<commit_before>// An example Backbone application contributed by
// [Jérôme Gravel-Niquet](http://jgn.me/). This demo uses a simple
// [LocalStorage adapter](backbone-localstorage.html)
// to persist Backbone models within your browser.

// Load the application once the DOM is ready, using `jQuery.ready`:
$(function(){

  // Todo Model
  // ----------

  // Our basic **Todo** model has `title`, `order`, and `done` attributes.
  var Todo = Backbone.Model.extend({

    // Default attributes for the todo item.
    defaults: function() {
      return {
        title: "empty todo...",
        order: Todos.nextOrder(),
        done: false
      };
    },

    // Ensure that each todo created has `title`.
    initialize: function() {
      if (!this.get("title")) {
        this.set({"title": this.defaults().title});
      }
    },

    // Toggle the `done` state of this todo item.
    toggle: function() {
      this.save({done: !this.get("done")});
    }

  });

  // Todo Collection
  // ---------------

  // The collection of todos is backed by *localStorage* instead of a remote
  // server.
  var TodoList = Backbone.Collection.extend({

    // Reference to this collection's model.
    model: Todo,

    // Save all of the todo items under the `"todos-backbone"` namespace.
    localStorage: new Backbone.LocalStorage("todos-backbone"),

    // Filter down the list of all todo items that are finished.
    done: function() {
      return this.filter(function(todo){ return todo.get('done'); });
    },

    // Filter down the list to only todo items that are still not finished.
    remaining: function() {
      return this.without.apply(this, this.done());
    },

    // We keep the Todos in sequential order, despite being saved by unordered
    // GUID in the database. This generates the next order number for new items.
    nextOrder: function() {
      if (!this.length) return 1;
      return this.last().get('order') + 1;
    },

    // Todos are sorted by their original insertion order.
    comparator: function(todo) {
      return todo.get('order');
    }

  });

  // Create our global collection of **Todos**.
  var Todos = new TodoList;

  // Todo Item View
  // --------------

  // The DOM element for a todo item...
  var TodoView = Backbone.View.extend({

    //... is a list tag.
    tagName:  "li",

    // Cache the template function for a single item.
    template: _.template($('#item-template').html()),

    // The DOM events specific to an item.
    events: {
      "click .toggle"   : "toggleDone",
      "dblclick .view"  : "edit",
      "click a.destroy" : "clear",
      "keypress .edit"  : "updateOnEnter",
      "blur .edit"      : "close"
    },

    // The TodoView listens for changes to its model, re-rendering. Since there's
    // a one-to-one correspondence between a **Todo** and a **TodoView** in this
    // app, we set a direct reference on the model for convenience.
    initialize: function() {
      this.listenTo(this.model, 'change', this.render);
      this.listenTo(this.model, 'destroy', this.remove);
    },

    // Re-render the titles of the todo item.
    render: function() {
      this.$el.html(this.template(this.model.toJSON()));
      this.$el.toggleClass('done', this.model.get('done'));
      this.input = this.$('.edit');
      return this;
    },

    // Toggle the `"done"` state of the model.
    toggleDone: function() {
      this.model.toggle();
    },

    // Switch this view into `"editing"` mode, displaying the input field.
    edit: function() {
      this.$el.addClass("editing");
      this.input.focus();
    },

    // Close the `"editing"` mode, saving changes to the todo.
    close: function() {
      var value = this.input.val();
      if (!value) {
        this.clear();
      } else {
        this.model.save({title: value});
        this.$el.removeClass("editing");
      }
    },

    // If you hit `enter`, we're through editing the item.
    updateOnEnter: function(e) {
      if (e.keyCode == 13) this.close();
    },

    // Remove the item, destroy the model.
    clear: function() {
      this.model.destroy();
    }

  });

  // The Application
  // ---------------

  // Our overall **AppView** is the top-level piece of UI.
  var AppView = Backbone.View.extend({

    // Instead of generating a new element, bind to the existing skeleton of
    // the App already present in the HTML.
    el: $("#todoapp"),

    // Our template for the line of statistics at the bottom of the app.
    statsTemplate: _.template($('#stats-template').html()),

    // Delegated events for creating new items, and clearing completed ones.
    events: {
      "keypress #new-todo":  "createOnEnter",
      "click #clear-completed": "clearCompleted",
      "click #toggle-all": "toggleAllComplete"
    },

    // At initialization we bind to the relevant events on the `Todos`
    // collection, when items are added or changed. Kick things off by
    // loading any preexisting todos that might be saved in *localStorage*.
    initialize: function() {

      this.input = this.$("#new-todo");
      this.allCheckbox = this.$("#toggle-all")[0];

      this.listenTo(Todos, 'add', this.addOne);
      this.listenTo(Todos, 'reset', this.addAll);
      this.listenTo(Todos, 'all', this.render);

      this.footer = this.$('footer');
      this.main = $('#main');

      Todos.fetch();
    },

    // Re-rendering the App just means refreshing the statistics -- the rest
    // of the app doesn't change.
    render: function() {
      var done = Todos.done().length;
      var remaining = Todos.remaining().length;

      if (Todos.length) {
        this.main.show();
        this.footer.show();
        this.footer.html(this.statsTemplate({done: done, remaining: remaining}));
      } else {
        this.main.hide();
        this.footer.hide();
      }

      this.allCheckbox.checked = !remaining;
    },

    // Add a single todo item to the list by creating a view for it, and
    // appending its element to the `<ul>`.
    addOne: function(todo) {
      var view = new TodoView({model: todo});
      this.$("#todo-list").append(view.render().el);
    },

    // Add all items in the **Todos** collection at once.
    addAll: function() {
      Todos.each(this.addOne, this);
    },

    // If you hit return in the main input field, create new **Todo** model,
    // persisting it to *localStorage*.
    createOnEnter: function(e) {
      if (e.keyCode != 13) return;
      if (!this.input.val()) return;

      Todos.create({title: this.input.val()});
      this.input.val('');
    },

    // Clear all done todo items, destroying their models.
    clearCompleted: function() {
      _.invoke(Todos.done(), 'destroy');
      return false;
    },

    toggleAllComplete: function () {
      var done = this.allCheckbox.checked;
      Todos.each(function (todo) { todo.save({'done': done}); });
    }

  });

  // Finally, we kick things off by creating the **App**.
  var App = new AppView;

});
<commit_msg>remove initialize defaults logic; defaults handles this for us<commit_after>// An example Backbone application contributed by
// [Jérôme Gravel-Niquet](http://jgn.me/). This demo uses a simple
// [LocalStorage adapter](backbone-localstorage.html)
// to persist Backbone models within your browser.

// Load the application once the DOM is ready, using `jQuery.ready`:
$(function(){

  // Todo Model
  // ----------

  // Our basic **Todo** model has `title`, `order`, and `done` attributes.
  var Todo = Backbone.Model.extend({

    // Default attributes for the todo item.
    defaults: function() {
      return {
        title: "empty todo...",
        order: Todos.nextOrder(),
        done: false
      };
    },

    // Toggle the `done` state of this todo item.
    toggle: function() {
      this.save({done: !this.get("done")});
    }

  });

  // Todo Collection
  // ---------------

  // The collection of todos is backed by *localStorage* instead of a remote
  // server.
  var TodoList = Backbone.Collection.extend({

    // Reference to this collection's model.
    model: Todo,

    // Save all of the todo items under the `"todos-backbone"` namespace.
    localStorage: new Backbone.LocalStorage("todos-backbone"),

    // Filter down the list of all todo items that are finished.
    done: function() {
      return this.filter(function(todo){ return todo.get('done'); });
    },

    // Filter down the list to only todo items that are still not finished.
    remaining: function() {
      return this.without.apply(this, this.done());
    },

    // We keep the Todos in sequential order, despite being saved by unordered
    // GUID in the database. This generates the next order number for new items.
    nextOrder: function() {
      if (!this.length) return 1;
      return this.last().get('order') + 1;
    },

    // Todos are sorted by their original insertion order.
    comparator: function(todo) {
      return todo.get('order');
    }

  });

  // Create our global collection of **Todos**.
  var Todos = new TodoList;

  // Todo Item View
  // --------------

  // The DOM element for a todo item...
  var TodoView = Backbone.View.extend({

    //... is a list tag.
    tagName:  "li",

    // Cache the template function for a single item.
    template: _.template($('#item-template').html()),

    // The DOM events specific to an item.
    events: {
      "click .toggle"   : "toggleDone",
      "dblclick .view"  : "edit",
      "click a.destroy" : "clear",
      "keypress .edit"  : "updateOnEnter",
      "blur .edit"      : "close"
    },

    // The TodoView listens for changes to its model, re-rendering. Since there's
    // a one-to-one correspondence between a **Todo** and a **TodoView** in this
    // app, we set a direct reference on the model for convenience.
    initialize: function() {
      this.listenTo(this.model, 'change', this.render);
      this.listenTo(this.model, 'destroy', this.remove);
    },

    // Re-render the titles of the todo item.
    render: function() {
      this.$el.html(this.template(this.model.toJSON()));
      this.$el.toggleClass('done', this.model.get('done'));
      this.input = this.$('.edit');
      return this;
    },

    // Toggle the `"done"` state of the model.
    toggleDone: function() {
      this.model.toggle();
    },

    // Switch this view into `"editing"` mode, displaying the input field.
    edit: function() {
      this.$el.addClass("editing");
      this.input.focus();
    },

    // Close the `"editing"` mode, saving changes to the todo.
    close: function() {
      var value = this.input.val();
      if (!value) {
        this.clear();
      } else {
        this.model.save({title: value});
        this.$el.removeClass("editing");
      }
    },

    // If you hit `enter`, we're through editing the item.
    updateOnEnter: function(e) {
      if (e.keyCode == 13) this.close();
    },

    // Remove the item, destroy the model.
    clear: function() {
      this.model.destroy();
    }

  });

  // The Application
  // ---------------

  // Our overall **AppView** is the top-level piece of UI.
  var AppView = Backbone.View.extend({

    // Instead of generating a new element, bind to the existing skeleton of
    // the App already present in the HTML.
    el: $("#todoapp"),

    // Our template for the line of statistics at the bottom of the app.
    statsTemplate: _.template($('#stats-template').html()),

    // Delegated events for creating new items, and clearing completed ones.
    events: {
      "keypress #new-todo":  "createOnEnter",
      "click #clear-completed": "clearCompleted",
      "click #toggle-all": "toggleAllComplete"
    },

    // At initialization we bind to the relevant events on the `Todos`
    // collection, when items are added or changed. Kick things off by
    // loading any preexisting todos that might be saved in *localStorage*.
    initialize: function() {

      this.input = this.$("#new-todo");
      this.allCheckbox = this.$("#toggle-all")[0];

      this.listenTo(Todos, 'add', this.addOne);
      this.listenTo(Todos, 'reset', this.addAll);
      this.listenTo(Todos, 'all', this.render);

      this.footer = this.$('footer');
      this.main = $('#main');

      Todos.fetch();
    },

    // Re-rendering the App just means refreshing the statistics -- the rest
    // of the app doesn't change.
    render: function() {
      var done = Todos.done().length;
      var remaining = Todos.remaining().length;

      if (Todos.length) {
        this.main.show();
        this.footer.show();
        this.footer.html(this.statsTemplate({done: done, remaining: remaining}));
      } else {
        this.main.hide();
        this.footer.hide();
      }

      this.allCheckbox.checked = !remaining;
    },

    // Add a single todo item to the list by creating a view for it, and
    // appending its element to the `<ul>`.
    addOne: function(todo) {
      var view = new TodoView({model: todo});
      this.$("#todo-list").append(view.render().el);
    },

    // Add all items in the **Todos** collection at once.
    addAll: function() {
      Todos.each(this.addOne, this);
    },

    // If you hit return in the main input field, create new **Todo** model,
    // persisting it to *localStorage*.
    createOnEnter: function(e) {
      if (e.keyCode != 13) return;
      if (!this.input.val()) return;

      Todos.create({title: this.input.val()});
      this.input.val('');
    },

    // Clear all done todo items, destroying their models.
    clearCompleted: function() {
      _.invoke(Todos.done(), 'destroy');
      return false;
    },

    toggleAllComplete: function () {
      var done = this.allCheckbox.checked;
      Todos.each(function (todo) { todo.save({'done': done}); });
    }

  });

  // Finally, we kick things off by creating the **App**.
  var App = new AppView;

});
<|endoftext|>


