<commit_before>define(['jquery', 'DoughBaseComponent', 'common'], function($, DoughBaseComponent, MAS) {
  'use strict';

  var OnPageFeedback;

  OnPageFeedback = function($el, config) {
    OnPageFeedback.baseConstructor.call(this, $el, config, {});

    this.interactionBtn = $el.find('[data-dough-feedback]');
    this.pages = $el.find('[data-dough-feedback-page]');
    this.shareBtns = $el.find('[data-dough-feedback-share] .social-sharing__item__icon');
    this.submitBtn = $el.find('[data-dough-feedback-submit]');
    this.submitForm = $el.find('[data-dough-feedback-form]');
    this.ajaxUrl = $el.attr('data-dough-on-page-feedback-post');
    this.likeCount = $el.find('[data-dough-feedback-like-count]');
    this.dislikeCount = $el.find('[data-dough-feedback-dislike-count]');
    this.pageId = window.location.pathname.match(/^.*\/([a-zA-Z0-9-_]+)$/)[1];
  };

  DoughBaseComponent.extend(OnPageFeedback);
  OnPageFeedback.componentName = 'OnPageFeedback';

  OnPageFeedback.prototype._submitInteraction = function(interaction) {
    var isLiked = (interaction === 'positive') ? true : false;

    var postObject = {
      liked: isLiked
    };

    var submitInteraction = $.post(this.ajaxUrl, postObject, function(data){
      this._storeLastInteraction(interaction);
      this._showPage(interaction);
      this._updateCount(data);
    }.bind(this))
    .fail(function() {
      MAS.warn('failed to submit like / dislike');
    }.bind(this));
  };

  OnPageFeedback.prototype._share = function(share) {
    var submitShare = $.ajax({
      url: this.ajaxUrl,
      type: 'PATCH',
      data: {'shared_on': share}
    });
    submitShare.fail(function(status){
      MAS.warn('failed to submit share');
    });

    this._storeLastInteraction('share');
    this._showPage('results');
    this._animateResult('like');
  };

  OnPageFeedback.prototype._submitComment = function() {
    var userComment = $('[data-dough-feedback-comment]').val(),
    submitFeedback = $.ajax({
      url: this.ajaxUrl,
      type: 'PATCH',
      data: {'comment': userComment}
    });

    submitFeedback.fail(function(status){
      MAS.warn('failed to submit comment');
    });
    this._storeLastInteraction('comment');
    this._showPage('results');
    this._animateResult('dislike');
  };

  OnPageFeedback.prototype._animateResult = function(interaction) {
    var el,
    total;

    if (interaction === 'like') {
      el = this.likeCount;
    } else {
      el = this.dislikeCount;
    };

    total = parseInt(el.text());
    el.text(total - 1);

    window.setTimeout(function(){
      el.closest('.on-page-feedback__results-item').addClass('is-animating');
    }.bind(this), 300);
    window.setTimeout(function(){
      el.text(total);
    }.bind(this), 600);
  };

  OnPageFeedback.prototype._updateCount = function(data) {
    var countResponse = data;

    this.likeCount.text(countResponse.likes_count);
    this.dislikeCount.text(countResponse.dislikes_count);
  };

  OnPageFeedback.prototype._showPage = function(pageName) {
    this.pages.addClass('is-hidden');
    this.pages.filter('[data-dough-feedback-page=' + pageName + ']').removeClass('is-hidden');
  };

  OnPageFeedback.prototype._storeLastInteraction = function(interaction) {
    localStorage.setItem('MAS.onPageFeedback.' + this.pageId, interaction);
  };

  OnPageFeedback.prototype._checkForStoredState = function() {
    var lastInteraction = localStorage['MAS.onPageFeedback.' + this.pageId];

    if (typeof lastInteraction != 'undefined') {
      switch (lastInteraction) {
        case 'positive':
        case 'negative':
          this._showPage(lastInteraction);
          break;
        case 'share':
        case 'comment':
          this._showPage('results');
          break;
      }
    }
  };

  OnPageFeedback.prototype._bindHandlers = function() {
    var self = this;

    this.interactionBtn.on('click', function(e) {
      e.preventDefault();
      self._submitInteraction($(this).attr('data-dough-feedback'));
    });
    this.shareBtns.on('click', function() {
      self._share($(this).attr('data-dough-shared-on'));
    });
    this.submitForm.on('submit', $.proxy(function(e){
      e.preventDefault;
      // Only submit the form if there are no validation errors
      if (this.submitForm.find('.is-errored').length === 0) {
        this._submitComment();
      };
      return false;
    }, this));
  };

  OnPageFeedback.prototype.init = function(initialised) {
    this._bindHandlers();
    this._checkForStoredState();
    this._initialisedSuccess(initialised);
  };

  return OnPageFeedback;
});
<commit_msg>Abort if localStorage isn’t supported<commit_after>define(['jquery', 'featureDetect', 'DoughBaseComponent', 'common'], function($, FeatureDetect, DoughBaseComponent, MAS) {
  'use strict';

  var OnPageFeedback;

  OnPageFeedback = function($el, config) {
    OnPageFeedback.baseConstructor.call(this, $el, config, {});

    this.interactionBtn = $el.find('[data-dough-feedback]');
    this.pages = $el.find('[data-dough-feedback-page]');
    this.shareBtns = $el.find('[data-dough-feedback-share] .social-sharing__item__icon');
    this.submitBtn = $el.find('[data-dough-feedback-submit]');
    this.submitForm = $el.find('[data-dough-feedback-form]');
    this.ajaxUrl = $el.attr('data-dough-on-page-feedback-post');
    this.likeCount = $el.find('[data-dough-feedback-like-count]');
    this.dislikeCount = $el.find('[data-dough-feedback-dislike-count]');
    this.pageId = window.location.pathname.match(/^.*\/([a-zA-Z0-9-_]+)$/)[1];
  };

  DoughBaseComponent.extend(OnPageFeedback);
  OnPageFeedback.componentName = 'OnPageFeedback';

  OnPageFeedback.prototype._submitInteraction = function(interaction) {
    var isLiked = (interaction === 'positive') ? true : false;

    var postObject = {
      liked: isLiked
    };

    var submitInteraction = $.post(this.ajaxUrl, postObject, function(data){
      this._storeLastInteraction(interaction);
      this._showPage(interaction);
      this._updateCount(data);
    }.bind(this))
    .fail(function() {
      MAS.warn('failed to submit like / dislike');
    }.bind(this));
  };

  OnPageFeedback.prototype._share = function(share) {
    var submitShare = $.ajax({
      url: this.ajaxUrl,
      type: 'PATCH',
      data: {'shared_on': share}
    });
    submitShare.fail(function(status){
      MAS.warn('failed to submit share');
    });

    this._storeLastInteraction('share');
    this._showPage('results');
    this._animateResult('like');
  };

  OnPageFeedback.prototype._submitComment = function() {
    var userComment = $('[data-dough-feedback-comment]').val(),
    submitFeedback = $.ajax({
      url: this.ajaxUrl,
      type: 'PATCH',
      data: {'comment': userComment}
    });

    submitFeedback.fail(function(status){
      MAS.warn('failed to submit comment');
    });
    this._storeLastInteraction('comment');
    this._showPage('results');
    this._animateResult('dislike');
  };

  OnPageFeedback.prototype._animateResult = function(interaction) {
    var el,
    total;

    if (interaction === 'like') {
      el = this.likeCount;
    } else {
      el = this.dislikeCount;
    };

    total = parseInt(el.text());
    el.text(total - 1);

    window.setTimeout(function(){
      el.closest('.on-page-feedback__results-item').addClass('is-animating');
    }.bind(this), 300);
    window.setTimeout(function(){
      el.text(total);
    }.bind(this), 600);
  };

  OnPageFeedback.prototype._updateCount = function(data) {
    var countResponse = data;

    this.likeCount.text(countResponse.likes_count);
    this.dislikeCount.text(countResponse.dislikes_count);
  };

  OnPageFeedback.prototype._showPage = function(pageName) {
    this.pages.addClass('is-hidden');
    this.pages.filter('[data-dough-feedback-page=' + pageName + ']').removeClass('is-hidden');
  };

  OnPageFeedback.prototype._storeLastInteraction = function(interaction) {
    localStorage.setItem('MAS.onPageFeedback.' + this.pageId, interaction);
  };

  OnPageFeedback.prototype._checkForStoredState = function() {
    var lastInteraction = localStorage['MAS.onPageFeedback.' + this.pageId];

    if (typeof lastInteraction != 'undefined') {
      switch (lastInteraction) {
        case 'positive':
        case 'negative':
          this._showPage(lastInteraction);
          break;
        case 'share':
        case 'comment':
          this._showPage('results');
          break;
      }
    }
  };

  OnPageFeedback.prototype._bindHandlers = function() {
    var self = this;

    this.interactionBtn.on('click', function(e) {
      e.preventDefault();
      self._submitInteraction($(this).attr('data-dough-feedback'));
    });
    this.shareBtns.on('click', function() {
      self._share($(this).attr('data-dough-shared-on'));
    });
    this.submitForm.on('submit', $.proxy(function(e){
      e.preventDefault;
      // Only submit the form if there are no validation errors
      if (this.submitForm.find('.is-errored').length === 0) {
        this._submitComment();
      };
      return false;
    }, this));
  };

  OnPageFeedback.prototype.init = function(initialised) {
    if (!FeatureDetect.localstorage) return

    this._bindHandlers();
    this._checkForStoredState();
    this._initialisedSuccess(initialised);
  };

  return OnPageFeedback;
});
<|endoftext|>


<commit_before>function setRemoveLinkEvents(){
  $(".removeAnlage").click(function()
  {
      $(this).parent().next().find(".remove_loader").show();
      $("#form_data").load(
        $(this).attr('href') + ' #form_data',
	function(){
      		$(this).parent().next().find(".remove_loader").hide();
	}
      );
      return false;
  });
}

$(document).ready(function()
{
  setRemoveLinkEvents();

  $(document).ajaxComplete(function()
  {
    setRemoveLinkEvents();
  });
});
<commit_msg>zimremoveanlage: fix ajax error case<commit_after>/*
 * Author: Christoph Herbst
 * Date: 07.2010
 *
 */

var openZIMzimRemoveAnlage = {

	setup: function() {
	  $(".removeAnlage").click(function()
	  {
	      var url = $(this).attr('href');
	      $(this).parent().next().find(".remove_loader").show();
	      $("#form_data").load(
	        url + ' #form_data',
	        function(response, status, xhr) {
			if (status == "error") {
				alert("error:!"+url);
				window.document.location = url;
			}else
		      		$(this).parent().next().find(".remove_loader").hide();
		}
	      );
	      return false;
	  });
	}
}

