<commit_before>/*
Copyright 2018 New Vector Ltd
Copyright 2020 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * QR code key verification.
 * @module crypto/verification/QRCode
 */

import {VerificationBase as Base} from "./Base";
import {
    newKeyMismatchError,
    newUserMismatchError,
} from './Error';

export const SHOW_QR_CODE_METHOD = "m.qr_code.show.v1";
export const SCAN_QR_CODE_METHOD = "m.qr_code.scan.v1";

/**
 * @class crypto/verification/QRCode/ReciprocateQRCode
 * @extends {module:crypto/verification/Base}
 */
export class ReciprocateQRCode extends Base {
    static factory(...args) {
        return new ReciprocateQRCode(...args);
    }

    static get NAME() {
        return "m.reciprocate.v1";
    }

    async _doVerification() {
        if (!this.startEvent) {
            // TODO: Support scanning QR codes
            throw new Error("It is not currently possible to start verification" +
                "with this method yet.");
        }

        const targetUserId = this.startEvent.getSender();
        if (!this.userId) {
            console.log("Asking to confirm user ID");
            this.userId = await new Promise((resolve, reject) => {
                this.emit("confirm_user_id", {
                    userId: targetUserId,
                    confirm: resolve, // takes a userId
                    cancel: () => reject(newUserMismatchError()),
                });
            });
        } else if (targetUserId !== this.userId) {
            throw newUserMismatchError({
                expected: this.userId,
                actual: targetUserId,
            });
        }

        if (this.startEvent.getContent()['secret'] !== this.request.encodedSharedSecret) {
            throw newKeyMismatchError();
        }

        // If we've gotten this far, verify the user's master cross signing key
        const xsignInfo = this._baseApis.getStoredCrossSigningInfo(this.userId);
        if (!xsignInfo) throw new Error("Missing cross signing info");

        const masterKey = xsignInfo.getId("master");
        await this._verifyKeys(this.userId, [masterKey, masterKey]);
    }
}
<commit_msg>Fix verification of the master key<commit_after>/*
Copyright 2018 New Vector Ltd
Copyright 2020 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * QR code key verification.
 * @module crypto/verification/QRCode
 */

import {VerificationBase as Base} from "./Base";
import {
    newKeyMismatchError,
    newUserMismatchError,
} from './Error';

export const SHOW_QR_CODE_METHOD = "m.qr_code.show.v1";
export const SCAN_QR_CODE_METHOD = "m.qr_code.scan.v1";

/**
 * @class crypto/verification/QRCode/ReciprocateQRCode
 * @extends {module:crypto/verification/Base}
 */
export class ReciprocateQRCode extends Base {
    static factory(...args) {
        return new ReciprocateQRCode(...args);
    }

    static get NAME() {
        return "m.reciprocate.v1";
    }

    async _doVerification() {
        if (!this.startEvent) {
            // TODO: Support scanning QR codes
            throw new Error("It is not currently possible to start verification" +
                "with this method yet.");
        }

        const targetUserId = this.startEvent.getSender();
        if (!this.userId) {
            console.log("Asking to confirm user ID");
            this.userId = await new Promise((resolve, reject) => {
                this.emit("confirm_user_id", {
                    userId: targetUserId,
                    confirm: resolve, // takes a userId
                    cancel: () => reject(newUserMismatchError()),
                });
            });
        } else if (targetUserId !== this.userId) {
            throw newUserMismatchError({
                expected: this.userId,
                actual: targetUserId,
            });
        }

        if (this.startEvent.getContent()['secret'] !== this.request.encodedSharedSecret) {
            throw newKeyMismatchError();
        }

        // If we've gotten this far, verify the user's master cross signing key
        const xsignInfo = this._baseApis.getStoredCrossSigningForUser(this.userId);
        if (!xsignInfo) throw new Error("Missing cross signing info");

        const masterKey = xsignInfo.getId("master");
        const masterKeyId = `ed25519:${masterKey}`;
        await this._verifyKeys(this.userId, {[masterKeyId]:masterKey}, (keyId, device, keyInfo) => {
            console.log({keyId, device, keyInfo});
            if (keyId !== masterKeyId) {
                throw newKeyMismatchError();
            }
        });
    }
}
<|endoftext|>


<commit_before>//
// Analytics for all things articles. This includes tests for share buttons
// and potentionally other alternative layout options or more.
//

if (
  location.pathname.match("/article/") ||
  location.pathname.match("/2016-year-in-art")
) {
  $(document.body)
    .on("click", ".article-social a", function() {
      var articleId = $(this)
        .closest(".article-container")
        .data("id")
      analytics.track("Article Share", {
        article_id: articleId,
        context_type: sd.ARTICLE ? "article_fixed" : "magazine_fixed",
        service: $(this).attr("data-service"),
      })
    })
    .on("click", ".article-share-fixed > a", function() {
      var articleId = $(this)
        .closest(".article-container")
        .data("id")
      analytics.track("Article Share", {
        article_id: articleId,
        context_type: "article_sticky",
        service: $(this).attr("data-service"),
      })
    })
    .on("click", ".article-sa-primary-logo a", function() {
      analytics.track("Clicked primary partner logo", {
        destination_path: $(this)[0].href,
        impression_type: "sa_primary_logo",
        context_type: "article_fixed",
      })
    })
    .on("click", ".article-sa-secondary-logo a", function() {
      analytics.track("Clicked secondary partner logo", {
        destination_path: $(this)[0].href,
        impression_type: "sa_secondary_logo",
        context_type: "article_fixed",
      })
    })
    .on("click", ".article-sa-cta-container a", function() {
      analytics.track("Clicked partner cta link", {
        destination_path: $(this)[0].href,
        impression_type: "sa_partner_cta",
        context_type: "article_fixed",
      })
    })
    .on("click", ".article-sa-footer-blurb a", function() {
      analytics.track("Clicked partner cta link in footer blurb", {
        destination_path: $(this)[0].href,
        impression_type: "sa_partner_cta",
        context_type: "article_fixed",
      })
    })

  // Hooks
  analyticsHooks.on("view:editorial-signup", function(options) {
    analytics.track("Article impression", {
      article_id: null,
      destination_path: null,
      impression_type: "newsletter_signup",
      context_type: options.type,
    })
  })
}

// Applies to both /article/* and /articles
if (
  location.pathname.match("/article/") ||
  location.pathname.match("/articles") ||
  location.pathname.match("/venice-biennale-2015")
) {
  analyticsHooks.on("submit:editorial-signup", function(options) {
    analytics.track("Sign up for editorial email", {
      article_id: $(this)
        .closest(".article-container")
        .data("id"),
      context_type: options.type,
      user_email: options.email,
    })
  })

  analyticsHooks.on("dismiss:editorial-signup", function(options) {
    analytics.track("Dismiss editorial signup", {
      context_type: options.type,
    })
  })
}
<commit_msg>remove unused hooks for editorial signup<commit_after>//
// Analytics for all things articles. This includes tests for share buttons
// and potentionally other alternative layout options or more.
//

if (
  location.pathname.match("/article/") ||
  location.pathname.match("/2016-year-in-art")
) {
  $(document.body)
    .on("click", ".article-social a", function () {
      const articleId = $(this).closest(".article-container").data("id")
      analytics.track("Article Share", {
        article_id: articleId,
        context_type: sd.ARTICLE ? "article_fixed" : "magazine_fixed",
        service: $(this).attr("data-service"),
      })
    })
    .on("click", ".article-share-fixed > a", function () {
      const articleId = $(this).closest(".article-container").data("id")
      analytics.track("Article Share", {
        article_id: articleId,
        context_type: "article_sticky",
        service: $(this).attr("data-service"),
      })
    })
    .on("click", ".article-sa-primary-logo a", function () {
      analytics.track("Clicked primary partner logo", {
        destination_path: $(this)[0].href,
        impression_type: "sa_primary_logo",
        context_type: "article_fixed",
      })
    })
    .on("click", ".article-sa-secondary-logo a", function () {
      analytics.track("Clicked secondary partner logo", {
        destination_path: $(this)[0].href,
        impression_type: "sa_secondary_logo",
        context_type: "article_fixed",
      })
    })
    .on("click", ".article-sa-cta-container a", function () {
      analytics.track("Clicked partner cta link", {
        destination_path: $(this)[0].href,
        impression_type: "sa_partner_cta",
        context_type: "article_fixed",
      })
    })
    .on("click", ".article-sa-footer-blurb a", function () {
      analytics.track("Clicked partner cta link in footer blurb", {
        destination_path: $(this)[0].href,
        impression_type: "sa_partner_cta",
        context_type: "article_fixed",
      })
    })
}
<|endoftext|>


<commit_before>/*!
 * Tweenie.js - Copyright (c) 2014 Jacob Buck
 * https://github.com/jacobbuck/tweenie
 * Licensed under the terms of the MIT license.
 */
(function( context, window ){

	// requestAnimationFrame polyfill by Erik Möller with fixes from Paul Irish and Tino Zijdel
	// modified by Jacob Buck for Tweenie.js
	var lastTime = 0,
		requestAnimationFrame = window.requestAnimationFrame,
		vendors = [ 'ms', 'moz', 'webkit', 'o' ],
		i = 0;
	for ( ; i < vendors.length && ! requestAnimationFrame; i++ ) {
		requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame'];
	};
	if ( ! requestAnimationFrame ) {
		requestAnimationFrame = function( callback, element ){
			var currTime = Date.now(),
				timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ),
				id = window.setTimeout(
					function(){ callback( currTime + timeToCall ); },
					timeToCall
				);
			lastTime = currTime + timeToCall;
			return id;
		};
	};

	// Stack Object
	var Stack = function(){
		this.items = [];
		return this;
	};
	Stack.prototype = {
		add: function( fn ){
			this.items.push( fn );
			return this.tick();
		},
		remove: function( fn ){
			for ( var i = 0; i < this.items.length; i++ )
				if ( fn === this.items[ i ] )
					this.items.splice( i, 1 );
			return this;
		},
		step: function( time ){
			if ( this.items.length < 1 )
				return this;
			for ( var i = 0, item; item = this.items[ i ], i < this.items.length; i++ ) {
				item.step( time );
				if ( item.finish )
					this.remove( item );
			};
			return this;
		},
		tick: function () {
			if ( this.items.length > 0 ) {
				var self = this;
				requestAnimationFrame(function( time ){
					self.step( time ).tick();
				});
			};
			return this;
		},
		stop: function ( finish ) {
			for ( var i = 0; i < this.items.length; i++ )
				this.items[ i ].stop( finish );
			return this;
		}
	};

	// Tween Object
	var Tween = function( options, parent ){
		this.options = options;
		this.parent  = parent;
		return this;
	};
	Tween.prototype = {
		start: function(){
			if ( this.finish )
				this.started = this.finish = 0;
			this.parent.stack.remove( this ).add( this );
			return this;
		},
		step: function( time ){
			this.started = this.started || time;
			if ( time > this.started + this.options.duration )
				this.finish = 1;
			this.options.step( this.finish ? this.options.to : this.options.easing( time - this.started, 0, 1, this.options.duration ) * ( this.options.to - this.options.from ) + this.options.from, this );
			if ( this.finish && this.options.callback )
				this.options.callback( this );
			return this;
		},
		stop: function( finish ){
			this.finish = 1;
			if ( ! finish )
				this.parent.stack.remove( this );
			return this;
		}
	};

	// Tweenie Object
	var Tweenie = function(){
		this.stack = new Stack();
	};
	Tweenie.prototype = {
		tween: function( duration, from, to, step, callback, easing ){
			return new Tween( {
				duration : duration,
				from     : from,
				to       : to,
				step     : step,
				callback : callback,
				easing   : easing || function (t,b,c,d) { return c * Math.sin(t/d * (Math.PI/2)) + b; }
			}, this );
		},
		stop: function( finish ){
			this.stack.stop( finish );
			return this;
		}
	};

	// Tweenie Object Global
	context.Tweenie = Tweenie;

}( this, window ));<commit_msg>Use CommonJS and add 'use strict'<commit_after>/*!
 * Tweenie.js - Copyright (c) 2014 Jacob Buck
 * https://github.com/jacobbuck/tweenie
 * Licensed under the terms of the MIT license.
 */
