<commit_before>
//
//  replay.js
//
//  - View a replay of all operations that have occurred in a room.
//
//  Copyright (c) 2015 Visionist, Inc.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//

function Replay (params) {
  this.chat         = params.chat;
  this.client       = params.client;
  this.codemirror   = params.codemirror;
  this.delay        = params.delay;
  this.room         = params.room;
  this.share        = params.share;
  this.timestamps   = params.timestamps;
  this.operations   = [];
  this.snapshot     = {};
  this.time_slider  = null;
  this.current_v    = null;
  this.old_toc      = params.old_toc;
  this.old_inst     = params.old_inst;
  this.old_tstamps  = params.old_tstamps;
  this.stopped      = false;
  this.flagged      = [];
  this.current_flag = null;
  this.next_flag    = 0;
  this.prev_flag    = null;

  var at_flag = false;
  var instance = this;
  var stop = false;

  var flagTemplate = '
' +
    '
';

  /*
   *  Sets the everything to .
   */
  this.setUp = function (callback) {
    $.get ('ops/' + this.room, function (operations) {
      if (operations[0] && operations[0].create) {
        instance.current_v  = 0;
        instance.operations = operations;
        instance.snapshot   = operations[0].create.data;
        instance.codemirror.setValue (instance.snapshot.text);

        instance.fireSliderEventHandlers ();
        instance.timestamps.draw (instance.snapshot.lines);

        callback ();
      }
    });

    // click handler for changing replay speed
    $('#speed-buttons-container button').on('click', function(event) {
      $activeButton = $(this);
      $activeButton.blur();
      instance.delay = Number($activeButton.data('delay'));
      $('#speed-buttons-container button').removeClass('active');
      $activeButton.toggleClass('active');
    });
  };

  /*
   *  Add any flagged versions to the replay slider div
   */
  this.addFlags = function() {
    this.flagged = [];
    this.current_flag = null;
    $('#flag-left').prop("disabled",true);
    for (var i = 0; i < instance.operations.length; i++) {
      if (instance.operations[i].flagged) {
        this.flagged.push(i);
        var percentLeft = (instance.operations[i].v / instance.operations.length * 100);
        var element = flagTemplate.replace('{{percentLeft}}', percentLeft);
        $('#replaySlider').append (element);
      }
    }
    if (this.flagged.length === 0){
      $('#flag-left').prop("disabled",true);
      $('#flag-right').prop("disabled",true);
    }
  };
  this.setVersion = function (version) {
    /*
     *  This fires whenever the timeslider moves --
     *  -- manually or programatically.
     */
    if (version < instance.current_v) {
      /*
       *  Unbuild the snapshot up to the desired version.
       */
      for (var i = instance.current_v - 1; i >= version; i--) {
        if (instance.operations[i].op) {
          instance.snapshot = ottypes.json0.apply (instance.snapshot, ottypes.json0.invert(instance.operations[i].op));
        }
      }
    } else if (version > instance.current_v) {
      /*
       *  Build the snapshot up to the desired version.
       */
      for (var j = instance.current_v; j < version; j++) {

        if (instance.operations[j].op) {
          instance.snapshot = ottypes.json0.apply (instance.snapshot, instance.operations[j].op);
        }
      }
    }

    instance.codemirror.setValue (instance.snapshot.text);
    instance.timestamps.draw (instance.snapshot.lines);
    instance.old_toc.generateHeaders(instance.codemirror);
    instance.current_v = version;
    instance.time_slider.slider ('setValue', instance.current_v);
    instance.setCurrentFlag();
    return 'Version: ' + version;
  };

  /*
  * Moves to next flag
  */
  this.nextFlag = function(){
    if (!this.stopped){
      $('#start-replay-button').toggleClass('active');
      $('#start-replay-button').find('span.glyphicon').toggleClass('glyphicon-pause').toggleClass('glyphicon-play');
      this.stop();
    }

    this.setVersion(this.flagged[this.next_flag]);
    at_flag = true;
  };

  /*
  * Moves to previous flag
  */
  this.prevFlag = function(){
    if(!this.stopped){
      $('#start-replay-button').toggleClass('active');
      $('#start-replay-button').find('span.glyphicon').toggleClass('glyphicon-pause').toggleClass('glyphicon-play');
      this.stop();
    }

    this.setVersion(this.flagged[this.prev_flag]);
    at_flag = true;

  };

  this.setCurrentFlag = function(){
    var index = 0;
    if (this.current_v < this.flagged[0]){
      this.current_flag = null;
      this.prev_flag = null;
      this.next_flag = 0;
    }
    else if(this.current_v === this.flagged[0]){
      this.current_flag = 0;
      this.prev_flag = null;
      this.next_flag = 1;
    }
    else if(this.current_v > this.flagged[this.flagged.length-1]){
      this.current_flag = this.flagged.length-1;
      this.prev_flag = this.flagged.length-1;
      this.next_flag = null;
    }
    else if(this.current_v === this.flagged[this.flagged.length-1]){
      this.current_flag = this.flagged.length-1;
      this.prev_flag = this.flagged.length-2;
      this.next_flag = null;
    }
    else{
      while(index < this.flagged.length-1){
        if (this.current_v > this.flagged[index] && this.current_v < this.flagged[index+1]){
          this.current_flag = index;
          this.prev_flag = index;
          this.next_flag = index+1;
          break;
        }
        else if(this.current_v === this.flagged[index]){
          this.current_flag = index;
          this.prev_flag = index - 1;
          this.next_flag = index + 1;
          break;
        }
        index++;
      }

    }
    this.checkFlagButtons();
  };

  this.checkFlagButtons = function(){
    if(this.prev_flag === null){
      $('#flag-left').prop("disabled",true);
    }
    else if(this.next_flag === null){
      $('#flag-right').prop("disabled",true);
    }
    else{
      $('#flag-left').prop("disabled",false);
      $('#flag-right').prop("disabled",false);
    }

  };

  this.reset = function () {
    instance.current_v = 0;
    instance.snapshot  = instance.operations[0].create.data;
    instance.time_slider.slider ('setValue', instance.current_v);
    instance.codemirror.setValue (instance.snapshot.text);

    $('#start-replay-button').removeClass ('active');
    $('#start-replay-button').find('span.glyphicon').removeClass ('glyphicon-pause').addClass ('glyphicon-play');
    this.stopped = true;

    // clear flags, since they will need to be redrawn next time
    $('#replaySlider .flagged-versions').remove();
  };

  /*
   *  Instantiates the slider within the controls container.
   */
  this.fireSliderEventHandlers = function () {
    instance.time_slider = $('#replay-slider').slider ({
      min: 0,
      max: instance.operations.length,
      value: 0,
      formatter: function (version) {
        /*
         *  This fires whenever the timeslider moves --
         *  -- manually or programatically.
         */
        if (version < instance.current_v) {
          /*
           *  Unbuild the snapshot up to the desired version.
           */
          for (var i = instance.current_v - 1; i >= version; i--) {
            if (instance.operations[i].op) {
              instance.snapshot = ottypes.json0.apply (instance.snapshot, ottypes.json0.invert(instance.operations[i].op));
            }
          }
        } else if (version > instance.current_v) {
          /*
           *  Build the snapshot up to the desired version.
           */
          for (var j = instance.current_v; j < version; j++) {

            if (instance.operations[j].op) {
              instance.snapshot = ottypes.json0.apply (instance.snapshot, instance.operations[j].op);
            }
          }
        }

        instance.codemirror.setValue (instance.snapshot.text);
        instance.timestamps.draw (instance.snapshot.lines);
        instance.old_toc.generateHeaders(instance.codemirror);
        instance.current_v = version;
        instance.setCurrentFlag();
        return 'Version: ' + version;
      }
    });
  };

  /*
   *  Starts document replay.
   */
  this.replay = function () {
    this.stopped = false;
    if (instance.current_v >= instance.operations.length) {
      instance.setUp (function () {
        instance.replay ();
      });
    } else {
      instance.slide ();
    }
  };

  /*
   *  Recursively plays through the rest of the operations.
   */
  this.slide = function () {
    if (instance.current_v >= instance.operations.length || (instance.operations[instance.current_v].flagged && !at_flag)) {
      console.log(this.flagged);
      at_flag = true;
      $('#start-replay-button').toggleClass('active');
      $('#start-replay-button').find('span.glyphicon').toggleClass('glyphicon-pause').toggleClass('glyphicon-play');
      this.current_flag =
      this.stopped = true;
      stop = false;
      return;
    } else if (stop) {
      at_flag = false;
      stop = false;
      return;
    }
    at_flag = false;
    instance.time_slider.slider ('setValue', instance.current_v + 1);

    setTimeout(function() {
      instance.slide ();
    }, instance.delay);
  };

  this.stop = function() {
    this.stopped = true;
    stop = true;
    at_flag = true;
  };
}
<commit_msg>Fixed Replay bugs<commit_after>
//
//  replay.js
//
//  - View a replay of all operations that have occurred in a room.
//
//  Copyright (c) 2015 Visionist, Inc.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//

