<commit_before>var http = require('http');
var express = require("express");

var app = express();

var body = '';

var options = {
    host: 'dashboard.glasgow.gov.uk',
    port: 80,
    path: '/api/live/parking.php?type=json'
};

function pull() {
    http.get(options, function(res) {
    // console.log('started pull');
    var previous = body;
    body = '';

    res.on('data', function(chunk) {
	if (chunk != '{"error":"RATE_LIMIT"}'){
	    body += chunk;
	} else {
	    body = previous;
	    // console.log('using cache');
	}
    });

    res.on("end", function() {
	// console.log("BODY: " + body);
    });

}).on('error', function(e) {
    console.log("Got error: " + e.message);
});
}

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  next();
});

app.get('/api', function (req, res) {
    pull();
    res.send(body);
});

server.get('/', function(req, res) {
    res.render('./index.html');
};

var port = Number(process.env.PORT || 4242);

app.listen(port);
<commit_msg>note to self: be more careful when copy pasta code<commit_after>var http = require('http');
var express = require("express");

var app = express();

var body = '';

var options = {
    host: 'dashboard.glasgow.gov.uk',
    port: 80,
    path: '/api/live/parking.php?type=json'
};

function pull() {
    http.get(options, function(res) {
    // console.log('started pull');
    var previous = body;
    body = '';

    res.on('data', function(chunk) {
	if (chunk != '{"error":"RATE_LIMIT"}'){
	    body += chunk;
	} else {
	    body = previous;
	    // console.log('using cache');
	}
    });

    res.on("end", function() {
	// console.log("BODY: " + body);
    });

}).on('error', function(e) {
    console.log("Got error: " + e.message);
});
}

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  next();
});

app.get('/api', function (req, res) {
    pull();
    res.send(body);
});

app.get('/', function(req, res) {
    res.render('./index.html');
};

var port = Number(process.env.PORT || 4242);

app.listen(port);
<|endoftext|>


<commit_before>/*
 * Copyright 2018 The Kythe Authors. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = {
  // https://www.conventionalcommits.org/en/v1.0.0-beta.2/
  extends: ['@commitlint/config-conventional']
}
<commit_msg>release(dev): add stricter checking of commit messages (#3458)<commit_after>/*
 * Copyright 2018 The Kythe Authors. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

module.exports = {
  // https://www.conventionalcommits.org/en/v1.0.0-beta.2/
  extends: ['@commitlint/config-conventional'],
  rules: {
    'scope-case': [2, 'always', 'snake-case'],
    'scope-empty': [1, 'never'],
    'scope-enum': [
      1, 'always',
      [
        'api',              // user-facing API (e.g. XRefService)
        'dev',              // developer tooling/scripting (e.g. linting)
        'example',          // example tools or docs (e.g. sample web ui)
        'extraction',       // compilation extraction
        'indexing',         // semantic analysis over compilations
        'post_processing',  // serving data construction
        'serving',          // server logic or data formats
        'tooling',          // CLI utilities (e.g. entrystream)

        // Language-specific scopes
        'cxx_common',
        'cxx_extractor',
        'cxx_indexer',
        'go_common',
        'go_extractor',
        'go_indexer',
        'java_common',
        'java_extractor',
        'java_indexer',
        'jvm_common',
        'jvm_extractor',
        'jvm_indexer',
        'typescript_common',
        'typescript_extractor',
        'typescript_indexer',
      ]
    ],
    'type-enum': [
      2, 'always',
      [
        'build',
        'chore',
        'ci',
        'deprecation',
        'docs',
        'feat',
        'fix',
        'perf',
        'refactor',
        'release',
        'revert',
        'style',
        'test',
      ]
    ],
  },
}
<|endoftext|>


<commit_before>const webpack = require('webpack');
const { join } = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
  modules: [
    '@nuxtjs/pwa',
    '@nuxtjs/axios'
  ],
  build: {
    plugins: [
      new webpack.DefinePlugin({
        BASE_API_URL: !!process.env.PROD ? '"https://api.ammobin.ca/"' : '"http://localhost:8080/"',
        PROD: process.env.PROD ? 'true' : 'false'
      }),
      new CopyWebpackPlugin([{ from: 'static' }]),
    ],
    extractCSS: true,
    vendor: ['axios', 'vue-i18n'] // Add axios in the vendor.bundle.js
  },
  loading: {
    color: '#4FC08D',
    failedColor: '#bf5050',
    duration: 2000
  },
  css: [
    `purecss/build/pure${process.env.PROD ? '-min' : ''}.css`,
    `purecss/build/grids-responsive${process.env.PROD ? '-min' : ''}.css`,
    join(__dirname, 'css/main.css')
  ],
  head: {
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1, shrink-to-fit=no' },
      { hid: 'description', name: 'description', content: 'The place to view ammo prices across Canada.' },
      {
        // google webmaster
        name: 'google-site-verification',
        content: 'X3ZsfEygJo1ywKMaf5Q8ltUgkgK7o9buM7yMsI6G7yc'
      },
      {
        // bing webmaster (since helps to feed duckduckgo)
        name: 'msvalidate.01',
        content: '330D6A0BB2221C7F78C038494DE50309'
      },
      {
        //yandex also feeds duckduckgo
        name: 'yandex-verification',
        content: '99071bdc94d7e5ed'
      },
      {
        name: "theme_color",
        content: "#41b883"
      }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      { rel: 'alternate', hreflang: 'fr-ca', href: 'https://ammobin.ca/fr' },
      { rel: 'alternate', hreflang: 'x-default', href: 'https://ammobin.ca/' },
    ]
  },
  router: {
    middleware: 'i18n'
  },
  plugins: ['~/plugins/i18n.js'],
  /*
  disabled while working on api memory useage
  cache: {
     max: 1000,
     maxAge: 86400000
   },*/
  manifest: {
    "start_url": "/?launcher=true",
    "background_color": "#f4f4f4",
    "theme_color": "#41b883",
    "display": "standalone"
  },
  workbox: {
    globIgnores: ['sw.js', '**/workbox*.js']
  }
}
<commit_msg>added hreflang linke back to english (#129)<commit_after>const webpack = require('webpack');
const { join } = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
  modules: [
    '@nuxtjs/pwa',
    '@nuxtjs/axios'
  ],
  build: {
    plugins: [
      new webpack.DefinePlugin({
        BASE_API_URL: !!process.env.PROD ? '"https://api.ammobin.ca/"' : '"http://localhost:8080/"',
        PROD: process.env.PROD ? 'true' : 'false'
      }),
      new CopyWebpackPlugin([{ from: 'static' }]),
    ],
    extractCSS: true,
    vendor: ['axios', 'vue-i18n'] // Add axios in the vendor.bundle.js
  },
  loading: {
    color: '#4FC08D',
    failedColor: '#bf5050',
    duration: 2000
  },
  css: [
    `purecss/build/pure${process.env.PROD ? '-min' : ''}.css`,
    `purecss/build/grids-responsive${process.env.PROD ? '-min' : ''}.css`,
    join(__dirname, 'css/main.css')
  ],
  head: {
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1, shrink-to-fit=no' },
      { hid: 'description', name: 'description', content: 'The place to view ammo prices across Canada.' },
      {
        // google webmaster
        name: 'google-site-verification',
        content: 'X3ZsfEygJo1ywKMaf5Q8ltUgkgK7o9buM7yMsI6G7yc'
      },
      {
        // bing webmaster (since helps to feed duckduckgo)
        name: 'msvalidate.01',
        content: '330D6A0BB2221C7F78C038494DE50309'
      },
      {
        //yandex also feeds duckduckgo
        name: 'yandex-verification',
        content: '99071bdc94d7e5ed'
      },
      {
        name: "theme_color",
        content: "#41b883"
      }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      { rel: 'alternate', hreflang: 'fr-ca', href: 'https://ammobin.ca/fr' },
      { rel: 'alternate', hreflang: 'en-ca', href: 'https://ammobin.ca/' },
      { rel: 'alternate', hreflang: 'x-default', href: 'https://ammobin.ca/' },
    ]
  },
  router: {
    middleware: 'i18n'
  },
  plugins: ['~/plugins/i18n.js'],
  /*
  disabled while working on api memory useage
  cache: {
     max: 1000,
     maxAge: 86400000
   },*/
  manifest: {
    "start_url": "/?launcher=true",
    "background_color": "#f4f4f4",
    "theme_color": "#41b883",
    "display": "standalone"
  },
  workbox: {
    globIgnores: ['sw.js', '**/workbox*.js']
  }
}
<|endoftext|>


<commit_before>"use strict";

/**
* get "nested" object property
*/

function dive(obj) { //..., path
  var parts = [].slice.call(arguments, 1);
  for(let part of parts) {
    if(part == null) return;
    for(let spart of String(part).split('.')) {
      if(obj == null) return;
      obj = obj[spart];
    }
  }
  return obj;
}

module.exports = dive;
<commit_msg>With divev2<commit_after>"use strict";

/**
* get "nested" object property
*/

function dive(obj) { //..., path
  var parts = [].slice.call(arguments, 1);
  for(let part of parts) {
    if(part == null) return;
    if(obj == null) return;

    if(obj[part] != null) {
      obj = obj[part];
      continue;
    }

    for(let spart of String(part).split('.')) {
      if(obj == null) return;
      obj = obj[spart];
    }
  }
  return obj;
}

module.exports = dive;
<|endoftext|>


<commit_before>var Backbone = require('backbone');

var ToolbarView = require('./toolbar');
var FeedHeaderView = require('./feedHeader');
var FeedBodyView = require('./feedBody');
var SettingsView = require('./settings');
var Settings = require('../models/settings');

var AppView = Backbone.View.extend({

    template: require('../templates/app.hbs'),

    initialize: function(opts) {
        this.model = new Settings(null, { webSocketManager: opts.webSocketManager });
        this.webSocketManager = opts.webSocketManager;
    },

    render: function() {
        var $markup = $(this.template());

        this._renderChildViews($markup);

        this.$el.html($markup);

        return this;
    },

    _renderChildViews: function($markup) {
        var settingsView = new SettingsView({
            el: $markup.siblings('.settings-modal-container'),
            settingsModel: this.model
        }).render();

        var feedHeaderView = new FeedHeaderView({
            el: $markup.find('.header'),
            webSocketManager: this.webSocketManager
        }).render();

        var feedBodyView = new FeedBodyView({
            el: $markup.find('.body'),
            collection: this.collection
        }).render();

        var toolbarView = new ToolbarView({
            el: $markup.siblings('.toolbar'),
            model: this.model,
            webSocketManager: this.webSocketManager
        }).render();

        this.listenTo(toolbarView, 'searchChanged', feedBodyView.filterRequests.bind(feedBodyView));
        this.listenTo(toolbarView, 'showSettings', settingsView.show);
        this.listenTo(toolbarView, 'clearFeed', function() {
            feedHeaderView.clear();
            feedBodyView.clear();
        });

        this.listenTo(feedHeaderView, 'toggleFavorites', feedBodyView.toggleFavorites.bind(feedBodyView));
        this.listenTo(feedHeaderView, 'collapseAll', feedBodyView.collapseAll.bind(feedBodyView));

        this.listenTo(feedBodyView, 'requestExpandToggle', function(toggle) {
            if (!toggle && !feedBodyView.hasExpandedRequests()) {
                feedHeaderView.disableCollapseAll();
            } else if(toggle) {
                feedHeaderView.enableCollapseAll();
            }
        });

        this.listenTo(feedBodyView, 'requestFavoriteToggle', function(toggle) {
            if (!toggle && !feedBodyView.hasFavoritedRequests()) {
                feedHeaderView.disableFavoritesFilter();
            } else if (toggle) {
                feedHeaderView.enableFavoritesFilter();
            }
        });
    }

});