'use strict';

// Stack Object
var Stack = function(){
	this.items = [];
	return this;
};
Stack.prototype = {
	add: function( fn ){
		this.items.push( fn );
		return this.tick();
	},
	remove: function( fn ){
		for ( var i = 0; i < this.items.length; i++ )
			if ( fn === this.items[ i ] )
				this.items.splice( i, 1 );
		return this;
	},
	step: function( time ){
		if ( this.items.length < 1 )
			return this;
		for ( var i = 0, item; item = this.items[ i ], i < this.items.length; i++ ) {
			item.step( time );
			if ( item.finish )
				this.remove( item );
		};
		return this;
	},
	tick: function () {
		if ( this.items.length > 0 ) {
			var self = this;
			requestAnimationFrame(function( time ){
				self.step( time ).tick();
			});
		};
		return this;
	},
	stop: function ( finish ) {
		for ( var i = 0; i < this.items.length; i++ )
			this.items[ i ].stop( finish );
		return this;
	}
};

// Tween Object
var Tween = function( options, parent ){
	this.options = options;
	this.parent  = parent;
	return this;
};
Tween.prototype = {
	start: function(){
		if ( this.finish )
			this.started = this.finish = 0;
		this.parent.stack.remove( this ).add( this );
		return this;
	},
	step: function( time ){
		this.started = this.started || time;
		if ( time > this.started + this.options.duration )
			this.finish = 1;
		this.options.step( this.finish ? this.options.to : this.options.easing( time - this.started, 0, 1, this.options.duration ) * ( this.options.to - this.options.from ) + this.options.from, this );
		if ( this.finish && this.options.callback )
			this.options.callback( this );
		return this;
	},
	stop: function( finish ){
		this.finish = 1;
		if ( ! finish )
			this.parent.stack.remove( this );
		return this;
	}
};

// Tweenie Object
var Tweenie = function(){
	this.stack = new Stack();
};
Tweenie.prototype = {
	tween: function( duration, from, to, step, callback, easing ){
		return new Tween( {
			duration : duration,
			from     : from,
			to       : to,
			step     : step,
			callback : callback,
			easing   : easing || function (t,b,c,d) { return c * Math.sin(t/d * (Math.PI/2)) + b; }
		}, this );
	},
	stop: function( finish ){
		this.stack.stop( finish );
		return this;
	}
};

// Tweenie Object Global
module.exports = Tweenie;
<|endoftext|>


<commit_before>var RECORD_URL = "http://localhost/record?start=-4&duration=16";
var TWITTER_USERNAME = "GoalFlash";

var twitter = require('twitter')
  , humanize = require('humanize')
  , googl = require('goo.gl')
  , request = require('request');

var twit = new twitter(require('./settings.json').twitter);

var notify = function(url) {
  var text = lastTweet.replace(/http.*/i,'').replace(/^RT @[a-zA-Z]{1,15}:? ?/i,'').replace(/ $/,'');
  googl.shorten(url)
    .then(function (shortUrl) {
      twit.updateStatus(text + " - Video: "+shortUrl, function(data) {
        console.log("notify> ", data);
      });
    })
    .catch(function (err) {
        console.error(err.message);
    });
};

var lastTweet = '';

/* For testing:
setTimeout(function() {
  request(RECORD_URL, function(err, res, body) {
    console.log("body: ", body);
    notify(body);
  });

}, 1000);
*/

console.log(humanize.date("Y-m-d H:i:s")+" Connecting to the Twitter Stream for @"+TWITTER_USERNAME);
twit.stream('user', {track:TWITTER_USERNAME}, function(stream) {
    console.log(humanize.date("Y-m-d H:i:s")+" Connected");
    stream.on('data', function(data) {
      console.log(humanize.date("Y-m-d H:i:s")+" DATA: ", data);
      if(!data.text) return;
      if(data.user.screen_name != TWITTER_USERNAME) return;
      lastTweet = data.text;
      request(RECORD_URL, function(err, res, body) {
        console.log("body: ", body);
        if(body.match(/http/))
          notify(body);
      });
    });

    stream.on('error', function(error) {
      console.error("Error in the twitter stream: ", error);
      process.exit(1);
    });

    stream.on('end', function(error) {
      console.error("Twitter stream ended - exiting");
      process.exit(1);
    });
});
<commit_msg>18s to be sure to not miss anything<commit_after>var RECORD_URL = "http://localhost/record?start=-4&duration=18";
var TWITTER_USERNAME = "GoalFlash";

var twitter = require('twitter')
  , humanize = require('humanize')
  , googl = require('goo.gl')
  , request = require('request');

var twit = new twitter(require('./settings.json').twitter);

var notify = function(url) {
  var text = lastTweet.replace(/http.*/i,'').replace(/^RT @[a-zA-Z]{1,15}:? ?/i,'').replace(/ $/,'');
  googl.shorten(url)
    .then(function (shortUrl) {
      twit.updateStatus(text + " - Video: "+shortUrl, function(data) {
        console.log("notify> ", data);
      });
    })
    .catch(function (err) {
        console.error(err.message);
    });
};

var lastTweet = '';

/* For testing:
setTimeout(function() {
  request(RECORD_URL, function(err, res, body) {
    console.log("body: ", body);
    notify(body);
  });

}, 1000);
*/

console.log(humanize.date("Y-m-d H:i:s")+" Connecting to the Twitter Stream for @"+TWITTER_USERNAME);
twit.stream('user', {track:TWITTER_USERNAME}, function(stream) {
    console.log(humanize.date("Y-m-d H:i:s")+" Connected");
    stream.on('data', function(data) {
      console.log(humanize.date("Y-m-d H:i:s")+" DATA: ", data);
      if(!data.text) return;
      if(data.user.screen_name != TWITTER_USERNAME) return;
      lastTweet = data.text;
      request(RECORD_URL, function(err, res, body) {
        console.log("body: ", body);
        if(body.match(/http/))
          notify(body);
      });
    });

    stream.on('error', function(error) {
      console.error("Error in the twitter stream: ", error);
      process.exit(1);
    });

    stream.on('end', function(error) {
      console.error("Twitter stream ended - exiting");
      process.exit(1);
    });
});
<|endoftext|>


<commit_before>(function(w) {
	/**
	 * minc.js
	 * @param {Array} a An Array containing the URLs/Paths to your scripts
	 * @param {Array} [b] An Array containing the URLs/Paths to you fallback-scripts
	 * @returns {Function}
	 * @constructor
	 */
	function $(a, b) {
		return (function _() {
			var r, i, L, g,
				m = Minc.m,
				M = [],
				C = w.console;

			/**
			 * Success method when all scripts are loaded
			 * @param {Function} c callback
			 */
			_.done = function(c) {
				r = c
			};

			try {
				!function l(s, d, o, t, I) {
					// AMD define()
					(w.define =
						/**
						 *
						 * @param {Function|String|Array} x Module function or moduleName or dependencies
						 * @param {Function|Array} y Module function or dependencies
						 * @param {Function|undefined} z Module function or undefined
						 */
							function(x, y, z) {
							// check multi-use of parameters
							x.call ? (z = x, x = "", y = []) : x.pop && (z = y, y = x, x = "");

							// save module
							m.push({ i: x, d: y, m: z });

							if(L=y.length)
								for(d=L, o = []; d--;) { 		// parse dependencies
									for(g=m.length; g--;) 		// parse modules
										if(m[g] && y[d] == m[g].i)
											o.push(m[g].m());

									L != o.length && 			// validate dependencies
									C && C.log("Missing", y)

									M[i] = z.apply(w, o);		// assign module callback
								}
							else 								// assign module callback
								M[i] = z()
						}
					).amd = 1;

					// load
					t = s.indexOf(".css") > -1 ? 'link' : 'script';
					with(document)
						(d=createElement(t))[t == 'link' ? 'href' : 'src'] = s.replace(/https*:/, ""),
							t == 'link'

								?

								// load CSS
							(I = setInterval(function() {
								if(d.sheet && d.sheet.cssRules && d.sheet.cssRules[0] || d.styleSheet && d.styleSheet.rules && d.styleSheet.rules[0]) {
									a[++i] ? l(a[i]) : r && r.apply(_, M);
									clearInterval(I)
								}
							}, 5)) && (d.rel = 'stylesheet')

								:

								// load JS
								d.onload = d.onreadystatechange = d.onerror = function(e) {
									(e = e || this).type == 'error' && b[i]
										? l(b[i])
										: e.type == 'load' || e[g="readyState"] == 'loaded' || e[g] == 'complete' ?
										a[++i] ? l(a[i]) : r && r.apply(_, M) : 0
								},

							getElementsByTagName('head')[0].appendChild(d)
				}(a[i=0]);
			} catch(e) { C && C.log(e) }

			return _
		})()
	};

	$.m = [];

	w.define && define.amd
		?
			define('Minc', function() {
				return $
			})
		:
			w['Minc'] = $

})(window);<commit_msg>indents<commit_after>(function(w) {
	/**
	 * minc.js
	 * @param {Array} a An Array containing the URLs/Paths to your scripts
	 * @param {Array} [b] An Array containing the URLs/Paths to you fallback-scripts
	 * @returns {Function}
	 * @constructor
	 */
	function $(a, b) {
		return (function _() {
			var r, i, L, g,
				m = Minc.m,
				M = [],
				C = w.console;

			/**
			 * Success method when all scripts are loaded
			 * @param {Function} c callback
			 */
			_.done = function(c) {
				r = c
			};

			try {
				!function l(s, d, o, t, I) {
					// AMD define()
					(w.define =
						/**
						 *
						 * @param {Function|String|Array} x Module function or moduleName or dependencies
						 * @param {Function|Array} y Module function or dependencies
						 * @param {Function|undefined} z Module function or undefined
						 */
						function(x, y, z) {
							// check multi-use of parameters
							x.call ? (z = x, x = "", y = []) : x.pop && (z = y, y = x, x = "");

							// save module
							m.push({ i: x, d: y, m: z });

							if(L=y.length)
								for(d=L, o = []; d--;) { 		// parse dependencies
									for(g=m.length; g--;) 		// parse modules
										if(m[g] && y[d] == m[g].i)
											o.push(m[g].m());

									L != o.length && 			// validate dependencies
									C && C.log("Missing", y)

									M[i] = z.apply(w, o);		// assign module callback
								}
							else 								// assign module callback
								M[i] = z()
						}
					).amd = 1;

					// load
					t = s.indexOf(".css") > -1 ? 'link' : 'script';
					with(document)
						(d=createElement(t))[t == 'link' ? 'href' : 'src'] = s.replace(/https*:/, ""),
						t == 'link' ?

						// load CSS
						(I = setInterval(function() {
							if(d.sheet && d.sheet.cssRules && d.sheet.cssRules[0] || d.styleSheet && d.styleSheet.rules && d.styleSheet.rules[0]) {
								a[++i] ? l(a[i]) : r && r.apply(_, M);
								clearInterval(I)
							}
						}, 5)) && (d.rel = 'stylesheet')

						:

						// load JS
						d.onload = d.onreadystatechange = d.onerror = function(e) {
							(e = e || this).type == 'error' && b[i]
								? l(b[i])
								: e.type == 'load' || e[g="readyState"] == 'loaded' || e[g] == 'complete' ?
								a[++i] ? l(a[i]) : r && r.apply(_, M) : 0
						},

						getElementsByTagName('head')[0].appendChild(d)
				}(a[i=0]);
			} catch(e) { C && C.log(e) }

			return _
		})()
	};

	$.m = [];

	w.define && define.amd
		?
			define('Minc', function() {
				return $
			})
		:
			w['Minc'] = $

})(window);<|endoftext|>