function Replay (params) {
  this.chat         = params.chat;
  this.client       = params.client;
  this.codemirror   = params.codemirror;
  this.delay        = params.delay;
  this.room         = params.room;
  this.share        = params.share;
  this.timestamps   = params.timestamps;
  this.operations   = [];
  this.snapshot     = {};
  this.time_slider  = null;
  this.current_v    = null;

  /*
  * These are for the realtime adjustment of the table of contents.
  * Also used to recreate editor view without needing a refresh by user
  */
  this.old_toc      = params.old_toc;
  this.old_inst     = params.old_inst;
  this.old_tstamps  = params.old_tstamps;

  //Used to tell the play/pause button when to start/stop
  this.stopped      = false;

  //Used for flagging capabilities
  this.flagged      = [];
  this.current_flag = null;
  this.next_flag    = 0;
  this.prev_flag    = null;
  this.at_flag = false;

  var instance = this;
  var stop = false;

  var flagTemplate = '
' +
    '
';

  /*
   *  Sets the everything to .
   */
  this.setUp = function (callback) {
    $.get ('ops/' + this.room, function (operations) {
      if (operations[0] && operations[0].create) {
        instance.current_v  = 0;
        instance.operations = operations;
        instance.snapshot   = operations[0].create.data;
        instance.codemirror.setValue (instance.snapshot.text);

        instance.fireSliderEventHandlers ();
        instance.timestamps.draw (instance.snapshot.lines);

        // makes sure to reset the current/prev/next flag on startup
        this.current_flag = null;
        this.prev_flag = null;
        this.next_flag = 0;

        callback ();
      }
    });

    // click handler for changing replay speed
    $('#speed-buttons-container button').on('click', function(event) {
      $activeButton = $(this);
      $activeButton.blur();
      instance.delay = Number($activeButton.data('delay'));
      $('#speed-buttons-container button').removeClass('active');
      $activeButton.toggleClass('active');
    });
  };

  /*
   *  Add any flagged versions to the replay slider div
   */
  this.addFlags = function() {
    this.flagged = [];
    this.current_flag = null;
    $('#flag-left').prop("disabled",true);
    for (var i = 0; i < instance.operations.length; i++) {
      if (instance.operations[i].flagged) {
        this.flagged.push(i);
        var percentLeft = (instance.operations[i].v / instance.operations.length * 100);
        var element = flagTemplate.replace('{{percentLeft}}', percentLeft);
        $('#replaySlider').append (element);
      }
    }
    if (this.flagged.length === 0){
      $('#flag-left').prop("disabled",true);
      $('#flag-right').prop("disabled",true);
    }
  };

  /*
  * Non-anonymous version of the slider listener. Just a copy-paste of it really..
  */
  this.setVersion = function (version) {
    /*
     *  This fires whenever the timeslider moves --
     *  -- manually or programatically.
     */
    if (version < instance.current_v) {
      /*
       *  Unbuild the snapshot up to the desired version.
       */
      for (var i = instance.current_v - 1; i >= version; i--) {
        if (instance.operations[i].op) {
          instance.snapshot = ottypes.json0.apply (instance.snapshot, ottypes.json0.invert(instance.operations[i].op));
        }
      }
    } else if (version > instance.current_v) {
      /*
       *  Build the snapshot up to the desired version.
       */
      for (var j = instance.current_v; j < version; j++) {

        if (instance.operations[j].op) {
          instance.snapshot = ottypes.json0.apply (instance.snapshot, instance.operations[j].op);
        }
      }
    }

    instance.codemirror.setValue (instance.snapshot.text);
    instance.timestamps.draw (instance.snapshot.lines);
    instance.old_toc.generateHeaders(instance.codemirror);
    instance.current_v = version;
    instance.time_slider.slider ('setValue', instance.current_v);
    instance.setCurrentFlag();
    return 'Version: ' + version;
  };

  /*
  * Moves to next flag
  */
  this.nextFlag = function(){
    if (!this.stopped){
      $('#start-replay-button').toggleClass('active');
      $('#start-replay-button').find('span.glyphicon').toggleClass('glyphicon-pause').toggleClass('glyphicon-play');
      this.stop();
    }
    this.at_flag = true;
    this.setVersion(this.flagged[this.next_flag]);

  };

  /*
  * Moves to previous flag
  */
  this.prevFlag = function(){
    if(!this.stopped){
      $('#start-replay-button').toggleClass('active');
      $('#start-replay-button').find('span.glyphicon').toggleClass('glyphicon-pause').toggleClass('glyphicon-play');
      this.stop();
    }
    this.at_flag = true;
    this.setVersion(this.flagged[this.prev_flag]);

  };

  /*
  * Gets the current/prev/next flag based on the position of the slider
  * Iterates through all flags, each time the slider moves, so for a large
  * number of flagged versions, it may have performance issues.
  */
  this.setCurrentFlag = function(){
    var index = 0;
    if (this.current_v < this.flagged[0]){
      this.current_flag = null;
      this.prev_flag = null;
      this.next_flag = 0;
    }
    else if(this.current_v === this.flagged[0]){
      this.current_flag = 0;
      this.prev_flag = null;
      this.next_flag = 1;
    }
    else if(this.current_v > this.flagged[this.flagged.length-1]){
      this.current_flag = this.flagged.length-1;
      this.prev_flag = this.flagged.length-1;
      this.next_flag = null;
    }
    else if(this.current_v === this.flagged[this.flagged.length-1]){
      this.current_flag = this.flagged.length-1;
      this.prev_flag = this.flagged.length-2;
      this.next_flag = null;
    }
    else{
      while(index < this.flagged.length-1){
        if (this.current_v > this.flagged[index] && this.current_v < this.flagged[index+1]){
          this.current_flag = index;
          this.prev_flag = index;
          this.next_flag = index+1;
          break;
        }
        else if(this.current_v === this.flagged[index]){
          this.current_flag = index;
          this.prev_flag = index - 1;
          this.next_flag = index + 1;
          break;
        }
        index++;
      }

    }
    this.checkFlagButtons();
  };

  /*
  * Checks to see if the left/right flag buttons should be disabled. If
  * there are no more flags on either side, disable it.
  */
  this.checkFlagButtons = function(){
    if(this.prev_flag !== null){
      $('#flag-left').prop("disabled",false);
    }else{
      $('#flag-left').prop("disabled",true);
    }
    if(this.next_flag !== null){
      $('#flag-right').prop("disabled",false);
    }
    else{
      $('#flag-right').prop("disabled",true);
    }

  };

  this.reset = function () {
    instance.current_v = 0;
    instance.snapshot  = instance.operations[0].create.data;
    instance.time_slider.slider ('setValue', instance.current_v);
    instance.codemirror.setValue (instance.snapshot.text);
    $('#start-replay-button').removeClass ('active');
    $('#start-replay-button').find('span.glyphicon').removeClass ('glyphicon-pause').addClass ('glyphicon-play');
    this.stopped = true;

    // clear flags, since they will need to be redrawn next time
    $('#replaySlider .flagged-versions').remove();
  };

  /*
   *  Instantiates the slider within the controls container.
   */
  this.fireSliderEventHandlers = function () {
    instance.time_slider = $('#replay-slider').slider ({
      min: 0,
      max: instance.operations.length,
      value: 0,
      formatter: function (version) {
        /*
         *  This fires whenever the timeslider moves --
         *  -- manually or programatically.
         */
        if (version < instance.current_v) {
          /*
           *  Unbuild the snapshot up to the desired version.
           */
          for (var i = instance.current_v - 1; i >= version; i--) {
            if (instance.operations[i].op) {
              instance.snapshot = ottypes.json0.apply (instance.snapshot, ottypes.json0.invert(instance.operations[i].op));
            }
          }
        } else if (version > instance.current_v) {
          /*
           *  Build the snapshot up to the desired version.
           */
          for (var j = instance.current_v; j < version; j++) {

            if (instance.operations[j].op) {
              instance.snapshot = ottypes.json0.apply (instance.snapshot, instance.operations[j].op);
            }
          }
        }

        instance.codemirror.setValue (instance.snapshot.text);
        instance.timestamps.draw (instance.snapshot.lines);
        instance.old_toc.generateHeaders(instance.codemirror);
        instance.current_v = version;
        instance.setCurrentFlag();
        return 'Version: ' + version;
      }
    });
  };

  /*
   *  Starts document replay.
   */
  this.replay = function () {
    this.stopped = false;
    if (instance.current_v >= instance.operations.length) {
      instance.setUp (function () {
        instance.replay ();
      });
    } else {
      instance.slide ();
    }
  };

  /*
   *  Recursively plays through the rest of the operations.
   */
  this.slide = function () {
    if (instance.current_v >= instance.operations.length || (instance.operations[instance.current_v].flagged && !this.at_flag)) {
      console.log(this.flagged);
      this.at_flag = true;
      $('#start-replay-button').toggleClass('active');
      $('#start-replay-button').find('span.glyphicon').toggleClass('glyphicon-pause').toggleClass('glyphicon-play');

      this.stopped = true;
      stop = false;
      return;
    } else if (stop) {
      stop = false;
      return;
    }
    this.at_flag = false;
    instance.time_slider.slider ('setValue', instance.current_v + 1);

    setTimeout(function() {
      instance.slide ();
    }, instance.delay);
  };

  this.stop = function() {
    this.stopped = true;
    stop = true;
    //at_flag = true;
  };
}
<|endoftext|>


<commit_before>module.exports = function (config) {
    if (process.env.TRAVIS && (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY)) {
        console.log('Make sure the SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables are set.');
        process.exit(1);
    }

    var customLaunchers = {
        sl_chrome: {
            base: 'SauceLabs',
            browserName: 'chrome',
            platform: 'Windows 7'
        },
        sl_firefox: {
            base: 'SauceLabs',
            browserName: 'firefox'
        },
        sl_safari: {
            base: 'SauceLabs',
            browserName: 'iphone',
            platform: 'OS X 10.9'
        },
        sl_ie: {
            base: 'SauceLabs',
            browserName: 'internet explorer',
            platform: 'Windows 8.1'
        },
        sl_edge: {
            base: 'SauceLabs',
            browserName: 'MicrosoftEdge',
            platform: 'Windows 10'
        }
    };

    config.set({

        // base path that will be used to resolve all patterns (eg. files, exclude)
        basePath: '',

        // frameworks to use
        // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
        frameworks: ['systemjs', 'jasmine'],

        //plugins
        plugins: process.env.TRAVIS
            ? ['karma-systemjs', 'karma-jasmine', 'karma-sauce-launcher']
            : ['karma-systemjs', 'karma-jasmine', 'karma-chrome-launcher'],

        // list of files / patterns to load in the browser
        files: [
            'tests/*-spec.js',
            'tests/*-specs.js'
        ],

        // list of files to exclude
        exclude: [],

        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors: {},

        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: process.env.TRAVIS ? ['dots', 'saucelabs'] : ['progress'],

        // web server port
        port: 9876,

        // enable / disable colors in the output (reporters and logs)
        colors: true,

        // level of logging
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_INFO,

        // enable / disable watching file and executing tests whenever any file changes
        autoWatch: false,

        // define browsers
        customLaunchers: customLaunchers,

        browsers: process.env.TRAVIS
            ? Object.keys(customLaunchers)
            : ['Chrome'],

        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: process.env.TRAVIS ? true : false,

        concurrency: 2,

        systemjs: {
            configFile: 'config.js',
            serveFiles: [
                'src/**/*',
                'tests/**/*',
                'jspm_packages/**/*',
                'node_modules/**/*'
            ]
        }
    });
};<commit_msg>add OSX safari<commit_after>module.exports = function (config) {
    if (process.env.TRAVIS && (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY)) {
        console.log('Make sure the SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables are set.');
        process.exit(1);
    }

    var customLaunchers = {
        sl_chrome: {
            base: 'SauceLabs',
            browserName: 'chrome',
            platform: 'Windows 7'
        },
        sl_firefox: {
            base: 'SauceLabs',
            browserName: 'firefox'
        },
        sl_safari: {
            base: 'SauceLabs',
            browserName: 'safari',
            platform: 'OS X 10.11'
        },
        sl_iphone: {
            base: 'SauceLabs',
            browserName: 'iphone',
            platform: 'OS X 10.9'
        },
        sl_ie: {
            base: 'SauceLabs',
            browserName: 'internet explorer',
            platform: 'Windows 8.1'
        },
        sl_edge: {
            base: 'SauceLabs',
            browserName: 'MicrosoftEdge',
            platform: 'Windows 10'
        }
    };

    config.set({

        // base path that will be used to resolve all patterns (eg. files, exclude)
        basePath: '',

        // frameworks to use
        // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
        frameworks: ['systemjs', 'jasmine'],

        //plugins
        plugins: process.env.TRAVIS
            ? ['karma-systemjs', 'karma-jasmine', 'karma-sauce-launcher']
            : ['karma-systemjs', 'karma-jasmine', 'karma-chrome-launcher'],

        // list of files / patterns to load in the browser
        files: [
            'tests/*-spec.js',
            'tests/*-specs.js'
        ],

        // list of files to exclude
        exclude: [],

        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors: {},

        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: process.env.TRAVIS ? ['dots', 'saucelabs'] : ['progress'],

        // web server port
        port: 9876,

        // enable / disable colors in the output (reporters and logs)
        colors: true,

        // level of logging
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_INFO,

        // enable / disable watching file and executing tests whenever any file changes
        autoWatch: false,

        // define browsers
        customLaunchers: customLaunchers,

        browsers: process.env.TRAVIS
            ? Object.keys(customLaunchers)
            : ['Chrome'],

        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: process.env.TRAVIS ? true : false,

        concurrency: 2,

        systemjs: {
            configFile: 'config.js',
            serveFiles: [
                'src/**/*',
                'tests/**/*',
                'jspm_packages/**/*',
                'node_modules/**/*'
            ]
        }
    });
};<|endoftext|>


