<commit_before>/**
 * angular-localForage - Angular service & directive for https://github.com/mozilla/localForage (Offline storage, improved.)
 * @version v0.2.3
 * @link https://github.com/ocombe/angular-localForage
 * @license MIT
 * @author Olivier Combe <olivier.combe@gmail.com>
 */
(function(window, angular, localforage, undefined) {
	'use strict';

	var angularLocalForage = angular.module('LocalForageModule', ['ng']);
	angularLocalForage.provider('$localForage', function() {
		localforage.config({
			name: 'lf' // default prefix
		});

		// Send signals for each of the following actions ?
		this.notify = {
			setItem: false,
			removeItem: false
		};

		// Setter for the storage driver
		var setDriver = function(driver) {
			return localforage.setDriver(driver);
		};

		this.setDriver = setDriver;

		// Getter for the storage driver
		var driver = function() {
			return localforage.driver();
		};

		// Setter for notification config, itemSet & itemRemove should be booleans
		this.setNotify = function(itemSet, itemRemove) {
			this.notify = {
				setItem: itemSet,
				removeItem: itemRemove
			};
		};

        this.config = function(config) {
            if(angular.isObject(config)) {
                if(angular.isDefined(config.driver)) {
	                localforage.config(config);
                    return setDriver(config.driver);
                } else {
                    return localforage.config(config);
                }
            }
        }

		this.$get = ['$rootScope', '$q', '$parse', function($rootScope, $q, $parse) {
			var notify = this.notify;
			var watchers = {};

            var prefix = function() {
                return driver() === 'localStorageWrapper' ? localforage.config().name + '.' : '';
            }

			var onError = function(data, args, fct, deferred) {
				if(data === 'InvalidStateError' && driver() === 'asyncStorage') {
					setDriver('localStorageWrapper').then(function() {
						fct(args).then(function(item) {
							deferred.resolve(item);
						}, function(data) {
							deferred.reject(data);
						});
					}, function() {
						deferred.reject(data);
					});
				} else {
					deferred.reject(data);
				}
			}

			// Directly adds a value to storage
			var setItem = function(key, value) {
				var deferred = $q.defer(),
					args = arguments;
				localforage.setItem(prefix() + key, value).then(function success() {
					if(notify.setItem) {
						$rootScope.$broadcast('LocalForageModule.setItem', {key: key, newvalue: value, driver: localforage.driver()});
					}
					deferred.resolve(value);
				}, function error(data) {
					onError(data, args, setItem, deferred);
				});

				return deferred.promise;
			};

			// Directly get a value from storage
			var getItem = function(key) {
				var deferred = $q.defer(),
					args = arguments;
				localforage.getItem(prefix() + key).then(function success(item) {
					deferred.resolve(item);
				}, function error(data) {
					onError(data, args, getItem, deferred);
				});
				return deferred.promise;
			};

			// Remove an item from storage
			var removeItem = function(key) {
				var promise = localforage.removeItem(prefix() + key);
				if(notify.removeItem) {
					return promise.then(function(value) {
						$rootScope.$broadcast('LocalForageModule.removeItem', {key: key, driver: localforage.driver()});
					});
				} else {
					return promise;
				}
			};

			// Remove all data for this app from storage (we could use localforage.clear(); but we don't want to remove things without the prefix
			var clear = function() {
				var deferred = $q.defer(),
					args = arguments,
					promises = [];
				getKeys().then(function success(keys) {
					angular.forEach(keys, function(key) {
						promises.push(removeItem(key));
					});

					$q.all(promises).then(function() {
						deferred.resolve();
					});
				}, function error(data) {
					onError(data, args, clearAll, deferred);
				});
				return deferred.promise;
			}

			// Return the key for item at position n
			var key = function(n) {
				var deferred = $q.defer(),
					args = arguments;
				localforage.key(n).then(function success(key) {
					deferred.resolve(key);
				}, function error(data) {
					onError(data, args, key, deferred);
				});
				return deferred.promise;
			};

			var length = function() {
				var deferred = $q.defer(),
					args = arguments; // using $q to avoid using $apply
				localforage.length().then(function success(length) {
					deferred.resolve(length);
				}, function error(data) {
					onError(data, args, length, deferred);
				});
				return deferred.promise;
			}

			// Return the list of keys stored for this application
			var getKeys = function() {
				var deferred = $q.defer(),
					args = arguments;
				length().then(function success(length) {
					var promises = [],
						keys = [],
                        p = prefix();
					for(var i = 0; i < length; i++) {
						promises.push(key(i).then(function(key) {
							if(key.indexOf(p) === 0) {
								keys.push(key.substr(p.length, key.length));
							}
						}));
					}

					$q.all(promises).then(function() {
						deferred.resolve(keys);
					});
				}, function error(data) {
					onError(data, args, getKeys, deferred);
				});
				return deferred.promise;
			}

			/**
			 * Bind - let's you directly bind a LocalForage value to a $scope variable
			 * @param {Angular $scope} $scope - the current scope you want the variable available in
			 * @param {String} key - the name of the variable you are binding
			 * @param {String} key - the name of the variable you are binding OR {Object} opts - key and custom options like default value or unique store name
			 * Here are the available options you can set:
			 * * defaultValue: the default value
			 * * storeName: add a custom store key value instead of using the scope variable name
			 * @returns {*} - returns whatever the stored value is
			 */
			var bind = function($scope, opts) {
				if(angular.isString(opts)) {
					opts = {
						key: opts
					}
				} else if(!angular.isObject(opts) || angular.isUndefined(opts.key)) {
					throw "You must defined a key to bind";
				}
				var defaultOpts = {
					defaultValue: '',
					storeName: ''
				};
				// If no defined options we use defaults otherwise extend defaults
				opts = angular.extend(defaultOpts, opts || {});

				// Set the storeName key for the LocalForage entry
				// use user defined in specified
				var storeName = opts.storeName || opts.key,
					model = $parse(opts.key);

				return getItem(storeName).then(function(item) {
					if(item) { // If it does exist assign it to the $scope value
						model.assign($scope, item);
					} else if(opts.defaultValue) { // If a value doesn't already exist store it as is
						setItem(storeName, opts.defaultValue);
					}

					// Register a listener for changes on the $scope value
					// to update the localForage value
					if(angular.isDefined(watchers[opts.key])) {
						watchers[opts.key]();
					}

					watchers[opts.key] = $scope.$watch($parse(opts.key), function(val) {
						if(angular.isDefined(val)) {
							setItem(storeName, val);
						}
					}, true);
				});
			}

			/**
			 * Unbind - let's you unbind a variable from localForage while removing the value from both
			 * the localForage and the local variable and sets it to null
			 * @param $scope - the scope the variable was initially set in
			 * @param key - the name of the variable you are unbinding
			 * @param storeName - (optional) if you used a custom storeName you will have to specify it here as well
			 */
			var unbind = function($scope, key, storeName) {
				storeName = storeName || key;
				$parse(key).assign($scope, null);
				if(angular.isDefined(watchers[key])) {
					watchers[key](); // unwatch
					delete watchers[key];
				}
				removeItem(storeName);
			}

			return {
				setDriver: setDriver,
                driver: driver,
				getDriver: driver, // deprecated
				setItem: setItem,
                set: setItem, // deprecated
                getItem: getItem,
                get: getItem, // deprecated
				remove: removeItem,
                removeItem: removeItem, // deprecated
				clear: clear,
				clearAll: clear, // deprecated
                key: key,
				getKeyAt: key, // deprecated
				getKeys: getKeys,
				length: length,
				getLength: length, // deprecated
				bind: bind,
				unbind: unbind
			};
		}]
	});

	angularLocalForage.directive('localForage', ['$localForage', function ($localForage) {
		return {
			restrict: 'A',
			link: function ($scope, $element, $attrs) {
				var opts = $scope.$eval($attrs.localForage);
				if(angular.isObject(opts) && angular.isDefined(opts.key) && angular.isDefined(opts.storeName)) {
					$localForage.bind($scope, opts);
				} else {
					$localForage.bind($scope, $attrs.localForage);
				}
			}
		}
	}]);
})(window, window.angular, window.localforage);<commit_msg>fix: remove $promise attributes from objects before we store them on localforage.<commit_after>/**
 * angular-localForage - Angular service & directive for https://github.com/mozilla/localForage (Offline storage, improved.)
 * @version v0.2.3
 * @link https://github.com/ocombe/angular-localForage
 * @license MIT
 * @author Olivier Combe <olivier.combe@gmail.com>
 */