$(document).ready(function()
{
  openZIMzimRemoveAnlage.setup();

  $(document).ajaxComplete(function()
  {
    openZIMzimRemoveAnlage.setup();
  });
});
<|endoftext|>


<commit_before>var express = require("express"),
    fs = require("fs");

// module's export is a function,
// that when called creates and returns a new app
// `var apper = require("apper"),
//      app = apper();`
//  just like connect and express
exports = module.exports = function () {
    return new App();
};

// you can also create a new app using:
// `new apper.App()`
exports.App = App;

// current version
exports.version = "0.0.2";

// new App() created for a certain directory path
function App(path, indent, mountPath) {
    // new customizable settings for each App instance
    this.settings = getAppSettings();

    // if no path sent in to init, nor to App constructor,
    // then assume it's the root app being initialised
    this.path = path || process.cwd();

    this.mountPath = mountPath || "";

    // indent starts at 0 to demarcate subapps with increasing indent
    this.indent = indent || 1;
}

App.prototype.debug = function () {
    var args = [].slice.call(arguments);
    var indentText = new Array(this.indent).join("- ");
    console.log.apply(console, [indentText].concat(args));
};

// calling init does the following:
// * load the environment and middleware modules
// * init nested app directories and mount them as subapps of the current app
// * load the routes module to register app's routes
App.prototype.init = function () {

    // get respective module paths in the current app directory
    var envModulePath = this.getModulePath("environment"),
        middlewarePath = this.getModulePath("middleware"),
        routesModulePath = this.getModulePath("routes");

    if (!(envModulePath || middlewarePath || routesModulePath)) {
        // if neither of these modules exists in the current directory,
        // then it's probably not meant to be a sub-app
        return false;
    }

    // if this really is a proper app, then load an express app here
    this.expressApp = express();

    this.debug(this.mountPath || "/");
    this.indent += 1;

    // if environment and middleware exist, load them
    if (envModulePath) {
        this.loadModule(envModulePath);
        this.debug("Loaded environment.");
    }
    if (middlewarePath) {
        this.loadModule(middlewarePath);
        this.debug("Loaded middleware.");
    }

    var path = this.path;
    // if a /public directory exists for current app, expose it
    if (fs.existsSync(path + "/public")) {
        this.expressApp.use("/public", express.static(path + "/public"));
        this.debug("Exposed /public.");
    }

    var i;
    var subappNames = this.subappNames();
    // start a new app for all subapps and mount them under the current one
    for (i = 0; i < subappNames.length; i++) {
        var name = subappNames[i];
        var subapp = new App(path + "/" + name, this.indent, this.mountPath + "/" + name);

        // if the subapp's initialization was successful,
        if (subapp.init()) {
            // mount it as a subapp of the parent app
            this.expressApp.use("/" + name, subapp.expressApp);
        }
    }

    // load the routes last,
    // because they should only be matched if nothing else did.
    // hence it's possible to have catch-all routes.
    if (routesModulePath) {
        this.loadModule(routesModulePath);
        this.debug("Loaded routes.");
    }

    return true;
};

App.prototype.subappNames = function () {
    // directories to ignore can be custom for each instance of App
    var dirToIgnore = this.settings.dirToIgnore,
        path = this.path,
        subapps = [];

    var files;
    try {
        // read the list of files in path
        files = fs.readdirSync(path);
    } catch (e) {
        console.log("Error reading directory:", path, e.message);
    }
    if (files) {
        files
            // filter them based on ignored list,
            // and remove hidden files/folders as well
            .filter(function (fileName) {
                return dirToIgnore.indexOf(fileName) === -1 && fileName[0] !== ".";
            })
            // and for the rest,
            .forEach(function (fileName) {
                var filePath = path + "/" + fileName;
                var fileStats;
                try {
                    // get their filesystem stats
                    fileStats = fs.statSync(filePath);
                } catch (e) {
                    console.log("Error reading file stats for:", filePath, e.message);
                }
                if (fileStats && fileStats.isDirectory()) {
                    // and take the remaining directories as subapps
                    subapps.push(fileName);
                }
            });
    }
    return subapps;
};

App.prototype.loadModule = function (modulePath) {
    var loadedModule;
    try {
        loadedModule = require(modulePath);
    } catch (e) {
        console.log(["Error loading module:", modulePath, e.message].join("\n"));
    }
    if (typeof loadedModule === "function") {
        // the module to be loaded needs to be a function
        loadedModule.call(this.expressApp, this.expressApp, this.mountPath);
    }
    return this;
};

App.prototype.getModulePath = function (type) {
    // from the list of possible module names
    var moduleNames = this.settings.moduleNames,
        moduleNamesForType = moduleNames[type],
        path = this.path,
        modulePath,
        i;

    if (moduleNamesForType) {
        for (i = 0; i < moduleNamesForType.length; i++) {
            modulePath = path + "/" + moduleNamesForType[i];
            if (fs.existsSync(modulePath)) {
                // return the first one that exists
                return modulePath;
            }
        }
    }
    return null;
};

App.prototype.start = function () {
    var callback = arguments[arguments.length - 1];
    if (typeof callback !== "function") {
        // create a callback, notifying port,
        // if one is not already present
        callback = function () {
            console.log("Serving on " + this.address().port);
        };
    }
    // and start listening on the express app
    this.expressApp.listen.apply(this.expressApp, arguments);
    return this;
};

function getAppSettings() {
    // these app settings are generated per subapp,
    // and as such, can be modified for each subapp
    return {
        // directories that are never taken as a subapp
        dirToIgnore: [
            "public",
            "private",
            "lib",
            "test"
        ],
        // possible module names for
        moduleNames: {
            // environment settings
            "environment": [
                "env",
                "env.js",
                "environment",
                "environment.js"
            ],
            // middleware subscriptions
            "middleware": [
                "middleware",
                "middleware.js",
                "middlewares",
                "middlewares.js"
            ],
            // and registering routes
            "routes": [
                "routes",
                "routes.js",
                "routing",
                "routing.js"
            ]
        }
    };
}

/*
(function () {
    "use strict";

    var express      = require("express"),
        fs           = require("fs"),
        _            = require("underscore");

    var defaultModules = [
            "environment",
            "middlewares",
            "routes"
        ],
        dirToIgnore = [
            "public",
            "private",
            "lib",
            "test"
        ];

    var expressApp = express();

    exports.start = function () {
        var callback = arguments[arguments.length - 1];
        if (typeof callback !== "function") {
            callback = function () {
                console.log("Serving on " + this.address().port);
            };
        }
        expressApp.listen.apply(expressApp, arguments);
    };

    exports.init = function (mountPath) {
        mountPath = mountPath || ".";
        var routesPath = mountPath + "/routes",
            envPath = mountPath + "/environment",
            middlewaresPath = mountPath + "/middlewares";

        if (fs.existsSync(routesPath) || fs.existsSync(routesPath + ".js")) {
            try {
                var routes = require(routesPath);
            } catch (e) {
                console.log("\nError in loading module: " + routesPath + "\n" + e.message + "\n");
                return;
            }

            _.each(routes, function (fn, route) {
                expressApp.
            });
        }
    };

    function getDefaultModules(mountPath) {
        var modulesPresent = [];

        defaultModules.forEach(function (moduleName) {
            var modulePath = mountPath + "/" + moduleName;
            if (fs.existsSync(modulePath) || fs.existsSync(modulePath + ".js")) {
                try {
                    var moduleFunc = require(modulePath);
                    if (typeof moduleFunc === "function") {
                        modulesPresent.push({
                            moduleFunc: moduleFunc,
                            moduleName: moduleName
                        });
                    }
                } catch (e) {
                    console.log("\nError in loading module: " + modulePath + "\n" + e.message + "\n");
                }
            }
        });

        return modulesPresent;
    }

    function loadDefaultModules(modulesPresent, mountPath) {
        modulesPresent.forEach(function (m) {
            console.log("Loading " + mountPath + "/" + m.moduleName);
            m.moduleFunc(moduleContext[m.moduleName](mountPath), mountPath);
        });
    }

    function initPath(fullPath, mountPath) {
        mountPath = mountPath || "";
        if (fullPath.indexOf(".") === 0) {
            fullPath = process.cwd() + "/" + fullPath;
        }

        var modulesPresent = getDefaultModules(fullPath, mountPath);

        if (modulesPresent.length > 0) {
            loadDefaultModules(modulesPresent, mountPath);

            expressApp.use(mountPath + "/public", express.static(fullPath + "/public"));
            console.log("Exposed " + mountPath + "/public");

            var files;
            try {
                files = fs.readdirSync(fullPath);
            } catch (e) {
                log.err(e);
            }
            if (files) {
                files.filter(function (fileName) {
                    return dirToIgnore.indexOf(fileName) === -1;
                }).forEach(function (fileName) {
                    var filePath = fullPath + "/" + fileName;
                    var fileStats;
                    try {
                        fileStats = fs.statSync(filePath);
                    } catch (e) {
                        log.err(e);
                    }
                    if (fileStats && fileStats.isDirectory()) {
                        initPath(filePath, mountPath + "/" + fileName);
                    }
                });
            }
        } else {
            console.log("No default modules in " + mountPath + ". Skipping directory.");
        }

        return this;
    }

    exports.init = initPath;
}());
*/
<commit_msg>removed old backup-like comments<commit_after>var express = require("express"),
    fs = require("fs");

// module's export is a function,
// that when called creates and returns a new app
// `var apper = require("apper"),
//      app = apper();`
//  just like connect and express
exports = module.exports = function () {
    return new App();
};

// you can also create a new app using:
// `new apper.App()`
exports.App = App;

// current version
exports.version = "0.0.2";

// new App() created for a certain directory path
function App(path, indent, mountPath) {
    // new customizable settings for each App instance
    this.settings = getAppSettings();

    // if no path sent in to init, nor to App constructor,
    // then assume it's the root app being initialised
    this.path = path || process.cwd();

    this.mountPath = mountPath || "";

    // indent starts at 0 to demarcate subapps with increasing indent
    this.indent = indent || 1;
}

App.prototype.debug = function () {
    var args = [].slice.call(arguments);
    var indentText = new Array(this.indent).join("- ");
    console.log.apply(console, [indentText].concat(args));
};