<commit_before>'use strict'

const yaml = require('js-yaml')
const fs = require('fs')
const path = require('path')
const _ = require('halcyon')

const config = {
  /**
   * @property {string} Default location of binci.yml config file
   */
  defaultPath: `${process.cwd()}/binci.yml`,
  /**
   * Loads config from yaml, attempts to parse to object
   * @param {string} (configPath) Path to config file or use defaultPath
   * @returns {object}
   */
  load: (configPath = config.defaultPath) => {
    try {
      fs.statSync(configPath)
    } catch (err) {
      throw new Error([
        `No config found at ${configPath}.`,
        'Please run `binci init` to create a binci.yml file or specify one with the `-c` flag.'
      ].join(' '))
    }

    let cfg
    try {
      cfg = yaml.safeLoad(fs.readFileSync(configPath, 'utf8'))
    } catch (e) {
      const relPath = path.relative(process.cwd(), configPath)
      const error = new Error(`Please fix the errors in ${relPath}`)
      error.message = error.message + `:\n\n${e.message}`
      throw error
    }
    return config.validate(cfg)
  },
  /**
   * Filters out empty config properties
   * @param {object}
   * @returns {object}
   */
  validate: (cfg) => _.pipe([
    _.toPairs,
    _.reject(([key, val]) => key !== 'tasks' && key !== 'from' && _.isEmpty(val) || _.isNil(val)),
    _.fromPairs
  ])(cfg)
}

module.exports = config
<commit_msg>refactor(config): simplify validate logic<commit_after>'use strict'

const yaml = require('js-yaml')
const fs = require('fs')
const path = require('path')
const _ = require('halcyon')

const config = {
  /**
   * @property {string} Default location of binci.yml config file
   */
  defaultPath: `${process.cwd()}/binci.yml`,
  /**
   * Loads config from yaml, attempts to parse to object
   * @param {string} (configPath) Path to config file or use defaultPath
   * @returns {object}
   */
  load: (configPath = config.defaultPath) => {
    try {
      fs.statSync(configPath)
    } catch (err) {
      throw new Error([
        `No config found at ${configPath}.`,
        'Please run `binci init` to create a binci.yml file or specify one with the `-c` flag.'
      ].join(' '))
    }

    let cfg
    try {
      cfg = yaml.safeLoad(fs.readFileSync(configPath, 'utf8'))
    } catch (e) {
      const relPath = path.relative(process.cwd(), configPath)
      const error = new Error(`Please fix the errors in ${relPath}`)
      error.message = error.message + `:\n\n${e.message}`
      throw error
    }
    return config.validate(cfg)
  },
  /**
   * Filters out empty config properties
   * @param {object}
   * @returns {object}
   */
  validate: (cfg) => _.pipe([
    _.toPairs,
    _.reject(([key, val]) => !_.contains(key, ['from', 'tasks']) && _.isEmpty(val) || _.isNil(val)),
    _.fromPairs
  ])(cfg)
}

module.exports = config
<|endoftext|>


