<commit_before>var mout = require('mout');
var fs = require('graceful-fs');
var path = require('path');
var Q = require('q');
var inquirer = require('inquirer');
var Logger = require('bower-logger');
var endpointParser = require('bower-endpoint-parser');
var cli = require('../util/cli');
var cmd = require('../util/cmd');
var Project = require('../core/Project');
var defaultConfig = require('../config');
var GitHubResolver = require('../core/resolvers/GitHubResolver');

function init(config) {
    var project;
    var logger = new Logger();

    config = mout.object.deepFillIn(config || {}, defaultConfig);
    project = new Project(config, logger);

    // Start with existing JSON details
    readJson(project, logger)
    // Fill in defaults
    .then(setDefaults.bind(null, config))
    // Now prompt user to make changes
    .then(promptUser)
    // Set ignore based on the response
    .spread(setIgnore)
    // Set dependencies based on the response
    .spread(setDependencies.bind(null, project))
    // All done!
    .spread(saveJson.bind(null, project))
    .then(function (json) {
        logger.emit('end', json);
    })
    .fail(function (error) {
        logger.emit('error', error);
    });

    return logger;
}

function readJson(project, logger) {
    return project.hasJson()
    .then(function (json) {
        if (json) {
            logger.warn('existing', 'The existing ' + path.basename(json) + ' file will be used and filled in');
        }

        return project.getJson();
    });
}

function saveJson(project, json) {
    // Cleanup empty props, including objects and arrays
    mout.object.forOwn(json, function (value, key) {
        if (mout.lang.isEmpty(value)) {
            delete json[key];
        }
    });

    // Save json (true forces file creation)
    return project.saveJson(true);
}

function setDefaults(config, json) {
    var name;
    var gitEmail, gitUsername;
    var promise = Q.resolve();

    // Name
    if (!json.name) {
        json.name = path.basename(config.cwd);
    }

    // Version
    if (!json.version) {
        json.version = '0.0.0';
    }

    // Main
    if (!json.main) {
        // Remove '.js' from the end of the package name if it is there
        name = path.basename(json.name, '.js');

        if (fs.existsSync(path.join(config.cwd, 'index.js'))) {
            json.main = 'index.js';
        } else if (fs.existsSync(path.join(config.cwd, name + '.js'))) {
            json.main = name + '.js';
        }
    }

    // Homepage
    if (!json.homepage) {
        promise = promise.then(function () {
            return cmd('git', ['config', '--get', 'remote.origin.url'])
            .spread(function (stdout) {
                stdout = stdout.trim();
                if (!stdout) {
                    return;
                }
                var gitPair = GitHubResolver.getOrgRepoPair(json.homepage);
                if (gitPair) {
                    json.homepage = 'https://github.com/' + gitPair.org + '/' + gitPair.repo;
                }
            })
            .fail(function (error) {
                // Fail silently
            });
        });
    }

    if (!json.authors) {
        promise = promise.then(function () {
            return cmd('git', ['config', '--get', '--global', 'user.email'])
            .spread(function (stdout) {
                stdout = stdout.trim();
                if (stdout) {
                    gitEmail = stdout;
                }
            })
            .fail(function (error) {
                // Fail silently
            });
        });

        promise = promise.then(function () {
            return cmd('git', ['config', '--get', '--global', 'user.name'])
            .spread(function (stdout) {
                stdout = stdout.trim();
                if (stdout) {
                    gitUsername = stdout;
                }
                if (gitUsername) {
                    json.authors = gitUsername;
                    json.authors += gitEmail ? '<' + gitEmail + '>' : '';
                }
            })
            .fail(function (error) {
                // Fail silently
            });
        });
    }

    return promise.then(function () {
        return json;
    });
}

function promptUser(json) {
    var deferred = Q.defer();

    var questions = [
        {
            'name': 'name',
            'message': 'name',
            'default': json.name,
            'type': 'input'
        },
        {
            'name': 'version',
            'message': 'version',
            'default': json.version,
            'type': 'input'
        },
        {
            'name': 'description',
            'message': 'description',
            'default': json.description,
            'type': 'input'
        },
        {
            'name': 'main',
            'message': 'main file',
            'default': json.main,
            'type': 'input'
        },
        {
            'name': 'keywords',
            'message': 'keywords',
            'default': json.keywords ? json.keywords.toString() : null,
            'type': 'input'
        },
        {
            'name': 'authors',
            'message': 'authors',
            'default': json.authors ? json.authors.toString() : null,
            'type': 'input'
        },
        {
            'name': 'license',
            'message': 'license',
            'default': json.license || 'MIT',
            'type': 'input'
        },
        {
            'name': 'homepage',
            'message': 'homepage',
            'default': json.homepage,
            'type': 'input'
        },
        {
            'name': 'dependencies',
            'message': 'set currently installed components as dependencies?',
            'default': !mout.object.size(json.dependencies) && !mout.object.size(json.devDependencies),
            'type': 'confirm'
        },
        {
            'name': 'private',
            'message': 'would you like to mark this package as private which prevents it from being accidentally published to the registry?',
            'default': !!json.private,
            'type': 'confirm'
        },
        {
            'name': 'ignore',
            'message': 'add commonly ignored files to ignore list?',
            'default': true,
            'type': 'confirm'
        }
    ];

    inquirer.prompt(questions, function (answers) {
        json.name = answers.name;
        json.version = answers.version;
        json.description = answers.description;
        json.main = answers.main;
        json.keywords = answers.keywords ? answers.keywords.split(/[,\s]/) : undefined;
        json.authors = answers.authors ? answers.authors.split(',') : undefined;
        json.license = answers.license;
        json.homepage = answers.homepage;
        json.private = answers.private;

        return deferred.resolve([json, answers]);
    });

    return deferred.promise;
}

function setIgnore(json, answers) {
    if (answers.ignore) {
        json.ignore = mout.array.combine(json.ignore || [], [
            '**/.*',
            'node_modules',
            'bower_components',
            'test',
            'tests'
        ]);
    }

    return [json, answers];
}

function setDependencies(project, json, answers) {
    if (answers.dependencies) {
        return project.getTree()
        .spread(function (tree, flattened, extraneous) {
            if (extraneous.length) {
                json.dependencies = {};

                // Add extraneous as dependencies
                // TODO: The final expanded source is used instead of the original source
                //       While this the most correct it might be confusing to users
                extraneous.forEach(function (extra) {
                    var jsonEndpoint;

                    // Skip linked packages
                    if (extra.linked) {
                        return;
                    }

                    jsonEndpoint = endpointParser.decomposed2json(extra.endpoint);
                    mout.object.mixIn(json.dependencies, jsonEndpoint);
                });
            }

            return [json, answers];
        });
    }

    return [json, answers];
}

// -------------------

init.line = function () {
    return init();
};

init.options = function (argv) {
    return cli.readOptions(argv);
};

init.completion = function () {
    // TODO:
};

module.exports = init;
<commit_msg>Tweaks to PR #763.<commit_after>var mout = require('mout');
var fs = require('graceful-fs');
var path = require('path');
var Q = require('q');
var inquirer = require('inquirer');
var Logger = require('bower-logger');
var endpointParser = require('bower-endpoint-parser');
var cli = require('../util/cli');
var cmd = require('../util/cmd');
var Project = require('../core/Project');
var defaultConfig = require('../config');
var GitHubResolver = require('../core/resolvers/GitHubResolver');

function init(config) {
    var project;
    var logger = new Logger();

    config = mout.object.deepFillIn(config || {}, defaultConfig);
    project = new Project(config, logger);

    // Start with existing JSON details
    readJson(project, logger)
    // Fill in defaults
    .then(setDefaults.bind(null, config))
    // Now prompt user to make changes
    .then(promptUser)
    // Set ignore based on the response
    .spread(setIgnore)
    // Set dependencies based on the response
    .spread(setDependencies.bind(null, project))
    // All done!
    .spread(saveJson.bind(null, project))
    .then(function (json) {
        logger.emit('end', json);
    })
    .fail(function (error) {
        logger.emit('error', error);
    });

    return logger;
}

function readJson(project, logger) {
    return project.hasJson()
    .then(function (json) {
        if (json) {
            logger.warn('existing', 'The existing ' + path.basename(json) + ' file will be used and filled in');
        }

        return project.getJson();
    });
}

function saveJson(project, json) {
    // Cleanup empty props (null values, empty strings, objects and arrays)
    mout.object.forOwn(json, function (value, key) {
        if (value == null || mout.lang.isEmpty(value)) {
            delete json[key];
        }
    });

    // Save json (true forces file creation)
    return project.saveJson(true);
}

function setDefaults(config, json) {
    var name;
    var promise = Q.resolve();

    // Name
    if (!json.name) {
        json.name = path.basename(config.cwd);
    }

    // Version
    if (!json.version) {
        json.version = '0.0.0';
    }

    // Main
    if (!json.main) {
        // Remove '.js' from the end of the package name if it is there
        name = path.basename(json.name, '.js');

        if (fs.existsSync(path.join(config.cwd, 'index.js'))) {
            json.main = 'index.js';
        } else if (fs.existsSync(path.join(config.cwd, name + '.js'))) {
            json.main = name + '.js';
        }
    }

    // Homepage
    if (!json.homepage) {
        promise = promise.then(function () {
            return cmd('git', ['config', '--get', 'remote.origin.url'])
            .spread(function (stdout) {
                var pair;

                stdout = stdout.trim();
                if (!stdout) {
                    return;
                }

                pair = GitHubResolver.getOrgRepoPair(json.homepage);
                if (pair) {
                    json.homepage = 'https://github.com/' + pair.org + '/' + pair.repo;
                }
            })
            .fail(function () { });
        });
    }

    if (!json.authors) {
        promise = promise.then(function () {
            // Get the user name configured in git
            return cmd('git', ['config', '--get', '--global', 'user.name'])
            .spread(function (stdout) {
                var gitEmail;
                var gitName = stdout.trim();

                // Abort if no name specified
                if (!gitName) {
                    return;
                }

                // Get the user email configured in git
                return cmd('git', ['config', '--get', '--global', 'user.email'])
                .spread(function (stdout) {
                    gitEmail = stdout.trim();
                }, function () {})
                .then(function () {
                    json.authors = gitName;
                    json.authors += gitEmail ? ' <' + gitEmail + '>' : '';
                });
            }, function () {});
        });
    }

    return promise.then(function () {
        return json;
    });
}