// calling init does the following:
// * load the environment and middleware modules
// * init nested app directories and mount them as subapps of the current app
// * load the routes module to register app's routes
App.prototype.init = function () {

    // get respective module paths in the current app directory
    var envModulePath = this.getModulePath("environment"),
        middlewarePath = this.getModulePath("middleware"),
        routesModulePath = this.getModulePath("routes");

    if (!(envModulePath || middlewarePath || routesModulePath)) {
        // if neither of these modules exists in the current directory,
        // then it's probably not meant to be a sub-app
        return false;
    }

    // if this really is a proper app, then load an express app here
    this.expressApp = express();

    this.debug(this.mountPath || "/");
    this.indent += 1;

    // if environment and middleware exist, load them
    if (envModulePath) {
        this.loadModule(envModulePath);
        this.debug("Loaded environment.");
    }
    if (middlewarePath) {
        this.loadModule(middlewarePath);
        this.debug("Loaded middleware.");
    }

    var path = this.path;
    // if a /public directory exists for current app, expose it
    if (fs.existsSync(path + "/public")) {
        this.expressApp.use("/public", express.static(path + "/public"));
        this.debug("Exposed /public.");
    }

    var i;
    var subappNames = this.subappNames();
    // start a new app for all subapps and mount them under the current one
    for (i = 0; i < subappNames.length; i++) {
        var name = subappNames[i];
        var subapp = new App(path + "/" + name, this.indent, this.mountPath + "/" + name);

        // if the subapp's initialization was successful,
        if (subapp.init()) {
            // mount it as a subapp of the parent app
            this.expressApp.use("/" + name, subapp.expressApp);
        }
    }

    // load the routes last,
    // because they should only be matched if nothing else did.
    // hence it's possible to have catch-all routes.
    if (routesModulePath) {
        this.loadModule(routesModulePath);
        this.debug("Loaded routes.");
    }

    return true;
};

App.prototype.subappNames = function () {
    // directories to ignore can be custom for each instance of App
    var dirToIgnore = this.settings.dirToIgnore,
        path = this.path,
        subapps = [];

    var files;
    try {
        // read the list of files in path
        files = fs.readdirSync(path);
    } catch (e) {
        console.log("Error reading directory:", path, e.message);
    }
    if (files) {
        files
            // filter them based on ignored list,
            // and remove hidden files/folders as well
            .filter(function (fileName) {
                return dirToIgnore.indexOf(fileName) === -1 && fileName[0] !== ".";
            })
            // and for the rest,
            .forEach(function (fileName) {
                var filePath = path + "/" + fileName;
                var fileStats;
                try {
                    // get their filesystem stats
                    fileStats = fs.statSync(filePath);
                } catch (e) {
                    console.log("Error reading file stats for:", filePath, e.message);
                }
                if (fileStats && fileStats.isDirectory()) {
                    // and take the remaining directories as subapps
                    subapps.push(fileName);
                }
            });
    }
    return subapps;
};

App.prototype.loadModule = function (modulePath) {
    var loadedModule;
    try {
        loadedModule = require(modulePath);
    } catch (e) {
        console.log(["Error loading module:", modulePath, e.message].join("\n"));
    }
    if (typeof loadedModule === "function") {
        // the module to be loaded needs to be a function
        loadedModule.call(this.expressApp, this.expressApp, this.mountPath);
    }
    return this;
};

App.prototype.getModulePath = function (type) {
    // from the list of possible module names
    var moduleNames = this.settings.moduleNames,
        moduleNamesForType = moduleNames[type],
        path = this.path,
        modulePath,
        i;

    if (moduleNamesForType) {
        for (i = 0; i < moduleNamesForType.length; i++) {
            modulePath = path + "/" + moduleNamesForType[i];
            if (fs.existsSync(modulePath)) {
                // return the first one that exists
                return modulePath;
            }
        }
    }
    return null;
};

App.prototype.start = function () {
    var callback = arguments[arguments.length - 1];
    if (typeof callback !== "function") {
        // create a callback, notifying port,
        // if one is not already present
        callback = function () {
            console.log("Serving on " + this.address().port);
        };
    }
    // and start listening on the express app
    this.expressApp.listen.apply(this.expressApp, arguments);
    return this;
};

function getAppSettings() {
    // these app settings are generated per subapp,
    // and as such, can be modified for each subapp
    return {
        // directories that are never taken as a subapp
        dirToIgnore: [
            "public",
            "private",
            "lib",
            "test"
        ],
        // possible module names for
        moduleNames: {
            // environment settings
            "environment": [
                "env",
                "env.js",
                "environment",
                "environment.js"
            ],
            // middleware subscriptions
            "middleware": [
                "middleware",
                "middleware.js",
                "middlewares",
                "middlewares.js"
            ],
            // and registering routes
            "routes": [
                "routes",
                "routes.js",
                "routing",
                "routing.js"
            ]
        }
    };
}
<|endoftext|>


<commit_before>(function($) {
  'use strict';

  function fadeArrow() {
    var topWindow = $(window).scrollTop() * 1.5;
    var windowHeight = $(window).height();
    var position = 1 - (topWindow / windowHeight);

    $('.js-hero-arrow').css('opacity', position);
  }

  function animateHeader() {
    var $header = $('.js-navbar');
    $(window).scrollTop() > 1 ? $header.addClass('sticky') : $header.removeClass('sticky');
  }

  function initAnchorLinks() {
    $('.js-anchor-link').on('click', 'a', function(event) {
      event.preventDefault();

      $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top
      }, 500);
    });
  }

  function scrollToTopOnVisit() {
    $(window).scrollTop(0);
  }

  $(window).scroll(function(){
    fadeArrow();
    animateHeader();
  });

  function myMap() {
    var myLatLng = { lat: -26.2893037, lng: -48.8451019 }
    var mapProp= {
        center:new google.maps.LatLng(-26.2893037,-48.8451019),
        zoom:15,
    };
    var map=new google.maps.Map(document.getElementById("googleMap"),mapProp);
    var marker = new google.maps.Marker({
      position: myLatLng,
      map: map,
      title: 'Estamos aqui!'
    });
  }

  function initHighlights() {
    $('.column-value, .column-title').on('mouseover', function() {
      var cointainer = $(this).parents('.container');
      cointainer.find('.column-value').removeClass('highlight')
      cointainer.find('.column-title').removeClass('highlight')
      cointainer.find('.column-value:nth-child('+ ($(this).index() + 1) +')').addClass('highlight')
      cointainer.find('.column-title:nth-child('+ ($(this).index() + 1) +')').addClass('highlight')
    })
  }

  $(function() {
    initAnchorLinks();
    scrollToTopOnVisit();
    myMap();
    initHighlights();
  })
})(jQuery);
<commit_msg>Update based on comments<commit_after>(function($) {
  'use strict';

  function fadeArrow() {
    var topWindow = $(window).scrollTop() * 1.5;
    var windowHeight = $(window).height();
    var position = 1 - (topWindow / windowHeight);

    $('.js-hero-arrow').css('opacity', position);
  }

  function animateHeader() {
    var $header = $('.js-navbar');
    $(window).scrollTop() > 1 ? $header.addClass('sticky') : $header.removeClass('sticky');
  }

  function initAnchorLinks() {
    $('.js-anchor-link').on('click', 'a', function(event) {
      event.preventDefault();

      $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top
      }, 500);
    });
  }

  function scrollToTopOnVisit() {
    $(window).scrollTop(0);
  }

  $(window).scroll(function(){
    fadeArrow();
    animateHeader();
  });

  function myMap() {
    var myLatLng = { lat: -26.2893037, lng: -48.8451019 }
    var mapProp= {
        center:new google.maps.LatLng(-26.2893037,-48.8451019),
        zoom:15,
    };
    var map=new google.maps.Map(document.getElementById("googleMap"),mapProp);
    var marker = new google.maps.Marker({
      position: myLatLng,
      map: map,
      title: 'Estamos aqui!'
    });
  }

  function initHighlights() {
    $('.column-value, .column-title').on('mouseover', function() {
      var cointainer = $(this).parents('.container'),
          cells      = $.merge(cointainer.find('.column-value'), cointainer.find('.column-title')),
          childIndex = $(this).index() + 1;

      cells.removeClass('highlight');
      cells.filter(':nth-child('+ childIndex +')').addClass('highlight');
    })
  }

  $(function() {
    initAnchorLinks();
    scrollToTopOnVisit();
    myMap();
    initHighlights();
  })
})(jQuery);
<|endoftext|>


<commit_before>/**
 * Unit tests around _routing (and sharding)
 *
 */
'use strict'

// dependencies
const _ = require('lodash')
const $http = require('http-as-promised')
const request = require('request')
const seeder = require('./seeder')
const Promise = require('bluebird')
const ElasticHarvest = require('../elastic-harvester')
const Utils = require('../Util')

const syncWaitTime = 1000  // milliseconds

function queryElasticSearch(config, command) {
    return new Promise(function (resolve, reject) {
        var options = {
            uri: config.harvester.options.es_url + command
        }
        request.get(options, function (error, response, body) {
            if (error) return reject(error)
            return resolve(JSON.parse(body))
        })
    })
}

function catElasticSearch(config, catCommand) {
    return new Promise(function (resolve, reject) {
        var options = {
            uri: config.harvester.options.es_url + '/_cat/' + catCommand
        }
        request.get(options, function (error, response, body) {
            if (error) return reuect(error)
            return resolve(body)
        })
    })
}