module.exports = AppView;
<commit_msg>Minor readability update.<commit_after>var Backbone = require('backbone');

var ToolbarView = require('./toolbar');
var FeedHeaderView = require('./feedHeader');
var FeedBodyView = require('./feedBody');
var SettingsView = require('./settings');
var Settings = require('../models/settings');

var AppView = Backbone.View.extend({

    template: require('../templates/app.hbs'),

    initialize: function(opts) {
        this.model = new Settings(null, { webSocketManager: opts.webSocketManager });
        this.webSocketManager = opts.webSocketManager;
    },

    render: function() {
        var $markup = $(this.template());

        this._renderChildViews($markup);

        this.$el.html($markup);

        return this;
    },

    _renderChildViews: function($markup) {
        var settingsView = new SettingsView({
            el: $markup.siblings('.settings-modal-container'),
            settingsModel: this.model
        }).render();

        var feedHeaderView = new FeedHeaderView({
            el: $markup.find('.header'),
            webSocketManager: this.webSocketManager
        }).render();

        var feedBodyView = new FeedBodyView({
            el: $markup.find('.body'),
            collection: this.collection
        }).render();

        var toolbarView = new ToolbarView({
            el: $markup.siblings('.toolbar'),
            model: this.model,
            webSocketManager: this.webSocketManager
        }).render();

        this.listenTo(toolbarView, 'searchChanged', feedBodyView.filterRequests.bind(feedBodyView));
        this.listenTo(toolbarView, 'showSettings', settingsView.show);
        this.listenTo(toolbarView, 'clearFeed', function() {
            feedHeaderView.clear();
            feedBodyView.clear();
        });

        this.listenTo(feedHeaderView, 'toggleFavorites', feedBodyView.toggleFavorites.bind(feedBodyView));
        this.listenTo(feedHeaderView, 'collapseAll', feedBodyView.collapseAll.bind(feedBodyView));

        this.listenTo(feedBodyView, 'requestExpandToggle', function(expanded) {
            if (!expanded && !feedBodyView.hasExpandedRequests()) {
                feedHeaderView.disableCollapseAll();
            } else if(expanded) {
                feedHeaderView.enableCollapseAll();
            }
        });

        this.listenTo(feedBodyView, 'requestFavoriteToggle', function(favorited) {
            if (!favorited && !feedBodyView.hasFavoritedRequests()) {
                feedHeaderView.disableFavoritesFilter();
            } else if (favorited) {
                feedHeaderView.enableFavoritesFilter();
            }
        });
    }

});

module.exports = AppView;
<|endoftext|>


<commit_before><generic-url>
	le document
	<input class="source" required type="url" placeholder="https://www.legifrance.gouv.fr/affichCodeArticle.do?idArticle=LEGIARTI000030021309&cidTexte=LEGITEXT000006069577&categorieLien=id&dateTexte=20151231" value={ url }>

	<style scoped>
		input {
			display: block;
		}

		input[type="url"] {
			width: 100%;
		}
	</style>

	<script>
		setValue() {
			fetch({ url })
				.then(function(response) {
					if (this.response.ok)
						this.root.value = this.url;
					this.update();
				}.bind(this), console.error.bind(console));
		}
	</script>
</generic-url>
<commit_msg>fixup! Make generic URL inputs a component<commit_after><generic-url>
	le document
	<input class="source" required type="url" placeholder="https://www.legifrance.gouv.fr/affichCodeArticle.do?idArticle=LEGIARTI000030021309&cidTexte=LEGITEXT000006069577&categorieLien=id&dateTexte=20151231" value={ url } onchange={ setValue }>

	<style scoped>
		input {
			display: block;
		}

		input[type="url"] {
			width: 100%;
		}
	</style>

	<script>
		setValue() {
			fetch(this.url)
				.then(function(response) {
					if (response.ok)
						this.root.value = this.url;
					this.update();
				}.bind(this), console.error.bind(console));
		}
	</script>
</generic-url>
<|endoftext|>