function promptUser(json) {
    var deferred = Q.defer();

    var questions = [
        {
            'name': 'name',
            'message': 'name',
            'default': json.name,
            'type': 'input'
        },
        {
            'name': 'version',
            'message': 'version',
            'default': json.version,
            'type': 'input'
        },
        {
            'name': 'description',
            'message': 'description',
            'default': json.description,
            'type': 'input'
        },
        {
            'name': 'main',
            'message': 'main file',
            'default': json.main,
            'type': 'input'
        },
        {
            'name': 'keywords',
            'message': 'keywords',
            'default': json.keywords ? json.keywords.toString() : null,
            'type': 'input'
        },
        {
            'name': 'authors',
            'message': 'authors',
            'default': json.authors ? json.authors.toString() : null,
            'type': 'input'
        },
        {
            'name': 'license',
            'message': 'license',
            'default': json.license || 'MIT',
            'type': 'input'
        },
        {
            'name': 'homepage',
            'message': 'homepage',
            'default': json.homepage,
            'type': 'input'
        },
        {
            'name': 'dependencies',
            'message': 'set currently installed components as dependencies?',
            'default': !mout.object.size(json.dependencies) && !mout.object.size(json.devDependencies),
            'type': 'confirm'
        },
        {
            'name': 'ignore',
            'message': 'add commonly ignored files to ignore list?',
            'default': true,
            'type': 'confirm'
        },
        {
            'name': 'private',
            'message': 'would you like to mark this package as private which prevents it from being accidentally published to the registry?',
            'default': !!json.private,
            'type': 'confirm'
        }
    ];

    inquirer.prompt(questions, function (answers) {
        json.name = answers.name;
        json.version = answers.version;
        json.description = answers.description;
        json.main = answers.main;
        json.keywords = answers.keywords ? answers.keywords.split(/[,\s]+/) : null;
        json.authors = answers.authors ? answers.authors.split(',') : null;
        json.license = answers.license;
        json.homepage = answers.homepage;
        json.private = answers.private || null;

        return deferred.resolve([json, answers]);
    });

    return deferred.promise;
}

function setIgnore(json, answers) {
    if (answers.ignore) {
        json.ignore = mout.array.combine(json.ignore || [], [
            '**/.*',
            'node_modules',
            'bower_components',
            'test',
            'tests'
        ]);
    }

    return [json, answers];
}

function setDependencies(project, json, answers) {
    if (answers.dependencies) {
        return project.getTree()
        .spread(function (tree, flattened, extraneous) {
            if (extraneous.length) {
                json.dependencies = {};

                // Add extraneous as dependencies
                // TODO: The final expanded source is used instead of the original source
                //       While this the most correct it might be confusing to users
                extraneous.forEach(function (extra) {
                    var jsonEndpoint;

                    // Skip linked packages
                    if (extra.linked) {
                        return;
                    }

                    jsonEndpoint = endpointParser.decomposed2json(extra.endpoint);
                    mout.object.mixIn(json.dependencies, jsonEndpoint);
                });
            }

            return [json, answers];
        });
    }

    return [json, answers];
}

// -------------------

init.line = function () {
    return init();
};

init.options = function (argv) {
    return cli.readOptions(argv);
};

init.completion = function () {
    // TODO:
};

module.exports = init;
<|endoftext|>


<commit_before>
/**
 * Module dependencies
 */

var _       = require('underscore');
var config  = require('./config.js');
var gpio    = require('rpi-gpio');
var log     = require('logule').init(module, 'cascade');
var nfc     = require('./nfc.js');
var usb     = require('./usb.js');
var user    = require('./user.js');

/**
 * Initialize Cascade
 *
 * @constructor
 */

function Cascade() {

  /**
   * self
   * @type {Cascade}
   */

  var self = this;

  /**
   * setup rpi pins
   *
   * GPIO 21 = change slot relay
   * GPIO 12 = status light
   *
   * @see https://github.com/JamesBarwell/rpi-gpio.js
   */

  var initPins = [
    config.rpi.relayPin,
    config.rpi.ledPin
  ];

  _.each(initPins, function(pin) {

    log.info(pin);

    gpio.setup(pin, gpio.DIR_OUT, function(err) {
      if (err) {
        throw err;
      }
      gpio.write(pin, true, function(err) {
        if (err) {
          throw err;
        }
      });
    });
  });

  // ..

  log.info('init');
}

/**
 *
 */

Cascade.prototype.init = function() {
  //stub
};

/**
 * init usb
 */

Cascade.prototype.initUsb = function() {
  /**
   * usb detection handlers
   */
  usb.on('add', this._handleAddUsbDevice.bind(this));
};

/**
 * init nfc detection handlers
 */

Cascade.prototype.initNfc = function() {
  nfc.on('uid', self._handleNfcUid.bind(self));
};

/**
 * find user for device event
 *
 * @param id device either usb serial or nfs uid/ats
 */

Cascade.prototype.findUserAndWithdraw = function(id) {
  var self = this;

  user.findUserForDevice(id, function(error, user) {
    if (error) {
      //failed
      return;
    }

    if (!user) {
      //user doesn't exist
      return;
    }

    if (machine.balance < amount) {
      //machine is empty
      return;
    }

    if (user.balance < amount) {
      //user doesn't have cash
      return;
    }

    //machine.decrement

    //user.decrement
    //user.notify

  });

};

/**
 * withdraw `amount` from `username`
 *
 * @param username
 * @param amount
 */

Cascade.prototype.withdrawForUser = function(username, amount) {
  /**
   * user exists, see if they have any money
   *
   * @param res
   * @param next
   */
  User.find({
    where: {
      username: username
    }
  })
    .error(function(err) {
      throw err;
    })
    .success(function(user) {
      if(user === null) {
        log.error(user + ' does not have a cascade account');

        /**
         * blink LED to show no user account
         */

        blinkLED(config.ledBlinkTime);

      } else {
        if (user.balance >= amount) {

          /**
           * cycle relay and drop coins
           */

          cycleSlot(config.relayCycleTime);

          /**
           * update machine account
           */

          User.find(1).success(function(machine) {
            machine.decrement('balance', { by: amount });
          });

          /**
           * update user balance
           */

          user.decrement('balance', { by: amount });

          /**
           * send email if user has email?
           */

          if (user.email) {
            notifyNewBalance(user);
          }
        } else {
          log.error('user does not have enough funds');

          /**
           * blink LED three times to show no user funds
           */

          blinkLED(config.ledBlinkTime);
          setTimeout(function() {blinkLED(config.ledBlinkTime);}, config.ledBlinkTime*2*1);
          setTimeout(function() {blinkLED(config.ledBlinkTime);}, config.ledBlinkTime*2*2);

        }
      }
    }
  );
};

// ------------------------------------------------------------------------------------
// NFC
// ------------------------------------------------------------------------------------

/**
 * trigger on nfc ats event, look up user and spit out coins
 *
 * @param ats
 * @private
 */

Cascade.prototype._handleNfcAts = function(ats) {
  this.findUserAndWithdraw(ats);
};

/**
 * trigger on nfc uid event, look up user and spit out coins
 *
 * @param _uid
 * @private
 */

Cascade.prototype._handleNfcUid = function(uid) {
  this.findUserAndWithdraw(uid);
};

// ------------------------------------------------------------------------------------
// USB
// ------------------------------------------------------------------------------------

/**
 * Handle usb-detection `add` device event
 *
 * @param err
 * @param devices
 * @private
 */

Cascade.prototype._handleAddUsbDevice = function(usbSerialID) {
  this.findUserAndWithdraw(usbSerialID);
};

// ------------------------------------------------------------------------------------
// Workflow helpers
// ------------------------------------------------------------------------------------

/**
 *
 * @param user
 */

function notifyNewBalance(user) {
  mandrill('/messages/send', {
    message: {
      to: [{email: user.email, name: user.username}],
      from_email: 'no-reply@makerslocal.org',
      subject: "[Cascade] Receipt",
      text: "Hi " + user.username + ", your current balance is: " + user.balance.toFixed(2)
    }
  }, function(err) {
    if (err) {
      log.error(err);
    }
    // ..
  });
}

// ------------------------------------------------------------------------------------
// RPI helpers
// ------------------------------------------------------------------------------------

/**
 * Set pin high and after `delay` set pin low
 * @param delay in milliseconds
 */

function cycleSlot(delay) {
  gpio.write(config.rpi.relayPin, false, function(err) {
    if (err) {
      throw err;
    }
    setTimeout(function() {
      gpio.write(config.rpi.relayPin, true, function(err) {
        if (err) {
          throw err;
        }
      });
    }, delay);
  });
}

/**
 * Blink LED for a number of milliseconds
 * @param delay in milliseconds
 */

function blinkLED(delay) {
  gpio.write(config.rpi.ledPin, false, function(err) {
    if (err) throw err;
    setTimeout(function() {
      gpio.write(config.rpi.ledPin, true, function(err) {
        if (err) throw err;
      });
    }, delay)
  });
}

/**
 * Toggle led stub
 */