// need a harvester with routing turned on.
describe('Custom Routing', function () {
    var seederInstance
    var config
    var options
    var personCustomRoutingKeyPath
    var warriorCustomRoutingKeyPath

    beforeEach(function () {
        seederInstance = seeder(this.harvesterApp)
        config = this.config
        options = config.harvester.options
        personCustomRoutingKeyPath = this.personCustomRoutingKeyPath
        warriorCustomRoutingKeyPath = this.warriorCustomRoutingKeyPath
        this.createOptions = function (uri) {
            // helper function to create $http options object when given a uri
            return {
                url: config.baseUrl + uri,
                json: true,
                error: false
            }
        }
    })

    afterEach(function () {
    })

    describe('The setPathToCustomRoutingKey function', function () {

        it('should be a function of ElasticHarvest', function () {
            var testSearch = new ElasticHarvest(this.app, options.es_url, options.es_index, 'test')

            testSearch.should.have.property('setPathToCustomRoutingKey').and.be.an.Function
        })

        it('should add property to options', function () {
            var testSearch = new ElasticHarvest(this.app, options.es_url, options.es_index, 'test')

            testSearch.setPathToCustomRoutingKey('gender')
            testSearch.pathToCustomRoutingKey.should.equal('gender')
        })

        it('should add multiple pathToCustomRoutingKeys for each model', function () {
            var testSearchA = new ElasticHarvest(this.app, options.es_url, options.es_index, 'testA')
            var testSearchB = new ElasticHarvest(this.app, options.es_url, options.es_index, 'testB')

            testSearchA.setPathToCustomRoutingKey('gender')
            testSearchB.setPathToCustomRoutingKey('nationality')
            testSearchA.pathToCustomRoutingKey.should.equal('gender')
            testSearchB.pathToCustomRoutingKey.should.equal('nationality')
        })

    })

    describe('Syncing with CustomRouting', function () {

        function validateShardMatchesSearch(config, customRoutingValue) {
           return Promise.all([
               // ElasticSearch API command to get the shard searched for a given routing key
               queryElasticSearch(config, '/' + config.harvester.options.es_index + '/_search_shards?routing=' + customRoutingValue),
               // ElasticSearch "_cat" command that gets the number of documents per shard. Also indicates
               // parimary/replica since we can't filter the replicas out, we'll have to do this manually.
               catElasticSearch(config, 'shards/' + config.harvester.options.es_index + '?h=s,p,d')
           ])
               .spread(function (searchedShards, shardStats) {
                   var searchShard = searchedShards.shards[0][0].shard
                   var docsCount

                   console.log('searchedShard:', searchShard)
                   console.log('docsPerShard:', shardStats)

                   _.forEach(shardStats.split('\n'), function (row) {
                       var values = row.split(' ')
                       var shard = parseInt(values[0], 10)
                       var docs = parseInt(values[2], 10)

                       if (shard === searchShard && values[1] === 'p' && !isNaN(docs)) {
                           docsCount = docs
                           return false
                       }
                   })
                   return docsCount
               })
        }

        it('should send documents to different shards', function () {
            var collection = 'people'
            // plan is to post a document, which should get indexed
            // then we can use the ElasticSearch API to get the shard our key would map to and the documents listed per
            // shard and check that it incremented by one after we added our document.
            var newPerson = {
                id: 'c05afa8f-b26b-481e-b9a8-0b306d4ef026',
                name: 'Alice',
                appearances: 893,
                dateOfBirth: '1992-08-25T13:22:38.000Z'
            }
            var routingKey = this.personCustomRoutingKeyPath

            this.timeout(syncWaitTime + 1000)
            return seederInstance.dropCollections(collection)
                .then(function () {
                    return seederInstance.post(collection, [newPerson])
                })
                .then(function (results) {
                    // check it was posted correctly. Note this can pass, but indexing might still fail...
                    results.should.have.property(collection)
                    results[collection].should.be.an.Array
                    results[collection][0].should.equal(newPerson.id)

                    return Promise.delay(syncWaitTime)  // allow sync to happen
                })
                .then(function () {
                    return validateShardMatchesSearch(config, newPerson[routingKey])
                })
                .then(function (shardMatchesSearch) {
                    shardMatchesSearch.should.equal(1)  // there should only be one document here
                })
        })

        it('should send document to different shards WHEN pathToRoutingKey is a path', function () {
            var newEquipment = {
                name: 'Fist of Fury',
                id: '024f266c-e0e6-4384-b55e-92693c43096e'
            }
            var newWarrior = {
                name: 'Alice the Angry',
                id: '781ace40-60c1-4c0c-809b-58352c024c36',
                links: {
                    weapon: newEquipment.id
                }
            }
            var warriorCustomRoutingKeyPath = this.warriorCustomRoutingKeyPath

            this.timeout(syncWaitTime + 1000)
            return seederInstance.dropCollections('warriors', 'equipment')
                .then(function () {
                    return Promise.all([
                        seederInstance.post('equipment', [ newEquipment ]),
                        seederInstance.post('warriors', [ newWarrior ])
                    ])
                })
                .spread(function (equipment, warriors) {
                    equipment.should.have.property('equipment')
                    equipment['equipment'].should.be.an.Array
                    equipment['equipment'][0].should.equal(newEquipment.id)
                    warriors.should.have.property('warriors')
                    warriors['warriors'].should.be.an.Array
                    warriors['warriors'][0].should.equal(newWarrior.id)
                    return Promise.delay(syncWaitTime)  // allow sync to happen
                })
                .then(function () {
                    return validateShardMatchesSearch(config, newEquipment.id)
                })
                .then(function (shardMatchesSearch) {
                    // as warriors are linked to equipment, both warriors and equipment will be stored on the same shard
                    shardMatchesSearch.should.be.above(2)  // expected two but there are 4

                })
        })
    })

    describe('Searching With Custom Routing', function () {
        var config

        beforeEach(function seedPeople() {
            config = this.config
            this.timeout(config.esIndexWaitTime + 6000)
            return seeder(this.harvesterApp).dropCollectionsAndSeed('pets', 'people', 'equipment')
                .then(function () {
                    return Promise.delay(config.esIndexWaitTime + 2000)
                })
        })

        it('should still search WHEN customRouting is enabled BUT not given as a search predicate', function () {
            return $http.get(this.createOptions('/people/search?appearances=le=2000'))
                .spread(function (res, body) {
                    res.statusCode.should.equal(200)
                    body.people.should.be.an.Array
                    body.people.length.should.equal(1)
                    body.people[0].name.should.equal('Wally')
                })
        })

        it('should add one custom routing value WHEN customRouting is enabled', function () {
            return $http.get(this.createOptions('/people/search?name=Dilbert'))
                .spread(function (res, body) {
                    res.statusCode.should.equal(200)
                    body.people.should.be.an.Array
                    body.people.length.should.equal(1)
                    body.people[0].should.have.property('name').and.equal('Dilbert')
                })
        })

        it('should add many custom routing values WHEN custumRouting is enabled', function () {
            return $http.get(this.createOptions('/people/search?name=Dilbert,Wally'))
                .spread(function (res, body) {
                    res.statusCode.should.equal(200)
                    body.people.should.be.an.Array
                    body.people.length.should.equal(2)
                    _.find(body.people, { name: 'Wally'}).should.be.an.Object
                    _.find(body.people, { name: 'Dilbert'}).should.be.an.Object
                })
        })

        it('should still search WHEN customRouting is NOT enabled', function () {
            var searchKey = 'name'
            var searchTerm = 'Dilbot'

            return $http.get(this.createOptions('/equipment/search?' + searchKey + '=' + searchTerm))
                .spread(function (res, body) {
                    res.statusCode.should.equal(200)
                    body.equipment.should.be.an.Array
                    body.equipment.length.should.equal(1)
                    body.equipment[0].should.have.property(searchKey).and.equal(searchTerm)
                })
        })
    })
})

<commit_msg>removed use of const<commit_after>/**
 * Unit tests around _routing (and sharding)
 *
 */
'use strict'

// dependencies
var _ = require('lodash')
var $http = require('http-as-promised')
var request = require('request')
var seeder = require('./seeder')
var Promise = require('bluebird')
var ElasticHarvest = require('../elastic-harvester')
var Utils = require('../Util')

var syncWaitTime = 1000  // milliseconds

function queryElasticSearch(config, command) {
    return new Promise(function (resolve, reject) {
        var options = {
            uri: config.harvester.options.es_url + command
        }
        request.get(options, function (error, response, body) {
            if (error) return reject(error)
            return resolve(JSON.parse(body))
        })
    })
}

function catElasticSearch(config, catCommand) {
    return new Promise(function (resolve, reject) {
        var options = {
            uri: config.harvester.options.es_url + '/_cat/' + catCommand
        }
        request.get(options, function (error, response, body) {
            if (error) return reuect(error)
            return resolve(body)
        })
    })
}