<commit_before>;(function (window, document) {

    'use strict';

    var $, defaultWidths, getKeys, isArray;

    window.requestAnimationFrame =
    window.requestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    function (callback) {
        window.setTimeout(callback, 1000 / 60);
    };

    function applyEach(collection, callbackEach){
        var i = 0,
            length = collection.length,
            new_collection = [];

        for(; i < length; i++){
            new_collection[i] = callbackEach(collection[i]);
        }

        return new_collection;
    }

    function returnDirectValue(d){
      return d;
    }

    $ = (function (dollar) {
        if (dollar) {
            return dollar;
        }

        return function (selector) {
            return applyEach(document.querySelectorAll(selector), returnDirectValue);
        };
    }(window.$));

    defaultWidths = [96, 130, 165, 200, 235, 270, 304, 340, 375, 410, 445, 485, 520, 555, 590, 625, 660, 695, 736];

    getKeys = typeof Object.keys === 'function' ? Object.keys : function(object){
        var keys = [],
            key;

        for (key in object){
            keys.push(key);
        }

        return keys;
    };

    isArray = function isArray(thing){
      return Object.prototype.toString.call(thing) === '[object Array]';
    };

    /*
        Construct a new Imager instance, passing an optional configuration object.

        Example usage:

            {
                // Available widths for your images
                availableWidths: [Number]

                // Selector to be used to locate your div placeholders
                selector: '',

                // Class name to give your resizable images.
                className: '',

                // Toggle the lazy load functionality on or off
                lazyload: Boolean

                // Used alongside the lazyload feature (helps performance by setting a higher delay)
                scrollDelay: Number
            }

        @param {object} configuration settings
        @return {object} instance of Imager
     */
    function Imager(elements, opts) {
        var self = this;
            opts = opts || {};

        if (elements !== undefined){
          //first argument as string
          if (typeof elements === 'string'){
            opts.selector = elements;
            elements = undefined;
          }

          //first argument as options
          else if (!('length' in elements)){
            opts = elements;
            elements = undefined;
          }
        }

        this.imagesOffScreen = [];
        this.viewportHeight  = document.documentElement.clientHeight;
        this.selector        = opts.selector || '.delayed-image-load';
        this.className       = '.' + (opts.className || 'image-replace').replace(/^\.+/, '.');
        this.gif             = document.createElement('img');
        this.gif.src         = 'data:image/gif;base64,R0lGODlhEAAJAIAAAP///wAAACH5BAEAAAAALAAAAAAQAAkAAAIKhI+py+0Po5yUFQA7';
        this.gif.className   = this.className.replace(/^[#.]/, '');
        this.cache           = {};
        this.scrollDelay     = opts.scrollDelay || 250;
        this.onResize        = opts.hasOwnProperty('onResize') ? opts.onResize : true;
        this.lazyload        = opts.hasOwnProperty('lazyload') ? opts.lazyload : false;
        this.scrolled        = false;
        this.devicePixelRatio = Imager.getPixelRatio();

        if (opts.availableWidths === undefined){
            opts.availableWidths = defaultWidths;
        }

        if (isArray(opts.availableWidths)){
          this.availableWidths = opts.availableWidths;
          this.widthsMap = Imager.createWidthsMap(this.availableWidths);
        }
        else {
          this.availableWidths = getKeys(opts.availableWidths);
          this.widthsMap = opts.availableWidths;
        }

        this.availableWidths = this.availableWidths.sort(function(a, b){ return a - b; });

        if (elements){
          this.divs = applyEach(elements, returnDirectValue);
          this.selector = null;
        }
        else{
          this.divs = $(this.selector);
        }

        this.changeDivsToEmptyImages();

        window.requestAnimationFrame(function(){
            self.init();
        });
    }

    Imager.prototype.scrollCheck = function(){
        if (this.scrolled) {
            if (!this.imagesOffScreen.length) {
                window.clearInterval(this.interval);
            }
            this.divs = this.imagesOffScreen.slice(0); // copy by value, don't copy by reference
            this.imagesOffScreen.length = 0;
            this.changeDivsToEmptyImages();
            this.scrolled = false;
        }
    };

    Imager.prototype.init = function(){
        this.initialized = true;

        this.checkImagesNeedReplacing();

        if (this.onResize) {
            this.registerResizeEvent();
        }

        if (this.lazyload) {
            this.registerScrollEvent();
        }
    };

    Imager.prototype.createGif = function (element) {
        var gif = this.gif.cloneNode(false);
            gif.width = element.getAttribute('data-width');
            gif.setAttribute('data-src', element.getAttribute('data-src'));

        element.parentNode.replaceChild(gif, element);
    };

    Imager.prototype.changeDivsToEmptyImages = function(){
        var divs = this.divs,
            i = divs.length,
            element;

        while (i--) {
            element = divs[i];

            if (this.lazyload) {
                if (this.isThisElementOnScreen(element)) {
                    this.createGif(element);
                } else {
                    this.imagesOffScreen.push(element);
                }
            } else {
                this.createGif(element);
            }
        }

        if (this.initialized) {
            this.checkImagesNeedReplacing();
        }
    };

    Imager.prototype.isThisElementOnScreen = function (element) {
        // document.body.scrollTop was working in Chrome but didn't work on Firefox, so had to resort to window.pageYOffset
        // but can't fallback to document.body.scrollTop as that doesn't work in IE with a doctype (?) so have to use document.documentElement.scrollTop
        var offset = ('pageYOffset' in window) ? window.pageYOffset : document.documentElement.scrollTop;

        return (element.offsetTop < (this.viewportHeight + offset)) ? true : false;
    };

    Imager.prototype.checkImagesNeedReplacing = function(){
        var images = $(this.className),
            i = images.length,
            currentImage;

        if (!this.isResizing) {
            this.isResizing = true;

            while (i--) {
                currentImage = images[i];
                this.replaceImagesBasedOnScreenDimensions(currentImage);
            }

            this.isResizing = false;
        }
    };

    Imager.prototype.replaceImagesBasedOnScreenDimensions = function (image) {
        var computedWidth = typeof this.availableWidths === 'function'? this.availableWidths(image) : this.determineAppropriateResolution(image),
            src = this.changeImageSrcToUseNewImageDimensions(image.getAttribute('data-src'), computedWidth),
            parent = image.parentNode,
            replacedImage;

        if (this.cache[src]) {
            replacedImage = this.cache[src].cloneNode(false);
            replacedImage.width = image.getAttribute('width');
        } else {
            replacedImage = image.cloneNode(false);
            replacedImage.src = src;
            this.cache[src] = replacedImage;
        }

        parent.replaceChild(replacedImage, image);
    };

    Imager.prototype.determineAppropriateResolution = function (image) {
        var imagewidth    = image.clientWidth,
            i             = this.availableWidths.length,
            selectedWidth = this.availableWidths[i - 1];

        while (i--) {
            if (imagewidth <= this.availableWidths[i]) {
                selectedWidth = this.availableWidths[i];
            }
        }

        return selectedWidth;
    };

    Imager.prototype.changeImageSrcToUseNewImageDimensions = function (src, selectedWidth) {
        return src
          .replace(/{width}/g, Imager.transforms.width(selectedWidth, this.widthsMap))
          .replace(/{pixel_ratio}/g, Imager.transforms.pixelRatio(this.devicePixelRatio));
    };

    Imager.getPixelRatio = function getPixelRatio(){
        return window.devicePixelRatio || 1;
    };

    Imager.createWidthsMap = function createWidthsMap(widths){
        var map = {},
            i = widths.length;

        while(i--){
            map[widths[i]] = null;
        }
        return map;
    };

    Imager.transforms = {
        pixelRatio: function(value){
            return value === 1 ? '' : '-'+value+'x';
        },
        width: function transformWidth(width, map){
          return map[width] || width;
        }
    };

    Imager.prototype.registerResizeEvent = function (){
      var self = this;

      window.addEventListener('resize', function(){
        self.checkImagesNeedReplacing();
      }, false);
    };

    Imager.prototype.registerScrollEvent = function (){
      var self = this;

      this.scrolled = false;

      this.interval = window.setInterval(function(){
        self.scrollCheck();
      }, self.scrollDelay);

      window.addEventListener('scroll', function(){
        self.scrolled = true;
      }, false);
    };

    /* global module, exports: true, define */
    if (typeof module === 'object' && typeof module.exports === 'object') {
        // CommonJS, just export
        module.exports = exports = Imager;
    } else if (typeof define === 'function' && define.amd) {
        // AMD support
        define(function () { return Imager; });
    } else if (typeof window === 'object') {
        // If no AMD and we are in the browser, attach to window
        window.Imager = Imager;
    }
    /* global -module, -exports, -define */

}(window, document));
<commit_msg>Removed `$`<commit_after>;(function (window, document) {

    'use strict';

    var defaultWidths, getKeys, isArray;

    window.requestAnimationFrame =
    window.requestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    function (callback) {
        window.setTimeout(callback, 1000 / 60);
    };

    function applyEach(collection, callbackEach){
        var i = 0,
            length = collection.length,
            new_collection = [];

        for(; i < length; i++){
            new_collection[i] = callbackEach(collection[i]);
        }

        return new_collection;
    }

    function returnDirectValue(d){
      return d;
    }

    defaultWidths = [96, 130, 165, 200, 235, 270, 304, 340, 375, 410, 445, 485, 520, 555, 590, 625, 660, 695, 736];

    getKeys = typeof Object.keys === 'function' ? Object.keys : function(object){
        var keys = [],
            key;

        for (key in object){
            keys.push(key);
        }

        return keys;
    };

    isArray = function isArray(thing){
      return Object.prototype.toString.call(thing) === '[object Array]';
    };

    /*
        Construct a new Imager instance, passing an optional configuration object.

        Example usage:

            {
                // Available widths for your images
                availableWidths: [Number]

                // Selector to be used to locate your div placeholders
                selector: '',

                // Class name to give your resizable images.
                className: '',

                // Toggle the lazy load functionality on or off
                lazyload: Boolean

                // Used alongside the lazyload feature (helps performance by setting a higher delay)
                scrollDelay: Number
            }

        @param {object} configuration settings
        @return {object} instance of Imager
     */
    function Imager(elements, opts) {
        var self = this;
            opts = opts || {};

        if (elements !== undefined){
          //first argument as string
          if (typeof elements === 'string'){
            opts.selector = elements;
            elements = undefined;
          }

          //first argument as options
          else if (!('length' in elements)){
            opts = elements;
            elements = undefined;
          }
        }

        this.imagesOffScreen = [];
        this.viewportHeight  = document.documentElement.clientHeight;
        this.selector        = opts.selector || '.delayed-image-load';
        this.className       = '.' + (opts.className || 'image-replace').replace(/^\.+/, '.');
        this.gif             = document.createElement('img');
        this.gif.src         = 'data:image/gif;base64,R0lGODlhEAAJAIAAAP///wAAACH5BAEAAAAALAAAAAAQAAkAAAIKhI+py+0Po5yUFQA7';
        this.gif.className   = this.className.replace(/^[#.]/, '');
        this.cache           = {};
        this.scrollDelay     = opts.scrollDelay || 250;
        this.onResize        = opts.hasOwnProperty('onResize') ? opts.onResize : true;
        this.lazyload        = opts.hasOwnProperty('lazyload') ? opts.lazyload : false;
        this.scrolled        = false;
        this.devicePixelRatio = Imager.getPixelRatio();

        if (opts.availableWidths === undefined){
            opts.availableWidths = defaultWidths;
        }

        if (isArray(opts.availableWidths)){
          this.availableWidths = opts.availableWidths;
          this.widthsMap = Imager.createWidthsMap(this.availableWidths);
        }
        else {
          this.availableWidths = getKeys(opts.availableWidths);
          this.widthsMap = opts.availableWidths;
        }

        this.availableWidths = this.availableWidths.sort(function(a, b){ return a - b; });

        if (elements){
          this.divs = applyEach(elements, returnDirectValue);
          this.selector = null;
        }
        else{
          this.divs = applyEach(document.querySelectorAll(this.selector), returnDirectValue);
        }

        this.changeDivsToEmptyImages();

        window.requestAnimationFrame(function(){
            self.init();
        });
    }

    Imager.prototype.scrollCheck = function(){
        if (this.scrolled) {
            if (!this.imagesOffScreen.length) {
                window.clearInterval(this.interval);
            }
            this.divs = this.imagesOffScreen.slice(0); // copy by value, don't copy by reference
            this.imagesOffScreen.length = 0;
            this.changeDivsToEmptyImages();
            this.scrolled = false;
        }
    };

    Imager.prototype.init = function(){
        this.initialized = true;

        this.checkImagesNeedReplacing();

        if (this.onResize) {
            this.registerResizeEvent();
        }

        if (this.lazyload) {
            this.registerScrollEvent();
        }
    };

    Imager.prototype.createGif = function (element) {
        var gif = this.gif.cloneNode(false);
            gif.width = element.getAttribute('data-width');
            gif.setAttribute('data-src', element.getAttribute('data-src'));

        element.parentNode.replaceChild(gif, element);
    };

    Imager.prototype.changeDivsToEmptyImages = function(){
        var divs = this.divs,
            i = divs.length,
            element;

        while (i--) {
            element = divs[i];

            if (this.lazyload) {
                if (this.isThisElementOnScreen(element)) {
                    this.createGif(element);
                } else {
                    this.imagesOffScreen.push(element);
                }
            } else {
                this.createGif(element);
            }
        }

        if (this.initialized) {
            this.checkImagesNeedReplacing();
        }
    };

    Imager.prototype.isThisElementOnScreen = function (element) {
        // document.body.scrollTop was working in Chrome but didn't work on Firefox, so had to resort to window.pageYOffset
        // but can't fallback to document.body.scrollTop as that doesn't work in IE with a doctype (?) so have to use document.documentElement.scrollTop
        var offset = ('pageYOffset' in window) ? window.pageYOffset : document.documentElement.scrollTop;

        return (element.offsetTop < (this.viewportHeight + offset)) ? true : false;
    };

    Imager.prototype.checkImagesNeedReplacing = function(){
        var images = document.querySelectorAll(this.className),
            i = images.length,
            currentImage;

        if (!this.isResizing) {
            this.isResizing = true;

            while (i--) {
                currentImage = images[i];
                this.replaceImagesBasedOnScreenDimensions(currentImage);
            }

            this.isResizing = false;
        }
    };

    Imager.prototype.replaceImagesBasedOnScreenDimensions = function (image) {
        var computedWidth = typeof this.availableWidths === 'function'? this.availableWidths(image) : this.determineAppropriateResolution(image),
            src = this.changeImageSrcToUseNewImageDimensions(image.getAttribute('data-src'), computedWidth),
            parent = image.parentNode,
            replacedImage;

        if (this.cache[src]) {
            replacedImage = this.cache[src].cloneNode(false);
            replacedImage.width = image.getAttribute('width');
        } else {
            replacedImage = image.cloneNode(false);
            replacedImage.src = src;
            this.cache[src] = replacedImage;
        }

        parent.replaceChild(replacedImage, image);
    };

    Imager.prototype.determineAppropriateResolution = function (image) {
        var imagewidth    = image.clientWidth,
            i             = this.availableWidths.length,
            selectedWidth = this.availableWidths[i - 1];

        while (i--) {
            if (imagewidth <= this.availableWidths[i]) {
                selectedWidth = this.availableWidths[i];
            }
        }

        return selectedWidth;
    };

    Imager.prototype.changeImageSrcToUseNewImageDimensions = function (src, selectedWidth) {
        return src
          .replace(/{width}/g, Imager.transforms.width(selectedWidth, this.widthsMap))
          .replace(/{pixel_ratio}/g, Imager.transforms.pixelRatio(this.devicePixelRatio));
    };

    Imager.getPixelRatio = function getPixelRatio(){
        return window.devicePixelRatio || 1;
    };

    Imager.createWidthsMap = function createWidthsMap(widths){
        var map = {},
            i = widths.length;

        while(i--){
            map[widths[i]] = null;
        }
        return map;
    };

    Imager.transforms = {
        pixelRatio: function(value){
            return value === 1 ? '' : '-'+value+'x';
        },
        width: function transformWidth(width, map){
          return map[width] || width;
        }
    };

    Imager.prototype.registerResizeEvent = function (){
      var self = this;

      window.addEventListener('resize', function(){
        self.checkImagesNeedReplacing();
      }, false);
    };

    Imager.prototype.registerScrollEvent = function (){
      var self = this;

      this.scrolled = false;

      this.interval = window.setInterval(function(){
        self.scrollCheck();
      }, self.scrollDelay);

      window.addEventListener('scroll', function(){
        self.scrolled = true;
      }, false);
    };

    /* global module, exports: true, define */
    if (typeof module === 'object' && typeof module.exports === 'object') {
        // CommonJS, just export
        module.exports = exports = Imager;
    } else if (typeof define === 'function' && define.amd) {
        // AMD support
        define(function () { return Imager; });
    } else if (typeof window === 'object') {
        // If no AMD and we are in the browser, attach to window
        window.Imager = Imager;
    }
    /* global -module, -exports, -define */

}(window, document));
<|endoftext|>


<commit_before>'use-strict';

var hours = ['6:00am', '7:00am', '8:00am', '9:00am', '10:00am', '11:00am', '12:00pm', '1:00pm', '2:00pm', '3:00pm', '4:00pm', '5:00pm', '6:00pm', '7:00pm'];
var allLocations = [];
var theTable = document.getElementById('pike');
var el = document.getElementById('moreStores');
// var hourlyTotals = [];

// contructor for the Cookie Stores
function CookieStore(locationName, minCustomersPerHour, maxCustomersPerHour, avgCookiesPerCustomer) {
  this.locationName = locationName;
  this.minCustomersPerHour = minCustomersPerHour;
  this.maxCustomersPerHour = maxCustomersPerHour;
  this.avgCookiesPerCustomer = avgCookiesPerCustomer;
  this.customersEachHour = [];
  this.cookiesEachHour = [];
  this.totalDaily = 0;
  this.calcCustomersThisHour();
  this.calcCookiesThisHour();
  allLocations.push(this);
}

// creates total for customers each hour
CookieStore.prototype.calcCustomersThisHour = function() {
  var reference = [];
  for (var i = 0; i < hours.length; i++) {
    var numberCustomersPerHour = Math.floor(Math.random() * (this.maxCustomersPerHour - this.minCustomersPerHour + 1)) + this.minCustomersPerHour;
    reference.push(numberCustomersPerHour);
  }
  this.customersEachHour = reference;
  return numberCustomersPerHour;
};

// Creates total for daily cookie sales
CookieStore.prototype.calcCookiesThisHour = function() {
  for (var j = 0; j < hours.length; j++) {
    var totalCookieSales = Math.ceil(this.customersEachHour[j] * this.avgCookiesPerCustomer);
    this.cookiesEachHour.push(totalCookieSales);
    this.totalDaily += this.cookiesEachHour[j];
  }
  this.cookiesEachHour.push(this.totalDaily);
};

// creates table elements
function makeElement(type, content, parent){
  // create
  var newEl = document.createElement(type);
  // content
  newEl.textContent = content;
  // append
  parent.appendChild(newEl);
}

// Push hours to table header
var renderHeader = function() {
  var trEL = document.createElement('tr');
  var thEL = document.createElement('th');
  thEL.textContent = 'Locations';
  trEL.appendChild(thEL);
  for (var i = 0; i < hours.length; i++) {
    var thEL = document.createElement('th');
    thEL.textContent = hours[i];
    trEL.appendChild(thEL);
  }
  thEL = document.createElement('th');
  thEL.textContent = 'Daily';
  trEL.appendChild(thEL);
  theTable.appendChild(trEL);
};

// Push totals to TD's in DOM
CookieStore.prototype.render = function() {
  var trEL = document.createElement('tr');
  var tdEL = document.createElement('td');
  tdEL.textContent = this.locationName;
  trEL.appendChild(tdEL);

  for (var i = 0; i < hours.length + 1; i++) {
    var tdEL = document.createElement('td');
    tdEL.textContent = this.cookiesEachHour[i];
    trEL.appendChild(tdEL);
  }
  theTable.appendChild(trEL);
};

// Footer TOTALLLLL
function renderFooter() {
  var trEL = document.createElement('tr');
  var thEL = document.createElement('th');
  thEL.textContent = 'Total';
  trEL.appendChild(thEL);
  var totalOfTotals = 0;
  var hourlyTotal = 0;
  for (var i = 0; i < hours.length; i++) {
    hourlyTotal = 0;
    for (var j = 0; j < allLocations.length; j++) {
      hourlyTotal += allLocations[j].cookiesEachHour[i];
      totalOfTotals += allLocations[j].cookiesEachHour[i];
    }
    thEL = document.createElement('th');
    thEL.textContent = hourlyTotal;
    trEL.appendChild(thEL);
  }
  thEL = document.createElement('th');
  thEL.textContent = totalOfTotals;
  trEL.appendChild(thEL);
  theTable.appendChild(trEL);
};

// passing new stores to the cookie store constructor
var pikePlace = new CookieStore('Pike Place Market', 23, 65, 6.3);
var seaTac = new CookieStore('Seatac', 3, 24, 1.2);
var seattleCenter = new CookieStore('Seattle Center', 11, 38, 3.7);
var capitolHill = new CookieStore('Capitol Hill', 20, 38, 2.3);
var alki = new CookieStore('Alki', 2, 16, 4.6);

// Renders the table
function renderTable(){
  theTable.innerHTML = '';
  renderHeader();
  for (i = 0; i < allLocations.length; i++) {
    allLocations[i].render();
  }
  renderFooter();
}
renderTable();

// Handler for listener
function handleStoreSubmit(event) {
  event.preventDefault();
  var newStoreLocation = event.target.storeLocation.value;
  var minCustomers = parseInt(event.target.minCustomers.value);
  var maxCustomers = parseInt(event.target.maxCustomers.value);
  var avgCookie = parseFloat(event.target.avgCookiesSold.value);

  // prevent empty
  if(!newStoreLocation || !minCustomers || !maxCustomers || !avgCookies){
    return alert('All fields must have a value');
  }

  //validate by type
  if (typeof minCustomers !== 'number') {
    return alert('Min customers must be a number');
  }

  // ignore case on store names

  for(var i = 0; i < allLocations.length; i++){
    if(newStoreLocation === allLocations[i].locationName) {
      allLocations[i].minCustomersPerHour = minCustomers;
      allLocations[i].maxCustomersPerHour = maxCustomers;
      allLocations[i].avgCookiesPerCustomer = avgCookie;
      clearForm();
      allLocations[i].totalDaily = 0;
      allLocations[i].customersEachHour = [];
      allLocations[i].cookiesEachHour = [];
      allLocations[i].calcCustomersThisHour();
      allLocations[i].calcCookiesThisHour();
      console.log('A match was found at index', allLocations[i]);
      renderTable();
      return;
    }
  }

  new CookieStore(newStoreLocation, minCustomers, maxCustomers, avgCookie);

  function clearForm(){
    event.target.storeLocation.value = null;
    event.target.minCustomers.value = null;
    event.target.maxCustomers.value = null;
    event.target.avgCookiesSold.value = null;
  }
  clearForm();
  // for(var i = allLocations.length - 1; i < allLocations.length; i++){
  //   allLocations[i].render();
  // }
  renderTable();
};

// Listener code
el.addEventListener('submit', handleStoreSubmit);
<commit_msg>fixed changes<commit_after>'use-strict';

var hours = ['6:00am', '7:00am', '8:00am', '9:00am', '10:00am', '11:00am', '12:00pm', '1:00pm', '2:00pm', '3:00pm', '4:00pm', '5:00pm', '6:00pm', '7:00pm'];
var allLocations = [];
var theTable = document.getElementById('pike');
var el = document.getElementById('moreStores');
// var hourlyTotals = [];

// contructor for the Cookie Stores
function CookieStore(locationName, minCustomersPerHour, maxCustomersPerHour, avgCookiesPerCustomer) {
  this.locationName = locationName;
  this.minCustomersPerHour = minCustomersPerHour;
  this.maxCustomersPerHour = maxCustomersPerHour;
  this.avgCookiesPerCustomer = avgCookiesPerCustomer;
  this.customersEachHour = [];
  this.cookiesEachHour = [];
  this.totalDaily = 0;
  this.calcCustomersThisHour();
  this.calcCookiesThisHour();
  allLocations.push(this);
}

// creates total for customers each hour
CookieStore.prototype.calcCustomersThisHour = function() {
  var reference = [];
  for (var i = 0; i < hours.length; i++) {
    var numberCustomersPerHour = Math.floor(Math.random() * (this.maxCustomersPerHour - this.minCustomersPerHour + 1)) + this.minCustomersPerHour;
    reference.push(numberCustomersPerHour);
  }
  this.customersEachHour = reference;
  return numberCustomersPerHour;
};

// Creates total for daily cookie sales
CookieStore.prototype.calcCookiesThisHour = function() {
  for (var j = 0; j < hours.length; j++) {
    var totalCookieSales = Math.ceil(this.customersEachHour[j] * this.avgCookiesPerCustomer);
    this.cookiesEachHour.push(totalCookieSales);
    this.totalDaily += this.cookiesEachHour[j];
  }
  this.cookiesEachHour.push(this.totalDaily);
};

// creates table elements
function makeElement(type, content, parent){
  // create
  var newEl = document.createElement(type);
  // content
  newEl.textContent = content;
  // append
  parent.appendChild(newEl);
}

// Push hours to table header
var renderHeader = function() {
  var trEL = document.createElement('tr');
  var thEL = document.createElement('th');
  thEL.textContent = 'Locations';
  trEL.appendChild(thEL);
  for (var i = 0; i < hours.length; i++) {
    var thEL = document.createElement('th');
    thEL.textContent = hours[i];
    trEL.appendChild(thEL);
  }
  thEL = document.createElement('th');
  thEL.textContent = 'Daily';
  trEL.appendChild(thEL);
  theTable.appendChild(trEL);
};

// Push totals to TD's in DOM
CookieStore.prototype.render = function() {
  var trEL = document.createElement('tr');
  var tdEL = document.createElement('td');
  tdEL.textContent = this.locationName;
  trEL.appendChild(tdEL);

  for (var i = 0; i < hours.length + 1; i++) {
    var tdEL = document.createElement('td');
    tdEL.textContent = this.cookiesEachHour[i];
    trEL.appendChild(tdEL);
  }
  theTable.appendChild(trEL);
};

// Footer TOTALLLLL
function renderFooter() {
  var trEL = document.createElement('tr');
  var thEL = document.createElement('th');
  thEL.textContent = 'Total';
  trEL.appendChild(thEL);
  var totalOfTotals = 0;
  var hourlyTotal = 0;
  for (var i = 0; i < hours.length; i++) {
    hourlyTotal = 0;
    for (var j = 0; j < allLocations.length; j++) {
      hourlyTotal += allLocations[j].cookiesEachHour[i];
      totalOfTotals += allLocations[j].cookiesEachHour[i];
    }
    thEL = document.createElement('th');
    thEL.textContent = hourlyTotal;
    trEL.appendChild(thEL);
  }
  thEL = document.createElement('th');
  thEL.textContent = totalOfTotals;
  trEL.appendChild(thEL);
  theTable.appendChild(trEL);
};

// passing new stores to the cookie store constructor
var pikePlace = new CookieStore('Pike Place Market', 23, 65, 6.3);
var seaTac = new CookieStore('Seatac', 3, 24, 1.2);
var seattleCenter = new CookieStore('Seattle Center', 11, 38, 3.7);
var capitolHill = new CookieStore('Capitol Hill', 20, 38, 2.3);
var alki = new CookieStore('Alki', 2, 16, 4.6);

// Renders the table
function renderTable(){
  theTable.innerHTML = '';
  renderHeader();
  for (i = 0; i < allLocations.length; i++) {
    allLocations[i].render();
  }
  renderFooter();
}
renderTable();

// Handler for listener
function handleStoreSubmit(event) {
  event.preventDefault();
  var newStoreLocation = event.target.storeLocation.value;
  var minCustomers = parseInt(event.target.minCustomers.value);
  var maxCustomers = parseInt(event.target.maxCustomers.value);
  var avgCookie = parseFloat(event.target.avgCookiesSold.value);
  console.log('go here');
  // prevent empty
  if(!newStoreLocation || !minCustomers || !maxCustomers || !avgCookie){
    return alert('All fields must have a value');
  }

  //validate by type
  if (typeof minCustomers !== 'number') {
    return alert('Min customers must be a number');
  }

  // ignore case on store names

  for(var i = 0; i < allLocations.length; i++){
    if(newStoreLocation === allLocations[i].locationName) {
      allLocations[i].minCustomersPerHour = minCustomers;
      allLocations[i].maxCustomersPerHour = maxCustomers;
      allLocations[i].avgCookiesPerCustomer = avgCookie;
      clearForm();
      allLocations[i].totalDaily = 0;
      allLocations[i].customersEachHour = [];
      allLocations[i].cookiesEachHour = [];
      allLocations[i].calcCustomersThisHour();
      allLocations[i].calcCookiesThisHour();
      console.log('A match was found at index', allLocations[i]);
      renderTable();
      return;
    }
  }

  new CookieStore(newStoreLocation, minCustomers, maxCustomers, avgCookie);

  function clearForm(){
    event.target.storeLocation.value = null;
    event.target.minCustomers.value = null;
    event.target.maxCustomers.value = null;
    event.target.avgCookiesSold.value = null;
  }
  clearForm();
  // for(var i = allLocations.length - 1; i < allLocations.length; i++){
  //   allLocations[i].render();
  // }
  renderTable();
};

// Listener code
el.addEventListener('submit', handleStoreSubmit);
<|endoftext|>


<commit_before>"use strict"

module.exports = new function init() {
	var spec = {}, subjects = [], results = [], only = null, ctx = spec, start, stack = 0, hasProcess = typeof process === "object"

	function o(subject, predicate) {
		ctx[subject] = predicate
		if (predicate === undefined) return new Assert(subject)
	}
	o.before = hook("__before")
	o.after = hook("__after")
	o.beforeEach = hook("__beforeEach")
	o.afterEach = hook("__afterEach")
	o.new = init
	o.spec = function(subject, predicate) {
		var parent = ctx
		ctx = ctx[subject] = {}
		predicate()
		ctx = parent
	}
	o.only = function(subject, predicate) {o(subject, only = predicate)}
	o.spy = function() {
		var spy = function() {
			spy.this = this
			spy.args = [].slice.call(arguments)
			spy.callCount++
		}
		spy.args = []
		spy.callCount = 0
		return spy
	}
	o.run = function() {
		start = new Date
		test(spec, [], [], report)

		function test(spec, pre, post, finalize) {
			pre = [].concat(pre, spec["__beforeEach"] || [])
			post = [].concat(spec["__afterEach"] || [], post)
			series([].concat(spec["__before"] || [], Object.keys(spec).map(function(key) {
				return function(done, timeout) {
					timeout(Infinity)

					if (key.slice(0, 2) === "__") return done()
					if (only !== null && spec[key] !== only && typeof only === typeof spec[key]) return done()
					subjects.push(key)
					var type = typeof spec[key]
					if (type === "object") test(spec[key], pre, post, pop)
					if (type === "function") series([].concat(pre, spec[key], post, pop))

					function pop() {
						subjects.pop()
						done()
					}
				}
			}), spec["__after"] || [], finalize))
		}

		function series(fns) {
			var cursor = 0
			next()

			function next() {
				stack++
				if (cursor === fns.length) return

				var fn = fns[cursor++]
				if (fn.length > 0) {
					var timeout = 0, delay = 40, s = new Date
					var isDone = false
					var body = fn.toString()
					var arg = (body.match(/\(([\w_$]+)/) || body.match(/([\w_$]+)\s*=>/) || []).pop()
					if (body.indexOf(arg) === body.lastIndexOf(arg)) throw new Error("`" + arg + "()` should be called at least once")
					try {
						fn(function done() {
							if (timeout !== undefined) {
								timeout = clearTimeout(timeout)
								if (delay !== Infinity) record(null)
								if (!isDone) next()
								else throw new Error("`" + arg + "()` should only be called once")
								isDone = true
							}
							else console.log("# elapsed: " + Math.round(new Date - s) + "ms, expected under " + delay + "ms")
						}, function(t) {delay = t})
					}
					catch (e) {
						record(e.message, e)
						next()
					}
					if (timeout === 0) {
						timeout = setTimeout(function() {
							timeout = undefined
							record("async test timed out")
							next()
						}, Math.min(delay, 2147483647))
					}
				}
				else {
					fn()
					if (stack < 5000) next()
					else (hasProcess ? process.nextTick : setTimeout)(next, stack = 0)
				}
			}
		}
	}
	function hook(name) {
		return function(predicate) {
			if (ctx[name]) throw new Error("This hook should be defined outside of a loop or inside a nested test group:\n" + predicate)
			ctx[name] = predicate
		}
	}

	define("equals", "should equal", function(a, b) {return a === b})
	define("notEquals", "should not equal", function(a, b) {return a !== b})
	define("deepEquals", "should deep equal", deepEqual)
	define("notDeepEquals", "should not deep equal", function(a, b) {return !deepEqual(a, b)})

	function isArguments(a) {
		if ("callee" in a) {
			for (var i in a) if (i === "callee") return false
			return true
		}
	}
	function deepEqual(a, b) {
		if (a === b) return true
		if (a === null ^ b === null || a === undefined ^ b === undefined) return false
		if (typeof a === "object" && typeof b === "object") {
			var aIsArgs = isArguments(a), bIsArgs = isArguments(b)
			if (a.constructor === Object && b.constructor === Object && !aIsArgs && !bIsArgs) {
				for (var i in a) {
					if (!deepEqual(a[i], b[i])) return false
				}
				for (var i in b) {
					if (!(i in a)) return false
				}
				return true
			}
			if (a.length === b.length && (a instanceof Array && b instanceof Array || aIsArgs && bIsArgs)) {
				for (var i = 0; i < a.length; i++) {
					if (!deepEqual(a[i], b[i])) return false
				}
				return true
			}
			if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime()
			if (typeof Buffer === "function" && a instanceof Buffer && b instanceof Buffer) {
				for (var i = 0; i < a.length; i++) {
					if (a[i] !== b[i]) return false
				}
				return true
			}
			if (a.valueOf() === b.valueOf()) return true
		}
		return false
	}

	function Assert(value) {this.value = value}
	function define(name, verb, compare) {
		Assert.prototype[name] = function assert(value) {
			if (compare(this.value, value)) record(null)
			else record(serialize(this.value) + " " + verb + " " + serialize(value))
			return function(message) {
				var result = results[results.length - 1]
				result.message = message + "\n\n" + result.message
			}
		}
	}
	function record(message, error) {
		var result = {pass: message === null}
		if (result.pass === false) {
			if (error == null) {
				error = new Error
				if (error.stack === undefined) new function() {try {throw error} catch (e) {error = e}}
			}
			result.context = subjects.join(" > ")
			result.message = message
			result.error = error.stack
		}
		results.push(result)
	}
	function serialize(value) {
		if (value === null || typeof value === "object") return String(value)
		else if (typeof value === "function") return value.name || "<anonymous function>"
		try {return JSON.stringify(value)} catch (e) {return String(value)}
	}
	function highlight(message) {
		return hasProcess ? "\x1b[31m" + message + "\x1b[0m" : "%c" + message + "%c "
	}

	function report() {
		for (var i = 0, r; r = results[i]; i++) {
			if (!r.pass) {
				var stackTrace = r.error.match(/^(?:(?!Error|[\/\\]ospec[\/\\]ospec\.js).)*$/m)
				console.error(r.context + ": " + highlight(r.message) + (stackTrace ? "\n\n" + stackTrace + "\n\n" : ""), hasProcess ? "" : "color:red", hasProcess ? "" : "color:black")
			}
		}
		console.log(results.length + " assertions completed in " + Math.round(new Date - start) + "ms")
	}

	return o
}<commit_msg>exit on error<commit_after>"use strict"

module.exports = new function init() {
	var spec = {}, subjects = [], results = [], only = null, ctx = spec, start, stack = 0, hasProcess = typeof process === "object"

	function o(subject, predicate) {
		ctx[subject] = predicate
		if (predicate === undefined) return new Assert(subject)
	}
	o.before = hook("__before")
	o.after = hook("__after")
	o.beforeEach = hook("__beforeEach")
	o.afterEach = hook("__afterEach")
	o.new = init
	o.spec = function(subject, predicate) {
		var parent = ctx
		ctx = ctx[subject] = {}
		predicate()
		ctx = parent
	}
	o.only = function(subject, predicate) {o(subject, only = predicate)}
	o.spy = function() {
		var spy = function() {
			spy.this = this
			spy.args = [].slice.call(arguments)
			spy.callCount++
		}
		spy.args = []
		spy.callCount = 0
		return spy
	}
	o.run = function() {
		start = new Date
		test(spec, [], [], report)

		function test(spec, pre, post, finalize) {
			pre = [].concat(pre, spec["__beforeEach"] || [])
			post = [].concat(spec["__afterEach"] || [], post)
			series([].concat(spec["__before"] || [], Object.keys(spec).map(function(key) {
				return function(done, timeout) {
					timeout(Infinity)

					if (key.slice(0, 2) === "__") return done()
					if (only !== null && spec[key] !== only && typeof only === typeof spec[key]) return done()
					subjects.push(key)
					var type = typeof spec[key]
					if (type === "object") test(spec[key], pre, post, pop)
					if (type === "function") series([].concat(pre, spec[key], post, pop))

					function pop() {
						subjects.pop()
						done()
					}
				}
			}), spec["__after"] || [], finalize))
		}

		function series(fns) {
			var cursor = 0
			next()

			function next() {
				stack++
				if (cursor === fns.length) return

				var fn = fns[cursor++]
				if (fn.length > 0) {
					var timeout = 0, delay = 40, s = new Date
					var isDone = false
					var body = fn.toString()
					var arg = (body.match(/\(([\w_$]+)/) || body.match(/([\w_$]+)\s*=>/) || []).pop()
					if (body.indexOf(arg) === body.lastIndexOf(arg)) throw new Error("`" + arg + "()` should be called at least once")
					try {
						fn(function done() {
							if (timeout !== undefined) {
								timeout = clearTimeout(timeout)
								if (delay !== Infinity) record(null)
								if (!isDone) next()
								else throw new Error("`" + arg + "()` should only be called once")
								isDone = true
							}
							else console.log("# elapsed: " + Math.round(new Date - s) + "ms, expected under " + delay + "ms")
						}, function(t) {delay = t})
					}
					catch (e) {
						record(e.message, e)
						next()
					}
					if (timeout === 0) {
						timeout = setTimeout(function() {
							timeout = undefined
							record("async test timed out")
							next()
						}, Math.min(delay, 2147483647))
					}
				}
				else {
					fn()
					if (stack < 5000) next()
					else (hasProcess ? process.nextTick : setTimeout)(next, stack = 0)
				}
			}
		}
	}
	function hook(name) {
		return function(predicate) {
			if (ctx[name]) throw new Error("This hook should be defined outside of a loop or inside a nested test group:\n" + predicate)
			ctx[name] = predicate
		}
	}

	define("equals", "should equal", function(a, b) {return a === b})
	define("notEquals", "should not equal", function(a, b) {return a !== b})
	define("deepEquals", "should deep equal", deepEqual)
	define("notDeepEquals", "should not deep equal", function(a, b) {return !deepEqual(a, b)})

	function isArguments(a) {
		if ("callee" in a) {
			for (var i in a) if (i === "callee") return false
			return true
		}
	}
	function deepEqual(a, b) {
		if (a === b) return true
		if (a === null ^ b === null || a === undefined ^ b === undefined) return false
		if (typeof a === "object" && typeof b === "object") {
			var aIsArgs = isArguments(a), bIsArgs = isArguments(b)
			if (a.constructor === Object && b.constructor === Object && !aIsArgs && !bIsArgs) {
				for (var i in a) {
					if (!deepEqual(a[i], b[i])) return false
				}
				for (var i in b) {
					if (!(i in a)) return false
				}
				return true
			}
			if (a.length === b.length && (a instanceof Array && b instanceof Array || aIsArgs && bIsArgs)) {
				for (var i = 0; i < a.length; i++) {
					if (!deepEqual(a[i], b[i])) return false
				}
				return true
			}
			if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime()
			if (typeof Buffer === "function" && a instanceof Buffer && b instanceof Buffer) {
				for (var i = 0; i < a.length; i++) {
					if (a[i] !== b[i]) return false
				}
				return true
			}
			if (a.valueOf() === b.valueOf()) return true
		}
		return false
	}

	function Assert(value) {this.value = value}
	function define(name, verb, compare) {
		Assert.prototype[name] = function assert(value) {
			if (compare(this.value, value)) record(null)
			else record(serialize(this.value) + " " + verb + " " + serialize(value))
			return function(message) {
				var result = results[results.length - 1]
				result.message = message + "\n\n" + result.message
			}
		}
	}
	function record(message, error) {
		var result = {pass: message === null}
		if (result.pass === false) {
			if (error == null) {
				error = new Error
				if (error.stack === undefined) new function() {try {throw error} catch (e) {error = e}}
			}
			result.context = subjects.join(" > ")
			result.message = message
			result.error = error.stack
		}
		results.push(result)
	}
	function serialize(value) {
		if (value === null || typeof value === "object") return String(value)
		else if (typeof value === "function") return value.name || "<anonymous function>"
		try {return JSON.stringify(value)} catch (e) {return String(value)}
	}
	function highlight(message) {
		return hasProcess ? "\x1b[31m" + message + "\x1b[0m" : "%c" + message + "%c "
	}

	function printInfo() {
		var total = results.length
		var completed = total - subjects.length
		console.log(completed + " out of " + total + " assertions completed in " + Math.round(new Date - start) + "ms")
	}

	function report() {
		for (var i = 0, r; r = results[i]; i++) {
			if (!r.pass) {
				var stackTrace = r.error.match(/^(?:(?!Error|[\/\\]ospec[\/\\]ospec\.js).)*$/m)
				console.error(r.context + ": " + highlight(r.message) + (stackTrace ? "\n\n" + stackTrace + "\n\n" : ""), hasProcess ? "" : "color:red", hasProcess ? "" : "color:black")
				printInfo()
				process.exit(1)
			}
		}
		printInfo()
	}

	return o
}
<|endoftext|>


<commit_before>'use strict'
const Output = use('output')

function letterCount (nn) {
  let base = Math.floor((nn-1) / 26)
  let num = (nn-1) % 26
  return (base > 0 ? String.fromCharCode(96 + base) : '') +
    String.fromCharCode(97 + num)
}

function upperLetterCount (nn) {
  let base = Math.floor((nn-1) / 26)
  let num = (nn-1) % 26
  return (base > 0 ? String.fromCharCode(64 + base) : '') +
    String.fromCharCode(65 + num)
}

class OutputEpub extends Output {
  from (fic) {
    const filenameize = use('filenameize')
    return super.from(fic).to(filenameize(fic.title) + '.epub')
  }

  chapterExt () {
    return '.xhtml'
  }

  write () {
    const Streampub = require('streampub')
    const statusRe = /^status:(stalled|abandoned|complete|one-shot)$/
    const fandomRe = /^fandom:/
    let tags = this.fic.tags && this.fic.tags.filter(tag => !fandomRe.test(tag) && !statusRe.test(tag))
    let modified = this.fic.modified || this.fic.started || this.fic.created
    let status = this.fic.tags && this.fic.tags.filter(tag => statusRe.test(tag))[0]
    if (status) status = status.replace(/^status:/, '')
    if (!status && modified) {
      const now = new Date()
      const oneMonth = 86400*30*1000
      const sixMonths = 86400*182*1000
      if (now - modified > sixMonths) {
        status = 'abandoned'
      } else if (now - modified > oneMonth) {
        status = 'stalled'
      } else {
        status = 'in-progress'
      }
    }
    let fandom = this.fic.tags && this.fic.tags.filter(tag => fandomRe.test(tag)).map(tag => tag.replace(fandomRe, ''))[0]
    const epub = new Streampub({
      id: this.fic.id,
      title: this.fic.title,
      author: this.fic.author,
      authorUrl: this.fic.authorUrl,
      description: this.fic.description,
      source: this.fic.link,
      subject: tags && tags.length && tags.join(','),
      publisher: this.fic.publisher,
      published: this.fic.started || this.fic.created || this.fic.modified,
      modified: modified,
      calibre: {
        'updated': modified && {'#value#': modified.toISOString().slice(0,10), 'datatype': 'text'},
        'words': {'#value#': this.fic.words, 'datatype': 'int'},
        'authorurl': {'#value#': this.fic.authorUrl, 'datatype': 'text'},
        'status': status && {'#value#': status, 'datatype': 'enumeration'},
        'fandom': fandom && {'#value#': fandom, 'datatype': 'text'}
      }
    })

    let title = 'Title Page'
    if (this.fic.numberTOC) title = 'ⅰ. ' + title
    epub.write(Streampub.newChapter(title, this.titlePageHTML(), 0, 'top.xhtml'))
    if (this.fic.includeTOC) {
      let toctitle = 'Table of Contents'
      if (this.fic.numberTOC) toctitle = 'ⅱ. ' + toctitle
      epub.write(Streampub.newChapter(toctitle, this.tableOfContentsHTML(), 1, 'toc.xhtml'))
    }
    const WriteStreamAtomic = require('fs-write-stream-atomic')
    const output = new WriteStreamAtomic(this.outname)
    const pump = use('pump')
    return pump(
      this.fic,
      this.transform(),
      epub,
      output).then(() => this.outname)
  }

  transformChapter (chapter) {
    const Streampub = require('streampub')
    if (chapter.outputType === 'image') {
      return Streampub.newFile(chapter.filename, chapter.content)
    }
    if (chapter.outputType === 'cover') {
      return Streampub.newCoverImage(chapter.content)
    }
    const index = chapter.order != null && (1 + chapter.order)
    let name = chapter.name
    if (name != null && this.fic.numberTOC) {
      if (index >= 9000) {
        name = upperLetterCount(index - 9000) + '. ' + name
      } else if (index >= 8000) {
        name = letterCount(index - 8000) + '. ' + name
      } else {
        name = String(index) + '. ' + name
        if (chapter.author && chapter.author != this.fic.author) {
          name += ` (${chapter.author})`
        }
      }
    }
    const filename = this.chapterFilename(chapter)
    const html = use('html-template-tag')
    const toSanitize = '\n' +
      (name ? html`<head><title>${name}</title></head>` : '') +
      '
' + chapter.content + '
\n' +
      '\n'
    return Streampub.newChapter(name, this.prepareHtml(toSanitize), 100 + index, filename)
  }

  prepareHtml (html) {
    // remove any doc-wide stylesheet so we can do our styling.
    return super.prepareHtml(html.replace(/


<commit_before>var elf     = require( "../../lib/elf" )
  , should  = require( "should"        )
  , stream  = require( "stream"        )
  , events  = require( "events"        )
  ;

describe ('REPL', function () {
  var repl;
  beforeEach(function () {
    repl = elf.REPL.clone();
  });

  describe ('defaults', function () {
    describe ('reader', function () {
      it ('defaults to readline', function () {
        repl.reader.should.eql(require('readline'));
      });
    });

    describe ('in', function () {
      it ('defaults to process.stdin', function () {
        repl.in.should.eql(process.stdin);
      });
    });

    describe ('out', function () {
      it ('defaults to process.stdout', function () {
        repl.out.should.eql(process.stdout);
      });
    });

    describe ('colorize', function () {
      it ('defaults to sys.inspect', function () {
        repl.colorize.toString().should.match(/return sys\.inspect\(expr\, false\, null\, true\)/)
      })
    });

    describe ('eval', function () {
      it ('defaults to a wrapper for the regular js eval', function () {
        repl.eval('23').should.eql(23);
      });
    })

    describe ('prompt', function () {
      it ('defaults to > ', function () {
        repl.prompt.should.eql("> ");
      });
    });

    describe ("completer", function () {
      it ("should return an empty array of matches if no completions are found", function () {
        repl.completer("f")[0].should.eql([])
      })

      it ("should return an array of matches based on the current env", function () {
        repl.env[ "split"  ] = "foo";
        repl.env[ "splice" ] = "foo";
        repl.env[ "foo"    ] = "foo";

        repl.completer("spl")[0].should.eql(["split", "splice"]);
        repl.completer("f")[0].should.eql(["foo"]);
      })

      it ("should return the substring that was used for matching", function () {
        repl.completer("spl")[1].should.eql("spl");
      })
    });
  });
});<commit_msg>added semicolons<commit_after>var elf     = require( "../../lib/elf" )
  , should  = require( "should"        )
  , stream  = require( "stream"        )
  , events  = require( "events"        )
  ;

describe ('REPL', function () {
  var repl;
  beforeEach(function () {
    repl = elf.REPL.clone();
  });

  describe ('defaults', function () {
    describe ('reader', function () {
      it ('defaults to readline', function () {
        repl.reader.should.eql(require('readline'));
      });
    });

    describe ('in', function () {
      it ('defaults to process.stdin', function () {
        repl.in.should.eql(process.stdin);
      });
    });

    describe ('out', function () {
      it ('defaults to process.stdout', function () {
        repl.out.should.eql(process.stdout);
      });
    });

    describe ('colorize', function () {
      it ('defaults to sys.inspect', function () {
        repl.colorize.toString().should.match(/return sys\.inspect\(expr\, false\, null\, true\)/)
      })
    });

    describe ('eval', function () {
      it ('defaults to a wrapper for the regular js eval', function () {
        repl.eval('23').should.eql(23);
      });
    })

    describe ('prompt', function () {
      it ('defaults to > ', function () {
        repl.prompt.should.eql("> ");
      });
    });

    describe ("completer", function () {
      it ("should return an empty array of matches if no completions are found", function () {
        repl.completer("f")[0].should.eql([]);
      });

      it ("should return an array of matches based on the current env", function () {
        repl.env[ "split"  ] = "foo";
        repl.env[ "splice" ] = "foo";
        repl.env[ "foo"    ] = "foo";

        repl.completer("spl")[0].should.eql(["split", "splice"]);
        repl.completer("f")[0].should.eql(["foo"]);
      });

      it ("should return the substring that was used for matching", function () {
        repl.completer("spl")[1].should.eql("spl");
      });
    });
  });
});<|endoftext|>


<commit_before>// Set the test environment
process.env.NODE_ENV = 'test';

// Dependencies
var exec = require('child_process').exec,
    fs = require('fs'),
    version = require('../package.json').version,
    request = require('request');

// Helper function to exectue the sickmerge cli
function execSickmerge (options, callback) {
    exec('sickmerge ' + options, function(err, stdout) {
        console.log(stdout);
        callback(stdout);
    });
}

// Tests
describe('Sickmerge', function() {
    it('should be present', function(done) {
        fs.readFile('./sickmerge.js', function(err, response) {
            expect(err).toBe(null);
            done();
        });
    });

    // Testing command line options (help/version/errors)
    describe('command line options', function() {
        it('should output help when no options are passed', function(done) {
            execSickmerge('', function(response) {
                expect(response).toEqual(jasmine.any(String));
                done();
            });
        });
        it('should prompt an error message when an invalid file is passed', function(done) {
            execSickmerge('notafile', function(response) {
                expect(response).toContain('There was an error loading your file!');
                done();
            });
        });
        it('should print the version when using -V or --version', function(done) {
            execSickmerge('-V', function(response) {
                expect(response).toContain(version.toString());
                execSickmerge('--version', function(response) {
                    expect(response).toContain(version.toString());
                    done();
                });
            });
        });
        it('should print available syntaxes when using -o or --syntaxes', function(done) {
            execSickmerge('-o', function(response) {
                expect(response).toContain('Available options include:');
                execSickmerge('--syntaxes', function(response) {
                    expect(response).toContain('Available options include:');
                    done();
                });
            });
        });
        it('should print an error message when an invalid merge pattern is passed', function(done) {
            execSickmerge('-m fake ./spec/fixtures/javascript.js', function(response) {
                expect(response).toContain("You've specified an invalid initial merged view");
                done();
            });
        });
    });
});<commit_msg>Removing testing console, unused<commit_after>// Set the test environment
process.env.NODE_ENV = 'test';

// Dependencies
var exec = require('child_process').exec,
    fs = require('fs'),
    version = require('../package.json').version,
    request = require('request');

// Helper function to exectue the sickmerge cli
function execSickmerge (options, callback) {
    exec('sickmerge ' + options, function(err, stdout) {
        callback(stdout);
    });
}

// Tests
describe('Sickmerge', function() {
    it('should be present', function(done) {
        fs.readFile('./sickmerge.js', function(err, response) {
            expect(err).toBe(null);
            done();
        });
    });

    // Testing command line options (help/version/errors)
    describe('command line options', function() {
        it('should output help when no options are passed', function(done) {
            execSickmerge('', function(response) {
                expect(response).toEqual(jasmine.any(String));
                done();
            });
        });
        it('should prompt an error message when an invalid file is passed', function(done) {
            execSickmerge('notafile', function(response) {
                expect(response).toContain('There was an error loading your file!');
                done();
            });
        });
        it('should print the version when using -V or --version', function(done) {
            execSickmerge('-V', function(response) {
                expect(response).toContain(version.toString());
                execSickmerge('--version', function(response) {
                    expect(response).toContain(version.toString());
                    done();
                });
            });
        });
        it('should print available syntaxes when using -o or --syntaxes', function(done) {
            execSickmerge('-o', function(response) {
                expect(response).toContain('Available options include:');
                execSickmerge('--syntaxes', function(response) {
                    expect(response).toContain('Available options include:');
                    done();
                });
            });
        });
        it('should print an error message when an invalid merge pattern is passed', function(done) {
            execSickmerge('-m fake ./spec/fixtures/javascript.js', function(response) {
                expect(response).toContain("You've specified an invalid initial merged view");
                done();
            });
        });
    });
});<|endoftext|>


<commit_before>if(Object.prototype.isEmpty === undefined) {
  Object.prototype.isEmpty = function(o) {
    return Object.keys(o).reduce((p, n) => n ? p+1 : p, 0) <= 0;
  };
}

if(Object.prototype.isObject === undefined) {
  Object.prototype.isObject = function(o) {
    if(typeof(o) !== "object") return false;
    else if(Array.isArray(o) || o === null) return false;
    else return true;
  };
}

if(Object.prototype.isEqual === undefined) {
  Object.prototype.isEqual = function(o1, o2) {
    const keysO1 = Object.keys(o1);
    const keysO2 = Object.keys(o2);

    // Ensure they're in the same order.
    keysO1.sort();
    keysO2.sort();

    // They're both empty.
    if(Object.isEmpty(o1) && Object.isEmpty(o2)) return true;

    // Have different sets of keys.
    if(keysO1.toString() !== keysO2.toString()) return false;

    // Values within the keys are different.
    return keysO1.every((elm, count, arr) => o1[elm] === o2[elm]);
  };
}
<commit_msg>Added a check for parameters being objects.<commit_after>if(Object.prototype.isEmpty === undefined) {
  Object.prototype.isEmpty = function(o) {
    return Object.keys(o).reduce((p, n) => n ? p+1 : p, 0) <= 0;
  };
}

if(Object.prototype.isObject === undefined) {
  Object.prototype.isObject = function(o) {
    if(typeof(o) !== "object") return false;
    else if(Array.isArray(o) || o === null) return false;
    else return true;
  };
}

if(Object.prototype.isEqual === undefined) {
  Object.prototype.isEqual = function(o1, o2) {
    if(!Object.isObject(o1) || !Object.isObject(o2)) return false;
    const keysO1 = Object.keys(o1);
    const keysO2 = Object.keys(o2);

    // Ensure they're in the same order.
    keysO1.sort();
    keysO2.sort();

    // They're both empty.
    if(Object.isEmpty(o1) && Object.isEmpty(o2)) return true;

    // Have different sets of keys.
    if(keysO1.toString() !== keysO2.toString()) return false;

    // Values within the keys are different.
    return keysO1.every((elm, count, arr) => o1[elm] === o2[elm]);
  };
}
<|endoftext|>


<commit_before>/**
 * PUBSUB
 *
 * PubSub is a JS implementation of a publication/subscription pattern in JS
 * using vanilla JS.
 *
 * Subscibe:
 *   PubSub.subscribe('App.loaded', function () {});
 *   PubSub.subscribe('App.done', [App.loadStack, App.clock]);
 *
 * Unsubscribe:
 *   PubSub.unsubscribe('App.done', App.loadStack);
 *
 * Publish:
 *   PubSub.publish('App.loaded');
 *   PubSub.publish('App.loaded', { data: App.data });
 *
 */
void function (global) {

  /**
   * Object to store all functions and data
   * @type {Object}
   */
  var PubSub = {};

  /**
   * Storage for functions and events
   * @type {Object}
   */
  PubSub._storage = {};

  /**
   * Public API
   */

  /**
   * Subscribe funtions by mapping them to events
   * @param  {String}         type      Event type
   * @param  {Function|Array} functions Function or array of functions to subscribe to event
   * @return {void}
   */
  PubSub.subscribe = function (type, functions) {
    var i = 0;

    // If `functions` is not an array, make it one
    if (!functions.length) {
      functions = [functions];
    }

    // Add subsciption name to storage
    if (!PubSub._storage[type]) {
      PubSub._storage[type] = [];
    }

    for (; i < functions.length; i++) {
      PubSub._storage[type].push(functions[i]);
    }
  };

  /**
   * Unsubscribe a functions form an event
   * @param  {String}         type      Event type
   * @param  {Function|Array} functions Functions to unsubscribe from event
   * @return {void}
   */
  PubSub.unsubscribe = function (type, functions) {
    var index;
    var i = 0;

    // If `functions` is not an array, make it one
    if (!functions.length) {
      functions = [functions];
    }

    // If the type does not exist, throw an error
    if (!PubSub._storage[type]) {
      throw new Error('Type ' + type + ' does not exist.');
    }

    for (; i < functions.length; i++) {
      index = PubSub._storage[type].indexOf(functions[i]);

      PubSub._storage[type].splice(index, 1);
    }
  };

  /**
   * Call functions subscribed to an event
   * If you want to publish multiple events, call PubSub.publish multiple times.
   *
   * @param  {String} type Event type to publish
   * @param  {Object} data Data to send with publish event
   * @return {void}
   */
  PubSub.publish = function (type, data) {
    var i = 0;

    if (!PubSub._storage[type]) {
      return;
    }

    for (; i < PubSub._storage[type].length; i++) {
      PubSub._storage[type][i](data);
    }
  };

  /*
   * AMD, module loader, global registration
   */

  // Expose loaders that implement the Node module pattern.
  if (typeof module === 'object' && module && typeof module.exports === 'object') {
    module.exports = PubSub;

  // Register as an AMD module
  } else if (typeof define === 'function' && define.amd) {
    define('PubSub', [], function () {
      return PubSub;
    });

  // Export into global space
  } else if (typeof global === 'object' && typeof global.document === 'object') {
    global.PubSub = PubSub;
  }
}(this);
<commit_msg>Subscribe: Add check if passed argument is a function<commit_after>/**
 * PUBSUB
 *
 * PubSub is a JS implementation of a publication/subscription pattern in JS
 * using vanilla JS.
 *
 * Subscibe:
 *   PubSub.subscribe('App.loaded', function () {});
 *   PubSub.subscribe('App.done', [App.loadStack, App.clock]);
 *
 * Unsubscribe:
 *   PubSub.unsubscribe('App.done', App.loadStack);
 *
 * Publish:
 *   PubSub.publish('App.loaded');
 *   PubSub.publish('App.loaded', { data: App.data });
 *
 */
void function (global) {

  /**
   * Object to store all functions and data
   * @type {Object}
   */
  var PubSub = {};

  /**
   * Storage for functions and events
   * @type {Object}
   */
  PubSub._storage = {};

  /**
   * Public API
   */

  /**
   * Subscribe funtions by mapping them to events
   * @param  {String}         type      Event type
   * @param  {Function|Array} functions Function or array of functions to subscribe to event
   * @return {void}
   */
  PubSub.subscribe = function (type, functions) {
    var i = 0;

    // If `functions` is not an array, make it one
    if (!functions.length) {
      functions = [functions];
    }

    // Add subsciption name to storage
    if (!PubSub._storage[type]) {
      PubSub._storage[type] = [];
    }

    for (; i < functions.length; i++) {
      if (typeof(functions[i]) === 'function') {
        PubSub._storage[type].push(functions[i]);
      }
    }
  };

  /**
   * Unsubscribe a functions form an event
   * @param  {String}         type      Event type
   * @param  {Function|Array} functions Functions to unsubscribe from event
   * @return {void}
   */
  PubSub.unsubscribe = function (type, functions) {
    var index;
    var i = 0;

    // If `functions` is not an array, make it one
    if (!functions.length) {
      functions = [functions];
    }

    // If the type does not exist, throw an error
    if (!PubSub._storage[type]) {
      throw new Error('Type ' + type + ' does not exist.');
    }

    for (; i < functions.length; i++) {
      index = PubSub._storage[type].indexOf(functions[i]);

      PubSub._storage[type].splice(index, 1);
    }
  };

  /**
   * Call functions subscribed to an event
   * If you want to publish multiple events, call PubSub.publish multiple times.
   *
   * @param  {String} type Event type to publish
   * @param  {Object} data Data to send with publish event
   * @return {void}
   */
  PubSub.publish = function (type, data) {
    var i = 0;

    if (!PubSub._storage[type]) {
      return;
    }

    for (; i < PubSub._storage[type].length; i++) {
      PubSub._storage[type][i](data);
    }
  };

  /*
   * AMD, module loader, global registration
   */

  // Expose loaders that implement the Node module pattern.
  if (typeof module === 'object' && module && typeof module.exports === 'object') {
    module.exports = PubSub;

  // Register as an AMD module
  } else if (typeof define === 'function' && define.amd) {
    define('PubSub', [], function () {
      return PubSub;
    });

  // Export into global space
  } else if (typeof global === 'object' && typeof global.document === 'object') {
    global.PubSub = PubSub;
  }
}(this);
<|endoftext|>


<commit_before>"use strict";

let PageCustom = Vue.component(
	'page-custom',
	{
		template: `

Custom orders

I am currently accepting commissions and other custom orders! Commissions are expected to continue through October 2017 for fan art and mid-2018 for everything else.

Current Commission Slots:

1. rock

2. tseng

3. empty!

4. empty!

5. empty!

Types of Commissions

Fan Art: Any character from a commercial franchise. (See the General Catalog.) Characters can be from anime, comics, games, television shows, movies, or anything else provided the parent company (and rights holder) is tolerant of fan art. This category is for characters that have a broad fanbase and that could be sold in the Artist Alley at anime conventions.

OCs: Short for “original characters,” this category includes any original design of your own, including self-insert characters for commercial franchises. Common examples include fursonas, MLP ponysonas, and customized characters for popular anime. These are unique characters of your own design that would not be sold in the Artist Alley at anime conventions.

People [head only]: This category is for drawings made from photos of you or anyone else you know in real life. For the time being, I will only draw heads from photos like this, meaning you will have to use bodies from other characters (to “cosplay”).

Pets / Animals: I will draw your pet or a generic animal in a mini size.

Color Edits: Any already-existing drawing can have its colors altered. (Lineart alterations count as a new commission in one of the above categories, though a reduced rate may be arranged depending on the scope of the alteration.)

Other Special Orders: Other requests will be handled the same way as the next most-similar commission. E.g., a head-on-body non-decapitation order will be handled and charged like a POD magnet order.

Prices

							Size
							POD
							Drawing
							Cost
							Bulk Rate
							Bulk Cost
							Examples

							Fan Art
							large
							no
							$40
							$4

							Sephiroth, Vash the Stampede

							mini
							no
							$30
							$2

							Tony Tony Chopper, Raichu

							OCs
							large
							yes
							$60
							$6
							6+
							$5
							a fursona, a DnD character

							People [head only]
							large
							yes
							$25
							$4
							10+
							$3
							you, your fiance, your children, your BFF

							Pets / Animals
							mini
							yes
							$30
							$4
							12+
							$3
							my pet dog, a Red-tailed Hawk

							Color Edits
							large
							yes
							$10
							$6
							6+
							$5
							game pallet swaps, hair “dye”

							mini
							yes
							$10
							$4
							12+
							$3
							shiny Pokemon, pet breed color variations

Remember that shipping is not included in the above chart, and will be at the regular rates. (See the Order section for current rates.)

Size: Cosplay Scramble magnets come in two sizes: large and small/mini. Generally humans and humanoids are the large size, while animals or small creatures, like Pokemon, are the small size.

POD: This column indicates whether magnets are print-on-demand (as opposed to pre-made). Print-on-demand magnets are not made until ordered, and are hand cut unless ordered in bulk.

Drawing: This is how much it costs to get the drawing made. The drawing cost also includes one copy of the finished drawing as a cut magnet.

Cost: The first magnet is free, so this column is the cost of each magnet after the first if you want more than one. Special cases can be made for POD magnets that are ordered in bulk, which can be cost-effectively cut by machine. For the purposes of ordering in bulk, POD magnets that have the same cuttable outline count toward the total.

Examples: Some examples of each category.

Commission Procedure

Each commissions slot allows someone to commission up to three new characters. Note that slots may be finished out of order depending on the drawings’ difficulty.

While I may decline or delay the commission due to subject matter or logistics issues, I will try to get as many done as I can this year. In advance I will say that I won’t draw anything controversial (i.e. lewd, politically charged, excessively violent).

There are limitations on poses and characters due to the format, so arms cannot be above the character’s head and thin pieces like tails or antenna will have to be thickened so the magnet won’t break off. In addition, Cosplay Scramble magnets cannot be made from characters without a workable jawline, such as characters whose entire body is their head (e.g. Jigglypuff) or bulky characters without anything resembling the anatomy of a neck (e.g. Totoro).

Reserve a Slot

To reserve a slot, email me with the words “reserve a slot” in the subject line.

I’ll also need to know who or what you’d like me to draw. If your commission is fan art, you’ll need to let me know if there’s a specific outfit you would prefer. If your commission is an original character, I’ll need head-to-toe reference. Attach or link any relevant images at this step. I might have questions about specific details, particularly for characters from franchises I’m not familiar with.

If you have any special requests, let me know at this point in case it will affect the final price. Special requests can include custom packaging (perhaps for a party), shipping to multiple addresses, non-decapitation, etc.

Once we’ve agreed on what I will be drawing, your slot is reserved! I will pick a codeword to represent your order in the Commissions Slot list above.

Payment

Once I’ve agreed to your commission, I will send a Paypal invoice to your email address. Paypal will let you pay in several ways, including with a credit card, so you won’t need a Paypal account to pay. The shipping rates are the same as for a general order — see the Order section for current shipping prices.

(Magnets from the General Catalog can be ordered and shipped with your commission. Just let me know which sets you want, and I’ll include them on the invoice. You’ll receive all ordered magnets together.)

You may cancel your commission at any point, but the refund may be reduced depending on how far along I am. (E.g., if I haven’t started drawing yet you will get a full refund, but if I am done drawing but haven’t made the magnet yet you will only get the magnet manufacturing cost back.)

I do insist that the full commission cost is paid in advance. If payment takes too long, there’s a good change I will ask you to give up your slot (at least for the moment) so that others may have a turn.

Production

Once payment clears, I’ll begin. Note: because some commissions will be more difficult than others, I may finish them out of order. I want them all to turn out well, and sometimes I need extra time to make sure I get them right.

When I’m done drawing, I’ll send you the finished image to see what you think. I can still make changes at this point, so it’s important to make sure I got everything about the character correct. (If I haven’t seen the anime the character is from, for example, I might miss an important detail.) Then, once we are both satisfied, I will print, magnet-ify, and cut the finished drawing(s). I’ll ship them as soon as they’re done, you’ll receive them in the mail!

Fan art commissions will appear in the General Catalog at this point, and will also be available at any future conventions (while supplies last).

Contact

Questions? Send me an email me or convo me on Etsy.

		`
	}
);
<commit_msg>typo (my > your)<commit_after>"use strict";

let PageCustom = Vue.component(
	'page-custom',
	{
		template: `

Custom orders

I am currently accepting commissions and other custom orders! Commissions are expected to continue through October 2017 for fan art and mid-2018 for everything else.

Current Commission Slots:

1. rock

2. tseng

3. empty!

4. empty!

5. empty!

Types of Commissions

Fan Art: Any character from a commercial franchise. (See the General Catalog.) Characters can be from anime, comics, games, television shows, movies, or anything else provided the parent company (and rights holder) is tolerant of fan art. This category is for characters that have a broad fanbase and that could be sold in the Artist Alley at anime conventions.

OCs: Short for “original characters,” this category includes any original design of your own, including self-insert characters for commercial franchises. Common examples include fursonas, MLP ponysonas, and customized characters for popular anime. These are unique characters of your own design that would not be sold in the Artist Alley at anime conventions.

People [head only]: This category is for drawings made from photos of you or anyone else you know in real life. For the time being, I will only draw heads from photos like this, meaning you will have to use bodies from other characters (to “cosplay”).

Pets / Animals: I will draw your pet or a generic animal in a mini size.

Color Edits: Any already-existing drawing can have its colors altered. (Lineart alterations count as a new commission in one of the above categories, though a reduced rate may be arranged depending on the scope of the alteration.)

Other Special Orders: Other requests will be handled the same way as the next most-similar commission. E.g., a head-on-body non-decapitation order will be handled and charged like a POD magnet order.

Prices

							Size
							POD
							Drawing
							Cost
							Bulk Rate
							Bulk Cost
							Examples

							Fan Art
							large
							no
							$40
							$4

							Sephiroth, Vash the Stampede

							mini
							no
							$30
							$2

							Tony Tony Chopper, Raichu

							OCs
							large
							yes
							$60
							$6
							6+
							$5
							a fursona, a DnD character

							People [head only]
							large
							yes
							$25
							$4
							10+
							$3
							you, your fiance, your children, your BFF

							Pets / Animals
							mini
							yes
							$30
							$4
							12+
							$3
							your pet dog, a Red-tailed Hawk

							Color Edits
							large
							yes
							$10
							$6
							6+
							$5
							game pallet swaps, hair “dye”

							mini
							yes
							$10
							$4
							12+
							$3
							shiny Pokemon, pet breed color variations

Remember that shipping is not included in the above chart, and will be at the regular rates. (See the Order section for current rates.)

Size: Cosplay Scramble magnets come in two sizes: large and small/mini. Generally humans and humanoids are the large size, while animals or small creatures, like Pokemon, are the small size.

POD: This column indicates whether magnets are print-on-demand (as opposed to pre-made). Print-on-demand magnets are not made until ordered, and are hand cut unless ordered in bulk.

Drawing: This is how much it costs to get the drawing made. The drawing cost also includes one copy of the finished drawing as a cut magnet.

Cost: The first magnet is free, so this column is the cost of each magnet after the first if you want more than one. Special cases can be made for POD magnets that are ordered in bulk, which can be cost-effectively cut by machine. For the purposes of ordering in bulk, POD magnets that have the same cuttable outline count toward the total.

Examples: Some examples of each category.

Commission Procedure

Each commissions slot allows someone to commission up to three new characters. Note that slots may be finished out of order depending on the drawings’ difficulty.

While I may decline or delay the commission due to subject matter or logistics issues, I will try to get as many done as I can this year. In advance I will say that I won’t draw anything controversial (i.e. lewd, politically charged, excessively violent).

There are limitations on poses and characters due to the format, so arms cannot be above the character’s head and thin pieces like tails or antenna will have to be thickened so the magnet won’t break off. In addition, Cosplay Scramble magnets cannot be made from characters without a workable jawline, such as characters whose entire body is their head (e.g. Jigglypuff) or bulky characters without anything resembling the anatomy of a neck (e.g. Totoro).

Reserve a Slot

To reserve a slot, email me with the words “reserve a slot” in the subject line.

I’ll also need to know who or what you’d like me to draw. If your commission is fan art, you’ll need to let me know if there’s a specific outfit you would prefer. If your commission is an original character, I’ll need head-to-toe reference. Attach or link any relevant images at this step. I might have questions about specific details, particularly for characters from franchises I’m not familiar with.

If you have any special requests, let me know at this point in case it will affect the final price. Special requests can include custom packaging (perhaps for a party), shipping to multiple addresses, non-decapitation, etc.

Once we’ve agreed on what I will be drawing, your slot is reserved! I will pick a codeword to represent your order in the Commissions Slot list above.

Payment

Once I’ve agreed to your commission, I will send a Paypal invoice to your email address. Paypal will let you pay in several ways, including with a credit card, so you won’t need a Paypal account to pay. The shipping rates are the same as for a general order — see the Order section for current shipping prices.

(Magnets from the General Catalog can be ordered and shipped with your commission. Just let me know which sets you want, and I’ll include them on the invoice. You’ll receive all ordered magnets together.)

You may cancel your commission at any point, but the refund may be reduced depending on how far along I am. (E.g., if I haven’t started drawing yet you will get a full refund, but if I am done drawing but haven’t made the magnet yet you will only get the magnet manufacturing cost back.)

I do insist that the full commission cost is paid in advance. If payment takes too long, there’s a good change I will ask you to give up your slot (at least for the moment) so that others may have a turn.

Production

Once payment clears, I’ll begin. Note: because some commissions will be more difficult than others, I may finish them out of order. I want them all to turn out well, and sometimes I need extra time to make sure I get them right.

When I’m done drawing, I’ll send you the finished image to see what you think. I can still make changes at this point, so it’s important to make sure I got everything about the character correct. (If I haven’t seen the anime the character is from, for example, I might miss an important detail.) Then, once we are both satisfied, I will print, magnet-ify, and cut the finished drawing(s). I’ll ship them as soon as they’re done, you’ll receive them in the mail!

Fan art commissions will appear in the General Catalog at this point, and will also be available at any future conventions (while supplies last).

Contact

Questions? Send me an email me or convo me on Etsy.

		`
	}
);
<|endoftext|>