function toggleLight() {

  log.info('toggle light');

  gpio.write(config.rpi.relayPin, false, function(err) {
    if (err) {
      throw err;
    }

    log.info('toggled light');
  });
}

/**
 * Expose `Cascade`
 * @type {Cascade}
 */

module.exports = (function() {
  var instance;
  if (typeof instance === 'undefined') {
    instance = new Cascade();
  }
  return instance;
}());
<commit_msg>cleaning up<commit_after>
/**
 * Module dependencies
 */

var _       = require('underscore');
var config  = require('./config.js');
var gpio    = require('rpi-gpio');
var log     = require('logule').init(module, 'cascade');
var nfc     = require('./nfc.js');
var usb     = require('./usb.js');
var user    = require('./user.js');

/**
 * Initialize Cascade
 *
 * @constructor
 */

function Cascade() {

  /**
   * setup rpi pins
   *
   * GPIO 21 = change slot relay
   * GPIO 12 = status light
   *
   * @see https://github.com/JamesBarwell/rpi-gpio.js
   */

  var initPins = [
    config.rpi.relayPin,
    config.rpi.ledPin
  ];

  _.each(initPins, function(pin) {

    log.info(pin);

    gpio.setup(pin, gpio.DIR_OUT, function(err) {
      if (err) {
        throw err;
      }
      gpio.write(pin, true, function(err) {
        if (err) {
          throw err;
        }
      });
    });
  });

  // ..

  log.info('init');
}

/**
 * init
 */

Cascade.prototype.init = function() {
  //stub
};

/**
 * init usb
 */

Cascade.prototype.initUsb = function() {
  /**
   * usb detection handlers
   */
  usb.on('add', this._handleAddUsbDevice.bind(this));
};

/**
 * init nfc detection handlers
 */

Cascade.prototype.initNfc = function() {
  nfc.on('uid', this._handleNfcUid.bind(this));
};

/**
 * find user for device event
 *
 * @param id device either usb serial or nfs uid/ats
 */

Cascade.prototype.findUserAndWithdraw = function(id) {

  user.findUserForDevice(id, function(error, user) {
    if (error) {
      //failed
      return;
    }

    if (!user) {
      //user doesn't exist
      return;
    }

    if (machine.balance < amount) {
      //machine is empty
      return;
    }

    if (user.balance < amount) {
      //user doesn't have cash
      return;
    }

    //machine.decrement

    //user.decrement
    //user.notify

  });

};

/**
 * withdraw `amount` from `username`
 *
 * @param username
 * @param amount
 */

Cascade.prototype.withdrawForUser = function(username, amount) {
  /**
   * user exists, see if they have any money
   *
   * @param res
   * @param next
   */
  User.find({
    where: {
      username: username
    }
  })
    .error(function(err) {
      throw err;
    })
    .success(function(user) {
      if(user === null) {
        log.error(user + ' does not have a cascade account');

        /**
         * blink LED to show no user account
         */

        blinkLED(config.ledBlinkTime);

      } else {
        if (user.balance >= amount) {

          /**
           * cycle relay and drop coins
           */

          cycleSlot(config.relayCycleTime);

          /**
           * update machine account
           */

          User.find(1).success(function(machine) {
            machine.decrement('balance', { by: amount });
          });

          /**
           * update user balance
           */

          user.decrement('balance', { by: amount });

          /**
           * send email if user has email?
           */

          if (user.email) {
            notifyNewBalance(user);
          }
        } else {
          log.error('user does not have enough funds');

          /**
           * blink LED three times to show no user funds
           */

          blinkLED(config.ledBlinkTime);
          setTimeout(function() {blinkLED(config.ledBlinkTime);}, config.ledBlinkTime*2*1);
          setTimeout(function() {blinkLED(config.ledBlinkTime);}, config.ledBlinkTime*2*2);

        }
      }
    }
  );
};

// ------------------------------------------------------------------------------------
// NFC
// ------------------------------------------------------------------------------------

/**
 * trigger on nfc ats event, look up user and spit out coins
 *
 * @param ats
 * @private
 */

Cascade.prototype._handleNfcAts = function(ats) {
  this.findUserAndWithdraw(ats);
};

/**
 * trigger on nfc uid event, look up user and spit out coins
 *
 * @param _uid
 * @private
 */

Cascade.prototype._handleNfcUid = function(uid) {
  this.findUserAndWithdraw(uid);
};

// ------------------------------------------------------------------------------------
// USB
// ------------------------------------------------------------------------------------

/**
 * Handle usb-detection `add` device event
 *
 * @param err
 * @param devices
 * @private
 */

Cascade.prototype._handleAddUsbDevice = function(usbSerialID) {
  this.findUserAndWithdraw(usbSerialID);
};

// ------------------------------------------------------------------------------------
// RPI helpers
// ------------------------------------------------------------------------------------

/**
 * Set pin high and after `delay` set pin low
 * @param delay in milliseconds
 */

function cycleSlot(delay) {
  gpio.write(config.rpi.relayPin, false, function(err) {
    if (err) {
      throw err;
    }
    setTimeout(function() {
      gpio.write(config.rpi.relayPin, true, function(err) {
        if (err) {
          throw err;
        }
      });
    }, delay);
  });
}

/**
 * Blink LED for a number of milliseconds
 * @param delay in milliseconds
 */

function blinkLED(delay) {
  gpio.write(config.rpi.ledPin, false, function(err) {
    if (err) throw err;
    setTimeout(function() {
      gpio.write(config.rpi.ledPin, true, function(err) {
        if (err) throw err;
      });
    }, delay)
  });
}

/**
 * Expose `Cascade`
 * @type {Cascade}
 */

module.exports = (function() {
  var instance;
  if (typeof instance === 'undefined') {
    instance = new Cascade();
  }
  return instance;
}());
<|endoftext|>


<commit_before>import React, { Component } from 'react';

import {
  StyleSheet,
  Text,
  View,
  TouchableHighlight,
} from 'react-native';

import I18n from 'react-native-i18n'

class Profile extends Component{

_onPressAddStory(){

  }

_onPressViewMessages(){

}

  featuredStory() {

  }

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.title}>Smeagles {I18n.t('profile')}</Text>

        <Text style={styles.featuredStory}>"My day today was very interesting. First I woke up late and I couldn't find my clean clothes and my mom......"</Text>
        <Text style={styles.featuredStoryArabic}>كان يوم لي اليوم مثيرة جدا للاهتمام. أولا استيقظت في وقت متأخر، وأنا لا يمكن أن تجد لي ملابس نظيفة وأمي</Text>

        <TouchableHighlight onPress={this._onPressAddStory.bind(this)} style={styles.button}>
        <Text style={styles.buttonText}>
        Add Story
        </Text>
        </TouchableHighlight>

        <TouchableHighlight onPress={this._onPressViewMessages.bind(this)} style={styles.button}>
        <Text style={styles.buttonText}>
        View Messages
        </Text>
        </TouchableHighlight>

        <Text style={styles.body}> {JSON.stringify(this.props.users)}</Text>
        <Text style={styles.body}> This will be a list of user stories </Text>
        <Text> {JSON.stringify(this.props.user)}</Text>

        <Text> blablabla </Text>
      </View>
    )
  }
};

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  title: {
   marginTop: 25,
   fontSize: 20,
   alignSelf: 'center',
   margin: 40,
  },
  body: {
    flex: 0.1,
  },
  button: {
    height: 50,
    backgroundColor: '#48BBEC',
    alignSelf: 'stretch',
    marginTop: 10,
    justifyContent: 'center'
  },
  buttonText: {
    textAlign: 'center',
  },
  featuredStory: {
    backgroundColor: 'lightgrey',
  },
  featuredStoryArabic: {
    backgroundColor: 'lightgrey',
  },
});

module.exports = Profile;
<commit_msg>Fix all merge conflicts, add profile skeleton again, still needs work<commit_after>import React, { Component } from 'react';

import {
  StyleSheet,
  Text,
  View,
  TouchableHighlight,
} from 'react-native';

import I18n from 'react-native-i18n'

class Profile extends Component{

_onPressAddStory(){

  }

_onPressViewMessages(){

}

featuredStory() {

  }

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.title}>Smeagles {I18n.t('profile')}</Text>

        <Text style={styles.featuredStory}>"My day today was very interesting. First I woke up late and I couldn't find my clean clothes and my mom......"</Text>
        <Text style={styles.featuredStoryArabic}>كان يوم لي اليوم مثيرة جدا للاهتمام. أولا استيقظت في وقت متأخر، وأنا لا يمكن أن تجد لي ملابس نظيفة وأمي</Text>

        <TouchableHighlight onPress={this._onPressAddStory.bind(this)} style={styles.button}>
        <Text style={styles.buttonText}>
        Add Story
        </Text>
        </TouchableHighlight>

        <TouchableHighlight onPress={this._onPressViewMessages.bind(this)} style={styles.button}>
        <Text style={styles.buttonText}>
        View Messages
        </Text>
        </TouchableHighlight>

        <Text style={styles.body}> {JSON.stringify(this.props.users)}</Text>
        <Text style={styles.body}> This will be a list of user stories </Text>

        <Text> Personal Info </Text>
        <Text> Contact Info </Text>
      </View>
    )
  }
};

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  title: {
   marginTop: 25,
   fontSize: 20,
   alignSelf: 'center',
   margin: 40,
  },
  body: {
    flex: 0.1,
  },
  button: {
    height: 50,
    backgroundColor: '#48BBEC',
    alignSelf: 'stretch',
    marginTop: 10,
    justifyContent: 'center'
  },
  buttonText: {
    textAlign: 'center',
  },
  featuredStory: {
    backgroundColor: 'lightgrey',
  },
  featuredStoryArabic: {
    backgroundColor: 'lightgrey',
  },
});

module.exports = Profile;
<|endoftext|>