// need a harvester with routing turned on.
describe('Custom Routing', function () {
    var seederInstance
    var config
    var options
    var personCustomRoutingKeyPath
    var warriorCustomRoutingKeyPath

    beforeEach(function () {
        seederInstance = seeder(this.harvesterApp)
        config = this.config
        options = config.harvester.options
        personCustomRoutingKeyPath = this.personCustomRoutingKeyPath
        warriorCustomRoutingKeyPath = this.warriorCustomRoutingKeyPath
        this.createOptions = function (uri) {
            // helper function to create $http options object when given a uri
            return {
                url: config.baseUrl + uri,
                json: true,
                error: false
            }
        }
    })

    afterEach(function () {
    })

    describe('The setPathToCustomRoutingKey function', function () {

        it('should be a function of ElasticHarvest', function () {
            var testSearch = new ElasticHarvest(this.app, options.es_url, options.es_index, 'test')

            testSearch.should.have.property('setPathToCustomRoutingKey').and.be.an.Function
        })

        it('should add property to options', function () {
            var testSearch = new ElasticHarvest(this.app, options.es_url, options.es_index, 'test')

            testSearch.setPathToCustomRoutingKey('gender')
            testSearch.pathToCustomRoutingKey.should.equal('gender')
        })

        it('should add multiple pathToCustomRoutingKeys for each model', function () {
            var testSearchA = new ElasticHarvest(this.app, options.es_url, options.es_index, 'testA')
            var testSearchB = new ElasticHarvest(this.app, options.es_url, options.es_index, 'testB')

            testSearchA.setPathToCustomRoutingKey('gender')
            testSearchB.setPathToCustomRoutingKey('nationality')
            testSearchA.pathToCustomRoutingKey.should.equal('gender')
            testSearchB.pathToCustomRoutingKey.should.equal('nationality')
        })

    })

    describe('Syncing with CustomRouting', function () {

        function validateShardMatchesSearch(config, customRoutingValue) {
           return Promise.all([
               // ElasticSearch API command to get the shard searched for a given routing key
               queryElasticSearch(config, '/' + config.harvester.options.es_index + '/_search_shards?routing=' + customRoutingValue),
               // ElasticSearch "_cat" command that gets the number of documents per shard. Also indicates
               // parimary/replica since we can't filter the replicas out, we'll have to do this manually.
               catElasticSearch(config, 'shards/' + config.harvester.options.es_index + '?h=s,p,d')
           ])
               .spread(function (searchedShards, shardStats) {
                   var searchShard = searchedShards.shards[0][0].shard
                   var docsCount

                   console.log('searchedShard:', searchShard)
                   console.log('docsPerShard:', shardStats)

                   _.forEach(shardStats.split('\n'), function (row) {
                       var values = row.split(' ')
                       var shard = parseInt(values[0], 10)
                       var docs = parseInt(values[2], 10)

                       if (shard === searchShard && values[1] === 'p' && !isNaN(docs)) {
                           docsCount = docs
                           return false
                       }
                   })
                   return docsCount
               })
        }

        it('should send documents to different shards', function () {
            var collection = 'people'
            // plan is to post a document, which should get indexed
            // then we can use the ElasticSearch API to get the shard our key would map to and the documents listed per
            // shard and check that it incremented by one after we added our document.
            var newPerson = {
                id: 'c05afa8f-b26b-481e-b9a8-0b306d4ef026',
                name: 'Alice',
                appearances: 893,
                dateOfBirth: '1992-08-25T13:22:38.000Z'
            }
            var routingKey = this.personCustomRoutingKeyPath

            this.timeout(syncWaitTime + 1000)
            return seederInstance.dropCollections(collection)
                .then(function () {
                    return seederInstance.post(collection, [newPerson])
                })
                .then(function (results) {
                    // check it was posted correctly. Note this can pass, but indexing might still fail...
                    results.should.have.property(collection)
                    results[collection].should.be.an.Array
                    results[collection][0].should.equal(newPerson.id)

                    return Promise.delay(syncWaitTime)  // allow sync to happen
                })
                .then(function () {
                    return validateShardMatchesSearch(config, newPerson[routingKey])
                })
                .then(function (shardMatchesSearch) {
                    shardMatchesSearch.should.equal(1)  // there should only be one document here
                })
        })

        it('should send document to different shards WHEN pathToRoutingKey is a path', function () {
            var newEquipment = {
                name: 'Fist of Fury',
                id: '024f266c-e0e6-4384-b55e-92693c43096e'
            }
            var newWarrior = {
                name: 'Alice the Angry',
                id: '781ace40-60c1-4c0c-809b-58352c024c36',
                links: {
                    weapon: newEquipment.id
                }
            }
            var warriorCustomRoutingKeyPath = this.warriorCustomRoutingKeyPath

            this.timeout(syncWaitTime + 1000)
            return seederInstance.dropCollections('warriors', 'equipment')
                .then(function () {
                    return Promise.all([
                        seederInstance.post('equipment', [ newEquipment ]),
                        seederInstance.post('warriors', [ newWarrior ])
                    ])
                })
                .spread(function (equipment, warriors) {
                    equipment.should.have.property('equipment')
                    equipment['equipment'].should.be.an.Array
                    equipment['equipment'][0].should.equal(newEquipment.id)
                    warriors.should.have.property('warriors')
                    warriors['warriors'].should.be.an.Array
                    warriors['warriors'][0].should.equal(newWarrior.id)
                    return Promise.delay(syncWaitTime)  // allow sync to happen
                })
                .then(function () {
                    return validateShardMatchesSearch(config, newEquipment.id)
                })
                .then(function (shardMatchesSearch) {
                    // as warriors are linked to equipment, both warriors and equipment will be stored on the same shard
                    shardMatchesSearch.should.be.above(2)  // expected two but there are 4

                })
        })
    })

    describe('Searching With Custom Routing', function () {
        var config

        beforeEach(function seedPeople() {
            config = this.config
            this.timeout(config.esIndexWaitTime + 6000)
            return seeder(this.harvesterApp).dropCollectionsAndSeed('pets', 'people', 'equipment')
                .then(function () {
                    return Promise.delay(config.esIndexWaitTime + 2000)
                })
        })

        it('should still search WHEN customRouting is enabled BUT not given as a search predicate', function () {
            return $http.get(this.createOptions('/people/search?appearances=le=2000'))
                .spread(function (res, body) {
                    res.statusCode.should.equal(200)
                    body.people.should.be.an.Array
                    body.people.length.should.equal(1)
                    body.people[0].name.should.equal('Wally')
                })
        })

        it('should add one custom routing value WHEN customRouting is enabled', function () {
            return $http.get(this.createOptions('/people/search?name=Dilbert'))
                .spread(function (res, body) {
                    res.statusCode.should.equal(200)
                    body.people.should.be.an.Array
                    body.people.length.should.equal(1)
                    body.people[0].should.have.property('name').and.equal('Dilbert')
                })
        })

        it('should add many custom routing values WHEN custumRouting is enabled', function () {
            return $http.get(this.createOptions('/people/search?name=Dilbert,Wally'))
                .spread(function (res, body) {
                    res.statusCode.should.equal(200)
                    body.people.should.be.an.Array
                    body.people.length.should.equal(2)
                    _.find(body.people, { name: 'Wally'}).should.be.an.Object
                    _.find(body.people, { name: 'Dilbert'}).should.be.an.Object
                })
        })

        it('should still search WHEN customRouting is NOT enabled', function () {
            var searchKey = 'name'
            var searchTerm = 'Dilbot'

            return $http.get(this.createOptions('/equipment/search?' + searchKey + '=' + searchTerm))
                .spread(function (res, body) {
                    res.statusCode.should.equal(200)
                    body.equipment.should.be.an.Array
                    body.equipment.length.should.equal(1)
                    body.equipment[0].should.have.property(searchKey).and.equal(searchTerm)
                })
        })
    })
})

<|endoftext|>