<commit_before>/*
 * The MIT License
 *
 * Copyright 2014 Irfan Ahmed.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

"use strict";

(function () {
    var module = angular.module("pmdApp.leftPanel", []);

    module.controller("LeftPanelCtrl", [
        "$scope", "storeService", "$location", "$modal", "$timeout",
        function ($scope, store, $location, $modal, $timeout) {
            var panelNames = ["topics", "settings", "search"];

            $scope.leftPanel = {
                topics: [],
                currentPanel: "topics",
            };

            $scope.$on("leftpanel.panel", function (event, name) {
                console.debug("leftPanel Name event: ", name);
                if (panelNames.indexOf(name) === -1) {
                    console.error("Panel name", name, "does not exist");
                    return;
                }
                $scope.leftPanel.currentPanel = name;
            });

            $scope.$on("topic.sections", function(event, data) {
                console.debug("Got Sections for :", data);
                var topicID = data.topic.id;
                for(var i=0;i<$scope.leftPanel.topics.length;i++) {
                    var panelTopic = $scope.leftPanel.topics[i];
                    if(panelTopic.id === topicID) {
                        console.debug("Match : ", panelTopic, data.sections);
                        panelTopic.sections = data.sections;
                        console.debug("Topic Sections:", panelTopic.sections);
                        break;
                    }
                }

            });

            $scope.onTopic = function (topic, index) {
                $scope.leftPanel.currentTopic = topic;
                var displayedID = $location.search().id;
                if(topic.id !== displayedID) {
                    console.debug("Showing Topic: ", topic);
                    $location.search({id: topic.id});
                }
            };

            $scope.newTopic = function () {
                var newTopicDialog = $modal.open({
                    templateUrl: "components/leftpanel/newTopic.html",
                    controller: "NewTopicDialogCtrl"
                });
                newTopicDialog.result.then(function (topicInfo) {
                    console.debug("New Topic Info: ", topicInfo);
                    store.createTopic(topicInfo).then(function () {
                        $scope.leftPanel.topics.push(topicInfo);
                        $scope.leftPanel.currentTopic = topicInfo;
                        $location.search(topicInfo);
                    }, function (e) {
                        console.error("Create Topic: ", e);
                    });
                }, function () {
                    console.debug("Dialog Cancelled/closed...");
                });
            };

            $scope.showSection = function(id) {
                console.debug("Showing Section : ", id);
                $location.hash(id);
            };

            $scope.backToTopics = function() {
                // TODO store the old link and move back to that location
                console.debug("Current Topic: ", $scope.leftPanel.currentTopic);
                $location.url("/topic?id=" + $scope.leftPanel.currentTopic.id);
            };

            store.getSettings().success(function (settings) {
                console.debug("Settings : ", settings, $location.path(), $location.search());
                if (settings.topics && settings.topics.length) {
                    $scope.leftPanel.topics = settings.topics;
                    var page = $location.path();
                    if(page === "/topic") {
                        var id = $location.search().id;
                        if(!id) {
                            id = $scope.leftPanel.topics[0].id;
                            $timeout(function() {
                                $location.search({id: id});
                            }, 500);
                        }
                        $scope.leftPanel.topics.forEach(function(t) {
                            if(id === t.id) {
                                t.open = true;
                                $scope.leftPanel.currentTopic = t;
                            } else {
                                t.open = false;
                            }
                            console.debug("Opened ", t.id, t.open);
                        });
                    }
                }
            }).error(function (e) {
                console.error("No Topics/Settings : ", e);
            });
        }
    ]);

    module.controller("NewTopicDialogCtrl", [
        "$scope", "$modalInstance",
        function ($scope, $modalInstance) {
            $scope.topic = {
                label: "",
                desc: ""
            };

            $scope.ok = function (e) {
                var topicInfo = {};
                if (!$scope.topic.label) {
                    $scope.topic.error = "Label is required.";
                    e.preventDefault();
                    return false;
                }
                topicInfo.label = $scope.topic.label;

                topicInfo.desc = $scope.topic.desc;
                if (!topicInfo) {
                    topicInfo.desc = topicInfo.label;
                }
                topicInfo.id = topicInfo.label.toLowerCase().replace(/ /g, "_") + "_" + new Date().getTime();
                $modalInstance.close(topicInfo);
            };

            $scope.cancel = function (e) {
                $modalInstance.dismiss('cancel');
            };
        }
    ]);
})();<commit_msg>fix the name of the new topic template<commit_after>/*
 * The MIT License
 *
 * Copyright 2014 Irfan Ahmed.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

"use strict";

(function () {
    var module = angular.module("pmdApp.leftPanel", []);

    module.controller("LeftPanelCtrl", [
        "$scope", "storeService", "$location", "$modal", "$timeout",
        function ($scope, store, $location, $modal, $timeout) {
            var panelNames = ["topics", "settings", "search"];

            $scope.leftPanel = {
                topics: [],
                currentPanel: "topics",
            };

            $scope.$on("leftpanel.panel", function (event, name) {
                console.debug("leftPanel Name event: ", name);
                if (panelNames.indexOf(name) === -1) {
                    console.error("Panel name", name, "does not exist");
                    return;
                }
                $scope.leftPanel.currentPanel = name;
            });

            $scope.$on("topic.sections", function(event, data) {
                console.debug("Got Sections for :", data);
                var topicID = data.topic.id;
                for(var i=0;i<$scope.leftPanel.topics.length;i++) {
                    var panelTopic = $scope.leftPanel.topics[i];
                    if(panelTopic.id === topicID) {
                        console.debug("Match : ", panelTopic, data.sections);
                        panelTopic.sections = data.sections;
                        console.debug("Topic Sections:", panelTopic.sections);
                        break;
                    }
                }

            });

            $scope.onTopic = function (topic, index) {
                $scope.leftPanel.currentTopic = topic;
                var displayedID = $location.search().id;
                if(topic.id !== displayedID) {
                    console.debug("Showing Topic: ", topic);
                    $location.search({id: topic.id});
                }
            };

            $scope.newTopic = function () {
                var newTopicDialog = $modal.open({
                    templateUrl: "components/leftpanel/newtopic.html",
                    controller: "NewTopicDialogCtrl"
                });
                newTopicDialog.result.then(function (topicInfo) {
                    console.debug("New Topic Info: ", topicInfo);
                    store.createTopic(topicInfo).then(function () {
                        $scope.leftPanel.topics.push(topicInfo);
                        $scope.leftPanel.currentTopic = topicInfo;
                        $location.search(topicInfo);
                    }, function (e) {
                        console.error("Create Topic: ", e);
                    });
                }, function () {
                    console.debug("Dialog Cancelled/closed...");
                });
            };

            $scope.showSection = function(id) {
                console.debug("Showing Section : ", id);
                $location.hash(id);
            };

            $scope.backToTopics = function() {
                // TODO store the old link and move back to that location
                console.debug("Current Topic: ", $scope.leftPanel.currentTopic);
                $location.url("/topic?id=" + $scope.leftPanel.currentTopic.id);
            };

            store.getSettings().success(function (settings) {
                console.debug("Settings : ", settings, $location.path(), $location.search());
                if (settings.topics && settings.topics.length) {
                    $scope.leftPanel.topics = settings.topics;
                    var page = $location.path();
                    if(page === "/topic") {
                        var id = $location.search().id;
                        if(!id) {
                            id = $scope.leftPanel.topics[0].id;
                            $timeout(function() {
                                $location.search({id: id});
                            }, 500);
                        }
                        $scope.leftPanel.topics.forEach(function(t) {
                            if(id === t.id) {
                                t.open = true;
                                $scope.leftPanel.currentTopic = t;
                            } else {
                                t.open = false;
                            }
                            console.debug("Opened ", t.id, t.open);
                        });
                    }
                }
            }).error(function (e) {
                console.error("No Topics/Settings : ", e);
            });
        }
    ]);

    module.controller("NewTopicDialogCtrl", [
        "$scope", "$modalInstance",
        function ($scope, $modalInstance) {
            $scope.topic = {
                label: "",
                desc: ""
            };

            $scope.ok = function (e) {
                var topicInfo = {};
                if (!$scope.topic.label) {
                    $scope.topic.error = "Label is required.";
                    e.preventDefault();
                    return false;
                }
                topicInfo.label = $scope.topic.label;

                topicInfo.desc = $scope.topic.desc;
                if (!topicInfo) {
                    topicInfo.desc = topicInfo.label;
                }
                topicInfo.id = topicInfo.label.toLowerCase().replace(/ /g, "_") + "_" + new Date().getTime();
                $modalInstance.close(topicInfo);
            };

            $scope.cancel = function (e) {
                $modalInstance.dismiss('cancel');
            };
        }
    ]);
})();<|endoftext|>


<commit_before>var log = require("./lib/log"),
    $ = require("./vendor/jquery");

function hovercar (el) {
  var $el = $(el);
  var width = $el.outerWidth( true );
  var height = $el.outerHeight( true );
  var pWidth = $el.parent().outerWidth( true );
  var pHeight = $el.parent().outerHeight( true );
  var dimensions = getDimensions($el);
  // console.log($el);
  //
  // console.log("element = " + width + "px" + " x " + height + "px");
  // console.log("parent = " + pWidth + "px" + " x " + pHeight + "px");

  var fontSize = Number($el.css("font-size").replace(/[^\d.-]/g, ''));
  var newFontSize = fontSize;

  function newWidth ($el) { width = $el.outerWidth( true ); }
  function newHeight ($el) { height = $el.outerHeight( true ); }
  function newPWidth ($el) { pWidth = $el.parent().outerWidth( true ); }
  function newPHeight ($el) { pHeight = $el.parent().outerHeight( true ); }

  function getDimensions ($el) {
    var dimensions = {};
    dimensions.width = $el.outerWidth( true );
    dimensions.height = $el.outerHeight( true );
    dimensions.parent = {};
    dimensions.parent.width = $el.parent().outerWidth( true );
    dimensions.parent.height = $el.parent().outerHeight( true );

    return dimensions;
  }

  function center ($el) {
    // I feel like there should be an easier way to set the height variable and
    // then refresh it on resize.
    // newWidth($el);
    // newHeight($el);
    // newPWidth($el);
    // newPHeight($el);

    // this only works if the parent element is set postion: relative; and if
    // the target element is set position: absolute;. it'd be nice to do a check
    // of these two to see if they already have the position attribute and then
    // tweak the position based on that and/or add the position to each.
    getDimensions($el);

    $el.css({
      "top": ((dimensions.parent.height - dimensions.height) / 2) + "px",
      "left": ((dimensions.parent.width - dimensions.width) / 2) + "px",
    });
    console.log("//////////RESIZE//////////");
    console.log("$el: " + dimensions.width + " x " + dimensions.height);
    console.log("parent: " + dimensions.parent.width + " x " + dimensions.parent.height);
    console.log("window: " + window.innerWidth + " x " + window.innerHeight);
  }

  function fontSizer (scale, $el) {
    newFontSize = newFontSize * scale;
    $el.css({
      "font-size": (newFontSize / 10) + "rem",
    });
  }

  function fontSizeChecker ($el) {
    // this whole if check is a little dicey I think. Not sure if there's a
    // better way or if I should pass in the scaling factors when the function
    // is called. Should the scaling up and down be separate functions?
    if ( dimensions.width >= (dimensions.parent.width * 0.9)) {
      fontSizer(0.9, $el);
      // console.log("after css change" + fontSize + ", " + newFontSize);
      center($el);
    } else if ( dimensions.width < (dimensions.parent.width * 0.8) && newFontSize < fontSize ) {
      fontSizer(1.11111111, $el);
      // is there a better way to do this rather than nesting ifs?
      if ( newFontSize > fontSize ) {
        newFontSize = fontSize;
        // console.log("after css change" + fontSize + ", " + newFontSize);
      }
      // console.log("after css change" + fontSize + ", " + newFontSize);
      center($el);
    }
  }

  fontSizeChecker($el);
  center($el);

  $(window).resize( function() {
    fontSizeChecker($el);
    center($el);
  });

}

$(window).load( function() {
  hovercar($(".hovercar"));
});
<commit_msg>Shit tonne of work done here<commit_after>var log = require("./lib/log"),
    $ = require("./vendor/jquery");

function hovercar (cars, plates) {
  var $cars = $(cars);
  var $plates = $(plates);
  if ($cars.length === 0 && $plates.length === 0) { return; }

  function getDimensions ($el) {
    var dimensions = {};
    dimensions.width = $el.outerWidth( true );
    dimensions.height = $el.outerHeight( true );
    if ( $el.context.nodeName === "VIDEO" ) {
      dimensions.nativeWidth = $el.context.videoWidth;
      dimensions.nativeHeight = $el.context.videoHeight;
    } else if ( $el.context.nodeName === "IMG" ) {
      dimensions.nativeWidth = $el.context.naturalWidth;
      dimensions.nativeHeight = $el.context.naturalHeight;
    } else {
      dimensions.nativeWidth = 0;
      dimensions.nativeHeight = 0;
    }
    dimensions.parent = {};
    dimensions.parent.width = $el.parent().outerWidth( true );
    dimensions.parent.height = $el.parent().outerHeight( true );

    return dimensions;
  }

  function center ($el) {
    var dims = getDimensions($el);

    $el.css({
      "top": ((dims.parent.height - dims.height) / 2) + "px",
      "left": ((dims.parent.width - dims.width) / 2) + "px",
    });
  }

  function liftOff ($el) {
    accidentWarning($el);
    center($el);
  }

  function accidentWarning (car) {
    var dims = getDimensions(car);
    var carRatio = dims.nativeWidth / dims.nativeHeight;
    var parkingSpace = dims.parent.width / dims.parent.height;

    if ( carRatio >= parkingSpace ) {
      car.css({
        "width": "auto",
        "height": dims.parent.height + "px",
      });
    } else {
      car.css({
        "width": dims.parent.width + "px",
        "height": "auto",
      });
    }
  }

  function licensePlate (plate) {
    var fontSize = Number(plate.css("font-size").replace(/[^\d.-]/g, ''));
    var newFontSize = fontSize;
    if ($plates.length === 0) { return; }

    function fontResize (scale, plate) {
      newFontSize = newFontSize * scale;
      plate.css({
        "font-size": (newFontSize / 10) + "rem",
      });
    }

    function checkFontSize (plate) {
      var dims = getDimensions(plate);
      if ( dims.width >= (dims.parent.width * 0.9) ) {
        fontResize(0.9, plate);
        checkFontSize(plate);
      } else if ( dims.width < (dims.parent.width * 0.8) && newFontSize < fontSize ) {
        fontResize(1.11111111, plate);
      } else if ( dims.width < (dims.parent.width * 0.8) && newFontSize >= fontSize ) {
        newFontSize = fontSize;
      } else {
        return;
      }
    }

    $plates.each( function () {
      var plate = $(this);
      checkFontSize(plate);
      center(plate);

      $(window).resize( function () {
        checkFontSize(plate);
        center(plate);
      });
    });
  }

  $cars.each( function () {
    var car = $(this);
    var dims = getDimensions(car);
    var i = 0;
    function preFlightCheck ($el, max) {
      setTimeout(function () {
        dims = getDimensions($el);
        if ( dims.nativeHeight > 0 ) { liftOff($el); }
        else if (i < max) {
          i = i + 1;
          preFlightCheck($el, max);
        }
      }, 50);
    }
    if ( Number(dims.nativeHeight) >= 0 ) {
      preFlightCheck(car, 10);
    }

    $(window).resize( function () {
      liftOff(car);
    });
  });

  $plates.each( function () {
    var plate = $(this);
    licensePlate(plate);
  });
}

$(window).load( function () {
  hovercar($(".hovercar"), $(".license-plate"));
});
<|endoftext|>


<commit_before>// An example Backbone application contributed by
// [Jérôme Gravel-Niquet](http://jgn.me/). This demo uses a simple
// [LocalStorage adapter](backbone-localstorage.html)
// to persist Backbone models within your browser.

// Load the application once the DOM is ready, using `jQuery.ready`:
$(function(){

  // Todo Model
  // ----------

  // Our basic **Todo** model has `title`, `order`, and `done` attributes.
  var Todo = Backbone.Model.extend({

    // Default attributes for the todo item.
    defaults: function() {
      return {
        title: "empty todo...",
        order: Todos.nextOrder(),
        done: false
      };
    },

    // Ensure that each todo created has `title`.
    initialize: function() {
      if (!this.get("title")) {
        this.set({"title": this.defaults().title});
      }
    },

    // Toggle the `done` state of this todo item.
    toggle: function() {
      this.save({done: !this.get("done")});
    }

  });

  // Todo Collection
  // ---------------

  // The collection of todos is backed by *localStorage* instead of a remote
  // server.
  var TodoList = Backbone.Collection.extend({

    // Reference to this collection's model.
    model: Todo,

    // Save all of the todo items under the `"todos-backbone"` namespace.
    localStorage: new Backbone.LocalStorage("todos-backbone"),

    // Filter down the list of all todo items that are finished.
    done: function() {
      return this.filter(function(todo){ return todo.get('done'); });
    },

    // Filter down the list to only todo items that are still not finished.
    remaining: function() {
      return this.without.apply(this, this.done());
    },

    // We keep the Todos in sequential order, despite being saved by unordered
    // GUID in the database. This generates the next order number for new items.
    nextOrder: function() {
      if (!this.length) return 1;
      return this.last().get('order') + 1;
    },

    // Todos are sorted by their original insertion order.
    comparator: function(todo) {
      return todo.get('order');
    }

  });

  // Create our global collection of **Todos**.
  var Todos = new TodoList;

  // Todo Item View
  // --------------

  // The DOM element for a todo item...
  var TodoView = Backbone.View.extend({

    //... is a list tag.
    tagName:  "li",

    // Cache the template function for a single item.
    template: _.template($('#item-template').html()),

    // The DOM events specific to an item.
    events: {
      "click .toggle"   : "toggleDone",
      "dblclick .view"  : "edit",
      "click a.destroy" : "clear",
      "keypress .edit"  : "updateOnEnter",
      "blur .edit"      : "close"
    },

    // The TodoView listens for changes to its model, re-rendering. Since there's
    // a one-to-one correspondence between a **Todo** and a **TodoView** in this
    // app, we set a direct reference on the model for convenience.
    initialize: function() {
      this.model.on('change', this.render, this);
      this.model.on('destroy', this.remove, this);
    },

    // Re-render the titles of the todo item.
    render: function() {
      this.$el.html(this.template(this.model.toJSON()));
      this.$el.toggleClass('done', this.model.get('done'));
      this.input = this.$('.edit');
      return this;
    },

    // Toggle the `"done"` state of the model.
    toggleDone: function() {
      this.model.toggle();
    },

    // Switch this view into `"editing"` mode, displaying the input field.
    edit: function() {
      this.$el.addClass("editing");
      this.input.focus();
    },

    // Close the `"editing"` mode, saving changes to the todo.
    close: function() {
      var value = this.input.val();
      if (!value) {
        this.clear();
      } else {
        this.model.save({title: value});
        this.$el.removeClass("editing");
      }
    },

    // If you hit `enter`, we're through editing the item.
    updateOnEnter: function(e) {
      if (e.keyCode == 13) this.close();
    },

    // Remove the item, destroy the model.
    clear: function() {
      this.model.destroy();
    }

  });

  // The Application
  // ---------------

  // Our overall **AppView** is the top-level piece of UI.
  var AppView = Backbone.View.extend({

    // Instead of generating a new element, bind to the existing skeleton of
    // the App already present in the HTML.
    el: $("#todoapp"),

    // Our template for the line of statistics at the bottom of the app.
    statsTemplate: _.template($('#stats-template').html()),

    // Delegated events for creating new items, and clearing completed ones.
    events: {
      "keypress #new-todo":  "createOnEnter",
      "click #clear-completed": "clearCompleted",
      "click #toggle-all": "toggleAllComplete"
    },

    // At initialization we bind to the relevant events on the `Todos`
    // collection, when items are added or changed. Kick things off by
    // loading any preexisting todos that might be saved in *localStorage*.
    initialize: function() {

      this.input = this.$("#new-todo");
      this.allCheckbox = this.$("#toggle-all")[0];

      Todos.on('add', this.addOne, this);
      Todos.on('reset', this.addAll, this);
      Todos.on('all', this.render, this);

      this.footer = this.$('footer');
      this.main = $('#main');

      Todos.fetch();
    },

    // Re-rendering the App just means refreshing the statistics -- the rest
    // of the app doesn't change.
    render: function() {
      var done = Todos.done().length;
      var remaining = Todos.remaining().length;

      if (Todos.length) {
        this.main.show();
        this.footer.show();
        this.footer.html(this.statsTemplate({done: done, remaining: remaining}));
      } else {
        this.main.hide();
        this.footer.hide();
      }

      this.allCheckbox.checked = !remaining;
    },

    // Add a single todo item to the list by creating a view for it, and
    // appending its element to the `<ul>`.
    addOne: function(todo) {
      var view = new TodoView({model: todo});
      this.$("#todo-list").append(view.render().el);
    },

    // Add all items in the **Todos** collection at once.
    addAll: function() {
      Todos.each(this.addOne);
    },

    // If you hit return in the main input field, create new **Todo** model,
    // persisting it to *localStorage*.
    createOnEnter: function(e) {
      if (e.keyCode != 13) return;
      if (!this.input.val()) return;

      Todos.create({title: this.input.val()});
      this.input.val('');
    },

    // Clear all done todo items, destroying their models.
    clearCompleted: function() {
      _.invoke(Todos.done(), 'destroy');
      return false;
    },

    toggleAllComplete: function () {
      var done = this.allCheckbox.checked;
      Todos.each(function (todo) { todo.save({'done': done}); });
    }

  });

  // Finally, we kick things off by creating the **App**.
  var App = new AppView;

});
<commit_msg>using 'listenTo' instead of 'on' in todos example app<commit_after>// An example Backbone application contributed by
// [Jérôme Gravel-Niquet](http://jgn.me/). This demo uses a simple
// [LocalStorage adapter](backbone-localstorage.html)
// to persist Backbone models within your browser.

// Load the application once the DOM is ready, using `jQuery.ready`:
$(function(){

  // Todo Model
  // ----------

  // Our basic **Todo** model has `title`, `order`, and `done` attributes.
  var Todo = Backbone.Model.extend({

    // Default attributes for the todo item.
    defaults: function() {
      return {
        title: "empty todo...",
        order: Todos.nextOrder(),
        done: false
      };
    },

    // Ensure that each todo created has `title`.
    initialize: function() {
      if (!this.get("title")) {
        this.set({"title": this.defaults().title});
      }
    },

    // Toggle the `done` state of this todo item.
    toggle: function() {
      this.save({done: !this.get("done")});
    }

  });

  // Todo Collection
  // ---------------

  // The collection of todos is backed by *localStorage* instead of a remote
  // server.
  var TodoList = Backbone.Collection.extend({

    // Reference to this collection's model.
    model: Todo,

    // Save all of the todo items under the `"todos-backbone"` namespace.
    localStorage: new Backbone.LocalStorage("todos-backbone"),

    // Filter down the list of all todo items that are finished.
    done: function() {
      return this.filter(function(todo){ return todo.get('done'); });
    },

    // Filter down the list to only todo items that are still not finished.
    remaining: function() {
      return this.without.apply(this, this.done());
    },

    // We keep the Todos in sequential order, despite being saved by unordered
    // GUID in the database. This generates the next order number for new items.
    nextOrder: function() {
      if (!this.length) return 1;
      return this.last().get('order') + 1;
    },

    // Todos are sorted by their original insertion order.
    comparator: function(todo) {
      return todo.get('order');
    }

  });

  // Create our global collection of **Todos**.
  var Todos = new TodoList;

  // Todo Item View
  // --------------

  // The DOM element for a todo item...
  var TodoView = Backbone.View.extend({

    //... is a list tag.
    tagName:  "li",

    // Cache the template function for a single item.
    template: _.template($('#item-template').html()),

    // The DOM events specific to an item.
    events: {
      "click .toggle"   : "toggleDone",
      "dblclick .view"  : "edit",
      "click a.destroy" : "clear",
      "keypress .edit"  : "updateOnEnter",
      "blur .edit"      : "close"
    },

    // The TodoView listens for changes to its model, re-rendering. Since there's
    // a one-to-one correspondence between a **Todo** and a **TodoView** in this
    // app, we set a direct reference on the model for convenience.
    initialize: function() {
      this.listenTo(this.model, 'change', this.render);
      this.listenTo(this.model, 'destroy', this.remove);
    },

    // Re-render the titles of the todo item.
    render: function() {
      this.$el.html(this.template(this.model.toJSON()));
      this.$el.toggleClass('done', this.model.get('done'));
      this.input = this.$('.edit');
      return this;
    },

    // Toggle the `"done"` state of the model.
    toggleDone: function() {
      this.model.toggle();
    },

    // Switch this view into `"editing"` mode, displaying the input field.
    edit: function() {
      this.$el.addClass("editing");
      this.input.focus();
    },

    // Close the `"editing"` mode, saving changes to the todo.
    close: function() {
      var value = this.input.val();
      if (!value) {
        this.clear();
      } else {
        this.model.save({title: value});
        this.$el.removeClass("editing");
      }
    },

    // If you hit `enter`, we're through editing the item.
    updateOnEnter: function(e) {
      if (e.keyCode == 13) this.close();
    },

    // Remove the item, destroy the model.
    clear: function() {
      this.model.destroy();
    }

  });

  // The Application
  // ---------------

  // Our overall **AppView** is the top-level piece of UI.
  var AppView = Backbone.View.extend({

    // Instead of generating a new element, bind to the existing skeleton of
    // the App already present in the HTML.
    el: $("#todoapp"),

    // Our template for the line of statistics at the bottom of the app.
    statsTemplate: _.template($('#stats-template').html()),

    // Delegated events for creating new items, and clearing completed ones.
    events: {
      "keypress #new-todo":  "createOnEnter",
      "click #clear-completed": "clearCompleted",
      "click #toggle-all": "toggleAllComplete"
    },

    // At initialization we bind to the relevant events on the `Todos`
    // collection, when items are added or changed. Kick things off by
    // loading any preexisting todos that might be saved in *localStorage*.
    initialize: function() {

      this.input = this.$("#new-todo");
      this.allCheckbox = this.$("#toggle-all")[0];

      this.listenTo(Todos, 'add', this.addOne);
      this.listenTo(Todos, 'reset', this.addAll);
      this.listenTo(Todos, 'all', this.render);

      this.footer = this.$('footer');
      this.main = $('#main');

      Todos.fetch();
    },

    // Re-rendering the App just means refreshing the statistics -- the rest
    // of the app doesn't change.
    render: function() {
      var done = Todos.done().length;
      var remaining = Todos.remaining().length;

      if (Todos.length) {
        this.main.show();
        this.footer.show();
        this.footer.html(this.statsTemplate({done: done, remaining: remaining}));
      } else {
        this.main.hide();
        this.footer.hide();
      }

      this.allCheckbox.checked = !remaining;
    },

    // Add a single todo item to the list by creating a view for it, and
    // appending its element to the `<ul>`.
    addOne: function(todo) {
      var view = new TodoView({model: todo});
      this.$("#todo-list").append(view.render().el);
    },

    // Add all items in the **Todos** collection at once.
    addAll: function() {
      Todos.each(this.addOne);
    },

    // If you hit return in the main input field, create new **Todo** model,
    // persisting it to *localStorage*.
    createOnEnter: function(e) {
      if (e.keyCode != 13) return;
      if (!this.input.val()) return;

      Todos.create({title: this.input.val()});
      this.input.val('');
    },

    // Clear all done todo items, destroying their models.
    clearCompleted: function() {
      _.invoke(Todos.done(), 'destroy');
      return false;
    },

    toggleAllComplete: function () {
      var done = this.allCheckbox.checked;
      Todos.each(function (todo) { todo.save({'done': done}); });
    }

  });

  // Finally, we kick things off by creating the **App**.
  var App = new AppView;

});
<|endoftext|>


<commit_before>"use strict";

(function () {
    angular
        .module("argo")
        .factory("chartsService", chartsService);

    chartsService.$inject = ["$http", "sessionService"];
    function chartsService($http, sessionService) {
        var quotes = {},
            service = {
                getHistQuotes: getHistQuotes,
                getQuotes: getQuotes,
                updateTick: updateTick
            };

        return service;

        function getHistQuotes(opt) {
            var instrument = opt && opt.instrument || "EUR_USD",
                granularity = opt && opt.granularity || "M5",
                count = opt && opt.count,
                candleFormat = opt && opt.candleFormat || "midpoint",
                alignmentTimezone = opt && opt.alignmentTimezone
                    || "America/New_York",
                dailyAlignment = opt && opt.dailyAlignment || "0";

            return $http.post("/api/candles", {
                environment: sessionService.environment,
                token: sessionService.token,
                instrument: instrument,
                granularity: granularity,
                cound: count,
                candleFormat: candleFormat,
                alignmentTimezone: alignmentTimezone,
                dailyAlignment: dailyAlignment
            });
        }

        function getQuotes() {
            return quotes;
        }

        function updateTick(tick) {
            var instrument = tick.instrument;

            quotes[instrument] = {
                time: tick.time,
                ask: tick.ask,
                bid: tick.bid
            };
        }
    }

}());
<commit_msg>Fix count in charts service.<commit_after>"use strict";

(function () {
    angular
        .module("argo")
        .factory("chartsService", chartsService);

    chartsService.$inject = ["$http", "sessionService"];
    function chartsService($http, sessionService) {
        var quotes = {},
            service = {
                getHistQuotes: getHistQuotes,
                getQuotes: getQuotes,
                updateTick: updateTick
            };

        return service;

        function getHistQuotes(opt) {
            var instrument = opt && opt.instrument || "EUR_USD",
                granularity = opt && opt.granularity || "M5",
                count = opt && opt.count || 251,
                candleFormat = opt && opt.candleFormat || "midpoint",
                alignmentTimezone = opt && opt.alignmentTimezone
                    || "America/New_York",
                dailyAlignment = opt && opt.dailyAlignment || "0";

            return $http.post("/api/candles", {
                environment: sessionService.environment,
                token: sessionService.token,
                instrument: instrument,
                granularity: granularity,
                count: count,
                candleFormat: candleFormat,
                alignmentTimezone: alignmentTimezone,
                dailyAlignment: dailyAlignment
            });
        }

        function getQuotes() {
            return quotes;
        }

        function updateTick(tick) {
            var instrument = tick.instrument;

            quotes[instrument] = {
                time: tick.time,
                ask: tick.ask,
                bid: tick.bid
            };
        }
    }

}());
<|endoftext|>


<commit_before>/**
 * Created by kintesh on 28/01/15.
 */