(function(window, angular, localforage, undefined) {
	'use strict';

	var angularLocalForage = angular.module('LocalForageModule', ['ng']);
	angularLocalForage.provider('$localForage', function() {
		localforage.config({
			name: 'lf' // default prefix
		});

		// Send signals for each of the following actions ?
		this.notify = {
			setItem: false,
			removeItem: false
		};

		// Setter for the storage driver
		var setDriver = function(driver) {
			return localforage.setDriver(driver);
		};

		this.setDriver = setDriver;

		// Getter for the storage driver
		var driver = function() {
			return localforage.driver();
		};

		// Setter for notification config, itemSet & itemRemove should be booleans
		this.setNotify = function(itemSet, itemRemove) {
			this.notify = {
				setItem: itemSet,
				removeItem: itemRemove
			};
		};

        this.config = function(config) {
            if(angular.isObject(config)) {
                if(angular.isDefined(config.driver)) {
	                localforage.config(config);
                    return setDriver(config.driver);
                } else {
                    return localforage.config(config);
                }
            }
        }

		this.$get = ['$rootScope', '$q', '$parse', function($rootScope, $q, $parse) {
			var notify = this.notify;
			var watchers = {};

            var prefix = function() {
                return driver() === 'localStorageWrapper' ? localforage.config().name + '.' : '';
            }

			var onError = function(data, args, fct, deferred) {
				if(data === 'InvalidStateError' && driver() === 'asyncStorage') {
					setDriver('localStorageWrapper').then(function() {
						fct(args).then(function(item) {
							deferred.resolve(item);
						}, function(data) {
							deferred.reject(data);
						});
					}, function() {
						deferred.reject(data);
					});
				} else {
					deferred.reject(data);
				}
			}

			// Directly adds a value to storage
			var setItem = function(key, value) {
				var deferred = $q.defer(),
					args = arguments;

				//avoid $promises attributes from value objects, if is there.
				if (angular.isObject(value) && angular.isDefined(value.$promise)) {
					delete value.$promise; //delete attribut from object structure.
				}

				localforage.setItem(prefix() + key, value).then(function success() {
					if(notify.setItem) {
						$rootScope.$broadcast('LocalForageModule.setItem', {key: key, newvalue: value, driver: localforage.driver()});
					}
					deferred.resolve(value);
				}, function error(data) {
					onError(data, args, setItem, deferred);
				});

				return deferred.promise;
			};

			// Directly get a value from storage
			var getItem = function(key) {
				var deferred = $q.defer(),
					args = arguments;
				localforage.getItem(prefix() + key).then(function success(item) {
					deferred.resolve(item);
				}, function error(data) {
					onError(data, args, getItem, deferred);
				});
				return deferred.promise;
			};

			// Remove an item from storage
			var removeItem = function(key) {
				var promise = localforage.removeItem(prefix() + key);
				if(notify.removeItem) {
					return promise.then(function(value) {
						$rootScope.$broadcast('LocalForageModule.removeItem', {key: key, driver: localforage.driver()});
					});
				} else {
					return promise;
				}
			};

			// Remove all data for this app from storage (we could use localforage.clear(); but we don't want to remove things without the prefix
			var clear = function() {
				var deferred = $q.defer(),
					args = arguments,
					promises = [];
				getKeys().then(function success(keys) {
					angular.forEach(keys, function(key) {
						promises.push(removeItem(key));
					});

					$q.all(promises).then(function() {
						deferred.resolve();
					});
				}, function error(data) {
					onError(data, args, clearAll, deferred);
				});
				return deferred.promise;
			}

			// Return the key for item at position n
			var key = function(n) {
				var deferred = $q.defer(),
					args = arguments;
				localforage.key(n).then(function success(key) {
					deferred.resolve(key);
				}, function error(data) {
					onError(data, args, key, deferred);
				});
				return deferred.promise;
			};

			var length = function() {
				var deferred = $q.defer(),
					args = arguments; // using $q to avoid using $apply
				localforage.length().then(function success(length) {
					deferred.resolve(length);
				}, function error(data) {
					onError(data, args, length, deferred);
				});
				return deferred.promise;
			}

			// Return the list of keys stored for this application
			var getKeys = function() {
				var deferred = $q.defer(),
					args = arguments;
				length().then(function success(length) {
					var promises = [],
						keys = [],
                        p = prefix();
					for(var i = 0; i < length; i++) {
						promises.push(key(i).then(function(key) {
							if(key.indexOf(p) === 0) {
								keys.push(key.substr(p.length, key.length));
							}
						}));
					}

					$q.all(promises).then(function() {
						deferred.resolve(keys);
					});
				}, function error(data) {
					onError(data, args, getKeys, deferred);
				});
				return deferred.promise;
			}

			/**
			 * Bind - let's you directly bind a LocalForage value to a $scope variable
			 * @param {Angular $scope} $scope - the current scope you want the variable available in
			 * @param {String} key - the name of the variable you are binding
			 * @param {String} key - the name of the variable you are binding OR {Object} opts - key and custom options like default value or unique store name
			 * Here are the available options you can set:
			 * * defaultValue: the default value
			 * * storeName: add a custom store key value instead of using the scope variable name
			 * @returns {*} - returns whatever the stored value is
			 */
			var bind = function($scope, opts) {
				if(angular.isString(opts)) {
					opts = {
						key: opts
					}
				} else if(!angular.isObject(opts) || angular.isUndefined(opts.key)) {
					throw "You must defined a key to bind";
				}
				var defaultOpts = {
					defaultValue: '',
					storeName: ''
				};
				// If no defined options we use defaults otherwise extend defaults
				opts = angular.extend(defaultOpts, opts || {});

				// Set the storeName key for the LocalForage entry
				// use user defined in specified
				var storeName = opts.storeName || opts.key,
					model = $parse(opts.key);

				return getItem(storeName).then(function(item) {
					if(item) { // If it does exist assign it to the $scope value
						model.assign($scope, item);
					} else if(opts.defaultValue) { // If a value doesn't already exist store it as is
						setItem(storeName, opts.defaultValue);
					}

					// Register a listener for changes on the $scope value
					// to update the localForage value
					if(angular.isDefined(watchers[opts.key])) {
						watchers[opts.key]();
					}

					watchers[opts.key] = $scope.$watch($parse(opts.key), function(val) {
						if(angular.isDefined(val)) {
							setItem(storeName, val);
						}
					}, true);
				});
			}

			/**
			 * Unbind - let's you unbind a variable from localForage while removing the value from both
			 * the localForage and the local variable and sets it to null
			 * @param $scope - the scope the variable was initially set in
			 * @param key - the name of the variable you are unbinding
			 * @param storeName - (optional) if you used a custom storeName you will have to specify it here as well
			 */
			var unbind = function($scope, key, storeName) {
				storeName = storeName || key;
				$parse(key).assign($scope, null);
				if(angular.isDefined(watchers[key])) {
					watchers[key](); // unwatch
					delete watchers[key];
				}
				removeItem(storeName);
			}

			return {
				setDriver: setDriver,
                driver: driver,
				getDriver: driver, // deprecated
				setItem: setItem,
                set: setItem, // deprecated
                getItem: getItem,
                get: getItem, // deprecated
				remove: removeItem,
                removeItem: removeItem, // deprecated
				clear: clear,
				clearAll: clear, // deprecated
                key: key,
				getKeyAt: key, // deprecated
				getKeys: getKeys,
				length: length,
				getLength: length, // deprecated
				bind: bind,
				unbind: unbind
			};
		}]
	});

	angularLocalForage.directive('localForage', ['$localForage', function ($localForage) {
		return {
			restrict: 'A',
			link: function ($scope, $element, $attrs) {
				var opts = $scope.$eval($attrs.localForage);
				if(angular.isObject(opts) && angular.isDefined(opts.key) && angular.isDefined(opts.storeName)) {
					$localForage.bind($scope, opts);
				} else {
					$localForage.bind($scope, $attrs.localForage);
				}
			}
		}
	}]);
})(window, window.angular, window.localforage);<|endoftext|>


<commit_before>const {DatabaseConnectionFactory} = require('nylas-core')

function processMessage({message, accountId}) {
  return DatabaseConnectionFactory.forAccount(accountId)
  .then((db) => addMessageToThread({db, accountId, message}))
  .then((thread) => {
    thread.addMessage(message)
    message.setThread(thread)
    return message
  })
}

function addMessageToThread({db, accountId, message}) {
  const {Thread, Message} = db
  if (message.threadId) {
    return Thread.find({where: {threadId: message.threadId}})
  }
  return matchThread({db, accountId, message})
  .then((thread) => (thread))
}

function matchThread({db, accountId, message}) {
  const {Thread} = db

  // TODO: Add once we have some test data with this header
  /*
  if (message.headers['in-reply-to']) {
    return getThreadFromHeader() // Doesn't exist yet
    .then((thread) => {
      if (thread) {
        return thread
      }
      return Thread.create({
        subject: message.subject,
        cleanedSubject: cleanSubject(message.subject),
      })
    })
  }
  */
  return Thread.create({
    subject: message.subject,
    cleanedSubject: cleanSubject(message.subject),
  })
}

function cleanSubject(subject) {
  if (subject === null)
    return ""
  const regex = new RegExp(/^((re|fw|fwd|aw|wg|undeliverable|undelivered):\s*)+/ig)
  const cleanedSubject = subject.replace(regex, (match) => "")
  return cleanedSubject
}

// TODO: Incorporate this more elaborate threading algorithm
/*
function fetchCorrespondingThread({db, accountId, message}) {
  const cleanedSubject = cleanSubject(message.subject)
  return getThreads({db, message, cleanedSubject})
  .then((threads) => {
    return findCorrespondingThread({message, threads})
  })
}

function getThreads({db, message, cleanedSubject}) {
  const {Thread} = db
  return Thread.findAll({
    where: {
      threadId: message.headers.threadId,
      cleanedSubject: cleanedSubject,
    },
    order: [
      ['id', 'DESC']
    ],
  })
}

function findCorrespondingThread({message, threads}) {
  for (const thread of threads) {
    for (const match of thread.messages) {
      // Ignore BCC
      const {matchEmails, messageEmails} = removeBccParticipants({message, match})

      // A thread is probably related if it has more than two common participants
      const intersectingParticipants = getIntersectingParticipants({messageEmails, matchEmails})
      if (intersectingParticipants.length >= 2) {
        if (thread.messages.length >= MAX_THREAD_LENGTH)
          break
        return match.thread
      }

      // Handle case for self-sent emails
      if (!message.from || !message.to)
        return
      if (isSentToSelf({message, match})) {
        if (thread.messages.length >= MAX_THREAD_LENGTH)
          break
        return match.thread
      }
    }
  }
}

function removeBccParticipants({message, match}) {
  const matchBcc = match.bcc ? match.bcc : []
  const messageBcc = message.bcc ? message.bcc : []
  let matchEmails = match.participants.filter((participant) => {
    return matchBcc.find(bcc => bcc === participant)
  })
  matchEmails.map((email) => {
    return email[1]
  })
  let messageEmails = message.participants.filter((participant) => {
    return messageBcc.find(bcc => bcc === participant)
  })
  messageEmails.map((email) => {
    return email[1]
  })
  return {messageEmails, matchEmails}
}

function getIntersectingParticipants({messageEmails, matchEmails}) {
  const matchParticipants = new Set(matchEmails)
  const messageParticipants = new Set(messageEmails)
  const intersectingParticipants = new Set([...matchParticipants]
    .filter(participant => messageParticipants.has(participant)))
  return intersectingParticipants
}

function isSentToSelf({message, match}) {
  const matchFrom = match.from.map((participant) => {
    return participant[1]
  })
  const matchTo = match.to.map((participant) => {
    return participant[1]
  })
  const messageFrom = message.from.map((participant) => {
    return participant[1]
  })
  const messageTo = message.to.map((participant) => {
    return participant[1]
  })

  return (messageTo.length === 1 &&
    messageFrom === messageTo &&
    matchFrom === matchTo &&
    messageTo === matchFrom)
}
*/

module.exports = {
  order: 0,
  processMessage,
}
<commit_msg>Update order of threading processor<commit_after>const {DatabaseConnectionFactory} = require('nylas-core')

function processMessage({message, accountId}) {
  return DatabaseConnectionFactory.forAccount(accountId)
  .then((db) => addMessageToThread({db, accountId, message}))
  .then((thread) => {
    thread.addMessage(message)
    message.setThread(thread)
    return message
  })
}

function addMessageToThread({db, accountId, message}) {
  const {Thread, Message} = db
  if (message.threadId) {
    return Thread.find({where: {threadId: message.threadId}})
  }
  return matchThread({db, accountId, message})
  .then((thread) => (thread))
}

function matchThread({db, accountId, message}) {
  const {Thread} = db

  // TODO: Add once we have some test data with this header
  /*
  if (message.headers['in-reply-to']) {
    return getThreadFromHeader() // Doesn't exist yet
    .then((thread) => {
      if (thread) {
        return thread
      }
      return Thread.create({
        subject: message.subject,
        cleanedSubject: cleanSubject(message.subject),
      })
    })
  }
  */
  return Thread.create({
    subject: message.subject,
    cleanedSubject: cleanSubject(message.subject),
  })
}

function cleanSubject(subject) {
  if (subject === null) {
    return ""
  }
  const regex = new RegExp(/^((re|fw|fwd|aw|wg|undeliverable|undelivered):\s*)+/ig)
  const cleanedSubject = subject.replace(regex, (match) => "")
  return cleanedSubject
}