<commit_before>describe('Parser', function() {
  'use strict';
  var noteType = Polyhymnia.noteType;

  it('can parse a simple sequence rule', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> R2 R3'));

    expect(rules[0].name).toBe('R1');
    expect(rules[0].definitions[0].sequence[0]).toBe('R2');
    expect(rules[0].definitions[0].sequence[1]).toBe('R3');
  });

  it('can parse a simple pattern rule', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> Piano: C D E F'));

    expect(rules[0].name).toBe('R1');
    expect(rules[0].definitions[0].instrument).toBe('Piano');
    expect(rules[0].definitions[0].pattern[0].value).toBe('C');
    expect(rules[0].definitions[0].pattern[0].type).toBe(noteType.NOTE);
    expect(rules[0].definitions[0].pattern[1].value).toBe('D');
    expect(rules[0].definitions[0].pattern[1].type).toBe(noteType.NOTE);
    expect(rules[0].definitions[0].pattern[2].value).toBe('E');
    expect(rules[0].definitions[0].pattern[2].type).toBe(noteType.NOTE);
    expect(rules[0].definitions[0].pattern[3].value).toBe('F');
    expect(rules[0].definitions[0].pattern[3].type).toBe(noteType.NOTE);
  });

  it('can parse min conditions', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (var > 0.1) Piano: C D E F'));

    expect(rules[0].definitions[0].condition.param).toBe('var');
    expect(rules[0].definitions[0].condition.min).toBe('0.1');
  });

  it('can parse max conditions', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (var < 1.0) Piano: C D E F'));

    expect(rules[0].definitions[0].condition.param).toBe('var');
    expect(rules[0].definitions[0].condition.max).toBe('1.0');
  });

  it('can parse between conditions', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.5 < var < 1.0) Piano: C D E F'));

    expect(rules[0].definitions[0].condition.param).toBe('var');
    expect(rules[0].definitions[0].condition.min).toBe('0.5');
    expect(rules[0].definitions[0].condition.max).toBe('1.0');
  });

  it('can parse reverse min conditions', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.1 < var) Piano: C D E F'));

    expect(rules[0].definitions[0].condition.param).toBe('var');
    expect(rules[0].definitions[0].condition.min).toBe('0.1');
  });

  it('can parse reverse max conditions', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (1.0 > var) Piano: C D E F'));

    expect(rules[0].definitions[0].condition.param).toBe('var');
    expect(rules[0].definitions[0].condition.max).toBe('1.0');
  });

  it('can parse reverse between conditions', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (1.0 > var > 0.5) Piano: C D E F'));

    expect(rules[0].definitions[0].condition.param).toBe('var');
    expect(rules[0].definitions[0].condition.min).toBe('0.5');
    expect(rules[0].definitions[0].condition.max).toBe('1.0');
  });

  it('doesn\'t parse rules that don\'t start with a name' , function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('x -> R2 R3'));
    expect(rules.errors[0].error).toBe('Rules must start with a name');
  });

  it('doesn\'t parse rules that don\'t have an arrow', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 R2 R3'));
    expect(rules.errors[0].error).toBe('Expected ->');
  });

  it('doesn\'t parse conditions without numbers', function() {
    var rules1 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x > y) R1 R2'));
    expect(rules1.errors[0].error).toBe('Expected a condition');

    var rules2 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x < y) R1 R2'));
    expect(rules2.errors[0].error).toBe('Expected a condition');

    var rules3 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x < y < z) R1 R2'));
    expect(rules3.errors[0].error).toBe('Expected a condition');

    var rules4 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x > y > z) R1 R2'));
    expect(rules4.errors[0].error).toBe('Expected a condition');
  });

  it('doesn\'t parse conditions without parameters', function() {
    var rules1 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.1 > 0.2) R1 R2'));
    expect(rules1.errors[0].error).toBe('Expected a condition');

    var rules2 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.1 < 0.2) R1 R2'));
    expect(rules2.errors[0].error).toBe('Expected a condition');

    var rules3 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.1 < 0.2 < 0.3) R1 R2'));
    expect(rules3.errors[0].error).toBe('Expected a condition');

    var rules4 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.3 > 0.2 > 0.1) R1 R2'));
    expect(rules4.errors[0].error).toBe('Expected a condition');
  });

  it('doesn\'t parse conditions without < or >', function() {
    var rules1 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x == 0.1) R1 R2'));
    expect(rules1.errors[0].error).toBe('Expected a condition');

    var rules2 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.1 == x) R1 R2'));
    expect(rules2.errors[0].error).toBe('Expected a condition');
  });

  it('doesn\'t parse conditions that don\'t end with )', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x > 0.1 R1 R2'));
    expect(rules.errors[0].error).toBe('Expected a condition');
  });

  it('doesn\'t parse conditions with other stuff than parameters or numbers', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (R1 > 0.1) R1 R2'));
    expect(rules.errors[0].error).toBe('Expected a condition');
  });

  it('doesn\'t parse patterns with invalid notes', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> Piano: C / J Caug2'));
    expect(rules.errors[0].error).toBe('Expected a note, chord, drum symbol or pause');
  });

  it('can parse incomplete rules', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1'));
    expect(rules.length).toBe(1);
  });

  it('can parse empty definitions', function() {
    var rules1 = Polyhymnia.parse(Polyhymnia.tokenize('R1 ->'));
    expect(rules1.length).toBe(1);

    var rules2 = Polyhymnia.parse(Polyhymnia.tokenize('R1 ->\n'));
    expect(rules2.length).toBe(1);

    var rules3 = Polyhymnia.parse(Polyhymnia.tokenize('R1 ->\nR2 -> R3'));
    expect(rules3[0].name).toBe('R1');
    expect(rules3[1].name).toBe('R2');
    expect(rules3[1].definitions[0].sequence[0]).toBe('R3');

    var rules4 = Polyhymnia.parse(Polyhymnia.tokenize('R1 ->\n\nR2 -> R3'));
    expect(rules4[0].name).toBe('R1');
    expect(rules4[1].name).toBe('R2');
    expect(rules4[1].definitions[0].sequence[0]).toBe('R3');
  });

  it('can parse empty definitions with condition', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x > 0.3)'));
    expect(rules[0].definitions[0]).toEqual({});
  });

  it('ignores line breaks after arrow', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 ->\nR2\nR3'));
    expect(rules[0].name).toBe('R1');
    expect(rules[0].definitions[0].sequence[0]).toBe('R2');
    expect(rules[0].definitions[1].sequence[0]).toBe('R3');
  });

  it('ignores line breaks before the first rule', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('\n\nR1 -> R2 R1\n\nR2 -> Piano: C'));
    expect(rules[0].name).toBe('R1');
  });

  it('ignores line breaks after the last rule', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> R2 R1\n\nR2 -> Piano: C\n\n'));
    expect(rules[0].name).toBe('R1');
  });

  it('ignores extra line breaks between rules', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> R2 R2\n\n\n\nR2 -> Piano: C'));
    expect(rules[0].name).toBe('R1');
    expect(rules[1].name).toBe('R2');
  });

  it('flags missing rules', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> R2'));
    expect(rules.errors[0].error).toBe('There is no rule R2');
  });

  it('flags missing instruments', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> Piano: C'), {});
    expect(rules.errors[0].error).toBe('There is no instrument Piano');
  });
});<commit_msg>Correct test name to reflect graceful parsing<commit_after>describe('Parser', function() {
  'use strict';
  var noteType = Polyhymnia.noteType;

  it('can parse a simple sequence rule', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> R2 R3'));

    expect(rules[0].name).toBe('R1');
    expect(rules[0].definitions[0].sequence[0]).toBe('R2');
    expect(rules[0].definitions[0].sequence[1]).toBe('R3');
  });

  it('can parse a simple pattern rule', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> Piano: C D E F'));

    expect(rules[0].name).toBe('R1');
    expect(rules[0].definitions[0].instrument).toBe('Piano');
    expect(rules[0].definitions[0].pattern[0].value).toBe('C');
    expect(rules[0].definitions[0].pattern[0].type).toBe(noteType.NOTE);
    expect(rules[0].definitions[0].pattern[1].value).toBe('D');
    expect(rules[0].definitions[0].pattern[1].type).toBe(noteType.NOTE);
    expect(rules[0].definitions[0].pattern[2].value).toBe('E');
    expect(rules[0].definitions[0].pattern[2].type).toBe(noteType.NOTE);
    expect(rules[0].definitions[0].pattern[3].value).toBe('F');
    expect(rules[0].definitions[0].pattern[3].type).toBe(noteType.NOTE);
  });

  it('can parse min conditions', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (var > 0.1) Piano: C D E F'));

    expect(rules[0].definitions[0].condition.param).toBe('var');
    expect(rules[0].definitions[0].condition.min).toBe('0.1');
  });

  it('can parse max conditions', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (var < 1.0) Piano: C D E F'));

    expect(rules[0].definitions[0].condition.param).toBe('var');
    expect(rules[0].definitions[0].condition.max).toBe('1.0');
  });

  it('can parse between conditions', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.5 < var < 1.0) Piano: C D E F'));

    expect(rules[0].definitions[0].condition.param).toBe('var');
    expect(rules[0].definitions[0].condition.min).toBe('0.5');
    expect(rules[0].definitions[0].condition.max).toBe('1.0');
  });

  it('can parse reverse min conditions', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.1 < var) Piano: C D E F'));

    expect(rules[0].definitions[0].condition.param).toBe('var');
    expect(rules[0].definitions[0].condition.min).toBe('0.1');
  });

  it('can parse reverse max conditions', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (1.0 > var) Piano: C D E F'));

    expect(rules[0].definitions[0].condition.param).toBe('var');
    expect(rules[0].definitions[0].condition.max).toBe('1.0');
  });

  it('can parse reverse between conditions', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (1.0 > var > 0.5) Piano: C D E F'));

    expect(rules[0].definitions[0].condition.param).toBe('var');
    expect(rules[0].definitions[0].condition.min).toBe('0.5');
    expect(rules[0].definitions[0].condition.max).toBe('1.0');
  });

  it('doesn\'t parse rules that don\'t start with a name' , function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('x -> R2 R3'));
    expect(rules.errors[0].error).toBe('Rules must start with a name');
  });

  it('doesn\'t parse rules that don\'t have an arrow', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 R2 R3'));
    expect(rules.errors[0].error).toBe('Expected ->');
  });

  it('doesn\'t parse conditions without numbers', function() {
    var rules1 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x > y) R1 R2'));
    expect(rules1.errors[0].error).toBe('Expected a condition');

    var rules2 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x < y) R1 R2'));
    expect(rules2.errors[0].error).toBe('Expected a condition');

    var rules3 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x < y < z) R1 R2'));
    expect(rules3.errors[0].error).toBe('Expected a condition');

    var rules4 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x > y > z) R1 R2'));
    expect(rules4.errors[0].error).toBe('Expected a condition');
  });

  it('doesn\'t parse conditions without parameters', function() {
    var rules1 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.1 > 0.2) R1 R2'));
    expect(rules1.errors[0].error).toBe('Expected a condition');

    var rules2 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.1 < 0.2) R1 R2'));
    expect(rules2.errors[0].error).toBe('Expected a condition');

    var rules3 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.1 < 0.2 < 0.3) R1 R2'));
    expect(rules3.errors[0].error).toBe('Expected a condition');

    var rules4 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.3 > 0.2 > 0.1) R1 R2'));
    expect(rules4.errors[0].error).toBe('Expected a condition');
  });

  it('doesn\'t parse conditions without < or >', function() {
    var rules1 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x == 0.1) R1 R2'));
    expect(rules1.errors[0].error).toBe('Expected a condition');

    var rules2 = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (0.1 == x) R1 R2'));
    expect(rules2.errors[0].error).toBe('Expected a condition');
  });

  it('doesn\'t parse conditions that don\'t end with )', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x > 0.1 R1 R2'));
    expect(rules.errors[0].error).toBe('Expected a condition');
  });

  it('doesn\'t parse conditions with other stuff than parameters or numbers', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (R1 > 0.1) R1 R2'));
    expect(rules.errors[0].error).toBe('Expected a condition');
  });

  it('doesn\'t parse invalid notes', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> Piano: C / J Caug2'));
    expect(rules.errors[0].error).toBe('Expected a note, chord, drum symbol or pause');
  });

  it('can parse incomplete rules', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1'));
    expect(rules.length).toBe(1);
  });

  it('can parse empty definitions', function() {
    var rules1 = Polyhymnia.parse(Polyhymnia.tokenize('R1 ->'));
    expect(rules1.length).toBe(1);

    var rules2 = Polyhymnia.parse(Polyhymnia.tokenize('R1 ->\n'));
    expect(rules2.length).toBe(1);

    var rules3 = Polyhymnia.parse(Polyhymnia.tokenize('R1 ->\nR2 -> R3'));
    expect(rules3[0].name).toBe('R1');
    expect(rules3[1].name).toBe('R2');
    expect(rules3[1].definitions[0].sequence[0]).toBe('R3');

    var rules4 = Polyhymnia.parse(Polyhymnia.tokenize('R1 ->\n\nR2 -> R3'));
    expect(rules4[0].name).toBe('R1');
    expect(rules4[1].name).toBe('R2');
    expect(rules4[1].definitions[0].sequence[0]).toBe('R3');
  });

  it('can parse empty definitions with condition', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> (x > 0.3)'));
    expect(rules[0].definitions[0]).toEqual({});
  });

  it('ignores line breaks after arrow', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 ->\nR2\nR3'));
    expect(rules[0].name).toBe('R1');
    expect(rules[0].definitions[0].sequence[0]).toBe('R2');
    expect(rules[0].definitions[1].sequence[0]).toBe('R3');
  });

  it('ignores line breaks before the first rule', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('\n\nR1 -> R2 R1\n\nR2 -> Piano: C'));
    expect(rules[0].name).toBe('R1');
  });

  it('ignores line breaks after the last rule', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> R2 R1\n\nR2 -> Piano: C\n\n'));
    expect(rules[0].name).toBe('R1');
  });

  it('ignores extra line breaks between rules', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> R2 R2\n\n\n\nR2 -> Piano: C'));
    expect(rules[0].name).toBe('R1');
    expect(rules[1].name).toBe('R2');
  });

  it('flags missing rules', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> R2'));
    expect(rules.errors[0].error).toBe('There is no rule R2');
  });

  it('flags missing instruments', function() {
    var rules = Polyhymnia.parse(Polyhymnia.tokenize('R1 -> Piano: C'), {});
    expect(rules.errors[0].error).toBe('There is no instrument Piano');
  });
});<|endoftext|>


<commit_before>'use strict';

var util = require('util');

const mongoErrorContextSymbol = Symbol('mongoErrorContextSymbol');

/**
 * Creates a new MongoError
 * @class
 * @augments Error
 * @param {Error|string|object} message The error message
 * @property {string} message The error message
 * @property {string} stack The error call stack
 * @return {MongoError} A MongoError instance
 */
function MongoError(message) {
  var tmp = Error.apply(this, arguments);
  tmp.name = this.name = 'MongoError';

  if (message instanceof Error) {
    this.message = message.message;
    this.stack = message.stack;
  } else {
    if (typeof message === 'string') {
      this.message = message;
    } else {
      this.message = message.message || message.errmsg || message.$err || 'n/a';
      for (var name in message) {
        this[name] = message[name];
      }
    }
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, this.constructor);
    }
  }

  this[mongoErrorContextSymbol] = this[mongoErrorContextSymbol] || {};
}
util.inherits(MongoError, Error);

/**
 * Creates a new MongoError object
 * @method
 * @param {Error|string|object} options The options used to create the error.
 * @return {MongoError} A MongoError instance
 * @deprecated Use `new MongoError()` instead.
 */
MongoError.create = function(options) {
  return new MongoError(options);
};

/**
 * Creates a new MongoNetworkError
 * @class
 * @param {Error|string|object} message The error message
 * @property {string} message The error message
 * @property {string} stack The error call stack
 * @return {MongoNetworkError} A MongoNetworkError instance
 * @extends {MongoError}
 */
var MongoNetworkError = function(message) {
  MongoError.call(this, message);
  this.name = 'MongoNetworkError';

  // This is added as part of the transactions specification
  this.errorLabels = ['TransientTransactionError'];
};
util.inherits(MongoNetworkError, MongoError);

/**
 * An error used when attempting to parse a value (like a connection string)
 *
 * @class
 * @param {Error|string|object} message The error message
 * @property {string} message The error message
 * @return {MongoParseError} A MongoParseError instance
 * @extends {MongoError}
 */
const MongoParseError = function(message) {
  MongoError.call(this, message);
  this.name = 'MongoParseError';
};
util.inherits(MongoParseError, MongoError);

/**
 * An error signifying a timeout event
 *
 * @class
 * @param {Error|string|object} message The error message
 * @property {string} message The error message
 * @return {MongoTimeoutError} A MongoTimeoutError instance
 * @extends {MongoError}
 */