var assert = require("assert"),
    translator = require("../lib/translator"),
    fs = require("fs"),
    testSource
    ;

describe("Translator", function() {

    it("Rigorous tests", function() {
        assert.equal(true, true);
        assert.notEqual(true, false);
        assert.notDeepEqual(translator, {});
        assert.notDeepEqual(fs, {});
    });

    it("Test removeComments(source)", function() {
        var input = "Tyche is the /*nick*/name given to a /**hypothetical**/ gas giant located in the " +
                "Solar System's Oort cloud//.",
            output = "Tyche is the name given to a  gas giant located in the Solar System's Oort cloud";
        assert.equal(translator.removeComments(input), output);
    });

    it("read test for source file", function() {
        testSource = fs.readFileSync(__dirname+"/testSource", "utf8");
        assert.notDeepEqual(testSource, undefined);
    });

    it("test for readProperties", function() {
        var input = testSource,
            output = {
                title: 'Sample Slides',
                sub_title: 'The following are sample slides showing different features.',
                author: 'Kintesh Patel',
                date: '28/01/2015'
            };
        assert.deepEqual(translator.readProperties(input), output);
    });

    it("test for extractFrames", function() {
        var input = testSource,
            frameLength = 7,
            frame0 = "# Headers\n---------\n\n# H1 header\n## H2 header\n### H3 header\n#### H4 header\n" +
                "##### H5 header\n###### H6 header\n\n";
        var frames = translator.extractFrames(input);

        assert.equal(frameLength, frames.length);
        assert.deepEqual(frame0, frames[0]);
    });

    it("test for extractMaths", function() {
        var inputFrame = "Inline math equations go in like so: $ \\omega = d\\phi / dt $. Display math should " +
                "get its own line and be put in in double-dollarsigns:\n\n$$ I = \\int \\rho R^{2} dV $$\n\nAnd " +
                "note that you can backslash-escape any punctuation characters.",
            outputFrame = "Inline math equations go in like so: %{MATH0}. Display math should get its own " +
                "line and be put in in double-dollarsigns:\n\n%{MATH1}\n\nAnd note that you can backslash-escape " +
                "any punctuation characters.",
            mathsOutput = [
                { type: 0, value: " \\omega = d\\phi / dt " },
                { type: 1, value: " I = \\int \\rho R^{2} dV " }
            ];
        var output = translator.extractMaths(inputFrame);
        assert.deepEqual(outputFrame, output.frame);
        assert.deepEqual(mathsOutput, output.maths);
    });

    it("test for restoreMaths", function() {
        var inputFrame = "Inline math equations go in like so: %{MATH0}. Display math should get its own " +
                "line and be put in in double-dollarsigns:\n\n%{MATH1}\n\nAnd note that you can backslash-escape " +
                "any punctuation characters.",
            outputFrame = "Inline math equations go in like so:
 \\omega = d\\phi / dt " +
                "
. Display math should get its own line and be put in in double-dollarsigns:\n\n" +
                "
 I = \\int \\rho R^{2} dV
\n\nAnd note that you can " +
                "backslash-escape any punctuation characters.",
            maths = [
                { type: 0, value: " \\omega = d\\phi / dt " },
                { type: 1, value: " I = \\int \\rho R^{2} dV " }
            ],
            replaceInline = "
%{MATH}
",
            replaceBlock = "
%{MATH}
";
        var output = translator.restoreMaths(inputFrame, maths, replaceInline, replaceBlock);
        assert.deepEqual(outputFrame, output);
    });

    it("test for replaceControlTags", function() {
        var inputFrame = "Itemized lists look like:\n[visibility:reveal, animation:fade]\n  * this one\n  " +
            "* that one\n  * the other one\n",
            outputFrame = "Itemized lists look like:\n
" +
                "{visibility:\"reveal\",animation:\"fade\"}
\n  * this one\n  * that one\n  * the other one\n";
        var output = translator.replaceControlTags(inputFrame);

        assert.deepEqual(outputFrame, output);
    });

});<commit_msg>added test for makeTitleSlide<commit_after>/**
 * Created by kintesh on 28/01/15.
 */