// TODO: Incorporate this more elaborate threading algorithm
/*
function fetchCorrespondingThread({db, accountId, message}) {
  const cleanedSubject = cleanSubject(message.subject)
  return getThreads({db, message, cleanedSubject})
  .then((threads) => {
    return findCorrespondingThread({message, threads})
  })
}

function getThreads({db, message, cleanedSubject}) {
  const {Thread} = db
  return Thread.findAll({
    where: {
      threadId: message.headers.threadId,
      cleanedSubject: cleanedSubject,
    },
    order: [
      ['id', 'DESC']
    ],
  })
}

function findCorrespondingThread({message, threads}) {
  for (const thread of threads) {
    for (const match of thread.messages) {
      // Ignore BCC
      const {matchEmails, messageEmails} = removeBccParticipants({message, match})

      // A thread is probably related if it has more than two common participants
      const intersectingParticipants = getIntersectingParticipants({messageEmails, matchEmails})
      if (intersectingParticipants.length >= 2) {
        if (thread.messages.length >= MAX_THREAD_LENGTH)
          break
        return match.thread
      }

      // Handle case for self-sent emails
      if (!message.from || !message.to)
        return
      if (isSentToSelf({message, match})) {
        if (thread.messages.length >= MAX_THREAD_LENGTH)
          break
        return match.thread
      }
    }
  }
}

function removeBccParticipants({message, match}) {
  const matchBcc = match.bcc ? match.bcc : []
  const messageBcc = message.bcc ? message.bcc : []
  let matchEmails = match.participants.filter((participant) => {
    return matchBcc.find(bcc => bcc === participant)
  })
  matchEmails.map((email) => {
    return email[1]
  })
  let messageEmails = message.participants.filter((participant) => {
    return messageBcc.find(bcc => bcc === participant)
  })
  messageEmails.map((email) => {
    return email[1]
  })
  return {messageEmails, matchEmails}
}

function getIntersectingParticipants({messageEmails, matchEmails}) {
  const matchParticipants = new Set(matchEmails)
  const messageParticipants = new Set(messageEmails)
  const intersectingParticipants = new Set([...matchParticipants]
    .filter(participant => messageParticipants.has(participant)))
  return intersectingParticipants
}

function isSentToSelf({message, match}) {
  const matchFrom = match.from.map((participant) => {
    return participant[1]
  })
  const matchTo = match.to.map((participant) => {
    return participant[1]
  })
  const messageFrom = message.from.map((participant) => {
    return participant[1]
  })
  const messageTo = message.to.map((participant) => {
    return participant[1]
  })

  return (messageTo.length === 1 &&
    messageFrom === messageTo &&
    matchFrom === matchTo &&
    messageTo === matchFrom)
}
*/

module.exports = {
  order: 1,
  processMessage,
}
<|endoftext|>


<commit_before>(function(root, factory) {

  if (typeof define === 'function' && define.amd) {
    define(['backbone', 'underscore'], function(Backbone, _) {
      return factory(Backbone, _);
    });
  } else if (typeof exports !== 'undefined') {
    var Backbone = require('backbone');
    var _  = require('underscore');
    module.exports = factory(Backbone, _);
  } else {
    factory(root.Backbone, root._);
  }

}(this, function(Backbone, _) {
  'use strict';

  var previousEnumerable = Backbone.Enumerable;

  // Backbone.Enumerable

  Backbone.Enumerable = (function(Backbone, _) {

    var Enumerable = function(items) {
      this._items = [];
      this._currentItem = null;
      this._currentIndex = null;
      this._updateLength();
      _.each(items, this.add, this);
      this._setCurrentItem();
    };

    _.extend(Enumerable.prototype, {

      add: function(item, index) {
        if (index === undefined) {
          this._items.push(item);
        } else {
          this._items.splice(index, 0, item);
        }
        this._updateLength();
        return this;
      },

      remove: function(index) {
        if (index === undefined) {
          this._items.pop();
          this._updateLength();
          return this;
        }
        if (index > -1) {
          this._items.splice(index, 1);
        }
        this._updateLength();
        return this;
      },

      first: function() {
        return this._items.length ? this._items[0] : null;
      },

      last: function() {
        return this._items.length ? this._items[this._items.length - 1] : null;
      },

      get: function(index) {
        if (index === undefined) {
          return null;
        }
        return this._items[index] ? this._items[index] : null;
      },

      next: function() {
        this._traverse(1);
      },

      prev: function() {
        this._traverse(-1);
      },

      _traverse: function(change) {
        if (!this._currentItem) {
          return false;
        }
      },

      getCurrentItem: function() {
        return this._currentItem;
      },

      getCurrentIndex: function() {
        return this._currentIndex;
      },

      setCurrentItem: function(item) {
        if (item === undefined) {
          return false;
        }
        this._setCurrentItem(item);
      },

      _getCurrentItemIndex: function() {
        if (!this._currentItem) {
          return false;
        }
        return _.indexOf(this._items, this._currentItem);
      },

      _setCurrentItem: function(item) {
        if (item === undefined) {
          this._currentItem = this.first();
        } else if (this._getCurrentItemIndex() > -1) {
          this._currentItem = item;
        }
        this._setCurrentIndex();
        return this;
      },

      _setCurrentIndex: function() {
        this._currentIndex = this._getCurrentItemIndex();
      },

      _updateLength: function() {
        this.length = this._items.length;
      }

    });

    return Enumerable;
  })(Backbone, _);

  Backbone.Enumerable.VERSION = '0.0.0';

  Backbone.Enumerable.noConflict = function() {
    Backbone.Enumerable = previousEnumerable;
    return this;
  };

  return Backbone.Enumerable;
}));
<commit_msg>add built version<commit_after>(function(root, factory) {

  if (typeof define === 'function' && define.amd) {
    define(['backbone', 'underscore'], function(Backbone, _) {
      return factory(Backbone, _);
    });
  } else if (typeof exports !== 'undefined') {
    var Backbone = require('backbone');
    var _  = require('underscore');
    module.exports = factory(Backbone, _);
  } else {
    factory(root.Backbone, root._);
  }

}(this, function(Backbone, _) {
  'use strict';

  var previousEnumerable = Backbone.Enumerable;

  // Backbone.Enumerable

  Backbone.Enumerable = (function(Backbone, _) {

    var Enumerable = function(items) {
      this._items = [];
      this._currentItem = null;
      this._currentIndex = null;
      this._type = null;
      this._updateLength();
      _.each(items, this.add, this);
      this._setCurrentItem();
    };

    _.extend(Enumerable.prototype, {

      /**

      Public Methods

      **/

      add: function(item, index) {
        if (!this._items.length) {
          this._setType(item);
        }
        if (!(item instanceof this._type)) {
          throw new Error('Wrong type supplied.');
        }
        if (index === undefined) {
          this._items.push(item);
        } else {
          this._items.splice(index, 0, item);
        }
        this._updateLength();
        return this;
      },

      remove: function(index) {
        if (index === undefined) {
          this._items.pop();
          this._updateLength();
          return this;
        }
        if (index > -1) {
          this._items.splice(index, 1);
        }
        this._updateLength();
        return this;
      },

      first: function() {
        return this._items.length ? this._items[0] : null;
      },

      last: function() {
        return this._items.length ? this._items[this._items.length - 1] : null;
      },

      get: function(index) {
        if (index === undefined) {
          return null;
        }
        return this._items[index] ? this._items[index] : null;
      },

      next: function() {
        this._traverse(1);
      },

      prev: function() {
        this._traverse(-1);
      },

      getNext: function() {
        if (this._currentIndex === this.length - 1) {
          return this._items[0];
        }
        return this._items[this._currentIndex + 1]
      },

      getPrev: function() {
        if (this._currentIndex === 0) {
          return this._items[this.length - 1];
        }
        return this._items[this._currentIndex - 1];
      },

      getCurrentItem: function() {
        return this._currentItem;
      },

      getCurrentIndex: function() {
        return this._currentIndex;
      },

      setCurrentItem: function(item) {
        if (item === undefined) {
          return false;
        }
        this._setCurrentItem(item);
      },

      /**

      Private Methods

      **/

      _setType: function(item) {
        this._type = item.constructor;
        return this;
      },

      _traverse: function(change) {
        if (!this._currentItem) {
          return false;
        }
        var index = this._currentIndex + change;
        if (index === -1) {
          index = this.length - 1;
        }
        if (index === this.length) {
          index = 0;
        }
        this._setCurrentItem(this._items[index]);
      },

      _getCurrentItemIndex: function() {
        if (!this._currentItem) {
          return false;
        }
        return _.indexOf(this._items, this._currentItem);
      },

      _setCurrentItem: function(item) {
        if (item === undefined) {
          this._currentItem = this.first();
        } else if (this._getCurrentItemIndex() > -1) {
          this._currentItem = item;
        }
        this._setCurrentIndex();
        return this;
      },

      _setCurrentIndex: function() {
        this._currentIndex = this._getCurrentItemIndex();
      },

      _updateLength: function() {
        this.length = this._items.length;
      }

    });

    // Mix in methods from Underscore, for iteration, and other
    // collection related features.
    // Borrowing this code from Backbone.Collection:
    // http://backbonejs.org/docs/backbone.html#section-121
    var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',
      'select', 'reject', 'every', 'all', 'some', 'any', 'include',
      'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',
      'last', 'without', 'isEmpty', 'pluck'];

    _.each(methods, function(method) {
      Enumerable.prototype[method] = function() {
        var items = _.values(this._items);
        var args = [items].concat(_.toArray(arguments));
        return _[method].apply(_, args);
      };
    });

    return Enumerable;
  })(Backbone, _);

  Backbone.Enumerable.VERSION = '<%= version %>';

  Backbone.Enumerable.noConflict = function() {
    Backbone.Enumerable = previousEnumerable;
    return this;
  };

  return Backbone.Enumerable;
}));
<|endoftext|>


<commit_before>/* global module */
module.exports = {
  root: true,
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: 'module'
  },
  plugins: ['prettier'],
  extends: ['eslint:recommended', 'plugin:ember-suave/recommended', 'prettier'],
  env: {
    browser: true,
    es6: true
  },
  globals: {
    BoxSelect: true,
    ColorThief: true,
    Stripe: true,
    deparam: true,
    google: true,
    superUser: true,
    md5: true
  },
  rules: {
    'ember-suave/no-direct-property-access': 'off',
    'ember-suave/prefer-destructuring': 'off',
    'ember-suave/require-access-in-comments': 'off',
    'ember-suave/require-const-for-ember-properties': 'off',
    'generator-star-spacing': ['error', 'neither'],
    'no-constant-condition': ['error', { checkLoops: false }],
    'no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
    'one-var': 'off',
    'prettier/prettier': ['error', { singleQuote: true }],
    quotes: ['error', 'single', { allowTemplateLiterals: true, avoidEscape: true }]
  }
};
<commit_msg>eslintrc<commit_after>module.exports = {
  root: true,
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: 'module'
  },
  plugins: ['ember', 'prettier'],
  extends: ['eslint:recommended', 'plugin:ember/recommended', 'prettier'],
  env: {
    browser: true,
    es6: true
  },
  globals: {
    BoxSelect: true,
    ColorThief: true,
    Stripe: true,
    deparam: true,
    google: true,
    superUser: true,
    md5: true
  },
  rules: {
    'generator-star-spacing': ['error', 'neither'],
    'no-constant-condition': ['error', { checkLoops: false }],
    'no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
    'one-var': 'off',
    'prettier/prettier': ['error', { singleQuote: true }],
    quotes: ['error', 'single', { allowTemplateLiterals: true, avoidEscape: true }]
  },
  overrides: [
    // node files
    {
      files: [
        '.template-lintrc.js',
        'ember-cli-build.js',
        'testem.js',
        'blueprints/*/index.js',
        'config/**/*.js',
        'lib/*/index.js'
      ],
      parserOptions: {
        sourceType: 'script',
        ecmaVersion: 2015
      },
      env: {
        browser: false,
        node: true
      }
    }
  ]
};
<|endoftext|>


<commit_before>require("../only_locally");

var fs = require("fs-extra");
var exec = require("child_process").exec;
var redis = require("redis");
var cp = require("child_process");
var ROOT = process.env.BLOT_DIRECTORY;

var DATA_DIRECTORY = ROOT + "/data";
var BLOG_FOLDERS_DIRECTORY = ROOT + "/blogs";
var GIT_CLIENTS_DATA = ROOT + "/app/clients/git/data";
var STATIC_FILES_DIRECTORY = ROOT + "/static";
var ACTIVE_DATABASE_DUMP = ROOT + "/db/dump.rdb";