const MongoTimeoutError = function(message) {
  MongoError.call(this, message);
  this.name = 'MongoTimeoutError';
};
util.inherits(MongoTimeoutError, MongoError);

// see: https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.rst#terms
const RETRYABLE_ERROR_CODES = new Set([
  6, // HostUnreachable
  7, // HostNotFound
  64, // WriteConcernFailed
  89, // NetworkTimeout
  91, // ShutdownInProgress
  189, // PrimarySteppedDown
  9001, // SocketException
  11600, // InterruptedAtShutdown
  11602, // InterruptedDueToReplStateChange
  10107, // NotMaster
  13435, // NotMasterNoSlaveOk
  13436 // NotMasterOrSecondary
]);

function isRetryableError(error) {
  if (
    RETRYABLE_ERROR_CODES.has(error.code) ||
    error instanceof MongoNetworkError ||
    error.message.match(/not master/) ||
    error.message.match(/node is recovering/)
  ) {
    return true;
  }

  return false;
}

/**
 * An error thrown when the server reports a writeConcernError
 *
 * @class
 * @param {Error|string|object} message The error message
 * @property {string} message The error message
 * @return {MongoWriteConcernError} A MongoWriteConcernError instance
 * @extends {MongoError}
 */
const MongoWriteConcernError = function(message) {
  MongoError.call(this, message);
  this.name = 'MongoWriteConcernError';
};
util.inherits(MongoWriteConcernError, MongoError);

module.exports = {
  MongoError,
  MongoNetworkError,
  MongoParseError,
  MongoTimeoutError,
  MongoWriteConcernError,
  mongoErrorContextSymbol,
  isRetryableError
};
<commit_msg>refactor(error): update list of retryable error codes<commit_after>'use strict';

var util = require('util');

const mongoErrorContextSymbol = Symbol('mongoErrorContextSymbol');

/**
 * Creates a new MongoError
 * @class
 * @augments Error
 * @param {Error|string|object} message The error message
 * @property {string} message The error message
 * @property {string} stack The error call stack
 * @return {MongoError} A MongoError instance
 */
function MongoError(message) {
  var tmp = Error.apply(this, arguments);
  tmp.name = this.name = 'MongoError';

  if (message instanceof Error) {
    this.message = message.message;
    this.stack = message.stack;
  } else {
    if (typeof message === 'string') {
      this.message = message;
    } else {
      this.message = message.message || message.errmsg || message.$err || 'n/a';
      for (var name in message) {
        this[name] = message[name];
      }
    }
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, this.constructor);
    }
  }

  this[mongoErrorContextSymbol] = this[mongoErrorContextSymbol] || {};
}
util.inherits(MongoError, Error);

/**
 * Creates a new MongoError object
 * @method
 * @param {Error|string|object} options The options used to create the error.
 * @return {MongoError} A MongoError instance
 * @deprecated Use `new MongoError()` instead.
 */
MongoError.create = function(options) {
  return new MongoError(options);
};

/**
 * Creates a new MongoNetworkError
 * @class
 * @param {Error|string|object} message The error message
 * @property {string} message The error message
 * @property {string} stack The error call stack
 * @return {MongoNetworkError} A MongoNetworkError instance
 * @extends {MongoError}
 */
var MongoNetworkError = function(message) {
  MongoError.call(this, message);
  this.name = 'MongoNetworkError';

  // This is added as part of the transactions specification
  this.errorLabels = ['TransientTransactionError'];
};
util.inherits(MongoNetworkError, MongoError);

/**
 * An error used when attempting to parse a value (like a connection string)
 *
 * @class
 * @param {Error|string|object} message The error message
 * @property {string} message The error message
 * @return {MongoParseError} A MongoParseError instance
 * @extends {MongoError}
 */
const MongoParseError = function(message) {
  MongoError.call(this, message);
  this.name = 'MongoParseError';
};
util.inherits(MongoParseError, MongoError);

/**
 * An error signifying a timeout event
 *
 * @class
 * @param {Error|string|object} message The error message
 * @property {string} message The error message
 * @return {MongoTimeoutError} A MongoTimeoutError instance
 * @extends {MongoError}
 */
const MongoTimeoutError = function(message) {
  MongoError.call(this, message);
  this.name = 'MongoTimeoutError';
};
util.inherits(MongoTimeoutError, MongoError);

// see: https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.rst#terms
const RETRYABLE_ERROR_CODES = new Set([
  6, // HostUnreachable
  7, // HostNotFound
  89, // NetworkTimeout
  91, // ShutdownInProgress
  189, // PrimarySteppedDown
  9001, // SocketException
  10107, // NotMaster
  11600, // InterruptedAtShutdown
  11602, // InterruptedDueToReplStateChange
  13435, // NotMasterNoSlaveOk
  13436 // NotMasterOrSecondary
]);

function isRetryableError(error) {
  if (
    RETRYABLE_ERROR_CODES.has(error.code) ||
    error instanceof MongoNetworkError ||
    error.message.match(/not master/) ||
    error.message.match(/node is recovering/)
  ) {
    return true;
  }

  return false;
}

/**
 * An error thrown when the server reports a writeConcernError
 *
 * @class
 * @param {Error|string|object} message The error message
 * @property {string} message The error message
 * @return {MongoWriteConcernError} A MongoWriteConcernError instance
 * @extends {MongoError}
 */
const MongoWriteConcernError = function(message) {
  MongoError.call(this, message);
  this.name = 'MongoWriteConcernError';
};
util.inherits(MongoWriteConcernError, MongoError);

module.exports = {
  MongoError,
  MongoNetworkError,
  MongoParseError,
  MongoTimeoutError,
  MongoWriteConcernError,
  mongoErrorContextSymbol,
  isRetryableError
};
<|endoftext|>


<commit_before>define(['jquery', 'bacon', 'bacon.jquery'], function($, bacon, bjq) {
	$(document).ready(function() {
		var width = $('#widthInput').asEventStream('keyup').map(function(e) {
			return parseInt($(e.target).val());
		});
		var height = $('#heightInput').asEventStream('keyup').map(function(e) {
			return parseInt($(e.target).val());
		});
		var both = bacon.combineAsArray(width, height);
		both.onValue(function(val) {
			console.log(val)
		})
	});
});<commit_msg>add initial flow from form elements to figuring out print-sizes<commit_after>define(['jquery', 'bacon', 'bacon.jquery', 'printanalyzer/findBestAR', 'printanalyzer/AspectRatio', 'vow'], function($, bacon, bjq, findBestAR, AspectRatio, vow) {
	$(document).ready(function() {

		//reading from form changes
		var width = bjq.textFieldValue($('#widthInput')).changes().map(function(e) {
			return parseInt(e)
		});
		var height = bjq.textFieldValue($('#heightInput')).changes().map(function(e) {
			return parseInt(e);
		})

		var both = bacon.combineAsArray(width, height);
		both.onValue(function(val) {
			return new vow.Promise(function(resolve, reject){
				if (val[0] > 0 && val[1] > 0) {
					resolve(findBestAR(val[0], val[1]));
				} else {
					reject(new Error("Bad response" + this.status));
				}
			}).then(function(AR) {
				if (AR) {
					return AR.ratio.findSizes({width: val[0], height: val[1]}, 130, 150);
				} else {
					console.log("Bad dimensions");
				}
			}).then(function(sizes) {
				console.log(sizes);
			});
		});
	});
});<|endoftext|>


<commit_before>---
---
{% include javascript/jquery-1.11.1.min.js %}
{% include javascript/turbolinks.js %}
{% include javascript/modernizr.js %}
{% include javascript/scrollr.js %}
{% include javascript/jquery.sharrre.js %}
{% include javascript/viglink.js %}

// on mobile / touch devices, get rid of the fadeOut titles on image posts
if (Modernizr.touch)
  skrollr.init().destroy();
else
  var s = skrollr.init();

initialize_post();

