diff --git a/README.markdown b/README.markdown
new file mode 100644
index 0000000..b093f97
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,6 @@
+####A service that creates your resume based on your GitHub repos.
+
+Possible Usecases:
+
+ * Boon for all the tech-savy bosses who want to have a **quick view** of person's git/github activity, _before the interview_
+
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000..6ef85f9
--- /dev/null
+++ b/config.ru
@@ -0,0 +1,2 @@
+use Rack::Static, :urls => ["/css", "/images", "/js", "/views"], :root => "."
+run lambda { |env| [200, { 'Content-Type' => 'text/html' }, File.open('index.html', File::RDONLY)] }
diff --git a/css/print.css b/css/print.css
new file mode 100644
index 0000000..3745ce6
--- /dev/null
+++ b/css/print.css
@@ -0,0 +1,124 @@
+/*
+ Print stylesheet for résumés
+*/
+
+
+/* =! Template */
+
+#doc2 {
+ width: 100%;
+}
+#inner {
+ margin: 0 auto;
+ padding: 10pt;
+ border: 0;
+}
+#hd {
+ margin-top: 0;
+}
+
+.enlarge {
+ padding-right: 0;
+}
+
+.talent li {
+ border: 0;
+}
+
+.org p,
+.job p {
+ margin: 5pt 0 15pt;
+}
+
+#repositories {
+ padding-bottom: 0;
+}
+
+#jobs h4 {
+ margin-top: 10pt;
+}
+
+#jobs .job,
+#about {
+ page-break-inside: avoid;
+}
+
+#bd,
+#about {
+ margin-bottom: 0;
+}
+
+#ft {
+ padding: 5pt 0;
+}
+
+/* --------- */
+
+
+
+/* =! Font */
+
+body {
+ font-size: 10pt;
+}
+
+#hd h1 {
+ font-size: 28pt;
+}
+#hd h2 {
+ font-size: 14pt;
+}
+
+#bd h2,
+#profile .enlarge,
+#about .enlarge {
+ font-size: 12pt;
+}
+
+/* --------- */
+
+
+
+/* =! Colors */
+
+body,
+h1, h2, h3, h4 {
+ color: #000;
+}
+
+#inner {
+ background: #fff;
+}
+
+/* --------- */
+
+
+
+/* =! Links */
+
+#profile a:after,
+#repositories a:after,
+#about a:after {
+ content: " (" attr(href) ")";
+ font-style: italic;
+ font-size: 10pt;
+}
+#profile #myblog:after,
+#jobs p a:after {
+ content: none;
+}
+
+a {
+ text-decoration: none;
+}
+
+#mylanguages a,
+#jobs p a {
+ color: inherit;
+}
+
+#actions {
+ visibility: hidden;
+}
+
+/* --------- */
\ No newline at end of file
diff --git a/css/resume.css b/css/resume.css
index 46ba5ed..6ea05f8 100644
--- a/css/resume.css
+++ b/css/resume.css
@@ -1,134 +1,289 @@
/*
---------------------------------------------------------------------------------
- STRIPPED DOWN RESUME TEMPLATE
+ STRIPPED DOWN RESUME TEMPLATE
html resume
v0.9: 5/28/09
- design and code by: thingsthatarebrown.com
+ design and code by: thingsthatarebrown.com
(matt brown)
---------------------------------------------------------------------------------
*/
+.msg {
+ padding: 10px;
+ background: #222;
+ position: relative;
+}
-.msg { padding: 10px; background: #222; position: relative; }
-.msg h1 { color: #fff; }
-.msg a { margin-left: 20px; background: #408814; color: white; padding: 4px 8px; text-decoration: none; }
-.msg a:hover { background: #266400; }
+.msg h1 { color: #fff }
+
+.msg a {
+ margin-left: 20px;
+ background: #408814;
+ color: white;
+ padding: 4px 8px;
+ text-decoration: none;
+}
+
+.msg a:hover { background: #266400 }
+
+html {
+ height: 100% ! important;
+ background: url('../images/low_contrast_linen.png');
+}
/* //-- yui-grids style overrides -- */
-body { font-family: Georgia; color: #444; }
-#inner { padding: 10px 80px; margin: 80px auto; background: #f5f5f5; border: solid #666; border-width: 8px 0 2px 0; }
-.yui-gf { margin-bottom: 2em; padding-bottom: 2em; border-bottom: 1px solid #ccc; }
+
+body {
+ font-family: Georgia, Garamond, "Times New Roman", Times, serif;
+ color: #444;
+}
+
+#inner {
+ padding: 10px 80px;
+ margin: 0 auto;
+ background: #f5f5f5;
+ border: solid #666;
+ border-width: 8px 0 2px 0;
+ box-shadow: 0 1px 3px #000;
+}
+
+.yui-gf {
+ margin-bottom: 2em;
+ padding-bottom: 2em;
+ border-bottom: 1px solid #ccc;
+}
+
+.yui-gf div.first { width: 12.3% }
+
+.yui-gf .yui-u { width: 80.2% }
/* //-- header, body, footer -- */
-#hd { margin: 2.5em 0 3em 0; padding-bottom: 1.5em; border-bottom: 1px solid #ccc }
-#hd h2 { text-transform: uppercase; letter-spacing: 2px; }
-#bd, #ft { margin-bottom: 2em; }
+
+#hd {
+ margin: 2.5em 0 3em 0;
+ padding-bottom: 1.5em;
+ border-bottom: 1px solid #ccc;
+}
+
+#hd h1 {
+ font-size: 48px;
+ text-transform: uppercase;
+ letter-spacing: 3px;
+}
+
+#hd h2 {
+ text-transform: uppercase;
+ letter-spacing: 2px;
+}
+
+#bd,
+#ft { margin-bottom: 2em }
+
+#ft p {
+ margin-bottom: 0;
+ text-align: center;
+}
/* //-- footer -- */
-#ft { padding: 1em 0 5em 0; font-size: 92%; border-top: 1px solid #ccc; text-align: center; }
-#ft p { margin-bottom: 0; text-align: center; }
+
+#ft {
+ padding: 1em 0 5em 0;
+ font-size: 92%;
+ border-top: 1px solid #ccc;
+ text-align: center;
+}
/* //-- core typography and style -- */
-#hd h1 { font-size: 48px; text-transform: uppercase; letter-spacing: 3px; }
-h2 { font-size: 152% }
-h3, h4 { font-size: 122%; }
-h1, h2, h3, h4 { color: #333; }
-p { font-size: 100%; line-height: 18px; padding-right: 3em; }
-a { color: #990003 }
-a:hover { text-decoration: none; }
-strong { font-weight: bold; }
-li { line-height: 24px; border-bottom: 1px solid #ccc; }
-p.enlarge { font-size: 144%; padding-right: 6.5em; line-height: 24px; }
-p.enlarge span { color: #000 }
-.contact-info { margin-top: 7px; text-align: right; font-size: 12px; position: relative; float: left; width: 100%;}
-.contact-info a { position :relative; float: left; width: 100%;}
-.contact-info img {float: right; border: 1px solid #ccc; width: 150px; height: 150px; margin: -24px 0 14px;}
-.first h2 { font-style: italic; }
-.last { border-bottom: 0 }
+h2 { font-size: 152% }
+
+h3,
+h4 { font-size: 122% }
+
+h1,
+h2,
+h3,
+h4 { color: #333 }
+
+p {
+ font-size: 100%;
+ line-height: 18px;
+ padding-right: 3em;
+}
+
+a { color: #990003 }
+
+a:hover { text-decoration: none }
+
+strong { font-weight: bold }
+
+li {
+ line-height: 24px;
+ border-bottom: 1px solid #ccc;
+}
+
+p.enlarge {
+ font-size: 144%;
+ padding-right: 6.5em;
+ line-height: 24px;
+}
+
+.contact-info {
+ margin-top: 7px;
+ text-align: right;
+ font-size: 12px;
+ position: relative;
+ float: left;
+ width: 100%;
+}
+
+.contact-info img {
+ float: right;
+ border: 1px solid #ccc;
+ width: 140px;
+ height: 140px;
+ margin: -24px 0 14px;
+ border-radius: 3px;
+}
+
+.contact-info a {
+ position : relative;
+ float: left;
+ width: 100%;
+}
+
+.first h2 { font-style: italic }
+
+.last { border-bottom: 0 }
/* //-- section styles -- */
-a#pdf { display: block; float: left; background: #666; color: white; padding: 6px 50px 6px 12px; margin-bottom: 6px; text-decoration: none; }
-a#pdf:hover { background: #222; }
+#pdf {
+ display: block;
+ float: left;
+ background: #666;
+ color: #fff;
+ padding: 6px 50px 6px 12px;
+ margin-bottom: 6px;
+ text-decoration: none;
+}
-.org, .job { position: relative; margin-bottom: 1em; padding-bottom: 1em; border-bottom: 1px solid #ccc; }
-.org a, .job a { border: none; text-decoration: none; }
-.org h4, .job h4 { position: absolute; top: 0.35em; right: 0 }
-.org p, .job p { margin: 0.75em 0 3em 0; }
+#pdf:hover { background: #222 }
-.last { border: none; }
-.content-languages { }
-.content-languages ul { margin: 0; display: inline; float: left; position: relative; width: 30%;}
-.content-languages li { margin: 3px 0; padding: 3px 0; position: relative; float: left; display-inline; }
-.content-languages li span { font-size: 152%; display: block; margin-bottom: -2px; padding: 0 }
-.talent { width: 32%; float: left }
-.talent h2 { margin-bottom: 6px; }
+.org,
+.job {
+ position: relative;
+ margin-bottom: 1em;
+ padding-bottom: 1em;
+ border-bottom: 1px solid #ccc;
+}
-#srt-ttab { margin-bottom: 100px; text-align: center; }
-#srt-ttab img.last { margin-top: 20px }
+.org h4,
+.job h4 {
+ position: absolute;
+ top: 0.35em;
+ right: 0;
+}
+
+.org a,
+.job a {
+ border: none;
+ text-decoration: none;
+}
+
+.org p,
+.job p { margin: 0.75em 0 3em 0 }
+
+.last { border: none }
+
+.talent {
+ width: 32%;
+ float: left;
+}
+
+.talent h2 { margin-bottom: 6px }
+
+#srt-ttab {
+ margin-bottom: 100px;
+ text-align: center;
+}
+
+#srt-ttab img.last { margin-top: 20px }
/* --// override to force 1/8th width grids -- */
-.yui-gf .yui-u{width:80.2%;}
-.yui-gf div.first{width:12.3%;}
-input#username {
- position: relative;
- float: left;
- height: 30px;
- width: 75%;
- border: 2px solid #444;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- font-family: Georgia; color: #444;
- font-size: 18px;
- padding: 5px;
+#username {
+ position: relative;
+ float: left;
+ height: 30px;
+ width: 75%;
+ border: 2px solid #444;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ font-family: Georgia, Garamond, "Times New Roman", Times, serif;
+ color: #444;
+ font-size: 18px;
+ padding: 5px;
}
-button#gen {
- position: relative;
- float: left;
- margin-left: 10px;
- width: 20%;
- height: 44px;
- font-family: Georgia; color: #444;
- font-size: 18px;
- color: white;
- background-image: -webkit-gradient(
- linear,
- left bottom,
- left top,
- color-stop(0.21, rgb(31,31,31)),
- color-stop(0.61, rgb(51,51,51))
- );
- background-image: -moz-linear-gradient(
- center bottom,
- rgb(31,31,31) 21%,
- rgb(51,51,51) 61%
- );
- border: 1px solid #444;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+#gen {
+ position: relative;
+ float: left;
+ margin-left: 10px;
+ width: 20%;
+ height: 44px;
+ font-family: Georgia, Garamond, "Times New Roman", Times, serif;
+ font-size: 18px;
+ color: #fff;
+ background-image: -webkit-gradient( linear, left bottom, left top, color-stop(0.21, rgb(31,31,31)), color-stop(0.61, rgb(51,51,51)) );
+ background-image: -moz-linear-gradient( center bottom, rgb(31,31,31) 21%, rgb(51,51,51) 61% );
+ border: 1px solid #444;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
}
-button#gen:hover {
- cursor: pointer;
-}
-
-.yui-gb ul {
- width: 80%;
-}
+#gen:hover { cursor: pointer }
.yui-gb {
- margin-top: 10px;
- margin-bottom: 10px;
- padding-bottom: 10px;
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding-bottom: 10px;
}
-.enlarge-medium {
- font-size: 15px;
+.enlarge-medium { font-size: 15px }
+
+.yui-gb ul { width: 80% }
+
+noscript {
+ display: block;
+ margin-top: 30px;
+ font-size: 152%;
+ color: #990003;
}
+
+#actions {
+ padding: 30px 0 40px 0;
+ margin: 0 auto 0 auto;
+ width: 73.076em;
+}
+
+#actions a {
+ color: #ccc;
+ text-decoration: none;
+ text-shadow: 0 0 5px #000;
+ margin-left: 1em;
+}
+
+#actions * { float: right }
+
+#doc {
+ margin-top: 70px;
+ background: #f5f5f5;
+ padding: 25px 107px 0px 107px;
+}
+
+#doc2 { padding-bottom: 70px }
\ No newline at end of file
diff --git a/images/low_contrast_linen.png b/images/low_contrast_linen.png
new file mode 100644
index 0000000..17b491e
Binary files /dev/null and b/images/low_contrast_linen.png differ
diff --git a/index.html b/index.html
index ac1e791..2e1b7c6 100644
--- a/index.html
+++ b/index.html
@@ -1,17 +1,18 @@
-
+
- Github Résumé
+ GitHub Résumé
-
+
-
+
+
-
+ You need to enable Javascript to generate and see résumé pages.
diff --git a/js/github.js b/js/github.js
deleted file mode 100644
index a67bf7d..0000000
--- a/js/github.js
+++ /dev/null
@@ -1,702 +0,0 @@
-// ## Client-side Javascript API wrapper for GitHub
-//
-// Tries to map one-to-one with the GitHub API V2, but in a Javascripty manner.
-
-(function (globals) {
-
- // Before we implement the API methods, we will define all of our private
- // variables and helper functions with one `var` statement.
- var
-
- // The username and authentication token of the library's user.
- authUsername,
- authToken,
-
- // To save keystrokes when we make JSONP calls to the HTTP API, we will keep
- // track of the root from which all V2 urls extend.
- apiRoot = "https://github.com/api/v2/json/",
-
- // Send a JSONP request to the Github API that calls `callback` with
- // the `context` argument as `this`.
- //
- // The `url` parameter is concatenated with the apiRoot, for the reasons
- // mentioned above. The way that we are supporting non-global, anonymous
- // functions is by sticking them in the globally exposed
- // `gh.__jsonp_callbacks` object with a "unique" `id` that is the current
- // time in milliseconds. Once the callback is called, it is deleted from the
- // object to prevent memory leaks.
- jsonp = function (url, callback, context) {
- var id = +new Date,
- script = document.createElement("script");
-
- while (gh.__jsonp_callbacks[id] !== undefined)
- id += Math.random(); // Avoid slight possibility of id clashes.
-
- gh.__jsonp_callbacks[id] = function () {
- delete gh.__jsonp_callbacks[id];
- callback.apply(context, arguments);
- };
-
- var prefix = "?";
- if (url.indexOf("?") >= 0)
- prefix = "&";
-
- url += prefix + "callback=" + encodeURIComponent("gh.__jsonp_callbacks[" + id + "]");
- if (authUsername && authToken) {
- url += "&login=" + authUsername + "&authToken=" + authToken;
- }
- script.setAttribute("src", apiRoot + url);
-
- document.getElementsByTagName('head')[0].appendChild(script);
- },
-
- // Send an HTTP POST. Unfortunately, it isn't possible to support a callback
- // with the resulting data. (Please prove me wrong if you can!)
- //
- // This is implemented with a hack to get around the cross-domain
- // restrictions on ajax calls. Basically, a form is created that will POST
- // to the GitHub API URL, stuck inside an iframe so that it won't redirect
- // this page, and then submitted.
- post = function (url, vals) {
- var
- form = document.createElement("form"),
- iframe = document.createElement("iframe"),
- doc = iframe.contentDocument !== undefined ?
- iframe.contentDocument :
- iframe.contentWindow.document,
- key, field;
- vals = vals || {};
-
- form.setAttribute("method", "post");
- form.setAttribute("action", apiRoot + url);
- for (key in vals) {
- if (vals.hasOwnProperty(key)) {
- field = document.createElement("input");
- field.type = "hidden";
- field.value = encodeURIComponent(vals[key]);
- form.appendChild(field);
- }
- }
-
- iframe.setAttribute("style", "display: none;");
- doc.body.appendChild(form);
- document.body.appendChild(iframe);
- form.submit();
- },
-
- // This helper function will throw a TypeError if the library user is not
- // properly authenticated. Otherwise, it silently returns.
- authRequired = function (username) {
- if (!authUsername || !authToken || authUsername !== username) {
- throw new TypeError("gh: Must be authenticated to do that.");
- }
- },
-
- // Convert an object to a url parameter string.
- //
- // paramify({foo:1, bar:3}) -> "foo=1&bar=3".
- paramify = function (params) {
- var str = "", key;
- for (key in params) if (params.hasOwnProperty(key))
- str += key + "=" + params[key] + "&";
- return str.replace(/&$/, "");
- },
-
- // Get around how the GH team haven't migrated all the API to version 2, and
- // how gists use a different api root.
- withTempApiRoot = function (tempApiRoot, fn) {
- return function () {
- var oldRoot = apiRoot;
- apiRoot = tempApiRoot;
- fn.apply(this, arguments);
- apiRoot = oldRoot;
- };
- },
-
- // Expose the global `gh` variable, through which every API method is
- // accessed, but keep a local variable around so we can reference it easily.
- gh = globals.gh = {};
-
- // Psuedo private home for JSONP callbacks (which are required to be global
- // by the nature of JSONP, as discussed earlier).
- gh.__jsonp_callbacks = {};
-
- // Authenticate as a user. Does not try to validate at any point; that job
- // is up to each individual method, which calls `authRequired` as needed.
- gh.authenticate = function (username, token) {
- authUsername = username;
- authToken = token;
- return this;
- };
-
- // ### Users
-
- // The constructor for user objects. Just creating an instance of a user
- // doesn't fetch any data from GitHub, you need to get explicit about what
- // you want to do that.
- //
- // var huddlej = gh.user("huddlej");
- gh.user = function (username) {
- if ( !(this instanceof gh.user)) {
- return new gh.user(username);
- }
- this.username = username;
- };
-
- // Show basic user info; you can get more info if you are authenticated as
- // this user.
- //
- // gh.user("fitzgen").show(function (data) {
- // console.log(data.user);
- // });
- gh.user.prototype.show = function (callback, context) {
- jsonp("user/show/" + this.username, callback, context);
- return this;
- };
-
- // Update a user's info. You must be authenticated as this user for this to
- // succeed.
- //
- // TODO: example
- gh.user.prototype.update = function (params) {
- authRequired(this.username);
- var key, postData = {
- login: authUsername,
- token: authToken
- };
- for (key in params) {
- if (params.hasOwnProperty(key)) {
- postData["values["+key+"]"] = encodeURIComponent(params[key]);
- }
- }
- post("user/show/" + this.username, postData);
- return this;
- };
-
- // Get a list of who this user is following.
- //
- // TODO: example
- gh.user.prototype.following = function (callback, context) {
- jsonp("user/show/" + this.username + "/following", callback, context);
- };
-
- // Find out what other users are following this user.
- //
- // TODO: example
- gh.user.prototype.followers = function (callback, context) {
- jsonp("user/show/" + this.username + "/followers", callback, context);
- };
-
- // Make this user follow some other user. You must be authenticated as this
- // user for this to succeed.
- //
- // TODO: example
- gh.user.prototype.follow = function (user) {
- authRequired.call(this);
- post("user/follow/" + user);
- return this;
- };
-
- // Make this user quit following the given `user`. You must be authenticated
- // as this user to succeed.
- //
- // TODO: example
- gh.user.prototype.unfollow = function (user) {
- authRequired.call(this);
- post("user/unfollow/" + user);
- return this;
- };
-
- // Get a list of repositories that this user is watching.
- //
- // TODO: example
- gh.user.prototype.watching = function (callback, context) {
- jsonp("repos/watched/" + this.username, callback, context);
- return this;
- };
-
- // Get a list of this user's repositories, 30 per page
- //
- // gh.user("fitzgen").repos(function (data) {
- // data.repositories.forEach(function (repo) {
- // ...
- // });
- // });
- gh.user.prototype.repos = function (callback, context, page) {
- gh.repo.forUser(this.username, callback, context, page);
- return this;
- };
-
- // Get a list of all repos for this user.
- //
- // gh.user("fitzgen").allRepos(function (data) {
- // alert(data.repositories.length);
- // });
- gh.user.prototype.allRepos = function (callback, context) {
- var repos = [],
- username = this.username,
- page = 1;
-
- function exitCallback () {
- callback.call(context, { repositories: repos });
- }
-
- function pageLoop (data) {
- if (data.repositories.length == 0) {
- exitCallback();
- } else {
- repos = repos.concat(data.repositories);
- page += 1;
- gh.repo.forUser(username, pageLoop, context, page);
- }
- }
-
- gh.repo.forUser(username, pageLoop, context, page);
-
- return this;
- };
-
- // Make this user fork the repo that lives at
- // http://github.com/user/repo. You must be authenticated as this user for
- // this to succeed.
- //
- // gh.user("fitzgen").forkRepo("brianleroux", "wtfjs");
- gh.user.prototype.forkRepo = function (user, repo) {
- authRequired(this.username);
- post("repos/fork/" + user + "/" + repo);
- return this;
- };
-
- // Get a list of all repos that this user can push to (including ones that
- // they are just a collaborator on, and do not own). Must be authenticated
- // as this user.
- gh.user.prototype.pushable = function (callback, context) {
- authRequired(authUsername);
- jsonp("repos/pushable", callback, context);
- };
-
- gh.user.prototype.publicGists = withTempApiRoot(
- "http://gist.github.com/api/v1/json/gists/",
- function (callback, context) {
- jsonp(this.username, callback, context);
- return this;
- }
- );
-
- // Search users for `query`.
- gh.user.search = function (query, callback, context) {
- jsonp("user/search/" + query, callback, context);
- return this;
- };
-
- // ### Repositories
-
- // This is the base constructor for creating repo objects. Note that this
- // won't actually hit the GitHub API until you specify what data you want,
- // or what action you wish to take via a prototype method.
- gh.repo = function (user, repo) {
- if ( !(this instanceof gh.repo)) {
- return new gh.repo(user, repo);
- }
- this.repo = repo;
- this.user = user;
- };
-
- // Get basic information on this repo.
- //
- // gh.repo("schacon", "grit").show(function (data) {
- // console.log(data.repository.description);
- // });
- gh.repo.prototype.show = function (callback, context) {
- jsonp("repos/show/" + this.user + "/" + this.repo, callback, context);
- return this;
- };
-
- // Update the information for this repo. Must be authenticated as the
- // repository owner. Params can include:
- //
- // * description
- // * homepage
- // * has_wiki
- // * has_issues
- // * has_downloads
- gh.repo.prototype.update = function (params) {
- authRequired(this.user);
- var key, postData = {
- login: authUsername,
- token: authToken
- };
- for (key in params) {
- if (params.hasOwnProperty(key)) {
- postData["values["+key+"]"] = encodeURIComponent(params[key]);
- }
- }
- post("repos/show/" + this.user + "/" + this.repo, postData);
- return this;
- };
-
- // Get all tags for this repo.
- gh.repo.prototype.tags = function (callback, context) {
- jsonp("repos/show/" + this.user + "/" + this.repo + "/tags",
- callback,
- context);
- return this;
- };
-
- // Get all branches in this repo.
- gh.repo.prototype.branches = function (callback, context) {
- jsonp("repos/show/" + this.user + "/" + this.repo + "/branches",
- callback,
- context);
- return this;
- };
-
- // Gather line count information on the language(s) used in this repo.
- gh.repo.prototype.languages = function (callback, context) {
- jsonp("/repos/show/" + this.user + "/" + this.repo + "/languages",
- callback,
- context);
- return this;
- };
-
- // Gather data on all the forks of this repo.
- gh.repo.prototype.network = function (callback, context) {
- jsonp("repos/show/" + this.user + "/" + this.repo + "/network",
- callback,
- context);
- return this;
- };
-
- // All users who have contributed to this repo. Pass `true` to showAnon if you
- // want to see the non-github contributors.
- gh.repo.prototype.contributors = function (callback, context, showAnon) {
- var url = "repos/show/" + this.user + "/" + this.repo + "/contributors";
- if (showAnon)
- url += "/anon";
- jsonp(url,
- callback,
- context);
- return this;
- };
-
- // Get all of the collaborators for this repo.
- gh.repo.prototype.collaborators = function (callback, context) {
- jsonp("repos/show/" + this.user + "/" + this.repo + "/collaborators",
- callback,
- context);
- return this;
- };
-
- // Add a collaborator to this project. Must be authenticated.
- gh.repo.prototype.addCollaborator = function (collaborator) {
- authRequired(this.user);
- post("repos/collaborators/" + this.repo + "/add/" + collaborator);
- return this;
- };
-
- // Remove a collaborator from this project. Must be authenticated.
- gh.repo.prototype.removeCollaborator = function (collaborator) {
- authRequired(this.user);
- post("repos/collaborators/" + this.repo + "/remove/" + collaborator);
- return this;
- };
-
- // Make this repository private. Authentication required.
- gh.repo.prototype.setPrivate = function () {
- authRequired(this.user);
- post("repo/set/private/" + this.repo);
- return this;
- };
-
- // Make this repository public. Authentication required.
- gh.repo.prototype.setPublic = function () {
- authRequired(this.user);
- post("repo/set/public/" + this.repo);
- return this;
- };
-
- // Search for repositories. `opts` may include `start_page` or `language`,
- // which must be capitalized.
- gh.repo.search = function (query, opts, callback, context) {
- var url = "repos/search/" + query.replace(" ", "+");
- if (typeof opts === "function") {
- opts = {};
- callback = arguments[1];
- context = arguments[2];
- }
- url += "?" + paramify(opts);
- return this;
- };
-
- // Get all the repos that are owned by `user`.
- gh.repo.forUser = function (user, callback, context, page) {
- if (!page)
- page = 1;
-
- jsonp("repos/show/" + user + '?page=' + page, callback, context);
- return this;
- };
-
- // Create a repository. Must be authenticated.
- gh.repo.create = function (name, opts) {
- authRequired(authUsername);
- opts.name = name;
- post("repos/create", opts);
- return this;
- };
-
- // Delete a repository. Must be authenticated.
- gh.repo.del = function (name) {
- authRequired(authUsername);
- post("repos/delete/" + name);
- return this;
- };
-
- // ### Commits
-
- gh.commit = function (user, repo, sha) {
- if ( !(this instanceof gh.commit) )
- return new gh.commit(user, repo, sha);
- this.user = user;
- this.repo = repo;
- this.sha = sha;
- };
-
- gh.commit.prototype.show = function (callback, context) {
- jsonp("commits/show/" + this.user + "/" + this.repo + "/" + this.sha,
- callback,
- context);
- return this;
- };
-
- // Get a list of all commits on a repos branch.
- gh.commit.forBranch = function (user, repo, branch, callback, context) {
- jsonp("commits/list/" + user + "/" + repo + "/" + branch,
- callback,
- context);
- return this;
- };
-
- // Get a list of all commits on this path (file or dir).
- gh.commit.forPath = function (user, repo, branch, path, callback, context) {
- jsonp("commits/list/" + user + "/" + repo + "/" + branch + "/" + path,
- callback,
- context);
- return this;
- };
-
- // ### Issues
-
- gh.issue = function (user, repo, number) {
- if ( !(this instanceof gh.issue) )
- return new gh.commit(user, repo, number);
- this.user = user;
- this.repo = repo;
- this.number = number;
- };
-
- // View this issue's info.
- gh.issue.prototype.show = function (callback, context) {
- jsonp("issues/show/" + this.user + "/" + this.repo + "/" + this.number,
- callback,
- context);
- return this;
- };
-
- // Get a list of all comments on this issue.
- gh.issue.prototype.comments = function (callback, context) {
- jsonp("issues/comments/" + this.user + "/" + this.repo + "/" + this.number,
- callback,
- context);
- return this;
- };
-
- // Close this issue.
- gh.issue.prototype.close = function () {
- authRequired(this.user);
- post("issues/close/" + this.user + "/" + this.repo + "/" + this.number);
- return this;
- };
-
- // Reopen this issue.
- gh.issue.prototype.reopen = function () {
- authRequired(this.user);
- post("issues/reopen/" + this.user + "/" + this.repo + "/" + this.number);
- return this;
- };
-
- // Reopen this issue.
- gh.issue.prototype.update = function (title, body) {
- authRequired(this.user);
- post("issues/edit/" + this.user + "/" + this.repo + "/" + this.number, {
- title: title,
- body: body
- });
- return this;
- };
-
- // Add `label` to this issue. If the label is not yet in the system, it will
- // be created.
- gh.issue.prototype.addLabel = function (label) {
- post("issues/label/add/" + this.user + "/" + this.repo + "/" + label + "/" + this.number);
- return this;
- };
-
- // Remove a label from this issue.
- gh.issue.prototype.removeLabel = function (label) {
- post("issues/label/remove/" + this.user + "/" + this.repo + "/" + label + "/" + this.number);
- return this;
- };
-
- // Comment on this issue as the user that is authenticated.
- gh.issue.prototype.comment = function (comment) {
- authRequired(authUsername);
- post("/issues/comment/" + user + "/" + repo + "/" + this.number, {
- comment: comment
- });
- return this;
- };
-
- // Get all issues' labels for the repo.
- gh.issue.labels = function (user, repo) {
- jsonp("issues/labels/" + user + "/" + repo,
- callback,
- context);
- return this;
- };
-
- // Open an issue. Must be authenticated.
- gh.issue.open = function (repo, title, body) {
- authRequired(authUsername);
- post("issues/open/" + authUsername + "/" + repo, {
- title: title,
- body: body
- });
- return this;
- };
-
- // Search a repository's issue tracker. `state` can be "open" or "closed".
- gh.issue.search = function (user, repo, state, query, callback, context) {
- jsonp("/issues/search/" + user + "/" + repo + "/" + state + "/" + query,
- callback,
- context);
- return this;
- };
-
- // Get a list of issues for the given repo. `state` can be "open" or
- // "closed".
- gh.issue.list = function (user, repo, state, callback, context) {
- jsonp("issues/list/" + user + "/" + repo + "/" + state,
- callback,
- context);
- return this;
- };
-
- // ### Gists
-
- gh.gist = function (id) {
- if ( !(this instanceof gh.gist) ) {
- return new gh.gist(id);
- }
- this.id = id;
- };
-
- gh.gist.prototype.show = withTempApiRoot(
- "http://gist.github.com/api/v1/json/",
- function (callback, context) {
- jsonp(this.id, callback, cont);
- return this;
- }
- );
-
- gh.gist.prototype.file = withTempApiRoot(
- "http://gist.github.com/raw/v1/json/",
- function (filename, callback, context) {
- jsonp(this.id + "/" + filename, callback, cont);
- return this;
- }
- );
-
- // ### Objects
-
- gh.object = function (user, repo) {
- if (!(this instanceof gh.object)) {
- return new gh.object(user, repo);
- }
- this.user = user;
- this.repo = repo;
- };
-
- // Get the contents of a tree by tree SHA
- gh.object.prototype.tree = function (sha, callback, context) {
- jsonp("tree/show/" + this.user + "/" + this.repo + "/" + sha,
- callback,
- context);
- return this;
- };
-
- // Get the data about a blob by tree SHA and path
- gh.object.prototype.blob = function (path, sha, callback, context) {
- jsonp("blob/show/" + this.user + "/" + this.repo + "/" + sha + "/" + path,
- callback,
- context);
- return this;
- };
-
- // Get only blob meta
- gh.object.prototype.blobMeta = function (path, sha, callback, context) {
- jsonp("blob/show/" + this.user + "/" + this.repo + "/" + sha + "/" + path + "?meta=1",
- callback,
- context);
- return this;
- };
-
- // Get list of blobs
- gh.object.prototype.blobAll = function (branch, callback, context) {
- jsonp("blob/all/" + this.user + "/" + this.repo + "/" + branch,
- callback,
- context);
- return this;
- };
-
- // Get meta of each blob in tree
- gh.object.prototype.blobFull = function (sha, callback, context) {
- jsonp("blob/full/" + this.user + "/" + this.repo + "/" + sha,
- callback,
- context);
- return this;
- };
-
- // ### Network
-
- gh.network = function(user, repo) {
- if (!(this instanceof gh.network)) {
- return new gh.network(user, repo);
- }
- this.user = user;
- this.repo = repo;
- };
-
- gh.network.prototype.data = withTempApiRoot(
- "http://github.com/",
- function (nethash, start, end, callback, context) {
- jsonp(this.user + "/" + this.repo + "/network_data_chunk?"
- + nethash + "&" + start + "&" + end,
- callback,
- context);
- return this;
- }
- );
-
- gh.network.prototype.meta = withTempApiRoot(
- "http://github.com/",
- function (callback, context) {
- jsonp(this.user + "/" + this.repo + "/network_meta",
- callback,
- context);
- return this;
- }
- );
-
-}(window));
-
diff --git a/js/githubresume.js b/js/githubresume.js
index ea8535b..d8d5450 100644
--- a/js/githubresume.js
+++ b/js/githubresume.js
@@ -53,96 +53,122 @@ var home = function() {
});
};
+var github_user = function(username, callback) {
+ $.getJSON('https://api.github.com/users/' + username + '?callback=?', callback);
+}
+
+var github_user_repos = function(username, callback, page_number, prev_data) {
+ var page = (page_number ? page_number : 1),
+ url = 'https://api.github.com/users/' + username + '/repos?callback=?',
+ data = (prev_data ? prev_data : []);
+
+ if (page_number > 1) {
+ url += '&page=' + page_number;
+ }
+ $.getJSON(url, function(repos) {
+ data = data.concat(repos.data);
+ if (repos.data.length > 0) {
+ github_user_repos(username, callback, page + 1, data);
+ } else {
+ callback(data);
+ }
+ });
+}
+
+var github_user_orgs = function(username, callback) {
+ $.getJSON('https://api.github.com/users/' + username + '/orgs?callback=?', callback);
+}
+
var run = function() {
+ var itemCount = 0,
+ maxItems = 5,
+ maxLanguages = 9;
- var gh_user = gh.user(username);
- var itemCount = 0, maxItems = 5, maxLanguages = 9;
-
- var res = gh_user.show(function(data) {
- gh_user.allRepos(function(data) {
- repos = data;
- });
-
- var sinceDate = new Date(data.user.created_at);
- since = sinceDate.getFullYear();
- var sinceMonth = sinceDate.getMonth();
+ var res = github_user(username, function(data) {
+ var sinceDate = new Date(data.created_at);
+ var since = sinceDate.getFullYear();
+ var sinceMonth = sinceDate.getMonth();
var currentYear = (new Date).getFullYear();
- switch (since) {
- case currentYear-1:
- since = 'last year';
- break;
- case currentYear:
- since = 'this year';
- break;
- }
+ switch (since) {
+ case currentYear-1:
+ since = 'last year';
+ break;
+ case currentYear:
+ since = 'this year';
+ break;
+ }
var addHttp = '';
- if (data.user.blog !== undefined && data.user.blog !== null) {
- if (data.user.blog.indexOf('http') < 0) {
- addHttp = 'http://';
- }
+ if (data.blog && data.blog.indexOf('http') < 0) {
+ addHttp = 'http://';
}
var name = username;
- if (data.user.name !== null && data.user.name !== undefined) {
- name = data.user.name;
+ if (data.name !== null && data.name !== undefined) {
+ name = data.name;
}
var view = {
name: name,
- email: data.user.email,
- created_at: data.user.created_at,
- earlyAdopter: 0,
- location: data.user.location,
- gravatar_id: data.user.gravatar_id,
- repos: data.user.public_repo_count,
- plural: data.user.public_repo_count > 1 ? 'repositories' : 'repository',
+ email: data.email,
+ created_at: data.created_at,
+ earlyAdopter: 0,
+ location: data.location,
+ gravatar_id: data.gravatar_id,
+ repos: data.public_repos,
+ reposLabel: data.public_repos > 1 ? 'repositories' : 'repository',
+ followers: data.followers,
+ followersLabel: data.followers > 1 ? 'followers' : 'follower',
username: username,
- since: since
+ since: since,
+ resume_url: window.location
};
- if (data.user.blog !== undefined && data.user.blog !== null) {
- view.blog = addHttp + data.user.blog;
+ if (data.blog !== undefined && data.blog !== null && data.blog !== '') {
+ view.blog = addHttp + data.blog;
+ }
+
+ // We consider a limit of 4 months since the Github opening (Feb 2008) to be considered as an early adopter
+ if (since == '2008' && sinceMonth <= 5) {
+ view.earlyAdopter = 1;
}
- // We consider a limit of 4 months since the Github opening (Feb 2008) to be considered as an early adopter
- if (since == '2008' && sinceMonth <= 5) {
- view.earlyAdopter = 1;
- }
-
$.ajax({
url: 'views/resume.html',
dataType: 'html',
success: function(data) {
- var template = data;
- var html = Mustache.to_html(template, view);
+ var template = data,
+ html = Mustache.to_html(template, view);
$('#resume').html(html);
document.title = name + "'s Résumé";
+ $("#actions #print").click(function(){
+ window.print();
+ return false;
+ });
}
});
});
- gh_user.allRepos(function(data) {
- var repos = data.repositories;
+ github_user_repos(username, function(data) {
+ var sorted = [],
+ languages = {},
+ popularity;
- var sorted = [];
- var languages = {};
-
- repos.forEach(function(elm, i, arr) {
- if (arr[i].fork !== false) {
+ $.each(data, function(i, repo) {
+ if (repo.fork !== false) {
return;
}
-
- if (arr[i].language) {
- if (arr[i].language in languages) {
- languages[arr[i].language]++;
+
+ if (repo.language) {
+ if (repo.language in languages) {
+ languages[repo.language]++;
} else {
- languages[arr[i].language] = 1;
+ languages[repo.language] = 1;
}
}
- var popularity = arr[i].watchers + arr[i].forks;
- sorted.push({position: i, popularity: popularity, info: arr[i]});
+ popularity = repo.watchers + repo.forks;
+ sorted.push({position: i, popularity: popularity, info: repo});
});
function sortByPopularity(a, b) {
@@ -154,6 +180,7 @@ var run = function() {
var languageTotal = 0;
function sortLanguages(languages, limit) {
var sorted_languages = [];
+
for (var lang in languages) {
if (typeof(lang) !== "string") {
continue;
@@ -167,11 +194,12 @@ var run = function() {
});
languageTotal += languages[lang];
-
}
+
if (limit) {
sorted_languages = sorted_languages.slice(0, limit);
}
+
return sorted_languages.sort(sortByPopularity);
}
@@ -179,15 +207,17 @@ var run = function() {
url: 'views/job.html',
dataType: 'html',
success: function(response) {
- var now = new Date().getFullYear();
languages = sortLanguages(languages, maxLanguages);
if (languages && languages.length > 0) {
- var ul = $('');
- languages.forEach(function(elm, i, arr) {
+ var ul = $(''),
+ percent, li;
+
+ $.each(languages, function(i, lang) {
x = i + 1;
- var percent = parseInt((arr[i].popularity / languageTotal) * 100);
- var li = $('' + arr[i].toString() + ' ('+percent+'%) ');
+ percent = parseInt((lang.popularity / languageTotal) * 100);
+ li = $('' + lang.toString() + ' ('+percent+'%) ');
+
if (x % 3 == 0 || (languages.length < 3 && i == languages.length - 1)) {
li.attr('class', 'last');
ul.append(li);
@@ -205,54 +235,60 @@ var run = function() {
if (sorted.length > 0) {
$('#jobs').html('');
itemCount = 0;
- sorted.forEach(function(elm, index, arr) {
+ var since, until, date, view, template, html;
+
+ $.each(sorted, function(index, repo) {
if (itemCount >= maxItems) {
return;
}
- var since = new Date(arr[index].info.created_at);
+ since = new Date(repo.info.created_at);
since = since.getFullYear();
+ until = new Date(repo.info.pushed_at);
+ until = until.getFullYear();
+ if (since == until) {
+ date = since;
+ } else {
+ date = since + ' - ' + until;
+ }
- var view = {
- name: arr[index].info.name,
- since: since,
- now: now,
- language: arr[index].info.language,
- description: arr[index].info.description,
+ view = {
+ name: repo.info.name,
+ date: date,
+ language: repo.info.language,
+ description: repo.info.description,
username: username,
- watchers: arr[index].info.watchers,
- forks: arr[index].info.forks
+ watchers: repo.info.watchers,
+ forks: repo.info.forks,
+ watchersLabel: repo.info.watchers > 1 ? 'watchers' : 'watcher',
+ forksLabel: repo.info.forks > 1 ? 'forks' : 'fork',
};
if (itemCount == sorted.length - 1 || itemCount == maxItems - 1) {
view.last = 'last';
}
- var template = response;
- var html = Mustache.to_html(template, view);
-
+ template = response;
+ html = Mustache.to_html(template, view);
$('#jobs').append($(html));
++itemCount;
});
} else {
- $('#jobs').html('');
- $('#jobs').append('I do not have any public repository. Sorry.
');
+ $('#jobs').html('').append('I do not have any public repositories. Sorry.
');
}
}
});
});
- gh_user.orgs(function(data) {
- var orgs = data.organizations;
-
+ github_user_orgs(username, function(response) {
var sorted = [];
- orgs.forEach(function(elm, i, arr) {
- if (arr[i].name === undefined) {
+ $.each(response.data, function(i, org) {
+ if (org.login === undefined) {
return;
}
- sorted.push({position: i, info: arr[i]});
+ sorted.push({position: i, info: org});
});
$.ajax({
@@ -263,21 +299,24 @@ var run = function() {
if (sorted.length > 0) {
$('#orgs').html('');
- sorted.forEach(function(elm, index, arr) {
+
+ var name, view, template, html;
+
+ $.each(sorted, function(index, org) {
if (itemCount >= maxItems) {
return;
}
- var view = {
- name: arr[index].info.name,
- login: arr[index].info.login,
+ name = (org.info.name || org.info.login);
+ view = {
+ name: name,
now: now
};
if (itemCount == sorted.length - 1 || itemCount == maxItems) {
view.last = 'last';
}
- var template = response;
- var html = Mustache.to_html(template, view);
+ template = response;
+ html = Mustache.to_html(template, view);
$('#orgs').append($(html));
++itemCount;
diff --git a/views/error.html b/views/error.html
index 72d4306..1b03f72 100644
--- a/views/error.html
+++ b/views/error.html
@@ -3,7 +3,7 @@
diff --git a/views/index.html b/views/index.html
index f92e783..baac670 100644
--- a/views/index.html
+++ b/views/index.html
@@ -1,5 +1,5 @@
-
My Github Résumé
+
My GitHub Résumé
@@ -9,7 +9,7 @@
After a tweet by John Resig
- I imagined that it may be nice for people to be able to generate their Github résumés.
+ I imagined that it may be nice for people to be able to generate their GitHub résumés.
@@ -54,9 +54,7 @@
This is the first version. I am planning on adding
things as such as your most committed forks, most committed repositories and make the "My Popular Repositories" be built from
- your complete list of repositories. The issue right now is say you have 37 repositories, this will only retrieve the first
- 30 repositories that were created. I'll put a note here when this is fixed or feel free to fork the page ,
- make changes and send them back :-)
+ your complete list of repositories. Feel free to fork the page if you want to help :-)
diff --git a/views/job.html b/views/job.html
index 5a141ff..449d005 100644
--- a/views/job.html
+++ b/views/job.html
@@ -3,14 +3,14 @@
{{name}}
{{#language}}{{language}} - {{/language}}Creator & Owner
-
{{since}} - {{now}}
-
{{description}}.
+
{{date}}
+
{{description}}
- This repository has {{watchers}} watcher(s) and {{forks}} fork(s).
+ This repository has {{watchers}} {{watchersLabel}} and {{forks}} {{forksLabel}}.
If you would like more information about this repository and my
contributed code, please visit
the repo on
- Github.
+ GitHub.
diff --git a/views/org.html b/views/org.html
index a69c970..8b80672 100644
--- a/views/org.html
+++ b/views/org.html
@@ -3,7 +3,7 @@
{{name}}
Member
{{now}}
-
If you would like more information about this organization, please visit the organization page on Github.
+
If you would like more information about this organization, please visit the organization page on GitHub.
diff --git a/views/resume.html b/views/resume.html
index 8df4c79..5e2450f 100644
--- a/views/resume.html
+++ b/views/resume.html
@@ -1,11 +1,17 @@
+
+
-
+
+
- {{name}}
+ {{name}}
Passionate github user
@@ -13,9 +19,9 @@
@@ -25,34 +31,32 @@
-
+
-
Github Profile
+ GitHub Profile
I'm a developer
{{#location}}
- based in {{location}}
+ based in {{location}}
{{/location}}
- {{#repos}}with {{repos}} public {{plural}} {{/repos}}{{^repos}}without any public repository for now{{/repos}}.
+ {{#repos}}with {{repos}} public {{reposLabel}} {{/repos}}{{^repos}}without any public repository for now{{/repos}}{{#followers}} and {{followers}} {{followersLabel}}{{/followers}}.
I've been using github.com since {{since}}{{#earlyAdopter}}, therefore I'm an early adopter,{{/earlyAdopter}}
- {{#blog}}
- and sometimes I blog at {{blog}} .
- {{/blog}}
+ {{#blog}} and sometimes I blog at {{blog}} .{{/blog}}
-
+
-
+
My Popular Repositories
@@ -72,7 +76,7 @@
-
+
About This Résumé
@@ -80,7 +84,7 @@
This résumé is generated automatically using information from my github account. The repositories are
ordered by popularity based on a very simple popularity heuristic that defines the popularity of a repository
- by its sum of watchers and forks. Do not hesitate to visit my github page
+ by its sum of watchers and forks. Do not hesitate to visit my github page
for more information about my repositories and work.
@@ -90,15 +94,9 @@
-
diff --git a/views/resumeOrgs.html b/views/resumeOrgs.html
new file mode 100644
index 0000000..039d805
--- /dev/null
+++ b/views/resumeOrgs.html
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+ {{name}}
+ Github organization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Github Profile
+
+
+
+ We are XX developers gathered in a group
+ {{#location}}
+ based in {{location}}
+ {{/location}}
+ with {{repos}} public {{reposLabel}} .
+ We've created this Github group in {{since}}{{#earlyAdopter}}, therefore I'm an early adopter,{{/earlyAdopter}}{{#blog}} and you can find more informations about us at {{blog}} {{/blog}}.
+
+
+
+
+
+
+
+
Our Popular Repositories
+
+
+
+
Loading information...
+
+
+
+
+
+
About This Résumé
+
+
+
+ This résumé is generated automatically using information from github. The repositories are
+ ordered by popularity based on a very simple popularity heuristic that defines the popularity of a repository
+ by its sum of watchers and forks. Do not hesitate to visit our github group's page
+ for more information about our repositories and work.
+
+
+
+
+
+
+
+
+
+
+
+