<commit_before>'use strict';
var Search = require('node-bing-api');

module.exports = function (app, db) {
	var collection = db.collection('search_history');
	app.get('/',function(req,res){
		res.render('index.html');
	});

	app.get('/history',function(req,res){
		collection.find({}).sort({'time_search': -1}).limit(10).toArray( function (err, docs) {
            if(err) throw err;

            docs.forEach( function (element, index, array) {
               res.write( 'Date: ' + element.time_search + '\nSearch: ' + element.str_search + '\n' );
            });
			res.end();
		});
	});

	app.get('/search/:str',function(req, res) {
		var str = req.params.str;
		var offset = req.query.offset || 0;
		var search = new Search({ accKey: process.env.Bing_Search_API });

		str = str.replace(/%20/g, ' ');
		collection.insert({'str_search': req.params.str, 'time_search': new Date()});
		search.images(str, {top: 5, skip: offset*5}, function(err, respond, body){
			if(err) throw err;
			res.send(body.d.results.map(makeList));
			});
			res.end();
	});
	function makeList(img) {
	// Construct object from the json result
		return {
		  "url": img.MediaUrl,
		  "snippet": img.Title,
		  "thumbnail": img.Thumbnail.MediaUrl,
		  "context": img.SourceUrl
		};
	}

}<commit_msg>revise index.js-1<commit_after>'use strict';
var Search = require('node-bing-api');
var request = require('request');
module.exports = function (app, db) {
	var collection = db.collection('search_history');
	app.get('/',function(req,res){
		res.render('index.html');
	});

	app.get('/history',function(req,res){
		collection.find({}).sort({'time_search': -1}).limit(10).toArray( function (err, docs) {
            if(err) throw err;

            docs.forEach( function (element, index, array) {
               res.write( 'Date: ' + element.time_search + '\nSearch: ' + element.str_search + '\n' );
            });
			res.end();
		});
	});

	app.get('/search/:str',function(req, res) {
		request({
		  url: "https://immense-tundra-66578.herokuapp.com/",
		  method: "GET"
		  /*headers: {
				'Authorization': 'Client-ID ad4de0bf-47c8-4bf5-8619-66c542449c0b'
			},*/
		}, function(error, response, body) {
		if (!error && response.statusCode == 200){
		var str = req.params.str;
		var offset = req.query.offset || 0;
		var search = new Search({ accKey: process.env.Bing_Search_API });

		str = str.replace(/%20/g, ' ');
		collection.insert({'str_search': req.params.str, 'time_search': new Date()});
		search.images(str, {top: 5, skip: offset*5}, function(err, respond, body){
			if(err) throw err;
				res.send(body.d.results.map(makeList));
			});
			res.end();
		}

	});
	function makeList(img) {
	// Construct object from the json result
		return {
		  "url": img.MediaUrl,
		  "snippet": img.Title,
		  "thumbnail": img.Thumbnail.MediaUrl,
		  "context": img.SourceUrl
		};
	}

}<|endoftext|>


<commit_before>var EventEmitter = require('events').EventEmitter,
    inherits = require('util').inherits;

var StreamSearch = require('streamsearch');

var PartStream = require('./PartStream'),
    HeaderParser = require('./HeaderParser');

var B_ONEDASH = new Buffer('-'),
    B_CRLF = new Buffer('\r\n');

function Dicer(conf) {
  if (!(this instanceof Dicer))
    return new Dicer(conf);
  EventEmitter.call(this);

  if (typeof conf.boundary !== 'string')
    throw new TypeError('Boundary required');

  var self = this, isPreamble = true, inHeader = true, dashes = 0;
  this._justMatched = false;
  this._firstWrite = true;
  this._bparser = new StreamSearch('\r\n--' + conf.boundary);
  this._bparser.on('info', function redo(isMatch, data, start, end) {
    var buf;
    if (!self._part && self._justMatched && data) {
      var i = 0;
      while (dashes < 2 && (start + i) < end) {
        if (data[start + i] === 45) {
          ++i;
          ++dashes;
        } else {
          if (dashes)
            buf = B_ONEDASH;
          dashes = 0;
          break;
        }
      }
      if (dashes === 2) {
        if ((start + i) < end && self._events.trailer)
          self.emit('trailer', data.slice(start + i, end));
        self.emit('end');
        self.destroy();
      }
      if (dashes)
        return;
    }
    if (self._justMatched)
      self._justMatched = false;
    if (!self._part) {
      self._part = new PartStream();
      self.emit(isPreamble ? 'preamble' : 'part', self._part);
      if (!isPreamble)
        inHeader = true;
    }
    if (data && start < end) {
      if (isPreamble || !inHeader) {
        if (buf)
          self._part.emit('data', buf);
        self._part.emit('data', data.slice(start, end));
      } else if (!isPreamble && inHeader) {
        if (buf)
          self._hparser.push(buf);
        var r = self._hparser.push(data.slice(start, end));
        if (!inHeader && r !== undefined && r < end)
          redo(false, data, start + r, end);
      }
    }
    if (isMatch) {
      if (isPreamble)
        isPreamble = false;
      self._hparser.reset();
      self._part.emit('end');
      self._part = undefined;
      self._justMatched = true;
      dashes = 0;
    }
  });
  this._part = undefined;
  this._hparser = new HeaderParser();
  this._hparser.on('header', function(header) {
    inHeader = false;
    self._part.emit('header', header);
  });
  this.writable = true;
}
inherits(Dicer, EventEmitter);

Dicer.prototype.write = function(data, encoding) {
  if (typeof data === 'string') {
    encoding = encoding || 'utf8';
    data = new Buffer(data, encoding);
  }

  // allows for "easier" testing
  if (this._firstWrite) {
    this._bparser.push(B_CRLF);
    this._firstWrite = false;
  }

  this._bparser.push(data);

  return true;
};

Dicer.prototype.end = function(data, encoding) {
  if (data)
    this.write(data, encoding);
  this.destroy();
};

Dicer.prototype.destroy = function() {
  this.writable = false;
  this._part = undefined;
  this._bparser = undefined;
  this._hparser = undefined;
  this._justMatched = false;
  this._firstWrite = true;
  this.emit('close');
};

module.exports = Dicer;
<commit_msg>dicer: move streamsearch instance 'info' handler to prototype method, add setBoundary()<commit_after>var EventEmitter = require('events').EventEmitter,
    inherits = require('util').inherits;

var StreamSearch = require('streamsearch');

var PartStream = require('./PartStream'),
    HeaderParser = require('./HeaderParser');

var B_ONEDASH = new Buffer('-'),
    B_CRLF = new Buffer('\r\n');

function Dicer(opts) {
  if (!(this instanceof Dicer))
    return new Dicer(opts);
  EventEmitter.call(this);

  if (!opts.headerFirst && typeof opts.boundary !== 'string')
    throw new TypeError('Boundary required');

  if (typeof opts.boundary === 'string')
    this.setBoundary(opts.boundary);
  else
    this._bparser = undefined;

  this._headerFirst = opts.headerFirst;

  var self = this;

  this._dashes = 0;
  this._isPreamble = true;
  this._justMatched = false;
  this._firstWrite = true;
  this._inHeader = true;
  this._part = undefined;

  this._hparser = new HeaderParser();
  this._hparser.on('header', function(header) {
    self._inHeader = false;
    self._part.emit('header', header);
  });

  this.writable = true;
}
inherits(Dicer, EventEmitter);

Dicer.prototype.write = function(data, encoding) {
  if (typeof data === 'string') {
    encoding = encoding || 'utf8';
    data = new Buffer(data, encoding);
  }

  if (this._headerFirst && this._isPreamble) {
    if (!this._part) {
      this._part = new PartStream();
      this.emit('preamble', this._part);
    }
    var r = this._hparser.push(data);
    if (!this._inHeader && r !== undefined && r < data.length)
      data = data.slice(r);
    else
      return true;
  }

  // allows for "easier" testing
  if (this._firstWrite) {
    this._bparser.push(B_CRLF);
    this._firstWrite = false;
  }

  this._bparser.push(data);

  return true;
};

Dicer.prototype.end = function(data, encoding) {
  if (data)
    this.write(data, encoding);
  this.destroy();
};

Dicer.prototype.destroy = function() {
  this.writable = false;
  this._part = undefined;
  this._bparser = undefined;
  this._hparser = undefined;
  this.emit('close');
};

Dicer.prototype.setBoundary = function(boundary) {
  var self = this;
  this._bparser = new StreamSearch('\r\n--' + boundary);
  this._bparser.on('info', function(isMatch, data, start, end) {
    self._oninfo(isMatch, data, start, end);
  });
};

Dicer.prototype._oninfo = function(isMatch, data, start, end) {
  var buf;

  if (!this._part && this._justMatched && data) {
    var i = 0;
    while (this._dashes < 2 && (start + i) < end) {
      if (data[start + i] === 45) {
        ++i;
        ++this._dashes;
      } else {
        if (this._dashes)
          buf = B_ONEDASH;
        this._dashes = 0;
        break;
      }
    }
    if (this._dashes === 2) {
      if ((start + i) < end && this._events.trailer)
        this.emit('trailer', data.slice(start + i, end));
      this.emit('end');
      this.destroy();
    }
    if (this._dashes)
      return;
  }
  if (this._justMatched)
    this._justMatched = false;
  if (!this._part) {
    this._part = new PartStream();
    this.emit(this._isPreamble ? 'preamble' : 'part', this._part);
    if (!this._isPreamble)
      this._inHeader = true;
  }
  if (data && start < end) {
    if (this._isPreamble || !this._inHeader) {
      if (buf)
        this._part.emit('data', buf);
      this._part.emit('data', data.slice(start, end));
    } else if (!this._isPreamble && this._inHeader) {
      if (buf)
        this._hparser.push(buf);
      var r = this._hparser.push(data.slice(start, end));
      if (!this._inHeader && r !== undefined && r < end)
        this._oninfo(false, data, start + r, end);
    }
  }
  if (isMatch) {
    if (this._isPreamble)
      this._isPreamble = false;
    this._hparser.reset();
    this._part.emit('end');
    this._part = undefined;
    this._justMatched = true;
    this._dashes = 0;
  }
};

module.exports = Dicer;
<|endoftext|>


<commit_before>var simulateWorld = require("../app/simulator");
var Entity = require("../app/entity");
var assert = require("assert");

describe('simulateWorld', () => {
  it('simulates an individual', () => {
    var individual = [
      (function (entity, api) {
        api.setVelocity(entity, {x: 1, y: 0});
      })
    ];

    var entity = new Entity(individual, {x: 0, y: 0}, [], true);

    simulateWorld([entity], 10, []);

    assert.equal(entity.x, 10);
  });

  it('handles input', () => {
    var individual = [
      (function (entity, api, currentFrame) {
        if (api.checkButtonDown(entity, 'right', currentFrame)) {
          api.setVelocity(entity, {x: 1, y: 0});
        }
      })
    ];

    var entity = new Entity(individual, {x: 0, y: 0}, [], true);

    simulateWorld([entity], 10, []);

    assert.equal(entity.x, 0);

    simulateWorld([entity], 10, [{key: 'right', startFrame: 0, endFrame: 10}]);

    assert.equal(entity.x, 0);
  });
});
<commit_msg>Add failing test for simulated collisions. Fixes #13<commit_after>var simulateWorld = require("../app/simulator");
var Entity = require("../app/entity");
var assert = require("assert");

describe('simulateWorld', () => {
  it('simulates an individual', () => {
    var individual = [
      (function (entity, api) {
        api.setVelocity(entity, {x: 1, y: 0});
      })
    ];

    var entity = new Entity(individual, {x: 0, y: 0}, [], true);

    simulateWorld([entity], 10, []);

    assert.equal(entity.x, 10);
  });

  it('handles input', () => {
    var individual = [
      (function (entity, api, currentFrame) {
        if (api.checkButtonDown(entity, 'right', currentFrame)) {
          api.setVelocity(entity, {x: 1, y: 0});
        }
      })
    ];

    var entity = new Entity(individual, {x: 0, y: 0}, [], true);

    simulateWorld([entity], 10, []);

    assert.equal(entity.x, 0);

    simulateWorld([entity], 10, [{key: 'right', startFrame: 0, endFrame: 10}]);

    assert.equal(entity.x, 0);
  });

  it('simulates collision', () => {
    var hasCollided = false;

    var individual = [
      (function (entity, api, currentFrame) {
        api.setVelocity({x: 10, y: 0});
        if (api.checkCollision()) {
          hasCollided = true;
        }
      })
    ];

    var entity = new Entity(individual, {x: 0, y: 0}, [], true);
    var entityToCollideAgainst = new Entity([], {x: 80, y: 0}, [], false);

    simulateWorld([entity, entityToCollideAgainst], 10, []);

    assert(hasCollided);
  });
});
<|endoftext|>


<commit_before>var config = require('../config');
var WXBizDataCrypt = require('../vendor/WXBizDataCrypt');
var request = require('superagent');
var jwt = require('jsonwebtoken');

var User = require('../models/user');

/**
 * 用户登录
 * @param {*} code 用户登录凭证
 * @param {*} encryptedData 包括敏感数据在内的完整用户信息的加密数据
 * @param {*} iv 加密算法的初始向量
 */
exports.login = function (req, res, next) {
  var code = req.body.code;
  var encryptedData = req.body.encryptedData;
  var iv = req.body.iv;

  if (!code && !encryptedData && !iv) {
    res.status(400).json({
      code: 400,
      errMsg: '请求格式错误'
    });
  }

  // 获取sessionKey
  request
    .get(config.jscode2session)
    .query({
      appid: config.appId,
      secret: config.appSecret,
      js_code: code,
      grant_type: 'authorization_code'
    })
    .then(loginInfo => {
      var loginInfo = JSON.parse(loginInfo.text);

      // 解密用户信息
      var openid = loginInfo.openid;
      var pc = new WXBizDataCrypt(config.appId, loginInfo.session_key);
      var userInfo = pc.decryptData(encryptedData, iv);

      return Promise.resolve(JSON.parse(userInfo));
    })
    .then(userInfo => {
      // 验证用户是否存在
      User.findOne({
        openid: userInfo.openid
      }, (err, person) => {

        // 生成会话token，有效期7天
        var token = jwt.sign({
          openid: userInfo.openid,
          nickName: userInfo.nickName
        }, config.jwtSecret, {
          expiresIn: '7d'
        });

        if (err) {
          // 不存在，注册并返回绑定信息和token
          new User({
              openid: userInfo.openid,
              nickName: userInfo.nickName,
              gender: userInfo.gender,
              city: userInfo.city,
              avatarUrl: userInfo.avatarUrl,
              bind: false
            })
            .save()
            .then(() => {
              res.status(201).json({
                code: 201,
                msg: '登录成功',
                data: {
                  bind: false,
                  token: token
                }
              });
            });
        } else {
          // 已存在，返回绑定信息和token
          res.status(200).json({
            code: 200,
            msg: '登录成功',
            data: {
              bind: person.bind,
              token: token
            }
          });
        }
      });
    })
    .catch(() => {
      res.status(500).json({
        code: 500,
        errMsg: '登录出错，请联系开发人员'
      });
    });
};<commit_msg>Fix object parse, fix mongo findOne, ok!<commit_after>var config = require('../config');
var WXBizDataCrypt = require('../vendor/WXBizDataCrypt');
var request = require('superagent');
var jwt = require('jsonwebtoken');

var User = require('../models/user');

/**
 * 用户登录
 * @param {*} code 用户登录凭证
 * @param {*} encryptedData 包括敏感数据在内的完整用户信息的加密数据
 * @param {*} iv 加密算法的初始向量
 * @return {*} bind token
 */
exports.login = function(req, res, next) {
  var code = req.body.code;
  var encryptedData = req.body.encryptedData;
  var iv = req.body.iv;

  if (!code && !encryptedData && !iv) {
    res.status(400).json({
      code: 400,
      errMsg: '请求格式错误'
    });
  }

  // 获取sessionKey
  request
    .get(config.jscode2session)
    .query({
      appid: config.appId,
      secret: config.appSecret,
      js_code: code,
      grant_type: 'authorization_code'
    })
    .then(loginInfo => {
      var loginInfo = JSON.parse(loginInfo.text);

      // 解密用户信息
      var openid = loginInfo.openid;
      var pc = new WXBizDataCrypt(config.appId, loginInfo.session_key);
      var userInfo = pc.decryptData(encryptedData, iv);

      return userInfo;
    })
    .then(userInfo => {
      // 验证用户是否存在
      User.findOne(
        {
          openid: userInfo.openid
        },
        (err, person) => {
          if (err) {
            res.status(500).json({
              code: 500,
              errMsg: '登录出错，请联系开发人员'
            });
          }

          // 生成会话token，有效期7天
          var token = jwt.sign(
            {
              openid: userInfo.openid,
              nickName: userInfo.nickName
            },
            config.jwtSecret,
            {
              expiresIn: '7d'
            }
          );

          if (!person) {
            // 不存在，注册并返回绑定信息和token
            new User({
              openid: userInfo.openid,
              nickName: userInfo.nickName,
              gender: userInfo.gender,
              city: userInfo.city,
              avatarUrl: userInfo.avatarUrl,
              bind: false
            })
              .save()
              .then(() => {
                res.status(201).json({
                  code: 201,
                  msg: '登录成功',
                  data: {
                    bind: false,
                    token: token
                  }
                });
              });
          } else {
            // 已存在，返回绑定信息和token
            res.status(200).json({
              code: 200,
              msg: '登录成功',
              data: {
                bind: person.bind,
                token: token
              }
            });
          }
        }
      );
    })
    .catch(() => {
      res.status(500).json({
        code: 500,
        errMsg: '登录出错，请联系开发人员'
      });
    });
};
<|endoftext|>


<commit_before>// File: router.js
define([
    // Libraries
    'underscore',
    'backbone',
    'navigation',
    'parsley',
    // app
    'app',
    // Base views
    'views/home/HomeView',
    'views/header/HeaderView',
    'views/breadcrumb/BreadcrumbView',
    // Auth views
    'views/auth/SignUpView',
    'views/auth/SignInView',
    // Projects views
    'views/projects/ProjectsView',
    'views/projects/NewProjectView',
    'views/projects/ProjectView',
    'views/projects/ConfirmDeleteProjectView',
    'views/projects/ViewProjectView',
    // Test Suite views
    'views/testsuites/TestSuiteView'
], function(
    _,
    Backbone,
    Navigation,
    Parsley,

    app,

    HomeView,
    HeaderView,
    BreadcrumbView,

    SignUpView,
    SignInView,

    ProjectsView,
    NewProjectView,
    ProjectView,
    ConfirmDeleteProjectView,
    ViewProjectView,

    TestSuiteView) {

    'use strict';

    var navigation = new Navigation();

    /**
     * http://stackoverflow.com/questions/11671400/navigate-route-with-querystring
     */
    function parseQueryString(queryString) {
        var params = {};
        if (queryString) {
            _.each(
                _.map(decodeURI(queryString).split(/&/g), function(el, i) {
                    var aux = el.split('='),
                        o = {};
                    if (aux.length >= 1) {
                        var val = undefined;
                        if (aux.length == 2)
                            val = aux[1];
                        o[aux[0]] = val;
                    }
                    return o;
                }),
                function(o) {
                    _.extend(params, o);
                }
            );
        }
        return params;
    }

    var BaseRouter = Backbone.Router.extend({
        routes: {
            'home': 'defaultAction',
            '*actions': 'defaultAction'
        },
        navigation: {
            prefix: 'Base',
            pages: {
                'Base.defaultAction': {
                    template: 'Home'
                }
            }
        }
    });

    var AuthRouter = Backbone.Router.extend({
        routes: {
            'signup': 'signUp',
            'signin': 'signIn'
        },
        navigation: {
            prefix: 'Auth',
            pages: {
                'Auth.signUp': {
                    template: 'Sign Up',
                    parent: 'Base.defaultAction'
                },
                'Auth.signIn': {
                    template: 'Sign In',
                    parent: 'Base.defaultAction'
                }
            }
        }
    });

    var ProjectsRouter = Backbone.Router.extend({
        routes: {
            // Project routes
            'projects': 'showProjects',
            'projects?*queryString': 'showProjects',
            'projects/new': 'showAddProject',
            'projects/:projectId': 'showProject',
            'projects/:projectId/confirmDelete': 'showConfirmDeleteProject',
            'projects/:projectId/view': 'viewProject',
            // User routes
            'users': 'showContributors'
        },
        navigation: {
            prefix: 'Projects',
            pages: {
                'Projects.showProjects': {
                    template: 'Projects',
                    parent: 'Base.defaultAction'
                },
                'Projects.showProject': {
                    template: function(args) {
                        var tpl = _.template('Edit Project <%= args[":projectId"] %>');
                        return tpl({
                            args: args
                        });
                    },
                    parent: 'Projects.showProjects'
                },
                'Projects.showAddProject': {
                    template: 'Add new Project',
                    parent: 'Projects.showProjects'
                },
                'Projects.showConfirmDeleteProject': {
                    template: function(args) {
                        var tpl = _.template('Delete Project <%= args[":projectId"] %>');
                        return tpl({
                            args: args
                        });
                    },
                    parent: 'Projects.showProjects'
                },
                'Projects.viewProject': {
                    template: function(args) {
                        var tpl = _.template('View Project <%= args[":projectId"] %>');
                        return tpl({
                            args: args
                        });
                    },
                    parent: 'Projects.showProjects'
                }
            }
        }
    });

    var TestSuitesRouter = Backbone.Router.extend({
        routes: {
            'projects/:projectId/testsuites/new': 'showAddTestSuite',
            'projects/:projectId/testsuites/:testsuiteId': 'showTestSuite',
            'projects/:projectId/testsuites/showConfirmDeleteTestSuite': 'showConfirmDeleteTestSuite',
            'projects/:projectId/testsuites/:testsuiteId/view': 'viewTestSuite'
        },
        navigation: {
            prefix: 'TestSuites',
            pages: {
                'TestSuites.showAddTestSuite': {
                    template: 'Add new Test Suite',
                    parent: 'Projects.viewProject'
                }
            }
        }
    });

    var initialize = function() {

        // --- common views ---
        if (!app.headerView) {
            app.headerView = new HeaderView();
            app.headerView.render();
        }

        if (!app.breadcrumbView) {
            app.breadcrumbView = new BreadcrumbView({
                navigation: navigation
            });
            // render happens after breadcrumbView has calculated its breadcrumbs, within itself it calls render()
        }
        // --- end common views ---

        // --- base router ---
        var baseRouter = new BaseRouter();

        baseRouter.on('route:defaultAction', function(actions) {
            // We have no matching route, lets display the home page
            if (!app.homeView) {
                app.homeView = new HomeView();
            }
            app.showView(app.homeView);
        });
        // --- end base router

        // --- auth router ---
        var authRouter = new AuthRouter();

        authRouter.on('route:signUp', function() {
            if (!app.signUpView) {
                app.signUpView = new SignUpView();
            }
            app.showView(app.signUpView);
        });

        authRouter.on('route:signIn', function() {
            if (!app.signInView) {
                app.signInView = new SignInView();
            }
            app.showView(app.signInView);
        });
        // --- end auth router ---

        // --- projects router ---
        var projectsRouter = new ProjectsRouter();

        projectsRouter.on('route:showProjects', function(queryString) {
            var params = parseQueryString(queryString);
            var page = 1;
            if (typeof(params.page) != "undefined") {
                page = params.page;
            }
            if (!app.projectsView) {
                app.projectsView = new ProjectsView();
            }
            app.projectsView.setPage(page);
            app.showView(app.projectsView, {
                requiresAuth: true
            });
        });

        projectsRouter.on('route:showAddProject', function() {
            if (!app.newProjectView) {
                app.newProjectView = new NewProjectView();
            }
            app.showView(app.newProjectView, {
                requiresAuth: true
            });
        });

        projectsRouter.on('route:showProject', function(id) {
            if (!app.projectView) {
                app.projectView = new ProjectView();
            }
            app.projectView.model.id = id;
            app.showView(app.projectView, {
                requiresAuth: true
            });
        });

        projectsRouter.on('route:showConfirmDeleteProject', function(id) {
            if (!app.confirmDeleteProjectView) {
                app.confirmDeleteProjectView = new ConfirmDeleteProjectView();
            }
            app.confirmDeleteProjectView.model.id = id;
            app.showView(app.confirmDeleteProjectView, {
                requiresAuth: true
            });
        });

        projectsRouter.on('route:viewProject', function(id) {
            if (!app.viewProjectView) {
                app.viewProjectView = new ViewProjectView({
                    projectId: id
                });
            }
            if (typeof app.currentView !== 'undefined' && app.currentView.cid == app.viewProjectView.cid) {
                app.viewProjectView.displayProject(id);
            } else {
                app.showView(app.viewProjectView, {
                    requiresAuth: true,
                    // TBD: using a closure here with a variable in a different scope doesn't look very elegant
                    onSuccess: function() { app.viewProjectView.displayProject(id) }
                });
            }

            app.viewProjectView.displayProject(id);
        });

        projectsRouter.on('route:showContributors', function() {
            // Like above, call render but know that this view has nested sub views which
            // handle loading and displaying data from the GitHub API
            var contributorsView = new ContributorsView();
        });
        // --- end projects router ---

        // --- test suites router ---
        var testSuitesRouter = new TestSuitesRouter();

        testSuitesRouter.on('route:showAddTestSuite', function(projectId) {
            if (!app.viewProjectView) {
                app.viewProjectView = new ViewProjectView({
                    projectId: projectId
                });
            }
            if (typeof app.currentView !== 'undefined' && app.currentView.cid == app.viewProjectView.cid) {
                app.viewProjectView.displayNewTestSuite();
            } else {
                app.showView(app.viewProjectView, {
                    requiresAuth: true,
                    onSuccess: app.viewProjectView.displayNewTestSuite
                });
            }
        });

        testSuitesRouter.on('route:showTestSuite', function(projectId, testSuiteId) {
            if (!app.testSuiteView) {
                app.testSuiteView = new TestSuiteView();
            }
            app.testSuiteView.projectId = projectId;
            app.testSuiteView.testSuiteId = testSuiteId;
            app.showView(app.testSuiteView, {
                requiresAuth: true
            });
        });

        testSuitesRouter.on('route:showConfirmDeleteTestSuite', function(id) {
            var projectView = new ViewProjectView({
                id: projectId
            });
            projectView.render();
            var confirmDeleteTestSuiteView = new ConfirmDeleteTestSuiteView({
                id: id
            });
            confirmDeleteTestSuiteView.render();
        });

        testSuitesRouter.on('route:viewTestSuite', function(projectId, testSuiteId) {
            if (!app.viewProjectView) {
                app.viewProjectView = new ViewProjectView({
                    projectId: projectId
                });
            }

            app.viewProjectView.projectId = projectId;
            app.viewProjectView.testSuiteId = testSuiteId;
            if (typeof app.currentView !== 'undefined' && app.currentView.cid == app.viewProjectView.cid) {
                app.viewProjectView.displayTestSuite();
            } else {
                app.showView(app.viewProjectView, {
                    requiresAuth: true,
                    onSuccess: app.viewProjectView.displayTestSuite
                });
            }
        });

        // --- end test suites router ---

        navigation.appendRouter(baseRouter);
        navigation.appendRouter(authRouter);
        navigation.appendRouter(projectsRouter);
        navigation.appendRouter(testSuitesRouter);
        navigation.mapRouters();

        Backbone.history.start();
    };

    var AppRouter = {
        // router initialization function
        initialize: initialize,
        // for breadcrumbs
        navigation: navigation,
        // routes
        BaseRouter: BaseRouter,
        AuthRouter: AuthRouter,
        ProjectsRouter: ProjectsRouter,
        TestSuitesRouter: TestSuitesRouter
    };

    return AppRouter;
});<commit_msg>Add view test suite bread crumb<commit_after>// File: router.js
define([
    // Libraries
    'underscore',
    'backbone',
    'navigation',
    'parsley',
    // app
    'app',
    // Base views
    'views/home/HomeView',
    'views/header/HeaderView',
    'views/breadcrumb/BreadcrumbView',
    // Auth views
    'views/auth/SignUpView',
    'views/auth/SignInView',
    // Projects views
    'views/projects/ProjectsView',
    'views/projects/NewProjectView',
    'views/projects/ProjectView',
    'views/projects/ConfirmDeleteProjectView',
    'views/projects/ViewProjectView',
    // Test Suite views
    'views/testsuites/TestSuiteView'
], function(
    _,
    Backbone,
    Navigation,
    Parsley,

    app,

    HomeView,
    HeaderView,
    BreadcrumbView,

    SignUpView,
    SignInView,

    ProjectsView,
    NewProjectView,
    ProjectView,
    ConfirmDeleteProjectView,
    ViewProjectView,

    TestSuiteView) {

    'use strict';

    var navigation = new Navigation();

    /**
     * http://stackoverflow.com/questions/11671400/navigate-route-with-querystring
     */
    function parseQueryString(queryString) {
        var params = {};
        if (queryString) {
            _.each(
                _.map(decodeURI(queryString).split(/&/g), function(el, i) {
                    var aux = el.split('='),
                        o = {};
                    if (aux.length >= 1) {
                        var val = undefined;
                        if (aux.length == 2)
                            val = aux[1];
                        o[aux[0]] = val;
                    }
                    return o;
                }),
                function(o) {
                    _.extend(params, o);
                }
            );
        }
        return params;
    }

    var BaseRouter = Backbone.Router.extend({
        routes: {
            'home': 'defaultAction',
            '*actions': 'defaultAction'
        },
        navigation: {
            prefix: 'Base',
            pages: {
                'Base.defaultAction': {
                    template: 'Home'
                }
            }
        }
    });

    var AuthRouter = Backbone.Router.extend({
        routes: {
            'signup': 'signUp',
            'signin': 'signIn'
        },
        navigation: {
            prefix: 'Auth',
            pages: {
                'Auth.signUp': {
                    template: 'Sign Up',
                    parent: 'Base.defaultAction'
                },
                'Auth.signIn': {
                    template: 'Sign In',
                    parent: 'Base.defaultAction'
                }
            }
        }
    });

    var ProjectsRouter = Backbone.Router.extend({
        routes: {
            // Project routes
            'projects': 'showProjects',
            'projects?*queryString': 'showProjects',
            'projects/new': 'showAddProject',
            'projects/:projectId': 'showProject',
            'projects/:projectId/confirmDelete': 'showConfirmDeleteProject',
            'projects/:projectId/view': 'viewProject',
            // User routes
            'users': 'showContributors'
        },
        navigation: {
            prefix: 'Projects',
            pages: {
                'Projects.showProjects': {
                    template: 'Projects',
                    parent: 'Base.defaultAction'
                },
                'Projects.showProject': {
                    template: function(args) {
                        var tpl = _.template('Edit Project <%= args[":projectId"] %>');
                        return tpl({
                            args: args
                        });
                    },
                    parent: 'Projects.showProjects'
                },
                'Projects.showAddProject': {
                    template: 'Add new Project',
                    parent: 'Projects.showProjects'
                },
                'Projects.showConfirmDeleteProject': {
                    template: function(args) {
                        var tpl = _.template('Delete Project <%= args[":projectId"] %>');
                        return tpl({
                            args: args
                        });
                    },
                    parent: 'Projects.showProjects'
                },
                'Projects.viewProject': {
                    template: function(args) {
                        var tpl = _.template('View Project <%= args[":projectId"] %>');
                        return tpl({
                            args: args
                        });
                    },
                    parent: 'Projects.showProjects'
                }
            }
        }
    });

    var TestSuitesRouter = Backbone.Router.extend({
        routes: {
            'projects/:projectId/testsuites/new': 'showAddTestSuite',
            'projects/:projectId/testsuites/:testsuiteId/view': 'viewTestSuite',
            'projects/:projectId/testsuites/:testsuiteId': 'showTestSuite',
            'projects/:projectId/testsuites/showConfirmDeleteTestSuite': 'showConfirmDeleteTestSuite'
        },
        navigation: {
            prefix: 'TestSuites',
            pages: {
                'TestSuites.showAddTestSuite': {
                    template: 'Add new Test Suite',
                    parent: 'Projects.viewProject'
                },
                'TestSuites.viewTestSuite': {
                    template: function(args) {
                        var tpl = _.template('View Test Suite <%= args[":testsuiteId"] %>');
                        return tpl({
                            args: args
                        });
                    },
                    parent: 'Projects.viewProject'
                }
            }
        }
    });

    var initialize = function() {

        // --- common views ---
        if (!app.headerView) {
            app.headerView = new HeaderView();
            app.headerView.render();
        }

        if (!app.breadcrumbView) {
            app.breadcrumbView = new BreadcrumbView({
                navigation: navigation
            });
            // render happens after breadcrumbView has calculated its breadcrumbs, within itself it calls render()
        }
        // --- end common views ---

        // --- base router ---
        var baseRouter = new BaseRouter();

        baseRouter.on('route:defaultAction', function(actions) {
            // We have no matching route, lets display the home page
            if (!app.homeView) {
                app.homeView = new HomeView();
            }
            app.showView(app.homeView);
        });
        // --- end base router

        // --- auth router ---
        var authRouter = new AuthRouter();

        authRouter.on('route:signUp', function() {
            if (!app.signUpView) {
                app.signUpView = new SignUpView();
            }
            app.showView(app.signUpView);
        });

        authRouter.on('route:signIn', function() {
            if (!app.signInView) {
                app.signInView = new SignInView();
            }
            app.showView(app.signInView);
        });
        // --- end auth router ---

        // --- projects router ---
        var projectsRouter = new ProjectsRouter();

        projectsRouter.on('route:showProjects', function(queryString) {
            var params = parseQueryString(queryString);
            var page = 1;
            if (typeof(params.page) != "undefined") {
                page = params.page;
            }
            if (!app.projectsView) {
                app.projectsView = new ProjectsView();
            }
            app.projectsView.setPage(page);
            app.showView(app.projectsView, {
                requiresAuth: true
            });
        });

        projectsRouter.on('route:showAddProject', function() {
            if (!app.newProjectView) {
                app.newProjectView = new NewProjectView();
            }
            app.showView(app.newProjectView, {
                requiresAuth: true
            });
        });

        projectsRouter.on('route:showProject', function(id) {
            if (!app.projectView) {
                app.projectView = new ProjectView();
            }
            app.projectView.model.id = id;
            app.showView(app.projectView, {
                requiresAuth: true
            });
        });

        projectsRouter.on('route:showConfirmDeleteProject', function(id) {
            if (!app.confirmDeleteProjectView) {
                app.confirmDeleteProjectView = new ConfirmDeleteProjectView();
            }
            app.confirmDeleteProjectView.model.id = id;
            app.showView(app.confirmDeleteProjectView, {
                requiresAuth: true
            });
        });

        projectsRouter.on('route:viewProject', function(id) {
            if (!app.viewProjectView) {
                app.viewProjectView = new ViewProjectView({
                    projectId: id
                });
            }
            if (typeof app.currentView !== 'undefined' && app.currentView.cid == app.viewProjectView.cid) {
                app.viewProjectView.displayProject(id);
            } else {
                app.showView(app.viewProjectView, {
                    requiresAuth: true,
                    // TBD: using a closure here with a variable in a different scope doesn't look very elegant
                    onSuccess: function() { app.viewProjectView.displayProject(id) }
                });
            }

            app.viewProjectView.displayProject(id);
        });

        projectsRouter.on('route:showContributors', function() {
            // Like above, call render but know that this view has nested sub views which
            // handle loading and displaying data from the GitHub API
            var contributorsView = new ContributorsView();
        });
        // --- end projects router ---

        // --- test suites router ---
        var testSuitesRouter = new TestSuitesRouter();

        testSuitesRouter.on('route:showAddTestSuite', function(projectId) {
            if (!app.viewProjectView) {
                app.viewProjectView = new ViewProjectView({
                    projectId: projectId
                });
            }
            if (typeof app.currentView !== 'undefined' && app.currentView.cid == app.viewProjectView.cid) {
                app.viewProjectView.displayNewTestSuite();
            } else {
                app.showView(app.viewProjectView, {
                    requiresAuth: true,
                    onSuccess: app.viewProjectView.displayNewTestSuite
                });
            }
        });

        testSuitesRouter.on('route:showTestSuite', function(projectId, testSuiteId) {
            if (!app.testSuiteView) {
                app.testSuiteView = new TestSuiteView();
            }
            app.testSuiteView.projectId = projectId;
            app.testSuiteView.testSuiteId = testSuiteId;
            app.showView(app.testSuiteView, {
                requiresAuth: true
            });
        });

        testSuitesRouter.on('route:showConfirmDeleteTestSuite', function(id) {
            var projectView = new ViewProjectView({
                id: projectId
            });
            projectView.render();
            var confirmDeleteTestSuiteView = new ConfirmDeleteTestSuiteView({
                id: id
            });
            confirmDeleteTestSuiteView.render();
        });

        testSuitesRouter.on('route:viewTestSuite', function(projectId, testSuiteId) {
            if (!app.viewProjectView) {
                app.viewProjectView = new ViewProjectView({
                    projectId: projectId
                });
            }

            app.viewProjectView.projectId = projectId;
            app.viewProjectView.testSuiteId = testSuiteId;
            if (typeof app.currentView !== 'undefined' && app.currentView.cid == app.viewProjectView.cid) {
                app.viewProjectView.displayTestSuite();
            } else {
                app.showView(app.viewProjectView, {
                    requiresAuth: true,
                    onSuccess: app.viewProjectView.displayTestSuite
                });
            }
        });

        // --- end test suites router ---

        navigation.appendRouter(baseRouter);
        navigation.appendRouter(authRouter);
        navigation.appendRouter(projectsRouter);
        navigation.appendRouter(testSuitesRouter);
        navigation.mapRouters();

        Backbone.history.start();
    };

    var AppRouter = {
        // router initialization function
        initialize: initialize,
        // for breadcrumbs
        navigation: navigation,
        // routes
        BaseRouter: BaseRouter,
        AuthRouter: AuthRouter,
        ProjectsRouter: ProjectsRouter,
        TestSuitesRouter: TestSuitesRouter
    };

    return AppRouter;
});<|endoftext|>


<commit_before>module.exports = function (config) {

  var customLaunchers = {

    // BrowserStack
    'BS_Chrome': {
      base: 'BrowserStack',
      browser: 'chrome',
      os: 'OS X',
      os_version: 'Yosemite'
    },
    'BS_Safari': {
      base: 'BrowserStack',
      browser: 'safari',
      os: 'OS X',
      os_version: 'Yosemite'
    },
    'BS_Firefox': {
      base: 'BrowserStack',
      browser: 'firefox',
      os: 'Windows',
      os_version: '8'
    },
    'BS_IE_9': {
      base: 'BrowserStack',
      browser: 'ie',
      browser_version: '9.0',
      os: 'Windows',
      os_version: '7'
    },
    'BS_IE_10': {
      base: 'BrowserStack',
      browser: 'ie',
      browser_version: '10.0',
      os: 'Windows',
      os_version: '8'
    },
    'BS_IE_11': {
      base: 'BrowserStack',
      browser: 'ie',
      browser_version: '11.0',
      os: 'Windows',
      os_version: '8.1'
    }
  };

  config.set({

    browserStack: {
      username: process.env.BROWSER_STACK_USERNAME,
      accessKey: process.env.BROWSER_STACK_ACCESS_KEY
    },

    frameworks: ['jasmine'],

    files: [
      'src/carpet.js',
      'tests/spec/carpet.test.js'
    ],

    reporters: ['dots'],
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    singleRun: true,

    customLaunchers: customLaunchers,
    browsers: Object.keys(customLaunchers)
  });
};<commit_msg>modify: karma to test components too<commit_after>module.exports = function (config) {

  var customLaunchers = {

    // BrowserStack
    'BS_Chrome': {
      base: 'BrowserStack',
      browser: 'chrome',
      os: 'OS X',
      os_version: 'Yosemite'
    },
    'BS_Safari': {
      base: 'BrowserStack',
      browser: 'safari',
      os: 'OS X',
      os_version: 'Yosemite'
    },
    'BS_Firefox': {
      base: 'BrowserStack',
      browser: 'firefox',
      os: 'Windows',
      os_version: '8'
    },
    'BS_IE_9': {
      base: 'BrowserStack',
      browser: 'ie',
      browser_version: '9.0',
      os: 'Windows',
      os_version: '7'
    },
    'BS_IE_10': {
      base: 'BrowserStack',
      browser: 'ie',
      browser_version: '10.0',
      os: 'Windows',
      os_version: '8'
    },
    'BS_IE_11': {
      base: 'BrowserStack',
      browser: 'ie',
      browser_version: '11.0',
      os: 'Windows',
      os_version: '8.1'
    }
  };

  config.set({

    browserStack: {
      username: process.env.BROWSER_STACK_USERNAME,
      accessKey: process.env.BROWSER_STACK_ACCESS_KEY
    },

    frameworks: ['jasmine'],

    files: [
      'src/**/*.js',
      'tests/spec/**/*.js'
    ],

    reporters: ['dots'],
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    singleRun: true,

    customLaunchers: customLaunchers,
    browsers: Object.keys(customLaunchers)
  });
};<|endoftext|>


<commit_before>'use strict';

var path = process.cwd();
var User = require('../models/users'),
	Pic = require('../models/pics'),
	mongoose = require('mongoose');

var bodyParser = require('body-parser');

var urlencodedParser = bodyParser.urlencoded({ extended: false });

module.exports = function (app, passport) {

	function isLoggedIn (req, res, next) {
		if (req.isAuthenticated()) {
			next();
		} else {
			res.redirect('/auth/twitter/callback');
		}
	}

	app.route('/')
		.get(function (req, res) {
			if (req.isAuthenticated()) {
				res.render(path + '/app/views/all.handlebars', {loggedin: true});
			} else {
				res.render(path + '/app/views/all.handlebars', {loggedin: false});
			}
		});

	app.route('/user/:id')
		.get(function(req, res) {
			if (req.isAuthenticated()) {
				res.render(path + '/app/views/userpics.handlebars', {loggedin: true, id: req.params.id});
			} else {
				res.render(path + '/app/views/userpics.handlebars', {loggedin: false, id: req.params.id});
			}
		});
	app.route('/userpics/:id')
		.get(function(req, res) {
			Pic.find({_creator: req.params.id}, function(err, pics) {
				res.json(pics);
			})
		})

	app.route('/remove/:id')
		.get(function(req, res) {
			Pic.findOneAndRemove(req.params.id)
			.then(function() {
				console.log('pic removed!')
				console.log(req.params.id)
				res.redirect('/my_pics');
			})
		})

	app.route('/all_pics')
		.get(function(req, res, next){
			Pic.find({}).then(function(pics) {
				res.json(pics);
			})
		})

	app.route('/get_my_pics')
		.get(isLoggedIn, function(req, res, next) {
			res.json(req.user);
			// User.find({id: req.user._id}, function(err, user) {
			// 	if (err) throw err;
			// 	Pic.find({_creator: user}, function(err, pics) {
			// 		if (err) throw err;
			// 		res.json(pics);
			// 	})
			// })
		})

	app.route('/my_pics')
		.get(isLoggedIn, function(req, res, next) {
			res.render(path + '/app/views/mypics.handlebars', {loggedin: true});
		});

	app.route('/submit_pic')
		.post(isLoggedIn, urlencodedParser, function(req, res, next) {
			User.findOne({_id: req.user._id}, function(err, user) {
				if (err) throw err;

				var newPic = new Pic({
										  url: req.body.url,
										  description: req.body.description,
										  _creator: user._id,
										  creator_username: user.twitter.username,
									  });
				newPic.save();
			});
			res.redirect('/')
		});

	app.route('/logout')
		.get(function (req, res) {
			req.logout();
			res.redirect('/');
		});

	app.route('/profile')
		.get(isLoggedIn, function (req, res) {
			res.sendFile(path + '/public/profile.html');
		});

	app.route('/api/:id')
		.get(isLoggedIn, function (req, res) {
			res.json(req.user.github);
		});

	app.route('/auth/twitter/callback')
		.get(passport.authenticate('twitter', {
			successRedirect: '/',
			failureRedirect: '/',
		}));

};<commit_msg>some2<commit_after>'use strict';

var path = process.cwd();
var User = require('../models/users'),
	Pic = require('../models/pics'),
	mongoose = require('mongoose');

var bodyParser = require('body-parser');

var urlencodedParser = bodyParser.urlencoded({ extended: false });

module.exports = function (app, passport) {

	function isLoggedIn (req, res, next) {
		if (req.isAuthenticated()) {
			next();
		} else {
			res.redirect('/auth/twitter/callback');
		}
	}

	app.route('/')
		.get(function (req, res) {
			if (req.isAuthenticated()) {
				res.render(path + '/app/views/all.handlebars', {loggedin: true});
			} else {
				res.render(path + '/app/views/all.handlebars', {loggedin: false});
			}
		});

	app.route('/user/:id')
		.get(function(req, res) {
			if (req.isAuthenticated()) {
				res.render(path + '/app/views/userpics.handlebars', {loggedin: true, id: req.params.id});
			} else {
				res.render(path + '/app/views/userpics.handlebars', {loggedin: false, id: req.params.id});
			}
		});
	app.route('/userpics/:id')
		.get(function(req, res) {
			Pic.find({_creator: req.params.id}, function(err, pics) {
				res.json(pics);
			})
		})

	app.route('/remove/:id')
		.get(function(req, res) {
			Pic.findOneAndRemove(req.params.id)
			.then(function() {
				console.log('pic removed!')
				console.log(req.params.id)
				res.redirect('/my_pics');
			})
		})

	app.route('/all_pics')
		.get(function(req, res, next){
			Pic.find({}).then(function(pics) {
				res.json(pics);
			})
		})

	app.route('/get_my_pics')
		.get(isLoggedIn, function(req, res, next) {
			// res.json(req.user);
			User.find({id: req.user._id}, function(err, user) {
				if (err) throw err;
				Pic.find({_creator: user}, function(err, pics) {
					if (err) throw err;
					res.json(pics);
				})
			})
		})

	app.route('/my_pics')
		.get(isLoggedIn, function(req, res, next) {
			res.render(path + '/app/views/mypics.handlebars', {loggedin: true});
		});

	app.route('/submit_pic')
		.post(isLoggedIn, urlencodedParser, function(req, res, next) {
			User.findOne({_id: req.user._id}, function(err, user) {
				if (err) throw err;

				var newPic = new Pic({
										  url: req.body.url,
										  description: req.body.description,
										  _creator: user._id,
										  creator_username: user.twitter.username,
									  });
				newPic.save();
			});
			res.redirect('/')
		});

	app.route('/logout')
		.get(function (req, res) {
			req.logout();
			res.redirect('/');
		});

	app.route('/profile')
		.get(isLoggedIn, function (req, res) {
			res.sendFile(path + '/public/profile.html');
		});

	app.route('/api/:id')
		.get(isLoggedIn, function (req, res) {
			res.json(req.user.github);
		});

	app.route('/auth/twitter/callback')
		.get(passport.authenticate('twitter', {
			successRedirect: '/',
			failureRedirect: '/',
		}));

};<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var glob = require('glob');
var path = require('path');
var test = require('tape');

var paradise = require('../index');

var specDir = path.join(__dirname, 'spec');

var skipped = [];

var files = glob.sync('*/*.paradise', {
    cwd: specDir
});

files.sort();

files.forEach(function (file) {
    var target = path.join(specDir, file);

    if (!fs.statSync(target).isFile()) {
        return;
    }

    test(path.dirname(file), function (t) {
        t.plan(1);

        var skip = fs.existsSync(path.join(path.dirname(target), 'skip'));

        if (skip) {
            t.skip('skipped');
        } else {
            var source = fs.readFileSync(target, 'utf8');
            var expected = fs.readFileSync(path.join(path.dirname(target), 'expect.js'), 'utf8').trim();
            var actual = paradise(source).trim();

            fs.writeFileSync(path.join(path.dirname(target), 'actual.js'), actual, 'utf8');

            t.equal(actual, expected);
        }
    });
});<commit_msg>Add switch for debug mode<commit_after>'use strict';

var fs = require('fs');
var glob = require('glob');
var path = require('path');
var test = require('tape');

var paradise = require('../index');

var debug = false;

var specDir = path.join(__dirname, 'spec');

var skipped = [];

var files = glob.sync('*/*.paradise', {
    cwd: specDir
});

files.sort();

files.forEach(function (file) {
    var target = path.join(specDir, file);

    if (!fs.statSync(target).isFile()) {
        return;
    }

    test(path.dirname(file), function (t) {
        t.plan(1);

        var skip = fs.existsSync(path.join(path.dirname(target), 'skip'));

        if (skip) {
            t.skip('skipped');
        } else {
            var source = fs.readFileSync(target, 'utf8');
            var expected = fs.readFileSync(path.join(path.dirname(target), 'expect.js'), 'utf8').trim();
            var actual = paradise(source).trim();

            if (debug) {
                fs.writeFileSync(path.join(path.dirname(target), 'actual.js'), actual, 'utf8');
            }

            t.equal(actual, expected);
        }
    });
});<|endoftext|>


<commit_before>#!/usr/bin/env node

/**
 * Builds app binaries for OS X, Linux, and Windows.
 */

var config = require('../config')
var cp = require('child_process')
var electronPackager = require('electron-packager')
var fs = require('fs')
var path = require('path')
var pkg = require('../package.json')

var all = {
  // Build 64 bit binaries only.
  arch: 'x64',

  // The application source directory.
  dir: path.join(__dirname, '..'),

  // The release version of the application. Maps to the `ProductVersion` metadata
  // property on Windows, and `CFBundleShortVersionString` on OS X.
  'app-version': pkg.version,

  // Package the application's source code into an archive, using Electron's archive
  // format. Mitigates issues around long path names on Windows and slightly speeds up
  // require().
  asar: true,

  // The build version of the application. Maps to the FileVersion metadata property on
  // Windows, and CFBundleVersion on OS X. We're using the short git hash (e.g. 'e7d837e')
  // Windows requires the build version to start with a number :/ so we stick on a prefix
  'build-version': '0-' + cp.execSync('git rev-parse --short HEAD').toString().replace('\n', ''),

  // Pattern which specifies which files to ignore when copying files to create the
  // package(s).
  ignore: /^\/dist|\/(appveyor.yml|AUTHORS|CONTRIBUTORS|bench|benchmark|benchmark\.js|bin|bower\.json|component\.json|coverage|doc|docs|docs\.mli|dragdrop\.min\.js|example|examples|example\.html|example\.js|externs|ipaddr\.min\.js|Makefile|min|minimist|perf|rusha|simplepeer\.min\.js|simplewebsocket\.min\.js|static\/screenshot\.png|test|tests|test\.js|tests\.js|webtorrent\.min\.js|\.[^\/]*|.*\.md|.*\.markdown)$/,

  // The application name.
  name: config.APP_NAME,

  // The base directory where the finished package(s) are created.
  out: path.join(__dirname, '..', 'dist'),

  // Replace an already existing output directory.
  overwrite: true,

  // Runs `npm prune --production` which remove the packages specified in
  // "devDependencies" before starting to package the app.
  prune: true,

  // The Electron version with which the app is built (without the leading 'v')
  version: pkg.devDependencies['electron-prebuilt']
}

var darwin = {
  platform: 'darwin',

  // The bundle identifier to use in the application's plist (OS X only).
  'app-bundle-id': 'io.webtorrent.app',

  // The application category type, as shown in the Finder via "View" -> "Arrange by
  // Application Category" when viewing the Applications directory (OS X only).
  'app-category-type': 'public.app-category.utilities',

  // The bundle identifier to use in the application helper's plist (OS X only).
  'helper-bundle-id': 'io.webtorrent.app.helper',

  // Application icon.
  icon: path.join(__dirname, '..', 'static', 'WebTorrent.icns')
}

var win32 = {
  platform: 'win32',

  // Object hash of application metadata to embed into the executable (Windows only)
  'version-string': {

    // Company that produced the file.
    CompanyName: config.APP_NAME,

    // Copyright notices that apply to the file. This should include the full text of all
    // notices, legal symbols, copyright dates, and so on.
    LegalCopyright: fs.readFileSync(path.join(__dirname, '..', 'LICENSE'), 'utf8'),

    // Name of the program, displayed to users
    FileDescription: config.APP_NAME,

    // Original name of the file, not including a path. This information enables an
    // application to determine whether a file has been renamed by a user. The format of
    // the name depends on the file system for which the file was created.
    OriginalFilename: 'WebTorrent.exe',

    // Name of the product with which the file is distributed.
    ProductName: config.APP_NAME,

    // Internal name of the file, if one exists, for example, a module name if the file
    // is a dynamic-link library. If the file has no internal name, this string should be
    // the original filename, without extension. This string is required.
    InternalName: config.APP_NAME
  },

  // Application icon.
  icon: path.join(__dirname, '..', 'static', 'WebTorrent.ico')
}

var linux = {
  platform: 'linux'

  // Note: Application icon for Linux is specified via the BrowserWindow `icon` option.
}

var platform = process.argv[2]

if (platform === '--darwin') {
  buildDarwin(postDarwinism)
} else if (platform === '--win32') {
  buildWin32()
} else if (platform === '--linux') {
  buildLinux()
} else {
  // Build all
  buildDarwin(() => buildWin32(() => buildLinux()))
}

function buildDarwin (cb) {
  electronPackager(Object.assign({}, all, darwin), done.bind(null, cb))
}

function buildWin32 (cb) {
  electronPackager(Object.assign({}, all, win32), done.bind(null, cb))
}

function buildLinux (cb) {
  electronPackager(Object.assign({}, all, linux), done.bind(null, cb))
}

function postDarwinism () {
  var plist = require('plist')
  var contentsPath = path.join.apply(null, [
    __dirname,
    '..',
    'dist',
    `${config.APP_NAME}-darwin-x64`,
    `${config.APP_NAME}.app`,
    'Contents'
  ])
  var resourcesPath = path.join(contentsPath, 'Resources')
  var infoPlistPath = path.join(contentsPath, 'Info.plist')
  var webTorrentFileIconPath = path.join.apply(null, [
    __dirname,
    '..',
    'static',
    'WebTorrentFile.icns'
  ])
  var infoPlist = plist.parse(fs.readFileSync(infoPlistPath, 'utf8'))

  infoPlist.CFBundleDocumentTypes = [
    {
      CFBundleTypeExtensions: [ 'torrent' ],
      CFBundleTypeIconFile: 'WebTorrentFile.icns',
      CFBundleTypeName: 'BitTorrent Document',
      CFBundleTypeRole: 'Editor',
      LSHandlerRank: 'Owner',
      LSItemContentTypes: [ 'org.bittorrent.torrent' ]
    },
    {
      CFBundleTypeName: 'Any',
      CFBundleTypeOSTypes: [ '****' ],
      CFBundleTypeRole: 'Editor',
      LSTypeIsPackage: false,
      LSHandlerRank: 'Owner'
    }
  ]

  infoPlist.NSHumanReadableCopyright = 'Copyright © 2014-2016 The WebTorrent Project'

  fs.writeFileSync(infoPlistPath, plist.build(infoPlist))
  cp.execSync(`cp ${webTorrentFileIconPath} ${resourcesPath}`)
}

function done (cb, err, appPath) {
  if (err) console.error(err.message || err)
  else console.log('Built ' + appPath)
  if (cb) cb()
}
<commit_msg>Cleanup build script; Run plist update function for all builds<commit_after>#!/usr/bin/env node

/**
 * Builds app binaries for OS X, Linux, and Windows.
 */

var config = require('../config')
var cp = require('child_process')
var electronPackager = require('electron-packager')
var fs = require('fs')
var path = require('path')
var pkg = require('../package.json')
var plist = require('plist')

function build () {
  var platform = process.argv[2]
  if (platform === '--darwin') {
    buildDarwin()
  } else if (platform === '--win32') {
    buildWin32()
  } else if (platform === '--linux') {
    buildLinux()
  } else {
    buildDarwin(() => buildWin32(() => buildLinux())) // Build all
  }
}

var all = {
  // Build 64 bit binaries only.
  arch: 'x64',

  // The application source directory.
  dir: path.join(__dirname, '..'),

  // The release version of the application. Maps to the `ProductVersion` metadata
  // property on Windows, and `CFBundleShortVersionString` on OS X.
  'app-version': pkg.version,

  // Package the application's source code into an archive, using Electron's archive
  // format. Mitigates issues around long path names on Windows and slightly speeds up
  // require().
  asar: true,

  // The build version of the application. Maps to the FileVersion metadata property on
  // Windows, and CFBundleVersion on OS X. We're using the short git hash (e.g. 'e7d837e')
  // Windows requires the build version to start with a number :/ so we stick on a prefix
  'build-version': '0-' + cp.execSync('git rev-parse --short HEAD').toString().replace('\n', ''),

  // Pattern which specifies which files to ignore when copying files to create the
  // package(s).
  ignore: /^\/dist|\/(appveyor.yml|AUTHORS|CONTRIBUTORS|bench|benchmark|benchmark\.js|bin|bower\.json|component\.json|coverage|doc|docs|docs\.mli|dragdrop\.min\.js|example|examples|example\.html|example\.js|externs|ipaddr\.min\.js|Makefile|min|minimist|perf|rusha|simplepeer\.min\.js|simplewebsocket\.min\.js|static\/screenshot\.png|test|tests|test\.js|tests\.js|webtorrent\.min\.js|\.[^\/]*|.*\.md|.*\.markdown)$/,

  // The application name.
  name: config.APP_NAME,

  // The base directory where the finished package(s) are created.
  out: path.join(__dirname, '..', 'dist'),

  // Replace an already existing output directory.
  overwrite: true,

  // Runs `npm prune --production` which remove the packages specified in
  // "devDependencies" before starting to package the app.
  prune: true,

  // The Electron version with which the app is built (without the leading 'v')
  version: pkg.devDependencies['electron-prebuilt']
}

var darwin = {
  platform: 'darwin',

  // The bundle identifier to use in the application's plist (OS X only).
  'app-bundle-id': 'io.webtorrent.app',

  // The application category type, as shown in the Finder via "View" -> "Arrange by
  // Application Category" when viewing the Applications directory (OS X only).
  'app-category-type': 'public.app-category.utilities',

  // The bundle identifier to use in the application helper's plist (OS X only).
  'helper-bundle-id': 'io.webtorrent.app.helper',

  // Application icon.
  icon: path.join(__dirname, '..', 'static', 'WebTorrent.icns')
}

var win32 = {
  platform: 'win32',

  // Object hash of application metadata to embed into the executable (Windows only)
  'version-string': {

    // Company that produced the file.
    CompanyName: config.APP_NAME,

    // Copyright notices that apply to the file. This should include the full text of all
    // notices, legal symbols, copyright dates, and so on.
    LegalCopyright: fs.readFileSync(path.join(__dirname, '..', 'LICENSE'), 'utf8'),

    // Name of the program, displayed to users
    FileDescription: config.APP_NAME,

    // Original name of the file, not including a path. This information enables an
    // application to determine whether a file has been renamed by a user. The format of
    // the name depends on the file system for which the file was created.
    OriginalFilename: 'WebTorrent.exe',

    // Name of the product with which the file is distributed.
    ProductName: config.APP_NAME,

    // Internal name of the file, if one exists, for example, a module name if the file
    // is a dynamic-link library. If the file has no internal name, this string should be
    // the original filename, without extension. This string is required.
    InternalName: config.APP_NAME
  },

  // Application icon.
  icon: path.join(__dirname, '..', 'static', 'WebTorrent.ico')
}

var linux = {
  platform: 'linux'

  // Note: Application icon for Linux is specified via the BrowserWindow `icon` option.
}

build()

function buildDarwin (cb) {
  electronPackager(Object.assign({}, all, darwin), function (err, appPath) {
    printDone(err, appPath)
    if (err) return cb(err)

    var contentsPath = path.join(
      __dirname,
      '..',
      'dist',
      `${config.APP_NAME}-darwin-x64`,
      `${config.APP_NAME}.app`,
      'Contents'
    )
    var resourcesPath = path.join(contentsPath, 'Resources')
    var infoPlistPath = path.join(contentsPath, 'Info.plist')
    var webTorrentFileIconPath = path.join(
      __dirname,
      '..',
      'static',
      'WebTorrentFile.icns'
    )
    var infoPlist = plist.parse(fs.readFileSync(infoPlistPath).toString())

    infoPlist['CFBundleDocumentTypes'] = [{
      CFBundleTypeExtensions: [ 'torrent' ],
      CFBundleTypeName: 'BitTorrent Document',
      CFBundleTypeRole: 'Editor',
      CFBundleTypeIconFile: 'WebTorrentFile.icns'
    }]

    fs.writeFileSync(infoPlistPath, plist.build(infoPlist))
    cp.execSync(`cp ${webTorrentFileIconPath} ${resourcesPath}`)

    if (cb) cb(null)
  })
}

function buildWin32 (cb) {
  electronPackager(Object.assign({}, all, win32), function (err, appPath) {
    printDone(err, appPath)
    if (cb) cb(err)
  })
}

function buildLinux (cb) {
  electronPackager(Object.assign({}, all, linux), function (err, appPath) {
    printDone(err, appPath)
    if (cb) cb(err)
  })
}

function printDone (err, appPath) {
  if (err) console.error(err.message || err)
  else console.log('Built ' + appPath)
}
<|endoftext|>


<commit_before>function randomColor(n)
{
	var colors = ["#00008B","#5757FF","#006400","#CC99FF","#D2691E","#669999","#BC5D58","#6495ED","#66FF33",
	"#8B0000","#FF00FF","#FF8C00","#FFFF00","#2F4F4F","#CC3300","#1FCB4A","#FFD700","#00CED1","#FF0066",
	"#FF9900","#00FFFF","#B96F6F","#660066","#6699FF","#9D9D00","#9669FE","#DC143C","#8A2BE2","#333300",
	"#FF0000","#4B0082","#FF99CC","#03EBA6","#003300","#7442C8","#663300","#8B008B","#CC0099","#CD4A4A",
	"#8B4513","#414A4C","#808080","#2F4F4F","#0000FF","#00FF00","#008000","#006600","#FF4500","#E9967A",
	"#6B8E23","#FF4848","#1CAC78","#A5694F"];

        //var result;
        //result = Math.floor((Math.random() * 120) + 1);

        return colors[n];
    };<commit_msg>Randomized list of colors again<commit_after>function randomColor(n)
{
	var colors = ["#FF00FF","#9669FE","#9D9D00","#FF4848","#2F4F4F","#4B0082","#B96F6F",
	"#FFD700","#8B0000","#006400","#03EBA6","#DC143C","#5757FF","#FF0000","#8A2BE2",
	"#7442C8","#6495ED","#CC3300","#FF9900","#6B8E23","#660066","#2F4F4F","#8B4513",
	"#1FCB4A","#CC0099","#669999","#66FF33","#333300","#00FF00","#BC5D58","#6699FF",
	"#00FFFF","#414A4C","#00CED1","#CD4A4A","#FF99CC","#E9967A","#8B008B","#008000",
	"#006600","#663300","#808080","#FFFF00","#1CAC78","#003300","#A5694F","#0000FF",
	"#FF0066","#D2691E","#CC99FF","#00008B","#FF8C00","#FF4500"];

        //var result;
        //result = Math.floor((Math.random() * 120) + 1);

        return colors[n];
    };<|endoftext|>