var assert = require("assert"),
    translator = require("../lib/translator"),
    fs = require("fs"),
    testSource
    ;

describe("Translator", function() {

    it("Rigorous tests", function() {
        assert.equal(true, true);
        assert.notEqual(true, false);
        assert.notDeepEqual(translator, {});
        assert.notDeepEqual(fs, {});
    });

    it("Test removeComments(source)", function() {
        var input = "Tyche is the /*nick*/name given to a /**hypothetical**/ gas giant located in the " +
                "Solar System's Oort cloud//.",
            output = "Tyche is the name given to a  gas giant located in the Solar System's Oort cloud";
        assert.equal(translator.removeComments(input), output);
    });

    it("read test for source file", function() {
        testSource = fs.readFileSync(__dirname+"/testSource", "utf8");
        assert.notDeepEqual(testSource, undefined);
    });

    it("test for readProperties", function() {
        var input = testSource,
            output = {
                title: 'Sample Slides',
                sub_title: 'The following are sample slides showing different features.',
                author: 'Kintesh Patel',
                date: '28/01/2015'
            };
        assert.deepEqual(translator.readProperties(input), output);
    });

    it("test for extractFrames", function() {
        var input = testSource,
            frameLength = 7,
            frame0 = "# Headers\n---------\n\n# H1 header\n## H2 header\n### H3 header\n#### H4 header\n" +
                "##### H5 header\n###### H6 header\n\n";
        var frames = translator.extractFrames(input);

        assert.equal(frameLength, frames.length);
        assert.deepEqual(frame0, frames[0]);
    });

    it("test for extractMaths", function() {
        var inputFrame = "Inline math equations go in like so: $ \\omega = d\\phi / dt $. Display math should " +
                "get its own line and be put in in double-dollarsigns:\n\n$$ I = \\int \\rho R^{2} dV $$\n\nAnd " +
                "note that you can backslash-escape any punctuation characters.",
            outputFrame = "Inline math equations go in like so: %{MATH0}. Display math should get its own " +
                "line and be put in in double-dollarsigns:\n\n%{MATH1}\n\nAnd note that you can backslash-escape " +
                "any punctuation characters.",
            mathsOutput = [
                { type: 0, value: " \\omega = d\\phi / dt " },
                { type: 1, value: " I = \\int \\rho R^{2} dV " }
            ];
        var output = translator.extractMaths(inputFrame);
        assert.deepEqual(outputFrame, output.frame);
        assert.deepEqual(mathsOutput, output.maths);
    });

    it("test for restoreMaths", function() {
        var inputFrame = "Inline math equations go in like so: %{MATH0}. Display math should get its own " +
                "line and be put in in double-dollarsigns:\n\n%{MATH1}\n\nAnd note that you can backslash-escape " +
                "any punctuation characters.",
            outputFrame = "Inline math equations go in like so:
 \\omega = d\\phi / dt " +
                "
. Display math should get its own line and be put in in double-dollarsigns:\n\n" +
                "
 I = \\int \\rho R^{2} dV
\n\nAnd note that you can " +
                "backslash-escape any punctuation characters.",
            maths = [
                { type: 0, value: " \\omega = d\\phi / dt " },
                { type: 1, value: " I = \\int \\rho R^{2} dV " }
            ],
            replaceInline = "
%{MATH}
",
            replaceBlock = "
%{MATH}
";
        assert.deepEqual(translator.restoreMaths(inputFrame, maths, replaceInline, replaceBlock), outputFrame);
    });

    it("test for replaceControlTags", function() {
        var inputFrame = "Itemized lists look like:\n[visibility:reveal, animation:fade]\n  * this one\n  " +
            "* that one\n  * the other one\n",
            outputFrame = "Itemized lists look like:\n
" +
                "{visibility:\"reveal\",animation:\"fade\"}
\n  * this one\n  * that one\n  * the other one\n";
        assert.deepEqual(translator.replaceControlTags(inputFrame), outputFrame);
    });

    it("test for makeTitleSlide", function(){
        var input = {
                title: 'Sample Slides',
                sub_title: 'The following are sample slides showing different features.',
                author: 'Kintesh Patel',
                date: '28/01/2015'
            },
            output = "
\n
Sample Slides
" +
                "
The following are sample slides showing different features.
" +
                "
Kintesh Patel

28/01/2015
\n
\n";
        assert.deepEqual(translator.makeTitleSlide(input), output)
    });

});<|endoftext|>