<commit_before><commit_msg>Add comments<commit_after><|endoftext|>


<commit_before>import {
  GraphQLSchema,
  GraphQLObjectType,
  GraphQLEnumType,
  GraphQLUnionType,
  GraphQLInterfaceType,
  GraphQLList,
  getNullableType,
  getNamedType,
} from 'graphql/type';
import { graphql } from 'graphql';
import uuid from 'node-uuid';
import { forEachField, buildSchemaFromTypeDefinitions } from './schemaGenerator';

// This function wraps addMockFunctionsToSchema for more convenience
function mockServer(schema, mocks = {}, preserveResolvers = false) {
  let mySchema = schema;
  if (!(schema instanceof GraphQLSchema)) {
    // TODO: provide useful error messages here if this fails
    mySchema = buildSchemaFromTypeDefinitions(schema);
  }
  addMockFunctionsToSchema({ schema: mySchema, mocks, preserveResolvers });

  return { query: (query, vars) => graphql(mySchema, query, {}, {}, vars) };
}

// TODO allow providing a seed such that lengths of list could be deterministic
// this could be done by using casual to get a random list length if the casual
// object is global.
function addMockFunctionsToSchema({ schema, mocks = {}, preserveResolvers = false } = {}) {
  function isObject(thing) {
    return thing === Object(thing) && !Array.isArray(thing);
  }
  if (!schema) {
    // XXX should we check that schema is an instance of GraphQLSchema?
    throw new Error('Must provide schema to mock');
  }
  if (!isObject(mocks)) {
    throw new Error('mocks must be of type Object');
  }

  // use Map internally, because that API is nicer.
  const mockFunctionMap = new Map();
  Object.keys(mocks).forEach((typeName) => {
    mockFunctionMap.set(typeName, mocks[typeName]);
  });

  mockFunctionMap.forEach((mockFunction, mockTypeName) => {
    if (typeof mockFunction !== 'function') {
      throw new Error(`mockFunctionMap[${mockTypeName}] must be a function`);
    }
  });

  const defaultMockMap = new Map();
  defaultMockMap.set('Int', () => Math.round(Math.random() * 200) - 100);
  defaultMockMap.set('Float', () => (Math.random() * 200) - 100);
  defaultMockMap.set('String', () => 'Hello World');
  defaultMockMap.set('Boolean', () => Math.random() > 0.5);
  defaultMockMap.set('ID', () => uuid.v4());

  function mergeObjects(a, b) {
    return Object.assign(a, b);
  }

  function copyOwnProps(target, ...sources) {
    sources.forEach(source => {
      let chain = source;
      while (chain) {
        Object.getOwnPropertyNames(chain).forEach(prop => {
          if (!Object.getOwnPropertyDescriptor(target, prop)) {
            Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(chain, prop));
          }
        });
        chain = Object.getPrototypeOf(chain);
      }
    });
    return target;
  }

  // returns a random element from that ary
  function getRandomElement(ary) {
    const sample = Math.floor(Math.random() * ary.length);
    return ary[sample];
  }

  // takes either an object or a (possibly nested) array
  // and completes the customMock object with any fields
  // defined on genericMock
  // only merges objects or arrays. Scalars are returned as is
  function mergeMocks(genericMockFunction, customMock) {
    if (Array.isArray(customMock)) {
      return customMock.map((el) => mergeMocks(genericMockFunction, el));
    }
    if (isObject(customMock)) {
      return mergeObjects(genericMockFunction(), customMock);
    }
    return customMock;
  }

  function assignResolveType(type) {
    const fieldType = getNullableType(type);
    const namedFieldType = getNamedType(fieldType);

    const oldResolveType = namedFieldType.resolveType;
    if (preserveResolvers && oldResolveType && oldResolveType.length) {
      return;
    }

    if (namedFieldType instanceof GraphQLUnionType ||
        namedFieldType instanceof GraphQLInterfaceType
    ) {
      // the default `resolveType` always returns null. We add a fallback
      // resolution that works with how unions and interface are mocked
      namedFieldType.resolveType = (data, context, info) =>
        info.schema.getType(data.typename);
    }
  }

  const mockType = function mockType(type, typeName, fieldName) {
    // order of precendence for mocking:
    // 1. if the object passed in already has fieldName, just use that
    // --> if it's a function, that becomes your resolver
    // --> if it's a value, the mock resolver will return that
    // 2. if the nullableType is a list, recurse
    // 2. if there's a mock defined for this typeName, that will be used
    // 3. if there's no mock defined, use the default mocks for this type
    return (...args) => {
      const [root, queryArgs, context, info] = args;

      // nullability doesn't matter for the purpose of mocking.
      const fieldType = getNullableType(type);
      const namedFieldType = getNamedType(fieldType);

      if (root && typeof root[fieldName] !== 'undefined') {
        let result;
        // if we're here, the field is already defined
        if (typeof root[fieldName] === 'function') {
          result = root[fieldName](...args);
          if (result instanceof MockList) {
            result = result.mock(...args, fieldType, mockType);
          }
        } else {
          result = root[fieldName];
        }

        // Now we merge the result with the default mock for this type.
        // This allows overriding defaults while writing very little code.
        if (mockFunctionMap.has(namedFieldType.name)) {
          result = mergeMocks(
            mockFunctionMap.get(namedFieldType.name).bind(null, ...args), result
          );
        }
        return result;
      }

      if (fieldType instanceof GraphQLList) {
        return [mockType(fieldType.ofType)(...args), mockType(fieldType.ofType)(...args)];
      }
      if (mockFunctionMap.has(fieldType.name)) {
        // the object passed doesn't have this field, so we apply the default mock
        return mockFunctionMap.get(fieldType.name)(...args);
      }
      if (fieldType instanceof GraphQLObjectType) {
        // objects don't return actual data, we only need to mock scalars!
        return {};
      }
      // TODO mocking Interface and Union types will require determining the
      // resolve type before passing it on.
      // XXX we recommend a generic way for resolve type here, which is defining
      // typename on the object.
      if (fieldType instanceof GraphQLUnionType) {
        const randomType = getRandomElement(fieldType.getTypes());
        return {
          typename: randomType,
          ...mockType(randomType)(...args),
        };
      }
      if (fieldType instanceof GraphQLInterfaceType) {
        const possibleTypes = schema.getPossibleTypes(fieldType);
        const randomType = getRandomElement(possibleTypes);
        return {
          typename: randomType,
          ...mockType(randomType)(...args),
        };
      }
      if (fieldType instanceof GraphQLEnumType) {
        return getRandomElement(fieldType.getValues()).value;
      }
      if (defaultMockMap.has(fieldType.name)) {
        return defaultMockMap.get(fieldType.name)(...args);
      }
      // if we get to here, we don't have a value, and we don't have a mock for this type,
      // we could return undefined, but that would be hard to debug, so we throw instead.
      throw new Error(`No mock defined for type "${fieldType.name}"`);
    };
  };

  forEachField(schema, (field, typeName, fieldName) => {
    assignResolveType(field.type);
    let mockResolver;

    // we have to handle the root mutation and root query types differently,
    // because no resolver is called at the root.
    const isOnQueryType = typeName === (schema.getQueryType() || {}).name;
    const isOnMutationType = typeName === (schema.getMutationType() || {}).name;
    if (isOnQueryType || isOnMutationType) {
      if (mockFunctionMap.has(typeName)) {
        const rootMock = mockFunctionMap.get(typeName);
        if (rootMock()[fieldName]) {
          // TODO: assert that it's a function
          // eslint-disable-next-line no-param-reassign
          mockResolver = (root, ...rest) => {
            const updatedRoot = root || {}; // TODO: should we clone instead?
            updatedRoot[fieldName] = rootMock()[fieldName];
            // XXX this is a bit of a hack to still use mockType, which
            // lets you mock lists etc. as well
            // otherwise we could just set field.resolve to rootMock()[fieldName]
            // it's like pretending there was a resolve function that ran before
            // the root resolve function.
            return mockType(
              field.type, typeName, fieldName)(updatedRoot, ...rest);
          };
        }
      }
    }
    if (!mockResolver) {
      mockResolver = mockType(field.type, typeName, fieldName);
    }
    if (!preserveResolvers || !field.resolve) {
      // eslint-disable-next-line no-param-reassign
      field.resolve = mockResolver;
    } else {
      const oldResolver = field.resolve;
      // eslint-disable-next-line no-param-reassign
      field.resolve = (...args) => Promise.all([
        mockResolver(...args),
        oldResolver(...args),
      ]).then(values => {
        const [mockedValue, resolvedValue] = values;
        if (isObject(mockedValue) && isObject(resolvedValue)) {
          // Object.assign() won't do here, as we need to all properties, including
          // the non-enumerable ones and defined using Object.defineProperty
          return copyOwnProps({}, resolvedValue, mockedValue);
        }
        return resolvedValue;
      });
    }
  });
}

class MockList {
  // wrappedFunction can return another MockList or a value
  constructor(len, wrappedFunction) {
    this.len = len;
    if (typeof wrappedFunction !== 'undefined') {
      if (typeof wrappedFunction !== 'function') {
        throw new Error('Second argument to MockList must be a function or undefined');
      }
      this.wrappedFunction = wrappedFunction;
    }
  }

  mock(root, args, context, info, fieldType, mockTypeFunc) {
    function randint(low, high) {
      return Math.floor((Math.random() * ((high - low) + 1)) + low);
    }
    let arr;
    if (Array.isArray(this.len)) {
      arr = new Array(randint(this.len[0], this.len[1]));
    } else {
      arr = new Array(this.len);
    }
    for (let i = 0; i < arr.length; i++) {
      if (typeof this.wrappedFunction === 'function') {
        const res = this.wrappedFunction(root, args, context, info);
        if (res instanceof MockList) {
          const nullableType = getNullableType(fieldType.ofType);
          arr[i] = res.mock(root, args, context, info, nullableType, mockTypeFunc);
        } else {
          arr[i] = res;
        }
      } else {
        arr[i] = mockTypeFunc(fieldType.ofType)(root, args, context, info);
      }
    }
    return arr;
  }
}