<commit_before>ds.models.tag = function(data) {
  "use strict";

   var storage = {}
     , self = {}

  limivorous.observable(self, storage)
            .property(self, 'id', storage)
            .property(self, 'href', storage)
            .property(self, 'name', storage)
            .property(self, 'description', storage)
            .property(self, 'color', storage)
            .property(self, 'count', storage)
  Object.defineProperty(self, 'is_tag', {value: true});

  if (data) {
      if (data.is_tag) {
        return data
      } else if (typeof data === 'string') {
        self.name = data
      } else {
        self.id = data.id
        self.href = data.href
        self.name = data.name
        self.description = data.description
        self.color = data.color
        self.count = data.count
      }
  }

  self.toJSON = function() {
    return {
      id: self.id,
      href: self.href,
      name: self.name,
      description: self.description,
      color: self.color,
      count: self.count
    }
  }

  return self
}
<commit_msg>Rewrite toJSON to eliminate null values<commit_after>ds.models.tag = function(data) {
  "use strict";

   var storage = {}
     , self = {}

  limivorous.observable(self, storage)
            .property(self, 'id', storage)
            .property(self, 'href', storage)
            .property(self, 'name', storage)
            .property(self, 'description', storage)
            .property(self, 'color', storage)
            .property(self, 'count', storage)
  Object.defineProperty(self, 'is_tag', {value: true});

  if (data) {
      if (data.is_tag) {
        return data
      } else if (typeof data === 'string') {
        self.name = data
      } else {
        self.id = data.id
        self.href = data.href
        self.name = data.name
        self.description = data.description
        self.color = data.color
        self.count = data.count
      }
  }

  self.toJSON = function() {
    var json = {}
    if (self.id)
      json.id = self.id
    if (self.href)
      json.href = self.href
    if (self.name)
      json.name = self.name
    if (self.description)
      json.description = self.description
    if (self.color)
      json.color = self.color
    if (self.count)
      json.count = self.count
    return json
  }

  return self
}
<|endoftext|>


<commit_before>"use strict";

!function (name, context, definition) {
  if (typeof define == 'function') define(definition);
  else if (typeof module != 'undefined') module.exports = definition();
  else context[name] = definition();
}('mandlebrot', this, () => {
  // INIT CANVAS
  const canvas = document.getElementById("canvas");
  const canvasOverlay = document.getElementById("canvasOverlay");

  canvas.width  = window.innerWidth;
  canvas.height = window.innerHeight;
  canvasOverlay.width  = window.innerWidth;
  canvasOverlay.height = window.innerHeight;

  const ratio = canvas.width / canvas.height;

  const yMax = 1.2;
  const width = yMax * (canvas.width / canvas.height); // -2 to 2

  const overlayCtx = canvasOverlay.getContext('2d');
  overlayCtx.lineWidth = 2;
  overlayCtx.strokeStyle = '#FF00FF';
  const ctx = canvas.getContext('2d');
  const imgData = ctx.createImageData(canvas.width, 1);

  const x_interval = width * 2 / canvas.width; // -2 to 2
  const y_interval = yMax * 2 / canvas.height; // -2 to 2

  const m = {
    maxIterations: 50,
    escapeRadius: 5,
    y_interval,
    x_interval,
    boundaries: {
      top: yMax,
      right: width,
      bottom: -yMax,
      left: -width
    },
    ctx,
    overlayCtx,
    imgData,
    yPixel: 0,
    y: yMax,
    color: false,
    progressBar: document.getElementById("progressBar"),

    hsvToRgb(h, s, v) {
      let r, g, b;

      const i = Math.floor(h * 6);
      const f = h * 6 - i;
      const p = v * (1 - s);
      const q = v * (1 - f * s);
      const t = v * (1 - (1 - f) * s);

      switch (i % 6) {
        case 0: r = v, g = t, b = p; break;
        case 1: r = q, g = v, b = p; break;
        case 2: r = p, g = v, b = t; break;
        case 3: r = p, g = q, b = v; break;
        case 4: r = t, g = p, b = v; break;
        case 5: r = v, g = p, b = q; break;
      }

      return [ r * 255, g * 255, b * 255 ];
    },

    getColor(iterations) {
      // grayscale
      if (!m.color) {
        const value = 255 - (iterations / m.maxIterations * 255)
        return [value, value, value];
      }

      // color
      if (iterations === 1) return [255, 255, 255];
      if (iterations === m.maxIterations) return [0, 0, 0];

      const value = iterations / m.maxIterations;

      return m.hsvToRgb(.5 + value / 2, 1, 1 - value);
    },

    getIterations(real, imaginary) {
      let Zr = 0,
          Zi = 0,
          Tr = 0,
          Ti = 0,
          n  = 0;

      for ( ; n < m.maxIterations && (Tr + Ti) <= m.escapeRadius; n++) {
        Zi = 2 * Zr * Zi + imaginary;
        Zr = Tr - Ti + real;
        Tr = Zr * Zr;
        Ti = Zi * Zi;
      }

      return n;
    },

    updateProgressLine(yPixel) {
      m.overlayCtx.clearRect(0, 0, canvasOverlay.width, canvasOverlay.height);

      if (yPixel) {
        m.overlayCtx.beginPath();
        m.overlayCtx.moveTo(0, yPixel);
        m.overlayCtx.lineTo(canvasOverlay.width, yPixel);
        m.overlayCtx.stroke();
      }
    },

    drawSingleLine(x) {
      let offset = 0;
      // build line of pixel data to render
      for(; x <= m.boundaries.right; x += m.x_interval) {
        const iterations = m.getIterations(x, m.y);
        const color = m.getColor(iterations);

        m.imgData.data[offset++] = color[0];
        m.imgData.data[offset++] = color[1];
        m.imgData.data[offset++] = color[2];
        m.imgData.data[offset++] = 255;
      }
    },

    draw() {
      m.yPixel++;
      m.drawSingleLine(m.boundaries.left);
      m.ctx.putImageData(imgData, 0, m.yPixel);
      m.y -= m.y_interval

      if (m.y >= m.boundaries.bottom) {
        // not done, keep drawing
        m.draw();
        if (!m.waitToUpdate) {
          // don't wait to update DOM every time
          m.updateProgressLine(m.yPixel);
          m.waitToUpdate = true;
          setTimeout(() => {
            // set to wait again so it only updates every 200ms
            m.waitToUpdate = false;
          }, 200);
        }
      } else {
        // done drawing, reset
        m.updateProgressLine();
        m.lastUpdatedAt = null;
        m.y = m.boundaries.top;
        m.yPixel = 0;
      }
    },

    bindListeners() {
      // INPUT CONTROLS
      document.getElementById("maxIterations").addEventListener("change", (e) => {
        m.maxIterations = e.target.value;
        m.draw();
      });

      document.getElementById("escapeRadius").addEventListener("change", (e) => {
        m.escapeRadius = e.target.value;
        m.draw();
      });

      document.getElementById("color").addEventListener("change", (e) => {
        m.color = e.target.checked;
        m.draw();
      });

      // DRAG ZOOMING
      let zoomBox = null;

      canvasOverlay.addEventListener("mousedown", (e) => {
        zoomBox = [e.clientX, e.clientY, 0, 0];
      });

      canvasOverlay.addEventListener("mousemove", (e) => {
        if (zoomBox) {
          // clear out old box first
          m.overlayCtx.clearRect(0, 0, canvasOverlay.width, canvasOverlay.height);

          // draw new box keeping aspect ratio
          zoomBox[2] = e.clientX;
          zoomBox[3] = zoomBox[1] + ((e.clientX - zoomBox[0]) / ratio);

          m.overlayCtx.strokeRect(zoomBox[0], zoomBox[1], zoomBox[2] - zoomBox[0], zoomBox[3] - zoomBox[1]);
        }
      });

      canvasOverlay.addEventListener("mouseup", (e) => {
        m.boundaries = {
          left: m.boundaries.left + m.x_interval * zoomBox[0],
          right: m.boundaries.left + m.x_interval * zoomBox[2],
          top: m.boundaries.top - m.y_interval * zoomBox[1],
          bottom: m.boundaries.top - m.y_interval * zoomBox[3]
        };
        m.y = m.boundaries.top;
        m.x_interval = Math.abs(m.boundaries.left - m.boundaries.right) / canvasOverlay.width;
        m.y_interval = Math.abs(m.boundaries.top - m.boundaries.bottom) / canvasOverlay.height;

        zoomBox = null;
        m.overlayCtx.clearRect(0, 0, canvasOverlay.width, canvasOverlay.height);
        m.draw();
      });
    },

    init() {
      m.bindListeners();
      m.draw();
    }
  };

  return m;
});
<commit_msg>Revert "Merge branch 'gh-pages'"<commit_after>"use strict";