function initialize_post() {
  var share_buttons = $('.share-buttons');

  // fix for vh bug in iOS7
  var iOS = navigator.userAgent.match(/(iPod|iPhone|iPad)/);
  if(iOS){
    function iosVhHeightBug() {
      var height = $(window).height();
      $(".main-image-clear, .post-main-image, .image-h1-wrapper-outer").css('height', height);
    }

    iosVhHeightBug();
    $(window).bind('resize', iosVhHeightBug);
  }

  // js for share buttons
  if (share_buttons.length) {
    var share_buttons_position = share_buttons.offset();
    var $window = $(window);

    $window.scroll(function() {
      if($window.width() > 979) {
        if ( $(this).scrollTop() > ( $('.share-buttons-wrap').height() + 554 ) ) {
          share_buttons.css('position','absolute').css('top', 'auto').css('bottom', '0');
        } else if ( $window.scrollTop() > ( share_buttons_position.top - 88 ) ) {
          share_buttons.css('position', 'fixed').css('top', '88px').css('bottom', 'auto');
        } else {
          share_buttons.css('position','absolute').css('top', '0').css('bottom', 'auto');
        }
      }
    });

    $(window).resize(function() {
      // on window resize, unset any styles to the share buttons
      if($(this).width() < 979) {
        $('.share-buttons').attr('style', '');
      }
    });

    $('#shareme').sharrre({
      share: {
        twitter: true,
        facebook: true,
        googlePlus: true
      },
      urlCurl: 'http://become-fluent.com/sharrre.php',
      template: '',
      enableHover: false,
      enableTracking: true,
      render: function(api, options){
        $('.share-count.facebook').html(options.count.facebook);
        $('.share-count.twitter').html(options.count.twitter);
        $('.share-count.googleplus').html(options.count.googlePlus);
      }
    });

    // make share links open in popup
    $('.share-link').on('click', function(e) {
      var _this = $(this);
      popupCenter(_this.attr('href'), _this.find('.text').html(), 580, 470);
      e.preventDefault();
    });

    var popupCenter = function(url, title, w, h) {
      // Fixes dual-screen position                         Most browsers      Firefox
      var dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left;
      var dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top;

      var width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
      var height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;

      var left = ((width / 2) - (w / 2)) + dualScreenLeft;
      var top = ((height / 3) - (h / 3)) + dualScreenTop;

      var newWindow = window.open(url, title, 'scrollbars=yes, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left);

      // Puts focus on the newWindow
      if (window.focus) {
        newWindow.focus();
      }
    };
  }
}<commit_msg>sharrre fix<commit_after>---
---
{% include javascript/jquery-1.11.1.min.js %}
{% include javascript/turbolinks.js %}
{% include javascript/modernizr.js %}
{% include javascript/scrollr.js %}
{% include javascript/jquery.sharrre.js %}
{% include javascript/viglink.js %}

// on mobile / touch devices, get rid of the fadeOut titles on image posts
if (Modernizr.touch)
  skrollr.init().destroy();
else
  var s = skrollr.init();

initialize_post();

function initialize_post() {
  var share_buttons = $('.share-buttons');

  // fix for vh bug in iOS7
  var iOS = navigator.userAgent.match(/(iPod|iPhone|iPad)/);
  if(iOS){
    function iosVhHeightBug() {
      var height = $(window).height();
      $(".main-image-clear, .post-main-image, .image-h1-wrapper-outer").css('height', height);
    }

    iosVhHeightBug();
    $(window).bind('resize', iosVhHeightBug);
  }

  // js for share buttons
  if (share_buttons.length) {
    var share_buttons_position = share_buttons.offset();
    var $window = $(window);

    $window.scroll(function() {
      if($window.width() > 979) {
        if ( $(this).scrollTop() > ( $('.share-buttons-wrap').height() + 554 ) ) {
          share_buttons.css('position','absolute').css('top', 'auto').css('bottom', '0');
        } else if ( $window.scrollTop() > ( share_buttons_position.top - 88 ) ) {
          share_buttons.css('position', 'fixed').css('top', '88px').css('bottom', 'auto');
        } else {
          share_buttons.css('position','absolute').css('top', '0').css('bottom', 'auto');
        }
      }
    });

    $(window).resize(function() {
      // on window resize, unset any styles to the share buttons
      if($(this).width() < 979) {
        $('.share-buttons').attr('style', '');
      }
    });

    $('#shareme').sharrre({
      share: {
        twitter: true,
        facebook: true,
        googlePlus: true
      },
      urlCurl: 'https://goodandlost.com/sharrre.php',
      template: '',
      enableHover: false,
      enableTracking: true,
      render: function(api, options){
        $('.share-count.facebook').html(options.count.facebook);
        $('.share-count.twitter').html(options.count.twitter);
        $('.share-count.googleplus').html(options.count.googlePlus);
      }
    });

    // make share links open in popup
    $('.share-link').on('click', function(e) {
      var _this = $(this);
      popupCenter(_this.attr('href'), _this.find('.text').html(), 580, 470);
      e.preventDefault();
    });

    var popupCenter = function(url, title, w, h) {
      // Fixes dual-screen position                         Most browsers      Firefox
      var dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left;
      var dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top;

      var width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
      var height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;

      var left = ((width / 2) - (w / 2)) + dualScreenLeft;
      var top = ((height / 3) - (h / 3)) + dualScreenTop;

      var newWindow = window.open(url, title, 'scrollbars=yes, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left);

      // Puts focus on the newWindow
      if (window.focus) {
        newWindow.focus();
      }
    };
  }
}<|endoftext|>


<commit_before>const getLanguage = require('./language').getLanguage;

/**
 * Router module for ChampionFX
 * Some code was borrowed from pjax lib
 * https://github.com/defunkt/jquery-pjax
 */
const ChampionRouter = (function() {
    'use strict';

    let xhr;
    const params   = {},
        defaults = {
            timeout : 650,
            type    : 'GET',
            dataType: 'html',
        },
        cache = {};

    const init = (container, content_selector) => {
        if (!(window.history && window.history.pushState && window.history.replaceState &&
            // pushState isn't reliable on iOS until 5.
            !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/))) {
            console.error('Unable to initialize router');
            return;
        }

        container = $(container);

        if (!container.length) {
            console.error('Could not find container');
            return;
        }

        if (!(content_selector && content_selector.length)) {
            console.error('No content selector provided');
            return;
        }

        params.container = container;
        params.content_selector = content_selector;

        const url = window.location.href;
        const title = document.title;
        const content = container.find(content_selector);

        // put current content to cache, so we won't need to load it again
        if (title && content && content.length) {
            cachePut(url, {
                title  : title,
                content: content,
            });
            window.history.replaceState({ url: url }, title, url);
            content.attr('data-page', url.match('.+\/(.+)\.html.*')[1]);
            params.container.trigger('champion:after', content);
        }

        $(document).on('click', 'a', handleClick);
        $(window).on('popstate', handlePopstate);
    };

    const handleClick = (event) => {
        const link = event.currentTarget,
            url = link.href;

        if (url.length <= 0) {
            return;
        }
        // Middle click, cmd click, and ctrl click should open
        // links in a new tab as normal.
        if (event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
            return;
        }

        // Ignore cross origin links
        if (location.protocol !== link.protocol || location.hostname !== link.hostname) {
            return;
        }

        // Ignore event with default prevented
        if (event.isDefaultPrevented()) {
            return;
        }

        event.preventDefault();
        // check if url is not same as current
        if (location.href !== url) {
            processUrl(url);
        }
    };

    const processUrl = (url, replace) => {
        const cached_content = cacheGet(url);
        if (cached_content) {
            replaceContent(url, cached_content, replace);
        } else {
            load(url, replace);
        }
    };

    /**
     * Load url from server
     */
    const load = (url, replace) => {
        const lang = getLanguage();
        const options = $.extend(true, {}, $.ajaxSettings, defaults, {
            url: url.replace(new RegExp(`\/${lang}\/`, 'i'), `/${lang.toLowerCase()}/pjax/`) });

        options.success = (data) => {
            const result = {};

            result.title   = $(data).find('title').text().trim();
            result.content = $('<div/>', { html: data }).find(params.content_selector);

            // If failed to find title or content, load the page in traditional way
            if (result.title.length === 0 || result.content.length === 0) {
                locationReplace(url);
                return;
            }

            cachePut(url, result);
            replaceContent(url, result, replace);
        };

        // Cancel the current request if we're already loading some page
        abortXHR(xhr);

        xhr = $.ajax(options);
    };

    const handlePopstate = (e) => {
        const url = e.originalEvent.state ? e.originalEvent.state.url : window.location.href;
        if (url) {
            processUrl(url, true);
        }
        return false;
    };

    const replaceContent = (url, content, replace) => {
        window.history[replace ? 'replaceState' : 'pushState']({ url: url }, content.title, url);

        params.container.trigger('champion:before');

        document.title = content.title;
        params.container.find(params.content_selector).remove();
        params.container.append(content.content);

        params.container.trigger('champion:after', content.content);
    };

    const abortXHR = (xhrObj) => {
        if (xhrObj && xhrObj.readyState < 4) {
            xhrObj.abort();
        }
    };

    const cachePut = (url, content) => {
        cache[url] = content;
    };

    const cacheGet = url => cache[url];

    const locationReplace = (url) => {
        window.history.replaceState(null, '', url);
        window.location.replace(url);
    };

    return {
        init   : init,
        forward: processUrl,
    };
})();

module.exports = ChampionRouter;
<commit_msg>Fix links event<commit_after>const getLanguage = require('./language').getLanguage;

/**
 * Router module for ChampionFX
 * Some code was borrowed from pjax lib
 * https://github.com/defunkt/jquery-pjax
 */
const ChampionRouter = (function() {
    'use strict';

    let xhr;
    const params   = {},
        defaults = {
            timeout : 650,
            type    : 'GET',
            dataType: 'html',
        },
        cache = {};

    const init = (container, content_selector) => {
        if (!(window.history && window.history.pushState && window.history.replaceState &&
            // pushState isn't reliable on iOS until 5.
            !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/))) {
            console.error('Unable to initialize router');
            return;
        }

        container = $(container);

        if (!container.length) {
            console.error('Could not find container');
            return;
        }

        if (!(content_selector && content_selector.length)) {
            console.error('No content selector provided');
            return;
        }

        params.container = container;
        params.content_selector = content_selector;

        const url = window.location.href;
        const title = document.title;
        const content = container.find(content_selector);

        // put current content to cache, so we won't need to load it again
        if (title && content && content.length) {
            cachePut(url, {
                title  : title,
                content: content,
            });
            window.history.replaceState({ url: url }, title, url);
            content.attr('data-page', url.match('.+\/(.+)\.html.*')[1]);
            params.container.trigger('champion:after', content);
        }

        $(document).find('a').on('click', handleClick);
        $(window).on('popstate', handlePopstate);
    };

    const handleClick = (event) => {
        const link = event.currentTarget,
            url = link.href;

        if (url.length <= 0) {
            return;
        }
        // Middle click, cmd click, and ctrl click should open
        // links in a new tab as normal.
        if (event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
            return;
        }

        // Ignore cross origin links
        if (location.protocol !== link.protocol || location.hostname !== link.hostname) {
            return;
        }

        // Ignore event with default prevented
        if (event.isDefaultPrevented()) {
            return;
        }

        event.preventDefault();
        // check if url is not same as current
        if (location.href !== url) {
            processUrl(url);
        }
    };

    const processUrl = (url, replace) => {
        const cached_content = cacheGet(url);
        if (cached_content) {
            replaceContent(url, cached_content, replace);
        } else {
            load(url, replace);
        }
    };

    /**
     * Load url from server
     */
    const load = (url, replace) => {
        const lang = getLanguage();
        const options = $.extend(true, {}, $.ajaxSettings, defaults, {
            url: url.replace(new RegExp(`\/${lang}\/`, 'i'), `/${lang.toLowerCase()}/pjax/`) });

        options.success = (data) => {
            const result = {};

            result.title   = $(data).find('title').text().trim();
            result.content = $('<div/>', { html: data }).find(params.content_selector);

            // If failed to find title or content, load the page in traditional way
            if (result.title.length === 0 || result.content.length === 0) {
                locationReplace(url);
                return;
            }

            cachePut(url, result);
            replaceContent(url, result, replace);
        };

        // Cancel the current request if we're already loading some page
        abortXHR(xhr);

        xhr = $.ajax(options);
    };

    const handlePopstate = (e) => {
        const url = e.originalEvent.state ? e.originalEvent.state.url : window.location.href;
        if (url) {
            processUrl(url, true);
        }
        return false;
    };

    const replaceContent = (url, content, replace) => {
        window.history[replace ? 'replaceState' : 'pushState']({ url: url }, content.title, url);

        params.container.trigger('champion:before');

        document.title = content.title;
        params.container.find(params.content_selector).remove();
        params.container.append(content.content);

        params.container.trigger('champion:after', content.content);
    };

    const abortXHR = (xhrObj) => {
        if (xhrObj && xhrObj.readyState < 4) {
            xhrObj.abort();
        }
    };

    const cachePut = (url, content) => {
        cache[url] = content;
    };

    const cacheGet = url => cache[url];

    const locationReplace = (url) => {
        window.history.replaceState(null, '', url);
        window.location.replace(url);
    };

    return {
        init   : init,
        forward: processUrl,
    };
})();

module.exports = ChampionRouter;
<|endoftext|>