if (!ROOT) throw new Error("Please set environment variable BLOT_DIRECTORY");

function main(label, callback) {
  var directory = __dirname + "/data/" + label;

  if (!fs.existsSync(directory))
    return callback(new Error("No state " + label));

  cp.execSync("pg_ctl stop -D " + DATA_DIRECTORY + "/db/postgres", {
    stdio: "inherit",
  });

  loadDB(directory, function (err) {
    if (err) return callback(err);

    fs.emptyDirSync(DATA_DIRECTORY);
    fs.ensureDirSync(directory + "/data");
    fs.copySync(directory + "/data", DATA_DIRECTORY);

    // Why stdio: inherit?
    // https://github.com/shelljs/shelljs/issues/770#issuecomment-329357465
    cp.execSync("pg_ctl start -D " + DATA_DIRECTORY + "/db/postgres", {
      stdio: "inherit",
    });

    fs.emptyDirSync(BLOG_FOLDERS_DIRECTORY);
    fs.ensureDirSync(directory + "/blogs");
    fs.copySync(directory + "/blogs", BLOG_FOLDERS_DIRECTORY);

    fs.emptyDirSync(GIT_CLIENTS_DATA);
    fs.ensureDirSync(directory + "/git");
    fs.copySync(directory + "/git", GIT_CLIENTS_DATA);

    fs.emptyDirSync(STATIC_FILES_DIRECTORY);
    fs.ensureDirSync(directory + "/static");
    fs.copySync(directory + "/static", STATIC_FILES_DIRECTORY);

    require("./info")(callback);
  });
}

function loadDB(directory, callback) {
  var dump = directory + "/dump.rdb";
  var client = redis.createClient();
  var multi = client.multi();

  // If redis was already shut down, then
  // we won't be able to execute the multi()
  client.on("error", function (err) {
    if (err.code === "ECONNREFUSED") {
      then();
    }
  });

  multi.config("SET", "appendonly", "no").config("SET", "save", "").shutdown();

  multi.exec(then);

  function then() {
    fs.copySync(dump, ACTIVE_DATABASE_DUMP);

    exec(
      "redis-server " + ROOT + "/config/redis.conf",
      { silent: true },
      function (err) {
        if (err) return callback(err);
        callback(null);
      }
    );
  }
}

if (require.main === module) {
  main(process.argv[2], function (err) {
    if (err) throw err;
    process.exit();
  });
}

module.exports = main;
<commit_msg>Made the state switcher quieter<commit_after>require("../only_locally");

var fs = require("fs-extra");
var exec = require("child_process").exec;
var redis = require("redis");
var cp = require("child_process");
var ROOT = process.env.BLOT_DIRECTORY;

var DATA_DIRECTORY = ROOT + "/data";
var BLOG_FOLDERS_DIRECTORY = ROOT + "/blogs";
var GIT_CLIENTS_DATA = ROOT + "/app/clients/git/data";
var STATIC_FILES_DIRECTORY = ROOT + "/static";
var ACTIVE_DATABASE_DUMP = ROOT + "/db/dump.rdb";

if (!ROOT) throw new Error("Please set environment variable BLOT_DIRECTORY");

function main(label, callback) {
  var directory = __dirname + "/data/" + label;

  if (!fs.existsSync(directory))
    return callback(new Error("No state " + label));

  cp.execSync("pg_ctl -s -l logs/post.log  stop -D " + DATA_DIRECTORY + "/db/postgres", {
    stdio: "inherit",
  });

  loadDB(directory, function (err) {
    if (err) return callback(err);

    fs.emptyDirSync(DATA_DIRECTORY);
    fs.ensureDirSync(directory + "/data");
    fs.copySync(directory + "/data", DATA_DIRECTORY);

    // Why stdio: inherit?
    // https://github.com/shelljs/shelljs/issues/770#issuecomment-329357465
    cp.execSync("pg_ctl -s -l logs/post.log start -D " + DATA_DIRECTORY + "/db/postgres", {
      stdio: "inherit",
    });

    fs.emptyDirSync(BLOG_FOLDERS_DIRECTORY);
    fs.ensureDirSync(directory + "/blogs");
    fs.copySync(directory + "/blogs", BLOG_FOLDERS_DIRECTORY);

    fs.emptyDirSync(GIT_CLIENTS_DATA);
    fs.ensureDirSync(directory + "/git");
    fs.copySync(directory + "/git", GIT_CLIENTS_DATA);

    fs.emptyDirSync(STATIC_FILES_DIRECTORY);
    fs.ensureDirSync(directory + "/static");
    fs.copySync(directory + "/static", STATIC_FILES_DIRECTORY);

    require("./info")(callback);
  });
}

function loadDB(directory, callback) {
  var dump = directory + "/dump.rdb";
  var client = redis.createClient();
  var multi = client.multi();

  // If redis was already shut down, then
  // we won't be able to execute the multi()
  client.on("error", function (err) {
    if (err.code === "ECONNREFUSED") {
      then();
    }
  });

  multi.config("SET", "appendonly", "no").config("SET", "save", "").shutdown();

  multi.exec(then);

  function then() {
    fs.copySync(dump, ACTIVE_DATABASE_DUMP);

    exec(
      "redis-server " + ROOT + "/config/redis.conf",
      { silent: true },
      function (err) {
        if (err) return callback(err);
        callback(null);
      }
    );
  }
}

if (require.main === module) {
  main(process.argv[2], function (err) {
    if (err) throw err;
    process.exit();
  });
}

module.exports = main;
<|endoftext|>