!function (name, context, definition) {
  if (typeof define == 'function') define(definition);
  else if (typeof module != 'undefined') module.exports = definition();
  else context[name] = definition();
}('mandlebrot', this, () => {
  // INIT CANVAS
  const canvas = document.getElementById("canvas");
  const canvasOverlay = document.getElementById("canvasOverlay");

  canvas.width  = window.innerWidth;
  canvas.height = window.innerHeight;
  canvasOverlay.width  = window.innerWidth;
  canvasOverlay.height = window.innerHeight;

  const ratio = canvas.width / canvas.height;

  const yMax = 1.2;
  const width = yMax * (canvas.width / canvas.height); // -2 to 2

  const overlayCtx = canvasOverlay.getContext('2d');
  overlayCtx.lineWidth = 2;
  overlayCtx.strokeStyle = '#FF00FF';
  const ctx = canvas.getContext('2d');
  const imgData = ctx.createImageData(canvas.width, 1);

  const x_interval = width * 2 / canvas.width; // -2 to 2
  const y_interval = yMax * 2 / canvas.height; // -2 to 2

  const m = {
    maxIterations: 50,
    escapeRadius: 5,
    y_interval,
    x_interval,
    boundaries: {
      top: yMax,
      right: width,
      bottom: -yMax,
      left: -width
    },
    ctx,
    overlayCtx,
    imgData,
    yPixel: 0,
    y: yMax,
    color: false,
    progressBar: document.getElementById("progressBar"),

    hsvToRgb(h, s, v) {
      let r, g, b;

      const i = Math.floor(h * 6);
      const f = h * 6 - i;
      const p = v * (1 - s);
      const q = v * (1 - f * s);
      const t = v * (1 - (1 - f) * s);

      switch (i % 6) {
        case 0: r = v, g = t, b = p; break;
        case 1: r = q, g = v, b = p; break;
        case 2: r = p, g = v, b = t; break;
        case 3: r = p, g = q, b = v; break;
        case 4: r = t, g = p, b = v; break;
        case 5: r = v, g = p, b = q; break;
      }

      return [ r * 255, g * 255, b * 255 ];
    },

    getColor(iterations) {
      // grayscale
      if (!m.color) {
        const value = 255 - (iterations / m.maxIterations * 255)
        return [value, value, value];
      }

      // color
      if (iterations === 1) return [255, 255, 255];
      if (iterations === m.maxIterations) return [0, 0, 0];

      const value = iterations / m.maxIterations;

      return m.hsvToRgb(.5 + value / 2, 1, 1 - value);
    },

    getIterations(real, imaginary) {
      let Zr = 0,
          Zi = 0,
          Tr = 0,
          Ti = 0,
          n  = 0;

      for ( ; n < m.maxIterations && (Tr + Ti) <= m.escapeRadius; ++n) {
        Zi = 2 * Zr * Zi + imaginary;
        Zr = Tr - Ti + real;
        Tr = Zr * Zr;
        Ti = Zi * Zi;
      }

      return n;
    },

    updateProgressLine(yPixel) {
      // if (percent === 0) {
      //   // done
      //   m.progressBar.style.display = "none";
      // } else {
      //   m.progressBar.style.width = `${window.innerWidth * percent}px`;
      //   m.progressBar.style.display = "block";
      // }
      m.overlayCtx.clearRect(0, 0, canvasOverlay.width, canvasOverlay.height);

      // overlayCtx.lineWidth = 1;
      // overlayCtx.strokeStyle = '#FF00FF';
      if (yPixel) {
        m.overlayCtx.beginPath();
        m.overlayCtx.moveTo(0, yPixel);
        m.overlayCtx.lineTo(canvasOverlay.width, yPixel);
        m.overlayCtx.stroke();
      }

    },

    drawSingleLine(x) {
      let offset = 0;
      // build line of pixel data to render
      for(; x <= m.boundaries.right; x += m.x_interval) {
        const iterations = m.getIterations(x, m.y);
        const color = m.getColor(iterations);

        m.imgData.data[offset++] = color[0];
        m.imgData.data[offset++] = color[1];
        m.imgData.data[offset++] = color[2];
        m.imgData.data[offset++] = 255;
      }
    },

    draw() {
      let offset = 0;
      if (!m.lastUpdatedAt) m.lastUpdatedAt = new Date();
      m.yPixel++;

      m.drawSingleLine(m.boundaries.left);
      m.ctx.putImageData(imgData, 0, m.yPixel);
      m.y -= m.y_interval

      if (m.y >= m.boundaries.bottom) {
        // not done, keep drawing
        if (new Date() - m.lastUpdatedAt > 200) {
          // throttle updating DOM
          m.lastUpdatedAt = new Date();
          m.updateProgressLine(m.yPixel);
          // go to next tick so DOM can update
          setTimeout(m.draw, 0);
        } else {
          m.draw();
        }
      } else {
        // done drawing, reset
        m.updateProgressLine();
        m.lastUpdatedAt = null;
        m.y = m.boundaries.top;
        m.yPixel = 0;
      }
    },

    bindListeners() {
      // INPUT CONTROLS
      document.getElementById("maxIterations").addEventListener("change", (e) => {
        m.maxIterations = e.target.value;
        m.draw();
      });

      document.getElementById("escapeRadius").addEventListener("change", (e) => {
        m.escapeRadius = e.target.value;
        m.draw();
      });

      document.getElementById("color").addEventListener("change", (e) => {
        m.color = e.target.checked;
        m.draw();
      });

      // DRAG ZOOMING
      let zoomBox = null;

      canvasOverlay.addEventListener("mousedown", (e) => {
        zoomBox = [e.clientX, e.clientY, 0, 0];
      });

      canvasOverlay.addEventListener("mousemove", (e) => {
        if (zoomBox) {
          // clear out old box first
          m.overlayCtx.clearRect(0, 0, canvasOverlay.width, canvasOverlay.height);

          // draw new box keeping aspect ratio
          zoomBox[2] = e.clientX;
          zoomBox[3] = zoomBox[1] + ((e.clientX - zoomBox[0]) / ratio);

          m.overlayCtx.strokeRect(zoomBox[0], zoomBox[1], zoomBox[2] - zoomBox[0], zoomBox[3] - zoomBox[1]);
        }
      });

      canvasOverlay.addEventListener("mouseup", (e) => {
        m.boundaries = {
          left: m.boundaries.left + m.x_interval * zoomBox[0],
          right: m.boundaries.left + m.x_interval * zoomBox[2],
          top: m.boundaries.top - m.y_interval * zoomBox[1],
          bottom: m.boundaries.top - m.y_interval * zoomBox[3]
        };
        m.y = m.boundaries.top;
        m.x_interval = Math.abs(m.boundaries.left - m.boundaries.right) / canvasOverlay.width;
        m.y_interval = Math.abs(m.boundaries.top - m.boundaries.bottom) / canvasOverlay.height;

        zoomBox = null;
        m.overlayCtx.clearRect(0, 0, canvasOverlay.width, canvasOverlay.height);
        m.draw();
      });
    },

    init() {
      m.bindListeners();
      m.draw();
    }
  };

  return m;
});
<|endoftext|>


<commit_before>var fs = require('fs');
var url = require('url');
var render = require('./render');
global.render = render.render;

function route(res, req) {
	var pathname = getController(res).pathname;
	var handle = getController(res);
	if(typeof handle === 'function'){
		return handle(res, req);
	} else {
		console.log('No resuest handler found for ' + pathname);

		req.writeHead(404, {'Content-Type' : 'text/plain'});
		req.end('not assign.');
	}
}
//url 解析
// 找到渲染页面的函数

function getController(req){
	var pathString = url.parse(req.url, true).pathname;
	pathString = pathString.slice(1);
	var pathA = pathString.split('/');
	var controller_road = '../../apps/controller/';
	var method = '';
	var args = '';
	var lp = pathA.length;

	if(lp > 3){
		for(var i = 0, k = lp - 3; i < k; i++){
			controller_road += pathA[i] + '/';
		}
		controller_road += pathA[i];
		i += 1;
		method = pathA[i] || 'index';
		args = pathA[i+1] || '';
	} else {
		controller_road += pathA[0];
		method = pathA[1] || 'index';
		args = pathA[2] || '';
	}
	console.log(method)
	var controller_file = controller_road + '.js';
	if(fs.existsSync(controller_file)){
		console.log(require(controller_road)[method], '/n controller')
		return require(controller_road)[method];
	}
	return false;
}

exports.route = route;<commit_msg>添加controller js之后，路由新的实现<commit_after>var fs = require('fs');
var url = require('url');
var render = require('./render');
var controller = require('./base/controller');
global.render = render.render;
global.controller = controller;

function route(req, res) {
	var handle = getController(req);
	if(handle){
		var controllerFn = require(handle.controller_road)['__create']();
		controllerFn.setBaseR(req, res);
		controllerFn[handle.method](handle.args)
	} else {
		console.log('No resuest handler found for ' + handle.method);

		res.writeHead(404, {'Content-Type' : 'text/plain'});
		res.end('not assign.');
	}
}
//url 解析
// 找到渲染页面的函数

function getController(req){
	var pathString = url.parse(req.url, true).pathname;
	pathString = pathString.slice(1);
	var pathA = pathString.split('/');
	var urlRoute = {}
	var controller_road = '../../apps/controller/';
	var method = '';
	var args = '';
	var lp = pathA.length;

	// console.log(pathA)
	// console.log(lp)
	if(lp > 3){
		for(var i = 0, k = lp - 3; i < k; i++){
			controller_road += pathA[i] + '/';
		}
		controller_road += pathA[i];
		i += 1;
		method = pathA[i] || 'index';
		args = pathA[i+1] || '';
	} else {
		controller_road += pathA[0];
		method = pathA[1] || 'index';
		args = pathA[2] || '';
	}

	var controller_file = controller_road + '.js';
	if(fs.existsSync(controller_file)){
		return {
			controller_road : controller_road
			, method : method
			, args : args
		};
	}
	return false;
}

exports.route = route;<|endoftext|>


<commit_before>/**
 * InputWritr.js
 * A middleman that manages input events and their associated triggers
 */
