<commit_before>var __hasProp = {}.hasOwnProperty,
	__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
	fs = require('fs-plus'),
	path = require('path'),
	Model = require('theorist').Model;

module.exports = File = (function (parent) {
	__extends(File, parent);

	File.properties({
		parent: null,
		name: '',
		client: null,
		status: 0,
		size: 0,
		date: null,
		type: null
	});

	File.prototype.accessor('local', function () {
		if (this.parent)
			return path.normalize(path.join(this.parent.local, this.name)).replace(/\\/g, '/');
		throw "File needs to be in a Directory";
	});

	File.prototype.accessor('remote', function () {
		if (this.parent)
			return path.normalize(path.join(this.parent.remote, this.name)).replace(/\\/g, '/');
		throw "File needs to be in a Directory";
	});

	File.prototype.accessor('root', function () {
		if (this.parent)
			return this.parent.root;
		return this;
	});

	function File () {
		File.__super__.constructor.apply(this, arguments);

		if (fs.isReadmePath(this.path))
			this.type = 'readme';
		else if (fs.isCompressedExtension(this.path))
			this.type = 'compressed';
		else if (fs.isImageExtension(this.path))
			this.type = 'image';
		else if (fs.isPdfExtension(this.path))
			this.type = 'pdf';
		else if (fs.isBinaryExtension(this.path))
			this.type = 'binary';
		else
			this.type = 'text';
	}

	File.prototype.open = function () {
		var self = this,
			client = self.root.client;

		client.download(self.remote, false, function (err) {
			if (err)
				atom.notifications.addError("Remote FTP: " + err);
				return;
			atom.workspace.open(self.local);
		});
	};

	return File;

})(Model);
<commit_msg>Missed a spot.<commit_after>var __hasProp = {}.hasOwnProperty,
	__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
	fs = require('fs-plus'),
	path = require('path'),
	Model = require('theorist').Model;

module.exports = File = (function (parent) {
	__extends(File, parent);

	File.properties({
		parent: null,
		name: '',
		client: null,
		status: 0,
		size: 0,
		date: null,
		type: null
	});

	File.prototype.accessor('local', function () {
		if (this.parent)
			return path.normalize(path.join(this.parent.local, this.name)).replace(/\\/g, '/');
		throw "File needs to be in a Directory";
	});

	File.prototype.accessor('remote', function () {
		if (this.parent)
			return path.normalize(path.join(this.parent.remote, this.name)).replace(/\\/g, '/');
		throw "File needs to be in a Directory";
	});

	File.prototype.accessor('root', function () {
		if (this.parent)
			return this.parent.root;
		return this;
	});

	function File () {
		File.__super__.constructor.apply(this, arguments);

		if (fs.isReadmePath(this.path))
			this.type = 'readme';
		else if (fs.isCompressedExtension(this.path))
			this.type = 'compressed';
		else if (fs.isImageExtension(this.path))
			this.type = 'image';
		else if (fs.isPdfExtension(this.path))
			this.type = 'pdf';
		else if (fs.isBinaryExtension(this.path))
			this.type = 'binary';
		else
			this.type = 'text';
	}

	File.prototype.open = function () {
		var self = this,
			client = self.root.client;

		client.download(self.remote, false, function (err) {
			if (err) {
				atom.notifications.addError("Remote FTP: " + err);
				return;
			}
			atom.workspace.open(self.local);
		});
	};

	return File;

})(Model);
<|endoftext|>


<commit_before>// ==UserScript==
// @name            Redirector
// @author          xiaoxiaoflood
// @include         main
// @shutdown        UC.Redirector.destroy();
// @onlyonce
// ==/UserScript==

// inspired by: https://github.com/harv/userChromeJS/blob/master/redirector_ui.uc.js