<commit_before>import io from 'socket.io-client'

const uri = 'https://api.kody-koy.me'
export const socket = io.connect(uri)
export const URI = uri
<commit_msg>change api endpoint<commit_after>import io from 'socket.io-client'

const uri = 'https://api-music.herokuapp.com'
export const socket = io.connect(uri)
export const URI = uri
<|endoftext|>


<commit_before>define(['jquery', 'google', 'infobubble', 'oms', 'markerclusterer'],
function ($, google, InfoBubble, OverlappingMarkerSpiderfier, MarkerClusterer) {

    function MapMaker(map_canvas, mapOptions, mcOptions, omsOptions) {
        this.map_canvas = map_canvas;
        this.google_map = new google.maps.Map(map_canvas, mapOptions);
        this.geocoder = new google.maps.Geocoder();
        this.markerManager = new MarkerClusterer(this.google_map, [], mcOptions);
        this.infoWindow = undefined;

        var self = this;
        // this handles multiple markers at the same location
        this.oms = new OverlappingMarkerSpiderfier(this.google_map, omsOptions);
        this.oms.addListener('click', function(marker, evt) {
            self.showInfoWindow(marker);
        });
        google.maps.event.addListener(this.google_map, 'zoom_changed', function(ev) {
            setTimeout(function () {
                if (self.google_map.getZoom() <= 15) return;
                var markers = self.oms.markersNearAnyOtherMarker();
                var seen = {};
                var clusters = [];
                var ID = '__gm_id';
                markers.forEach(function (m) {
                    if (m[ID] in seen) return;
                    self.oms.markersNearMarker(m).forEach(function (nm) {
                        seen[nm[ID]] = true;
                    });
                    clusters.push(m);
                    seen[m[ID]] = true;
                });
                clusters.forEach(function (m) {
                    google.maps.event.trigger(m, 'click');
                });
            }, 400);
        });
    }
    MapMaker.prototype.dropPins = function (models, animate, filter) {
        animate = (animate === undefined) ? true : animate;

        var self = this;
        models.forEach(function (model) {
            if (filter && !filter(model)) return;

            if (animate)
                setTimeout(function() { self.addMarker(model, animate) },
                      300 + (500 * Math.random()));
            else
                self.addMarker(model, animate);
        })
    };
    MapMaker.prototype.addMarker = function (model, animate, dim) {
        animate = animate === undefined ? true  : animate;
        dim     = dim     === undefined ? false : dim;

        // pin-event.png or pin-event-featured.png
        var icon = {
            url: "/img/map/pin-event" + (
                     model.featured ? "-featured" : ""
                ) + ".png"   // 43 x 51
        };

        var marker = new google.maps.Marker({
            title: model.title,
            position: new google.maps.LatLng(model.latitude, model.longitude),
            icon: icon,
            draggable: false,
            animation: animate ? google.maps.Animation.DROP : undefined,
            // Point where info window is shown, horizontal is not used in
            // infoBubble.js -- see markers anchor for this horizontal adjustment
            anchorPoint: new google.maps.Point(0, 20),
        });

        this.markerManager.addMarker(marker);
        this.oms.addMarker(marker);    // must keep oms in sync
        scroll(0, 0);

        // store the content for the info window in the marker
        marker.set('infoContent', model.popupHTML());
        marker.set('model', model);

        return marker;
    };
    /* Delete all markers by removing references to them */
    MapMaker.prototype.clearMarkers = function () {
        this.markerManager.clearMarkers();
        this.oms.clearMarkers();
        return this;
    }
    MapMaker.prototype.getMarkers = function() {
        return this.markerManager.getMarkers();
    };
    MapMaker.prototype.setupInfoWindow = function () {
        var self = this;
        google.maps.event.addListener(this.google_map, 'click', function(ev) {
            self.closeInfoWindow();
        });
    };
    MapMaker.prototype.closeInfoWindow = function () {
        if (this.infoWindow) {
            this.infoWindow.setMap(null);
            this.infoWindow = undefined;
        }
    };
    MapMaker.prototype.showInfoWindow = function(marker) {
        latLng = marker.position;
        var self = this;

        // close info window if clicking on already shown info window
        if (this.infoWindow) {
            if (latLng.equals(this.infoWindow.get('position'))) {
                this.closeInfoWindow();
                return;
            }
        }

        this.closeInfoWindow();

        // WARNING! InfoBubble.js has been modified to support pixelOffset,
        // which for some reason isn't supported (although it is supported by
        // the parent class of InfoBubble, InfoWindow
        this.infoWindow = new InfoBubble({ // TODO: move styling into less/css file
            position: latLng,
            minWidth: 330,
            maxWidth: 330,
            minHeight: 130,
            maxHeight: 710,
            shadowStyle: 1,
            padding: 0,
            // Padding around the tabs, now set separately from the InfoBubble padding
            borderRadius: 8,
            borderWidth: 1,
            // Now that there is no borderWidth check, you can define
            // a borderColor and it will apply to Just the arrow
            disableAutoPan: false,
            hideCloseButton: true,
            backgroundColor: '#fff',
            backgroundClassName: 'info-container',
            arrowSize: 20,
            pixelOffset: [-5, 60],
            arrowStyle: 0
        });

        this.infoWindow.setContent(marker.get('infoContent'));
        this.infoWindow.open(this.google_map, marker);
        $('.gm-style').removeClass(); // remove new styling introduces in GM 3.1

        // close details window on click
        // ref. to actual details div is held in this.infowindow.bubble_
        $(this.infoWindow.bubble_).on('click', function(e) {
          self.closeInfoWindow();
          return;
        });
    };

    // queries the Google Maps Places API for a 'PlacesResult' object,
    // which contains data like lat/long, formatted address name, etc
    // See https://developers.google.com/maps/documentation/javascript/reference#Geocoder
    // for more information
    function getGooglePlaceResult(addr, autocomplete) {
      var addrText = $(addr).val();
      var geocoder = new google.maps.Geocoder();

      geocoder.geocode({address: addrText}, function(results, status) {
        if (status === google.maps.GeocoderStatus.OK) {
          google.maps.event.trigger(autocomplete, 'place_changed', results[0], true);
        }
      });
    }

    MapMaker.prototype.setupAutocomplete = function (input, cityLevel, cb) {
      var self = this;
      var options = { types: cityLevel ? ['(regions)'] : ['geocode', 'establishment'] }; // [] is all
      var autocomplete = new google.maps.places.Autocomplete(input, options);
      autocomplete.bindTo('bounds', this.google_map);

      // make sure that we query for address lat/long no matter what
      $(input).blur(function(e) {
        getGooglePlaceResult(input, autocomplete);
        return false;
      })
      .keydown(function(e) {
        if (e.which === 13) {
          getGooglePlaceResult(input, autocomplete);
          return false;
        }
      });

      // listen for location changes on this text field and center the map on new position
      google.maps.event.addListener(autocomplete, 'place_changed', function(results, needCoords) {
        var place;

        if (needCoords) {
          place = results;
        } else {
          place = autocomplete.getPlace();
        }

        cb.call(self, place);
      });
    };

    MapMaker.prototype.updateLocation = function() {
        var google_map = this.google_map;
        function getCurrentPosition_success(pos) {
            var crd = pos.coords;
            var mapCenter = new google.maps.LatLng(crd.latitude, crd.longitude);
            google_map.setZoom(13);
            google_map.setCenter(mapCenter);
        }
        function getCurrentPosition_error(err) {
            console.warn('ERROR(' + err.code + '): ' + err.message);
        };
        var options = {
            enableHighAccuracy: true,
            timeout: 1000,
            maximumAge: 0,
            };

        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(getCurrentPosition_success, getCurrentPosition_error, options);
        } else {
            console.log("Sorry - your browser doesn't support geolocation!");
        }
    }
    return MapMaker;
});
<commit_msg>[bug 896649] Fix clicking on clustered pins opens every single pin<commit_after>define(['jquery', 'google', 'infobubble', 'oms', 'markerclusterer'],
function ($, google, InfoBubble, OverlappingMarkerSpiderfier, MarkerClusterer) {

    function MapMaker(map_canvas, mapOptions, mcOptions, omsOptions) {
        var self = this;
        this.map_canvas = map_canvas;
        this.google_map = new google.maps.Map(map_canvas, mapOptions);
        this.geocoder = new google.maps.Geocoder();
        this.markerManager = new MarkerClusterer(this.google_map, [], mcOptions);
        this.infoWindow = new InfoBubble({ // TODO: move styling into less/css file
          minWidth: 330,
          maxWidth: 330,
          minHeight: 130,
          maxHeight: 710,
          shadowStyle: 1,
          padding: 0,
          // Padding around the tabs, now set separately from the InfoBubble padding
          borderRadius: 8,
          borderWidth: 1,
          // Now that there is no borderWidth check, you can define
          // a borderColor and it will apply to Just the arrow
          disableAutoPan: false,
          hideCloseButton: false,
          backgroundColor: '#fff',
          backgroundClassName: 'info-container',
          arrowSize: 20,
          pixelOffset: [-5, 60],
          arrowStyle: 0
        });

        // this handles multiple markers at the same location
        this.oms = new OverlappingMarkerSpiderfier(this.google_map, omsOptions);

        this.oms.addListener('click', function(marker, evt) {
          self.infoWindow.setContent(marker.get('infoContent'));
          self.infoWindow.open(self.google_map, marker);
          $('.gm-style').removeClass(); // remove new styling introduces in GM 3.1
        });

        google.maps.event.addListener(this.google_map, 'zoom_changed', function(ev) {
            setTimeout(function () {
                if (self.google_map.getZoom() <= 15) return;
                var markers = self.oms.markersNearAnyOtherMarker();
                var seen = {};
                var ID = '__gm_id';
                var theMarker = null;
                markers.forEach(function (m) {
                    if (m[ID] in seen) return;
                    self.oms.markersNearMarker(m).forEach(function (nm) {
                        seen[nm[ID]] = true;
                    });
                    theMarker = m;
                    seen[m[ID]] = true;
                });
                if (theMarker) {
                  google.maps.event.trigger(theMarker , 'click');
                }
            }, 400);
        });
    }

    MapMaker.prototype.dropPins = function (models, animate, filter) {
        animate = (animate === undefined) ? true : animate;

        var self = this;
        models.forEach(function (model) {
            if (filter && !filter(model)) return;

            if (animate)
                setTimeout(function() { self.addMarker(model, animate) },
                      300 + (500 * Math.random()));
            else
                self.addMarker(model, animate);
        })
    };
    MapMaker.prototype.addMarker = function (model, animate, dim) {
        animate = animate === undefined ? true  : animate;
        dim     = dim     === undefined ? false : dim;

        // pin-event.png or pin-event-featured.png
        var icon = {
            url: "/img/map/pin-event" + (
                     model.featured ? "-featured" : ""
                ) + ".png"   // 43 x 51
        };

        var marker = new google.maps.Marker({
            title: model.title,
            position: new google.maps.LatLng(model.latitude, model.longitude),
            icon: icon,
            draggable: false,
            animation: animate ? google.maps.Animation.DROP : undefined,
            // Point where info window is shown, horizontal is not used in
            // infoBubble.js -- see markers anchor for this horizontal adjustment
            anchorPoint: new google.maps.Point(0, 20),
        });

        this.markerManager.addMarker(marker);
        this.oms.addMarker(marker);    // must keep oms in sync
        scroll(0, 0);

        // store the content for the info window in the marker
        marker.set('infoContent', model.popupHTML());
        marker.set('model', model);

        return marker;
    };
    /* Delete all markers by removing references to them */
    MapMaker.prototype.clearMarkers = function () {
        this.markerManager.clearMarkers();
        this.oms.clearMarkers();
        return this;
    }
    MapMaker.prototype.getMarkers = function() {
        return this.markerManager.getMarkers();
    };
    MapMaker.prototype.setupInfoWindow = function () {
        var self = this;
        google.maps.event.addListener(this.google_map, 'click', function(ev) {
            self.closeInfoWindow();
        });
    };
    MapMaker.prototype.closeInfoWindow = function () {
        if (this.infoWindow) {
            this.infoWindow.setMap(null);
        }
    };

    // queries the Google Maps Places API for a 'PlacesResult' object,
    // which contains data like lat/long, formatted address name, etc
    // See https://developers.google.com/maps/documentation/javascript/reference#Geocoder
    // for more information
    function getGooglePlaceResult(addr, autocomplete) {
      var addrText = $(addr).val();
      var geocoder = new google.maps.Geocoder();

      geocoder.geocode({address: addrText}, function(results, status) {
        if (status === google.maps.GeocoderStatus.OK) {
          google.maps.event.trigger(autocomplete, 'place_changed', results[0], true);
        }
      });
    }

    MapMaker.prototype.setupAutocomplete = function (input, cityLevel, cb) {
      var self = this;
      var options = { types: cityLevel ? ['(regions)'] : ['geocode', 'establishment'] }; // [] is all
      var autocomplete = new google.maps.places.Autocomplete(input, options);
      autocomplete.bindTo('bounds', this.google_map);

      // make sure that we query for address lat/long no matter what
      $(input).blur(function(e) {
        getGooglePlaceResult(input, autocomplete);
        return false;
      })
      .keydown(function(e) {
        if (e.which === 13) {
          getGooglePlaceResult(input, autocomplete);
          return false;
        }
      });

      // listen for location changes on this text field and center the map on new position
      google.maps.event.addListener(autocomplete, 'place_changed', function(results, needCoords) {
        var place;

        if (needCoords) {
          place = results;
        } else {
          place = autocomplete.getPlace();
        }

        cb.call(self, place);
      });
    };

    MapMaker.prototype.updateLocation = function() {
        var google_map = this.google_map;
        function getCurrentPosition_success(pos) {
            var crd = pos.coords;
            var mapCenter = new google.maps.LatLng(crd.latitude, crd.longitude);
            google_map.setZoom(13);
            google_map.setCenter(mapCenter);
        }
        function getCurrentPosition_error(err) {
            console.warn('ERROR(' + err.code + '): ' + err.message);
        };
        var options = {
            enableHighAccuracy: true,
            timeout: 1000,
            maximumAge: 0,
            };

        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(getCurrentPosition_success, getCurrentPosition_error, options);
        } else {
            console.log("Sorry - your browser doesn't support geolocation!");
        }
    }
    return MapMaker;
});
<|endoftext|>