function InputWritr(settings) {
    "use strict";
    if (!this || this === window) {
        return new InputWritr(settings);
    }
    var self = this,

        //
        triggers,

        // The arguments to be passed to calls activated by triggers
        recipients,

        //
        aliases,

        // An Array of every action that has happened, with a timestamp
        history,
        // An Array of all histories, with indices set by self.saveHistory
        histories,

        // For compatibility, a var reference to getting the performance.now() timestamp
        get_timestamp,
        //
        starting_time,

        // An object to be passed to event calls, commonly with key information
        // (such as "Down" => 0 }
        event_information,

        // An optional boolean callback to disable or enable input triggers
        can_trigger,

        // Whether to record events into the history
        recording;

    /**
     *
     */
    self.reset = function (settings) {
        get_timestamp = (
            settings.get_timestamp
            || performance.now
            || performance.webkitNow
            || performance.mozNow
            || performance.msNow
            || performance.oNow
            || function () {
                return new Date().getTime();
            }
        ).bind(performance);

        histories = [];
        aliases = {};

        triggers = settings.triggers || {};
        recipients = settings.recipients || {};
        event_information = settings.event_information;
        can_trigger = settings.can_trigger;
        recording = settings.hasOwnProperty("recording") ? settings.recording : true;

        self.addAliases(settings.aliases || {});
    };

    /**
     * Clears the currently tracked inputs history and resets the starting time,
     * and (optionally) saves the current history.
     *
     * @param {Boolean} [keep_history]   Whether the currently tracked history
     *                                   of inputs should be added to the master
     *                                   Array of histories (defaults to true).
     */
    self.restartHistory = function (keep_history) {
        if (history && arguments.length && keep_history) {
            histories.push(history);
        }
        history = {};
        starting_time = get_timestamp();
    };

    /* Simple gets
     */

    /**
     * Returns the Object storing aliases, as "name" => [values]
     *
     * @return {Object} aliases
     */
    self.getAliases = function () {
        return aliases;
    };

    /**
     *
     */
    self.getAliasesAsKeyStrings = function () {
        var output = {},
            alias;

        for(alias in aliases) {
            output[alias] = self.getAliasAsKeyStrings(alias);
        }

        return output;
    };

    /**
     *
     */
    self.getAliasAsKeyStrings = function (alias) {
        return aliases[alias].map(self.convertAliasToKeyString);
    }

    /**
     *
     */
    self.convertAliasToKeyString = function (alias) {
        if(alias.constructor === String) {
            return alias;
        }

        if(alias > 96 && alias < 105) {
            return String.fromCharCode(alias - 48);
        }

        if(alias > 64 && alias < 97) {
            return String.fromCharCode(alias);
        }

        switch(alias) {
            case 16:
                return "shift";
            case 17:
                return "ctrl";
            case 32:
                return "space";
            case 37:
                return "left";
            case 38:
                return "up";
            case 39:
                return "right";
            case 40:
                return "down";
        }
        return "?";
    }

    /**
     *
     */
    self.convertKeyStringToAlias = function (key) {
        if(key.constructor === Number) {
            return key;
        }

        if(key.length === 1) {
            return key.charCodeAt(0) - 32;
        }

        switch(key) {
            case "shift":
                return 16;
            case "ctrl":
                return 17;
            case "space":
                return 32;
            case "left":
                return 37;
            case "up":
                return 38;
            case "right":
                return 39;
            case "down":
                return 40;
        }

        return -1;
    }

    /**
     * Get function for a single history, either the current or a past one.
     *
     * @param {String} [name]   The identifier for the old history to return. If
     *                          none is provided, the current history is used.
     * @return {Object}   A history of inputs
     */
    self.getHistory = function (name) {
        return arguments.length ? histories[name] : history;
    };

    /**
     * Simple get function for the Array of histories.
     *
     * @return {Array}
     */
    self.getHistories = function () {
        return histories;
    };

    /**
     * Simple get function for the Boolean of whether this is recording inputs.
     *
     * @return {Boolean}
     */
    self.getRecording = function () {
        return recording;
    };

    /* Simple sets
     */

    /**
     * Simple set function for the Function used to determine whether this is
     * accepting inputs.
     *
     * @param {Function}
     */
    self.setCanTrigger = function (status) {
        if(status.constructor === Boolean) {
            can_trigger = function () {
                return status;
            };
        } else {
            can_trigger = status;
        }
    }

    /**
     * Simple set function for the Boolean of whether this is recording inputs.
     *
     * @param {Boolean}
     */
    self.setRecording = function (recording_new) {
        recording = recording_new;
    };

    /**
     * Simple set function for the arguments object passed to event calls.
     *
     * @param {Object}
     */
    self.setEventInformation = function (event_info_new) {
        event_information = event_info_new;
    };

    /* Additions
    */

    /**
     * Adds a list of values by which an event may be triggered.
     *
     * @param {String} name   The name of the event that is being given
     *                        aliases, such as "left".
     * @param {Array} values   An array of aliases by which the event will also
     *                         be callable.
     */
    self.addAliasValues = function (name, values) {
        var trigger_name, trigger_group,
            i;

        if(!aliases.hasOwnProperty(name)) {
            aliases[name] = values;
        } else {
            aliases[name].push.apply(aliases[name], values);
        }

        console.log(name, "is now", aliases[name]);

        // trigger_name = "onkeydown", "onkeyup", ...
        for(trigger_name in triggers) {
            if(triggers.hasOwnProperty(trigger_name)) {
                // trigger_group = { "left": function, ... }, ...
                trigger_group = triggers[trigger_name];

                if(trigger_group.hasOwnProperty(name)) {
                    // values[i] = 37, 65, ...
                    for(i = 0; i < values.length; i += 1) {
                        trigger_group[values[i]] = trigger_group[name];
                    }
                }
            }
        }
    };

    /**
     * Removes a list of values by which an event may be triggered.
     *
     * @param {String} name   The name of the event that is having aliases
     *                        removed, such as "left".
     * @param {Array} values   An array of aliases by which the event will no
     *                         longer be callable.
     */
    self.removeAliasValues = function (name, values) {
        var trigger_name, trigger_group,
            i;

        if(!aliases.hasOwnProperty(name)) {
            return;
        }

        for(i = 0; i < values.length; i += 1) {
            aliases[name].splice(aliases[name].indexOf(values[i], 1));
        }

        // trigger_name = "onkeydown", "onkeyup", ...
        for(trigger_name in triggers) {
            if(triggers.hasOwnProperty(trigger_name)) {
                // trigger_group = { "left": function, ... }, ...
                trigger_group = triggers[trigger_name];

                if(trigger_group.hasOwnProperty(name)) {
                    // values[i] = 37, 65, ...
                    for(i = 0; i < values.length; i += 1) {
                        if(trigger_group.hasOwnProperty(values[i])) {
                            delete trigger_group[values[i]];
                        }
                    }
                }
            }
        }
    };

    /**
     *
     */
    self.switchAliasValues = function (name, valuesOld, valuesNew) {
        self.removeAliasValues(name, valuesOld);
        self.addAliasValues(name, valuesNew);
    };

    /**
     * Adds a set of alises from an Object containing "name" => [values] pairs.
     *
     * @param {Object} aliases_raw
     */
    self.addAliases = function (aliases_raw) {
        var alias_name;
        for (alias_name in aliases_raw) {
            if (aliases_raw.hasOwnProperty(alias_name)) {
                self.addAliasValues(alias_name, aliases_raw[alias_name]);
            }
        }
    }

    /**
     *
     *
     *
     */
    self.addEvent = function (trigger, label, callback) {
        if(!triggers.hasOwnProperty(trigger)) {
            throw new Error("Unknown trigger requested: '" + trigger + "'");
        }

        triggers[trigger][label] = callback;

        if(aliases.hasOwnProperty(label)) {
            for(var i = 0; i < aliases[label].length; i += 1) {
                if(triggers[trigger][label]) {
                    triggers[trigger][label][aliases[i]] = callback;
                }
            }
        }
    };

    /**
     *
     */
    self.clearEvent = function (trigger, label) {
        self.addEvent(trigger, label, false);
        console.log("clearEvent called. There used to be \"debugger;\" here, not sure why.");
    };

    /**
     * Stores the current history in the histories Array. self.restartHistory is
     * typically called directly after.
     *
     * @param {String} [name]   An optional name to save the history as.
     * @remarks Histories are stored in an Array, so it's more performant to not
     *          provide a name if you do call this function often.
     */
    self.saveHistory = function (name) {
        histories.push(history);
        if (arguments.length) {
            histories[name] = history;
        }
    };

    /**
     * "Plays" back an Array of event information by simulating each keystroke
     * in a new call, timed by setTimeout.
     *
     * @param {Object} events   An optional events history to play back. If not
     *                          provided, the current history is used.
     * @remarks This will execute the same actions in the same order as before,
     *          but the arguments object may be different.
     */
    self.playHistory = function (events) {
        var timeouts = {},
            time, call;

        if (!arguments.length) {
            events = history;
        }

        for (time in events) {
            if (events.hasOwnProperty(time)) {
                call = makeEventCall(events[time]);
                timeouts[time] = setTimeout(call, Math.round(time - starting_time));
            }
        }
    }

    /**
     * Curry utility to create a closure that runs call() when called.
     *
     * @param {Array} info   An array containing [alias, keycode].
     */
    // Returns a closure function that actives a trigger when called
    function makeEventCall(info) {
        return function () {
            callEvent(info[0], info[1]);
        };
    }

    /**
     * Primary driver function to run an event. The event is chosen from the
     * triggers object, and calld with event_information as the input.
     *
     * @param {Function, String} event   The event function (or string alias of
     *                                   it) that will be called.
     * @param {Number} [keycode]   The alias of the event function under
     *                             triggers[event], if event is a String.
     * @return {Mixed}
     */
    function callEvent(event, keycode) {
        if(can_trigger && !can_trigger(event, keycode)) {
            return;
        }

        // If the event doesn't exist, ignore it
        if (!event) {
            console.warn("Blank event given, ignoring it.");
            return;
        }

        if (typeof (event) === "string" || event instanceof String) {
            event = triggers[event][keycode];
        }

        return event(event_information);
    }

    /**
     * Creates and returns a function to run a trigger.
     *
     * @param {String} trigger   The label for the Array of functions that the
     *                           pipe function should choose from.
     * @param {String} [code_label]   An optional mapping String for the alias:
     *                                if provided, it changes the alias to a
     *                                listed alias keyed by code_label.
     * @param {Boolean} [prevent_defaults]   Whether the input to the pipe
     *                                       function will be an HTML-style
     *                                       event, where .preventDefault()
     *                                       should be clicked.
     * @return {Function}
     * @example   Creating a function that calls an onKeyUp event, with a given
     *            input's keyCode being used as the code_label.
     *            InputWriter.makePipe("onkeyup", "keyCode");
     * @example   Creating a function that calls an onContextMenu event, and
     *            preventDefault of the argument.
     *            InputWriter.makePipe("oncontextmenu", null, true);
     */
    self.makePipe = function (trigger, code_label, prevent_defaults) {
        if (!triggers.hasOwnProperty(trigger)) {
            console.warn("No trigger of label '" + trigger + "' has been defined.");
            return;
        }

        var functions = triggers[trigger],
            use_label = arguments.length >= 2;

        return function Pipe(alias) {
            // Typical usage means alias will be an event from a key/mouse input
            if (prevent_defaults && alias.preventDefault instanceof Function) {
                alias.preventDefault();
            }

            // If a code_label is needed, replace the alias with it
            if (use_label) {
                alias = alias[code_label];
            }

            // If there's a function under that alias, run it
            if (functions.hasOwnProperty(alias)) {
                if (recording) {
                    history[Math.round(get_timestamp())] = [trigger, alias];
                }

                callEvent(functions[alias]);
            }
        }
    }

    self.reset(settings || {});
}<commit_msg>Removed logs from controls menu<commit_after>/**
 * InputWritr.js
 * A middleman that manages input events and their associated triggers
 */