export {
  addMockFunctionsToSchema,
  MockList,
  mockServer,
};
<commit_msg>fix linting test<commit_after>import {
  GraphQLSchema,
  GraphQLObjectType,
  GraphQLEnumType,
  GraphQLUnionType,
  GraphQLInterfaceType,
  GraphQLList,
  getNullableType,
  getNamedType,
} from 'graphql/type';
import { graphql } from 'graphql';
import uuid from 'node-uuid';
import { forEachField, buildSchemaFromTypeDefinitions } from './schemaGenerator';

// This function wraps addMockFunctionsToSchema for more convenience
function mockServer(schema, mocks = {}, preserveResolvers = false) {
  let mySchema = schema;
  if (!(schema instanceof GraphQLSchema)) {
    // TODO: provide useful error messages here if this fails
    mySchema = buildSchemaFromTypeDefinitions(schema);
  }
  addMockFunctionsToSchema({ schema: mySchema, mocks, preserveResolvers });

  return { query: (query, vars) => graphql(mySchema, query, {}, {}, vars) };
}

// TODO allow providing a seed such that lengths of list could be deterministic
// this could be done by using casual to get a random list length if the casual
// object is global.
function addMockFunctionsToSchema({ schema, mocks = {}, preserveResolvers = false } = {}) {
  function isObject(thing) {
    return thing === Object(thing) && !Array.isArray(thing);
  }
  if (!schema) {
    // XXX should we check that schema is an instance of GraphQLSchema?
    throw new Error('Must provide schema to mock');
  }
  if (!isObject(mocks)) {
    throw new Error('mocks must be of type Object');
  }

  // use Map internally, because that API is nicer.
  const mockFunctionMap = new Map();
  Object.keys(mocks).forEach((typeName) => {
    mockFunctionMap.set(typeName, mocks[typeName]);
  });

  mockFunctionMap.forEach((mockFunction, mockTypeName) => {
    if (typeof mockFunction !== 'function') {
      throw new Error(`mockFunctionMap[${mockTypeName}] must be a function`);
    }
  });

  const defaultMockMap = new Map();
  defaultMockMap.set('Int', () => Math.round(Math.random() * 200) - 100);
  defaultMockMap.set('Float', () => (Math.random() * 200) - 100);
  defaultMockMap.set('String', () => 'Hello World');
  defaultMockMap.set('Boolean', () => Math.random() > 0.5);
  defaultMockMap.set('ID', () => uuid.v4());

  function mergeObjects(a, b) {
    return Object.assign(a, b);
  }

  function copyOwnPropsIfNotPresent(target, source) {
    Object.getOwnPropertyNames(source).forEach(prop => {
      if (!Object.getOwnPropertyDescriptor(target, prop)) {
        Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop));
      }
    });
  }

  function copyOwnProps(target, ...sources) {
    sources.forEach(source => {
      let chain = source;
      while (chain) {
        copyOwnPropsIfNotPresent(target, chain);
        chain = Object.getPrototypeOf(chain);
      }
    });
    return target;
  }

  // returns a random element from that ary
  function getRandomElement(ary) {
    const sample = Math.floor(Math.random() * ary.length);
    return ary[sample];
  }

  // takes either an object or a (possibly nested) array
  // and completes the customMock object with any fields
  // defined on genericMock
  // only merges objects or arrays. Scalars are returned as is
  function mergeMocks(genericMockFunction, customMock) {
    if (Array.isArray(customMock)) {
      return customMock.map((el) => mergeMocks(genericMockFunction, el));
    }
    if (isObject(customMock)) {
      return mergeObjects(genericMockFunction(), customMock);
    }
    return customMock;
  }

  function assignResolveType(type) {
    const fieldType = getNullableType(type);
    const namedFieldType = getNamedType(fieldType);

    const oldResolveType = namedFieldType.resolveType;
    if (preserveResolvers && oldResolveType && oldResolveType.length) {
      return;
    }

    if (namedFieldType instanceof GraphQLUnionType ||
        namedFieldType instanceof GraphQLInterfaceType
    ) {
      // the default `resolveType` always returns null. We add a fallback
      // resolution that works with how unions and interface are mocked
      namedFieldType.resolveType = (data, context, info) =>
        info.schema.getType(data.typename);
    }
  }

  const mockType = function mockType(type, typeName, fieldName) {
    // order of precendence for mocking:
    // 1. if the object passed in already has fieldName, just use that
    // --> if it's a function, that becomes your resolver
    // --> if it's a value, the mock resolver will return that
    // 2. if the nullableType is a list, recurse
    // 2. if there's a mock defined for this typeName, that will be used
    // 3. if there's no mock defined, use the default mocks for this type
    return (...args) => {
      const [root, queryArgs, context, info] = args;

      // nullability doesn't matter for the purpose of mocking.
      const fieldType = getNullableType(type);
      const namedFieldType = getNamedType(fieldType);

      if (root && typeof root[fieldName] !== 'undefined') {
        let result;
        // if we're here, the field is already defined
        if (typeof root[fieldName] === 'function') {
          result = root[fieldName](...args);
          if (result instanceof MockList) {
            result = result.mock(...args, fieldType, mockType);
          }
        } else {
          result = root[fieldName];
        }

        // Now we merge the result with the default mock for this type.
        // This allows overriding defaults while writing very little code.
        if (mockFunctionMap.has(namedFieldType.name)) {
          result = mergeMocks(
            mockFunctionMap.get(namedFieldType.name).bind(null, ...args), result
          );
        }
        return result;
      }

      if (fieldType instanceof GraphQLList) {
        return [mockType(fieldType.ofType)(...args), mockType(fieldType.ofType)(...args)];
      }
      if (mockFunctionMap.has(fieldType.name)) {
        // the object passed doesn't have this field, so we apply the default mock
        return mockFunctionMap.get(fieldType.name)(...args);
      }
      if (fieldType instanceof GraphQLObjectType) {
        // objects don't return actual data, we only need to mock scalars!
        return {};
      }
      // TODO mocking Interface and Union types will require determining the
      // resolve type before passing it on.
      // XXX we recommend a generic way for resolve type here, which is defining
      // typename on the object.
      if (fieldType instanceof GraphQLUnionType) {
        const randomType = getRandomElement(fieldType.getTypes());
        return {
          typename: randomType,
          ...mockType(randomType)(...args),
        };
      }
      if (fieldType instanceof GraphQLInterfaceType) {
        const possibleTypes = schema.getPossibleTypes(fieldType);
        const randomType = getRandomElement(possibleTypes);
        return {
          typename: randomType,
          ...mockType(randomType)(...args),
        };
      }
      if (fieldType instanceof GraphQLEnumType) {
        return getRandomElement(fieldType.getValues()).value;
      }
      if (defaultMockMap.has(fieldType.name)) {
        return defaultMockMap.get(fieldType.name)(...args);
      }
      // if we get to here, we don't have a value, and we don't have a mock for this type,
      // we could return undefined, but that would be hard to debug, so we throw instead.
      throw new Error(`No mock defined for type "${fieldType.name}"`);
    };
  };

  forEachField(schema, (field, typeName, fieldName) => {
    assignResolveType(field.type);
    let mockResolver;

    // we have to handle the root mutation and root query types differently,
    // because no resolver is called at the root.
    const isOnQueryType = typeName === (schema.getQueryType() || {}).name;
    const isOnMutationType = typeName === (schema.getMutationType() || {}).name;
    if (isOnQueryType || isOnMutationType) {
      if (mockFunctionMap.has(typeName)) {
        const rootMock = mockFunctionMap.get(typeName);
        if (rootMock()[fieldName]) {
          // TODO: assert that it's a function
          // eslint-disable-next-line no-param-reassign
          mockResolver = (root, ...rest) => {
            const updatedRoot = root || {}; // TODO: should we clone instead?
            updatedRoot[fieldName] = rootMock()[fieldName];
            // XXX this is a bit of a hack to still use mockType, which
            // lets you mock lists etc. as well
            // otherwise we could just set field.resolve to rootMock()[fieldName]
            // it's like pretending there was a resolve function that ran before
            // the root resolve function.
            return mockType(
              field.type, typeName, fieldName)(updatedRoot, ...rest);
          };
        }
      }
    }
    if (!mockResolver) {
      mockResolver = mockType(field.type, typeName, fieldName);
    }
    if (!preserveResolvers || !field.resolve) {
      // eslint-disable-next-line no-param-reassign
      field.resolve = mockResolver;
    } else {
      const oldResolver = field.resolve;
      // eslint-disable-next-line no-param-reassign
      field.resolve = (...args) => Promise.all([
        mockResolver(...args),
        oldResolver(...args),
      ]).then(values => {
        const [mockedValue, resolvedValue] = values;
        if (isObject(mockedValue) && isObject(resolvedValue)) {
          // Object.assign() won't do here, as we need to all properties, including
          // the non-enumerable ones and defined using Object.defineProperty
          return copyOwnProps({}, resolvedValue, mockedValue);
        }
        return resolvedValue;
      });
    }
  });
}

class MockList {
  // wrappedFunction can return another MockList or a value
  constructor(len, wrappedFunction) {
    this.len = len;
    if (typeof wrappedFunction !== 'undefined') {
      if (typeof wrappedFunction !== 'function') {
        throw new Error('Second argument to MockList must be a function or undefined');
      }
      this.wrappedFunction = wrappedFunction;
    }
  }

  mock(root, args, context, info, fieldType, mockTypeFunc) {
    function randint(low, high) {
      return Math.floor((Math.random() * ((high - low) + 1)) + low);
    }
    let arr;
    if (Array.isArray(this.len)) {
      arr = new Array(randint(this.len[0], this.len[1]));
    } else {
      arr = new Array(this.len);
    }
    for (let i = 0; i < arr.length; i++) {
      if (typeof this.wrappedFunction === 'function') {
        const res = this.wrappedFunction(root, args, context, info);
        if (res instanceof MockList) {
          const nullableType = getNullableType(fieldType.ofType);
          arr[i] = res.mock(root, args, context, info, nullableType, mockTypeFunc);
        } else {
          arr[i] = res;
        }
      } else {
        arr[i] = mockTypeFunc(fieldType.ofType)(root, args, context, info);
      }
    }
    return arr;
  }
}

export {
  addMockFunctionsToSchema,
  MockList,
  mockServer,
};
<|endoftext|>


<commit_before>/*
 * Collection.js
 * Fabian Irsara
 * Copyright 2015, Licensed GPL & MIT
 */