<commit_before>"use strict";var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(e){if("object"===("undefined"==typeof exports?"undefined":_typeof(exports))&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.GitHubCalendar=e()}}(function(){return function e(t,n,r){function a(u,s){if(!n[u]){if(!t[u]){var c="function"==typeof require&&require;if(!s&&c)return c(u,!0);if(o)return o(u,!0);var i=new Error("Cannot find module '"+u+"'");throw i.code="MODULE_NOT_FOUND",i}var l=n[u]={exports:{}};t[u][0].call(l.exports,function(e){var n=t[u][1][e];return a(n?n:e)},l,l.exports,e,t,n,r)}return n[u].exports}for(var o="function"==typeof require&&require,u=0;u<r.length;u++)a(r[u]);return a}({1:[function(e,t){var n=e("github-calendar-parser"),r=e("elly"),a=e("add-subtract-date"),o=e("formatoid"),u="MMM D, YYYY";t.exports=function(e,t,s){e=r(e),s=s||{},s.summary_text=s.summary_text||'Summary of pull requests, issues opened, and commits made by @'+t+"",s.global_stats===!1&&(e.style.minHeight="160px"),s.proxy=s.proxy||function(e){return"https://urlreq.appspot.com/req?method=GET&url="+e};var c=function i(){return fetch(s.proxy("https://github.com/"+t)).then(function(e){return e.text()}).then(function(t){var c=document.createElement("div");c.innerHTML=t;var l=c.querySelector("#contributions-calendar");if(l.querySelector(".left.text-muted").innerHTML=s.summary_text,l.querySelector("include-fragment"))setTimeout(i,500);else{if(s.global_stats!==!1){var f=n(r("svg",l).outerHTML),d=f.current_streak?o(f.current_streak_range[0],u)+" – "+o(f.current_streak_range[1],u):f.last_contributed?"Last contributed in "+o(f.last_contributed,u)+".":"Rock - Hard Place",p=f.longest_streak?o(f.longest_streak_range[0],u)+" – "+o(f.longest_streak_range[1],u):f.last_contributed?"Last contributed in "+o(f.last_contributed,u)+".":"Rock - Hard Place",g=r("
",{"class":"contrib-column contrib-column-first table-column",html:'Contributions in the last year\n                               '+f.last_year+' total\n                               '+o(a.subtract(new Date,1,"year"),u)+" – "+o(new Date,u)+""}),m=r("
",{"class":"contrib-column table-column",html:'Longest streak\n                               '+f.longest_streak+' days\n                               '+p+""}),y=r("
",{"class":"contrib-column table-column",html:'Current streak\n                               '+f.current_streak+' days\n                               '+d+""});l.appendChild(g),l.appendChild(m),l.appendChild(y)}e.innerHTML=l.innerHTML}})};return c()}},{"add-subtract-date":2,elly:4,formatoid:6,"github-calendar-parser":8}],2:[function(e,t){function n(e){return function t(n,r,a){switch(r=e*r,a){case"years":case"year":n.setFullYear(n.getFullYear()+r);break;case"months":case"month":n.setMonth(n.getMonth()+r);break;case"weeks":case"week":return t(n,7*r,"days");case"days":case"day":n.setDate(n.getDate()+r);break;case"hours":case"hour":n.setHours(n.getHours()+r);break;case"minutes":case"minute":n.setMinutes(n.getMinutes()+r);break;case"seconds":case"second":n.setSeconds(n.getSeconds()+r);break;case"milliseconds":case"millisecond":n.setMilliseconds(n.getMilliseconds()+r);break;default:throw new Error("Invalid range: "+a)}return n}}t.exports={add:n(1),subtract:n(-1)}},{}],3:[function(e,t){t.exports=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],t.exports.abbr=["Sun","Mon","Tue","Wed","Thur","Fri","Sat"],t.exports["short"]=["Su","Mo","Tu","We","Th","Fr","Sa"]},{}],4:[function(e,t){function n(e,t){return"string"==typeof e?"<"===e.charAt(0)?(e=document.createElement(e.slice(1,-1)),r(t||{},function(t,n){switch(n){case"text":return void(e.textContent=t);case"html":return void(e.innerHTML=t)}e.setAttribute(n,t)}),e):(t=t||document,t.querySelector(e)):e}var r=e("iterate-object");n.$$=function(e,t){return t=t||document,t.querySelectorAll(e)},t.exports=n},{"iterate-object":9}],5:[function(e,t){t.exports=function(e,t,n){t=t||2,n=n||"0",e=e.toString();var r=t-e.length;return(0>=r?"":n.repeat(r))+e}},{}],6:[function(e,t){var n=e("months"),r=e("days"),a=e("fillo"),o=e("parse-it").Parser,u=new o({YYYY:function(e){return e.getFullYear()},YY:function(e){return e.getFullYear()%100},MMMM:function(e){return n[e.getMonth()]},MMM:function(e){return n.abbr[e.getMonth()]},MM:function(e){return a(e.getMonth()+1)},M:function(e){return e.getMonth()+1},dddd:function(e){return r[e.getDay()]},ddd:function(e){return r.abbr[e.getDay()]},dd:function(e){return r["short"][e.getDay()]},d:function(e){return e.getDay()},DD:function(e){return a(e.getDate())},D:function(e){return e.getDate()},A:function(e){return e.getHours()>=12?"PM":"AM"},a:function(e){return e.getHours()>=12?"pm":"am"},hh:function(e){return a(e.getHours()%12||12)},h:function(e){return e.getHours()%12||12},HH:function(e){return a(e.getHours())},H:function(e){return e.getHours()},mm:function(e){return a(e.getMinutes())},m:function(e){return e.getMinutes()},ss:function(e){return a(e.getSeconds())},s:function(e){return e.getSeconds()}});t.exports=function(e,t){return u.run(t,[e])}},{days:3,fillo:5,months:10,"parse-it":11}],7:[function(e,t){t.exports=["#eee","#d6e685","#8cc665","#44a340","#1e6823"]},{}],8:[function(e,t){var n=e("github-calendar-legend");t.exports=function(e){var t={last_year:0,longest_streak:-1,longest_streak_range:[],current_streak:0,current_streak_range:[],weeks:[],days:[],last_contributed:null},r=[],a=function(){t.current_streak>t.longest_streak&&(t.longest_streak=t.current_streak,t.longest_streak_range[0]=t.current_streak_range[0],t.longest_streak_range[1]=t.current_streak_range[1])};return e.split("\n").slice(2).map(function(e){return e.trim()}).forEach(function(e){if(e.startsWith("<g transform"))return r.length&&t.weeks.push(r)&&(r=[]);var o=e.match(/fill="(#[a-z0-9]+)"/),u=e.match(/data-date="([0-9\-]+)"/),s=e.match(/data-count="([0-9]+)"/);if(o=o&&o[1],u=u&&u[1],s=s&&+s[1],o){var c={fill:o,date:new Date(u),count:s,level:n.indexOf(o)};0===t.current_streak&&(t.current_streak_range[0]=c.date),c.count?(++t.current_streak,t.last_year+=c.count,t.last_contributed=c.date,t.current_streak_range[1]=c.date):(a(),t.current_streak=0),r.push(c),t.days.push(c)}}),a(),t}},{"github-calendar-legend":7}],9:[function(e,t){function n(e,t){var n=0,r=[];if(Array.isArray(e))for(;n<e.length&&t(e[n],n,e)!==!1;++n);else if("object"===("undefined"==typeof e?"undefined":_typeof(e))&&null!==e)for(r=Object.keys(e);n<r.length&&t(e[r[n]],r[n],e)!==!1;++n);}t.exports=n},{}],10:[function(e,t){t.exports=["January","February","March","April","May","June","July","August","September","October","November","December"],t.exports.abbr=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]},{}],11:[function(e,t){function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t,n){return new u(t).run(e,n)}var a=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),o=e("regex-escape"),u=function(){function e(t){n(this,e),this.obj=t||{},this.re=new RegExp("^("+Object.keys(t).map(o).join("|")+")")}return a(e,[{key:"run",value:function(e,t){var n="";t=t||[];do{var r=e.match(this.re),a=r&&r[1],o=a||e.charAt(0);if(a){var u=this.obj[a];"function"==typeof u&&(u=u.apply(this,t)),n+=u}else n+=o;e=e.substring(o.length)}while(e);return n}}]),e}();r.Parser=u,t.exports=r},{"regex-escape":12}],12:[function(e,t){function n(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}n.proto=function(){return RegExp.escape=n,n},t.exports=n},{}]},{},[1])(1)});<commit_msg>Rebuild<commit_after>"use strict";var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(e){if("object"===("undefined"==typeof exports?"undefined":_typeof(exports))&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.GitHubCalendar=e()}}(function(){return function e(t,n,r){function a(u,s){if(!n[u]){if(!t[u]){var c="function"==typeof require&&require;if(!s&&c)return c(u,!0);if(o)return o(u,!0);var i=new Error("Cannot find module '"+u+"'");throw i.code="MODULE_NOT_FOUND",i}var l=n[u]={exports:{}};t[u][0].call(l.exports,function(e){var n=t[u][1][e];return a(n?n:e)},l,l.exports,e,t,n,r)}return n[u].exports}for(var o="function"==typeof require&&require,u=0;u<r.length;u++)a(r[u]);return a}({1:[function(e,t){var n=e("github-calendar-parser"),r=e("elly"),a=e("add-subtract-date"),o=e("formatoid"),u="MMM D, YYYY";t.exports=function(e,t,s){e=r(e),s=s||{},s.summary_text=s.summary_text||'Summary of pull requests, issues opened, and commits made by @'+t+"",s.global_stats===!1&&(e.style.minHeight="170px"),s.proxy=s.proxy||function(e){return"https://urlreq.appspot.com/req?method=GET&url="+e};var c=function i(){return fetch(s.proxy("https://github.com/"+t)).then(function(e){return e.text()}).then(function(t){var c=document.createElement("div");c.innerHTML=t;var l=c.querySelector("#contributions-calendar");if(l.querySelector(".left.text-muted").innerHTML=s.summary_text,l.querySelector("include-fragment"))setTimeout(i,500);else{if(s.global_stats!==!1){var f=n(r("svg",l).outerHTML),d=f.current_streak?o(f.current_streak_range[0],u)+" – "+o(f.current_streak_range[1],u):f.last_contributed?"Last contributed in "+o(f.last_contributed,u)+".":"Rock - Hard Place",p=f.longest_streak?o(f.longest_streak_range[0],u)+" – "+o(f.longest_streak_range[1],u):f.last_contributed?"Last contributed in "+o(f.last_contributed,u)+".":"Rock - Hard Place",g=r("
",{"class":"contrib-column contrib-column-first table-column",html:'Contributions in the last year\n                               '+f.last_year+' total\n                               '+o(a.subtract(new Date,1,"year"),u)+" – "+o(new Date,u)+""}),m=r("
",{"class":"contrib-column table-column",html:'Longest streak\n                               '+f.longest_streak+' days\n                               '+p+""}),y=r("
",{"class":"contrib-column table-column",html:'Current streak\n                               '+f.current_streak+' days\n                               '+d+""});l.appendChild(g),l.appendChild(m),l.appendChild(y)}e.innerHTML=l.innerHTML}})};return c()}},{"add-subtract-date":2,elly:4,formatoid:6,"github-calendar-parser":8}],2:[function(e,t){function n(e){return function t(n,r,a){switch(r=e*r,a){case"years":case"year":n.setFullYear(n.getFullYear()+r);break;case"months":case"month":n.setMonth(n.getMonth()+r);break;case"weeks":case"week":return t(n,7*r,"days");case"days":case"day":n.setDate(n.getDate()+r);break;case"hours":case"hour":n.setHours(n.getHours()+r);break;case"minutes":case"minute":n.setMinutes(n.getMinutes()+r);break;case"seconds":case"second":n.setSeconds(n.getSeconds()+r);break;case"milliseconds":case"millisecond":n.setMilliseconds(n.getMilliseconds()+r);break;default:throw new Error("Invalid range: "+a)}return n}}t.exports={add:n(1),subtract:n(-1)}},{}],3:[function(e,t){t.exports=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],t.exports.abbr=["Sun","Mon","Tue","Wed","Thur","Fri","Sat"],t.exports["short"]=["Su","Mo","Tu","We","Th","Fr","Sa"]},{}],4:[function(e,t){function n(e,t){return"string"==typeof e?"<"===e.charAt(0)?(e=document.createElement(e.slice(1,-1)),r(t||{},function(t,n){switch(n){case"text":return void(e.textContent=t);case"html":return void(e.innerHTML=t)}e.setAttribute(n,t)}),e):(t=t||document,t.querySelector(e)):e}var r=e("iterate-object");n.$$=function(e,t){return t=t||document,t.querySelectorAll(e)},t.exports=n},{"iterate-object":9}],5:[function(e,t){t.exports=function(e,t,n){t=t||2,n=n||"0",e=e.toString();var r=t-e.length;return(0>=r?"":n.repeat(r))+e}},{}],6:[function(e,t){var n=e("months"),r=e("days"),a=e("fillo"),o=e("parse-it").Parser,u=new o({YYYY:function(e){return e.getFullYear()},YY:function(e){return e.getFullYear()%100},MMMM:function(e){return n[e.getMonth()]},MMM:function(e){return n.abbr[e.getMonth()]},MM:function(e){return a(e.getMonth()+1)},M:function(e){return e.getMonth()+1},dddd:function(e){return r[e.getDay()]},ddd:function(e){return r.abbr[e.getDay()]},dd:function(e){return r["short"][e.getDay()]},d:function(e){return e.getDay()},DD:function(e){return a(e.getDate())},D:function(e){return e.getDate()},A:function(e){return e.getHours()>=12?"PM":"AM"},a:function(e){return e.getHours()>=12?"pm":"am"},hh:function(e){return a(e.getHours()%12||12)},h:function(e){return e.getHours()%12||12},HH:function(e){return a(e.getHours())},H:function(e){return e.getHours()},mm:function(e){return a(e.getMinutes())},m:function(e){return e.getMinutes()},ss:function(e){return a(e.getSeconds())},s:function(e){return e.getSeconds()}});t.exports=function(e,t){return u.run(t,[e])}},{days:3,fillo:5,months:10,"parse-it":11}],7:[function(e,t){t.exports=["#eee","#d6e685","#8cc665","#44a340","#1e6823"]},{}],8:[function(e,t){var n=e("github-calendar-legend");t.exports=function(e){var t={last_year:0,longest_streak:-1,longest_streak_range:[],current_streak:0,current_streak_range:[],weeks:[],days:[],last_contributed:null},r=[],a=function(){t.current_streak>t.longest_streak&&(t.longest_streak=t.current_streak,t.longest_streak_range[0]=t.current_streak_range[0],t.longest_streak_range[1]=t.current_streak_range[1])};return e.split("\n").slice(2).map(function(e){return e.trim()}).forEach(function(e){if(e.startsWith("<g transform"))return r.length&&t.weeks.push(r)&&(r=[]);var o=e.match(/fill="(#[a-z0-9]+)"/),u=e.match(/data-date="([0-9\-]+)"/),s=e.match(/data-count="([0-9]+)"/);if(o=o&&o[1],u=u&&u[1],s=s&&+s[1],o){var c={fill:o,date:new Date(u),count:s,level:n.indexOf(o)};0===t.current_streak&&(t.current_streak_range[0]=c.date),c.count?(++t.current_streak,t.last_year+=c.count,t.last_contributed=c.date,t.current_streak_range[1]=c.date):(a(),t.current_streak=0),r.push(c),t.days.push(c)}}),a(),t}},{"github-calendar-legend":7}],9:[function(e,t){function n(e,t){var n=0,r=[];if(Array.isArray(e))for(;n<e.length&&t(e[n],n,e)!==!1;++n);else if("object"===("undefined"==typeof e?"undefined":_typeof(e))&&null!==e)for(r=Object.keys(e);n<r.length&&t(e[r[n]],r[n],e)!==!1;++n);}t.exports=n},{}],10:[function(e,t){t.exports=["January","February","March","April","May","June","July","August","September","October","November","December"],t.exports.abbr=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]},{}],11:[function(e,t){function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t,n){return new u(t).run(e,n)}var a=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),o=e("regex-escape"),u=function(){function e(t){n(this,e),this.obj=t||{},this.re=new RegExp("^("+Object.keys(t).map(o).join("|")+")")}return a(e,[{key:"run",value:function(e,t){var n="";t=t||[];do{var r=e.match(this.re),a=r&&r[1],o=a||e.charAt(0);if(a){var u=this.obj[a];"function"==typeof u&&(u=u.apply(this,t)),n+=u}else n+=o;e=e.substring(o.length)}while(e);return n}}]),e}();r.Parser=u,t.exports=r},{"regex-escape":12}],12:[function(e,t){function n(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}n.proto=function(){return RegExp.escape=n,n},t.exports=n},{}]},{},[1])(1)});<|endoftext|>


<commit_before>function ultralight(partials){
	var i;

	if(partials.constructor === Array){
		this.partials = partials;
	} else{
		this.partials = [];
	}

	this.parseHash = function(){
		// split the url hash up into an array of strings.
		// if there's no hash, return an empty array.
	    var elts, hash;

	    hash = window.location.hash;
	    hash = hash.slice(1,hash.length)

	    if(hash){
	        elts = hash.split('/')
	    } else
	        elts = []

	    return elts
	}

	this.matchRoute = function(hashArray){
		//given the URL hash as an array, return the corresponding value from ul.routes
		var key, auxkey, route, template, data, auxdata, html;

		route = document.getElementById('body').getAttribute('route');
		routeArray = route.split('/');
		routeData = this.compareRoutes(hashArray, routeArray)

		if(routeData){

			//add additional data to the view as neessary:
			if (typeof ulAuxilaryData === "function"){
				auxdata = ulAuxilaryData(route, routeData)

				for(auxkey in auxdata){
					routeData[auxkey] = auxdata[auxkey]
				}
			}

			//render template
			template = document.getElementById('body').innerHTML;
			html = Mustache.to_html(template, routeData, ul.partials);
			//body = document.createElement('body'); //see #4
			//document.getElementsByTagName('body')[0].appendChild(body);
			document.body.innerHTML += html;
			return 0;
		}

		return 404;
	}

	this.compareRoutes = function(hash, route){
		//helper for comparing route arrays. hash is from the url hash, route is from ul.routes

		var key,
			data = {}

	 	if (hash == null || route == null) return false;
		if (hash.length != route.length) return false;

		for (var i = 0; i < hash.length; ++i) {
			// deal with variable routes
			if(route[i].slice(0,2) == '{{'){
				key = route[i].substring(2, route[i].length - 2);
				data[key] = hash[i];
				continue;
			} else if (hash[i] !== route[i])
				return false;
		}
		return data;
	}

	this.promisePartials = function(){
		// pull in all partials async, by the power of promises

		var sequence = Promise.resolve();

		sequence.then(function(){
			return Promise.all(ul.partials.map(ulUtilGet))
		}).then(function(partials){
			for(i=0; i<partials.length; i++){
				partial = document.createElement('script');
				partial.setAttribute('type', 'text/template');
				partial.setAttribute('id', ul.partials[i]);
				partial.innerHTML = partials[i]
				document.getElementsByTagName('head')[0].appendChild(partial);

			}

		}).then(function() {
			var i, key, hash, partials = {};

			//set up partials
			for(i=0; i<ul.partials.length; i++){
				partials[ul.partials[i]] = document.getElementById(ul.partials[i]).innerHTML;
			}
			ul.partials = partials;

			//render the route and report status in the console.
			hash = ul.parseHash()
			console.log(ul.matchRoute(hash))
		}).then(function(){
			//allow a post-rendering callback
			if(typeof ulCallback === "function"){
				ulCallback();
			}
		});
	}

	this.promisePartials()

}

function ulUtilGet(name) {
	// promise to get tempate <name>; thanks http://www.html5rocks.com/en/tutorials/es6/promises/
	var rootURL, path;

	rootURL = window.location.protocol + "//" + window.location.host;
	path = window.location.pathname.split('/').slice(0,-1);
	for(i=0; i<path.length; i++){
		rootURL += path[i] + '/'
	}

	url = rootURL + 'partials/' + name + '.mustache';

	// Return a new promise.
 	return new Promise(function(resolve, reject) {
		// Do the usual XHR stuff
    	var req = new XMLHttpRequest();
    	req.open('GET', url);

    	req.onload = function() {
      		// This is called even on 404 etc
      		// so check the status
      		if (req.status == 200) {
        		// Resolve the promise with the response text
        		resolve(req.response);
      		}
      		else {
        		// Otherwise reject with the status text
        		// which will hopefully be a meaningful error
        		reject(Error(req.statusText));
      		}
    	};

	    // Handle network errors
	    req.onerror = function() {
    		reject(Error("Network Error"));
    	};

	    // Make the request
	    req.send();
  	});
}

window.onhashchange = function(){
	// since we're using hashes like full-fledged routes.
	location.reload(false)
}<commit_msg>ultralight bugfix<commit_after>function ultralight(partials){
	var i;

	if(partials.constructor === Array){
		this.partials = partials;
	} else{
		this.partials = [];
	}

	this.parseHash = function(){
		// split the url hash up into an array of strings.
		// if there's no hash, return an empty array.
	    var elts, hash;

	    hash = window.location.hash;
	    hash = hash.slice(1,hash.length)

	    if(hash){
	        elts = hash.split('/')
	    } else
	        elts = []

	    return elts
	}

	this.matchRoute = function(hashArray){
		//given the URL hash as an array, return the corresponding value from ul.routes
		var key, auxkey, route, template, data, auxdata, html;

		route = document.getElementById('body').getAttribute('route');
		routeArray = route.split('/');
		routeData = this.compareRoutes(hashArray, routeArray)

		if(routeData || hashArray.length == 0){

			//add additional data to the view as neessary:
			if (typeof ulAuxilaryData === "function"){
				auxdata = ulAuxilaryData(route, routeData)

				for(auxkey in auxdata){
					routeData[auxkey] = auxdata[auxkey]
				}
			}

			//render template
			template = document.getElementById('body').innerHTML;
			html = Mustache.to_html(template, routeData, ul.partials);
			//body = document.createElement('body'); //see #4
			//document.getElementsByTagName('body')[0].appendChild(body);
			document.body.innerHTML += html;
			return 0;
		}

		return 404;
	}

	this.compareRoutes = function(hash, route){
		//helper for comparing route arrays. hash is from the url hash, route is from ul.routes

		var key,
			data = {}

	 	if (hash == null || route == null) return false;
		if (hash.length != route.length) return false;

		for (var i = 0; i < hash.length; ++i) {
			// deal with variable routes
			if(route[i].slice(0,2) == '{{'){
				key = route[i].substring(2, route[i].length - 2);
				data[key] = hash[i];
				continue;
			} else if (hash[i] !== route[i])
				return false;
		}
		return data;
	}

	this.promisePartials = function(){
		// pull in all partials async, by the power of promises

		var sequence = Promise.resolve();

		sequence.then(function(){
			return Promise.all(ul.partials.map(ulUtilGet))
		}).then(function(partials){
			for(i=0; i<partials.length; i++){
				partial = document.createElement('script');
				partial.setAttribute('type', 'text/template');
				partial.setAttribute('id', ul.partials[i]);
				partial.innerHTML = partials[i]
				document.getElementsByTagName('head')[0].appendChild(partial);

			}

		}).then(function() {
			var i, key, hash, partials = {};

			//set up partials
			for(i=0; i<ul.partials.length; i++){
				partials[ul.partials[i]] = document.getElementById(ul.partials[i]).innerHTML;
			}
			ul.partials = partials;

			//render the route and report status in the console.
			hash = ul.parseHash()
			console.log(ul.matchRoute(hash))
		}).then(function(){
			//allow a post-rendering callback
			if(typeof ulCallback === "function"){
				ulCallback();
			}
		});
	}

	this.promisePartials()

}

function ulUtilGet(name) {
	// promise to get tempate <name>; thanks http://www.html5rocks.com/en/tutorials/es6/promises/
	var rootURL, path;

	rootURL = window.location.protocol + "//" + window.location.host;
	path = window.location.pathname.split('/').slice(0,-1);
	for(i=0; i<path.length; i++){
		rootURL += path[i] + '/'
	}

	url = rootURL + 'partials/' + name + '.mustache';

	// Return a new promise.
 	return new Promise(function(resolve, reject) {
		// Do the usual XHR stuff
    	var req = new XMLHttpRequest();
    	req.open('GET', url);

    	req.onload = function() {
      		// This is called even on 404 etc
      		// so check the status
      		if (req.status == 200) {
        		// Resolve the promise with the response text
        		resolve(req.response);
      		}
      		else {
        		// Otherwise reject with the status text
        		// which will hopefully be a meaningful error
        		reject(Error(req.statusText));
      		}
    	};

	    // Handle network errors
	    req.onerror = function() {
    		reject(Error("Network Error"));
    	};

	    // Make the request
	    req.send();
  	});
}

window.onhashchange = function(){
	// since we're using hashes like full-fledged routes.
	location.reload(false)
}<|endoftext|>


<commit_before>'use strict';

function Fryr(callback) {
  return this.init(callback);
}

(function () {

  /**
  * @private
  * @function removeValue - delete value based on key
  * @param {string} key - param to target
  * @param {mixed} value - value to delete from param
  */
  var removeValue = function(key, value) {
    var hash = window.location.hash;
    // check for key, anything between key and value, the value itself, and optionally the trailing comma
    var regex_for_value = new RegExp('(' + key + '=.*)(' + value + '\,?)');
    // results come back [<search through value>, <search before value>, <value>]
    var regex_match = hash.match(regex_for_value);
    // replace <search through value> with everything before <value>
    // Key is included in search in case multiple keys have the same value
    hash = hash.replace(regex_match[0], regex_match[1]);

    // Remove trailing commas
    hash = hash.replace(/\,\&/g, '&');
    hash = hash.replace(/\,$/, '');
    hash = hash.replace(/\=\,/g, '=');

    window.location.hash = hash;
  };

  /**
  * @private
  * @function addValue - add value based on key
  * @param {string} key - param to target
  * @param {mixed} value - value to add to param
  * @param {optional boolean} should_replace_value - if false, value will be appended to the param
  */
  var addValue = function(key, value, should_replace_value) {
    var hash = window.location.hash;

    var old_value = param(key);
    var new_value;

    // If it's blank or is the value of the next param
    if(old_value.charAt(0) === '&' || old_value === '') {
      old_value = key + '=';
      new_value = old_value + value;

    } else {
      old_value = key + '=' + old_value;

      // If the value of the param should be replaced, don't append it to the existing value
      new_value = should_replace_value ? (key + '=' + value) : (old_value + ',' + value);
    }

    hash = hash.replace(old_value, new_value);

    window.location.hash = hash;
  };

  /**
  * @private
  * @function removeKey - remove key from hash. Key's value must be removed prior to executing this function
  * @param {string} key - key to search and destroy
  */
  var removeKey = function(key) {
    var hash = window.location.hash;
    var key_search = new RegExp('[?&]' + key + '=', 'g');

    hash = hash.replace(key_search, '');
    // if initial key removed, replace ampersand with question
    hash = hash.replace('#&', '#?');

    window.location.hash = hash;
  }

  /**
  * @private
  * @see documentation in the public `param` function
  */
  var param = function(key) {
    if(!window.location.hash) {
      return '';
    }
    var hash = window.location.hash;
    var search = new RegExp('#.*[?&]' + key + '=([^&]+)(&|$)');
    var key_value = hash.match(search);

    return (key_value ? key_value[1] : '');
  };

  /**
  * @private
  * @function setDefault - Apply value to variable if it has none
  * @param {var} variable - variable to set default to
  * @param {anything} value - default value to attribute to variable
  */
  var setDefault = function(variable, value){
    return (typeof variable === 'undefined') ? value : variable;
  };

  /**
  * @private
  * @function update - remove key/value if present in hash; add key/value if not present in hash
  * @param {string} key - param key to query against
  * @param {mixed} value - value for param key
  * @param {boolean} key_is_required - if the key is not required, it will be removed from the hash
  * @param {boolean} should_replace_value - if false, value will be appended to the key
  * @see .update and .append functions
  */
  var update = function(key, value, key_is_required, should_replace_value) {
    var hash = window.location.hash;

    // Ensure key exists in the hash
    if(hash.indexOf(key) !== -1) {
      var key_value = param(key);

      var regex_for_value = new RegExp(value, 'g');

      // If key_value contains the new value
      if(regex_for_value.test(key_value)) {

        // If key is required, swap it out
        if(key_is_required) {
          addValue(key, value, should_replace_value);

        } else {

          // If the value is blank, remove the original value from the key
          if(value === '') {
            removeValue(key, key_value);

          // Otherwise remove the vanilla value
          } else {
            removeValue(key, value);

          }

          // If key's value is blank, remove it from hash
          if(param(key) === '') {
            removeKey(key);
          }

        }

      // key_value does not contain the new value
      } else {
        addValue(key, value, should_replace_value);

      }

    // Add key if it doesn't exist
    } else {

      if(window.location.hash) {
        window.location.hash += '&' + key + '=' + value;
      } else {
        // Use a question mark if first key
        window.location.hash = '?' + key + '=' + value;
      }

    }

  };

  Fryr.prototype = {

    // Very important object holder
    params: {},

    /**
    * @function init - call once to initialize filtering
    * @param {func} hashChangeCallback - called on every hashchange (first argument is the updated params)
    */
    init: function(hashChangeCallback) {
      var _this = this;

      var privateHashChange = function() {
        var params = _this.parse();
        hashChangeCallback.call(this, params);
      };

      window.onhashchange = privateHashChange;

      privateHashChange();

      return this;

    },

    /**
    * @function update - replace key/value if present in hash; add key/value if not present in hash
    * @param {string} key - param key to query against
    * @param {mixed} value - value for param key
    * @param {optional boolean} key_is_required {false} - if the key is not required, it will be removed from the hash
    * @see .append function
    */
    update: function(key, value, key_is_required) {
      key_is_required = setDefault(key_is_required, false);
      update(key, value, key_is_required, true);
    },

    /**
    * @function append - add value to key's value in a comma-delineated list if it's not present in hash
    * @param {string} key - param key to query against
    * @param {mixed} value - value for param key
    * @see .update function
    */
    append: function(key, value) {
      update(key, value, false, false);
    },

    /**
    * @function parse - evaluate the hash
    * @return key/value hash of the hash broken down by params
    */
    parse: function() {
      var hash = window.location.hash;
      var params;

      // clear zombie keys and values
      this.params = {};

      if(window.location.hash && /\?/g.test(hash)) {
        params = hash.split('?')[1];
        params = params.split('&');

        // Separate params into key values
        for(var i = 0; i < params.length; i++) {
          var key_value = params[i].split('=');
          var key = key_value[0];
          var value = key_value[1];

          this.params[key] = value;
        }
      }

      return this.params;
    },

    /**
    * @function convert - change a JSON object into a string for the hash
    * @param {object | string} obj - object to convert
    * @return {string | boolean} to use in window.location.hash. Returns false if param is not object or string
    */
    convert: function(obj) {
      if( obj.constructor === String ) {
        obj = JSON.parse(obj);
      }

      // Escape if we're not dealing with an object
      if( obj.constructor !== Object ) {
        return false;
      }

      var keys = Object.keys(obj);
      // Set start with a ?
      var new_hash = '?';

      // Loop through all keys in the obj
      for(var i = 0; i < keys.length; i++) {
        var key = keys[i];
        var value = obj[keys[i]];

        if( value.constructor === Array ) {
          value = value.join(',');
        }

        // On next key, if it isn't the first, precede with an ampersand
        if(new_hash !== '?') {
          new_hash += '&';
        }

        // Append key/value to new_hash
        new_hash += key + '=' + value;
      }

      return new_hash;
    },

    /**
    * @function merge - wipe out or selectively replace keys in params
    * @param {object | string} obj - query to replace
    * @param {boolean} replace_all {false} - whether or not to blast existing params away or replace only changed keys
    * @return {string} but also updates hash
    */
    merge: function(obj, replace_all) {
      replace_all = setDefault(replace_all, false);
      var new_hash;

      // If it's a string, convert to an object
      if( obj.constructor === String ) {
        obj = JSON.parse(obj);
      }

      if( replace_all ) {
        // Unilaterally make a string based on the params to use
        new_hash = this.convert(obj);

      } else {
        var new_params = this.parse();
        var keys = Object.keys(new_params);

        for(var i = 0; i < keys.length; i++) {
          var key = keys[i];
          var value = new_params[key[i]];

          if(obj.hasOwnProperty(key)) {
            new_params[key] = obj[key];
          }
        }

        new_hash = this.convert(new_params);
      }

      window.location.hash = '#' + new_hash;

      return new_hash;
    },

    /**
    * @function param - retrieve a key's value
    * @param {string} key - param to target
    * @example
    *   window.location.hash = ?color=blue
    *   fryr.param('color') // => 'blue'
    * @return {string} the value of the key
    */
    param: function(key) {
      return param(key);
    },

    /**
    * @function paramPresent - determine if param is blank or undefined
    * @param {string} key - param to target
    * @return boolean
    */
    paramPresent: function(key) {
      var value = this.params[key];
      return (typeof value !== 'undefined' && value !== '');
    },

  };

})();
<commit_msg>polish documentation to be more inline with JSDoc 3<commit_after>'use strict';

/**
 * The Fryr global initialization
 * @class
 */
function Fryr(callback) {
  /** @lends Fryr.prototype */
  return this.init(callback);
}

(function () {

  /**
   * @private
   * @description Delete value based on key
   * @param {String} key - Param to target
   * @param {String|Number} value - Value to delete from param
   */
  var removeValue = function(key, value) {
    var hash = window.location.hash;
    // check for key, anything between key and value, the value itself, and optionally the trailing comma
    var regex_for_value = new RegExp('(' + key + '=.*)(' + value + '\,?)');
    // results come back [<search through value>, <search before value>, <value>]
    var regex_match = hash.match(regex_for_value);
    // replace <search through value> with everything before <value>
    // Key is included in search in case multiple keys have the same value
    hash = hash.replace(regex_match[0], regex_match[1]);

    // Remove trailing commas
    hash = hash.replace(/\,\&/g, '&');
    hash = hash.replace(/\,$/, '');
    hash = hash.replace(/\=\,/g, '=');

    window.location.hash = hash;
  };

  /**
   * @private
   * @description Add value based on key
   * @param {String} key - Param to target
   * @param {String|Number} value - Value to add to param
   * @param {Boolean} should_replace_value - if false, value will be appended to the param
   */
  var addValue = function(key, value, should_replace_value) {
    var hash = window.location.hash;

    var old_value = param(key);
    var new_value;

    // If it's blank or is the value of the next param
    if(old_value.charAt(0) === '&' || old_value === '') {
      old_value = key + '=';
      new_value = old_value + value;

    } else {
      old_value = key + '=' + old_value;

      // If the value of the param should be replaced, don't append it to the existing value
      new_value = should_replace_value ? (key + '=' + value) : (old_value + ',' + value);
    }

    hash = hash.replace(old_value, new_value);

    window.location.hash = hash;
  };

  /**
   * @private
   * @description Remove key from hash. Key's value must be removed prior to executing this function
   * @param {String} key - Key to search and destroy
   */
  var removeKey = function(key) {
    var hash = window.location.hash;
    var key_search = new RegExp('[?&]' + key + '=', 'g');

    hash = hash.replace(key_search, '');
    // if initial key removed, replace ampersand with question
    hash = hash.replace('#&', '#?');

    window.location.hash = hash;
  }

  /**
   * @private
   * @see {@link Fryr#param documentation in the public `param` function}
   */
  var param = function(key) {
    if(!window.location.hash) {
      return '';
    }
    var hash = window.location.hash;
    var search = new RegExp('#.*[?&]' + key + '=([^&]+)(&|$)');
    var key_value = hash.match(search);

    return (key_value ? key_value[1] : '');
  };

  /**
   * @private
   * @description Apply value to variable if it has none
   * @param {*} variable Variable to set default to
   * @param {*} value - Default value to attribute to variable
   * @return {*} Existing value or passed value argument
   */
  var setDefault = function(variable, value){
    return (typeof variable === 'undefined') ? value : variable;
  };

  /**
   * @private
   * @description Remove key/value if present in hash; add key/value if not present in hash
   * @param {String} key - Param key to query against
   * @param {String|Number} value - Value for param key
   * @param {Boolean} key_is_required - If the key is not required, it will be removed from the hash
   * @param {Boolean} should_replace_value - If false, value will be appended to the key
   * @see {@link Fryr#update}
   * @see {@link Fryr#append}
   */
  var update = function(key, value, key_is_required, should_replace_value) {
    var hash = window.location.hash;

    // Ensure key exists in the hash
    if(hash.indexOf(key) !== -1) {
      var key_value = param(key);

      var regex_for_value = new RegExp(value, 'g');

      // If key_value contains the new value
      if(regex_for_value.test(key_value)) {

        // If key is required, swap it out
        if(key_is_required) {
          addValue(key, value, should_replace_value);

        } else {

          // If the value is blank, remove the original value from the key
          if(value === '') {
            removeValue(key, key_value);

          // Otherwise remove the vanilla value
          } else {
            removeValue(key, value);

          }

          // If key's value is blank, remove it from hash
          if(param(key) === '') {
            removeKey(key);
          }

        }

      // key_value does not contain the new value
      } else {
        addValue(key, value, should_replace_value);

      }

    // Add key if it doesn't exist
    } else {

      if(window.location.hash) {
        window.location.hash += '&' + key + '=' + value;
      } else {
        // Use a question mark if first key
        window.location.hash = '?' + key + '=' + value;
      }

    }

  };

  Fryr.prototype = {

    /**
     * @description Very important object holder
     * @type {Object}
     */
    params: {},

    /**
     * @description Call once to initialize filtering
     * @param {Function} hashChangeCallback - Called on every hashchange (first argument is the updated params)
     * @return {Object} Fryr
     */
    init: function(hashChangeCallback) {
      var _this = this;

      var privateHashChange = function() {
        var params = _this.parse();
        hashChangeCallback.call(this, params);
      };

      window.onhashchange = privateHashChange;

      privateHashChange();

      return this;
    },

    /**
     * @description Replace key/value if present in hash; add key/value if not present in hash
     * @param {String} key - Param key to query against
     * @param {String|Number} value - Value for param key
     * @param {Boolean} [key_is_required=false] - if the key is not required, it will be removed from the hash
     * @see {@link Fryr#append}
     */
    update: function(key, value, key_is_required) {
      key_is_required = setDefault(key_is_required, false);
      update(key, value, key_is_required, true);
    },

    /**
     * @description Add value to key's value in a comma-delineated list if it's not present in hash
     * @param {String} key - Param key to query against
     * @param {String|Number} value - Value for param key
     * @see {@link Fryr#update}
     */
    append: function(key, value) {
      update(key, value, false, false);
    },

    /**
     * @description Evaluate the hash
     * @return {Object} Key/value hash of the hash broken down by params
     */
    parse: function() {
      var hash = window.location.hash;
      var params;

      // clear zombie keys and values
      this.params = {};

      if(window.location.hash && /\?/g.test(hash)) {
        params = hash.split('?')[1];
        params = params.split('&');

        // Separate params into key values
        for(var i = 0; i < params.length; i++) {
          var key_value = params[i].split('=');
          var key = key_value[0];
          var value = key_value[1];

          this.params[key] = value;
        }
      }

      return this.params;
    },

    /**
     * @description Change a JSON object into a string for the hash
     * @param {Object|String} obj - object to convert
     * @return {String|Boolean} For use in window.location.hash. Returns false if param is not object or string
     */
    convert: function(obj) {
      if( obj.constructor === String ) {
        obj = JSON.parse(obj);
      }

      // Escape if we're not dealing with an object
      if( obj.constructor !== Object ) {
        return false;
      }

      var keys = Object.keys(obj);
      // Set start with a ?
      var new_hash = '?';

      // Loop through all keys in the obj
      for(var i = 0; i < keys.length; i++) {
        var key = keys[i];
        var value = obj[keys[i]];

        if( value.constructor === Array ) {
          value = value.join(',');
        }

        // On next key, if it isn't the first, precede with an ampersand
        if(new_hash !== '?') {
          new_hash += '&';
        }

        // Append key/value to new_hash
        new_hash += key + '=' + value;
      }

      return new_hash;
    },

    /**
     * @description Wipe out or selectively replace keys in params
     * @param {Object|String} obj - Query to replace
     * @param {Boolean} [replace_all=false] - Whether or not to blast existing params away or replace only changed keys
     * @return {String} The new hash, but it also updates window.location.hash
     */
    merge: function(obj, replace_all) {
      replace_all = setDefault(replace_all, false);
      var new_hash;

      // If it's a string, convert to an object
      if( obj.constructor === String ) {
        obj = JSON.parse(obj);
      }

      if( replace_all ) {
        // Unilaterally make a string based on the params to use
        new_hash = this.convert(obj);

      } else {
        var new_params = this.parse();
        var keys = Object.keys(new_params);

        for(var i = 0; i < keys.length; i++) {
          var key = keys[i];
          var value = new_params[key[i]];

          if(obj.hasOwnProperty(key)) {
            new_params[key] = obj[key];
          }
        }

        new_hash = this.convert(new_params);
      }

      window.location.hash = '#' + new_hash;

      return new_hash;
    },

    /**
     * @description Retrieve a key's value
     * @param {String} key - Param to target
     * @example
     * window.location.hash = '?color=blue'
     * fryr.param('color') // => 'blue'
     * @return {String} The value of the key
     */
    param: function(key) {
      return param(key);
    },

    /**
     * @description Determine if param is blank or undefined
     * @param {String} key - Param to target
     * @return {Boolean}
     */
    paramPresent: function(key) {
      var value = this.params[key];
      return (typeof value !== 'undefined' && value !== '');
    },

  };

})();
<|endoftext|>


<commit_before>class Ball extends Phaser.Sprite {

  constructor(game, x, y, color = '#0000ff') {
    const bmd = game.add.bitmapData(50, 50);
    // draw to the canvas context like normal
    bmd.ctx.beginPath();
    bmd.ctx.arc(25, 25, 25 - 5, 0, 2 * Math.PI, false);
    bmd.ctx.fillStyle = 'green';
    bmd.ctx.fill();
    bmd.ctx.lineWidth = 5;
    bmd.ctx.strokeStyle = '#003300';
    bmd.ctx.stroke();
    super(game, x, y, bmd);
    game.physics.enable(this, Phaser.Physics.ARCADE);
    this.body.bounce.set(1);
  }

}

export default Ball;<commit_msg>fix collision ball<commit_after>class Ball extends Phaser.Sprite {

  constructor(game, x, y, color = '#0000ff', velX, velY) {
    const bmd = game.add.bitmapData(50, 50);
    bmd.ctx.beginPath();
    bmd.ctx.arc(25, 25, 25 - 5, 0, 2 * Math.PI, false);
    bmd.ctx.fillStyle = 'green';
    bmd.ctx.fill();
    bmd.ctx.lineWidth = 5;
    bmd.ctx.strokeStyle = '#003300';
    bmd.ctx.stroke();
    super(game, x, y, bmd);
    game.physics.enable(this, Phaser.Physics.ARCADE);
    this.checkWorldBounds = true;
    this.body.collideWorldBounds = true;
    this.anchor.set(0.5, 0.5);
    this.body.velocity.setTo(velX, velY);
    this.body.bounce.set(1);
  }

}

export default Ball;<|endoftext|>


<commit_before>define(['jquery'], function($) {

    /*!
     * jQuery Tiny Pub/Sub - v0.6 - 1/10/2011
     * http://benalman.com/
     *
     * Copyright (c) 2010 "Cowboy" Ben Alman
     * Dual licensed under the MIT and GPL licenses.
     * http://benalman.com/about/license/
     *
     * We purposely use an older version of the Tiny Pub/Sub implementation
     * because we want to keep API parity with existing code.
     * Newer versions meant the 'event' object would be passed as the first
     * argument to the subscriber/callback and this meant changing all our
     * EventEmitter code. I decided it was best to avoid that issue and use
     * an older version whose only difference is to strip off the first
     * argument so as to result in a true refactoring where we don't tamper
     * with the interface, just the implementation.
     */

    // Create a "dummy" jQuery object on which to bind, `off` and `trigger` event handlers.
    var o = $({}),
        emittedFromHost = false;

    /*
        Subscribe to a topic. Works just like `on`, except the passed handler
        is wrapped in a function so that the event object can be stripped out.
        Even though the event object might be useful, it is unnecessary and
        will only complicate things in the future should the user decide to move
        to a non-$.event-based pub/sub implementation.
     */
    $.on = function( topic, fn ) {
        // Call fn, stripping out the 1st argument (the event object).
        function wrapper() {
            return fn.apply(this, Array.prototype.slice.call(arguments, 1));
        }

        // Add .guid property to function to allow it to be easily unbound. Note
        // that $.guid is new in jQuery 1.4+, and $.event.guid was used before.
        wrapper.guid = fn.guid = fn.guid || ($.guid ? $.guid++ : $.event.guid++);

        // Bind the handler.
        o.on( topic, wrapper );
    };

    // Unsubscribe from a topic. Works exactly like unbind.
    $.off = function() {
        o.off.apply( o, arguments );
    };

    // Publish a topic. Works exactly like trigger.
    $.emit = function() {

        o.trigger.apply( o, arguments );

        var announcement         = arguments[0],
            details              = arguments[1];

        if (!emittedFromHost && announcement !== 'event_to_send_to_host') {
            $.emit('event_to_send_to_host', [announcement, details]);
        }

        emittedFromHost = false;
    };

    window.addEventListener('message', messageReceivedFromHost, false);

    function messageReceivedFromHost(event) {
        emittedFromHost = true;
        $.emit(event.data.announcement, [event.data.details]);
    }
});<commit_msg>fix jasmine<commit_after>define(['jquery'], function($) {

    /*!
     * jQuery Tiny Pub/Sub - v0.6 - 1/10/2011
     * http://benalman.com/
     *
     * Copyright (c) 2010 "Cowboy" Ben Alman
     * Dual licensed under the MIT and GPL licenses.
     * http://benalman.com/about/license/
     *
     * We purposely use an older version of the Tiny Pub/Sub implementation
     * because we want to keep API parity with existing code.
     * Newer versions meant the 'event' object would be passed as the first
     * argument to the subscriber/callback and this meant changing all our
     * EventEmitter code. I decided it was best to avoid that issue and use
     * an older version whose only difference is to strip off the first
     * argument so as to result in a true refactoring where we don't tamper
     * with the interface, just the implementation.
     */

    // Create a "dummy" jQuery object on which to bind, `off` and `trigger` event handlers.
    var o = $({}),
        emittedFromHost = false;

    /*
        Subscribe to a topic. Works just like `on`, except the passed handler
        is wrapped in a function so that the event object can be stripped out.
        Even though the event object might be useful, it is unnecessary and
        will only complicate things in the future should the user decide to move
        to a non-$.event-based pub/sub implementation.
     */
    $.on = function( topic, fn ) {
        // Call fn, stripping out the 1st argument (the event object).
        function wrapper() {
            return fn.apply(this, Array.prototype.slice.call(arguments, 1));
        }

        // Add .guid property to function to allow it to be easily unbound. Note
        // that $.guid is new in jQuery 1.4+, and $.event.guid was used before.
        wrapper.guid = fn.guid = fn.guid || ($.guid ? $.guid++ : $.event.guid++);

        // Bind the handler.
        o.on( topic, wrapper );
    };

    // Unsubscribe from a topic. Works exactly like unbind.
    $.off = function() {
        o.off.apply( o, arguments );
    };

    // Publish a topic. Works exactly like trigger.
    $.emit = function() {

        o.trigger.apply( o, arguments );

        var announcement         = arguments[0],
            details              = arguments[1];

        if (!emittedFromHost && announcement !== 'event_to_send_to_host') {
            $.emit('event_to_send_to_host', [announcement, details]);
        }

        emittedFromHost = false;
    };

    window.addEventListener('message', messageReceivedFromHost, false);

    function messageReceivedFromHost(event) {
        emittedFromHost = true;
        // shouldn't need this conditional, but PhantomJS/Jasmine complains otherwise.
        if (event.data.announcement) {
            $.emit(event.data.announcement, [event.data.details]);
        }
    }
});<|endoftext|>


<commit_before>var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
var ReactNative = require('react-native');

function CordovaPluginAdapter() {
    this.nativeInterface = ReactNative.NativeModules.CordovaPluginAdapter;
    this._callbackCount = Math.random();
    this._callbacks = {};

    this.initCallbackChannel();
};

CordovaPluginAdapter.prototype.exec = function(success, fail, service, action, args) {
    var callbackId = [service, action, this._callbackCount].join(':');
    this._callbacks[callbackId] = {
        success: success,
        fail: fail
    };
    this.nativeInterface.exec(service, action, callbackId, JSON.stringify(args));
    this._callbackCount++;
};

CordovaPluginAdapter.prototype.initCallbackChannel = function() {
    RCTDeviceEventEmitter.addListener('CordovaWebViewProxy', this.onChannelCallback, this);
};

CordovaPluginAdapter.prototype.onChannelCallback = function(params) {
    if (typeof this._callbacks[params.callbackId] === 'object') {
        var result = params.message;
        try {
            if (params.status === 1) {
                this._callbacks[params.callbackId].success(result);
            } else if (params.status > callbackStatus.OK) {
                this._callbacks[params.callbackId].fail(result);
            }
        } finally {
            if (!params.keepCallback) {
                delete this._callbacks[params.callbackId];
            }
        }
    }
};

module.exports = CordovaPluginAdapter;
<commit_msg>Fixed undefined variable<commit_after>var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
var ReactNative = require('react-native');

function CordovaPluginAdapter() {
    this.nativeInterface = ReactNative.NativeModules.CordovaPluginAdapter;
    this._callbackCount = Math.random();
    this._callbacks = {};

    this.initCallbackChannel();
};

CordovaPluginAdapter.prototype.exec = function(success, fail, service, action, args) {
    var callbackId = [service, action, this._callbackCount].join(':');
    this._callbacks[callbackId] = {
        success: success,
        fail: fail
    };
    this.nativeInterface.exec(service, action, callbackId, JSON.stringify(args));
    this._callbackCount++;
};

CordovaPluginAdapter.prototype.initCallbackChannel = function() {
    RCTDeviceEventEmitter.addListener('CordovaWebViewProxy', this.onChannelCallback, this);
};

CordovaPluginAdapter.prototype.onChannelCallback = function(params) {
    if (typeof this._callbacks[params.callbackId] === 'object') {
        var result = params.message;
        try {
            if (params.status === 1) {
                this._callbacks[params.callbackId].success(result);
            } else if (params.status === 1) {
                this._callbacks[params.callbackId].fail(result);
            }
        } finally {
            if (!params.keepCallback) {
                delete this._callbacks[params.callbackId];
            }
        }
    }
};

module.exports = CordovaPluginAdapter;
<|endoftext|>