<commit_before>/**
 * .reel Unit Tests
 */
(function($){

  module('Animation', { teardown: function teardown(){
    $('.jquery-reel').trigger('teardown');
		$(document).unbind('tick.reel');
  }});

	asyncTest( 'When at least one instance of Reel is present in the DOM a shared ticker is started', function()
	{
		expect(1);

		$(document).bind('tick.reel', tick);

		var
			ticks = 0;

		setTimeout(function(){
			ok( ticks == 0, 'Ticker isn\'t running when no Reel is on');
			start();
		}, 1000);

		function tick(){
			ticks++
		}
	});

	asyncTest( 'Ticker is driven by `leader`\'s data from `$.reel.leader()`', function()
	{
		expect(9);

		$(document).bind('tick.reel', tick);

		var
			ticks = 0,
			$faster = $('#image').reel({ tempo: 20 }),
			$slower = $('#image2').reel({ tempo: 10 });

		setTimeout(function(){
			deepEqual( $.reel.leader(), $faster.data(), 'Leader\'s data are the first (oldest living) instance\'s data')
			equals( $.reel.leader('tempo'), $faster.data('tempo'), 'Timer keeps faster tempo dictated by the leader');

			ok( $faster.trigger('teardown'), 'The older faster instance destroyed (the latter slower instance remains)');

			setTimeout(function(){
				deepEqual( $.reel.leader(), $slower.data(), 'Leader\'s data are the second (now the only) instance\'s data')
				equals( $.reel.leader('tempo'), $slower.data('tempo'), 'Ticker slowed down');

				ok( $slower.trigger('teardown'), 'Slower instance removed too (no instance remains)')
				var
					ticks_copy= ticks;

				setTimeout(function(){
					equals( $.reel.leader(), undefined, 'Without a leader there\'s no data');
					equals( $.reel.leader('tempo'), undefined, 'and no leader\'s tempo');
					equals( ticks_copy, ticks, 'Ticker is stopped.');

					start();
				}, 1000);

			}, 1000);

		}, 1000);

		function tick(){
			ticks++
		}
	});

	// We generate tests for several different tempos ranging from 6 to 48
	$.each([6, 8, 10, 12, 18, 24, 36], function(ix, tempo){

		var
			one_second= 1000,
			lazy_tempo= tempo / ($.reel.lazy? $.reel.def.laziness : 1)

		// We also try different speeds - no animation, odd value, normal value and a speedy value
		$.each([0, 0.69, 1, 3], function(ixx, speed){

			asyncTest( 'Ticker timing precision on `tempo: ' + lazy_tempo + '` - measuring 1 second at `speed: ' + speed + '`...', function()
			{
				expect(2);

				var
					ticks= 0,
					sum= 0,
					bang= +new Date(),
					$reel= $('#image').reel({ tempo: tempo, speed: speed })

				$(document).bind('tick.reel', function tick(){
					ticks++;
				});

				setTimeout(function(duration){
					duration= +new Date() - bang;
					ok( duration < 1.2 * one_second, 'Duration of what wannabe one second within 20 % tolerance with slip ' + (duration - one_second) + ' ms');
					ok( ticks < Math.max(1, 1.2 * lazy_tempo), 'Counted ticks within 20 % tolerance with slip ' + (tempo - ticks) + '.');
					start();
				}, one_second);
			});
		});
	});

	asyncTest( 'Running instances have their overall running cost (in ms) exposed as `$.reel.cost`', function()
	{
		expect(4);

		$('#image').reel({ speed: 1 });

		setTimeout(function(){
			var
				cost_of_one

			ok( is('Number', cost_of_one= $.reel.cost), 'Number `$.reel.cost`')
			ok( cost_of_one >= 0, 'Non-zero cost of one instance (' + cost_of_one + ' ms)' )

			$('#image2').reel({ speed: 2 });
			$('#stitched_looping').reel({ speed: 2 });

			setTimeout(function(){
				var
					cost_of_three= $.reel.cost

				ok( cost_of_three > 0, 'Non-zero cost of two instances (' + cost_of_three + ' ms)' )
				ok( cost_of_three > cost_of_one, 'Running cost of three instances is higher then of one' )
				start();

			}, 100);

		}, 100);

	});

})(jQuery);<commit_msg>Reduced speed samples to just two (0 and 1), which will test both animated and non-animated and reduce animation tests waiting time to a half.<commit_after>/**
 * .reel Unit Tests
 */