define([
  '../sys',
  './Model',
  './fs',
  './API'
], function(
  sys,
  Model,
  fs,
  API
) {
  /**
   * A collection holds and manages several models in an array
   *
   * @example
   * var collection = new Collection('User', [1, 2, 10]);
   * collection.pull(_pulled);
   *
   * @class Collection
   * @extends data.Model
   * @memberof data
   * @param {String} model the class name of the collection's model (i.e. user.hasMany = 'apps' //model = 'apps')
   * @param {object|Number} data is either a data object or an id of the model that should be fetched
   **/
  function Collection(model, data){
    this.model = model.substring(0, 1).toUpperCase() + model.substring(1);

    Model.call(this);

    if (data) {
      if (! Array.isArray(data)) data = [data];

      var _allLoaded = true;
      var _allCached = true;
      var _allDefinedData = true;

      for (var i = 0; i < data.length; i++) {
        var instance = Model.factory(this.modelClass, data[i]);
        this[i] = instance;

        if (! instance._loaded) _allLoaded = false;
        if (! instance._cached) _allCached = false;
        if (! instance._definedData) _allDefinedData = false;
      }

      // if at least one instance of the collection did not load yet: define collection to be not ready yet
      this._loaded = _allLoaded;
      this._cached = _allCached;
      this._definedData = _allDefinedData;
    }

    this.length = this.getCount();
  }

  var p = sys.extend(Collection, Model);

  /**
   * loops through collection items and calls callback for each of the items
   * @method each
   * @memberof data.Collection
   * @instance
   * @protected
   * @param {Function} callback (item, index)
   **/
  p.each = function(callback){
    if (callback) {
      var items = this.getItems();

      for (var i = 0, _len = items.length; i < _len; i++) {
        callback.call(this, items[i], i);
      }
    }

    return this;
  };

  /**
   * adds an item to the collection list
   * @method add
   * @memberof data.Collection
   * @instance
   * @protected
   **/
  p.add = function(item){
    var instance = Model.factory(this.modelClass, item);
    this[this.length] = instance;
    this.length++;
  };

  /**
   * gets collection's specific url for pulling data
   * @method getPullURL
   * @memberof data.Collection
   * @instance
   * @protected
   **/
  p.getPullURL = function(){
    var ids = [];
    var items = this.getItems();
    var _len = items.length;

    if (_len === 0) {
      return API.endpoint + this.model + 's';
    }

    for (var i = 0; i < _len; i++) {
      ids.push('ids[]=' + items[i].id);
    }

    return API.endpoint + this.model + 's' + '?' + ids.join('&') + this.getQuery().replace('?', '&');
  };

  /**
   * gets collection's specific url for pushing data
   * @method getPushURL
   * @memberof data.Collection
   * @instance
   * @protected
   **/
  p.getPushURL = function(){
    return API.endpoint + this.model + 's';
  };

  /**
   * gets how many items the collection contains
   *
   * @method getCount
   * @memberof data.Collection
   * @public
   **/
  p.getCount = function(){
    return this.getItems().length;
  };

  /**
   * gets all collection models as an array
   *
   * @method getItems
   * @memberof data.Collection
   * @public
   **/
  p.getItems = function(deep, caller){
    var items = [];

    for (var k in this) {
      // if key is numeric (assume it's an item of the collection)
      if (this.hasOwnProperty(k) && ! isNaN(k)) {
        if (! items[parseFloat(k)]) {
          items.push(this[k]);
        }
      }
    }

    return items;
  };

  /**
   * overwrite get method. only call individual item's get function
   *
   * @method get
   * @memberof data.Model
   * @public
   * @instance
   * @param {String} key (optional)
   **/
  p.get = function(key, caller){
    var items = this.getItems();
    var data = [];

    for (var i = 0, _len = items.length; i < _len; i++) {
      // if key was set to true (i.e. if it wanted to deep trace collection)
      // call get on individual items by deep tracing, otherwise simply get plain item data
      var item = items[i].get(key, caller);
      data.push(item);
    }

    return data;
  };

  /**
   * overwrite set method by calling parent's set and storing collection count afterwards
   * @example
   * collection.set([{id: '1', version: '10', name: 'application'}]);
   *
   * @method set
   * @memberof data.Collection
   * @override
   * @instance
   * @public
   * @param {object|String} dataOrKey should be either
   * * a number (assumes it sets the model's id)
   * * an object with key-value pairs
   * * a key string (in this case needs to add value as second parameter)
   * @param {object|String} value to set on model
   **/
  p.set = function(dataOrKey, value){
    Model.prototype.set.call(this, dataOrKey, value);
    this.length = this.getCount();
  };

  /**
   * downloads model from server and stores it to a local file
   *
   * @method download
   * @memberof data.Collection
   * @instance
   * @protected
   * @param {function} callback
   * @param {function} errorCallback
   **/
  p.download = function(callback, errorCallback){
    var run = function(options){
      var error = options.error;

      options.error = function(err){
        if (options.overwrite === 'try') {
          options.error = error;
          options.overwrite = false;
          run(options);
        } else {
          if (error) {
            error(err);
          }
        }
      };

      var data = [];

      var getItem = function(index){
        if (options.local[index] || options.local.length === 0) {
          var localPath = fs.correctLocalFilePath(options.local[index]);

          fs.exists(localPath, function(exists){
            if (exists && ! options.overwrite) {
              fs.readFile(localPath, function(result){
                if (typeof result !== 'object') {
                  result = JSON.parse(result.toString());
                }

                data.push(result);
                getItem(index + 1);
              }, options.error);
            } else {
              fs.request(options.remote, function(result){
                if (typeof result !== 'object') {
                  result = JSON.parse(result.toString());
                }

                var writeItem = function(itemIndex){
                  if (result[itemIndex]) {
                    fs.writeFile(options.local[itemIndex], JSON.stringify(result[itemIndex]), function(){
                      writeItem(itemIndex + 1);
                    });
                  } else {
                    if (options.success) {
                      options.success(result);
                    }
                  }
                };

                writeItem(0);
              }, options.error);
            }
          });
        } else {
          if (options.success) {
            options.success(data);
          }
        }
      };

      getItem(0);
    };

    var options = {};
    options.overwrite = this.overwrite;
    options.success = callback;
    options.error = errorCallback;
    options.remote = this.getPullURL();
    options.local = [];

    var items = this.getItems();

    for (var i = 0, _len = items.length; i < _len; i++) {
      options.local.push('json/' + this.model + 's/' + this.model + '-' + items[i].id + '.json');
    }

    run(options);
  };

  /**
   * factories a new model collection
   *
   * @method factory
   * @memberof data.Collection
   * @public
   * @static
   * @example
   * Collection.factory('User', [1, 2, 5]);
   * @param {String} model a string of the model (i.e. 'User')
   * @param {object} data (optional). if defined returns the stored model if it already exists
   **/
  Collection.factory = function(model, data) {
    return new Collection(model, data);
  };

  return Collection;
});
<commit_msg>refactor add logic<commit_after>/*
 * Collection.js
 * Fabian Irsara
 * Copyright 2015, Licensed GPL & MIT
 */
define([
  '../sys',
  './Model',
  './fs',
  './API'
], function(
  sys,
  Model,
  fs,
  API
) {
  /**
   * A collection holds and manages several models in an array
   *
   * @example
   * var collection = new Collection('User', [1, 2, 10]);
   * collection.pull(_pulled);
   *
   * @class Collection
   * @extends data.Model
   * @memberof data
   * @param {String} model the class name of the collection's model (i.e. user.hasMany = 'apps' //model = 'apps')
   * @param {object|Number} data is either a data object or an id of the model that should be fetched
   **/
  function Collection(model, data){
    this.model = model.substring(0, 1).toUpperCase() + model.substring(1);

    Model.call(this);

    if (data) {
      if (! Array.isArray(data)) data = [data];

      var _allLoaded = true;
      var _allCached = true;
      var _allDefinedData = true;

      for (var i = 0; i < data.length; i++) {
        var instance = Model.factory(this.modelClass, data[i]);
        this[i] = instance;

        if (! instance._loaded) _allLoaded = false;
        if (! instance._cached) _allCached = false;
        if (! instance._definedData) _allDefinedData = false;
      }

      // if at least one instance of the collection did not load yet: define collection to be not ready yet
      this._loaded = _allLoaded;
      this._cached = _allCached;
      this._definedData = _allDefinedData;
    }

    this.length = this.getCount();
  }

  var p = sys.extend(Collection, Model);

  /**
   * loops through collection items and calls callback for each of the items
   * @method each
   * @memberof data.Collection
   * @instance
   * @protected
   * @param {Function} callback (item, index)
   **/
  p.each = function(callback){
    if (callback) {
      var items = this.getItems();

      for (var i = 0, _len = items.length; i < _len; i++) {
        callback.call(this, items[i], i);
      }
    }

    return this;
  };

  /**
   * adds an item to the collection list
   * @method add
   * @memberof data.Collection
   * @instance
   * @protected
   **/
  p.add = function(item){
    var instance = item;

    if (item instanceof Model === false) {
      instance = Model.factory(this.modelClass, item);
    }

    this[this.length] = instance;
    this.length++;
  };

  /**
   * gets collection's specific url for pulling data
   * @method getPullURL
   * @memberof data.Collection
   * @instance
   * @protected
   **/
  p.getPullURL = function(){
    var ids = [];
    var items = this.getItems();
    var _len = items.length;

    if (_len === 0) {
      return API.endpoint + this.model + 's';
    }

    for (var i = 0; i < _len; i++) {
      ids.push('ids[]=' + items[i].id);
    }

    return API.endpoint + this.model + 's' + '?' + ids.join('&') + this.getQuery().replace('?', '&');
  };

  /**
   * gets collection's specific url for pushing data
   * @method getPushURL
   * @memberof data.Collection
   * @instance
   * @protected
   **/
  p.getPushURL = function(){
    return API.endpoint + this.model + 's';
  };

  /**
   * gets how many items the collection contains
   *
   * @method getCount
   * @memberof data.Collection
   * @public
   **/
  p.getCount = function(){
    return this.getItems().length;
  };

  /**
   * gets all collection models as an array
   *
   * @method getItems
   * @memberof data.Collection
   * @public
   **/
  p.getItems = function(deep, caller){
    var items = [];

    for (var k in this) {
      // if key is numeric (assume it's an item of the collection)
      if (this.hasOwnProperty(k) && ! isNaN(k)) {
        if (! items[parseFloat(k)]) {
          items.push(this[k]);
        }
      }
    }

    return items;
  };

  /**
   * overwrite get method. only call individual item's get function
   *
   * @method get
   * @memberof data.Model
   * @public
   * @instance
   * @param {String} key (optional)
   **/
  p.get = function(key, caller){
    var items = this.getItems();
    var data = [];

    for (var i = 0, _len = items.length; i < _len; i++) {
      // if key was set to true (i.e. if it wanted to deep trace collection)
      // call get on individual items by deep tracing, otherwise simply get plain item data
      var item = items[i].get(key, caller);
      data.push(item);
    }

    return data;
  };

  /**
   * overwrite set method by calling parent's set and storing collection count afterwards
   * @example
   * collection.set([{id: '1', version: '10', name: 'application'}]);
   *
   * @method set
   * @memberof data.Collection
   * @override
   * @instance
   * @public
   * @param {object|String} dataOrKey should be either
   * * a number (assumes it sets the model's id)
   * * an object with key-value pairs
   * * a key string (in this case needs to add value as second parameter)
   * @param {object|String} value to set on model
   **/
  p.set = function(dataOrKey, value){
    Model.prototype.set.call(this, dataOrKey, value);
    this.length = this.getCount();
  };

  /**
   * downloads model from server and stores it to a local file
   *
   * @method download
   * @memberof data.Collection
   * @instance
   * @protected
   * @param {function} callback
   * @param {function} errorCallback
   **/
  p.download = function(callback, errorCallback){
    var run = function(options){
      var error = options.error;

      options.error = function(err){
        if (options.overwrite === 'try') {
          options.error = error;
          options.overwrite = false;
          run(options);
        } else {
          if (error) {
            error(err);
          }
        }
      };

      var data = [];

      var getItem = function(index){
        if (options.local[index] || options.local.length === 0) {
          var localPath = fs.correctLocalFilePath(options.local[index]);

          fs.exists(localPath, function(exists){
            if (exists && ! options.overwrite) {
              fs.readFile(localPath, function(result){
                if (typeof result !== 'object') {
                  result = JSON.parse(result.toString());
                }

                data.push(result);
                getItem(index + 1);
              }, options.error);
            } else {
              fs.request(options.remote, function(result){
                if (typeof result !== 'object') {
                  result = JSON.parse(result.toString());
                }

                var writeItem = function(itemIndex){
                  if (result[itemIndex]) {
                    fs.writeFile(options.local[itemIndex], JSON.stringify(result[itemIndex]), function(){
                      writeItem(itemIndex + 1);
                    });
                  } else {
                    if (options.success) {
                      options.success(result);
                    }
                  }
                };

                writeItem(0);
              }, options.error);
            }
          });
        } else {
          if (options.success) {
            options.success(data);
          }
        }
      };

      getItem(0);
    };

    var options = {};
    options.overwrite = this.overwrite;
    options.success = callback;
    options.error = errorCallback;
    options.remote = this.getPullURL();
    options.local = [];

    var items = this.getItems();

    for (var i = 0, _len = items.length; i < _len; i++) {
      options.local.push('json/' + this.model + 's/' + this.model + '-' + items[i].id + '.json');
    }

    run(options);
  };

  /**
   * factories a new model collection
   *
   * @method factory
   * @memberof data.Collection
   * @public
   * @static
   * @example
   * Collection.factory('User', [1, 2, 5]);
   * @param {String} model a string of the model (i.e. 'User')
   * @param {object} data (optional). if defined returns the stored model if it already exists
   **/
  Collection.factory = function(model, data) {
    return new Collection(model, data);
  };

  return Collection;
});
<|endoftext|>