UC.Redirector = {

  // [regex, replace, decode, tld]
  rules: [[
    /^https?:\/\/redir\.folha\.com\.br\/redir\/online\/.+?\*(.+)/,
    '$1',
    true
  ], [
    /^https?:\/\/www\.google\.tld\/url\?(?:.*&)?(?:url|q)=([^&#]+).*/,
    '$1',
    true,
    true
  ], [
    /^https?:\/\/www\.google\.tld\/imgres\?imgurl=([^&#]+).*/,
    '$1',
    true,
    true
  ], [
    /^https:\/\/outgoing\.prod\.mozaws\.net\/v1\/\w+\/(.+)/,
    '$1',
    true
  ], [
    /^https?:\/\/click\.uol\.com\.br\/\?(?:.*&)?u=([^&#]+).*/,
    '$1',
    true
  ], [
    /^https?:\/\/(?:(?:m|new)\.)?vk\.com\/away\.php\?(?:.*&)?to=([^&#]+).*/,
    '$1',
    true
  ], [
    /^https?:\/\/l\.instagram\.com\/\?(?:.*&)?u=([^&#]+).*/,
    '$1',
    true
  ], [
    /^https?:\/\/www\.youtube\.com\/redirect\?(?:.*&)?q=([^&#]+).*/,
    '$1',
    true
  ], [
    /^https?:\/\/www\.reddit\.com\/u(?:(?:ser\/([^\/]+)\/?$)|\/(?:([^\/]+)\/?$|(.*)))/,
    function (url) {
      return 'https://www.reddit.com/user/' + (url[3] ? url[3] : (url[1] || url[2]) + '/overview/');
    }
  ], [
    /^https?:\/\/bugzil\.la\/(.*)/,
    function (url) {
      return 'https://bugzilla.mozilla.org/' + (url[1] ? 'show_bug.cgi?id=' + url[1] : '');
    }
  ], [
    /^https?:\/\/youtu\.be\/(.*)/,
    function (url) {
      return 'https://www.youtube.com/' + (url[1] ? 'watch?v=' + url[1] : '');
    }
  ], [
    /^https?:\/\/(userscripts\.org(?:\:8080|)|(?:www.|)webextender.net)\/(.*)/,
    'http://userscripts-mirror.org/$2'
  ], [
    /^http:\/\/ftp\.(mozilla\.org.*)/,
    'http://archive.$1'
  ], [
    //Remove universal parameters
    /(?:(\?)|&)(?:(?:(?:utm_\w+|ref|soc_\w+|cc_key|PHPSESSID|ig_mid|igshid|__twitter_impression|ved|cmpid|newreg|tag|fbclid|fref|variation|searchVariation|tracking_id|seller_id|partner_id|gclid)=).*?)(?=&|$|#)/g,
    '$1'
  ], [
    //Remove unnecesary ? and &
    /(?:(\?)(?:&+(?!$|&)))|(?:&(?=&))|(?:(?:\??&+|\?)$)/g,
    '$1'
  ]],

  internalRules: {
    [Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST]: [
      // bypass blocked embed youtube videos
      [/^https:\/\/www\.youtube\.com\/get_video_info\?(?:video_id=(.+?)(?:&|%26)|.+?&video_id=(.+?)&).+?eurl=.+?(&.*|)$/,
       'https://www.youtube.com/get_video_info?video_id=$1$2&eurl=https%3A%2F%2Fyoutube.com$3'],
    ],
  },

  getRedirectUrl: function (originUrl, aRules = this.rules) {
    var nsIOriginUrl = Services.io.newURI(originUrl);
    if (nsIOriginUrl.scheme == 'jar' || !nsIOriginUrl.asciiHost)
      return false;
    try {
      var tld = Services.eTLD.getPublicSuffix(nsIOriginUrl).replace(/\./, '\\.');
    } catch (e) { // ip
      var tld = 'tld';
    }
    var redirectUrl = false;
    aRules?.forEach((rule) => {
      var regex = rule[3] ? new RegExp(rule[0].source.replace(/\.tld/, '\.' + tld)) : rule[0];
      if (regex.test(originUrl)) {
        if (!redirectUrl)
          redirectUrl = true;
        originUrl = typeof rule[1] == 'function'
          ? rule[2]
            ? decodeURIComponent(rule[1](originUrl.match(regex)))
            : rule[1](originUrl.match(regex))
          : rule[2]
            ? decodeURIComponent(originUrl.replace(regex, rule[1]))
            : originUrl.replace(regex, rule[1]);
      }
    });
    return redirectUrl ? originUrl : false;
  },

  observe: function (subject) {
    let httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
    let contentType = httpChannel.loadInfo.externalContentPolicyType;
    if (contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT) {
      let redirectUrl = this.getRedirectUrl(httpChannel.URI.spec);
      if (redirectUrl) {
        let loadInfo = httpChannel.loadInfo;
        loadInfo.browsingContext.embedderElement.loadURI(redirectUrl, {referer: loadInfo.loadingPrincipal?.URI, triggeringPrincipal: loadInfo.triggeringPrincipal});
      }
    } else if (contentType in this.internalRules) {
      let redirectUrl = this.getRedirectUrl(httpChannel.URI.spec, this.internalRules[contentType]);
      if (redirectUrl) {
        httpChannel.redirectTo(Services.io.newURI(redirectUrl));
      }
    }
  },

  init: function () {
    Services.obs.addObserver(this, 'http-on-modify-request', false);
  },

  destroy: function () {
    Services.obs.removeObserver(this, 'http-on-modify-request', false);
    delete UC.Redirector;
  }
}

UC.Redirector.init();<commit_msg>fix redirector.uc.js<commit_after>// ==UserScript==
// @name            Redirector
// @author          xiaoxiaoflood
// @include         main
// @shutdown        UC.Redirector.destroy();
// @onlyonce
// ==/UserScript==

// inspired by: https://github.com/harv/userChromeJS/blob/master/redirector_ui.uc.js

UC.Redirector = {

  // [regex, replace, decode, tld]
  rules: [[
    /^https?:\/\/redir\.folha\.com\.br\/redir\/online\/.+?\*(.+)/,
    '$1',
    true
  ], [
    /^https?:\/\/www\.google\.tld\/url\?(?:.*&)?(?:url|q)=([^&#]+).*/,
    '$1',
    true,
    true
  ], [
    /^https?:\/\/www\.google\.tld\/imgres\?imgurl=([^&#]+).*/,
    '$1',
    true,
    true
  ], [
    /^https:\/\/outgoing\.prod\.mozaws\.net\/v1\/\w+\/(.+)/,
    '$1',
    true
  ], [
    /^https?:\/\/click\.uol\.com\.br\/\?(?:.*&)?u=([^&#]+).*/,
    '$1',
    true
  ], [
    /^https?:\/\/(?:(?:m|new)\.)?vk\.com\/away\.php\?(?:.*&)?to=([^&#]+).*/,
    '$1',
    true
  ], [
    /^https?:\/\/l\.instagram\.com\/\?(?:.*&)?u=([^&#]+).*/,
    '$1',
    true
  ], [
    /^https?:\/\/www\.youtube\.com\/redirect\?(?:.*&)?q=([^&#]+).*/,
    '$1',
    true
  ], [
    /^https?:\/\/www\.reddit\.com\/u(?:(?:ser\/([^\/]+)\/?$)|\/(?:([^\/]+)\/?$|(.*)))/,
    function (url) {
      return 'https://www.reddit.com/user/' + (url[3] ? url[3] : (url[1] || url[2]) + '/overview/');
    }
  ], [
    /^https?:\/\/bugzil\.la\/(.*)/,
    function (url) {
      return 'https://bugzilla.mozilla.org/' + (url[1] ? 'show_bug.cgi?id=' + url[1] : '');
    }
  ], [
    /^https?:\/\/youtu\.be\/(.*)/,
    function (url) {
      return 'https://www.youtube.com/' + (url[1] ? 'watch?v=' + url[1] : '');
    }
  ], [
    /^https?:\/\/(userscripts\.org(?:\:8080|)|(?:www.|)webextender.net)\/(.*)/,
    'http://userscripts-mirror.org/$2'
  ], [
    /^http:\/\/ftp\.(mozilla\.org.*)/,
    'http://archive.$1'
  ], [
    //Remove universal parameters
    /(?:(\?)|&)(?:(?:(?:utm_\w+|ref|soc_\w+|cc_key|PHPSESSID|ig_mid|igshid|__twitter_impression|ved|cmpid|newreg|tag|fbclid|fref|variation|searchVariation|tracking_id|seller_id|partner_id|gclid)=).*?)(?=&|$|#)/g,
    '$1'
  ], [
    //Remove unnecesary ? and &
    /(?:(\?)(?:&+(?!$|&)))|(?:&(?=&))|(?:(?:\??&+|\?)$)/g,
    '$1'
  ]],

  internalRules: {
    [Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST]: [
      // bypass blocked embed youtube videos
      [/^https:\/\/www\.youtube\.com\/get_video_info\?(?:video_id=(.+?)(?:&|%26)|.+?&video_id=(.+?)&).+?eurl=.+?(&.*|)$/,
       'https://www.youtube.com/get_video_info?video_id=$1$2&eurl=https%3A%2F%2Fyoutube.com$3'],
    ],
  },

  getRedirectUrl: function (originUrl, aRules = this.rules) {
    var nsIOriginUrl = Services.io.newURI(originUrl);
    if (nsIOriginUrl.scheme == 'jar' || !nsIOriginUrl.asciiHost)
      return false;
    try {
      var tld = Services.eTLD.getPublicSuffix(nsIOriginUrl).replace(/\./, '\\.');
    } catch (e) { // ip
      var tld = 'tld';
    }
    var redirectUrl = false;
    aRules?.forEach((rule) => {
      var regex = rule[3] ? new RegExp(rule[0].source.replace(/\.tld/, '\.' + tld)) : rule[0];
      if (regex.test(originUrl)) {
        if (!redirectUrl)
          redirectUrl = true;
        originUrl = typeof rule[1] == 'function'
          ? rule[2]
            ? rule[1](decodeURIComponent(originUrl).match(regex))
            : rule[1](originUrl.match(regex))
          : rule[2]
            ? decodeURIComponent(originUrl.replace(regex, rule[1]))
            : originUrl.replace(regex, rule[1]);
      }
    });
    return redirectUrl ? originUrl : false;
  },

  observe: function (subject) {
    let httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
    if (httpChannel.loadInfo.originAttributes.firstPartyDomain.startsWith('(view-source'))
      return;
    let contentType = httpChannel.loadInfo.externalContentPolicyType;
    if (contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT) {
      let redirectUrl = this.getRedirectUrl(httpChannel.URI.spec);
      if (redirectUrl) {
        let loadInfo = httpChannel.loadInfo;
        loadInfo.browsingContext.embedderElement.loadURI(redirectUrl, {referer: loadInfo.loadingPrincipal?.URI, triggeringPrincipal: loadInfo.triggeringPrincipal});
      }
    } else if (contentType in this.internalRules) {
      let redirectUrl = this.getRedirectUrl(httpChannel.URI.spec, this.internalRules[contentType]);
      if (redirectUrl) {
        httpChannel.redirectTo(Services.io.newURI(redirectUrl));
      }
    }
  },

  init: function () {
    Services.obs.addObserver(this, 'http-on-modify-request', false);
  },

  destroy: function () {
    Services.obs.removeObserver(this, 'http-on-modify-request', false);
    delete UC.Redirector;
  }
}

UC.Redirector.init();<|endoftext|>


<commit_before>'use strict';
var fs      = require('fs');
var path    = require('path');
var helpers = require('./helpers');

module.exports = function(file) {
  var file          = file;
  var originalPath  = file.path;
  var hash          = helpers.hash(file.contents);

  function newPath() {
    var ext       = path.extname(originalPath);
    var filename  = path.basename(originalPath, ext) + '-' + hash + ext;
    return path.join(path.dirname(originalPath), filename);
  }

  function name(name) {
    var name = name.replace(file.base, '');
    if (name.indexOf('/') == 0) name = name.slice(1);
    return name;
  }

  return {
    newName:  name(newPath()),
    oldName:  name(originalPath),
    newPath:  newPath(),
    mtime:    fs.statSync(originalPath).mtime,
    hash:     hash,
    size:     file.contents.length
  }

}
<commit_msg>Fix mtime<commit_after>'use strict';
var fs      = require('fs');
var path    = require('path');
var helpers = require('./helpers');

module.exports = function(file) {
  var file          = file;
  var originalPath  = file.path;
  var hash          = helpers.hash(file.contents);

  function newPath() {
    var ext       = path.extname(originalPath);
    var filename  = path.basename(originalPath, ext) + '-' + hash + ext;
    return path.join(path.dirname(originalPath), filename);
  }

  function name(name) {
    var name = name.replace(file.base, '');
    if (name.indexOf('/') == 0) name = name.slice(1);
    return name;
  }

  function mtime() {
    try {
      return fs.statSync(file.path).mtime;
    } catch(e) {
      return new Date();
    }
  }

  return {
    newName:  name(newPath()),
    oldName:  name(originalPath),
    newPath:  newPath(),
    mtime:    mtime(),
    hash:     hash,
    size:     file.contents.length
  }

}
<|endoftext|>


<commit_before>Polymer({
  /**
   * An url is provided that the user wants an ezyproxy url of
   * eg http://www.sciencedirect.com/science/article/pii/S1744388116300159
   * the eventual landing url will be
   * http://www.sciencedirect.com.ezproxy.library.uq.edu.au/science/article/pii/S1744388116300159
   * However!
   * @dcallan says that this can fail sometimes in the ezproxy portal
   * so the url we build has the form:
   * http://ezproxy.library.uq.edu.au/login?url=http://www.sciencedirect.com/science/article/pii/S1744388116300159
   * for passing to the portal
   *
   * Note:
   * Final landing urls for https urls have a special format.
   * but!
   * ezproxy will handle it - we do not need to do anything special for https urls here
   */

  is: 'uql-ezproxy',

  properties: {
    /**
     * Set the Widget mode to Display target link (true) or open the url in a new window/tab (false). Default: false
     * @type {Boolean}
     */
    createLink: {
      type: Object,
      value: false,
      observer: "_createLinkChanged"
    },

    /*
     * set the regexp for DOI url matching
     * DOI numbers have formats like: doi:10.10.1038/nphys1170
     * per http://www.doi.org/demos.html
     */
    doiRegexp: {
      type: RegExp,
      value: /^\b(10[.][0-9]{3,}(?:[.][0-9]+)*\/(?:(?!["&\'])\S)+)\b/
    }

  },

  /**
   * Set button label according to the widget mode
   * @param newValue
   * @param oldValue
   * @private
   */
  _createLinkChanged: function(newValue, oldValue) {
    if(this.createLink) {
      this.buttonLabelValue='Create Link'; // used on link generator widget mode
    } else {
      this.buttonLabelValue='Go'; // used on link visit widget mode
    }
  },

  /**
   * Based on the widget mode, the submit method will display the ezproxy link or will open the URL in a new windows/tab
   * @private
   */
  _submit: function (type) {
    var cleanedUrl = this.cleanupURL(this.$.url.value);
    if (this.createLink) {
      this.showUrl(cleanedUrl);
    } else {
      this.goProxie(cleanedUrl);
    }
  },

  /**
   * Display ezproxy link
   * @param cleanedUrl
   */
  showUrl: function (cleanedUrl) {
    var check = this.checkURL(cleanedUrl);
    if (check.valid) {
      var dest = this.getURL(cleanedUrl);
      this.$.ga.addEvent('ShowUrl', dest);
      this.panelToggle();
    }
  },

  /**
   * Open ezproxy link in a new window/tab
   * @param cleanedUrl
   */
  goProxie: function (cleanedUrl) {
    var check = this.checkURL(cleanedUrl);
    if (check.valid) {
      var dest = this.getURL(cleanedUrl);
      this.$.ga.addEvent('GoProxy', dest);
      var win = window.open(dest);
      win.focus();
    }
  },

  /**
   * remove extraneous bits from the web address
   * @param dest
   * @returns {*}
   */
  cleanupURL: function(dest) {
    dest = dest.trim();
    dest = dest.replace('http://ezproxy.library.uq.edu.au/login?url=', '');

    var ezproxyUrlRegexp = /(([A-Za-z]*:(?:\/\/)?)(.)+(.ezproxy.library.uq.edu.au))(.*)?/;
    if (ezproxyUrlRegexp.test(dest))  {
      dest = dest.replace('.ezproxy.library.uq.edu.au', '');
    }

    dest = dest.replace('http://dx.doi.org/', '');

    return dest;
  },

  /**
   * create the landing url
   * @param dest
   * @returns {string}
   */
  getURL: function(dest) {
    var result = "";

    var check = this.checkURL(dest);

    if (check.valid) {
      result = 'http://ezproxy.library.uq.edu.au/login?url=';
      if (this.doiRegexp.test(dest)) {
        result += 'http://dx.doi.org/';
      }
      result += dest;
    }
    return result;
  },

  /**
   * Verify if users URL request is a valid link
   * @param dest
   * @returns {boolean}
   */
  checkURL: function (dest) {
    var validation = {
      valid : false,
      message: ''
    };

    if (dest.length <= 0) {
      validation.message = "Please enter a URL";
    } else if(this.doiRegexp.test(dest)) {
      validation.valid = true;
    } else if (!validator.isURL(dest, {require_protocol: true})) {
      if (dest.substring(0, 4).toLowerCase() !== 'http') {
        validation.message = "Invalid URL. Please add the protocol ie: http://, https://";
      } else {
        validation.message = "Invalid URL.";
      }
    } else {
      validation.valid = true;
    }
    this.$.errorMsg.textContent = validation.message;

    this.$.urlContainer.invalid = !validation.valid;

    return validation;
  },

  /*
   * Show ezproxy link panel or Hide and clean its values
   */
  panelToggle: function() {
    this.hide=!this.hide;
    this.copyStatus = "";
    if(this.hide) {
      this.$.url.value = "";
      this.$.urlContainer.invalid = false;
      this.$.url.focus();
    } else {
      var cleanedUrl = this.cleanupURL(this.$.url.value);
      this.querySelector("#textarea").value = this.getURL(cleanedUrl);
      this.querySelector("#outputUrlDisplay").innerHTML = this.getURL(cleanedUrl);
      this.querySelector("#outputUrl").style.display = "none";
      this.$.testLinkButton.focus();
    }
  },

  /*
   * Copy URL to Clipboard (same as ctrl+a / ctrl+c)
   * Only available for Firefox 41+, Chrome 43+, Opera 29+, IE 10+
   */
  grabUrl: function() {
    //Show the hidden textfield with the URL, and select it
    this.querySelector("#outputUrl").style.display = "block";
    this.$.outputUrl.querySelector("#textarea").select();

    try {
      var successful = document.execCommand('copy');
      this.copyStatus = (successful ? 'URL copied successfully' : 'Unable to copy URL');
    } catch (err) {
      this.copyStatus = 'Unable to copy URL';
    }
    //Hide the textfield
    this.querySelector("#outputUrl").style.display = "none";
    this.$.copyNotification.open();
  },

  /*
   * Display widget primary panel
   */
  ready: function() {
    this.hide = true;
  }

});
<commit_msg>fixing test link [PT #131778911]<commit_after>Polymer({
  /**
   * An url is provided that the user wants an ezyproxy url of
   * eg http://www.sciencedirect.com/science/article/pii/S1744388116300159
   * the eventual landing url will be
   * http://www.sciencedirect.com.ezproxy.library.uq.edu.au/science/article/pii/S1744388116300159
   * However!
   * @dcallan says that this can fail sometimes in the ezproxy portal
   * so the url we build has the form:
   * http://ezproxy.library.uq.edu.au/login?url=http://www.sciencedirect.com/science/article/pii/S1744388116300159
   * for passing to the portal
   *
   * Note:
   * Final landing urls for https urls have a special format.
   * but!
   * ezproxy will handle it - we do not need to do anything special for https urls here
   */

  is: 'uql-ezproxy',

  properties: {
    /**
     * Set the Widget mode to Display target link (true) or open the url in a new window/tab (false). Default: false
     * @type {Boolean}
     */
    createLink: {
      type: Object,
      value: false,
      observer: "_createLinkChanged"
    },

    /*
     * set the regexp for DOI url matching
     * DOI numbers have formats like: doi:10.10.1038/nphys1170
     * per http://www.doi.org/demos.html
     */
    doiRegexp: {
      type: RegExp,
      value: /^\b(10[.][0-9]{3,}(?:[.][0-9]+)*\/(?:(?!["&\'])\S)+)\b/
    }

  },

  /**
   * Set button label according to the widget mode
   * @param newValue
   * @param oldValue
   * @private
   */
  _createLinkChanged: function(newValue, oldValue) {
    if(this.createLink) {
      this.buttonLabelValue='Create Link'; // used on link generator widget mode
    } else {
      this.buttonLabelValue='Go'; // used on link visit widget mode
    }
  },

  /**
   * Based on the widget mode, the submit method will display the ezproxy link or will open the URL in a new windows/tab
   * @private
   */
  _submit: function () {
    var cleanedUrl;
    if (this.createLink) {
      cleanedUrl = this.cleanupURL(this.$.url.value);
      this.showUrl(cleanedUrl);
    } else {
      this.goProxie(this.$.url.value);
    }
  },

  /**
   * Display ezproxy link
   * @param cleanedUrl
   */
  showUrl: function (cleanedUrl) {
    var check = this.checkURL(cleanedUrl);
    if (check.valid) {
      var dest = this.getURL(cleanedUrl);
      this.$.ga.addEvent('ShowUrl', dest);
      this.panelToggle();
    }
  },

  /**
   * Open ezproxy link in a new window/tab
   * @param cleanedUrl
   */
  goProxie: function (cleanedUrl) {
    var cleanedUrl = this.cleanupURL(this.$.url.value);
    var check = this.checkURL(cleanedUrl);
    if (check.valid) {
      var dest = this.getURL(cleanedUrl);
      this.$.ga.addEvent('GoProxy', dest);
      var win = window.open(dest);
      win.focus();
    }
  },

  /**
   * remove extraneous bits from the web address
   * @param dest
   * @returns {*}
   */
  cleanupURL: function(dest) {
    dest = dest.trim();
    dest = dest.replace('http://ezproxy.library.uq.edu.au/login?url=', '');

    var ezproxyUrlRegexp = /(([A-Za-z]*:(?:\/\/)?)(.)+(.ezproxy.library.uq.edu.au))(.*)?/;
    if (ezproxyUrlRegexp.test(dest))  {
      dest = dest.replace('.ezproxy.library.uq.edu.au', '');
    }

    dest = dest.replace('http://dx.doi.org/', '');

    return dest;
  },

  /**
   * create the landing url
   * @param dest
   * @returns {string}
   */
  getURL: function(dest) {
    var result = "";

    var check = this.checkURL(dest);

    if (check.valid) {
      result = 'http://ezproxy.library.uq.edu.au/login?url=';
      if (this.doiRegexp.test(dest)) {
        result += 'http://dx.doi.org/';
      }
      result += dest;
    }
    return result;
  },

  /**
   * Verify if users URL request is a valid link
   * @param dest
   * @returns {boolean}
   */
  checkURL: function (dest) {
    var validation = {
      valid : false,
      message: ''
    };

    if (dest.length <= 0) {
      validation.message = "Please enter a URL";
    } else if(this.doiRegexp.test(dest)) {
      validation.valid = true;
    } else if (!validator.isURL(dest, {require_protocol: true})) {
      if (dest.substring(0, 4).toLowerCase() !== 'http') {
        validation.message = "Invalid URL. Please add the protocol ie: http://, https://";
      } else {
        validation.message = "Invalid URL.";
      }
    } else {
      validation.valid = true;
    }
    this.$.errorMsg.textContent = validation.message;

    this.$.urlContainer.invalid = !validation.valid;

    return validation;
  },

  /*
   * Show ezproxy link panel or Hide and clean its values
   */
  panelToggle: function() {
    this.hide=!this.hide;
    this.copyStatus = "";
    if(this.hide) {
      this.$.url.value = "";
      this.$.urlContainer.invalid = false;
      this.$.url.focus();
    } else {
      var cleanedUrl = this.cleanupURL(this.$.url.value);
      this.querySelector("#textarea").value = this.getURL(cleanedUrl);
      this.querySelector("#outputUrlDisplay").innerHTML = this.getURL(cleanedUrl);
      this.querySelector("#outputUrl").style.display = "none";
      this.$.testLinkButton.focus();
    }
  },

  /*
   * Copy URL to Clipboard (same as ctrl+a / ctrl+c)
   * Only available for Firefox 41+, Chrome 43+, Opera 29+, IE 10+
   */
  grabUrl: function() {
    //Show the hidden textfield with the URL, and select it
    this.querySelector("#outputUrl").style.display = "block";
    this.$.outputUrl.querySelector("#textarea").select();

    try {
      var successful = document.execCommand('copy');
      this.copyStatus = (successful ? 'URL copied successfully' : 'Unable to copy URL');
    } catch (err) {
      this.copyStatus = 'Unable to copy URL';
    }
    //Hide the textfield
    this.querySelector("#outputUrl").style.display = "none";
    this.$.copyNotification.open();
  },

  /*
   * Display widget primary panel
   */
  ready: function() {
    this.hide = true;
  }

});
<|endoftext|>


<commit_before>var util = require('util');
var events = require('events');
var strtok = require('strtok');
var fs = require('fs');
var common = require('./common');

var Flac = module.exports = function(stream) {
  events.EventEmitter.call(this);
  this.stream = stream;
  this.parse();
};

util.inherits(Flac, events.EventEmitter);

Flac.prototype.parse = function() {
  var self = this;

  strtok.parse(self.stream, function(v, cb) {
    try {
      if (!v) {
        cb.position = 'ID';
        return new strtok.StringType(4);
      }

      if (cb.position === 'ID') {
        if (v !== 'fLaC') {
          throw new Error('expected flac header but was not found');
        }

        cb.position = 'METADATA_BLOCK_HEADER';
        return new strtok.BufferType(4);
      }

      if (cb.position === 'METADATA_BLOCK_HEADER') {
        cb.blockHeader = {
          last_metadata_block: (v[0] & 0x80) == 0x80,
          block_type: v[0] & 0x7f,
          length: strtok.UINT24_BE.get(v, 1)
        }

        if (cb.blockHeader.last_metadata_block) {
          self.emit('done');
          return strtok.DONE;
        }

        cb.position = 'METADATA_BLOCK_DATA';
        return new strtok.BufferType(cb.blockHeader.length);
      }

      if (cb.position === 'METADATA_BLOCK_DATA') {
        if (cb.blockHeader.block_type === 4) {
          var offset = 0;
          var vendorLen = strtok.UINT32_LE.get(v, offset);
          offset += 4;
          var vendorString = v.toString('utf8', offset, offset += vendorLen);
          var commentListLength = strtok.UINT32_LE.get(v, offset);
          offset += 4;

          for (var i = 0; i < commentListLength; i++) {
            var len = strtok.UINT32_LE.get(v, offset);
            offset += 4;
            var comment = v.toString('utf8', offset, offset += len);
            var split = comment.split('=');
            self.emit(split[0].toUpperCase(), split[1]);
          }
        }
        if (cb.blockHeader.block_type === 6) {
          var picture = common.readVorbisPicture(v);
          self.emit('METADATA_BLOCK_PICTURE', picture);
        }

        cb.position = 'METADATA_BLOCK_HEADER';
        return new strtok.BufferType(4);
      }

    } catch (exception) {
      self.emit('done', exception);
      return strtok.DONE;
    }
  });
};<commit_msg>#18 handling last data block of FLAC files - refactored implementation of flac.js to use State pattern - extracted DataDecoder helper for reading block<commit_after>/* jshint node:true, sub:true, globalstrict:true */
"use strict";

var util = require('util');
var events = require('events');
var strtok = require('strtok');
var common = require('./common');

var DataDecoder = function(data) {
  this.data = data;
  this.offset = 0;
};

DataDecoder.prototype.readInt32 = function() {
  var value = strtok.UINT32_LE.get(this.data, this.offset);

  this.offset += 4;

  return value;
};

DataDecoder.prototype.readStringUtf8 = function() {
  var len = this.readInt32();
  var value = this.data.toString('utf8', this.offset, this.offset + len);

  this.offset += len;

  return value;
};

var finishedState = {
  parse: function(context) {
    return this;
  },
  getExpectedType: function() {
    return strtok.DONE;
  }
};

var BlockDataState = function(type, length, nextStateFactory) {
  this.type = type;
  this.length = length;
  this.nextStateFactory = nextStateFactory;
};

BlockDataState.prototype.parse = function(context, data) {
  if (this.type === 4) {
    var decoder = new DataDecoder(data);
    var vendorString = decoder.readStringUtf8();
    var commentListLength = decoder.readInt32();
    var comment;
    var split;
    var i;

    for (i = 0; i < commentListLength; i++) {
      comment = decoder.readStringUtf8();
      split = comment.split('=');
      context.emit(split[0].toUpperCase(), split[1]);
    }
  } else if (this.type === 6) {
    var picture = common.readVorbisPicture(data);
    context.emit('METADATA_BLOCK_PICTURE', picture);
  }

  return this.nextStateFactory();
};

BlockDataState.prototype.getExpectedType = function() {
  return new strtok.BufferType(this.length);
};

var blockHeaderState = {
  parse: function(context, data) {
    var header = {
      lastBlock: (data[0] & 0x80) == 0x80,
      type: data[0] & 0x7f,
      length: strtok.UINT24_BE.get(data, 1)
    };
    var followingStateFactory = header.lastBlock ? function() {
        context.emit('done');
        return finishedState;
      } : function() {
        return blockHeaderState;
      };

    return new BlockDataState(header.type, header.length, followingStateFactory);
  },
  getExpectedType: function() {
    return new strtok.BufferType(4);
  }
};

var idState = {
  parse: function(context, data) {
    if (data !== 'fLaC') {
      throw new Error('expected flac header but was not found');
    }

    return blockHeaderState;
  },
  getExpectedType: function() {
    return new strtok.StringType(4);
  }
};

var startState = {
  parse: function(context) {
    return idState;
  },
  getExpectedType: function() {
    return strtok.DONE;
  }
};

var Flac = module.exports = function(stream) {
  events.EventEmitter.call(this);
  this.stream = stream;

  this.currentState = startState;

  this.parse();
};

util.inherits(Flac, events.EventEmitter);

Flac.prototype.parse = function() {
  var self = this;

  strtok.parse(self.stream, function(v, cb) {
    try {
      self.currentState = self.currentState.parse(self, v);
    } catch (exception) {
      self.currentState = finishedState;
      self.emit('done', exception);
    }
    return self.currentState.getExpectedType();
  });
};<|endoftext|>


<commit_before>var validator = require("validator"),
    object = require("object-additions").object;

/*!
 * Express - Form
 * Copyright(c) 2010 Dan Dean <me@dandean.com>
 * MIT Licensed
 */

/**
 * camelize(str): -> String
 * - str (String): The string to make camel-case.
 *
 * Converts dash-separated words into camelCase words. Cribbed from Prototype.js.
 *
 *    field-name -> fieldName
 *    -field-name -> FieldName
**/
function camelize(str) {
  return (str || "").replace(/-+(.)?/g, function(match, chr) {
    return chr ? chr.toUpperCase() : '';
  });
}

var Filter = require("./filter");
var Validator = require("./validator");

var dataSources = ["body", "query", "params"],
    autoLocals = true,
    flashErrors = true,
    SUPPORTS_REQUEST_FLASH = undefined; // Might not if used outside Express.

function form() {
  var routines = Array.prototype.slice.call(arguments);

  return function(req, res, next) {
    if (undefined === SUPPORTS_REQUEST_FLASH) {
      SUPPORTS_REQUEST_FLASH = "flash" in req && object.isFunction(req.flash);
    }

    if (!req.form) {
      req.form = {};
    }

    dataSources.forEach(function(source) {
      if (req[source] && !object.isString(req[source])) {
        Object.keys(req[source]).forEach(function(name) {
          if (autoLocals) {
            if (!res.locals) res.locals = {};
            // Make all params locals, so they're accessible from the view.
            // If they have dashes in their names, camelize them so they don't
            // break ejs: <%= field-name %> becomes <%= fieldName %> in your views.
            res.locals[camelize(name)] = req[source][name];
          }

          // Copy data as is from source to the form object.
          req.form[name] = req[source][name];
        });
      }
    });

    var map = {};
    var flashed = {};

    Object.defineProperties(req.form, {
      "errors": {
        value: [],
        enumerable: false
      },
      "getErrors": {
        value: function(name) {
          return map[name] || [];
        },
        enumerable: false
      },
      "isValid": {
        get: function() {
          return this.errors.length == 0;
        },
        enumerable: false
      },
      "flashErrors": {
        value: function() {
          if (!SUPPORTS_REQUEST_FLASH || !flashErrors) return;
          this.errors.forEach(function(error) {
            if (!flashed[error]) {
              flashed[error] = true;
              req.flash("error", error);
            }
          });
        },
        enumerable: false
      }
    });

    routines.forEach(function(routine) {
      var result = routine.run(req.form);

      if (Array.isArray(result) && result.length) {
        var errors = req.form.errors = req.form.errors || [],
            name = routine.name;

        map[name] = map[name] || [];

        result.forEach(function(error) {
          errors.push(error);
          map[name].push(error);
        });
      }
    });

    if (next) next();
  };
}

form.filter = function(fieldname) {
  return new Filter(fieldname);
};

form.validate = function(fieldname, label) {
  return new Validator(fieldname, label);
};

Object.defineProperty(form, "validator", {
  get: function() {
    console.log("WARNING: `validator()` is deprecated and will be removed soon. Use `validate()` instead.");
    return form.validate;
  }
});

form.configure = function(options) {
  if (options) {
    if ("dataSources" in options) {
      dataSources = [];
      var sources = options.dataSources;
      if (object.isString(sources)) {
        dataSources.push(sources);
      } else if (Array.isArray(sources)) {
        sources.forEach(function(source) { dataSources.push(source); });
      }
    }

    if ("autoLocals" in options) {
      autoLocals = !!options.autoLocals;
    }

    if ("flashErrors" in options) {
      flashErrors = !!options.flashErrors;
    }
  }
  return this;
};

module.exports = form;
<commit_msg>Only put params from the body into the locals object.<commit_after>var validator = require("validator"),
    object = require("object-additions").object;

/*!
 * Express - Form
 * Copyright(c) 2010 Dan Dean <me@dandean.com>
 * MIT Licensed
 */

/**
 * camelize(str): -> String
 * - str (String): The string to make camel-case.
 *
 * Converts dash-separated words into camelCase words. Cribbed from Prototype.js.
 *
 *    field-name -> fieldName
 *    -field-name -> FieldName
**/
function camelize(str) {
  return (str || "").replace(/-+(.)?/g, function(match, chr) {
    return chr ? chr.toUpperCase() : '';
  });
}

var Filter = require("./filter");
var Validator = require("./validator");

var dataSources = ["body", "query", "params"],
    autoLocals = true,
    flashErrors = true,
    SUPPORTS_REQUEST_FLASH = undefined; // Might not if used outside Express.

function form() {
  var routines = Array.prototype.slice.call(arguments);

  return function(req, res, next) {
    if (undefined === SUPPORTS_REQUEST_FLASH) {
      SUPPORTS_REQUEST_FLASH = "flash" in req && object.isFunction(req.flash);
    }

    if (!req.form) {
      req.form = {};
    }

    dataSources.forEach(function(source) {
      if (req[source] && !object.isString(req[source])) {
        Object.keys(req[source]).forEach(function(name) {
          if (autoLocals && source == "body") {
            if (!res.locals) res.locals = {};
            // Make all params locals, so they're accessible from the view.
            // If they have dashes in their names, camelize them so they don't
            // break ejs: <%= field-name %> becomes <%= fieldName %> in your views.
            res.locals[camelize(name)] = req[source][name];
          }

          // Copy data as is from source to the form object.
          req.form[name] = req[source][name];
        });
      }
    });

    var map = {};
    var flashed = {};

    Object.defineProperties(req.form, {
      "errors": {
        value: [],
        enumerable: false
      },
      "getErrors": {
        value: function(name) {
          return map[name] || [];
        },
        enumerable: false
      },
      "isValid": {
        get: function() {
          return this.errors.length == 0;
        },
        enumerable: false
      },
      "flashErrors": {
        value: function() {
          if (!SUPPORTS_REQUEST_FLASH || !flashErrors) return;
          this.errors.forEach(function(error) {
            if (!flashed[error]) {
              flashed[error] = true;
              req.flash("error", error);
            }
          });
        },
        enumerable: false
      }
    });

    routines.forEach(function(routine) {
      var result = routine.run(req.form);

      if (Array.isArray(result) && result.length) {
        var errors = req.form.errors = req.form.errors || [],
            name = routine.name;

        map[name] = map[name] || [];

        result.forEach(function(error) {
          errors.push(error);
          map[name].push(error);
        });
      }
    });

    if (next) next();
  };
}

form.filter = function(fieldname) {
  return new Filter(fieldname);
};

form.validate = function(fieldname, label) {
  return new Validator(fieldname, label);
};

Object.defineProperty(form, "validator", {
  get: function() {
    console.log("WARNING: `validator()` is deprecated and will be removed soon. Use `validate()` instead.");
    return form.validate;
  }
});

form.configure = function(options) {
  if (options) {
    if ("dataSources" in options) {
      dataSources = [];
      var sources = options.dataSources;
      if (object.isString(sources)) {
        dataSources.push(sources);
      } else if (Array.isArray(sources)) {
        sources.forEach(function(source) { dataSources.push(source); });
      }
    }

    if ("autoLocals" in options) {
      autoLocals = !!options.autoLocals;
    }

    if ("flashErrors" in options) {
      flashErrors = !!options.flashErrors;
    }
  }
  return this;
};

module.exports = form;
<|endoftext|>


<commit_before>module.exports = function (grunt) {
    "use strict";

    var environment = grunt.option('environment') || 'development';

    switch (environment) {
        case 'production':
            break;
        case 'development':
            break;
        default:
            console.log('Could not map environment `' + environment + '`');
            console.log('Defaulting to `development`');
            environment = 'development';
            break;
    }
    process.env.ANGULAR_ENV = environment;

    grunt.task.loadNpmTasks('grunt-contrib-clean');
    grunt.task.loadNpmTasks('grunt-broccoli');
    grunt.task.loadNpmTasks('grunt-bump');
    grunt.task.loadNpmTasks('grunt-exec');
    grunt.task.loadNpmTasks('grunt-express-server');

    grunt.initConfig({
        config: {
            destDir: 'dist/'
        },
        clean: {
            options : { force: true },
            dist    : [ '<%= config.destDir %>' ],
            tmp     : [ 'tmp' ]
        },
        broccoli: {
            dist: {
                dest: '<%= config.destDir %>',
            }
        },
        bump: {
            options: {
                files         : [ 'bower.json', 'package.json' ],
                commitFiles   : [ 'bower.json', 'package.json' ],
                commitMessage : 'Bumped version to: %VERSION%',
                createTag     : false,
                push          : false,

            }
        },
        exec: {
            updateWebdriver: {
                cmd: 'npm run update-webdriver'
            },
            broccoliTest: {
                cmd: 'npm test'
            }
        },
        express: {
            options: {
                port   : 4200,
                script : 'node_modules/angular-bro-app/lib/server.js'
            },
            e2e: {
                options: {
                    background: true
                }
            },
            server: {
                options: {
                    background: false,
                }
            }
        }
    });

    grunt.registerTask('default', 'Builds the angular app.', 'build');

    grunt.registerTask('build', 'Builds the angular app', 'broccoli:dist:build');

    grunt.registerTask('serve', 'Builds and launches a server for the app.', 'server');
    grunt.registerTask('server', 'Builds and launches a server for the app.', function () {
        process.env.ANGULAR_SERVER   = true;
        process.env.ANGULAR_DEST_DIR = grunt.config('config').destDir;

        grunt.task.run([
            'clean',
            'express:server'
        ]);
    });

    grunt.registerTask('test', 'Builds and runs unit tests.', function () {
        var broccoliType = 'build';

        process.env.ANGULAR_TEST = true;

        if (!!grunt.option('server')) {
            broccoliType = 'server';
            process.env.ANGULAR_SERVER = true;
        }

        grunt.task.run(broccoliType);
    });
};
<commit_msg>Updated Scaffolded Gruntfile. - Added pre/post hooks to build and server tasks - Added documentation for each grun task<commit_after>module.exports = function (grunt) {
    "use strict";

    var environment = grunt.option('environment') || 'development';

    switch (environment) {
        case 'production':
            break;
        case 'development':
            break;
        case 'test':
            break;
        default:
            console.log('Could not map environment `' + environment + '`');
            console.log('Defaulting to `development`');
            environment = 'development';
            break;
    }
    process.env.ANGULAR_ENV = environment;

    grunt.task.loadNpmTasks('grunt-contrib-clean');
    grunt.task.loadNpmTasks('grunt-broccoli');
    grunt.task.loadNpmTasks('grunt-bump');
    grunt.task.loadNpmTasks('grunt-exec');
    grunt.task.loadNpmTasks('grunt-express-server');

    grunt.initConfig({
        config: {
            destDir: 'dist/'
        },
        clean: {
            options : { force: true },
            dist    : [ '<%= config.destDir %>' ],
            tmp     : [ 'tmp' ]
        },
        broccoli: {
            dist: {
                dest: '<%= config.destDir %>',
            }
        },
        bump: {
            options: {
                files         : [ 'bower.json', 'package.json' ],
                commitFiles   : [ 'bower.json', 'package.json' ],
                commitMessage : 'Bumped version to: %VERSION%',
                createTag     : false,
                push          : false,

            }
        },
        exec: {
            updateWebdriver: {
                cmd: 'npm run update-webdriver'
            },
            broccoliTest: {
                cmd: 'npm test'
            }
        },
        express: {
            options: {
                port   : 4200,
                script : 'node_modules/angular-bro-app/lib/server.js'
            },
            e2e: {
                options: {
                    background: true
                }
            },
            server: {
                options: {
                    background: false,
                }
            }
        }
    });

    grunt.registerTask('default', 'Builds the angular app.', 'build');

    /**
     * Anything that is required for the app to be built should happen here.
     */
    grunt.registerTask('prebuild', 'Preps the environment for the build.', [
        'clean'
    ]);

    /**
     * Build routine with pre and post hooks. Any modifications should happen in either the
     * `prebuild` or `postbuild` tasks.
     */
    grunt.registerTask('build', 'Builds the angular app.', [
        'prebuild',
        'broccoli:dist:build',
        'postbuild'
    ]);

    /**
     * Anything that is required for the app to be served / deployed should happen here.
     */
    grunt.registerTask('postbuild', 'Post processing of the built angular app.', [
    ]);

    /**
     * Anything that is required for the app to be built and served should happen here.
     */
    grunt.registerTask('preserver', 'Prepwork for the server.', [
        'prebuild'
    ]);

    /**
     * Server routine with pre hooks. Any modifications should happen in the `preserver` task.
     * NOTE: There is not post hook as the last task is a forever running task, and any future
     * task wouldn't ever be run.
     */
    grunt.registerTask('serve',  'Builds and launches a server for the app.', 'server');
    grunt.registerTask('server', 'Builds and launches a server for the app.', function () {
        process.env.ANGULAR_SERVER   = true;
        process.env.ANGULAR_DEST_DIR = grunt.config('config').destDir;

        grunt.task.run([
            'preserver',
            'express:server'
        ]);
    });

    /**
     * Test prepwork goes here. In general you shouldn't need to modify this task, but rather update
     * the `prebuild` step.
     */
    grunt.registerTask('test', 'Builds and runs unit tests.', function () {
        var broccoliType = 'build';

        process.env.ANGULAR_TEST = true;
        process.env.ANGULAR_ENV  = 'test';

        if (!!grunt.option('server')) {
            broccoliType = 'server';
            process.env.ANGULAR_SERVER = true;
        }

        grunt.task.run(broccoliType);
    });
};
<|endoftext|>


<commit_before>const fs = require('fs');
const execSync = require('child_process').execSync;
const { tag, push } = require('semantic-release/lib/git');
const getGitAuthUrl = require('semantic-release/lib/get-git-auth-url');

/**
 A semantic release "publish" plugin to create tags and run `elm-package publish`.
 */
async function tagElmRelease(config, context) {
  function exec(command) {
    context.logger.log(`Running: ${command}`);
    execSync(command);
  }

  const elmPackageJson = JSON.parse(fs.readFileSync('elm-package.json'));
  await tag(elmPackageJson.version);
  const repositoryUrl = await getGitAuthUrl(config);
  await push(repositoryUrl, config.branch);

  exec(`elm-package publish`);

  return true;
}

module.exports = tagElmRelease;
<commit_msg>fix(ci): Fix semantic-release plugin<commit_after>const fs = require('fs');
const execSync = require('child_process').execSync;
const { tag, push } = require('semantic-release/lib/git');
const getGitAuthUrl = require('semantic-release/lib/get-git-auth-url');

/**
 A semantic release "publish" plugin to create tags and run `elm-package publish`.
 */
async function tagElmRelease(config, context) {
  function exec(command) {
    context.logger.log(`Running: ${command}`);
    execSync(command);
  }

  const elmPackageJson = JSON.parse(fs.readFileSync('elm-package.json'));
  await tag(elmPackageJson.version);
  const repositoryUrl = await getGitAuthUrl(config);
  await push(repositoryUrl, config.branch);

  exec(`elm-package publish`);

  return {
    name: 'Elm release',
    url:
      'http://package.elm-lang.org/packages/cultureamp/elm-css-modules-loader/' +
      elmPackageJson.version,
  };
}

module.exports = tagElmRelease;
<|endoftext|>


<commit_before>/*
 * gith
 * https://github.com/danheberden/gith
 *
 * Copyright (c) 2012 Dan Heberden
 * Licensed under the MIT license.
 */

var http = require("http");
var EventEmitter2 = require( "eventemitter2" ).EventEmitter2;
var util = require("util");
var _ = require("lodash");

var filterSettings = function( settings, payload ) {

  if ( !payload ) {
    return false;
  }

  settings = settings || {};

  // add the matches object for later
  payload.matches = {};

  // check all the things
  var checksPassed = true;

  [ 'repo', 'branch', 'file', 'tag' ].forEach( function( thing ) {
    var wat = settings[ thing ];

    // default to a passed state
    var passed = true;

    // was a filter specified? and is it not a wildcard?
    if ( wat && wat !== '*' ) {

      // checking, so default passed to false
      passed = false;

      // make an array of the thing or all the files
      var checks = [].concat( thing === 'file' ? payload.files.all : payload[ thing ] );

      // all the checks - did any of them pass?
      passed = checks.some( function( check ) {

         // direct match
        if ( wat === check ) {
          return true;
        }

        // if negated match (!string)
        if ( _.isString( wat ) && wat[0] === "!" &&
              wat.slice(1) !== check ) {
          return true;
        }

        // regex?
        if ( _.isRegExp( wat ) ) {
          var match = check.match( wat );

          // did it match? huh? did it?
          if ( match ) {
            // goddamn files being different
            if ( thing === 'file' ) {
              if ( !payload.matches.files ) {
                payload.matches.files = {};
              }
              payload.matches.files[ check ] = match;
            } else {
              payload.matches[ thing ] = match;
            }

            return true;
          }
        }
      });

      // usr function?
      if ( _.isFunction( wat ) ) {
        passed = wat( payload[ thing ], payload );
      }

      // assign the final result of this 'thing' to checksPassed
      checksPassed = passed;
    }
  });

  return checksPassed;
};

var Gith = function( eventaur, settings ) {
  var gith = this;
  this.settings = settings || {};

  // make this bad boy an event emitter
  EventEmitter2.call( this, {
    wildcard: true,
    delimiter: ':',
    maxListeners: 0
  });

  // handle bound payloads
  eventaur.on( 'payload', function( originalPayload ) {

    // make a simpler payload
    var payload = gith.simplifyPayload( originalPayload );

    // bother doing anything?
    if ( filterSettings( settings, payload ) ) {

      // all the things
      gith.emit( 'all', payload );

      // did we do any branch work?
      if ( originalPayload.created && originalPayload.forced && payload.branch ) {
        gith.emit( 'branch:add', payload );
      }
      if (  originalPayload.deleted && originalPayload.forced && payload.branch ) {
        gith.emit( 'branch:delete', payload );
      }

      // how about files?
      if ( payload.files.added.length > 0 ) {
        gith.emit( 'file:add', payload );
      }
      if ( payload.files.deleted.length > 0 ) {
        gith.emit( 'file:delete', payload );
      }
      if ( payload.files.modified.length > 0 ) {
        gith.emit( 'file:modify', payload );
      }
      if ( payload.files.all.length > 0 ) {
        gith.emit( 'file:all', payload );
      }

      // tagging?
      if ( payload.tag && originalPayload.created ) {
        gith.emit( 'tag:add', payload );
      }
      if ( payload.tag && originalPayload.deleted ) {
        gith.emit( 'tag:delete', payload );
      }

    }

  });
};

// inherit the EventEmitter2 stuff
util.inherits( Gith, EventEmitter2 );

Gith.prototype.simplifyPayload = function( payload ) {
  var branch = '';
  var tag = '';

  // break out if it was a tag or branch and assign
  var refMatches = ( payload.ref || "" ).match( /refs\/(tags|heads)\/(.*)$/ );
  if ( refMatches ) {
    if ( refMatches[1] === "heads" ) {
      branch = refMatches[2];
    }
    if ( refMatches[1] === "tags" ) {
      tag = refMatches[2];
    }
  }

  var simpler = {
    original: payload,
    files: {
      all: [],
      added: [],
      deleted: [],
      modified: []
    },
    tag: tag,
    branch: branch,
    repo: payload.repository.owner.name + '/' + payload.repository.name,
    sha: payload.after,
    time: payload.repository.pushed_at,
    urls: {
      head: payload.head_commit ? payload.head_commit.url : '',
      branch: '',
      tag: '',
      repo: payload.repository.url,
      compare: payload.compare
    },
    reset: !payload.created && payload.forced,
    pusher: payload.pusher.name,
    owner: payload.repository.owner.name
  };

  if ( branch ) {
    simpler.urls.branch = simpler.urls.branch + '/tree/' + branch;
  }
  if ( tag ) {
    simpler.urls.tag = simpler.urls.head;
  }

  // populate files for every commit
  payload.commits.forEach( function( commit ) {
    // github label and simpler label ( make 'removed' deleted to be consistant )
    _.each( { added: 'added', modified: 'modified', removed: 'deleted' }, function( s, g ) {
      simpler.files[ s ] = simpler.files[ s ].concat( commit[ g ] );
      simpler.files.all = simpler.files.all.concat( commit[ g ] );
    });
  });

  return simpler;
  // todo: use github api to find what files were removed if the
  // head was reset? maybe?
};

// the listen method - this gets added/bound in
// module.exports.create, fyi
var listen = function( eventaur, port ) {
  // are we changing ports?
  if ( port ) {
    this.port = port;
  }
  if ( !this.port ) {
    throw new Error('.listen() requires a port to be set');
  }

  this.server = http.createServer( function( req, res ) {
    var data = "";
    if ( req.method === "POST" ) {
      req.on( "data", function( chunk ) {
        data += chunk;
      });
    }

    req.on( "end", function() {
      if ( /^payload=/.test( data ) ) {
        var payload = JSON.parse( data.slice(8) );
        eventaur.emit( "payload", payload );
      }
      res.end();
    });

    res.writeHead( 200, {
      'Content-type': 'text/html'
    });
    res.end();
  }).listen( port );
};

// make require('gith')( 9001 ) work if someone really wants to
module.exports = function( port ) {
  return module.exports.create( port );
};

// make the preferred way of `require('gith').create( 9001 ) work
module.exports.create = function( port ) {

  // make an event emitter to use for the hardcore stuff
  var eventaur = new EventEmitter2({
    wildcard: true,
    delimter: ':',
    maxListeners: 0
  });

  // return a function that
  //   a) holds its own server/port/whatever
  //   b) exposes a listen method
  //   c) is a function that returns a new Gith object
  //   d) emits global events for things like 'payload'
  var ret = function( map ) {
    // make a new Gith with a reference to this factory
    return new Gith( eventaur, map );
  };

  // add the listen method to the function - bind to ret
  // and send eventaur to it
  ret.listen = listen.bind( ret, eventaur );

  // expose ability to close http server
  ret.close = function(){
    this.server.close();
  };

  ret.payload = function( payload ) {
   eventaur.emit( 'payload', payload );
  };

  // if create was sent port, call listen automatically
  if ( port ) {
    ret.listen( port );
  }

  // return the new function
  return ret;
};
<commit_msg>remove wildcard setting from EE2 and add some comments<commit_after>/*
 * gith
 * https://github.com/danheberden/gith
 *
 * Copyright (c) 2012 Dan Heberden
 * Licensed under the MIT license.
 */

var http = require("http");
var EventEmitter2 = require( "eventemitter2" ).EventEmitter2;
var util = require("util");
var _ = require("lodash");

var filterSettings = function( settings, payload ) {

  if ( !payload ) {
    return false;
  }

  settings = settings || {};

  // add the matches object for later
  payload.matches = {};

  // check all the things
  var checksPassed = true;

  [ 'repo', 'branch', 'file', 'tag' ].forEach( function( thing ) {
    var wat = settings[ thing ];

    // default to a passed state
    var passed = true;

    // was a filter specified? and is it not a wildcard?
    if ( wat && wat !== '*' ) {

      // checking, so default passed to false
      passed = false;

      // make an array of the thing or all the files
      var checks = [].concat( thing === 'file' ? payload.files.all : payload[ thing ] );

      // all the checks - did any of them pass?
      passed = checks.some( function( check ) {

         // direct match
        if ( wat === check ) {
          return true;
        }

        // if negated match (!string)
        if ( _.isString( wat ) && wat[0] === "!" &&
              wat.slice(1) !== check ) {
          return true;
        }

        // regex?
        if ( _.isRegExp( wat ) ) {
          var match = check.match( wat );

          // did it match? huh? did it?
          if ( match ) {
            // goddamn files being different
            if ( thing === 'file' ) {
              if ( !payload.matches.files ) {
                payload.matches.files = {};
              }
              payload.matches.files[ check ] = match;
            } else {
              payload.matches[ thing ] = match;
            }

            return true;
          }
        }
      });

      // usr function?
      if ( _.isFunction( wat ) ) {
        passed = wat( payload[ thing ], payload );
      }

      // assign the final result of this 'thing' to checksPassed
      checksPassed = passed;
    }
  });

  return checksPassed;
};

// Used by exports.module.create's returned function to create
// new gith objects that hold settings and emit events
var Gith = function( eventaur, settings ) {
  var gith = this;
  this.settings = settings || {};

  // make this bad boy an event emitter
  EventEmitter2.call( this, {
    delimiter: ':',
    maxListeners: 0
  });

  // handle bound payloads
  eventaur.on( 'payload', function( originalPayload ) {

    // make a simpler payload
    var payload = gith.simplifyPayload( originalPayload );

    // bother doing anything?
    if ( filterSettings( settings, payload ) ) {

      // all the things
      gith.emit( 'all', payload );

      // did we do any branch work?
      if ( originalPayload.created && originalPayload.forced && payload.branch ) {
        gith.emit( 'branch:add', payload );
      }
      if (  originalPayload.deleted && originalPayload.forced && payload.branch ) {
        gith.emit( 'branch:delete', payload );
      }

      // how about files?
      if ( payload.files.added.length > 0 ) {
        gith.emit( 'file:add', payload );
      }
      if ( payload.files.deleted.length > 0 ) {
        gith.emit( 'file:delete', payload );
      }
      if ( payload.files.modified.length > 0 ) {
        gith.emit( 'file:modify', payload );
      }
      if ( payload.files.all.length > 0 ) {
        gith.emit( 'file:all', payload );
      }

      // tagging?
      if ( payload.tag && originalPayload.created ) {
        gith.emit( 'tag:add', payload );
      }
      if ( payload.tag && originalPayload.deleted ) {
        gith.emit( 'tag:delete', payload );
      }
    }
  });
};

// inherit the EventEmitter2 stuff
util.inherits( Gith, EventEmitter2 );

// expose the simpliyPayload method on gith()
Gith.prototype.simplifyPayload = function( payload ) {
  var branch = '';
  var tag = '';

  // break out if it was a tag or branch and assign
  var refMatches = ( payload.ref || "" ).match( /refs\/(tags|heads)\/(.*)$/ );
  if ( refMatches ) {
    if ( refMatches[1] === "heads" ) {
      branch = refMatches[2];
    }
    if ( refMatches[1] === "tags" ) {
      tag = refMatches[2];
    }
  }

  var simpler = {
    original: payload,
    files: {
      all: [],
      added: [],
      deleted: [],
      modified: []
    },
    tag: tag,
    branch: branch,
    repo: payload.repository.owner.name + '/' + payload.repository.name,
    sha: payload.after,
    time: payload.repository.pushed_at,
    urls: {
      head: payload.head_commit ? payload.head_commit.url : '',
      branch: '',
      tag: '',
      repo: payload.repository.url,
      compare: payload.compare
    },
    reset: !payload.created && payload.forced,
    pusher: payload.pusher.name,
    owner: payload.repository.owner.name
  };

  if ( branch ) {
    simpler.urls.branch = simpler.urls.branch + '/tree/' + branch;
  }
  if ( tag ) {
    simpler.urls.tag = simpler.urls.head;
  }

  // populate files for every commit
  payload.commits.forEach( function( commit ) {
    // github label and simpler label ( make 'removed' deleted to be consistant )
    _.each( { added: 'added', modified: 'modified', removed: 'deleted' }, function( s, g ) {
      simpler.files[ s ] = simpler.files[ s ].concat( commit[ g ] );
      simpler.files.all = simpler.files.all.concat( commit[ g ] );
    });
  });

  return simpler;
  // todo: use github api to find what files were removed if the
  // head was reset? maybe?
};

// the listen method - this gets added/bound in
// module.exports.create, fyi
var listen = function( eventaur, port ) {
  // are we changing ports?
  if ( port ) {
    this.port = port;
  }
  if ( !this.port ) {
    throw new Error('.listen() requires a port to be set');
  }

  this.server = http.createServer( function( req, res ) {
    var data = "";
    if ( req.method === "POST" ) {
      req.on( "data", function( chunk ) {
        data += chunk;
      });
    }

    req.on( "end", function() {
      if ( /^payload=/.test( data ) ) {
        var payload = JSON.parse( data.slice(8) );
        eventaur.emit( "payload", payload );
      }
      res.end();
    });

    res.writeHead( 200, {
      'Content-type': 'text/html'
    });
    res.end();
  }).listen( port );
};

// make require('gith')( 9001 ) work if someone really wants to
module.exports = function( port ) {
  return module.exports.create( port );
};

// make the preferred way of `require('gith').create( 9001 ) work
module.exports.create = function( port ) {

  // make an event emitter to use for the hardcore stuff
  var eventaur = new EventEmitter2({
    delimter: ':',
    maxListeners: 0
  });

  // return a function that
  //   a) holds its own server/port/whatever
  //   b) exposes a listen method
  //   c) is a function that returns a new Gith object
  var ret = function( map ) {
    // make a new Gith with a reference to this factory
    return new Gith( eventaur, map );
  };

  // add the listen method to the function - bind to ret
  // and send eventaur to it
  ret.listen = listen.bind( ret, eventaur );

  // expose ability to close http server
  ret.close = function(){
    this.server.close();
  };

  ret.payload = function( payload ) {
   eventaur.emit( 'payload', payload );
  };

  // if create was sent port, call listen automatically
  if ( port ) {
    ret.listen( port );
  }

  // return the new function
  return ret;
};
<|endoftext|>


<commit_before>/*
 * Load required modules
 */
var path   = require('path'),
	fs     = require('fs'),
	marked = require('marked'),
	jade = require('jade'),
	exec  = require('child_process').exec;

/*
 * Scope variable to cache pages
 */
var pages = {};

/*
 * Setup module
 */
module.exports = new Glog();

function Glog() {};

/*
 * Function to handle loading of configs
 */
Glog.prototype.load_configs = function(cb) {

	// Set defaults
	var options = {
		blog_title : 'Glog Blog'
		},
		fn = this;

	fs.readFile(path.join('glog_config.json'), 'UTF-8', function(err, data) {
		if(err) {
			fn.handle_error('Could not load configuration file.  This should be named glog_config.json. Err: ' + err);
		}

		var configs = JSON.parse(data);

		// Check mandatory configs
		if(!configs.port) {
			fn.handle_error('port is not defined in glog_config.json.  This should be set to the port number you wish the blog to run on');
			process.exit();
		}

		if(!configs.blog_repository) {
			fn.handle_error('blog_repository is not defined in glog_config.json.  This should point to the git repository of the blog content');
			process.exit();
		}

		if(!configs.author) {
			fn.handle_error('author is not defined in glog_config.json.  This should be the default blog author');
			process.exit();
		}

		for(key in configs) {
			options[key] = configs[key];
		}

	cb(options);
	});

}

/*
 * Load the articles from disc and add them to an array
 */
Glog.prototype.load_articles = function(options, cb) {

	var articles = [],
		article_path = path.join('blog_repo', '/articles'),
		fn = this;

	console.log('Loading articles from ' + article_path);

	fs.readdir(article_path, function(err, files) {
		if(err) {
			fn.handle_error('Could not read articles directory.  Please make sure paths are set up correctly.  Err: ' + err);
		}

		// Remove incorrect extensions
		for(var i=0; i<files.length; i++) {
			if(path.extname(files[i]) !== '.txt') {
				console.log('Skipping file ' + files[i] + '  Incorrect extension');
				files.splice(i,1);
			}
		}

		for(var i=0; i<files.length; i++) {
			console.log('Reading file ' + files[i]);

			fs.readFile(path.join(article_path, files[i]), 'UTF-8', function(err, data) {
				if(err) {
					fn.handle_error('Error reading article.  Err: ' + err);
				}

				// Extract the header
				var parts = data.split('\n\n');
				var header = JSON.parse(parts[0]);
				parts.splice(0,1);
				var body = marked(parts.join('\n\n'));

				console.log('Read articles with headers: ');
				console.log(header);

				// Check mandatory fields
				if(!header.title) {
					fn.handle_error('Articles must have a title');
					cb(false);
					return;
				}

				if(!header.date) {
					fn.handle_error('Articles must have a date');
					cb(false);
					return;
				}

				// Extract date
				var date = new Date(header.date),
					year = date.getFullYear(),
					month = date.getMonth() + 1; // Month is + 1 as starts at 0

				// If month < 10 prepend a 0
				if(month < 10) {
					month = ['0', month].join('');
				}

				articles.push({
					'title'    : header.title,
					'author'   : header.author || options.author,
					'date'     : date,
					'date_str' : Glog.formatDate(date),
					'year'     : year,
					'month'    : month,
					'body'     : body,
					'url'      : [year, month, (header.url || header.title.replace(/\s/g, '-'))].join('/') + '/'
				});

				// If that was the last article then trigger the callback
				if(files.length === articles.length) {
					cb(articles);
				}

			});
		}
	});
}

/*
 * Render the entire blog and store pages in cache
 */
Glog.prototype.render_blog = function(options, articles) {

	var fn = this;

	fs.readFile(path.join('blog_repo', 'layout.jade'), 'UTF-8', function(err, data) {
		if(err) {
			fn.handle_error('Error loading layout.  Err: ' + err);
		}

		console.log('Compiling template for home page');
		var fn = jade.compile(data);

		pages['/'] = fn({
			'title'    : options.blog_title,
			'analytics_code' : options.analytics_code || null,
			'base_url' : options.base_url || '',
			'articles' : articles
		});

		console.log('Compiling template for individual pages');

		// Loop through articles and compile individual pages
		for(var i=0; i< articles.length; i++) {

			pages[articles[i].url] = fn({
				'title'          : options.blog_title,
				'articles'       : [articles[i]],
				'disqus_id'      : options.disqus_id || -1,
				'analytics_code' : options.analytics_code || null,
				'base_url' : options.base_url || '',
				'single'         : true
			});
		}
	});
};

/*
 * Handle a request for the home page
 */
Glog.prototype.req_home = function(req, res, next) {
	console.log('Home page requested');

	// Set headers
	res.setHeader('Content-Type', 'text/html; charset=utf-8');
	res.setHeader('Server', 'Glog (NodeJS)');
	res.end(pages['/']);
};

/*
 * Handle a request for an individual article
 */
Glog.prototype.req_article = function(req, res, next) {

	var fn = this,
		url = [req.params.year, req.params.month, req.params.article].join('/');

	console.log('Requesting ' + url);
	if(typeof pages[url] !== 'undefined') {
		// Set headers
		res.setHeader('Content-Type', 'text/html; charset=utf-8');
		res.setHeader('Server', 'Glog (NodeJS)');
		res.end(pages[url]);
	} else {
		// Set headers
		res.setHeader('Content-Type', 'text/html; charset=utf-8');
		res.setHeader('Server', 'Glog (NodeJS)');
		res.end(pages['/']);
	}
};

/*
 * Generic error handler
 */
Glog.prototype.handle_error = function(err) {
	console.error(err);
}

/*
 * Function to trigger a build of the entire site
 */
Glog.prototype.rebuild = function(cb) {
	var fn = this,
		next;

	fn.load_configs(function(options) {
		fn.update_repo(options, function() {
			fn.load_articles(options, function(articles) {
				articles = articles.sort(function(a,b) {
					return b.date - a.date;
				});
				fn.render_blog(options, articles);

				cb(options);
			});
		});
	});
};

/*
 * Clone a blog git repository
 */
Glog.prototype.get_repo = function(repo, cb) {

	var fn = this;

	// Attempt to clone the git repo
	console.log('Cloning git repository ' + repo);
	exec('git clone ' + repo + ' blog_repo', function(error, stdout, stderr) {
		if(error) {
			fn.handle_error('Could not clone git repository: ' + error);
		}
		console.log('Stdout: ' + stdout);
		console.log('Stderr: ' + stderr);

		cb();
	});
};

/*
 * Update git repository
 */
Glog.prototype.update_repo = function(options, cb) {

	var fn = this;

	// If repo does not exist, clone it
	fs.stat('blog_repo', function(err, stats) {
		if(err) {
			fn.handle_error(err);
		}

		if(err || !stats.isDirectory()) {
			fn.get_repo(options.blog_repository, cb);
		} else {

			console.log('Updating blog git repo');
			exec('cd blog_repo; git pull origin master', function(error, stdout, stderr) {
				if(err) {
					fn.handle_error('Could not update blog repo: ' + error);
				}
				console.log('Stdout: ' + stdout);
				console.log('Stderr: ' + stderr);

				cb();
			});
		}
	});
};

Glog.formatDate = function(date) {
	var days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
		months = ['January' , 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
		str;

	str = [days[date.getDay()], ', ', date.getDate(), ' ', months[date.getMonth()], ', ', date.getFullYear()].join('');

	return str;

};
<commit_msg>Reverting last commit<commit_after>/*
 * Load required modules
 */
var path   = require('path'),
	fs     = require('fs'),
	marked = require('marked'),
	jade = require('jade'),
	exec  = require('child_process').exec;

/*
 * Scope variable to cache pages
 */
var pages = {};

/*
 * Setup module
 */
module.exports = new Glog();

function Glog() {};

/*
 * Function to handle loading of configs
 */
Glog.prototype.load_configs = function(cb) {

	// Set defaults
	var options = {
		blog_title : 'Glog Blog'
		},
		fn = this;

	fs.readFile(path.join('glog_config.json'), 'UTF-8', function(err, data) {
		if(err) {
			fn.handle_error('Could not load configuration file.  This should be named glog_config.json. Err: ' + err);
		}

		var configs = JSON.parse(data);

		// Check mandatory configs
		if(!configs.port) {
			fn.handle_error('port is not defined in glog_config.json.  This should be set to the port number you wish the blog to run on');
			process.exit();
		}

		if(!configs.blog_repository) {
			fn.handle_error('blog_repository is not defined in glog_config.json.  This should point to the git repository of the blog content');
			process.exit();
		}

		if(!configs.author) {
			fn.handle_error('author is not defined in glog_config.json.  This should be the default blog author');
			process.exit();
		}

		for(key in configs) {
			options[key] = configs[key];
		}

	cb(options);
	});

}

/*
 * Load the articles from disc and add them to an array
 */
Glog.prototype.load_articles = function(options, cb) {

	var articles = [],
		article_path = path.join('blog_repo', '/articles'),
		fn = this;

	console.log('Loading articles from ' + article_path);

	fs.readdir(article_path, function(err, files) {
		if(err) {
			fn.handle_error('Could not read articles directory.  Please make sure paths are set up correctly.  Err: ' + err);
		}

		// Remove incorrect extensions
		for(var i=0; i<files.length; i++) {
			if(path.extname(files[i]) !== '.txt') {
				console.log('Skipping file ' + files[i] + '  Incorrect extension');
				files.splice(i,1);
			}
		}

		for(var i=0; i<files.length; i++) {
			console.log('Reading file ' + files[i]);

			fs.readFile(path.join(article_path, files[i]), 'UTF-8', function(err, data) {
				if(err) {
					fn.handle_error('Error reading article.  Err: ' + err);
				}

				// Extract the header
				var parts = data.split('\n\n');
				var header = JSON.parse(parts[0]);
				parts.splice(0,1);
				var body = marked(parts.join('\n\n'));

				console.log('Read articles with headers: ');
				console.log(header);

				// Check mandatory fields
				if(!header.title) {
					fn.handle_error('Articles must have a title');
					cb(false);
					return;
				}

				if(!header.date) {
					fn.handle_error('Articles must have a date');
					cb(false);
					return;
				}

				// Extract date
				var date = new Date(header.date),
					year = date.getFullYear(),
					month = date.getMonth() + 1; // Month is + 1 as starts at 0

				// If month < 10 prepend a 0
				if(month < 10) {
					month = ['0', month].join('');
				}

				articles.push({
					'title'    : header.title,
					'author'   : header.author || options.author,
					'date'     : date,
					'date_str' : Glog.formatDate(date),
					'year'     : year,
					'month'    : month,
					'body'     : body,
					'url'      : [year, month, (header.url || header.title.replace(/\s/g, '-'))].join('/')
				});

				// If that was the last article then trigger the callback
				if(files.length === articles.length) {
					cb(articles);
				}

			});
		}
	});
}

/*
 * Render the entire blog and store pages in cache
 */
Glog.prototype.render_blog = function(options, articles) {

	var fn = this;

	fs.readFile(path.join('blog_repo', 'layout.jade'), 'UTF-8', function(err, data) {
		if(err) {
			fn.handle_error('Error loading layout.  Err: ' + err);
		}

		console.log('Compiling template for home page');
		var fn = jade.compile(data);

		pages['/'] = fn({
			'title'    : options.blog_title,
			'analytics_code' : options.analytics_code || null,
			'base_url' : options.base_url || '',
			'articles' : articles
		});

		console.log('Compiling template for individual pages');

		// Loop through articles and compile individual pages
		for(var i=0; i< articles.length; i++) {

			pages[articles[i].url] = fn({
				'title'          : options.blog_title,
				'articles'       : [articles[i]],
				'disqus_id'      : options.disqus_id || -1,
				'analytics_code' : options.analytics_code || null,
				'base_url' : options.base_url || '',
				'single'         : true
			});
		}
	});
};

/*
 * Handle a request for the home page
 */
Glog.prototype.req_home = function(req, res, next) {
	console.log('Home page requested');

	// Set headers
	res.setHeader('Content-Type', 'text/html; charset=utf-8');
	res.setHeader('Server', 'Glog (NodeJS)');
	res.end(pages['/']);
};

/*
 * Handle a request for an individual article
 */
Glog.prototype.req_article = function(req, res, next) {

	var fn = this,
		url = [req.params.year, req.params.month, req.params.article].join('/');

	console.log('Requesting ' + url);
	if(typeof pages[url] !== 'undefined') {
		// Set headers
		res.setHeader('Content-Type', 'text/html; charset=utf-8');
		res.setHeader('Server', 'Glog (NodeJS)');
		res.end(pages[url]);
	} else {
		// Set headers
		res.setHeader('Content-Type', 'text/html; charset=utf-8');
		res.setHeader('Server', 'Glog (NodeJS)');
		res.end(pages['/']);
	}
};

/*
 * Generic error handler
 */
Glog.prototype.handle_error = function(err) {
	console.error(err);
}

/*
 * Function to trigger a build of the entire site
 */
Glog.prototype.rebuild = function(cb) {
	var fn = this,
		next;

	fn.load_configs(function(options) {
		fn.update_repo(options, function() {
			fn.load_articles(options, function(articles) {
				articles = articles.sort(function(a,b) {
					return b.date - a.date;
				});
				fn.render_blog(options, articles);

				cb(options);
			});
		});
	});
};

/*
 * Clone a blog git repository
 */
Glog.prototype.get_repo = function(repo, cb) {

	var fn = this;

	// Attempt to clone the git repo
	console.log('Cloning git repository ' + repo);
	exec('git clone ' + repo + ' blog_repo', function(error, stdout, stderr) {
		if(error) {
			fn.handle_error('Could not clone git repository: ' + error);
		}
		console.log('Stdout: ' + stdout);
		console.log('Stderr: ' + stderr);

		cb();
	});
};

/*
 * Update git repository
 */
Glog.prototype.update_repo = function(options, cb) {

	var fn = this;

	// If repo does not exist, clone it
	fs.stat('blog_repo', function(err, stats) {
		if(err) {
			fn.handle_error(err);
		}

		if(err || !stats.isDirectory()) {
			fn.get_repo(options.blog_repository, cb);
		} else {

			console.log('Updating blog git repo');
			exec('cd blog_repo; git pull origin master', function(error, stdout, stderr) {
				if(err) {
					fn.handle_error('Could not update blog repo: ' + error);
				}
				console.log('Stdout: ' + stdout);
				console.log('Stderr: ' + stderr);

				cb();
			});
		}
	});
};

Glog.formatDate = function(date) {
	var days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
		months = ['January' , 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
		str;

	str = [days[date.getDay()], ', ', date.getDate(), ' ', months[date.getMonth()], ', ', date.getFullYear()].join('');

	return str;

};
<|endoftext|>


<commit_before>var fs = require('fs');
var util = require('util');
var path = require('path');
var EventEmitter = require('events').EventEmitter;

var gpiopath = '/sys/class/gpio/';

var logError = function(e) { if(e) console.log(e.code, e.action, e.path); };
var logMessage = function() { if (exports.logging) console.log.apply(console, arguments) };

var _write = function(str, file, fn, override) {
	if(typeof fn !== "function") fn = logError;
	fs.writeFile(file, str, function(err) {
		if(err && !override) {
			err.path = file;
			err.action = 'write';
			logError(err);
		} else {
			if(typeof fn === "function") fn();
		}
	});
};
var _read = function(file, fn) {
	fs.readFile(file, "utf-8", function(err, data) {
		if(err) {
			err.path = file;
			err.action = 'read';
			logError(err);
		} else {
			if(typeof fn === "function") fn(data);
			else logMessage("value: ", data);
		}
	});
};

var _unexport = function(number, fn) {
	_write(number, gpiopath + 'unexport', function(err) {
		if(err) return logError(err);
		if(typeof fn === 'function') fn();
	}, 1);
};
var _export = function(n, fn) {
	if(path.exists(gpiopath + 'gpio'+n)) {
		// already exported, unexport and export again
		logMessage('Header already exported');
		_unexport(n, function() { _export(n, fn); });
	} else {
		logMessage('Exporting gpio' + n);
		_write(n, gpiopath + 'export', function(err) {
			// if there's an error when exporting, unexport and repeat
			if(err) _unexport(n, function() { _export(n, fn); });
			else if(typeof fn === 'function') fn();
		}, 1);
	}
};

// fs.watch doesn't get fired because the file never
// gets 'accessed' when setting header via hardware
// manually watching value changes
var FileWatcher = function(path, interval, fn) {
	if(typeof fn === 'undefined') {
		fn = interval;
		interval = 100;
	}
	if(typeof interval !== 'number') return false;
	if(typeof fn !== 'function') return false;

	var value;
	var readTimer = setInterval(function() {
		_read(path, function(val) {
			if(value !== val) {
				if(typeof value !== 'undefined') fn(val);
				value = val;
			}
		});
	}, interval);

	this.stop = function() { clearInterval(readTimer); };
};

var GPIO = function(headerNum, opts) {
	opts = opts || {};

	var self = this;
	var dir = opts.direction;
	var interval = opts.interval;
	if(typeof interval !== 'number') interval = 100;

	this.headerNum = headerNum;
	this.value = 0;

	this.PATH = {};
	this.PATH.PIN =       gpiopath + 'gpio' + headerNum + '/';
	this.PATH.VALUE =     this.PATH.PIN + 'value';
	this.PATH.DIRECTION = this.PATH.PIN + 'direction';

	this.export(function() {
		self.setDirection(dir);

		if(typeof opts.ready === 'function') opts.ready.call(self);

		// Watch changes to value only for 'in' direction since we manually trigger it
		// for 'out' direction when we set the value
		self.valueWatcher = new FileWatcher(self.PATH.VALUE, interval, function(val) {
			if(self.direction === 'in') {
				self.emit("valueChange", val);
				self.emit("change", val);
			}
		});
	});
};

util.inherits(GPIO, EventEmitter);

/**
 * Export and unexport gpio#, takes callback which fires when operation is completed
 */
GPIO.prototype.export = function(fn) { _export(this.headerNum, fn); };
GPIO.prototype.unexport = function(fn) { this.valueWatcher.stop(); _unexport(this.headerNum, fn); };

/**
 * Sets direction, default is "out"
 */
GPIO.prototype.setDirection = function(dir) {
	var self = this, path = this.PATH.DIRECTION;
	if(typeof dir !== "string" || dir !== "in") dir = "out";
	this.direction = dir;

	logMessage('Setting direction "' + dir + '" on gpio' + this.headerNum);
	_read(path, function(currDir) {
		if(dir === currDir) {
			logMessage('Current direction is already ' + dir);
		} else {
			_write(dir, path, function() {
				self.emit('directionChange', dir);
			}, 1);
		}
	});
};

/**
 * Internal getter, stores value
 */
GPIO.prototype._get = function(fn) {
	var self = this, currVal = this.value;

	if(this.direction === 'out') return currVal;

	_read(this.PATH.VALUE, function(val) {
		val = parseInt(val, 10);
		if(val !== currVal) {
			self.value = val;
			if(typeof fn === "function") fn.call(this, self.value);
		}
	});
};

/**
 * Sets the value. If v is specified as 0 or '0', reset will be called
 */
GPIO.prototype.set = function(v, fn) {
	var self = this;
	var callback = typeof v === 'function' ? v : fn;
	if(typeof v !== "number" || v !== 0) v = 1;

	// if direction is out, just emit change event since we can reliably predict
	// if the value has changed; we don't have to rely on watching a file
	if(this.direction === 'out') {
		if(this.value !== v) {
			_write(v, this.PATH.VALUE, function() {
				self.value = v;
				self.emit('valueChange', v);
				self.emit('change', v);
				if(typeof callback === 'function') callback();
			});
		}
	}
};
GPIO.prototype.reset = function(fn) { this.set(0, fn); };

exports.logging = false;
exports.export = function(headerNum, direction) { return new GPIO(headerNum, direction); };
exports.unexport = _unexport;

<commit_msg>use fs.exists if available<commit_after>var fs = require('fs');
var util = require('util');
var path = require('path');
var EventEmitter = require('events').EventEmitter;
var exists = fs.exists || path.exists;

var gpiopath = '/sys/class/gpio/';

var logError = function(e) { if(e) console.log(e.code, e.action, e.path); };
var logMessage = function() { if (exports.logging) console.log.apply(console, arguments) };

var _write = function(str, file, fn, override) {
	if(typeof fn !== "function") fn = logError;
	fs.writeFile(file, str, function(err) {
		if(err && !override) {
			err.path = file;
			err.action = 'write';
			logError(err);
		} else {
			if(typeof fn === "function") fn();
		}
	});
};
var _read = function(file, fn) {
	fs.readFile(file, "utf-8", function(err, data) {
		if(err) {
			err.path = file;
			err.action = 'read';
			logError(err);
		} else {
			if(typeof fn === "function") fn(data);
			else logMessage("value: ", data);
		}
	});
};

var _unexport = function(number, fn) {
	_write(number, gpiopath + 'unexport', function(err) {
		if(err) return logError(err);
		if(typeof fn === 'function') fn();
	}, 1);
};
var _export = function(n, fn) {
	if(exists(gpiopath + 'gpio'+n)) {
		// already exported, unexport and export again
		logMessage('Header already exported');
		_unexport(n, function() { _export(n, fn); });
	} else {
		logMessage('Exporting gpio' + n);
		_write(n, gpiopath + 'export', function(err) {
			// if there's an error when exporting, unexport and repeat
			if(err) _unexport(n, function() { _export(n, fn); });
			else if(typeof fn === 'function') fn();
		}, 1);
	}
};

// fs.watch doesn't get fired because the file never
// gets 'accessed' when setting header via hardware
// manually watching value changes
var FileWatcher = function(path, interval, fn) {
	if(typeof fn === 'undefined') {
		fn = interval;
		interval = 100;
	}
	if(typeof interval !== 'number') return false;
	if(typeof fn !== 'function') return false;

	var value;
	var readTimer = setInterval(function() {
		_read(path, function(val) {
			if(value !== val) {
				if(typeof value !== 'undefined') fn(val);
				value = val;
			}
		});
	}, interval);

	this.stop = function() { clearInterval(readTimer); };
};

var GPIO = function(headerNum, opts) {
	opts = opts || {};

	var self = this;
	var dir = opts.direction;
	var interval = opts.interval;
	if(typeof interval !== 'number') interval = 100;

	this.headerNum = headerNum;
	this.value = 0;

	this.PATH = {};
	this.PATH.PIN =       gpiopath + 'gpio' + headerNum + '/';
	this.PATH.VALUE =     this.PATH.PIN + 'value';
	this.PATH.DIRECTION = this.PATH.PIN + 'direction';

	this.export(function() {
		self.setDirection(dir);

		if(typeof opts.ready === 'function') opts.ready.call(self);

		// Watch changes to value only for 'in' direction since we manually trigger it
		// for 'out' direction when we set the value
		self.valueWatcher = new FileWatcher(self.PATH.VALUE, interval, function(val) {
			if(self.direction === 'in') {
				self.emit("valueChange", val);
				self.emit("change", val);
			}
		});
	});
};

util.inherits(GPIO, EventEmitter);

/**
 * Export and unexport gpio#, takes callback which fires when operation is completed
 */
GPIO.prototype.export = function(fn) { _export(this.headerNum, fn); };
GPIO.prototype.unexport = function(fn) { this.valueWatcher.stop(); _unexport(this.headerNum, fn); };

/**
 * Sets direction, default is "out"
 */
GPIO.prototype.setDirection = function(dir) {
	var self = this, path = this.PATH.DIRECTION;
	if(typeof dir !== "string" || dir !== "in") dir = "out";
	this.direction = dir;

	logMessage('Setting direction "' + dir + '" on gpio' + this.headerNum);
	_read(path, function(currDir) {
		if(dir === currDir) {
			logMessage('Current direction is already ' + dir);
		} else {
			_write(dir, path, function() {
				self.emit('directionChange', dir);
			}, 1);
		}
	});
};

/**
 * Internal getter, stores value
 */
GPIO.prototype._get = function(fn) {
	var self = this, currVal = this.value;

	if(this.direction === 'out') return currVal;

	_read(this.PATH.VALUE, function(val) {
		val = parseInt(val, 10);
		if(val !== currVal) {
			self.value = val;
			if(typeof fn === "function") fn.call(this, self.value);
		}
	});
};

/**
 * Sets the value. If v is specified as 0 or '0', reset will be called
 */
GPIO.prototype.set = function(v, fn) {
	var self = this;
	var callback = typeof v === 'function' ? v : fn;
	if(typeof v !== "number" || v !== 0) v = 1;

	// if direction is out, just emit change event since we can reliably predict
	// if the value has changed; we don't have to rely on watching a file
	if(this.direction === 'out') {
		if(this.value !== v) {
			_write(v, this.PATH.VALUE, function() {
				self.value = v;
				self.emit('valueChange', v);
				self.emit('change', v);
				if(typeof callback === 'function') callback();
			});
		}
	}
};
GPIO.prototype.reset = function(fn) { this.set(0, fn); };

exports.logging = false;
exports.export = function(headerNum, direction) { return new GPIO(headerNum, direction); };
exports.unexport = _unexport;

<|endoftext|>


<commit_before>var $ = require('jquery');
var Tile = require('../lib/tile.js');
var grid = new Grid();

function Grid(){
  this._length = 0;
  this.allTiles = [];
}

Grid.prototype.orient = function(){

  for (var i = 0; i < 16; i++) {
    this.allTiles.push(new Tile( null, i));
  }
  var array = this.allTiles;

  this.allTiles.forEach(function(t, i) {
    if ((t.position+1) % 4 !== 0) {
      t.right = array[i + 1];
    }
    if ((t.position % 4) !== 0) {
      t.left = array[i - 1];
    }
    if ((t.position+1) % 4 !==0) {
      t.above = array[i-4];
    }
    if ((t.position % 4) !==0) {
      t.below = array[i+4];
    }
  });

  this.allTiles = this.allTiles;
};

Grid.prototype.initGrid = function(){
  this.orient();
  this.allTiles[0].data = 4;
  this.allTiles[1].data = 2;
  this.allTiles[2].data = 2;
  this.allTiles[3].data = null;
  this.allTiles[4].data = 2;
  this.allTiles[5].data = null;
  this.allTiles[6].data = null;
  this.allTiles[7].data = 2;

  for (var i = 1; i < 17; i++) {
  $(`#c${i}`)[0].innerHTML = this.allTiles[i - 1].data;

  }
};

Grid.prototype.loadGrid = function (){
  this.orient();

// render
  for (var i = 1; i < 17; i++) {
    $(`#c${i}`)[0].innerHTML = this.allTiles[i - 1].data;
// TODO also need to iterate through, grab the values, and apply classes

  }
};

Grid.prototype.setHeads = function() {
  this.Lrow1 = this.allTiles[0];
  this.Rrow1 = this.allTiles[3];
  this.Lrow2 = this.allTiles[4];
  this.Rrow2 = this.allTiles[7];
  this.Lrow3 = this.allTiles[8];
  this.Rrow3 = this.allTiles[11];
  this.Lrow4 = this.allTiles[12];
  this.Rrow4 = this.allTiles[15];

  this.Ucolumn1 = this.allTiles[0];
  this.Dcolumn1 = this.allTiles[12];
  this.Ucolumn2 = this.allTiles[1];
  this.Dcolumn2 = this.allTiles[13];
  this.Ucolumn3 = this.allTiles[2];
  this.Dcolumn3 = this.allTiles[14];
  this.Ucolumn4 = this.allTiles[3];
  this.Dcolumn4 = this.allTiles[15];
};

Grid.prototype.rightRows = function(){
  var setRightRows =  [
  this.row1 = this.Rrow1,
  this.row2 = this.Rrow2,
  this.row3 = this.Rrow3,
  this.row4 = this.Rrow4,
  ];
  setRightRows.forEach(function(row){
    return grid.moveRight(row, 'left');
  });
};

Grid.prototype.leftRows = function(){
  var setLeftRows =  [
  this.row1 = this.Lrow1,
  this.row2 = this.Lrow2,
  this.row3 = this.Lrow3,
  this.row4 = this.Lrow4,
  ];
  setLeftRows.forEach(function(row){
   return grid.moveLeft(row);
  });
};

// TODO Generate Tile at Random position

Grid.prototype.moveRight = function(row, direction) {
  // tileWasSmushed
  row.compare = null;
  row[direction].compare = null;

  var pullTile = row;
  var compareTile = row[direction];

function multiply() {
  (pullTile.data *= 2);
  console.log('I have multiplied!');
  pullTile.compare = true; // the pull tile was multiplied (and by extension we know it shouldn't continue moving until the next move() is called/arrow is clicked)
}
function smush() {
  if (compareTile[direction]) {
    compareTile.data = compareTile[direction].data;
    // compareTile.compare = false///
    compareTile[direction].data = null;
  }
}

function nextTile() {
  // debugger
  pullTile = compareTile;
  compareTile = compareTile[direction];
}

  var i = 1;
  while (i > 0) {
    pullTile = row;
    compareTile = row[direction];
    i = 0;
    for(var t = 0; t < 3; t++) {
      var equalTiles = (pullTile.data === compareTile.data && pullTile.data !== null && !pullTile.compare ); ///
      if(pullTile.position === 7){
        // console.log("PullTile Position is 7 (meaning we are on row 2)! \n ---------- \n");
        if(!pullTile.compare === true){
          console.log("HOLY SHIT IT WORKED EVERYTHING IS BEAUTIFUL AND NOTHING HURT");
        }
      };

      var nullTiles = (compareTile.data === null);

      // console.log(compareTile.data)

// case equal
      if (equalTiles) {
        // debugger
        i++;

        multiply();

        smush();
      }

// TODO case pullTile null
      if (pullTile.data === null) {
        pullTile.data = compareTile.data;
        compareTile.data = null;

      }

// case null
          if(nullTiles){
            if(compareTile[direction]) {
              if(compareTile[direction].data !== null) {
                // console.log(i);
                // console.log(pullTile, "this is pullTile");
                // console.log('I will now increment i');
            //debugger
            i++;
            smush();
          }
        }
      }
      nextTile();
        // console.log(pullTile.position, "this is pullTile when nextTile ran");
    }
    console.log(this);
    // this.allTiles.forEach(function(tile) {
      // console.log('we set a tile to compare false');
      // tile.compare = null;
    // });
  }

  //     // inside case null case equal
  //       if (equalTiles) {
  //         multiply();
  //         smush();
  //       }
  //         // inside case null case null
  //       if (nullTiles){
  //         smush();
  //       }
   };

   // inside case null case equal
//       if (row.left.left.data = row.left.left.left.data){
//         row.left.left.data = row.left.left.left.data*2;
//         row.left.left.left.data = null;
//       }
//
// // inside case null case null
// if(row.left.data === null){
//   // function smush
//   row.left.data = row.left.left.data;
//   row.left.left.data = null;
//   //
//     if (row.left.left.data === row.left.left.left.data) {
//       row.left.left.data = row.left.left.left.data *2;
//     }
//     if (row.left.left.data === null){
//       row.left.left.data = row.left.left.left.data;
//       row.left.left.left.data = null;
//     }
// }

module.exports = Grid;
<commit_msg>WIP: fix move bugs<commit_after>var $ = require('jquery');
var Tile = require('../lib/tile.js');
var grid = new Grid();

function Grid(){
  this._length = 0;
  this.allTiles = [];
}

Grid.prototype.orient = function(){

  for (var i = 0; i < 16; i++) {
    this.allTiles.push(new Tile( null, i));
  }
  var array = this.allTiles;

  this.allTiles.forEach(function(t, i) {
    if ((t.position+1) % 4 !== 0) {
      t.right = array[i + 1];
    }
    if ((t.position % 4) !== 0) {
      t.left = array[i - 1];
    }
    if ((t.position+1) % 4 !==0) {
      t.above = array[i-4];
    }
    if ((t.position % 4) !==0) {
      t.below = array[i+4];
    }
  });

  this.allTiles = this.allTiles;
};

Grid.prototype.initGrid = function(){
  this.orient();
  this.allTiles[0].data = 4;
  this.allTiles[1].data = 2;
  this.allTiles[2].data = 2;
  this.allTiles[3].data = null;
  this.allTiles[4].data = 2;
  this.allTiles[5].data = null;
  this.allTiles[6].data = null;
  this.allTiles[7].data = 2;

  for (var i = 1; i < 17; i++) {
  $(`#c${i}`)[0].innerHTML = this.allTiles[i - 1].data;

  }
};

Grid.prototype.loadGrid = function (){
  this.orient();

// render
  for (var i = 1; i < 17; i++) {
    $(`#c${i}`)[0].innerHTML = this.allTiles[i - 1].data;
// TODO also need to iterate through, grab the values, and apply classes

  }
};

Grid.prototype.setHeads = function() {
  this.Lrow1 = this.allTiles[0];
  this.Rrow1 = this.allTiles[3];
  this.Lrow2 = this.allTiles[4];
  this.Rrow2 = this.allTiles[7];
  this.Lrow3 = this.allTiles[8];
  this.Rrow3 = this.allTiles[11];
  this.Lrow4 = this.allTiles[12];
  this.Rrow4 = this.allTiles[15];

  this.Ucolumn1 = this.allTiles[0];
  this.Dcolumn1 = this.allTiles[12];
  this.Ucolumn2 = this.allTiles[1];
  this.Dcolumn2 = this.allTiles[13];
  this.Ucolumn3 = this.allTiles[2];
  this.Dcolumn3 = this.allTiles[14];
  this.Ucolumn4 = this.allTiles[3];
  this.Dcolumn4 = this.allTiles[15];
};

Grid.prototype.rightRows = function(){
  var setRightRows =  [
  this.row1 = this.Rrow1,
  this.row2 = this.Rrow2,
  this.row3 = this.Rrow3,
  this.row4 = this.Rrow4,
  ];
  setRightRows.forEach(function(row){
    return grid.moveRight(row, 'left');
  });
};

Grid.prototype.leftRows = function(){
  var setLeftRows =  [
  this.row1 = this.Lrow1,
  this.row2 = this.Lrow2,
  this.row3 = this.Lrow3,
  this.row4 = this.Lrow4,
  ];
  setLeftRows.forEach(function(row){
   return grid.moveLeft(row);
  });
};

// TODO Generate Tile at Random position

Grid.prototype.moveRight = function(row, direction) {
  // tileWasSmushed
  row.compare = null;
  row[direction].compare = null;
  var pullTile = row;
  var compareTile = row[direction];

function multiply() {
  (pullTile.data *= 2);
  pullTile.compare = true; // the pull tile was multiplied (and by extension we know it shouldn't continue moving until the next move() is called/arrow is clicked)
}

function smush() {
  if (compareTile[direction]) {
    compareTile.data = compareTile[direction].data;
    // compareTile.compare = false///
    compareTile[direction].data = null;
  }
}

function nextTile() {
  pullTile = compareTile;
  compareTile = compareTile[direction];
}

  var i = 1;
  while (i > 0) {
    pullTile = row;
    compareTile = row[direction];
    i = 0;
    for(var t = 0; t < 3; t++) {
      var equalTiles = (pullTile.data === compareTile.data && pullTile.data !== null && !pullTile.compare );
      var nullTiles = (compareTile.data === null);
      // console.log(compareTile.data)

// case pullTile null
// smushed, then moved pullTile before multiply
    if (pullTile.data === null) {
          pullTile.data = compareTile.data;
          compareTile.data = null;
            if (equalTiles) {
              multiply();
            }
        }
// case equal
      if (equalTiles) {
        multiply();
        smush();
        nextTile();
      }

// case null
          if(nullTiles){
            console.log(pullTile.position,"this is the pull tile position");
              if(compareTile[direction]) {
                  if(compareTile[direction].data !== null) {
                i++;
                smush();
                nextTile();
              }
            }
            // TODO not skipping enough tiles
          }
        }
      }
  };
// console.log(pullTile.position, "this is pullTile when nextTile ran");

module.exports = Grid;
<|endoftext|>