(function($){

  module('Animation', { teardown: function teardown(){
    $('.jquery-reel').trigger('teardown');
		$(document).unbind('tick.reel');
  }});

	asyncTest( 'When at least one instance of Reel is present in the DOM a shared ticker is started', function()
	{
		expect(1);

		$(document).bind('tick.reel', tick);

		var
			ticks = 0;

		setTimeout(function(){
			ok( ticks == 0, 'Ticker isn\'t running when no Reel is on');
			start();
		}, 1000);

		function tick(){
			ticks++
		}
	});

	asyncTest( 'Ticker is driven by `leader`\'s data from `$.reel.leader()`', function()
	{
		expect(9);

		$(document).bind('tick.reel', tick);

		var
			ticks = 0,
			$faster = $('#image').reel({ tempo: 20 }),
			$slower = $('#image2').reel({ tempo: 10 });

		setTimeout(function(){
			deepEqual( $.reel.leader(), $faster.data(), 'Leader\'s data are the first (oldest living) instance\'s data')
			equals( $.reel.leader('tempo'), $faster.data('tempo'), 'Timer keeps faster tempo dictated by the leader');

			ok( $faster.trigger('teardown'), 'The older faster instance destroyed (the latter slower instance remains)');

			setTimeout(function(){
				deepEqual( $.reel.leader(), $slower.data(), 'Leader\'s data are the second (now the only) instance\'s data')
				equals( $.reel.leader('tempo'), $slower.data('tempo'), 'Ticker slowed down');

				ok( $slower.trigger('teardown'), 'Slower instance removed too (no instance remains)')
				var
					ticks_copy= ticks;

				setTimeout(function(){
					equals( $.reel.leader(), undefined, 'Without a leader there\'s no data');
					equals( $.reel.leader('tempo'), undefined, 'and no leader\'s tempo');
					equals( ticks_copy, ticks, 'Ticker is stopped.');

					start();
				}, 1000);

			}, 1000);

		}, 1000);

		function tick(){
			ticks++
		}
	});

	// We generate tests for several different tempos ranging from 6 to 48
	$.each([6, 8, 10, 12, 18, 24, 36], function(ix, tempo){

		var
			one_second= 1000,
			lazy_tempo= tempo / ($.reel.lazy? $.reel.def.laziness : 1)

		// We also try both animated and non-animated
		$.each([0, 1], function(ixx, speed){

			asyncTest( 'Ticker timing precision on `tempo: ' + lazy_tempo + '` - measuring 1 second at `speed: ' + speed + '`...', function()
			{
				expect(2);

				var
					ticks= 0,
					sum= 0,
					bang= +new Date(),
					$reel= $('#image').reel({ tempo: tempo, speed: speed })

				$(document).bind('tick.reel', function tick(){
					ticks++;
				});

				setTimeout(function(duration){
					duration= +new Date() - bang;
					ok( duration < 1.2 * one_second, 'Duration of what wannabe one second within 20 % tolerance with slip ' + (duration - one_second) + ' ms');
					ok( ticks < Math.max(1, 1.2 * lazy_tempo), 'Counted ticks within 20 % tolerance with slip ' + (tempo - ticks) + '.');
					start();
				}, one_second);
			});
		});
	});

	asyncTest( 'Running instances have their overall running cost (in ms) exposed as `$.reel.cost`', function()
	{
		expect(4);

		$('#image').reel({ speed: 1 });

		setTimeout(function(){
			var
				cost_of_one

			ok( is('Number', cost_of_one= $.reel.cost), 'Number `$.reel.cost`')
			ok( cost_of_one >= 0, 'Non-zero cost of one instance (' + cost_of_one + ' ms)' )

			$('#image2').reel({ speed: 2 });
			$('#stitched_looping').reel({ speed: 2 });

			setTimeout(function(){
				var
					cost_of_three= $.reel.cost

				ok( cost_of_three > 0, 'Non-zero cost of two instances (' + cost_of_three + ' ms)' )
				ok( cost_of_three > cost_of_one, 'Running cost of three instances is higher then of one' )
				start();

			}, 100);

		}, 100);

	});

})(jQuery);<|endoftext|>


<commit_before>export default {
  MAX_ATTACHMENT_SIZE: 5000000,
  s3: {
    BUCKET: "notes-app-uploads"
  },
  apiGateway: {
    REGION: "us-east-1",
    URL: "https://5by75p4gn3.execute-api.us-east-1.amazonaws.com/prod"
  },
  cognito: {
    REGION: "us-east-1",
    USER_POOL_ID: "us-east-1_udmFFSb92",
    APP_CLIENT_ID: "4hmari2sqvskrup67crkqa4rmo",
    IDENTITY_POOL_ID: "us-east-1:ceef8ccc-0a19-4616-9067-854dc69c2d82"
  }
};
<commit_msg>config<commit_after>export default {
  MAX_ATTACHMENT_SIZE: 5000000,
  s3: {
  BUCKET: "bryan-notes-serverless"
},
  apiGateway: {
  URL: "https://3xi2f2sfo4.execute-api.eu-west-2.amazonaws.com/prod",
  REGION: "eu-west-2"
},
  cognito: {
    USER_POOL_ID: "eu-west-2_hwTpXir6K",
    APP_CLIENT_ID: "39ccsoeve71591e9n63k340jq0"
    REGION: "eu-west-2",
    IDENTITY_POOL_ID: "eu-west-2:d38f353f-c2c2-4ee8-a5b0-6b83e4613894",
  }
};
<|endoftext|>


<commit_before>import fetch from 'jest-fetch-mock';

global.fetch = fetch;
<commit_msg>Eslint fix for jest-fetch-mock<commit_after>/* eslint-disable import/no-extraneous-dependencies */
import fetch from 'jest-fetch-mock';

global.fetch = fetch;
<|endoftext|>


<commit_before>module.exports = {
  sesRegion: 'us-east-1',
  sesEndpoint: process.env.SES_ENDPOINT,
  kinesisRegion: process.env.KINESIS_REGION || 'ap-southeast-2',
  kinesisEndpoint: process.env.KINESIS_ENDPOINT,
  accessKeyId: process.env.AWS_ACCESS_KEY_ID || 'FAKE',
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || 'FAKE',
  streamName: process.env.STREAM_NAME,
  listenerAuthToken: process.env.LISTENER_AUTH_TOKEN || 'secret',
  s3EmailBucket: process.env.S3_EMAILS_BUCKET || 'bucket',
  s3Endpoint: process.env.S3_ENDPOINT || 'bucketEndpoint',
  s3Region: process.env.S3_REGION || 'ap-southeast-2',
};
<commit_msg>Don't default the S3 endpoint, so prod doesn't break<commit_after>module.exports = {
  sesRegion: 'us-east-1',
  sesEndpoint: process.env.SES_ENDPOINT,
  kinesisRegion: process.env.KINESIS_REGION || 'ap-southeast-2',
  kinesisEndpoint: process.env.KINESIS_ENDPOINT,
  accessKeyId: process.env.AWS_ACCESS_KEY_ID || 'FAKE',
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || 'FAKE',
  streamName: process.env.STREAM_NAME,
  listenerAuthToken: process.env.LISTENER_AUTH_TOKEN || 'secret',
  s3EmailBucket: process.env.S3_EMAILS_BUCKET || 'bucket',
  s3Endpoint: process.env.S3_ENDPOINT,
  s3Region: process.env.S3_REGION || 'ap-southeast-2',
};
<|endoftext|>