<commit_before><commit_msg>use plain JavaScript arrays for ranges in coset table code<commit_after><|endoftext|>


<commit_before>define([
	'goo/sound/AudioContext',
	'goo/math/MathUtils',
	'goo/util/rsvp'
],
/** @lends */
function (
	AudioContext,
	MathUtils,
	RSVP
) {
	'use strict';

	/**
	 * @class A representation of a sound in the engine
	 */
	function Sound() {
		if (!AudioContext) {
			console.warn('Cannot create sound, webaudio not supported');
			return;
		}

		// Settings
		this.id = null;
		this._loop = false;
		this._rate = 1.0;
		this._offset = 0;
		this._duration = null;
		this._volume = 1.0;

		// Nodes
		this._buffer = null;
		this._currentSource = null;
		this._outNode = AudioContext.createGain();
		this.connectTo();

		// Playback memory
		this._playStart = 0;
		this._pausePos = 0;
		//this._endTimer = null;
		this._endPromise = null;

		this._paused = false;
	}

	/**
	 * Plays the sound if it's not playing
	 * @returns {RSVP.Promise} Resolves when sound has played through or when it's stopped.
	 * Looping sounds will never resolve
	 */
	Sound.prototype.play = function() {
		if (!AudioContext) {
			console.warn('Webaudio not supported');
			return;
		}
		if (this._currentSource) {
			return this._endPromise;
		}
		this._endPromise = new RSVP.Promise();
		if (!this._buffer) {
			return this._endPromise;
		}

		var currentSource = this._currentSource = AudioContext.createBufferSource();

		this._paused = false;
		this._currentSource.onended = function () {
			if (this._currentSource === currentSource && !this._paused) {
				this.stop();
			}
		}.bind(this);

		this._currentSource.playbackRate.value = this._rate;
		this._currentSource.connect(this._outNode);
		this._currentSource.buffer = this._buffer;
		this._currentSource.loop = this._loop;
		if (this._loop) {
			this._currentSource.loopStart = this._offset;
			this._currentSource.loopEnd = this._duration + this._offset;
		}

		this._playStart = AudioContext.currentTime - this._pausePos;
		var duration = this._duration - this._pausePos;

		this._currentSource.start(0, this._pausePos + this._offset, duration);

		return this._endPromise;
	};

	/**
	 * Pauses the sound if it's playing
	 */
	Sound.prototype.pause = function() {
		if (!AudioContext) {
			console.warn('Webaudio not supported');
			return;
		}
		if (!this._currentSource) {
			return;
		}
		this._paused = true;

		this._pausePos = (AudioContext.currentTime - this._playStart) % this._duration;
		this._pausePos /= this._rate;
		this._stop();
	};

	/**
	 * Stops the sound if it's playing
	 */
	Sound.prototype.stop = function() {
		if (!AudioContext) {
			console.warn('Webaudio not supported');
			return;
		}
		this._paused = false;
		this._pausePos = 0;
		if (this._endPromise) {
			this._endPromise.resolve();
		}
		if (this._currentSource) {
			this._stop();
		}
	};

	Sound.prototype.fadeIn = function(time) {
		this.stop();
		var volume = this._volume;
		this._outNode.gain.value = 0;
		var p = this.fade(volume, time);
		this.play();
		return p;
	};

	Sound.prototype.fadeOut = function(time) {
		return this.fade(0, time);
	};

	Sound.prototype.fade = function(volume, time) {
		this._outNode.gain.setValueAtTime(this._outNode.gain.value, AudioContext.currentTime);
		this._outNode.gain.linearRampToValueAtTime(volume, AudioContext.currentTime + time);
		var p = new RSVP.Promise();
		setTimeout(function() {
			p.resolve();
		}, time * 1000);
		return p;
	};

	Sound.prototype.isPlaying = function() {
		return !!this._currentSource;
	};

	/**
	 * Does the actual stopping of the sound
	 * @private
	 */
	Sound.prototype._stop = function() {
		this._currentSource.stop(0);
		this._currentSource = null;
	};

	/**
	 * Updates the sound according to config
	 * @param {object} [config]
	 * @param {boolean} [config.loop]
	 * @param {number} [config.volume]
	 * @param {number} [config.start] Start offset in seconds.
	 * Will be clamped to be in actual soundclip duration
	 * @param {number} [config.duration] Duration of the sound.
	 * Will be clamped to be in actual soundclip duration
	 * @param {number} [config.rate] Playback rate of the sound
	 */
	Sound.prototype.update = function(config) {
		if (!AudioContext) {
			console.warn('Webaudio not supported');
			return;
		}
		config = config || {};
		if (config.id !== undefined) {
			this.id = config.id;
		}
		if (config.loop !== undefined) {
			this._loop = !!config.loop;
			if (this._currentSource) {
				this._currentSource.loop = this._loop;
			}
		}
		if (config.volume !== undefined) {
			this._volume = MathUtils.clamp(config.volume, 0, 1);
			this._outNode.gain.value = this._volume;
		}
		if (config.offset !== undefined) {
			this._offset = config.offset;
		}
		if (config.duration !== undefined) {
			this._duration = config.duration;
		}
		if (config.timeScale !== undefined) {
			this._rate = config.timeScale;
			//! AT: should have the same name if they are the same thing
			// problem is that there are plenty of projects out there that have timeScale instead of rate
			// timeScale was considered because it's the same as for animations
			// rate would have been preferred to timeScale as it's the term used by WebAudio
		}
		if (this._buffer) {
			this._clampInterval();
		}
	};

	/**
	 * Clamps the start offset and duration to be in sound range
	 * @private
	 */
	Sound.prototype._clampInterval = function() {
		this._offset = Math.min(this._offset, this._buffer.duration);
		if (this._duration !== null) {
			this._duration = Math.min(this._buffer.duration - this._offset, this._duration);
		} else {
			this._duration = this._buffer.duration - this._offset;
		}
		this._pausePos = MathUtils.clamp(this._pausePos, 0, this._duration);
	};

	/**
	 * Connect output of sound to audionodes
	 * @param {AudioNode[]|AudioNode} nodes
	 */
	Sound.prototype.connectTo = function(nodes) {
		if (!AudioContext) {
			console.warn('Webaudio not supported');
			return;
		}
		this._outNode.disconnect();
		if (!nodes) {
			return;
		}
		if (!(nodes instanceof Array)) {
			nodes = [nodes];
		}
		for (var i = 0; i < nodes.length; i++) {
			this._outNode.connect(nodes[i]);
		}
	};

	/**
	 * Sets the audio buffer which will be the sound source
	 * @param {AudioBuffer} buffer
	 */
	Sound.prototype.setAudioBuffer = function(buffer) {
		if (!AudioContext) {
			console.warn('Webaudio not supported');
			return;
		}
		this._buffer = buffer;
		this._clampInterval();
	};

	return Sound;
});<commit_msg>fixed a small jsdocs bug in Sound.update<commit_after>define([
	'goo/sound/AudioContext',
	'goo/math/MathUtils',
	'goo/util/rsvp'
],
/** @lends */
function (
	AudioContext,
	MathUtils,
	RSVP
) {
	'use strict';

	/**
	 * @class A representation of a sound in the engine
	 */
	function Sound() {
		if (!AudioContext) {
			console.warn('Cannot create sound, webaudio not supported');
			return;
		}

		// Settings
		this.id = null;
		this._loop = false;
		this._rate = 1.0;
		this._offset = 0;
		this._duration = null;
		this._volume = 1.0;

		// Nodes
		this._buffer = null;
		this._currentSource = null;
		this._outNode = AudioContext.createGain();
		this.connectTo();

		// Playback memory
		this._playStart = 0;
		this._pausePos = 0;
		//this._endTimer = null;
		this._endPromise = null;

		this._paused = false;
	}

	/**
	 * Plays the sound if it's not playing
	 * @returns {RSVP.Promise} Resolves when sound has played through or when it's stopped.
	 * Looping sounds will never resolve
	 */
	Sound.prototype.play = function() {
		if (!AudioContext) {
			console.warn('Webaudio not supported');
			return;
		}
		if (this._currentSource) {
			return this._endPromise;
		}
		this._endPromise = new RSVP.Promise();
		if (!this._buffer) {
			return this._endPromise;
		}

		var currentSource = this._currentSource = AudioContext.createBufferSource();

		this._paused = false;
		this._currentSource.onended = function () {
			if (this._currentSource === currentSource && !this._paused) {
				this.stop();
			}
		}.bind(this);

		this._currentSource.playbackRate.value = this._rate;
		this._currentSource.connect(this._outNode);
		this._currentSource.buffer = this._buffer;
		this._currentSource.loop = this._loop;
		if (this._loop) {
			this._currentSource.loopStart = this._offset;
			this._currentSource.loopEnd = this._duration + this._offset;
		}

		this._playStart = AudioContext.currentTime - this._pausePos;
		var duration = this._duration - this._pausePos;

		this._currentSource.start(0, this._pausePos + this._offset, duration);

		return this._endPromise;
	};

	/**
	 * Pauses the sound if it's playing
	 */
	Sound.prototype.pause = function() {
		if (!AudioContext) {
			console.warn('Webaudio not supported');
			return;
		}
		if (!this._currentSource) {
			return;
		}
		this._paused = true;

		this._pausePos = (AudioContext.currentTime - this._playStart) % this._duration;
		this._pausePos /= this._rate;
		this._stop();
	};

	/**
	 * Stops the sound if it's playing
	 */
	Sound.prototype.stop = function() {
		if (!AudioContext) {
			console.warn('Webaudio not supported');
			return;
		}
		this._paused = false;
		this._pausePos = 0;
		if (this._endPromise) {
			this._endPromise.resolve();
		}
		if (this._currentSource) {
			this._stop();
		}
	};

	Sound.prototype.fadeIn = function(time) {
		this.stop();
		var volume = this._volume;
		this._outNode.gain.value = 0;
		var p = this.fade(volume, time);
		this.play();
		return p;
	};

	Sound.prototype.fadeOut = function(time) {
		return this.fade(0, time);
	};

	Sound.prototype.fade = function(volume, time) {
		this._outNode.gain.setValueAtTime(this._outNode.gain.value, AudioContext.currentTime);
		this._outNode.gain.linearRampToValueAtTime(volume, AudioContext.currentTime + time);
		var p = new RSVP.Promise();
		setTimeout(function() {
			p.resolve();
		}, time * 1000);
		return p;
	};

	Sound.prototype.isPlaying = function() {
		return !!this._currentSource;
	};

	/**
	 * Does the actual stopping of the sound
	 * @private
	 */
	Sound.prototype._stop = function() {
		this._currentSource.stop(0);
		this._currentSource = null;
	};

	/**
	 * Updates the sound according to config
	 * @param {object} [config]
	 * @param {boolean} [config.loop]
	 * @param {number} [config.volume]
	 * @param {number} [config.start] Start offset in seconds.
	 * Will be clamped to be in actual soundclip duration
	 * @param {number} [config.duration] Duration of the sound.
	 * Will be clamped to be in actual soundclip duration
	 * @param {number} [config.timeScale] Playback rate of the sound
	 */
	Sound.prototype.update = function(config) {
		if (!AudioContext) {
			console.warn('Webaudio not supported');
			return;
		}
		config = config || {};
		if (config.id !== undefined) {
			this.id = config.id;
		}
		if (config.loop !== undefined) {
			this._loop = !!config.loop;
			if (this._currentSource) {
				this._currentSource.loop = this._loop;
			}
		}
		if (config.volume !== undefined) {
			this._volume = MathUtils.clamp(config.volume, 0, 1);
			this._outNode.gain.value = this._volume;
		}
		if (config.offset !== undefined) {
			this._offset = config.offset;
		}
		if (config.duration !== undefined) {
			this._duration = config.duration;
		}
		if (config.timeScale !== undefined) {
			this._rate = config.timeScale;
			//! AT: should have the same name if they are the same thing
			// problem is that there are plenty of projects out there that have timeScale instead of rate
			// timeScale was considered because it's the same as for animations
			// rate would have been preferred to timeScale as it's the term used by WebAudio
		}
		if (this._buffer) {
			this._clampInterval();
		}
	};

	/**
	 * Clamps the start offset and duration to be in sound range
	 * @private
	 */
	Sound.prototype._clampInterval = function() {
		this._offset = Math.min(this._offset, this._buffer.duration);
		if (this._duration !== null) {
			this._duration = Math.min(this._buffer.duration - this._offset, this._duration);
		} else {
			this._duration = this._buffer.duration - this._offset;
		}
		this._pausePos = MathUtils.clamp(this._pausePos, 0, this._duration);
	};

	/**
	 * Connect output of sound to audionodes
	 * @param {AudioNode[]|AudioNode} nodes
	 */
	Sound.prototype.connectTo = function(nodes) {
		if (!AudioContext) {
			console.warn('Webaudio not supported');
			return;
		}
		this._outNode.disconnect();
		if (!nodes) {
			return;
		}
		if (!(nodes instanceof Array)) {
			nodes = [nodes];
		}
		for (var i = 0; i < nodes.length; i++) {
			this._outNode.connect(nodes[i]);
		}
	};

	/**
	 * Sets the audio buffer which will be the sound source
	 * @param {AudioBuffer} buffer
	 */
	Sound.prototype.setAudioBuffer = function(buffer) {
		if (!AudioContext) {
			console.warn('Webaudio not supported');
			return;
		}
		this._buffer = buffer;
		this._clampInterval();
	};

	return Sound;
});<|endoftext|>