function InputWritr(settings) {
    "use strict";
    if (!this || this === window) {
        return new InputWritr(settings);
    }
    var self = this,

        //
        triggers,

        // The arguments to be passed to calls activated by triggers
        recipients,

        //
        aliases,

        // An Array of every action that has happened, with a timestamp
        history,
        // An Array of all histories, with indices set by self.saveHistory
        histories,

        // For compatibility, a var reference to getting the performance.now() timestamp
        get_timestamp,
        //
        starting_time,

        // An object to be passed to event calls, commonly with key information
        // (such as "Down" => 0 }
        event_information,

        // An optional boolean callback to disable or enable input triggers
        can_trigger,

        // Whether to record events into the history
        recording;

    /**
     *
     */
    self.reset = function (settings) {
        get_timestamp = (
            settings.get_timestamp
            || performance.now
            || performance.webkitNow
            || performance.mozNow
            || performance.msNow
            || performance.oNow
            || function () {
                return new Date().getTime();
            }
        ).bind(performance);

        histories = [];
        aliases = {};

        triggers = settings.triggers || {};
        recipients = settings.recipients || {};
        event_information = settings.event_information;
        can_trigger = settings.can_trigger;
        recording = settings.hasOwnProperty("recording") ? settings.recording : true;

        self.addAliases(settings.aliases || {});
    };

    /**
     * Clears the currently tracked inputs history and resets the starting time,
     * and (optionally) saves the current history.
     *
     * @param {Boolean} [keep_history]   Whether the currently tracked history
     *                                   of inputs should be added to the master
     *                                   Array of histories (defaults to true).
     */
    self.restartHistory = function (keep_history) {
        if (history && arguments.length && keep_history) {
            histories.push(history);
        }
        history = {};
        starting_time = get_timestamp();
    };

    /* Simple gets
     */

    /**
     * Returns the Object storing aliases, as "name" => [values]
     *
     * @return {Object} aliases
     */
    self.getAliases = function () {
        return aliases;
    };

    /**
     *
     */
    self.getAliasesAsKeyStrings = function () {
        var output = {},
            alias;

        for(alias in aliases) {
            output[alias] = self.getAliasAsKeyStrings(alias);
        }

        return output;
    };

    /**
     *
     */
    self.getAliasAsKeyStrings = function (alias) {
        return aliases[alias].map(self.convertAliasToKeyString);
    }

    /**
     *
     */
    self.convertAliasToKeyString = function (alias) {
        if(alias.constructor === String) {
            return alias;
        }

        if(alias > 96 && alias < 105) {
            return String.fromCharCode(alias - 48);
        }

        if(alias > 64 && alias < 97) {
            return String.fromCharCode(alias);
        }

        switch(alias) {
            case 16:
                return "shift";
            case 17:
                return "ctrl";
            case 32:
                return "space";
            case 37:
                return "left";
            case 38:
                return "up";
            case 39:
                return "right";
            case 40:
                return "down";
        }
        return "?";
    }

    /**
     *
     */
    self.convertKeyStringToAlias = function (key) {
        if(key.constructor === Number) {
            return key;
        }

        if(key.length === 1) {
            return key.charCodeAt(0) - 32;
        }

        switch(key) {
            case "shift":
                return 16;
            case "ctrl":
                return 17;
            case "space":
                return 32;
            case "left":
                return 37;
            case "up":
                return 38;
            case "right":
                return 39;
            case "down":
                return 40;
        }

        return -1;
    }

    /**
     * Get function for a single history, either the current or a past one.
     *
     * @param {String} [name]   The identifier for the old history to return. If
     *                          none is provided, the current history is used.
     * @return {Object}   A history of inputs
     */
    self.getHistory = function (name) {
        return arguments.length ? histories[name] : history;
    };

    /**
     * Simple get function for the Array of histories.
     *
     * @return {Array}
     */
    self.getHistories = function () {
        return histories;
    };

    /**
     * Simple get function for the Boolean of whether this is recording inputs.
     *
     * @return {Boolean}
     */
    self.getRecording = function () {
        return recording;
    };

    /* Simple sets
     */

    /**
     * Simple set function for the Function used to determine whether this is
     * accepting inputs.
     *
     * @param {Function}
     */
    self.setCanTrigger = function (status) {
        if(status.constructor === Boolean) {
            can_trigger = function () {
                return status;
            };
        } else {
            can_trigger = status;
        }
    }

    /**
     * Simple set function for the Boolean of whether this is recording inputs.
     *
     * @param {Boolean}
     */
    self.setRecording = function (recording_new) {
        recording = recording_new;
    };

    /**
     * Simple set function for the arguments object passed to event calls.
     *
     * @param {Object}
     */
    self.setEventInformation = function (event_info_new) {
        event_information = event_info_new;
    };

    /* Additions
    */

    /**
     * Adds a list of values by which an event may be triggered.
     *
     * @param {String} name   The name of the event that is being given
     *                        aliases, such as "left".
     * @param {Array} values   An array of aliases by which the event will also
     *                         be callable.
     */
    self.addAliasValues = function (name, values) {
        var trigger_name, trigger_group,
            i;

        if(!aliases.hasOwnProperty(name)) {
            aliases[name] = values;
        } else {
            aliases[name].push.apply(aliases[name], values);
        }

        // trigger_name = "onkeydown", "onkeyup", ...
        for(trigger_name in triggers) {
            if(triggers.hasOwnProperty(trigger_name)) {
                // trigger_group = { "left": function, ... }, ...
                trigger_group = triggers[trigger_name];

                if(trigger_group.hasOwnProperty(name)) {
                    // values[i] = 37, 65, ...
                    for(i = 0; i < values.length; i += 1) {
                        trigger_group[values[i]] = trigger_group[name];
                    }
                }
            }
        }
    };

    /**
     * Removes a list of values by which an event may be triggered.
     *
     * @param {String} name   The name of the event that is having aliases
     *                        removed, such as "left".
     * @param {Array} values   An array of aliases by which the event will no
     *                         longer be callable.
     */
    self.removeAliasValues = function (name, values) {
        var trigger_name, trigger_group,
            i;

        if(!aliases.hasOwnProperty(name)) {
            return;
        }

        for(i = 0; i < values.length; i += 1) {
            aliases[name].splice(aliases[name].indexOf(values[i], 1));
        }

        // trigger_name = "onkeydown", "onkeyup", ...
        for(trigger_name in triggers) {
            if(triggers.hasOwnProperty(trigger_name)) {
                // trigger_group = { "left": function, ... }, ...
                trigger_group = triggers[trigger_name];

                if(trigger_group.hasOwnProperty(name)) {
                    // values[i] = 37, 65, ...
                    for(i = 0; i < values.length; i += 1) {
                        if(trigger_group.hasOwnProperty(values[i])) {
                            delete trigger_group[values[i]];
                        }
                    }
                }
            }
        }
    };

    /**
     *
     */
    self.switchAliasValues = function (name, valuesOld, valuesNew) {
        self.removeAliasValues(name, valuesOld);
        self.addAliasValues(name, valuesNew);
    };

    /**
     * Adds a set of alises from an Object containing "name" => [values] pairs.
     *
     * @param {Object} aliases_raw
     */
    self.addAliases = function (aliases_raw) {
        var alias_name;
        for (alias_name in aliases_raw) {
            if (aliases_raw.hasOwnProperty(alias_name)) {
                self.addAliasValues(alias_name, aliases_raw[alias_name]);
            }
        }
    }

    /**
     *
     *
     *
     */
    self.addEvent = function (trigger, label, callback) {
        if(!triggers.hasOwnProperty(trigger)) {
            throw new Error("Unknown trigger requested: '" + trigger + "'");
        }

        triggers[trigger][label] = callback;

        if(aliases.hasOwnProperty(label)) {
            for(var i = 0; i < aliases[label].length; i += 1) {
                if(triggers[trigger][label]) {
                    triggers[trigger][label][aliases[i]] = callback;
                }
            }
        }
    };

    /**
     *
     */
    self.clearEvent = function (trigger, label) {
        self.addEvent(trigger, label, false);
    };

    /**
     * Stores the current history in the histories Array. self.restartHistory is
     * typically called directly after.
     *
     * @param {String} [name]   An optional name to save the history as.
     * @remarks Histories are stored in an Array, so it's more performant to not
     *          provide a name if you do call this function often.
     */
    self.saveHistory = function (name) {
        histories.push(history);
        if (arguments.length) {
            histories[name] = history;
        }
    };

    /**
     * "Plays" back an Array of event information by simulating each keystroke
     * in a new call, timed by setTimeout.
     *
     * @param {Object} events   An optional events history to play back. If not
     *                          provided, the current history is used.
     * @remarks This will execute the same actions in the same order as before,
     *          but the arguments object may be different.
     */
    self.playHistory = function (events) {
        var timeouts = {},
            time, call;

        if (!arguments.length) {
            events = history;
        }

        for (time in events) {
            if (events.hasOwnProperty(time)) {
                call = makeEventCall(events[time]);
                timeouts[time] = setTimeout(call, Math.round(time - starting_time));
            }
        }
    }

    /**
     * Curry utility to create a closure that runs call() when called.
     *
     * @param {Array} info   An array containing [alias, keycode].
     */
    // Returns a closure function that actives a trigger when called
    function makeEventCall(info) {
        return function () {
            callEvent(info[0], info[1]);
        };
    }

    /**
     * Primary driver function to run an event. The event is chosen from the
     * triggers object, and calld with event_information as the input.
     *
     * @param {Function, String} event   The event function (or string alias of
     *                                   it) that will be called.
     * @param {Number} [keycode]   The alias of the event function under
     *                             triggers[event], if event is a String.
     * @return {Mixed}
     */
    function callEvent(event, keycode) {
        if(can_trigger && !can_trigger(event, keycode)) {
            return;
        }

        // If the event doesn't exist, ignore it
        if (!event) {
            console.warn("Blank event given, ignoring it.");
            return;
        }

        if (typeof (event) === "string" || event instanceof String) {
            event = triggers[event][keycode];
        }

        return event(event_information);
    }

    /**
     * Creates and returns a function to run a trigger.
     *
     * @param {String} trigger   The label for the Array of functions that the
     *                           pipe function should choose from.
     * @param {String} [code_label]   An optional mapping String for the alias:
     *                                if provided, it changes the alias to a
     *                                listed alias keyed by code_label.
     * @param {Boolean} [prevent_defaults]   Whether the input to the pipe
     *                                       function will be an HTML-style
     *                                       event, where .preventDefault()
     *                                       should be clicked.
     * @return {Function}
     * @example   Creating a function that calls an onKeyUp event, with a given
     *            input's keyCode being used as the code_label.
     *            InputWriter.makePipe("onkeyup", "keyCode");
     * @example   Creating a function that calls an onContextMenu event, and
     *            preventDefault of the argument.
     *            InputWriter.makePipe("oncontextmenu", null, true);
     */
    self.makePipe = function (trigger, code_label, prevent_defaults) {
        if (!triggers.hasOwnProperty(trigger)) {
            console.warn("No trigger of label '" + trigger + "' has been defined.");
            return;
        }

        var functions = triggers[trigger],
            use_label = arguments.length >= 2;

        return function Pipe(alias) {
            // Typical usage means alias will be an event from a key/mouse input
            if (prevent_defaults && alias.preventDefault instanceof Function) {
                alias.preventDefault();
            }

            // If a code_label is needed, replace the alias with it
            if (use_label) {
                alias = alias[code_label];
            }

            // If there's a function under that alias, run it
            if (functions.hasOwnProperty(alias)) {
                if (recording) {
                    history[Math.round(get_timestamp())] = [trigger, alias];
                }

                callEvent(functions[alias]);
            }
        }
    }

    self.reset(settings || {});
}<|endoftext|>


