summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGubolin <gubolin@fantasymail.de>2014-07-30 18:23:33 +0200
committerGubolin <gubolin@fantasymail.de>2014-07-30 18:23:33 +0200
commitb9ec43451b9feb0c743196e2b4c3419e5ff611f8 (patch)
tree13a695fd0e16de1af79ab87fa2d714e4415f65ca
parentbfdbeca146f8d58e1f15b2b85f4feae2687d1d9f (diff)
downloadsnap-b9ec43451b9feb0c743196e2b4c3419e5ff611f8.tar.gz
snap-b9ec43451b9feb0c743196e2b4c3419e5ff611f8.zip
replace the Snap!Cloud with GitHub
-rw-r--r--cloud.js616
-rw-r--r--gui.js409
-rw-r--r--octokit/octokit.js1465
-rw-r--r--octokit/promise-1.0.0.js684
-rwxr-xr-xsnap.html2
5 files changed, 2300 insertions, 876 deletions
diff --git a/cloud.js b/cloud.js
index 54189d8..02cc14f 100644
--- a/cloud.js
+++ b/cloud.js
@@ -1,12 +1,11 @@
/*
+cloud.js
- cloud.js
+ a GitHub backend API for SNAP!
- a backend API for SNAP!
+ written by Gubolin, based on cloud.js by Jens Mönig
- written by Jens Mönig
-
- Copyright (C) 2014 by Jens Mönig
+ Copyright (C) 2014 by Jens Mönig, Gubolin
This file is part of Snap!.
@@ -30,253 +29,73 @@
/*global modules, IDE_Morph, SnapSerializer, hex_sha512, alert, nop,
localize*/
-modules.cloud = '2014-May-26';
+modules.cloud = '2014-July-29';
// Global stuff
var Cloud;
-var SnapCloud = new Cloud(
- 'https://snapcloud.miosoft.com/miocon/app/login?_app=SnapCloud'
-);
+var SnapCloud = new Cloud();
// Cloud /////////////////////////////////////////////////////////////
function Cloud(url) {
+ this.gh = null;
this.username = null;
- this.password = null; // hex_sha512 hashed
- this.url = url;
+ this.password = null; // TODO saved as plain text
this.session = null;
this.api = {};
}
Cloud.prototype.clear = function () {
+ this.gh = null;
this.username = null;
this.password = null;
this.session = null;
this.api = {};
};
-Cloud.prototype.hasProtocol = function () {
- return this.url.toLowerCase().indexOf('http') === 0;
-};
-
// Cloud: Snap! API
-Cloud.prototype.signup = function (
- username,
- email,
+Cloud.prototype.getProject = function (
+ dict,
callBack,
errorCall
) {
- // both callBack and errorCall are two-argument functions
- var request = new XMLHttpRequest(),
- myself = this;
- try {
- request.open(
- "GET",
- (this.hasProtocol() ? '' : 'http://')
- + this.url + 'SignUp'
- + '&Username='
- + encodeURIComponent(username)
- + '&Email='
- + encodeURIComponent(email),
- true
- );
- request.setRequestHeader(
- "Content-Type",
- "application/x-www-form-urlencoded"
- );
- request.withCredentials = true;
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- if (request.responseText) {
- if (request.responseText.indexOf('ERROR') === 0) {
- errorCall.call(
- this,
- request.responseText,
- 'Signup'
- );
- } else {
- callBack.call(
- null,
- request.responseText,
- 'Signup'
- );
- }
- } else {
- errorCall.call(
- null,
- myself.url + 'SignUp',
- localize('could not connect to:')
- );
- }
- }
- };
- request.send(null);
- } catch (err) {
- errorCall.call(this, err.toString(), 'Snap!Cloud');
- }
-};
+ var myself = this;
+ var projectName = dict.projectname;
+ var userName = dict.username;
-Cloud.prototype.getPublicProject = function (
- id,
- callBack,
- errorCall
-) {
- // id is Username=username&projectName=projectname,
- // where the values are url-component encoded
- // callBack is a single argument function, errorCall take two args
- var request = new XMLHttpRequest(),
- responseList,
- myself = this;
- try {
- request.open(
- "GET",
- (this.hasProtocol() ? '' : 'http://')
- + this.url + 'Public'
- + '&'
- + id,
- true
- );
- request.setRequestHeader(
- "Content-Type",
- "application/x-www-form-urlencoded"
- );
- request.withCredentials = true;
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- if (request.responseText) {
- if (request.responseText.indexOf('ERROR') === 0) {
- errorCall.call(
- this,
- request.responseText
- );
- } else {
- responseList = myself.parseResponse(
- request.responseText
- );
- callBack.call(
- null,
- responseList[0].SourceCode
- );
- }
- } else {
- errorCall.call(
- null,
- myself.url + 'Public',
- localize('could not connect to:')
- );
- }
- }
- };
- request.send(null);
- } catch (err) {
- errorCall.call(this, err.toString(), 'Snap!Cloud');
- }
-};
+ if (myself.gh !== null) {
+ var repo = myself.gh.getRepo(userName, projectName);
+ var branch = repo.getBranch(); // master (default)
+ var media, pdata;
+ var br;
-Cloud.prototype.resetPassword = function (
- username,
- callBack,
- errorCall
-) {
- // both callBack and errorCall are two-argument functions
- var request = new XMLHttpRequest(),
- myself = this;
- try {
- request.open(
- "GET",
- (this.hasProtocol() ? '' : 'http://')
- + this.url + 'ResetPW'
- + '&Username='
- + encodeURIComponent(username),
- true
- );
- request.setRequestHeader(
- "Content-Type",
- "application/x-www-form-urlencoded"
- );
- request.withCredentials = true;
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- if (request.responseText) {
- if (request.responseText.indexOf('ERROR') === 0) {
- errorCall.call(
- this,
- request.responseText,
- 'Reset Password'
- );
- } else {
+ branch.read('snap.xml', false).then(
+ function (sourceContent) {
+ branch.read('media.xml', false).then( // true for binary
+ function (mediaContent) {
callBack.call(
null,
- request.responseText,
- 'Reset Password'
+ sourceContent.content,
+ mediaContent.content
);
+ },
+ function (error) {
+ errorCall.call(this, error, 'Github');
}
- } else {
- errorCall.call(
- null,
- myself.url + 'ResetPW',
- localize('could not connect to:')
- );
- }
+ );
+ },
+ function (error) {
+ errorCall.call(this, error, 'Github');
}
- };
- request.send(null);
- } catch (err) {
- errorCall.call(this, err.toString(), 'Snap!Cloud');
- }
-};
-
-Cloud.prototype.connect = function (
- callBack,
- errorCall
-) {
- // both callBack and errorCall are two-argument functions
- var request = new XMLHttpRequest(),
- myself = this;
- try {
- request.open(
- "GET",
- (this.hasProtocol() ? '' : 'http://') + this.url,
- true
- );
- request.setRequestHeader(
- "Content-Type",
- "application/x-www-form-urlencoded"
);
- request.withCredentials = true;
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- if (request.responseText) {
- myself.api = myself.parseAPI(request.responseText);
- myself.session = request.getResponseHeader('MioCracker')
- .split(';')[0];
- if (myself.api.login) {
- callBack.call(null, myself.api, 'Snap!Cloud');
- } else {
- errorCall.call(
- null,
- 'connection failed'
- );
- }
- } else {
- errorCall.call(
- null,
- myself.url,
- localize('could not connect to:')
- );
- }
- }
- };
- request.send(null);
- } catch (err) {
- errorCall.call(this, err.toString(), 'Snap!Cloud');
+ } else {
+ errorCall.call(null, 'Please login', 'Github');
}
};
-
Cloud.prototype.login = function (
username,
password,
@@ -284,61 +103,22 @@ Cloud.prototype.login = function (
errorCall
) {
var myself = this;
- this.connect(
- function () {
- myself.rawLogin(username, password, callBack, errorCall);
- myself.disconnect();
- },
- errorCall
- );
-};
-Cloud.prototype.rawLogin = function (
- username,
- password,
- callBack,
- errorCall
-) {
- // both callBack and errorCall are two-argument functions
- var myself = this,
- pwHash = hex_sha512("miosoft%20miocon,"
- + this.session.split('=')[1] + ","
- + encodeURIComponent(username.toLowerCase()) + ","
- + password // alreadey hex_sha512 hashed
- );
- this.callService(
- 'login',
- function (response, url) {
- if (myself.api.logout) {
- myself.username = username;
- myself.password = password;
- callBack.call(null, response, url);
- } else {
- errorCall.call(
- null,
- 'Service catalog is not available,\nplease retry',
- 'Connection Error:'
- );
- }
- },
- errorCall,
- [username, pwHash]
- );
-};
+ myself.gh = new Octokit({
+ username: username,
+ password: password
+ });
-Cloud.prototype.reconnect = function (
- callBack,
- errorCall
-) {
- if (!(this.username && this.password)) {
- this.message('You are not logged in');
- return;
- }
- this.login(
- this.username,
- this.password,
- callBack,
- errorCall
+ myself.gh.getUser().getInfo().then(
+ function(info) {
+ myself.username = username;
+ myself.password = password;
+
+ callBack.call(myself);
+ },
+ function (error) {
+ errorCall.call(this, error, 'Github');
+ }
);
};
@@ -346,6 +126,7 @@ Cloud.prototype.saveProject = function (ide, callBack, errorCall) {
var myself = this,
pdata,
media;
+ var repoName = ide.projectName.replace(/[^\w-]/g, ''); // FIXME validation of project name
ide.serializer.isCollectingMedia = true;
pdata = ide.serializer.serialize(ide.stage);
@@ -372,232 +153,111 @@ Cloud.prototype.saveProject = function (ide, callBack, errorCall) {
ide.serializer.isCollectingMedia = false;
ide.serializer.flushMedia();
- myself.reconnect(
- function () {
- myself.callService(
- 'saveProject',
- function (response, url) {
- callBack.call(null, response, url);
- myself.disconnect();
- ide.hasChangedMedia = false;
- },
- errorCall,
- [
- ide.projectName,
- pdata,
- media,
- pdata.length,
- media ? media.length : 0
- ]
- );
- },
- errorCall
- );
-};
-
-Cloud.prototype.getProjectList = function (callBack, errorCall) {
- var myself = this;
- this.reconnect(
- function () {
- myself.callService(
- 'getProjectList',
- function (response, url) {
- callBack.call(null, response, url);
- myself.disconnect();
- },
- errorCall
- );
- },
- errorCall
- );
-};
+ myself.getProjectList(
+ function (projects) {
+ var exists = false;
-Cloud.prototype.changePassword = function (
- oldPW,
- newPW,
- callBack,
- errorCall
-) {
- var myself = this;
- this.reconnect(
- function () {
- myself.callService(
- 'changePassword',
- function (response, url) {
- callBack.call(null, response, url);
- myself.disconnect();
- },
- errorCall,
- [oldPW, newPW]
- );
- },
- errorCall
- );
-};
+ projects.forEach(function (project) {
+ if (project.ProjectName.indexOf(repoName) > -1) {
+ exists = true;
+ return;
+ }
+ });
-Cloud.prototype.logout = function (callBack, errorCall) {
- this.clear();
- this.callService(
- 'logout',
- callBack,
- errorCall
- );
-};
+ if (exists === false){
+ myself.gh.getUser().createRepo(repoName, { // these should be discussed
+ 'description': 'Snap! Project',
+ 'has_wiki': 'false',
+ 'has_downloads': 'false',
+ 'auto_init': true,
+ 'license_template': 'mit' // discuss
+ }).then(
+ function () {},
+ function (error) {
+ errorCall.call(this, error, 'Github');
+ }
+ );
+ }
-Cloud.prototype.disconnect = function () {
- this.callService(
- 'logout',
- nop,
- nop
- );
-};
+ if (myself.gh !== null) {
+ var repo = myself.gh.getRepo(myself.username, ide.projectName);
+ var branch = repo.getBranch(); // master (default)
+ var message = ''; // FIXME optional: specify message
-// Cloud: backend communication
+ var contents = {
+ 'snap.xml': pdata,
+ 'media.xml': media // may be binary
+ };
-Cloud.prototype.callURL = function (url, callBack, errorCall) {
- // both callBack and errorCall are optional two-argument functions
- var request = new XMLHttpRequest(),
- myself = this;
- try {
- request.open('GET', url, true);
- request.withCredentials = true;
- request.setRequestHeader(
- "Content-Type",
- "application/x-www-form-urlencoded"
- );
- request.setRequestHeader('MioCracker', this.session);
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- if (request.responseText) {
- var responseList = myself.parseResponse(
- request.responseText
- );
- callBack.call(null, responseList, url);
- } else {
- errorCall.call(
- null,
- url,
- 'no response from:'
+ branch.writeMany(contents, message).then(
+ function () {
+ callBack.call()
+ },
+ function (error) {
+ errorCall.call(this, error, 'Github');
+ }
);
}
+ },
+ function (error) {
+ errorCall.call(null, error, 'Github');
}
- };
- request.send(null);
- } catch (err) {
- errorCall.call(this, err.toString(), url);
- }
+ );
};
-Cloud.prototype.callService = function (
- serviceName,
- callBack,
- errorCall,
- args
-) {
- // both callBack and errorCall are optional two-argument functions
- var request = new XMLHttpRequest(),
- service = this.api[serviceName],
- myself = this,
- postDict;
+Cloud.prototype.getProjectList = function (callBack, errorCall) {
+ var myself = this;
- if (!this.session) {
- errorCall.call(null, 'You are not connected', 'Cloud');
- return;
- }
- if (!service) {
- errorCall.call(
- null,
- 'service ' + serviceName + ' is not available',
- 'API'
- );
- return;
- }
- if (args && args.length > 0) {
- postDict = {};
- service.parameters.forEach(function (parm, idx) {
- postDict[parm] = args[idx];
- });
- }
- try {
- request.open(service.method, service.url, true);
- request.withCredentials = true;
- request.setRequestHeader(
- "Content-Type",
- "application/x-www-form-urlencoded"
- );
- request.setRequestHeader('MioCracker', this.session);
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- var responseList = [];
- if (request.responseText &&
- request.responseText.indexOf('ERROR') === 0) {
- errorCall.call(
- this,
- request.responseText,
- localize('Service:') + ' ' + localize(serviceName)
- );
- return;
- }
- if (serviceName === 'login') {
- myself.api = myself.parseAPI(request.responseText);
+ if (myself.gh !== null) {
+ myself.gh.getUser().getRepos().then(
+ function (repos) {
+ var snapProjects = [];
+
+ repos.forEach(function (repo) {
+ if (repo.description === 'Snap! Project') { // FIXME nicer detection
+ var project;
+
+ project = {
+ 'ProjectName': repo.name
+ };
+
+ snapProjects.push(project);
+ }
+ });
+
+ callBack.call(myself, snapProjects);
+ },
+ function (error) {
+ errorCall.call(this, error, 'Github');
}
- responseList = myself.parseResponse(
- request.responseText
- );
- callBack.call(null, responseList, service.url);
- }
- };
- request.send(this.encodeDict(postDict));
- } catch (err) {
- errorCall.call(this, err.toString(), service.url);
+ );
+ } else {
+ errorCall.call(myself, 'Please login', 'Github');
}
};
-// Cloud: payload transformation
-
-Cloud.prototype.parseAPI = function (src) {
- var api = {},
- services;
- services = src.split(" ");
- services.forEach(function (service) {
- var entries = service.split("&"),
- serviceDescription = {},
- parms;
- entries.forEach(function (entry) {
- var pair = entry.split("="),
- key = decodeURIComponent(pair[0]).toLowerCase(),
- val = decodeURIComponent(pair[1]);
- if (key === "service") {
- api[val] = serviceDescription;
- } else if (key === "parameters") {
- parms = val.split(",");
- if (!(parms.length === 1 && !parms[0])) {
- serviceDescription.parameters = parms;
- }
- } else {
- serviceDescription[key] = val;
- }
- });
- });
- return api;
+Cloud.prototype.logout = function (callBack) {
+ this.clear();
};
+// Cloud: backend communication
+
Cloud.prototype.parseResponse = function (src) {
var ans = [],
lines;
if (!src) {return ans; }
lines = src.split(" ");
lines.forEach(function (service) {
- var entries = service.split("&"),
- dict = {};
- entries.forEach(function (entry) {
- var pair = entry.split("="),
- key = decodeURIComponent(pair[0]),
- val = decodeURIComponent(pair[1]);
- dict[key] = val;
+ var entries = service.split("&"),
+ dict = {};
+ entries.forEach(function (entry) {
+ var pair = entry.split("="),
+ key = decodeURIComponent(pair[0]),
+ val = decodeURIComponent(pair[1]);
+ dict[key] = val;
+ });
+ ans.push(dict);
});
- ans.push(dict);
- });
return ans;
};
@@ -606,8 +266,8 @@ Cloud.prototype.parseDict = function (src) {
if (!src) {return dict; }
src.split("&").forEach(function (entry) {
var pair = entry.split("="),
- key = decodeURIComponent(pair[0]),
- val = decodeURIComponent(pair[1]);
+ key = decodeURIComponent(pair[0]),
+ val = decodeURIComponent(pair[1]);
dict[key] = val;
});
return dict;
@@ -619,10 +279,8 @@ Cloud.prototype.encodeDict = function (dict) {
key;
if (!dict) {return null; }
for (key in dict) {
- if (dict.hasOwnProperty(key)) {
- pair = encodeURIComponent(key)
- + '='
- + encodeURIComponent(dict[key]);
+ if (dict.hasOwnProperty(key)) {
+ pair = encodeURIComponent(key) + '=' + encodeURIComponent(dict[key]);
if (str.length > 0) {
str += '&';
}
@@ -631,9 +289,3 @@ Cloud.prototype.encodeDict = function (dict) {
}
return str;
};
-
-// Cloud: user messages (to be overridden)
-
-Cloud.prototype.message = function (string) {
- alert(string);
-};
diff --git a/gui.js b/gui.js
index e4c75dd..9850184 100644
--- a/gui.js
+++ b/gui.js
@@ -69,7 +69,7 @@ SpeechBubbleMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.gui = '2014-July-29';
+modules.gui = '2014-July-30';
// Declarations
@@ -243,8 +243,8 @@ IDE_Morph.prototype.openIn = function (world) {
if (usr) {
usr = SnapCloud.parseResponse(usr)[0];
if (usr) {
- SnapCloud.username = usr.username || null;
- SnapCloud.password = usr.password || null;
+ SnapCloud.login(usr.username, usr.password,
+ function() {}, myself.cloudError());
}
}
}
@@ -338,12 +338,11 @@ IDE_Morph.prototype.openIn = function (world) {
this.parent.add(this.shield);
myself.showMessage('Fetching project\nfrom the cloud...');
- // make sure to lowercase the username
dict = SnapCloud.parseDict(location.hash.substr(9));
- dict.Username = dict.Username.toLowerCase();
+ dict.Username = dict.Username;
SnapCloud.getPublicProject(
- SnapCloud.encodeDict(dict),
+ dict,
function (projectData) {
var msg;
myself.nextSteps([
@@ -375,8 +374,6 @@ IDE_Morph.prototype.openIn = function (world) {
urlLanguage = location.hash.substr(6);
this.setLanguage(urlLanguage);
this.loadNewProject = true;
- } else if (location.hash.substr(0, 7) === '#signup') {
- this.createCloudAccount();
}
}
@@ -1935,37 +1932,16 @@ IDE_Morph.prototype.cloudMenu = function () {
shiftClicked = (world.currentKey === 16);
menu = new MenuMorph(this);
- if (shiftClicked) {
- menu.addItem(
- 'url...',
- 'setCloudURL',
- null,
- new Color(100, 0, 0)
- );
- menu.addLine();
- }
if (!SnapCloud.username) {
menu.addItem(
'Login...',
'initializeCloud'
);
- menu.addItem(
- 'Signup...',
- 'createCloudAccount'
- );
- menu.addItem(
- 'Reset Password...',
- 'resetCloudPassword'
- );
} else {
menu.addItem(
localize('Logout') + ' ' + SnapCloud.username,
'logout'
);
- menu.addItem(
- 'Change Password...',
- 'changeCloudPassword'
- );
}
if (shiftClicked) {
menu.addLine();
@@ -2011,53 +1987,6 @@ IDE_Morph.prototype.cloudMenu = function () {
null,
new Color(100, 0, 0)
);
- menu.addLine();
- menu.addItem(
- 'open shared project from cloud...',
- function () {
- myself.prompt('Author name…', function (usr) {
- myself.prompt('Project name...', function (prj) {
- var id = 'Username=' +
- encodeURIComponent(usr.toLowerCase()) +
- '&ProjectName=' +
- encodeURIComponent(prj);
- myself.showMessage(
- 'Fetching project\nfrom the cloud...'
- );
- SnapCloud.getPublicProject(
- id,
- function (projectData) {
- var msg;
- if (!Process.prototype.isCatchingErrors) {
- window.open(
- 'data:text/xml,' + projectData
- );
- }
- myself.nextSteps([
- function () {
- msg = myself.showMessage(
- 'Opening project...'
- );
- },
- function () {
- myself.rawOpenCloudDataString(
- projectData
- );
- },
- function () {
- msg.destroy();
- }
- ]);
- },
- myself.cloudError()
- );
-
- }, null, 'project');
- }, null, 'project');
- },
- null,
- new Color(100, 0, 0)
- );
}
menu.popup(world, pos);
};
@@ -3623,17 +3552,17 @@ IDE_Morph.prototype.initializeCloud = function () {
new DialogBoxMorph(
null,
function (user) {
- var pwh = hex_sha512(user.password),
+ var pw = user.password,
str;
SnapCloud.login(
user.username,
- pwh,
+ pw,
function () {
if (user.choice) {
str = SnapCloud.encodeDict(
{
username: user.username,
- password: pwh
+ password: pw
}
);
localStorage['-snap-user'] = str;
@@ -3658,128 +3587,14 @@ IDE_Morph.prototype.initializeCloud = function () {
);
};
-IDE_Morph.prototype.createCloudAccount = function () {
- var myself = this,
- world = this.world();
-/*
- // force-logout, commented out for now:
- delete localStorage['-snap-user'];
- SnapCloud.clear();
-*/
- new DialogBoxMorph(
- null,
- function (user) {
- SnapCloud.signup(
- user.username,
- user.email,
- function (txt, title) {
- new DialogBoxMorph().inform(
- title,
- txt +
- '.\n\nAn e-mail with your password\n' +
- 'has been sent to the address provided',
- world,
- myself.cloudIcon(null, new Color(0, 180, 0))
- );
- },
- myself.cloudError()
- );
- }
- ).withKey('cloudsignup').promptCredentials(
- 'Sign up',
- 'signup',
- 'http://snap.berkeley.edu/tos.html',
- 'Terms of Service...',
- 'http://snap.berkeley.edu/privacy.html',
- 'Privacy...',
- 'I have read and agree\nto the Terms of Service',
- world,
- myself.cloudIcon(),
- myself.cloudMsg
- );
-};
-
-IDE_Morph.prototype.resetCloudPassword = function () {
- var myself = this,
- world = this.world();
-/*
- // force-logout, commented out for now:
- delete localStorage['-snap-user'];
- SnapCloud.clear();
-*/
- new DialogBoxMorph(
- null,
- function (user) {
- SnapCloud.resetPassword(
- user.username,
- function (txt, title) {
- new DialogBoxMorph().inform(
- title,
- txt +
- '.\n\nAn e-mail with a link to\n' +
- 'reset your password\n' +
- 'has been sent to the address provided',
- world,
- myself.cloudIcon(null, new Color(0, 180, 0))
- );
- },
- myself.cloudError()
- );
- }
- ).withKey('cloudresetpassword').promptCredentials(
- 'Reset password',
- 'resetPassword',
- null,
- null,
- null,
- null,
- null,
- world,
- myself.cloudIcon(),
- myself.cloudMsg
- );
-};
-
-IDE_Morph.prototype.changeCloudPassword = function () {
- var myself = this,
- world = this.world();
- new DialogBoxMorph(
- null,
- function (user) {
- SnapCloud.changePassword(
- user.oldpassword,
- user.password,
- function () {
- myself.logout();
- myself.showMessage('password has been changed.', 2);
- },
- myself.cloudError()
- );
- }
- ).withKey('cloudpassword').promptCredentials(
- 'Change Password',
- 'changePassword',
- null,
- null,
- null,
- null,
- null,
- world,
- myself.cloudIcon(),
- myself.cloudMsg
- );
-};
-
IDE_Morph.prototype.logout = function () {
var myself = this;
delete localStorage['-snap-user'];
SnapCloud.logout(
function () {
- SnapCloud.clear();
myself.showMessage('disconnected.', 2);
},
function () {
- SnapCloud.clear();
myself.showMessage('disconnected.', 2);
}
);
@@ -4010,31 +3825,6 @@ IDE_Morph.prototype.cloudIcon = function (height, color) {
return icon;
};
-IDE_Morph.prototype.setCloudURL = function () {
- new DialogBoxMorph(
- null,
- function (url) {
- SnapCloud.url = url;
- }
- ).withKey('cloudURL').prompt(
- 'Cloud URL',
- SnapCloud.url,
- this.world(),
- null,
- {
- 'Snap!Cloud' :
- 'https://snapcloud.miosoft.com/miocon/app/' +
- 'login?_app=SnapCloud',
- 'local network lab' :
- '192.168.2.107:8087/miocon/app/login?_app=SnapCloud',
- 'local network office' :
- '192.168.186.146:8087/miocon/app/login?_app=SnapCloud',
- 'localhost dev' :
- 'localhost/miocon/app/login?_app=SnapCloud'
- }
- );
-};
-
// IDE_Morph synchronous Http data fetching
IDE_Morph.prototype.getURL = function (url) {
@@ -4142,8 +3932,6 @@ ProjectDialogMorph.prototype.init = function (ide, task) {
this.notesText = null;
this.notesField = null;
this.deleteButton = null;
- this.shareButton = null;
- this.unshareButton = null;
// initialize inherited properties:
ProjectDialogMorph.uber.init.call(
@@ -4283,10 +4071,6 @@ ProjectDialogMorph.prototype.buildContents = function () {
this.addButton('saveProject', 'Save');
this.action = 'saveProject';
}
- this.shareButton = this.addButton('shareProject', 'Share');
- this.unshareButton = this.addButton('unshareProject', 'Unshare');
- this.shareButton.hide();
- this.unshareButton.hide();
this.deleteButton = this.addButton('deleteProject', 'Delete');
this.addButton('cancel', 'Cancel');
@@ -4516,8 +4300,6 @@ ProjectDialogMorph.prototype.setSource = function (source) {
};
}
this.body.add(this.listField);
- this.shareButton.hide();
- this.unshareButton.hide();
if (this.source === 'local') {
this.deleteButton.show();
} else { // examples
@@ -4594,12 +4376,7 @@ ProjectDialogMorph.prototype.installCloudProjectList = function (pl) {
function (element) {
return element.ProjectName;
} : null,
- [ // format: display shared project names bold
- [
- 'bold',
- function (proj) {return proj.Public === 'true'; }
- ]
- ],
+ [],
function () {myself.ok(); }
);
this.fixListFieldItemColors();
@@ -4635,20 +4412,11 @@ ProjectDialogMorph.prototype.installCloudProjectList = function (pl) {
myself.preview.rightCenter().add(new Point(2, 0))
);
}
- if (item.Public === 'true') {
- myself.shareButton.hide();
- myself.unshareButton.show();
- } else {
- myself.unshareButton.hide();
- myself.shareButton.show();
- }
myself.buttons.fixLayout();
myself.fixLayout();
myself.edit();
};
this.body.add(this.listField);
- this.shareButton.show();
- this.unshareButton.hide();
this.deleteButton.show();
this.buttons.fixLayout();
this.fixLayout();
@@ -4700,24 +4468,12 @@ ProjectDialogMorph.prototype.openCloudProject = function (project) {
ProjectDialogMorph.prototype.rawOpenCloudProject = function (proj) {
var myself = this;
- SnapCloud.reconnect(
- function () {
- SnapCloud.callService(
- 'getProject',
- function (response) {
- SnapCloud.disconnect();
- myself.ide.source = 'cloud';
- myself.ide.droppedText(response[0].SourceCode);
- if (proj.Public === 'true') {
- location.hash = '#present:Username=' +
- encodeURIComponent(SnapCloud.username) +
- '&ProjectName=' +
- encodeURIComponent(proj.ProjectName);
- }
- },
- myself.ide.cloudError(),
- [proj.ProjectName]
- );
+ SnapCloud.getProject(
+ {'projectname': proj.ProjectName, 'username': SnapCloud.username},
+ function (code, media) {
+ myself.ide.source = 'cloud';
+ myself.ide.droppedText(media);
+ myself.ide.droppedText(code);
},
myself.ide.cloudError()
);
@@ -4791,141 +4547,6 @@ ProjectDialogMorph.prototype.saveCloudProject = function () {
this.destroy();
};
-ProjectDialogMorph.prototype.deleteProject = function () {
- var myself = this,
- proj,
- idx,
- name;
-
- if (this.source === 'cloud') {
- proj = this.listField.selected;
- if (proj) {
- this.ide.confirm(
- localize(
- 'Are you sure you want to delete'
- ) + '\n"' + proj.ProjectName + '"?',
- 'Delete Project',
- function () {
- SnapCloud.reconnect(
- function () {
- SnapCloud.callService(
- 'deleteProject',
- function () {
- SnapCloud.disconnect();
- myself.ide.hasChangedMedia = true;
- idx = myself.projectList.indexOf(proj);
- myself.projectList.splice(idx, 1);
- myself.installCloudProjectList(
- myself.projectList
- ); // refresh list
- },
- myself.ide.cloudError(),
- [proj.ProjectName]
- );
- },
- myself.ide.cloudError()
- );
- }
- );
- }
- } else { // 'local, examples'
- if (this.listField.selected) {
- name = this.listField.selected.name;
- this.ide.confirm(
- localize(
- 'Are you sure you want to delete'
- ) + '\n"' + name + '"?',
- 'Delete Project',
- function () {
- delete localStorage['-snap-project-' + name];
- myself.setSource(myself.source); // refresh list
- }
- );
- }
- }
-};
-
-ProjectDialogMorph.prototype.shareProject = function () {
- var myself = this,
- proj = this.listField.selected,
- entry = this.listField.active;
-
- if (proj) {
- this.ide.confirm(
- localize(
- 'Are you sure you want to publish'
- ) + '\n"' + proj.ProjectName + '"?',
- 'Share Project',
- function () {
- myself.ide.showMessage('sharing\nproject...');
- SnapCloud.reconnect(
- function () {
- SnapCloud.callService(
- 'publishProject',
- function () {
- SnapCloud.disconnect();
- proj.Public = 'true';
- myself.unshareButton.show();
- myself.shareButton.hide();
- entry.label.isBold = true;
- entry.label.drawNew();
- entry.label.changed();
- myself.buttons.fixLayout();
- myself.drawNew();
- myself.ide.showMessage('shared.', 2);
- },
- myself.ide.cloudError(),
- [proj.ProjectName]
- );
- },
- myself.ide.cloudError()
- );
- }
- );
- }
-};
-
-ProjectDialogMorph.prototype.unshareProject = function () {
- var myself = this,
- proj = this.listField.selected,
- entry = this.listField.active;
-
-
- if (proj) {
- this.ide.confirm(
- localize(
- 'Are you sure you want to unpublish'
- ) + '\n"' + proj.ProjectName + '"?',
- 'Unshare Project',
- function () {
- myself.ide.showMessage('unsharing\nproject...');
- SnapCloud.reconnect(
- function () {
- SnapCloud.callService(
- 'unpublishProject',
- function () {
- SnapCloud.disconnect();
- proj.Public = 'false';
- myself.shareButton.show();
- myself.unshareButton.hide();
- entry.label.isBold = false;
- entry.label.drawNew();
- entry.label.changed();
- myself.buttons.fixLayout();
- myself.drawNew();
- myself.ide.showMessage('unshared.', 2);
- },
- myself.ide.cloudError(),
- [proj.ProjectName]
- );
- },
- myself.ide.cloudError()
- );
- }
- );
- }
-};
-
ProjectDialogMorph.prototype.edit = function () {
if (this.nameField) {
this.nameField.edit();
diff --git a/octokit/octokit.js b/octokit/octokit.js
new file mode 100644
index 0000000..40d8576
--- /dev/null
+++ b/octokit/octokit.js
@@ -0,0 +1,1465 @@
+(function() {
+ var Octokit, Promise, XMLHttpRequest, allPromises, createGlobalAndAMD, encode, err, injector, makeOctokit, newPromise, _, _ref,
+ _this = this,
+ __hasProp = {}.hasOwnProperty,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+ __slice = [].slice;
+
+ _ = {};
+
+ _.isEmpty = function(object) {
+ return Object.keys(object).length === 0;
+ };
+
+ _.isArray = function(object) {
+ return !!(object != null ? object.slice : void 0);
+ };
+
+ _.defaults = function(object, values) {
+ var key, _i, _len, _ref, _results;
+ _ref = Object.keys(values);
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ key = _ref[_i];
+ _results.push((function(key) {
+ return object[key] != null ? object[key] : object[key] = values[key];
+ })(key));
+ }
+ return _results;
+ };
+
+ _.each = function(object, fn) {
+ var arr, key, _i, _len, _ref, _results;
+ if (!object) {
+ return;
+ }
+ if (_.isArray(object)) {
+ object.forEach(fn);
+ }
+ arr = [];
+ _ref = Object.keys(object);
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ key = _ref[_i];
+ _results.push((function(key) {
+ return fn(object[key]);
+ })(key));
+ }
+ return _results;
+ };
+
+ _.pairs = function(object) {
+ var arr, key, _fn, _i, _len, _ref;
+ arr = [];
+ _ref = Object.keys(object);
+ _fn = function(key) {
+ return arr.push([key, object[key]]);
+ };
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ key = _ref[_i];
+ _fn(key);
+ }
+ return arr;
+ };
+
+ _.map = function(object, fn) {
+ var arr, key, _fn, _i, _len, _ref;
+ if (_.isArray(object)) {
+ return object.map(fn);
+ }
+ arr = [];
+ _ref = Object.keys(object);
+ _fn = function(key) {
+ return arr.push(fn(object[key]));
+ };
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ key = _ref[_i];
+ _fn(key);
+ }
+ return arr;
+ };
+
+ _.last = function(object, n) {
+ var len;
+ len = object.length;
+ return object.slice(len - n, len);
+ };
+
+ _.select = function(object, fn) {
+ return object.filter(fn);
+ };
+
+ _.extend = function(object, template) {
+ var key, _fn, _i, _len, _ref;
+ _ref = Object.keys(template);
+ _fn = function(key) {
+ return object[key] = template[key];
+ };
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ key = _ref[_i];
+ _fn(key);
+ }
+ return object;
+ };
+
+ _.toArray = function(object) {
+ return Array.prototype.slice.call(object);
+ };
+
+ makeOctokit = function(newPromise, allPromises, XMLHttpRequest, base64encode, userAgent) {
+ var Octokit, ajax, rejectedPromise, resolvedPromise;
+ ajax = function(options) {
+ return newPromise(function(resolve, reject) {
+ var name, value, xhr, _ref;
+ xhr = new XMLHttpRequest();
+ xhr.dataType = options.dataType;
+ if (typeof xhr.overrideMimeType === "function") {
+ xhr.overrideMimeType(options.mimeType);
+ }
+ xhr.open(options.type, options.url);
+ if (options.data && 'GET' !== options.type) {
+ xhr.setRequestHeader('Content-Type', options.contentType);
+ }
+ _ref = options.headers;
+ for (name in _ref) {
+ value = _ref[name];
+ xhr.setRequestHeader(name, value);
+ }
+ xhr.onreadystatechange = function() {
+ var _name, _ref1;
+ if (4 === xhr.readyState) {
+ if ((_ref1 = options.statusCode) != null) {
+ if (typeof _ref1[_name = xhr.status] === "function") {
+ _ref1[_name]();
+ }
+ }
+ if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
+ return resolve(xhr);
+ } else {
+ return reject(xhr);
+ }
+ }
+ };
+ return xhr.send(options.data);
+ });
+ };
+ resolvedPromise = function(val) {
+ return newPromise(function(resolve, reject) {
+ return resolve(val);
+ });
+ };
+ rejectedPromise = function(err) {
+ return newPromise(function(resolve, reject) {
+ return reject(err);
+ });
+ };
+ Octokit = (function() {
+ function Octokit(clientOptions) {
+ var AuthenticatedUser, Branch, ETagResponse, Gist, GitRepo, Organization, Repository, Team, User, clearCache, getCache, notifyEnd, notifyStart, setCache, toQueryString, _cachedETags, _client, _listeners, _request;
+ if (clientOptions == null) {
+ clientOptions = {};
+ }
+ _.defaults(clientOptions, {
+ rootURL: 'https://api.github.com',
+ useETags: true,
+ usePostInsteadOfPatch: false
+ });
+ _client = this;
+ _listeners = [];
+ ETagResponse = (function() {
+ function ETagResponse(eTag, data, status) {
+ this.eTag = eTag;
+ this.data = data;
+ this.status = status;
+ }
+
+ return ETagResponse;
+
+ })();
+ _cachedETags = {};
+ notifyStart = function(promise, path) {
+ return typeof promise.notify === "function" ? promise.notify({
+ type: 'start',
+ path: path
+ }) : void 0;
+ };
+ notifyEnd = function(promise, path) {
+ return typeof promise.notify === "function" ? promise.notify({
+ type: 'end',
+ path: path
+ }) : void 0;
+ };
+ _request = function(method, path, data, options) {
+ var auth, headers, mimeType, promise;
+ if (options == null) {
+ options = {
+ raw: false,
+ isBase64: false,
+ isBoolean: false
+ };
+ }
+ if ('PATCH' === method && clientOptions.usePostInsteadOfPatch) {
+ method = 'POST';
+ }
+ if (!/^http/.test(path)) {
+ path = "" + clientOptions.rootURL + path;
+ }
+ mimeType = void 0;
+ if (options.isBase64) {
+ mimeType = 'text/plain; charset=x-user-defined';
+ }
+ headers = {
+ 'Accept': 'application/vnd.github.raw'
+ };
+ if (userAgent) {
+ headers['User-Agent'] = userAgent;
+ }
+ if (path in _cachedETags) {
+ headers['If-None-Match'] = _cachedETags[path].eTag;
+ } else {
+ headers['If-Modified-Since'] = 'Thu, 01 Jan 1970 00:00:00 GMT';
+ }
+ if (clientOptions.token || (clientOptions.username && clientOptions.password)) {
+ if (clientOptions.token) {
+ auth = "token " + clientOptions.token;
+ } else {
+ auth = 'Basic ' + base64encode("" + clientOptions.username + ":" + clientOptions.password);
+ }
+ headers['Authorization'] = auth;
+ }
+ promise = newPromise(function(resolve, reject) {
+ var ajaxConfig, always, onError, xhrPromise,
+ _this = this;
+ ajaxConfig = {
+ url: path,
+ type: method,
+ contentType: 'application/json',
+ mimeType: mimeType,
+ headers: headers,
+ processData: false,
+ data: !options.raw && data && JSON.stringify(data) || data,
+ dataType: !options.raw ? 'json' : void 0
+ };
+ if (options.isBoolean) {
+ ajaxConfig.statusCode = {
+ 204: function() {
+ return resolve(true);
+ },
+ 404: function() {
+ return resolve(false);
+ }
+ };
+ }
+ xhrPromise = ajax(ajaxConfig);
+ always = function(jqXHR) {
+ var listener, rateLimit, rateLimitRemaining, _i, _len, _results;
+ notifyEnd(_this, path);
+ rateLimit = parseFloat(jqXHR.getResponseHeader('X-RateLimit-Limit'));
+ rateLimitRemaining = parseFloat(jqXHR.getResponseHeader('X-RateLimit-Remaining'));
+ _results = [];
+ for (_i = 0, _len = _listeners.length; _i < _len; _i++) {
+ listener = _listeners[_i];
+ _results.push(listener(rateLimitRemaining, rateLimit, method, path, data, options));
+ }
+ return _results;
+ };
+ xhrPromise.then(function(jqXHR) {
+ var converted, eTag, eTagResponse, i, links, valOptions, _i, _ref;
+ always(jqXHR);
+ if (304 === jqXHR.status) {
+ if (clientOptions.useETags && _cachedETags[path]) {
+ eTagResponse = _cachedETags[path];
+ return resolve(eTagResponse.data, eTagResponse.status, jqXHR);
+ } else {
+ return resolve(jqXHR.responseText, status, jqXHR);
+ }
+ } else if (204 === jqXHR.status && options.isBoolean) {
+ return resolve(true, status, jqXHR);
+ } else {
+ if (jqXHR.responseText && 'json' === ajaxConfig.dataType) {
+ data = JSON.parse(jqXHR.responseText);
+ valOptions = {};
+ links = jqXHR.getResponseHeader('Link');
+ _.each(links != null ? links.split(',') : void 0, function(part) {
+ var discard, href, rel, _ref;
+ _ref = part.match(/<([^>]+)>;\ rel="([^"]+)"/), discard = _ref[0], href = _ref[1], rel = _ref[2];
+ return valOptions["" + rel + "Page"] = function() {
+ return _request('GET', href, null, options);
+ };
+ });
+ _.extend(data, valOptions);
+ } else {
+ data = jqXHR.responseText;
+ }
+ if ('GET' === method && options.isBase64) {
+ converted = '';
+ for (i = _i = 0, _ref = data.length; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
+ converted += String.fromCharCode(data.charCodeAt(i) & 0xff);
+ }
+ data = converted;
+ }
+ if ('GET' === method && jqXHR.getResponseHeader('ETag') && clientOptions.useETags) {
+ eTag = jqXHR.getResponseHeader('ETag');
+ _cachedETags[path] = new ETagResponse(eTag, data, jqXHR.status);
+ }
+ return resolve(data, jqXHR.status, jqXHR);
+ }
+ });
+ onError = function(jqXHR) {
+ var err, json;
+ always(jqXHR);
+ if (options.isBoolean && 404 === jqXHR.status) {
+ return resolve(false);
+ } else {
+ if (jqXHR.getResponseHeader('Content-Type') !== 'application/json; charset=utf-8') {
+ err = new Error(jqXHR.responseText);
+ err['status'] = jqXHR.status;
+ err['__jqXHR'] = jqXHR;
+ return reject(err);
+ } else {
+ err = new Error("Github error: " + jqXHR.responseText);
+ if (jqXHR.responseText) {
+ json = JSON.parse(jqXHR.responseText);
+ } else {
+ json = '';
+ }
+ err['error'] = json;
+ err['status'] = jqXHR.status;
+ err['__jqXHR'] = jqXHR;
+ return reject(err);
+ }
+ }
+ };
+ return (typeof xhrPromise["catch"] === "function" ? xhrPromise["catch"](onError) : void 0) || xhrPromise.fail(onError);
+ });
+ notifyStart(promise, path);
+ return promise;
+ };
+ toQueryString = function(options) {
+ var params;
+ if (_.isEmpty(options)) {
+ return '';
+ }
+ params = [];
+ _.each(_.pairs(options), function(_arg) {
+ var key, value;
+ key = _arg[0], value = _arg[1];
+ return params.push("" + key + "=" + (encodeURIComponent(value)));
+ });
+ return "?" + (params.join('&'));
+ };
+ this.clearCache = clearCache = function() {
+ return _cachedETags = {};
+ };
+ this.getCache = getCache = function() {
+ return _cachedETags;
+ };
+ this.setCache = setCache = function(cachedETags) {
+ if (!(cachedETags !== null && typeof cachedETags === 'object')) {
+ throw new Error('BUG: argument of method "setCache" should be an object');
+ } else {
+ return _cachedETags = cachedETags;
+ }
+ };
+ this.onRateLimitChanged = function(listener) {
+ return _listeners.push(listener);
+ };
+ this.getZen = function() {
+ return _request('GET', '/zen', null, {
+ raw: true
+ });
+ };
+ this.getAllUsers = function(since) {
+ var options;
+ if (since == null) {
+ since = null;
+ }
+ options = {};
+ if (since) {
+ options.since = since;
+ }
+ return _request('GET', '/users', options);
+ };
+ this.getOrgRepos = function(orgName, type) {
+ if (type == null) {
+ type = 'all';
+ }
+ return _request('GET', "/orgs/" + orgName + "/repos?type=" + type + "&per_page=1000&sort=updated&direction=desc", null);
+ };
+ this.getPublicGists = function(since) {
+ var getDate, options;
+ if (since == null) {
+ since = null;
+ }
+ options = null;
+ getDate = function(time) {
+ if (Date === time.constructor) {
+ return time.toISOString();
+ }
+ return time;
+ };
+ if (since) {
+ options = {
+ since: getDate(since)
+ };
+ }
+ return _request('GET', '/gists/public', options);
+ };
+ this.getPublicEvents = function() {
+ return _request('GET', '/events', null);
+ };
+ this.getNotifications = function(options) {
+ var getDate, queryString;
+ if (options == null) {
+ options = {};
+ }
+ getDate = function(time) {
+ if (Date === time.constructor) {
+ return time.toISOString();
+ }
+ return time;
+ };
+ if (options.since) {
+ options.since = getDate(options.since);
+ }
+ queryString = toQueryString(options);
+ return _request('GET', "/notifications" + queryString, null);
+ };
+ User = (function() {
+ function User(_username) {
+ var _cachedInfo, _rootPath;
+ if (_username == null) {
+ _username = null;
+ }
+ if (_username) {
+ _rootPath = "/users/" + _username;
+ } else {
+ _rootPath = "/user";
+ }
+ _cachedInfo = null;
+ this.getInfo = function(force) {
+ if (force == null) {
+ force = false;
+ }
+ if (force) {
+ _cachedInfo = null;
+ }
+ if (_cachedInfo) {
+ return resolvedPromise(_cachedInfo);
+ }
+ return _request('GET', "" + _rootPath, null).then(function(info) {
+ return _cachedInfo = info;
+ });
+ };
+ this.getRepos = function(type, sort, direction) {
+ if (type == null) {
+ type = 'all';
+ }
+ if (sort == null) {
+ sort = 'pushed';
+ }
+ if (direction == null) {
+ direction = 'desc';
+ }
+ return _request('GET', "" + _rootPath + "/repos?type=" + type + "&per_page=1000&sort=" + sort + "&direction=" + direction, null);
+ };
+ this.getOrgs = function() {
+ return _request('GET', "" + _rootPath + "/orgs", null);
+ };
+ this.getGists = function() {
+ return _request('GET', "" + _rootPath + "/gists", null);
+ };
+ this.getFollowers = function() {
+ return _request('GET', "" + _rootPath + "/followers", null);
+ };
+ this.getFollowing = function() {
+ return _request('GET', "" + _rootPath + "/following", null);
+ };
+ this.isFollowing = function(user) {
+ return _request('GET', "" + _rootPath + "/following/" + user, null, {
+ isBoolean: true
+ });
+ };
+ this.getPublicKeys = function() {
+ return _request('GET', "" + _rootPath + "/keys", null);
+ };
+ this.getReceivedEvents = function(onlyPublic) {
+ var isPublic;
+ if (!_username) {
+ throw new Error('BUG: This does not work for authenticated users yet!');
+ }
+ isPublic = '';
+ if (onlyPublic) {
+ isPublic = '/public';
+ }
+ return _request('GET', "/users/" + _username + "/received_events" + isPublic, null);
+ };
+ this.getEvents = function(onlyPublic) {
+ var isPublic;
+ if (!_username) {
+ throw new Error('BUG: This does not work for authenticated users yet!');
+ }
+ isPublic = '';
+ if (onlyPublic) {
+ isPublic = '/public';
+ }
+ return _request('GET', "/users/" + _username + "/events" + isPublic, null);
+ };
+ }
+
+ return User;
+
+ })();
+ AuthenticatedUser = (function(_super) {
+ __extends(AuthenticatedUser, _super);
+
+ function AuthenticatedUser() {
+ AuthenticatedUser.__super__.constructor.call(this);
+ this.updateInfo = function(options) {
+ return _request('PATCH', '/user', options);
+ };
+ this.getGists = function() {
+ return _request('GET', '/gists', null);
+ };
+ this.follow = function(username) {
+ return _request('PUT', "/user/following/" + username, null);
+ };
+ this.unfollow = function(username) {
+ return _request('DELETE', "/user/following/" + username, null);
+ };
+ this.getEmails = function() {
+ return _request('GET', '/user/emails', null);
+ };
+ this.addEmail = function(emails) {
+ if (!_.isArray(emails)) {
+ emails = [emails];
+ }
+ return _request('POST', '/user/emails', emails);
+ };
+ this.addEmail = function(emails) {
+ if (!_.isArray(emails)) {
+ emails = [emails];
+ }
+ return _request('DELETE', '/user/emails', emails);
+ };
+ this.getPublicKey = function(id) {
+ return _request('GET', "/user/keys/" + id, null);
+ };
+ this.addPublicKey = function(title, key) {
+ return _request('POST', "/user/keys", {
+ title: title,
+ key: key
+ });
+ };
+ this.updatePublicKey = function(id, options) {
+ return _request('PATCH', "/user/keys/" + id, options);
+ };
+ this.createRepo = function(name, options) {
+ if (options == null) {
+ options = {};
+ }
+ options.name = name;
+ return _request('POST', "/user/repos", options);
+ };
+ this.getReceivedEvents = function(username, page) {
+ var currentPage;
+ if (page == null) {
+ page = 1;
+ }
+ currentPage = '?page=' + page;
+ return _request('GET', '/users/' + username + '/received_events' + currentPage, null);
+ };
+ }
+
+ return AuthenticatedUser;
+
+ })(User);
+ Team = (function() {
+ function Team(id) {
+ this.id = id;
+ this.getInfo = function() {
+ return _request('GET', "/teams/" + this.id, null);
+ };
+ this.updateTeam = function(options) {
+ return _request('PATCH', "/teams/" + this.id, options);
+ };
+ this.remove = function() {
+ return _request('DELETE', "/teams/" + this.id);
+ };
+ this.getMembers = function() {
+ return _request('GET', "/teams/" + this.id + "/members");
+ };
+ this.isMember = function(user) {
+ return _request('GET', "/teams/" + this.id + "/members/" + user, null, {
+ isBoolean: true
+ });
+ };
+ this.addMember = function(user) {
+ return _request('PUT', "/teams/" + this.id + "/members/" + user);
+ };
+ this.removeMember = function(user) {
+ return _request('DELETE', "/teams/" + this.id + "/members/" + user);
+ };
+ this.getRepos = function() {
+ return _request('GET', "/teams/" + this.id + "/repos");
+ };
+ this.addRepo = function(orgName, repoName) {
+ return _request('PUT', "/teams/" + this.id + "/repos/" + orgName + "/" + repoName);
+ };
+ this.removeRepo = function(orgName, repoName) {
+ return _request('DELETE', "/teams/" + this.id + "/repos/" + orgName + "/" + repoName);
+ };
+ }
+
+ return Team;
+
+ })();
+ Organization = (function() {
+ function Organization(name) {
+ this.name = name;
+ this.getInfo = function() {
+ return _request('GET', "/orgs/" + this.name, null);
+ };
+ this.updateInfo = function(options) {
+ return _request('PATCH', "/orgs/" + this.name, options);
+ };
+ this.getTeams = function() {
+ return _request('GET', "/orgs/" + this.name + "/teams", null);
+ };
+ this.createTeam = function(name, repoNames, permission) {
+ var options;
+ if (repoNames == null) {
+ repoNames = null;
+ }
+ if (permission == null) {
+ permission = 'pull';
+ }
+ options = {
+ name: name,
+ permission: permission
+ };
+ if (repoNames) {
+ options.repo_names = repoNames;
+ }
+ return _request('POST', "/orgs/" + this.name + "/teams", options);
+ };
+ this.getMembers = function() {
+ return _request('GET', "/orgs/" + this.name + "/members", null);
+ };
+ this.isMember = function(user) {
+ return _request('GET', "/orgs/" + this.name + "/members/" + user, null, {
+ isBoolean: true
+ });
+ };
+ this.removeMember = function(user) {
+ return _request('DELETE', "/orgs/" + this.name + "/members/" + user, null);
+ };
+ this.createRepo = function(name, options) {
+ if (options == null) {
+ options = {};
+ }
+ options.name = name;
+ return _request('POST', "/orgs/" + this.name + "/repos", options);
+ };
+ this.getRepos = function() {
+ return _request('GET', "/orgs/" + this.name + "/repos?type=all", null);
+ };
+ }
+
+ return Organization;
+
+ })();
+ GitRepo = (function() {
+ function GitRepo(repoUser, repoName) {
+ var _repoPath;
+ this.repoUser = repoUser;
+ this.repoName = repoName;
+ _repoPath = "/repos/" + this.repoUser + "/" + this.repoName;
+ this.deleteRepo = function() {
+ return _request('DELETE', "" + _repoPath);
+ };
+ this._updateTree = function(branch) {
+ return this.getRef("heads/" + branch);
+ };
+ this.getRef = function(ref) {
+ var _this = this;
+ return _request('GET', "" + _repoPath + "/git/refs/" + ref, null).then(function(res) {
+ return res.object.sha;
+ });
+ };
+ this.createRef = function(options) {
+ return _request('POST', "" + _repoPath + "/git/refs", options);
+ };
+ this.deleteRef = function(ref) {
+ return _request('DELETE', "" + _repoPath + "/git/refs/" + ref, this.options);
+ };
+ this.getBranches = function() {
+ var _this = this;
+ return _request('GET', "" + _repoPath + "/git/refs/heads", null).then(function(heads) {
+ return _.map(heads, function(head) {
+ return _.last(head.ref.split("/"));
+ });
+ });
+ };
+ this.getBlob = function(sha, isBase64) {
+ return _request('GET', "" + _repoPath + "/git/blobs/" + sha, null, {
+ raw: true,
+ isBase64: isBase64
+ });
+ };
+ this.getSha = function(branch, path) {
+ var _this = this;
+ if (path === '') {
+ return this.getRef("heads/" + branch);
+ }
+ return this.getTree(branch, {
+ recursive: true
+ }).then(function(tree) {
+ var file;
+ file = _.select(tree, function(file) {
+ return file.path === path;
+ })[0];
+ if (file != null ? file.sha : void 0) {
+ return file != null ? file.sha : void 0;
+ }
+ return rejectedPromise({
+ message: 'SHA_NOT_FOUND'
+ });
+ });
+ };
+ this.getContents = function(path, sha) {
+ var queryString,
+ _this = this;
+ if (sha == null) {
+ sha = null;
+ }
+ queryString = '';
+ if (sha !== null) {
+ queryString = toQueryString({
+ ref: sha
+ });
+ }
+ return _request('GET', "" + _repoPath + "/contents/" + path + queryString, null, {
+ raw: true
+ }).then(function(contents) {
+ return contents;
+ });
+ };
+ this.removeFile = function(path, message, sha, branch) {
+ var params;
+ params = {
+ message: message,
+ sha: sha,
+ branch: branch
+ };
+ return _request('DELETE', "" + _repoPath + "/contents/" + path, params, null);
+ };
+ this.getTree = function(tree, options) {
+ var queryString,
+ _this = this;
+ if (options == null) {
+ options = null;
+ }
+ queryString = toQueryString(options);
+ return _request('GET', "" + _repoPath + "/git/trees/" + tree + queryString, null).then(function(res) {
+ return res.tree;
+ });
+ };
+ this.postBlob = function(content, isBase64) {
+ var _this = this;
+ if (typeof content === 'string') {
+ if (isBase64) {
+ content = base64encode(content);
+ }
+ content = {
+ content: content,
+ encoding: 'utf-8'
+ };
+ }
+ if (isBase64) {
+ content.encoding = 'base64';
+ }
+ return _request('POST', "" + _repoPath + "/git/blobs", content).then(function(res) {
+ return res.sha;
+ });
+ };
+ this.updateTreeMany = function(baseTree, newTree) {
+ var data,
+ _this = this;
+ data = {
+ base_tree: baseTree,
+ tree: newTree
+ };
+ return _request('POST', "" + _repoPath + "/git/trees", data).then(function(res) {
+ return res.sha;
+ });
+ };
+ this.postTree = function(tree) {
+ var _this = this;
+ return _request('POST', "" + _repoPath + "/git/trees", {
+ tree: tree
+ }).then(function(res) {
+ return res.sha;
+ });
+ };
+ this.commit = function(parents, tree, message) {
+ var data;
+ if (!_.isArray(parents)) {
+ parents = [parents];
+ }
+ data = {
+ message: message,
+ parents: parents,
+ tree: tree
+ };
+ return _request('POST', "" + _repoPath + "/git/commits", data).then(function(commit) {
+ return commit.sha;
+ });
+ };
+ this.updateHead = function(head, commit, force) {
+ var options;
+ if (force == null) {
+ force = false;
+ }
+ options = {
+ sha: commit
+ };
+ if (force) {
+ options.force = true;
+ }
+ return _request('PATCH', "" + _repoPath + "/git/refs/heads/" + head, options);
+ };
+ this.getCommit = function(sha) {
+ return _request('GET', "" + _repoPath + "/commits/" + sha, null);
+ };
+ this.getCommits = function(options) {
+ var getDate, queryString;
+ if (options == null) {
+ options = {};
+ }
+ options = _.extend({}, options);
+ getDate = function(time) {
+ if (Date === time.constructor) {
+ return time.toISOString();
+ }
+ return time;
+ };
+ if (options.since) {
+ options.since = getDate(options.since);
+ }
+ if (options.until) {
+ options.until = getDate(options.until);
+ }
+ queryString = toQueryString(options);
+ return _request('GET', "" + _repoPath + "/commits" + queryString, null);
+ };
+ }
+
+ return GitRepo;
+
+ })();
+ Branch = (function() {
+ function Branch(git, getRef) {
+ var _getRef, _git;
+ _git = git;
+ _getRef = getRef || function() {
+ throw new Error('BUG: No way to fetch branch ref!');
+ };
+ this.getCommit = function(sha) {
+ return _git.getCommit(sha);
+ };
+ this.getCommits = function(options) {
+ if (options == null) {
+ options = {};
+ }
+ options = _.extend({}, options);
+ return _getRef().then(function(branch) {
+ options.sha = branch;
+ return _git.getCommits(options);
+ });
+ };
+ this.createBranch = function(newBranchName) {
+ var _this = this;
+ return _getRef().then(function(branch) {
+ return _git.getSha(branch, '').then(function(sha) {
+ return _git.createRef({
+ sha: sha,
+ ref: "refs/heads/" + newBranchName
+ });
+ });
+ });
+ };
+ this.read = function(path, isBase64) {
+ var _this = this;
+ return _getRef().then(function(branch) {
+ return _git.getSha(branch, path).then(function(sha) {
+ return _git.getBlob(sha, isBase64).then(function(bytes) {
+ return {
+ sha: sha,
+ content: bytes
+ };
+ });
+ });
+ });
+ };
+ this.contents = function(path) {
+ var _this = this;
+ return _getRef().then(function(branch) {
+ return _git.getSha(branch, '').then(function(sha) {
+ return _git.getContents(path, sha).then(function(contents) {
+ return contents;
+ });
+ });
+ });
+ };
+ this.remove = function(path, message, sha) {
+ var _this = this;
+ if (message == null) {
+ message = "Removed " + path;
+ }
+ if (sha == null) {
+ sha = null;
+ }
+ return _getRef().then(function(branch) {
+ if (sha) {
+ return _git.removeFile(path, message, sha, branch);
+ } else {
+ return _git.getSha(branch, path).then(function(sha) {
+ return _git.removeFile(path, message, sha, branch);
+ });
+ }
+ });
+ };
+ this.move = function(path, newPath, message) {
+ var _this = this;
+ if (message == null) {
+ message = "Moved " + path;
+ }
+ return _getRef().then(function(branch) {
+ return _git._updateTree(branch).then(function(latestCommit) {
+ return _git.getTree(latestCommit, {
+ recursive: true
+ }).then(function(tree) {
+ _.each(tree, function(ref) {
+ if (ref.path === path) {
+ ref.path = newPath;
+ }
+ if (ref.type === 'tree') {
+ return delete ref.sha;
+ }
+ });
+ return _git.postTree(tree).then(function(rootTree) {
+ return _git.commit(latestCommit, rootTree, message).then(function(commit) {
+ return _git.updateHead(branch, commit).then(function(res) {
+ return res;
+ });
+ });
+ });
+ });
+ });
+ });
+ };
+ this.write = function(path, content, message, isBase64, parentCommitSha) {
+ var contents;
+ if (message == null) {
+ message = "Changed " + path;
+ }
+ if (parentCommitSha == null) {
+ parentCommitSha = null;
+ }
+ contents = {};
+ contents[path] = {
+ content: content,
+ isBase64: isBase64
+ };
+ return this.writeMany(contents, message, parentCommitSha);
+ };
+ this.writeMany = function(contents, message, parentCommitShas) {
+ var _this = this;
+ if (message == null) {
+ message = "Changed Multiple";
+ }
+ if (parentCommitShas == null) {
+ parentCommitShas = null;
+ }
+ return _getRef().then(function(branch) {
+ var afterParentCommitShas;
+ afterParentCommitShas = function(parentCommitShas) {
+ var promises;
+ promises = _.map(_.pairs(contents), function(_arg) {
+ var content, data, isBase64, path,
+ _this = this;
+ path = _arg[0], data = _arg[1];
+ content = data.content || data;
+ isBase64 = data.isBase64 || false;
+ return _git.postBlob(content, isBase64).then(function(blob) {
+ return {
+ path: path,
+ mode: '100644',
+ type: 'blob',
+ sha: blob
+ };
+ });
+ });
+ return allPromises(promises).then(function(newTrees) {
+ return _git.updateTreeMany(parentCommitShas, newTrees).then(function(tree) {
+ return _git.commit(parentCommitShas, tree, message).then(function(commitSha) {
+ return _git.updateHead(branch, commitSha).then(function(res) {
+ return res.object;
+ });
+ });
+ });
+ });
+ };
+ if (parentCommitShas) {
+ return afterParentCommitShas(parentCommitShas);
+ } else {
+ return _git._updateTree(branch).then(afterParentCommitShas);
+ }
+ });
+ };
+ }
+
+ return Branch;
+
+ })();
+ Repository = (function() {
+ function Repository(options) {
+ var _repo, _user;
+ this.options = options;
+ _user = this.options.user;
+ _repo = this.options.name;
+ this.git = new GitRepo(_user, _repo);
+ this.repoPath = "/repos/" + _user + "/" + _repo;
+ this.currentTree = {
+ branch: null,
+ sha: null
+ };
+ this.updateInfo = function(options) {
+ return _request('PATCH', this.repoPath, options);
+ };
+ this.getBranches = function() {
+ return this.git.getBranches();
+ };
+ this.getBranch = function(branchName) {
+ var getRef,
+ _this = this;
+ if (branchName == null) {
+ branchName = null;
+ }
+ if (branchName) {
+ getRef = function() {
+ return resolvedPromise(branchName);
+ };
+ return new Branch(this.git, getRef);
+ } else {
+ return this.getDefaultBranch();
+ }
+ };
+ this.getDefaultBranch = function() {
+ var getRef,
+ _this = this;
+ getRef = function() {
+ return _this.getInfo().then(function(info) {
+ return info.default_branch;
+ });
+ };
+ return new Branch(this.git, getRef);
+ };
+ this.setDefaultBranch = function(branchName) {
+ return this.updateInfo({
+ name: _repo,
+ default_branch: branchName
+ });
+ };
+ this.getInfo = function() {
+ return _request('GET', this.repoPath, null);
+ };
+ this.getContents = function(branch, path) {
+ return _request('GET', "" + this.repoPath + "/contents?ref=" + branch, {
+ path: path
+ });
+ };
+ this.fork = function(organization) {
+ if (organization) {
+ return _request('POST', "" + this.repoPath + "/forks", {
+ organization: organization
+ });
+ } else {
+ return _request('POST', "" + this.repoPath + "/forks", null);
+ }
+ };
+ this.createPullRequest = function(options) {
+ return _request('POST', "" + this.repoPath + "/pulls", options);
+ };
+ this.getCommits = function(options) {
+ return this.git.getCommits(options);
+ };
+ this.getEvents = function() {
+ return _request('GET', "" + this.repoPath + "/events", null);
+ };
+ this.getIssueEvents = function() {
+ return _request('GET', "" + this.repoPath + "/issues/events", null);
+ };
+ this.getNetworkEvents = function() {
+ return _request('GET', "/networks/" + _user + "/" + _repo + "/events", null);
+ };
+ this.getNotifications = function(options) {
+ var getDate, queryString;
+ if (options == null) {
+ options = {};
+ }
+ getDate = function(time) {
+ if (Date === time.constructor) {
+ return time.toISOString();
+ }
+ return time;
+ };
+ if (options.since) {
+ options.since = getDate(options.since);
+ }
+ queryString = toQueryString(options);
+ return _request('GET', "" + this.repoPath + "/notifications" + queryString, null);
+ };
+ this.getCollaborators = function() {
+ return _request('GET', "" + this.repoPath + "/collaborators", null);
+ };
+ this.addCollaborator = function(username) {
+ if (!username) {
+ throw new Error('BUG: username is required');
+ }
+ return _request('PUT', "" + this.repoPath + "/collaborators/" + username, null, {
+ isBoolean: true
+ });
+ };
+ this.removeCollaborator = function(username) {
+ if (!username) {
+ throw new Error('BUG: username is required');
+ }
+ return _request('DELETE', "" + this.repoPath + "/collaborators/" + username, null, {
+ isBoolean: true
+ });
+ };
+ this.isCollaborator = function(username) {
+ if (username == null) {
+ username = null;
+ }
+ if (!username) {
+ throw new Error('BUG: username is required');
+ }
+ return _request('GET', "" + this.repoPath + "/collaborators/" + username, null, {
+ isBoolean: true
+ });
+ };
+ this.canCollaborate = function() {
+ var _this = this;
+ if (!(clientOptions.password || clientOptions.token)) {
+ return resolvedPromise(false);
+ }
+ return _client.getLogin().then(function(login) {
+ if (!login) {
+ return false;
+ } else {
+ return _this.isCollaborator(login);
+ }
+ }).then(null, function(err) {
+ return false;
+ });
+ };
+ this.getHooks = function() {
+ return _request('GET', "" + this.repoPath + "/hooks", null);
+ };
+ this.getHook = function(id) {
+ return _request('GET', "" + this.repoPath + "/hooks/" + id, null);
+ };
+ this.createHook = function(name, config, events, active) {
+ var data;
+ if (events == null) {
+ events = ['push'];
+ }
+ if (active == null) {
+ active = true;
+ }
+ data = {
+ name: name,
+ config: config,
+ events: events,
+ active: active
+ };
+ return _request('POST', "" + this.repoPath + "/hooks", data);
+ };
+ this.editHook = function(id, config, events, addEvents, removeEvents, active) {
+ var data;
+ if (config == null) {
+ config = null;
+ }
+ if (events == null) {
+ events = null;
+ }
+ if (addEvents == null) {
+ addEvents = null;
+ }
+ if (removeEvents == null) {
+ removeEvents = null;
+ }
+ if (active == null) {
+ active = null;
+ }
+ data = {};
+ if (config !== null) {
+ data.config = config;
+ }
+ if (events !== null) {
+ data.events = events;
+ }
+ if (addEvents !== null) {
+ data.add_events = addEvents;
+ }
+ if (removeEvents !== null) {
+ data.remove_events = removeEvents;
+ }
+ if (active !== null) {
+ data.active = active;
+ }
+ return _request('PATCH', "" + this.repoPath + "/hooks/" + id, data);
+ };
+ this.testHook = function(id) {
+ return _request('POST', "" + this.repoPath + "/hooks/" + id + "/tests", null);
+ };
+ this.deleteHook = function(id) {
+ return _request('DELETE', "" + this.repoPath + "/hooks/" + id, null);
+ };
+ this.getLanguages = function() {
+ return _request('GET', "" + this.repoPath + "/languages", null);
+ };
+ this.getReleases = function() {
+ return _request('GET', "" + this.repoPath + "/releases", null);
+ };
+ }
+
+ return Repository;
+
+ })();
+ Gist = (function() {
+ function Gist(options) {
+ var id, _gistPath;
+ this.options = options;
+ id = this.options.id;
+ _gistPath = "/gists/" + id;
+ this.read = function() {
+ return _request('GET', _gistPath, null);
+ };
+ this.create = function(files, isPublic, description) {
+ if (isPublic == null) {
+ isPublic = false;
+ }
+ if (description == null) {
+ description = null;
+ }
+ options = {
+ isPublic: isPublic,
+ files: files
+ };
+ if (description != null) {
+ options.description = description;
+ }
+ return _request('POST', "/gists", options);
+ };
+ this["delete"] = function() {
+ return _request('DELETE', _gistPath, null);
+ };
+ this.fork = function() {
+ return _request('POST', "" + _gistPath + "/forks", null);
+ };
+ this.update = function(files, description) {
+ if (description == null) {
+ description = null;
+ }
+ options = {
+ files: files
+ };
+ if (description != null) {
+ options.description = description;
+ }
+ return _request('PATCH', _gistPath, options);
+ };
+ this.star = function() {
+ return _request('PUT', "" + _gistPath + "/star");
+ };
+ this.unstar = function() {
+ return _request('DELETE', "" + _gistPath + "/star");
+ };
+ this.isStarred = function() {
+ return _request('GET', "" + _gistPath, null, {
+ isBoolean: true
+ });
+ };
+ }
+
+ return Gist;
+
+ })();
+ this.getRepo = function(user, repo) {
+ if (!user) {
+ throw new Error('BUG! user argument is required');
+ }
+ if (!repo) {
+ throw new Error('BUG! repo argument is required');
+ }
+ return new Repository({
+ user: user,
+ name: repo
+ });
+ };
+ this.getOrg = function(name) {
+ return new Organization(name);
+ };
+ this.getUser = function(login) {
+ if (login == null) {
+ login = null;
+ }
+ if (login) {
+ return new User(login);
+ } else if (clientOptions.password || clientOptions.token) {
+ return new AuthenticatedUser();
+ } else {
+ return null;
+ }
+ };
+ this.getGist = function(id) {
+ return new Gist({
+ id: id
+ });
+ };
+ this.getLogin = function() {
+ if (clientOptions.password || clientOptions.token) {
+ return new User().getInfo().then(function(info) {
+ return info.login;
+ });
+ } else {
+ return resolvedPromise(null);
+ }
+ };
+ }
+
+ return Octokit;
+
+ })();
+ return Octokit;
+ };
+
+ if (typeof exports !== "undefined" && exports !== null) {
+ Promise = this.Promise || require('es6-promise').Promise;
+ XMLHttpRequest = this.XMLHttpRequest || require('xmlhttprequest').XMLHttpRequest;
+ newPromise = function(fn) {
+ return new Promise(fn);
+ };
+ allPromises = function(promises) {
+ return Promise.all(promises);
+ };
+ encode = this.btoa || function(str) {
+ var buffer;
+ buffer = new Buffer(str, 'binary');
+ return buffer.toString('base64');
+ };
+ Octokit = makeOctokit(newPromise, allPromises, XMLHttpRequest, encode, 'octokit');
+ exports["new"] = function(options) {
+ return new Octokit(options);
+ };
+ } else {
+ createGlobalAndAMD = function(newPromise, allPromises) {
+ if (_this.define != null) {
+ return _this.define('octokit', [], function() {
+ return makeOctokit(newPromise, allPromises, _this.XMLHttpRequest, _this.btoa);
+ });
+ } else {
+ Octokit = makeOctokit(newPromise, allPromises, _this.XMLHttpRequest, _this.btoa);
+ _this.Octokit = Octokit;
+ return _this.Github = Octokit;
+ }
+ };
+ if (this.Q) {
+ newPromise = function(fn) {
+ var deferred, reject, resolve;
+ deferred = _this.Q.defer();
+ resolve = function(val) {
+ return deferred.resolve(val);
+ };
+ reject = function(err) {
+ return deferred.reject(err);
+ };
+ fn(resolve, reject);
+ return deferred.promise;
+ };
+ allPromises = function(promises) {
+ return this.Q.all(promises);
+ };
+ createGlobalAndAMD(newPromise, allPromises);
+ } else if (this.angular) {
+ injector = angular.injector(['ng']);
+ injector.invoke(function($q) {
+ newPromise = function(fn) {
+ var deferred, reject, resolve;
+ deferred = $q.defer();
+ resolve = function(val) {
+ return deferred.resolve(val);
+ };
+ reject = function(err) {
+ return deferred.reject(err);
+ };
+ fn(resolve, reject);
+ return deferred.promise;
+ };
+ allPromises = function(promises) {
+ return $q.all(promises);
+ };
+ return createGlobalAndAMD(newPromise, allPromises);
+ });
+ } else if ((_ref = this.jQuery) != null ? _ref.Deferred : void 0) {
+ newPromise = function(fn) {
+ var promise, reject, resolve;
+ promise = _this.jQuery.Deferred();
+ resolve = function(val) {
+ return promise.resolve(val);
+ };
+ reject = function(val) {
+ return promise.reject(val);
+ };
+ fn(resolve, reject);
+ return promise.promise();
+ };
+ allPromises = function(promises) {
+ var _ref1;
+ return (_ref1 = _this.jQuery).when.apply(_ref1, promises).then(function() {
+ var promises;
+ promises = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
+ return promises;
+ });
+ };
+ createGlobalAndAMD(newPromise, allPromises);
+ } else if (this.Promise) {
+ newPromise = function(fn) {
+ return new _this.Promise(function(resolve, reject) {
+ if (resolve.fulfill) {
+ return fn(resolve.resolve.bind(resolve), resolve.reject.bind(resolve));
+ } else {
+ return fn.apply(null, arguments);
+ }
+ });
+ };
+ allPromises = this.Promise.all;
+ createGlobalAndAMD(newPromise, allPromises);
+ } else {
+ err = function(msg) {
+ if (typeof console !== "undefined" && console !== null) {
+ if (typeof console.error === "function") {
+ console.error(msg);
+ }
+ }
+ throw new Error(msg);
+ };
+ err('A Promise API was not found. Supported libraries that have Promises are jQuery, angularjs, and https://github.com/jakearchibald/es6-promise');
+ }
+ }
+
+}).call(this);
diff --git a/octokit/promise-1.0.0.js b/octokit/promise-1.0.0.js
new file mode 100644
index 0000000..5619cfa
--- /dev/null
+++ b/octokit/promise-1.0.0.js
@@ -0,0 +1,684 @@
+(function() {
+var define, requireModule, require, requirejs;
+
+(function() {
+ var registry = {}, seen = {};
+
+ define = function(name, deps, callback) {
+ registry[name] = { deps: deps, callback: callback };
+ };
+
+ requirejs = require = requireModule = function(name) {
+ requirejs._eak_seen = registry;
+
+ if (seen[name]) { return seen[name]; }
+ seen[name] = {};
+
+ if (!registry[name]) {
+ throw new Error("Could not find module " + name);
+ }
+
+ var mod = registry[name],
+ deps = mod.deps,
+ callback = mod.callback,
+ reified = [],
+ exports;
+
+ for (var i=0, l=deps.length; i<l; i++) {
+ if (deps[i] === 'exports') {
+ reified.push(exports = {});
+ } else {
+ reified.push(requireModule(resolve(deps[i])));
+ }
+ }
+
+ var value = callback.apply(this, reified);
+ return seen[name] = exports || value;
+
+ function resolve(child) {
+ if (child.charAt(0) !== '.') { return child; }
+ var parts = child.split("/");
+ var parentBase = name.split("/").slice(0, -1);
+
+ for (var i=0, l=parts.length; i<l; i++) {
+ var part = parts[i];
+
+ if (part === '..') { parentBase.pop(); }
+ else if (part === '.') { continue; }
+ else { parentBase.push(part); }
+ }
+
+ return parentBase.join("/");
+ }
+ };
+})();
+
+define("promise/all",
+ ["./utils","exports"],
+ function(__dependency1__, __exports__) {
+ "use strict";
+ /* global toString */
+
+ var isArray = __dependency1__.isArray;
+ var isFunction = __dependency1__.isFunction;
+
+ /**
+ Returns a promise that is fulfilled when all the given promises have been
+ fulfilled, or rejected if any of them become rejected. The return promise
+ is fulfilled with an array that gives all the values in the order they were
+ passed in the `promises` array argument.
+
+ Example:
+
+ ```javascript
+ var promise1 = RSVP.resolve(1);
+ var promise2 = RSVP.resolve(2);
+ var promise3 = RSVP.resolve(3);
+ var promises = [ promise1, promise2, promise3 ];
+
+ RSVP.all(promises).then(function(array){
+ // The array here would be [ 1, 2, 3 ];
+ });
+ ```
+
+ If any of the `promises` given to `RSVP.all` are rejected, the first promise
+ that is rejected will be given as an argument to the returned promises's
+ rejection handler. For example:
+
+ Example:
+
+ ```javascript
+ var promise1 = RSVP.resolve(1);
+ var promise2 = RSVP.reject(new Error("2"));
+ var promise3 = RSVP.reject(new Error("3"));
+ var promises = [ promise1, promise2, promise3 ];
+
+ RSVP.all(promises).then(function(array){
+ // Code here never runs because there are rejected promises!
+ }, function(error) {
+ // error.message === "2"
+ });
+ ```
+
+ @method all
+ @for RSVP
+ @param {Array} promises
+ @param {String} label
+ @return {Promise} promise that is fulfilled when all `promises` have been
+ fulfilled, or rejected if any of them become rejected.
+ */
+ function all(promises) {
+ /*jshint validthis:true */
+ var Promise = this;
+
+ if (!isArray(promises)) {
+ throw new TypeError('You must pass an array to all.');
+ }
+
+ return new Promise(function(resolve, reject) {
+ var results = [], remaining = promises.length,
+ promise;
+
+ if (remaining === 0) {
+ resolve([]);
+ }
+
+ function resolver(index) {
+ return function(value) {
+ resolveAll(index, value);
+ };
+ }
+
+ function resolveAll(index, value) {
+ results[index] = value;
+ if (--remaining === 0) {
+ resolve(results);
+ }
+ }
+
+ for (var i = 0; i < promises.length; i++) {
+ promise = promises[i];
+
+ if (promise && isFunction(promise.then)) {
+ promise.then(resolver(i), reject);
+ } else {
+ resolveAll(i, promise);
+ }
+ }
+ });
+ }
+
+ __exports__.all = all;
+ });
+define("promise/asap",
+ ["exports"],
+ function(__exports__) {
+ "use strict";
+ var browserGlobal = (typeof window !== 'undefined') ? window : {};
+ var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
+ var local = (typeof global !== 'undefined') ? global : (this === undefined? window:this);
+
+ // node
+ function useNextTick() {
+ return function() {
+ process.nextTick(flush);
+ };
+ }
+
+ function useMutationObserver() {
+ var iterations = 0;
+ var observer = new BrowserMutationObserver(flush);
+ var node = document.createTextNode('');
+ observer.observe(node, { characterData: true });
+
+ return function() {
+ node.data = (iterations = ++iterations % 2);
+ };
+ }
+
+ function useSetTimeout() {
+ return function() {
+ local.setTimeout(flush, 1);
+ };
+ }
+
+ var queue = [];
+ function flush() {
+ for (var i = 0; i < queue.length; i++) {
+ var tuple = queue[i];
+ var callback = tuple[0], arg = tuple[1];
+ callback(arg);
+ }
+ queue = [];
+ }
+
+ var scheduleFlush;
+
+ // Decide what async method to use to triggering processing of queued callbacks:
+ if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
+ scheduleFlush = useNextTick();
+ } else if (BrowserMutationObserver) {
+ scheduleFlush = useMutationObserver();
+ } else {
+ scheduleFlush = useSetTimeout();
+ }
+
+ function asap(callback, arg) {
+ var length = queue.push([callback, arg]);
+ if (length === 1) {
+ // If length is 1, that means that we need to schedule an async flush.
+ // If additional callbacks are queued before the queue is flushed, they
+ // will be processed by this flush that we are scheduling.
+ scheduleFlush();
+ }
+ }
+
+ __exports__.asap = asap;
+ });
+define("promise/config",
+ ["exports"],
+ function(__exports__) {
+ "use strict";
+ var config = {
+ instrument: false
+ };
+
+ function configure(name, value) {
+ if (arguments.length === 2) {
+ config[name] = value;
+ } else {
+ return config[name];
+ }
+ }
+
+ __exports__.config = config;
+ __exports__.configure = configure;
+ });
+define("promise/polyfill",
+ ["./promise","./utils","exports"],
+ function(__dependency1__, __dependency2__, __exports__) {
+ "use strict";
+ /*global self*/
+ var RSVPPromise = __dependency1__.Promise;
+ var isFunction = __dependency2__.isFunction;
+
+ function polyfill() {
+ var local;
+
+ if (typeof global !== 'undefined') {
+ local = global;
+ } else if (typeof window !== 'undefined' && window.document) {
+ local = window;
+ } else {
+ local = self;
+ }
+
+ var es6PromiseSupport =
+ "Promise" in local &&
+ // Some of these methods are missing from
+ // Firefox/Chrome experimental implementations
+ "resolve" in local.Promise &&
+ "reject" in local.Promise &&
+ "all" in local.Promise &&
+ "race" in local.Promise &&
+ // Older version of the spec had a resolver object
+ // as the arg rather than a function
+ (function() {
+ var resolve;
+ new local.Promise(function(r) { resolve = r; });
+ return isFunction(resolve);
+ }());
+
+ if (!es6PromiseSupport) {
+ local.Promise = RSVPPromise;
+ }
+ }
+
+ __exports__.polyfill = polyfill;
+ });
+define("promise/promise",
+ ["./config","./utils","./all","./race","./resolve","./reject","./asap","exports"],
+ function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) {
+ "use strict";
+ var config = __dependency1__.config;
+ var configure = __dependency1__.configure;
+ var objectOrFunction = __dependency2__.objectOrFunction;
+ var isFunction = __dependency2__.isFunction;
+ var now = __dependency2__.now;
+ var all = __dependency3__.all;
+ var race = __dependency4__.race;
+ var staticResolve = __dependency5__.resolve;
+ var staticReject = __dependency6__.reject;
+ var asap = __dependency7__.asap;
+
+ var counter = 0;
+
+ config.async = asap; // default async is asap;
+
+ function Promise(resolver) {
+ if (!isFunction(resolver)) {
+ throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
+ }
+
+ if (!(this instanceof Promise)) {
+ throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
+ }
+
+ this._subscribers = [];
+
+ invokeResolver(resolver, this);
+ }
+
+ function invokeResolver(resolver, promise) {
+ function resolvePromise(value) {
+ resolve(promise, value);
+ }
+
+ function rejectPromise(reason) {
+ reject(promise, reason);
+ }
+
+ try {
+ resolver(resolvePromise, rejectPromise);
+ } catch(e) {
+ rejectPromise(e);
+ }
+ }
+
+ function invokeCallback(settled, promise, callback, detail) {
+ var hasCallback = isFunction(callback),
+ value, error, succeeded, failed;
+
+ if (hasCallback) {
+ try {
+ value = callback(detail);
+ succeeded = true;
+ } catch(e) {
+ failed = true;
+ error = e;
+ }
+ } else {
+ value = detail;
+ succeeded = true;
+ }
+
+ if (handleThenable(promise, value)) {
+ return;
+ } else if (hasCallback && succeeded) {
+ resolve(promise, value);
+ } else if (failed) {
+ reject(promise, error);
+ } else if (settled === FULFILLED) {
+ resolve(promise, value);
+ } else if (settled === REJECTED) {
+ reject(promise, value);
+ }
+ }
+
+ var PENDING = void 0;
+ var SEALED = 0;
+ var FULFILLED = 1;
+ var REJECTED = 2;
+
+ function subscribe(parent, child, onFulfillment, onRejection) {
+ var subscribers = parent._subscribers;
+ var length = subscribers.length;
+
+ subscribers[length] = child;
+ subscribers[length + FULFILLED] = onFulfillment;
+ subscribers[length + REJECTED] = onRejection;
+ }
+
+ function publish(promise, settled) {
+ var child, callback, subscribers = promise._subscribers, detail = promise._detail;
+
+ for (var i = 0; i < subscribers.length; i += 3) {
+ child = subscribers[i];
+ callback = subscribers[i + settled];
+
+ invokeCallback(settled, child, callback, detail);
+ }
+
+ promise._subscribers = null;
+ }
+
+ Promise.prototype = {
+ constructor: Promise,
+
+ _state: undefined,
+ _detail: undefined,
+ _subscribers: undefined,
+
+ then: function(onFulfillment, onRejection) {
+ var promise = this;
+
+ var thenPromise = new this.constructor(function() {});
+
+ if (this._state) {
+ var callbacks = arguments;
+ config.async(function invokePromiseCallback() {
+ invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail);
+ });
+ } else {
+ subscribe(this, thenPromise, onFulfillment, onRejection);
+ }
+
+ return thenPromise;
+ },
+
+ 'catch': function(onRejection) {
+ return this.then(null, onRejection);
+ }
+ };
+
+ Promise.all = all;
+ Promise.race = race;
+ Promise.resolve = staticResolve;
+ Promise.reject = staticReject;
+
+ function handleThenable(promise, value) {
+ var then = null,
+ resolved;
+
+ try {
+ if (promise === value) {
+ throw new TypeError("A promises callback cannot return that same promise.");
+ }
+
+ if (objectOrFunction(value)) {
+ then = value.then;
+
+ if (isFunction(then)) {
+ then.call(value, function(val) {
+ if (resolved) { return true; }
+ resolved = true;
+
+ if (value !== val) {
+ resolve(promise, val);
+ } else {
+ fulfill(promise, val);
+ }
+ }, function(val) {
+ if (resolved) { return true; }
+ resolved = true;
+
+ reject(promise, val);
+ });
+
+ return true;
+ }
+ }
+ } catch (error) {
+ if (resolved) { return true; }
+ reject(promise, error);
+ return true;
+ }
+
+ return false;
+ }
+
+ function resolve(promise, value) {
+ if (promise === value) {
+ fulfill(promise, value);
+ } else if (!handleThenable(promise, value)) {
+ fulfill(promise, value);
+ }
+ }
+
+ function fulfill(promise, value) {
+ if (promise._state !== PENDING) { return; }
+ promise._state = SEALED;
+ promise._detail = value;
+
+ config.async(publishFulfillment, promise);
+ }
+
+ function reject(promise, reason) {
+ if (promise._state !== PENDING) { return; }
+ promise._state = SEALED;
+ promise._detail = reason;
+
+ config.async(publishRejection, promise);
+ }
+
+ function publishFulfillment(promise) {
+ publish(promise, promise._state = FULFILLED);
+ }
+
+ function publishRejection(promise) {
+ publish(promise, promise._state = REJECTED);
+ }
+
+ __exports__.Promise = Promise;
+ });
+define("promise/race",
+ ["./utils","exports"],
+ function(__dependency1__, __exports__) {
+ "use strict";
+ /* global toString */
+ var isArray = __dependency1__.isArray;
+
+ /**
+ `RSVP.race` allows you to watch a series of promises and act as soon as the
+ first promise given to the `promises` argument fulfills or rejects.
+
+ Example:
+
+ ```javascript
+ var promise1 = new RSVP.Promise(function(resolve, reject){
+ setTimeout(function(){
+ resolve("promise 1");
+ }, 200);
+ });
+
+ var promise2 = new RSVP.Promise(function(resolve, reject){
+ setTimeout(function(){
+ resolve("promise 2");
+ }, 100);
+ });
+
+ RSVP.race([promise1, promise2]).then(function(result){
+ // result === "promise 2" because it was resolved before promise1
+ // was resolved.
+ });
+ ```
+
+ `RSVP.race` is deterministic in that only the state of the first completed
+ promise matters. For example, even if other promises given to the `promises`
+ array argument are resolved, but the first completed promise has become
+ rejected before the other promises became fulfilled, the returned promise
+ will become rejected:
+
+ ```javascript
+ var promise1 = new RSVP.Promise(function(resolve, reject){
+ setTimeout(function(){
+ resolve("promise 1");
+ }, 200);
+ });
+
+ var promise2 = new RSVP.Promise(function(resolve, reject){
+ setTimeout(function(){
+ reject(new Error("promise 2"));
+ }, 100);
+ });
+
+ RSVP.race([promise1, promise2]).then(function(result){
+ // Code here never runs because there are rejected promises!
+ }, function(reason){
+ // reason.message === "promise2" because promise 2 became rejected before
+ // promise 1 became fulfilled
+ });
+ ```
+
+ @method race
+ @for RSVP
+ @param {Array} promises array of promises to observe
+ @param {String} label optional string for describing the promise returned.
+ Useful for tooling.
+ @return {Promise} a promise that becomes fulfilled with the value the first
+ completed promises is resolved with if the first completed promise was
+ fulfilled, or rejected with the reason that the first completed promise
+ was rejected with.
+ */
+ function race(promises) {
+ /*jshint validthis:true */
+ var Promise = this;
+
+ if (!isArray(promises)) {
+ throw new TypeError('You must pass an array to race.');
+ }
+ return new Promise(function(resolve, reject) {
+ var results = [], promise;
+
+ for (var i = 0; i < promises.length; i++) {
+ promise = promises[i];
+
+ if (promise && typeof promise.then === 'function') {
+ promise.then(resolve, reject);
+ } else {
+ resolve(promise);
+ }
+ }
+ });
+ }
+
+ __exports__.race = race;
+ });
+define("promise/reject",
+ ["exports"],
+ function(__exports__) {
+ "use strict";
+ /**
+ `RSVP.reject` returns a promise that will become rejected with the passed
+ `reason`. `RSVP.reject` is essentially shorthand for the following:
+
+ ```javascript
+ var promise = new RSVP.Promise(function(resolve, reject){
+ reject(new Error('WHOOPS'));
+ });
+
+ promise.then(function(value){
+ // Code here doesn't run because the promise is rejected!
+ }, function(reason){
+ // reason.message === 'WHOOPS'
+ });
+ ```
+
+ Instead of writing the above, your code now simply becomes the following:
+
+ ```javascript
+ var promise = RSVP.reject(new Error('WHOOPS'));
+
+ promise.then(function(value){
+ // Code here doesn't run because the promise is rejected!
+ }, function(reason){
+ // reason.message === 'WHOOPS'
+ });
+ ```
+
+ @method reject
+ @for RSVP
+ @param {Any} reason value that the returned promise will be rejected with.
+ @param {String} label optional string for identifying the returned promise.
+ Useful for tooling.
+ @return {Promise} a promise that will become rejected with the given
+ `reason`.
+ */
+ function reject(reason) {
+ /*jshint validthis:true */
+ var Promise = this;
+
+ return new Promise(function (resolve, reject) {
+ reject(reason);
+ });
+ }
+
+ __exports__.reject = reject;
+ });
+define("promise/resolve",
+ ["exports"],
+ function(__exports__) {
+ "use strict";
+ function resolve(value) {
+ /*jshint validthis:true */
+ if (value && typeof value === 'object' && value.constructor === this) {
+ return value;
+ }
+
+ var Promise = this;
+
+ return new Promise(function(resolve) {
+ resolve(value);
+ });
+ }
+
+ __exports__.resolve = resolve;
+ });
+define("promise/utils",
+ ["exports"],
+ function(__exports__) {
+ "use strict";
+ function objectOrFunction(x) {
+ return isFunction(x) || (typeof x === "object" && x !== null);
+ }
+
+ function isFunction(x) {
+ return typeof x === "function";
+ }
+
+ function isArray(x) {
+ return Object.prototype.toString.call(x) === "[object Array]";
+ }
+
+ // Date.now is not available in browsers < IE9
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility
+ var now = Date.now || function() { return new Date().getTime(); };
+
+
+ __exports__.objectOrFunction = objectOrFunction;
+ __exports__.isFunction = isFunction;
+ __exports__.isArray = isArray;
+ __exports__.now = now;
+ });
+requireModule('promise/polyfill').polyfill();
+}()); \ No newline at end of file
diff --git a/snap.html b/snap.html
index 904aba8..26c5124 100755
--- a/snap.html
+++ b/snap.html
@@ -16,6 +16,8 @@
<script type="text/javascript" src="xml.js"></script>
<script type="text/javascript" src="store.js"></script>
<script type="text/javascript" src="locale.js"></script>
+ <script type="text/javascript" src="octokit/promise-1.0.0.js"></script>
+ <script type="text/javascript" src="octokit/octokit.js"></script>
<script type="text/javascript" src="cloud.js"></script>
<script type="text/javascript" src="sha512.js"></script>
<script type="text/javascript">