<commit_before><commit_msg>update http/simple-get — v.2<commit_after><|endoftext|>


<commit_before>Elm.Native.Json = {};
Elm.Native.Json.make = function(elm) {

  elm.Native = elm.Native || {};
  elm.Native.Json = elm.Native.Json || {};
  if (elm.Native.Json.values) return elm.Native.Json.values;

  var Maybe = Elm.Maybe.make(elm);
  var Dict = Elm.Dict.make(elm);
  var List = Elm.List.make(elm);
  var JS = Elm.JavaScript.make(elm);
  var Utils = Elm.Native.Utils.make(elm);

  function fromValue(v) {
    switch (v.ctor) {
    case 'Null'   : return null;
    case 'String' : return JS.fromString(v._0);
    case 'Number' : return v._0;
    case 'Boolean': return v._0;
    case 'Object' :
      var obj = {};
      var array = JS.fromList(Dict.toList(v._0));
      for (var i = array.length; i--; ) {
        var entry = array[i];
        obj[JS.fromString(entry._0)] = fromValue(entry._1);
      }
      return obj;
    case 'Array'  :
      var array = JS.fromList(v._0);
      for (var i = array.length; i--; ) {
	array[i] = fromValue(array[i]);
      }
      return array;
    }
  }

  function toString(sep, value) {
    return JSON.stringify(fromValue(value), null, JS.fromString(sep));
  }

  function toValue(v) {
    switch (typeof v) {
    case 'string' : return { ctor:"String" , _0: JS.toString(v) };
    case 'number' : return { ctor:"Number" , _0: JS.toFloat(v)  };
    case 'boolean': return { ctor:"Boolean", _0: JS.toBool(v)   };
    case 'object' :
      if (v === null) return { ctor:"Null" };
      if (v instanceof Array) {
          for (var i = v.length; i--; ) { v[i] = toValue(v[i]); }
	  return { ctor:"Array", _0: JS.toList(v) };
      }
      var array = [];
      for (var k in v) array.push(Utils.Tuple2(JS.toString(k), toValue(v[k])));
      return { ctor:"Object", _0: Dict.fromList(JS.toList(array)) };
    }
  }

  function fromString(str) {
    try {
	return Maybe.Just(toValue(JSON.parse(JS.fromString(str))));
    } catch (e) {
	return Maybe.Nothing;
    }
  }

  return elm.Native.Json.values = {
      toString : F2(toString),
      fromString : fromString,
  };

};
<commit_msg>cosmetic: normalize indentation<commit_after>Elm.Native.Json = {};
Elm.Native.Json.make = function(elm) {

    elm.Native = elm.Native || {};
    elm.Native.Json = elm.Native.Json || {};
    if (elm.Native.Json.values) return elm.Native.Json.values;

    var Maybe = Elm.Maybe.make(elm);
    var Dict = Elm.Dict.make(elm);
    var List = Elm.List.make(elm);
    var JS = Elm.JavaScript.make(elm);
    var Utils = Elm.Native.Utils.make(elm);

    function fromValue(v) {
        switch (v.ctor) {
        case 'Null'   : return null;
        case 'String' : return JS.fromString(v._0);
        case 'Number' : return v._0;
        case 'Boolean': return v._0;
        case 'Object' :
            var obj = {};
            var array = JS.fromList(Dict.toList(v._0));
            for (var i = array.length; i--; ) {
                var entry = array[i];
                obj[JS.fromString(entry._0)] = fromValue(entry._1);
            }
            return obj;
        case 'Array'  :
            var array = JS.fromList(v._0);
            for (var i = array.length; i--; ) {
	        array[i] = fromValue(array[i]);
            }
            return array;
        }
    }

    function toString(sep, value) {
        return JSON.stringify(fromValue(value), null, JS.fromString(sep));
    }

    function toValue(v) {
        switch (typeof v) {
        case 'string' : return { ctor:"String" , _0: JS.toString(v) };
        case 'number' : return { ctor:"Number" , _0: JS.toFloat(v)  };
        case 'boolean': return { ctor:"Boolean", _0: JS.toBool(v)   };
        case 'object' :
            if (v === null) return { ctor:"Null" };
            if (v instanceof Array) {
                for (var i = v.length; i--; ) { v[i] = toValue(v[i]); }
	        return { ctor:"Array", _0: JS.toList(v) };
            }
            var array = [];
            for (var k in v) array.push(Utils.Tuple2(JS.toString(k), toValue(v[k])));
            return { ctor:"Object", _0: Dict.fromList(JS.toList(array)) };
        }
    }

    function fromString(str) {
        try {
	    return Maybe.Just(toValue(JSON.parse(JS.fromString(str))));
        } catch (e) {
	    return Maybe.Nothing;
        }
    }

    return elm.Native.Json.values = {
        toString : F2(toString),
        fromString : fromString,
    };

};
<|endoftext|>


<commit_before>/**
  Copyright 2010-2011 Ondrej Certik <ondrej@certik.cz>
  Copyright 2010-2011 Mateusz Paprocki <mattpap@gmail.com>
  Copyright 2011 Christian Iversen <ci@sikkerhed.org>

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
**/

var tuple = __inherit(object, "tuple");

tuple.PY$__init__ = function(seq) {
    if (arguments.length > 1) {
        throw py_builtins.TypeError("tuple() takes at most 1 argument (" + arguments.length + " given)");
    } else if (seq === undefined) {
        this.items = [];
    } else if (seq.PY$__class__ === list || seq.PY$__class__ === tuple) {
        this.items = seq.items.concat();
    } else {
        var that = this;
        this.items = [];
        iterate(seq, function(elm) {
                    if (typeof(elm) == 'number')
                        that.items.push(int(elm));
                    else if (typeof(elm) == 'string')
                        that.items.push(str(elm));
                    else
                        that.items.push(elm);
                });
    }
};

tuple.PY$__str__ = function () {
    if (this.items.length === 0) {
        return str("()");
    } else if (this.items.length === 1) {
        return str("(" + str(this.items[0])._js_() + ",)");
    } else {
        var res = "(" + js(py_builtins.repr(this.items[0]));
        for (var i = 1; i < this.items.length; i++)  {
            res += ", " + js(py_builtins.repr(this.items[i]));
        }
        return str(res + ")");
    }
};

tuple.PY$__repr__ = tuple.PY$__str__;

tuple.PY$__eq__ = function (other) {
    if (other.PY$__class__ == this.PY$__class__) {
        if (js(py_builtins.len(this)) != js(py_builtins.len(other))) {
            return False;
        }
        var len = js(py_builtins.len(this));
        for (var i = 0; i < len; i++) {
            if (this.items[i].PY$__ne__(other.items[i]) == True) {
                return False;
            }
        }
        return True;
    } else {
        return False;
    }
};

tuple.PY$__cmp__ = function (other) {
    if (other.PY$__class__ !== this.PY$__class__) {
        if (object.PY$__gt__.call(this, other) == True) {
            return $c1;
        } else {
            if (object.PY$__lt__.call(this, other) == True) {
                return $cn1;
            } else {
                return $c0;
            }
        }
    } else {
        var count = 0;
        var res = $c0;
        try {
            var it = iter(other);
        } catch (exc) {
            if ($PY.isinstance(exc, py_builtins.TypeError)) {
                return $c1;
            } else {
                throw exc;
            }
        }

        while (true) {
            try {
                var elm = it.PY$next();
            } catch (exc) {
                if (exc === $PY.StopIter || $PY.isinstance(exc, py_builtins.StopIteration)) {
                    break;
                } else {
                    throw exc;
                }
            }
            if (count >= this.items.length) {
                res = $cn1;
                break;
            }
            var r = this.items[count].PY$__cmp__(elm);

            if (r.PY$__gt__($c0) == True) {
                res = $c1;
                break;
            } else if (r.PY$__lt__($c0) == True) {
                res = $cn1;
                break;
            }
            count++;
        }

        if (res == $c0) {
            if (this.items.length > count) {
                return $c1;
            } else {
                return $c0;
            }
        } else {
            return res;
        }
    }
};