<commit_before>/* global L */
var $ = require('jquery');
var Backbone = require('backbone');
var Map = require('../../../../src/geo/map');
var LeafletMapView = require('../../../../src/geo/leaflet/leaflet-map-view');
var LeafletLayerViewFactory = require('../../../../src/geo/leaflet/leaflet-layer-view-factory');
var TorqueLayer = require('../../../../src/geo/map/torque-layer');
var SharedTestsForTorqueLayer = require('../shared-tests-for-torque-layer');

describe('geo/leaflet/leaflet-torque-layer-view', function () {
  beforeEach(function () {
    var container = $('<div>').css({
      'height': '200px',
      'width': '200px'
    });
    this.vis = jasmine.createSpyObj('vis', ['reload']);
    this.map = new Map();
    this.mapView = new LeafletMapView({
      el: container,
      map: this.map,
      layerViewFactory: new LeafletLayerViewFactory(),
      layerGroupModel: new Backbone.Model()
    });

    spyOn(L.TorqueLayer.prototype, 'initialize').and.callThrough();

    this.model = new TorqueLayer({
      type: 'torque',
      sql: 'select * from table',
      cartocss: '#test {}',
      dynamic_cdn: 'dynamic-cdn-value'
    }, { vis: this.vis });
    this.map.addLayer(this.model);
    this.view = this.mapView._layerViews[this.model.cid];
  });

  SharedTestsForTorqueLayer.call(this);

  it('should reuse layer view', function () {
    expect(this.view instanceof L.TorqueLayer).toEqual(true);

    this.view.check = 'testing';
    var newLayer = new TorqueLayer(this.view.model.attributes, {
      vis: this.vis
    });
    newLayer.set({ sql: 'select * from table', cartocss: '#test {}' });
    this.map.layers.reset([newLayer]);

    expect(this.mapView._layerViews[newLayer.cid] instanceof L.TorqueLayer).toEqual(true);
    expect(this.mapView._layerViews[newLayer.cid].model).toEqual(newLayer);
    expect(this.mapView._layerViews[newLayer.cid].check).toEqual('testing');
  });

  it('should apply Leaflet TorqueLayer initialize method on the extended view with a bunch of attrs', function () {
    expect(L.TorqueLayer.prototype.initialize).toHaveBeenCalled();

    var attrs = L.TorqueLayer.prototype.initialize.calls.argsFor(0)[0];
    expect(attrs.cartocss).toEqual(jasmine.any(String));
    expect(attrs.dynamic_cdn).toEqual('dynamic-cdn-value');
    expect(attrs.instanciateCallback).toEqual(jasmine.any(Function));
  });

  it("should update providers's templateURL when urls change", function () {
    this.model.set('tileURLTemplates', [
      'http://pepe.carto.com/{z}/{x}/{y}.torque',
      'http://juan.carto.com/{z}/{x}/{y}.torque'
    ]);

    expect(this.view.provider.templateUrl).toEqual('http://pepe.carto.com/{z}/{x}/{y}.torque');
  });
});
<commit_msg>Fixed tests for leaflet-torque-layer-view<commit_after>/* global L */
var $ = require('jquery');
var Backbone = require('backbone');
var Map = require('../../../../src/geo/map');
var LeafletMapView = require('../../../../src/geo/leaflet/leaflet-map-view');
var LeafletLayerViewFactory = require('../../../../src/geo/leaflet/leaflet-layer-view-factory');
var TorqueLayer = require('../../../../src/geo/map/torque-layer');
var SharedTestsForTorqueLayer = require('../shared-tests-for-torque-layer');

describe('geo/leaflet/leaflet-torque-layer-view', function () {
  beforeEach(function () {
    var container = $('<div>').css({
      'height': '200px',
      'width': '200px'
    });
    this.vis = jasmine.createSpyObj('vis', ['reload']);
    this.map = new Map();
    this.mapView = new LeafletMapView({
      el: container,
      map: this.map,
      layerViewFactory: new LeafletLayerViewFactory(),
      layerGroupModel: new Backbone.Model()
    });

    spyOn(L.TorqueLayer.prototype, 'initialize').and.callThrough();

    this.model = new TorqueLayer({
      type: 'torque',
      sql: 'select * from table',
      cartocss: 'Map {}',
      dynamic_cdn: 'dynamic-cdn-value'
    }, { vis: this.vis });
    this.map.addLayer(this.model);
    this.view = this.mapView._layerViews[this.model.cid];
  });

  SharedTestsForTorqueLayer.call(this);

  it('should reuse layer view', function () {
    expect(this.view instanceof L.TorqueLayer).toEqual(true);

    this.view.check = 'testing';
    var newLayer = new TorqueLayer(this.view.model.attributes, {
      vis: this.vis
    });
    newLayer.set({ sql: 'select * from table', cartocss: 'Map {}' });
    this.map.layers.reset([newLayer]);

    expect(this.mapView._layerViews[newLayer.cid] instanceof L.TorqueLayer).toEqual(true);
    expect(this.mapView._layerViews[newLayer.cid].model).toEqual(newLayer);
    expect(this.mapView._layerViews[newLayer.cid].check).toEqual('testing');
  });

  it('should apply Leaflet TorqueLayer initialize method on the extended view with a bunch of attrs', function () {
    expect(L.TorqueLayer.prototype.initialize).toHaveBeenCalled();

    var attrs = L.TorqueLayer.prototype.initialize.calls.argsFor(0)[0];
    expect(attrs.cartocss).toEqual(jasmine.any(String));
    expect(attrs.dynamic_cdn).toEqual('dynamic-cdn-value');
    expect(attrs.instanciateCallback).toEqual(jasmine.any(Function));
  });

  it("should update providers's templateURL when urls change", function () {
    this.model.set('tileURLTemplates', [
      'http://pepe.carto.com/{z}/{x}/{y}.torque',
      'http://juan.carto.com/{z}/{x}/{y}.torque'
    ]);

    expect(this.view.provider.templateUrl).toEqual('http://pepe.carto.com/{z}/{x}/{y}.torque');
  });
});
<|endoftext|>