tuple.PY$__gt__ = function (other) {
    return this.PY$__cmp__(other).PY$__gt__($c0);
};

tuple.PY$__lt__ = function (other) {
    return this.PY$__cmp__(other).PY$__lt__($c0);
};

tuple.PY$__mul__ = function(num) {
    if ($PY.isinstance(num, int)) {
        var res = [];
        var count = num._js_();
        for (var i = 0; i < count; i++) {
            res = res.concat(this.items);
        }
        return this.PY$__class__(res);
    } else {
        var name = this.PY$__class__.PY$__name__;
        throw py_builtins.NotImplementedError("Cannot multiply " + name + " and non-int");
    }
};

tuple.PY$__add__ = function(other) {
    if (this.PY$__class__ == other.PY$__class__) {
        var res = this.items.concat([]);
        iterate(other, function(elm) {
                    res.push(elm);
                });
        return this.PY$__class__(res);
    } else {
        var name = this.PY$__class__.PY$__name__;
        throw py_builtins.NotImplementedError("Cannot add " + name + " and non-" + name);
    }
};

tuple._js_ = function () {
    var items = [];

    iterate(this, function(item) {
        items.push(js(item));
    });

    return items;
};

tuple.PY$__hash__ = function () {
    var value = 0x345678;
    var length = js(this.PY$__len__());

    for (var index in this.items) {
        value = ((1000003*value) & 0xFFFFFFFF) ^ py_builtins.hash(this.items[index]);
        value = value ^ length;
    }

    if (value == -1) {
        value = -2;
    }

    return value;
};

tuple.PY$__len__ = function() {
    return int(this.items.length);
};

tuple.PY$__iter__ = function() {
    return iter(this.items);
};

tuple.PY$__contains__ = function(item) {
    for (var index in this.items) {
        if (this.items[index].PY$__eq__(item) == True) {
            return True;
        }
    }

    return False;
};

tuple.PY$__getitem__ = function(index) {
    if (typeof(index) === 'number') index = int(index);
    var seq;
    if ($PY.isinstance(index, slice)) {
        var s = index;
        var inds = js(s.PY$indices(py_builtins.len(this)));
        var start = inds[0];
        var stop = inds[1];
        var step = inds[2];
        seq = [];
        for (var i = start; i < stop; i += step) {
            seq.push(this.items[i]);
        }
        return this.PY$__class__(seq);
    } else {
        if (!$PY.isinstance(index, int)) {
            index = int(index);
        }

        if (js(index.PY$__ge__($c0)) && js(index.PY$__lt__(py_builtins.len(this)))) {
            return this.items[index.PY$__int__()._js_()];
        } else if (js(index.PY$__lt__($c0)) && js(index.PY$__ge__(py_builtins.len(this).PY$__neg__()))) {
            return this.items[index.PY$__add__(py_builtins.len(this)).PY$__int__()._js_()];
        } else {
            throw py_builtins.IndexError("list index out of range");
        }
    }
};

tuple.PY$__setitem__ = function() {
    throw py_builtins.TypeError("'tuple' object doesn't support item assignment");
};

tuple.PY$__delitem__ = function() {
    throw py_builtins.TypeError("'tuple' object doesn't support item deletion");
};

tuple.PY$count = function(value) {
    var count = 0;

    for (var index in this.items) {
        if (this.items[index].PY$__eq__(value) == True) {
            count += 1;
        }
    }

    return count;
};

tuple.PY$index = function(value, start, end) {
    if (start === undefined) {
        start = 0;
    } else {
        start = js(start);
    }
    end = js(end);

    for (var i = start; (end === undefined) || (start < end); i++) {
        var _value = this.items[i];

        if (_value === undefined) {
            break;
        }

        if (_value.PY$__eq__(value) == True) {
            return int(i);
        }
    }

    throw py_builtins.ValueError(this.PY$__class__.PY$__name__ + ".index(x): x not in list");
};

$PY.tuple = tuple;
$PY.$c_emptytuple = tuple();
<commit_msg> * Make tuple.PY$__getitem__ use javascript types internally instead    of using __pythonic__ style methods, since it is faster.<commit_after>/**
  Copyright 2010-2011 Ondrej Certik <ondrej@certik.cz>
  Copyright 2010-2011 Mateusz Paprocki <mattpap@gmail.com>
  Copyright 2011 Christian Iversen <ci@sikkerhed.org>

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
**/

var tuple = __inherit(object, "tuple");

tuple.PY$__init__ = function(seq) {
    if (arguments.length > 1) {
        throw py_builtins.TypeError("tuple() takes at most 1 argument (" + arguments.length + " given)");
    } else if (seq === undefined) {
        this.items = [];
    } else if (seq.PY$__class__ === list || seq.PY$__class__ === tuple) {
        this.items = seq.items.concat();
    } else {
        var that = this;
        this.items = [];
        iterate(seq, function(elm) {
                    if (typeof(elm) == 'number')
                        that.items.push(int(elm));
                    else if (typeof(elm) == 'string')
                        that.items.push(str(elm));
                    else
                        that.items.push(elm);
                });
    }
};

tuple.PY$__str__ = function () {
    if (this.items.length === 0) {
        return str("()");
    } else if (this.items.length === 1) {
        return str("(" + str(this.items[0])._js_() + ",)");
    } else {
        var res = "(" + js(py_builtins.repr(this.items[0]));
        for (var i = 1; i < this.items.length; i++)  {
            res += ", " + js(py_builtins.repr(this.items[i]));
        }
        return str(res + ")");
    }
};

tuple.PY$__repr__ = tuple.PY$__str__;

tuple.PY$__eq__ = function (other) {
    if (other.PY$__class__ == this.PY$__class__) {
        if (this.items.length != js(py_builtins.len(other))) {
            return False;
        }
        for (var i = 0; i < this.items.length; i++) {
            if (this.items[i].PY$__ne__(other.items[i]) == True) {
                return False;
            }
        }
        return True;
    } else {
        return False;
    }
};

tuple.PY$__cmp__ = function (other) {
    if (other.PY$__class__ !== this.PY$__class__) {
        if (object.PY$__gt__.call(this, other) == True) {
            return $c1;
        } else {
            if (object.PY$__lt__.call(this, other) == True) {
                return $cn1;
            } else {
                return $c0;
            }
        }
    } else {
        var count = 0;
        var res = $c0;
        try {
            var it = iter(other);
        } catch (exc) {
            if ($PY.isinstance(exc, py_builtins.TypeError)) {
                return $c1;
            } else {
                throw exc;
            }
        }

        while (true) {
            try {
                var elm = it.PY$next();
            } catch (exc) {
                if (exc === $PY.StopIter || $PY.isinstance(exc, py_builtins.StopIteration)) {
                    break;
                } else {
                    throw exc;
                }
            }
            if (count >= this.items.length) {
                res = $cn1;
                break;
            }
            var r = this.items[count].PY$__cmp__(elm);

            if (r.PY$__gt__($c0) == True) {
                res = $c1;
                break;
            } else if (r.PY$__lt__($c0) == True) {
                res = $cn1;
                break;
            }
            count++;
        }

        if (res == $c0) {
            if (this.items.length > count) {
                return $c1;
            } else {
                return $c0;
            }
        } else {
            return res;
        }
    }
};

tuple.PY$__gt__ = function (other) {
    return this.PY$__cmp__(other).PY$__gt__($c0);
};

tuple.PY$__lt__ = function (other) {
    return this.PY$__cmp__(other).PY$__lt__($c0);
};

tuple.PY$__mul__ = function(num) {
    if ($PY.isinstance(num, int)) {
        var res = [];
        var count = num._js_();
        for (var i = 0; i < count; i++) {
            res = res.concat(this.items);
        }
        return this.PY$__class__(res);
    } else {
        var name = this.PY$__class__.PY$__name__;
        throw py_builtins.NotImplementedError("Cannot multiply " + name + " and non-int");
    }
};

tuple.PY$__add__ = function(other) {
    if (this.PY$__class__ == other.PY$__class__) {
        var res = this.items.concat([]);
        iterate(other, function(elm) {
                    res.push(elm);
                });
        return this.PY$__class__(res);
    } else {
        var name = this.PY$__class__.PY$__name__;
        throw py_builtins.NotImplementedError("Cannot add " + name + " and non-" + name);
    }
};

tuple._js_ = function () {
    var items = [];

    iterate(this, function(item) {
        items.push(js(item));
    });

    return items;
};

tuple.PY$__hash__ = function () {
    var value = 0x345678;
    var length = this.items.length;

    for (var index in this.items) {
        value = ((1000003*value) & 0xFFFFFFFF) ^ py_builtins.hash(this.items[index]);
        value = value ^ length;
    }

    if (value == -1) {
        value = -2;
    }

    return value;
};

tuple.PY$__len__ = function() {
    return int(this.items.length);
};

tuple.PY$__iter__ = function() {
    return iter(this.items);
};

tuple.PY$__contains__ = function(item) {
    for (var index in this.items) {
        if (this.items[index].PY$__eq__(item) == True) {
            return True;
        }
    }

    return False;
};

tuple.PY$__getitem__ = function(index) {
    var seq;
    if ($PY.isinstance(index, slice)) {
        var s = index;
        var inds = js(s.PY$indices(this.items.length));
        var start = inds[0];
        var stop = inds[1];
        var step = inds[2];
        seq = [];
        for (var i = start; i < stop; i += step) {
            seq.push(this.items[i]);
        }
        return this.PY$__class__(seq);
    } else {
        if (typeof(index) !== 'number') {
            index = js(index);
        }

        var len = int(this.items.length);
        if (index >= 0 && index < len) {
            return this.items[index];
        } else if (index < 0 && index >= -len) {
            return this.items[index + len];
        } else {
            throw py_builtins.IndexError("list index out of range");
        }
    }
};

tuple.PY$__setitem__ = function() {
    throw py_builtins.TypeError("'tuple' object doesn't support item assignment");
};

tuple.PY$__delitem__ = function() {
    throw py_builtins.TypeError("'tuple' object doesn't support item deletion");
};

tuple.PY$count = function(value) {
    var count = 0;

    for (var index in this.items) {
        if (this.items[index].PY$__eq__(value) == True) {
            count += 1;
        }
    }

    return count;
};

tuple.PY$index = function(value, start, end) {
    if (start === undefined) {
        start = 0;
    } else {
        start = js(start);
    }
    end = js(end);

    for (var i = start; (end === undefined) || (start < end); i++) {
        var _value = this.items[i];

        if (_value === undefined) {
            break;
        }

        if (_value.PY$__eq__(value) == True) {
            return int(i);
        }
    }

    throw py_builtins.ValueError(this.PY$__class__.PY$__name__ + ".index(x): x not in list");
};

$PY.tuple = tuple;
$PY.$c_emptytuple = tuple();
<|endoftext|>