<commit_before>const fs = require('fs');
const os = require('os');
const path = require('path');
const { spawn } = require('child_process');
const util = require('util');
const YAWN = require('yawn-yaml/cjs');

require('util.promisify/shim')();

const readFile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);

class PluginInstaller {
  constructor (options) {
    options = options || {};
    this.packageName = options.packageName || null;
    this.pluginManifest = options.pluginManifest || null;
    this.config = options.config;
  }

  static get PACKAGE_PREFIX () {
    return 'express-gateway-plugin-';
  }

  static create (options) {
    return new PluginInstaller(options);
  }

  runNPMInstallation ({ packageSpecifier, cwd, env }) {
    return new Promise((resolve, reject) => {
      // manually spawn npm
      // use --parseable flag to get tab-delimited output
      // forward sterr to process.stderr
      // capture stdout to get package name

      let pluginPath = null;

      const installArgs = [
        'install', packageSpecifier,
        '--cache-min', 24 * 60 * 60,
        '--parseable',
        '--save'
      ];

      const installOpts = {
        cwd: cwd || process.cwd(),
        env: env || process.env,
        stdio: ['ignore', 'pipe', 'inherit']
      };

      const npmCommand = os.platform() === 'win32' ? 'npm.cmd' : 'npm';
      const npmInstall = spawn(npmCommand, installArgs, installOpts);

      npmInstall.on('error', _ => {
        reject(new Error('Cannot install', packageSpecifier));
      });

      const bufs = [];
      let len = 0;
      npmInstall.stdout.on('readable', () => {
        const buf = npmInstall.stdout.read();

        if (buf) {
          bufs.push(buf);
          len += buf.length;
        }
      });

      npmInstall.stdout.on('end', () => {
        const lines = Buffer.concat(bufs, len)
          .toString()
          .trim()
          .split('\n');

        const line = lines[lines.length - 1];

        if (line.indexOf('\t') > -1) {
          // npm >= 5
          const output = lines[lines.length - 1].split('\t');

          if (output.length < 4) {
            reject(new Error('Cannot parse npm output while installing plugin.'));
            return;
          }

          this.packageName = output[1];
          pluginPath = path.join(cwd, output[3]);
        } else {
          // npm < 5
          this.packageName = path.basename(line);
          pluginPath = line;
        }
      });

      npmInstall.on('exit', () => {
        if (pluginPath) {
          this.pluginManifest = require(pluginPath);

          resolve({
            packageName: this.packageName,
            pluginManifest: this.pluginManifest
          });
        }
      });
    });
  }

  get existingPluginOptions () {
    const config = this.config || require('./config');
    const systemConfig = config.systemConfig;

    const name = this.pluginKey;

    const existingPluginOptions =
      systemConfig.plugins && systemConfig.plugins[name]
        ? systemConfig.plugins[name] : {};

    return existingPluginOptions;
  }

  get pluginKey () {
    let name = this.pluginManifest.name || this.packageName;

    if (!this.pluginManifest.name &&
      this.packageName.startsWith(PluginInstaller.PACKAGE_PREFIX)) {
      name = this.packageName.substr(PluginInstaller.PACKAGE_PREFIX.length);
    }

    return name;
  }

  updateConfigurationFiles ({
    pluginOptions,
    enablePlugin,
    addPoliciesToWhitelist }) {
    // WARNING (kevinswiber): Updating YAML while maintaining presentation
    // style is not easy.  We're using the YAWN library here, which has
    // a decent approach given the current state of available YAML parsers,
    // but it's far from perfect.  Take a look at existing YAWN issues
    // before making any optimizations.  If any section of this code looks
    // ugly or inefficient, it may be that way for a reason (or maybe not).
    //
    // ¯\_(ツ)_/¯
    //
    // https://github.com/mohsen1/yawn-yaml/issues

    if (!this.pluginManifest) {
      return Promise.reject(
        new Error('Configuration files require a plugin manifest.'));
    }

    let name = this.pluginManifest.name || this.packageName;

    if (!this.pluginManifest.name &&
      this.packageName.startsWith(PluginInstaller.PACKAGE_PREFIX)) {
      name = this.packageName.substr(PluginInstaller.PACKAGE_PREFIX.length);
    }

    const maybeWriteSystemConfig = () => {
      if (enablePlugin) {
        return this._generateSystemConfigData(name, pluginOptions)
          .then(({ systemConfigPath, output }) =>
            writeFile(systemConfigPath, output));
      }

      return Promise.resolve();
    };

    const maybeWriteGatewayConfig = () => {
      if (addPoliciesToWhitelist) {
        const policyNames = this.pluginManifest.policies || [];

        return this._generateGatewayConfigData(policyNames)
          .then(({ gatewayConfigPath, output }) =>
            writeFile(gatewayConfigPath, output));
      }

      return Promise.resolve();
    };

    return maybeWriteSystemConfig()
      .then(maybeWriteGatewayConfig);
  }

  _updateYAML (obj, yawn) {
    yawn.json = obj;
    return yawn.json;
  }

  _generateSystemConfigData (name, pluginOptions) {
    const config = this.config || require('./config');
    const isJSON = config.systemConfigPath.toLowerCase().endsWith('.json');
    const isYAML = !isJSON;

    return readFile(config.systemConfigPath)
      .then(systemConfig => {
        // YAML-specific variables
        let yawn = null;
        let oldLength = null;

        let obj = null;

        if (isYAML) {
          yawn = new YAWN(systemConfig.toString());
          obj = Object.assign({}, yawn.json);

          oldLength = obj.plugins ? null : yawn.yaml.length;
        } else {
          obj = JSON.parse(systemConfig.toString());
        }

        let plugins = obj.plugins || {};

        if (!plugins.hasOwnProperty(name)) {
          plugins[name] = {};
        }

        plugins[name].package = this.packageName;
        obj.plugins = plugins;

        if (isYAML) {
          obj = this._updateYAML(obj, yawn);
        }

        if (pluginOptions) {
          // YAWN needs to be updated by smallest atomic unit
          Object.keys(pluginOptions).forEach(key => {
            plugins[name][key] = pluginOptions[key];
            obj.plugins = plugins;

            if (isYAML) {
              obj = this._updateYAML(obj, yawn);
              plugins = obj.plugins;
            }
          });
        }

        if (isYAML && oldLength) {
          // add a line break before inserting a new plugins mapping
          yawn.yaml = yawn.yaml.substr(0, oldLength) + os.EOL +
            yawn.yaml.substr(oldLength);
        }

        const output = isYAML ? yawn.yaml.trim() : JSON.stringify(obj, null, 2);

        return {
          systemConfigPath: config.systemConfigPath,
          output
        };
      });
  }

  _generateGatewayConfigData (policyNames) {
    const config = this.config || require('./config');
    const isJSON =
      config.gatewayConfigPath.toLowerCase().endsWith('.json');
    const isYAML = !isJSON;

    return readFile(config.gatewayConfigPath)
      .then(gatewayConfig => {
        // YAML-specific variable
        let yawn = null;

        let obj = null;

        if (isYAML) {
          yawn = new YAWN(gatewayConfig.toString());
          obj = Object.assign({}, yawn.json);
        } else {
          obj = JSON.parse(gatewayConfig.toString());
        }

        const policies = obj.policies || [];

        // YAWN reverses arrays.  ¯\_(ツ)_/¯
        const correctedPolicyNames = isYAML ? policyNames.reverse() : policyNames;

        correctedPolicyNames.forEach(policy => {
          if (policies.indexOf(policy) === -1) {
            policies.push(policy);
          }
        });

        obj.policies = policies;

        if (isYAML) {
          yawn.json = obj;
        }

        const output = isYAML ? yawn.yaml.trim() : JSON.stringify(obj, null, 2);

        return {
          gatewayConfigPath: config.gatewayConfigPath,
          output
        };
      });
  }
}

module.exports = PluginInstaller;
<commit_msg>Correctly set indexes for substring manipulations.<commit_after>const fs = require('fs');
const os = require('os');
const path = require('path');
const { spawn } = require('child_process');
const util = require('util');
const YAWN = require('yawn-yaml/cjs');

require('util.promisify/shim')();

const readFile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);

class PluginInstaller {
  constructor (options) {
    options = options || {};
    this.packageName = options.packageName || null;
    this.pluginManifest = options.pluginManifest || null;
    this.config = options.config;
  }

  static get PACKAGE_PREFIX () {
    return 'express-gateway-plugin-';
  }

  static create (options) {
    return new PluginInstaller(options);
  }

  runNPMInstallation ({ packageSpecifier, cwd, env }) {
    return new Promise((resolve, reject) => {
      // manually spawn npm
      // use --parseable flag to get tab-delimited output
      // forward sterr to process.stderr
      // capture stdout to get package name

      let pluginPath = null;

      const installArgs = [
        'install', packageSpecifier,
        '--cache-min', 24 * 60 * 60,
        '--parseable',
        '--save'
      ];

      const installOpts = {
        cwd: cwd || process.cwd(),
        env: env || process.env,
        stdio: ['ignore', 'pipe', 'inherit']
      };

      const npmCommand = os.platform() === 'win32' ? 'npm.cmd' : 'npm';
      const npmInstall = spawn(npmCommand, installArgs, installOpts);

      npmInstall.on('error', _ => {
        reject(new Error('Cannot install', packageSpecifier));
      });

      const bufs = [];
      let len = 0;
      npmInstall.stdout.on('readable', () => {
        const buf = npmInstall.stdout.read();

        if (buf) {
          bufs.push(buf);
          len += buf.length;
        }
      });

      npmInstall.stdout.on('end', () => {
        const lines = Buffer.concat(bufs, len)
          .toString()
          .trim()
          .split('\n');

        const line = lines[lines.length - 1];

        if (line.indexOf('\t') > -1) {
          // npm >= 5
          const output = lines[lines.length - 1].split('\t');

          if (output.length < 4) {
            reject(new Error('Cannot parse npm output while installing plugin.'));
            return;
          }

          this.packageName = output[1];
          pluginPath = path.join(cwd, output[3]);
        } else {
          // npm < 5
          this.packageName = path.basename(line);
          pluginPath = line;
        }
      });

      npmInstall.on('exit', () => {
        if (pluginPath) {
          this.pluginManifest = require(pluginPath);

          resolve({
            packageName: this.packageName,
            pluginManifest: this.pluginManifest
          });
        }
      });
    });
  }

  get existingPluginOptions () {
    const config = this.config || require('./config');
    const systemConfig = config.systemConfig;

    const name = this.pluginKey;

    const existingPluginOptions =
      systemConfig.plugins && systemConfig.plugins[name]
        ? systemConfig.plugins[name] : {};

    return existingPluginOptions;
  }

  get pluginKey () {
    let name = this.pluginManifest.name || this.packageName;

    if (!this.pluginManifest.name &&
      this.packageName.startsWith(PluginInstaller.PACKAGE_PREFIX)) {
      name = this.packageName.substr(PluginInstaller.PACKAGE_PREFIX.length);
    }

    return name;
  }

  updateConfigurationFiles ({
    pluginOptions,
    enablePlugin,
    addPoliciesToWhitelist }) {
    // WARNING (kevinswiber): Updating YAML while maintaining presentation
    // style is not easy.  We're using the YAWN library here, which has
    // a decent approach given the current state of available YAML parsers,
    // but it's far from perfect.  Take a look at existing YAWN issues
    // before making any optimizations.  If any section of this code looks
    // ugly or inefficient, it may be that way for a reason (or maybe not).
    //
    // ¯\_(ツ)_/¯
    //
    // https://github.com/mohsen1/yawn-yaml/issues

    if (!this.pluginManifest) {
      return Promise.reject(
        new Error('Configuration files require a plugin manifest.'));
    }

    let name = this.pluginManifest.name || this.packageName;

    if (!this.pluginManifest.name &&
      this.packageName.startsWith(PluginInstaller.PACKAGE_PREFIX)) {
      name = this.packageName.substr(PluginInstaller.PACKAGE_PREFIX.length);
    }

    const maybeWriteSystemConfig = () => {
      if (enablePlugin) {
        return this._generateSystemConfigData(name, pluginOptions)
          .then(({ systemConfigPath, output }) =>
            writeFile(systemConfigPath, output));
      }

      return Promise.resolve();
    };

    const maybeWriteGatewayConfig = () => {
      if (addPoliciesToWhitelist) {
        const policyNames = this.pluginManifest.policies || [];

        return this._generateGatewayConfigData(policyNames)
          .then(({ gatewayConfigPath, output }) =>
            writeFile(gatewayConfigPath, output));
      }

      return Promise.resolve();
    };

    return maybeWriteSystemConfig()
      .then(maybeWriteGatewayConfig);
  }

  _updateYAML (obj, yawn) {
    yawn.json = obj;
    return yawn.json;
  }

  _generateSystemConfigData (name, pluginOptions) {
    const config = this.config || require('./config');
    const isJSON = config.systemConfigPath.toLowerCase().endsWith('.json');
    const isYAML = !isJSON;

    return readFile(config.systemConfigPath)
      .then(systemConfig => {
        // YAML-specific variables
        let yawn = null;
        let oldLength = null;

        let obj = null;

        if (isYAML) {
          yawn = new YAWN(systemConfig.toString());
          obj = Object.assign({}, yawn.json);

          oldLength = obj.plugins ? null : yawn.yaml.length;
        } else {
          obj = JSON.parse(systemConfig.toString());
        }

        let plugins = obj.plugins || {};

        if (!plugins.hasOwnProperty(name)) {
          plugins[name] = {};
        }

        plugins[name].package = this.packageName;
        obj.plugins = plugins;

        if (isYAML) {
          obj = this._updateYAML(obj, yawn);
        }

        if (pluginOptions) {
          // YAWN needs to be updated by smallest atomic unit
          Object.keys(pluginOptions).forEach(key => {
            plugins[name][key] = pluginOptions[key];
            obj.plugins = plugins;

            if (isYAML) {
              obj = this._updateYAML(obj, yawn);
              plugins = obj.plugins;
            }
          });
        }

        if (isYAML && oldLength) {
          // add a line break before inserting a new plugins mapping
          yawn.yaml = yawn.yaml.substr(0, oldLength - 1) + os.EOL + yawn.yaml.substr(oldLength - 1);
        }

        const output = isYAML ? yawn.yaml.trim() : JSON.stringify(obj, null, 2);

        return {
          systemConfigPath: config.systemConfigPath,
          output
        };
      });
  }

  _generateGatewayConfigData (policyNames) {
    const config = this.config || require('./config');
    const isJSON =
      config.gatewayConfigPath.toLowerCase().endsWith('.json');
    const isYAML = !isJSON;

    return readFile(config.gatewayConfigPath)
      .then(gatewayConfig => {
        // YAML-specific variable
        let yawn = null;

        let obj = null;

        if (isYAML) {
          yawn = new YAWN(gatewayConfig.toString());
          obj = Object.assign({}, yawn.json);
        } else {
          obj = JSON.parse(gatewayConfig.toString());
        }

        const policies = obj.policies || [];

        // YAWN reverses arrays.  ¯\_(ツ)_/¯
        const correctedPolicyNames = isYAML ? policyNames.reverse() : policyNames;

        correctedPolicyNames.forEach(policy => {
          if (policies.indexOf(policy) === -1) {
            policies.push(policy);
          }
        });

        obj.policies = policies;

        if (isYAML) {
          yawn.json = obj;
        }

        const output = isYAML ? yawn.yaml.trim() : JSON.stringify(obj, null, 2);

        return {
          gatewayConfigPath: config.gatewayConfigPath,
          output
        };
      });
  }
}

module.exports = PluginInstaller;
<|endoftext|>


<commit_before>var assert = require('assert');
var t = require('../tcomb');

var Nil = t.Nil;
var Bool = t.Bool;
var Num = t.Num;
var Str = t.Str;
var Arr = t.Arr;
var Obj = t.Obj;
var Func = t.Func;
var Err = t.Err;
var struct = t.struct;
var enums = t.enums;
var union = t.union;
var tuple = t.tuple;
var maybe = t.maybe;
var subtype = t.subtype;
var func = t.func;

//
// setup
//

var ok = function (x) { assert.strictEqual(true, x); };
var ko = function (x) { assert.strictEqual(false, x); };
var throws = assert.throws;

// structs
var Point = struct({
    x: Num,
    y: Num
}, 'Point');

// enums
var Direction = enums({
    North: 0,
    East: 1,
    South: 2,
    West: 3
}, 'Direction');

// unions
var Circle = struct({
    center: Point,
    radius: Num
});

var Rectangle = struct({
    a: Point,
    b: Point
});

var Shape = union([Circle, Rectangle], 'Shape');

Shape.dispatch = function (values) {
    assert(Obj.is(values));
    return values.hasOwnProperty('center') ?
        Circle :
        Rectangle;
};

// tuples
var Numbers = tuple([Num, Num]);

// funcs
var sum = func(tuple([Num, Num]), function (a, b) {
    return a + b;
}, Num);

//
// basic types specs
//

describe('Nil', function(){
    describe('#is(x)', function(){
        it('should return true when x is null or undefined', function() {
            ok(Nil.is(null));
            ok(Nil.is(undefined));
        });
        it('should return false when x is neither null nor undefined', function() {
            ko(Nil.is(0));
            ko(Nil.is(true));
            ko(Nil.is(''));
            ko(Nil.is([]));
            ko(Nil.is({}));
            ko(Nil.is(function () {}));
            ko(Nil.is(/a/));
            ko(Nil.is(new RegExp('a')));
        });
    });
});

describe('Bool', function(){
    describe('#is(x)', function(){
        it('should return true when x is true or false', function() {
            ok(Bool.is(true));
            ok(Bool.is(false));
        });
        it('should return false when x is neither true nor false', function() {
            ko(Bool.is(null));
            ko(Bool.is(undefined));
            ko(Bool.is(0));
            ko(Bool.is(''));
            ko(Bool.is([]));
            ko(Bool.is({}));
            ko(Bool.is(function () {}));
            ko(Bool.is(/a/));
            ko(Bool.is(new RegExp('a')));
        });
    });
});

describe('Num', function(){
    describe('#is(x)', function(){
        it('should return true when x is a number', function() {
            ok(Num.is(0));
            ok(Num.is(1));
            ko(Num.is(new Number(1)));
        });
        it('should return false when x is not a number', function() {
            ko(Num.is(NaN));
            ko(Num.is(Infinity));
            ko(Num.is(-Infinity));
            ko(Num.is(null));
            ko(Num.is(undefined));
            ko(Num.is(true));
            ko(Num.is(''));
            ko(Num.is([]));
            ko(Num.is({}));
            ko(Num.is(function () {}));
            ko(Num.is(/a/));
            ko(Num.is(new RegExp('a')));
        });
    });
});

describe('Str', function(){
    describe('#is(x)', function(){
        it('should return true when x is a string', function() {
            ok(Str.is(''));
            ok(Str.is('a'));
            ko(Str.is(new String('a')));
        });
        it('should return false when x is not a string', function() {
            ko(Str.is(NaN));
            ko(Str.is(Infinity));
            ko(Str.is(-Infinity));
            ko(Str.is(null));
            ko(Str.is(undefined));
            ko(Str.is(true));
            ko(Str.is(1));
            ko(Str.is([]));
            ko(Str.is({}));
            ko(Str.is(function () {}));
            ko(Str.is(/a/));
            ko(Str.is(new RegExp('a')));
        });
    });
});

describe('Arr', function(){
    describe('#is(x)', function(){
        it('should return true when x is an array', function() {
            ok(Arr.is([]));
        });
        it('should return false when x is not an array', function() {
            ko(Arr.is(NaN));
            ko(Arr.is(Infinity));
            ko(Arr.is(-Infinity));
            ko(Arr.is(null));
            ko(Arr.is(undefined));
            ko(Arr.is(true));
            ko(Arr.is(1));
            ko(Arr.is('a'));
            ko(Arr.is({}));
            ko(Arr.is(function () {}));
            ko(Arr.is(/a/));
            ko(Arr.is(new RegExp('a')));
        });
    });
});

describe('Obj', function(){
    describe('#is(x)', function(){
        it('should return true when x is an object literal', function() {
            ok(Obj.is({}));
        });
        it('should return false when x is not an object literal', function() {
            ko(Obj.is(null));
            ko(Obj.is(undefined));
            ko(Obj.is(0));
            ko(Obj.is(''));
            ko(Obj.is([]));
            ko(Obj.is(function () {}));
            ko(Obj.is(new String('1')));
            ko(Obj.is(new Number(1)));
            ko(Obj.is(new Boolean()));
            ko(Obj.is(/a/));
            ko(Obj.is(new RegExp('a')));
        });
    });
});

describe('Func', function(){
    describe('#is(x)', function(){
        it('should return true when x is a function', function() {
            ok(Func.is(function () {}));
            ok(Func.is(new Function()));
        });
        it('should return false when x is not a function', function() {
            ko(Func.is(null));
            ko(Func.is(undefined));
            ko(Func.is(0));
            ko(Func.is(''));
            ko(Func.is([]));
            ko(Func.is(new String('1')));
            ko(Func.is(new Number(1)));
            ko(Func.is(new Boolean()));
            ko(Func.is(/a/));
            ko(Func.is(new RegExp('a')));
        });
    });
});

//
// type combinators specs
//

describe('struct', function(){
    describe('#is(x)', function(){

        it('should return true when x is an instance of the struct', function() {
            var p = new Point({ x: 1, y: 2 });
            ok(Point.is(p));
        });

    });
});

describe('enum', function(){
    describe('#is(x)', function(){
        it('should return true when x is an instance of the enum', function() {
            ok(Direction.is('North'));
        });
        it("should return false when x is not an instance of the enum", function() {
            ko(Direction.is('North-East'));
        });
    });
});

describe('union', function(){
    describe('#is(x)', function(){
        it('should return true when x is an instance of the union', function() {
            var p = new Circle({center: { x: 0, y: 0 }, radius: 10});
            ok(Shape.is(p));
        });
    });
    describe('Shape constructor', function(){
        it('should be used to buils instances', function() {

        });
    });
});

describe('tuple', function(){
    describe('#is(x)', function(){
        it('should return true when x is an instance of the tuple', function() {
            ok(Numbers.is([1, 2]));
        });
        it("should return false when x is not an instance of the tuple", function() {
            ko(Numbers.is([1]));
            ko(Numbers.is([1, 2, 3]));
            ko(Numbers.is([1, 'a']));
        });
    });
});

describe('func', function(){
    describe('#is(x)', function(){
        it('should return true when x is the func', function() {
            ok(sum.is(sum));
            ok(sum(1, 2) === 3);
        });
        it("should return false when x is not the func", function() {
            ko(sum.is(function () {}));
        });
        it("should throw with wrong arguments", function() {
            throws(function () {
                sum(1, 'a');
            });
        });
        it("should throw with wrong return", function() {
            var bad = func(tuple([Num, Num]), function (a, b) {
                return a + String(b);
            }, Num);
            throws(function () {
                bad(1, 2);
            });
        });
        it("Return should be optional", function() {
            var bad = func(tuple([Num, Num]), function (a, b) {
                return a + String(b);
            });
            ok(bad(1, 2) === '12');
        });
        it("should handle optional arguments", function() {
            var sum3 = func(tuple([Num, Num, maybe(Num)]), function (a, b, c) {
                return a + b + (c || 0);
            }, Num);
            ok(sum3(1, 2, 3) === 6);
            ok(sum3(1, 2) === 3);
        });
    });
});

describe('generics', function(){
    // generic Either A B
    var Either = function (A, B) {
        return subtype(tuple([maybe(A), maybe(B)]), function (x) {
            return Nil.is(x[0]) !== Nil.is(x[1]);
        });
    };
    // node.js style callback
    var CallbackArguments = Either(Err, Obj);
    it('should return true when x is an instance of CallbackArguments', function() {
        ok(CallbackArguments.is([null, {}]));
        ok(CallbackArguments.is([new Error(), null]));
    });
    it('should return false when x is not an instance of CallbackArguments', function() {
        ko(CallbackArguments.is([null, null]));
    });
});

<commit_msg>Err tests<commit_after>var assert = require('assert');
var t = require('../tcomb');

var Nil = t.Nil;
var Bool = t.Bool;
var Num = t.Num;
var Str = t.Str;
var Arr = t.Arr;
var Obj = t.Obj;
var Func = t.Func;
var Err = t.Err;
var struct = t.struct;
var enums = t.enums;
var union = t.union;
var tuple = t.tuple;
var maybe = t.maybe;
var subtype = t.subtype;
var func = t.func;

//
// setup
//

var ok = function (x) { assert.strictEqual(true, x); };
var ko = function (x) { assert.strictEqual(false, x); };
var throws = assert.throws;

// structs
var Point = struct({
    x: Num,
    y: Num
}, 'Point');

// enums
var Direction = enums({
    North: 0,
    East: 1,
    South: 2,
    West: 3
}, 'Direction');

// unions
var Circle = struct({
    center: Point,
    radius: Num
});

var Rectangle = struct({
    a: Point,
    b: Point
});

var Shape = union([Circle, Rectangle], 'Shape');

Shape.dispatch = function (values) {
    assert(Obj.is(values));
    return values.hasOwnProperty('center') ?
        Circle :
        Rectangle;
};

// tuples
var Numbers = tuple([Num, Num]);

// funcs
var sum = func(tuple([Num, Num]), function (a, b) {
    return a + b;
}, Num);

//
// primitives types
//

describe('Nil', function(){
    describe('#is(x)', function(){
        it('should return true when x is null or undefined', function() {
            ok(Nil.is(null));
            ok(Nil.is(undefined));
        });
        it('should return false when x is neither null nor undefined', function() {
            ko(Nil.is(0));
            ko(Nil.is(true));
            ko(Nil.is(''));
            ko(Nil.is([]));
            ko(Nil.is({}));
            ko(Nil.is(function () {}));
            ko(Nil.is(/a/));
            ko(Nil.is(new RegExp('a')));
            ko(Nil.is(new Error()));
        });
    });
});

describe('Bool', function(){
    describe('#is(x)', function(){
        it('should return true when x is true or false', function() {
            ok(Bool.is(true));
            ok(Bool.is(false));
        });
        it('should return false when x is neither true nor false', function() {
            ko(Bool.is(null));
            ko(Bool.is(undefined));
            ko(Bool.is(0));
            ko(Bool.is(''));
            ko(Bool.is([]));
            ko(Bool.is({}));
            ko(Bool.is(function () {}));
            ko(Bool.is(/a/));
            ko(Bool.is(new RegExp('a')));
            ko(Bool.is(new Error()));
        });
    });
});

describe('Num', function(){
    describe('#is(x)', function(){
        it('should return true when x is a number', function() {
            ok(Num.is(0));
            ok(Num.is(1));
            ko(Num.is(new Number(1)));
        });
        it('should return false when x is not a number', function() {
            ko(Num.is(NaN));
            ko(Num.is(Infinity));
            ko(Num.is(-Infinity));
            ko(Num.is(null));
            ko(Num.is(undefined));
            ko(Num.is(true));
            ko(Num.is(''));
            ko(Num.is([]));
            ko(Num.is({}));
            ko(Num.is(function () {}));
            ko(Num.is(/a/));
            ko(Num.is(new RegExp('a')));
            ko(Num.is(new Error()));
        });
    });
});

describe('Str', function(){
    describe('#is(x)', function(){
        it('should return true when x is a string', function() {
            ok(Str.is(''));
            ok(Str.is('a'));
            ko(Str.is(new String('a')));
        });
        it('should return false when x is not a string', function() {
            ko(Str.is(NaN));
            ko(Str.is(Infinity));
            ko(Str.is(-Infinity));
            ko(Str.is(null));
            ko(Str.is(undefined));
            ko(Str.is(true));
            ko(Str.is(1));
            ko(Str.is([]));
            ko(Str.is({}));
            ko(Str.is(function () {}));
            ko(Str.is(/a/));
            ko(Str.is(new RegExp('a')));
            ko(Str.is(new Error()));
        });
    });
});

describe('Arr', function(){
    describe('#is(x)', function(){
        it('should return true when x is an array', function() {
            ok(Arr.is([]));
        });
        it('should return false when x is not an array', function() {
            ko(Arr.is(NaN));
            ko(Arr.is(Infinity));
            ko(Arr.is(-Infinity));
            ko(Arr.is(null));
            ko(Arr.is(undefined));
            ko(Arr.is(true));
            ko(Arr.is(1));
            ko(Arr.is('a'));
            ko(Arr.is({}));
            ko(Arr.is(function () {}));
            ko(Arr.is(/a/));
            ko(Arr.is(new RegExp('a')));
            ko(Arr.is(new Error()));
        });
    });
});

describe('Obj', function(){
    describe('#is(x)', function(){
        it('should return true when x is an object literal', function() {
            ok(Obj.is({}));
        });
        it('should return false when x is not an object literal', function() {
            ko(Obj.is(null));
            ko(Obj.is(undefined));
            ko(Obj.is(0));
            ko(Obj.is(''));
            ko(Obj.is([]));
            ko(Obj.is(function () {}));
            ko(Obj.is(new String('1')));
            ko(Obj.is(new Number(1)));
            ko(Obj.is(new Boolean()));
            ko(Obj.is(/a/));
            ko(Obj.is(new RegExp('a')));
            ko(Obj.is(new Error()));
        });
    });
});

describe('Func', function(){
    describe('#is(x)', function(){
        it('should return true when x is a function', function() {
            ok(Func.is(function () {}));
            ok(Func.is(new Function()));
        });
        it('should return false when x is not a function', function() {
            ko(Func.is(null));
            ko(Func.is(undefined));
            ko(Func.is(0));
            ko(Func.is(''));
            ko(Func.is([]));
            ko(Func.is(new String('1')));
            ko(Func.is(new Number(1)));
            ko(Func.is(new Boolean()));
            ko(Func.is(/a/));
            ko(Func.is(new RegExp('a')));
            ko(Func.is(new Error()));
        });
    });
});

describe('Err', function(){
    describe('#is(x)', function(){
        it('should return true when x is a function', function() {
            ok(Err.is(new Error()));
        });
        it('should return false when x is not a function', function() {
            ko(Err.is(null));
            ko(Err.is(undefined));
            ko(Err.is(0));
            ko(Err.is(''));
            ko(Err.is([]));
            ko(Err.is(new String('1')));
            ko(Err.is(new Number(1)));
            ko(Err.is(new Boolean()));
            ko(Err.is(/a/));
            ko(Err.is(new RegExp('a')));
        });
    });
});

//
// struct
//

describe('struct', function(){
    describe('#is(x)', function(){

        it('should return true when x is an instance of the struct', function() {
            var p = new Point({ x: 1, y: 2 });
            ok(Point.is(p));
        });

    });
});

//
// enum
//

describe('enum', function(){
    describe('#is(x)', function(){
        it('should return true when x is an instance of the enum', function() {
            ok(Direction.is('North'));
        });
        it("should return false when x is not an instance of the enum", function() {
            ko(Direction.is('North-East'));
        });
    });
});

//
// union
//

describe('union', function(){
    describe('#is(x)', function(){
        it('should return true when x is an instance of the union', function() {
            var p = new Circle({center: { x: 0, y: 0 }, radius: 10});
            ok(Shape.is(p));
        });
    });
    describe('Shape constructor', function(){
        it('should be used to buils instances', function() {

        });
    });
});

//
// tuple
//

describe('tuple', function(){
    describe('#is(x)', function(){
        it('should return true when x is an instance of the tuple', function() {
            ok(Numbers.is([1, 2]));
        });
        it("should return false when x is not an instance of the tuple", function() {
            ko(Numbers.is([1]));
            ko(Numbers.is([1, 2, 3]));
            ko(Numbers.is([1, 'a']));
        });
    });
});

//
// func (experimental)
//

describe('func', function(){
    describe('#is(x)', function(){
        it('should return true when x is the func', function() {
            ok(sum.is(sum));
            ok(sum(1, 2) === 3);
        });
        it("should return false when x is not the func", function() {
            ko(sum.is(function () {}));
        });
        it("should throw with wrong arguments", function() {
            throws(function () {
                sum(1, 'a');
            });
        });
        it("should throw with wrong return", function() {
            var bad = func(tuple([Num, Num]), function (a, b) {
                return a + String(b);
            }, Num);
            throws(function () {
                bad(1, 2);
            });
        });
        it("Return should be optional", function() {
            var bad = func(tuple([Num, Num]), function (a, b) {
                return a + String(b);
            });
            ok(bad(1, 2) === '12');
        });
        it("should handle optional arguments", function() {
            var sum3 = func(tuple([Num, Num, maybe(Num)]), function (a, b, c) {
                return a + b + (c || 0);
            }, Num);
            ok(sum3(1, 2, 3) === 6);
            ok(sum3(1, 2) === 3);
        });
    });
});

describe('generics', function(){
    // generic Either A B
    var Either = function (A, B) {
        return subtype(tuple([maybe(A), maybe(B)]), function (x) {
            return Nil.is(x[0]) !== Nil.is(x[1]);
        });
    };
    // node.js style callback
    var CallbackArguments = Either(Err, Obj);
    it('should return true when x is an instance of CallbackArguments', function() {
        ok(CallbackArguments.is([null, {}]));
        ok(CallbackArguments.is([new Error(), null]));
    });
    it('should return false when x is not an instance of CallbackArguments', function() {
        ko(CallbackArguments.is([null, null]));
    });
});

<|endoftext|>


<commit_before>var config = require('config');
var mapModule = require('map');
var plugins = require('./leaflet_plugins');
var polyUtil = require('./polyline_encoded.js');
var routeboxer = require('./leaflet_routeboxer.js');
var leaflet_label = require('./leaflet_label/leaflet.label-src.js');
var collision = require('./leaflet_layergroup_collision.js');
var session = require('session');

var center = config.geocode().center.split(',').map(parseFloat)
if (config.map_provider && config.map_provider() !== 'AmigoCloud') {
  L.mapbox.accessToken = config.mapbox_access_token();
}

module.exports = function(el) {
  var map, realtime, southWest, northEast, blurLayer;

  if (config.map_provider && config.map_provider() === 'AmigoCloud') {
    southWest = L.latLng(35.946877085397,-123.480610897013);
    northEast = L.latLng(40.763279543715,-118.789317362500);
    map = (new L.amigo.map(el, {
      amigoLogo: 'right',
      loadAmigoLayers: false,
      inertia: false,
      zoomAnimation: $('.hide-map').css('display') !== 'none',
      maxBounds: L.latLngBounds(southWest, northEast),
      minZoom: 8
    })).setView([center[1], center[0]], config.geocode().zoom);

    L.amigo.auth.setToken(config.support_data_token());

    blurLayer = L.tileLayer(
    'https://www.amigocloud.com/api/v1/users/'+
	'23/projects/3019/datasets/23835/tiles/{z}/{x}/{y}.png?' +
	'token=' + config.support_data_token(),
      {
        name: 'Uncovered Area'
      }
    );

    map.addAuthLayer({
      id: config.mapbox_map_id(),
      accessToken: config.mapbox_access_token(),
      name: 'Gray',
      provider: 'mapbox'
    });
    map.addBaseLayer(L.amigo.AmigoGray);
    map.layersControl.addBaseLayer(
      L.bingLayer(
        config.bing_key(),
	{
	  type: 'Road',
	  attribution: 'Bing Maps'
	}
      ),
      'Bing Road'
    );
    map.layersControl.addOverlay(blurLayer);
    blurLayer.addTo(map);

    module.exports.activeMap = map;

    map.realtimeControl = L.control.toggleRealTime().addTo(map);

    realtime = mapModule.realtime();

  } else {

    map = L.mapbox.map(el, config.mapbox_map_id(), {
      attributionControl: false,
      inertia: false,
      zoomAnimation: false
    }).setView([center[1], center[0]], config.geocode().zoom);
  }

  return map;
};

module.exports.getMap = function () {
  return this.activeMap;
};

module.exports.cleanRoute = function() {
    module.exports.activeRoute.removeLayer();
    module.exports.activeRoute = null;
};

module.exports.polyline_creadas = [];
module.exports.marker_creadas = [];
module.exports.makerpoint_creadas = [];
module.exports.collision_group = {};
module.exports.marker_collision_group = [];

module.exports.drawMakerCollision = function () {
    var collision_group = L.layerGroup.collision({margin:5});
    collision_group.addLayer(this.marker_collision_group);
    console.log("final -> collision_group", collision_group);
    collision_group.addTo(this.activeMap).eachLayer(function(layer){layer.showLabel()});
};

module.exports.getpolyline_creadas = function () {
  return this.polyline_creadas;
};

module.exports.getMarker_creadas = function () {
  return this.marker_creadas;
};

module.exports.cleanPolyline = function() {
    var polyline_creadas = this.getpolyline_creadas();
    var map = this.activeMap;
    for (i in polyline_creadas) {
        try {
                map.removeLayer(polyline_creadas[i]);

            } catch (e) {
                console.log("problema al eliminar " + e);
            }

  }
  this.polyline_creadas = [];

};

module.exports.cleanMarker = function() {
    var map = this.activeMap;
    for (i in this.marker_creadas) {
        try {
                map.removeLayer(this.marker_creadas[i]);

            } catch (e) {
                console.log("problema al eliminar " + e);
            }
    }

  this.marker_creadas = [];

};

module.exports.cleanMarkerpoint = function() {
    var map = this.activeMap;
    for (i in this.makerpoint_creadas) {
        try {
                map.removeLayer(this.makerpoint_creadas[i]);

            } catch (e) {
                console.log("problema al eliminar " + e);
            }
    }

  this.makerpoint_creadas = [];

};

module.exports.marker_map = function(from, to){
     var IconStart = L.icon({
        iconUrl: 'assets/images/graphics/start.svg',
        iconSize: [40, 55],
        iconAnchor: [20, 50],
        popupAnchor:  [0, -50]
    });
    var IconEnd = L.icon({
        iconUrl: 'assets/images/graphics/end.svg',
        iconSize: [40, 55],
        iconAnchor: [20, 50],
        popupAnchor:  [0, -50]
    });

    var markerform = new L.marker([from[0],from[1]], {icon: IconStart, draggable: true})
        .addTo(this.activeMap);
    var markerto = new L.marker([to[0],to[1]], {icon: IconEnd, draggable: true})
        .addTo(this.activeMap);
    var _this = this;

    markerform.on('dragend', function(e){
       var marker = e.target;
       var result = marker.getLatLng();
       _this.cleanPolyline();
       _this.cleanMarkerpoint();
       var plan = session.plan();

            plan.setAddress('from', result.lng + ',' + result.lat, function(err, rees) {
                plan.updateRoutes();
          });
    });

    markerto.on('dragend', function(e){
       var marker = e.target;
       var result = marker.getLatLng();
       _this.cleanPolyline();
       _this.cleanMarkerpoint();
       var plan = session.plan();
            plan.setAddress('to', result.lng + ',' + result.lat, function(err, rees) {
                plan.updateRoutes();
          });
    });

    this.marker_creadas.push(markerform);
    this.marker_creadas.push(markerto);
};

module.exports.marker_map_point = function(to, map){

    var name = to[2];

    var IconEnd = L.icon({
        iconUrl: 'assets/images/graphics/icono.png',
        iconSize: [20, 20],
        iconAnchor: [0, 0],
        popupAnchor:  [-3, -76]
    });

    var markers = [
      L.marker([to[0], to[1]], {icon: IconEnd}).bindLabel(name)
    ];

    var marker = L.marker([to[0], to[1]], {icon: IconEnd}).bindLabel(name);

    //var layer = L.layerGroup(markers).addTo(map).eachLayer(function(layer){layer.showLabel()});

    //console.log("antes del marker ->", this.collision_group);
    //this.collision_group.addLayer(marker);
    //console.log("inserto marker->", marker);
    //console.log("despues del marker ->", this.collision_group);
    //console.log("group ->", L.layerGroup(markers));

    //this.makerpoint_creadas.push(layer);

    //var collision_group = L.layerGroup.collision({margin:5});
    //collision_group.addLayer(marker);
    //collision_group.onAdd(this.activeMap);
    //this.collision_group = collision_group;
    //console.log("collision_group -> ",collision_group);
    //this.marker_collision_group.push(marker);

    this.marker_collision_group.push(marker);
};

module.exports.drawRouteAmigo = function(legs,mode) {

    var route = legs.legGeometry.points;
    var circle_from = [legs.from.lat, legs.from.lon, legs.from.name];
    var circle_to = [legs.to.lat, legs.to.lon, legs.to.name];
    var color = '#000';
    var weight = 5;
    var dasharray= '';

        if (mode=="CAR") {
            color = '#9E9E9E';
            dasharray= '6';
            weight = 3;

        }else if(mode=="BICYCLE") {
            color = '#FF0000';
            if(!(legs.routeColor === undefined)) {
                color = "#"+legs.routeColor;
             }
            dasharray= '6';
            weight = 3;

        }else if(mode=="SUBWAY" || mode=="RAIL") {
             if(!(legs.routeColor === undefined)) {
                if (legs.routeColor != "" || legs.routeColor.length == 6) {
                    color = "#"+legs.routeColor;
                }

             }
             weight = 8;
             console.log("circle from ->", circle_from);
             console.log("circle to ->", circle_to);
             this.marker_map_point(circle_from, this.activeMap);
             this.marker_map_point(circle_to, this.activeMap);

        }
        else if(mode == "WALK") {
            color = '#0BC8F4';
            dasharray= '6';
             weight = 3;
        }

        else if(mode=="BUS") {
            //color = '#FEF0B5';
            if(!(legs.routeColor === undefined)) {
                if (legs.routeColor != "" || legs.routeColor.length == 6) {
                    color = "#"+legs.routeColor;
                }
             }
             weight = 5;
             console.log("circle from ->", circle_from);
             console.log("circle to ->", circle_to);
             this.marker_map_point(circle_from, this.activeMap);
             this.marker_map_point(circle_to, this.activeMap);
        }

       var color_options = {
            color: color,
            opacity: 1,
            weight: weight,
            dashArray: dasharray
        };

      var argpolyline = L.PolylineUtil.decode(route, 5);
      argpolyline.unshift(circle_from);
      console.log("color ruta ->" , color);
      route = new L.Polyline(argpolyline, color_options);
      this.polyline_creadas.push(route);
      var boxes = L.RouteBoxer.box(route, 5);
      var boxpolys = new Array(boxes.length);
      route.addTo(this.activeMap);
};

<commit_msg>latitud longitud<commit_after>var config = require('config');
var mapModule = require('map');
var plugins = require('./leaflet_plugins');
var polyUtil = require('./polyline_encoded.js');
var routeboxer = require('./leaflet_routeboxer.js');
var leaflet_label = require('./leaflet_label/leaflet.label-src.js');
var collision = require('./leaflet_layergroup_collision.js');
var session = require('session');

var center = config.geocode().center.split(',').map(parseFloat)
if (config.map_provider && config.map_provider() !== 'AmigoCloud') {
  L.mapbox.accessToken = config.mapbox_access_token();
}

module.exports = function(el) {
  var map, realtime, southWest, northEast, blurLayer;

  if (config.map_provider && config.map_provider() === 'AmigoCloud') {
    southWest = L.latLng(35.946877085397,-123.480610897013);
    northEast = L.latLng(40.763279543715,-118.789317362500);
    map = (new L.amigo.map(el, {
      amigoLogo: 'right',
      loadAmigoLayers: false,
      inertia: false,
      zoomAnimation: $('.hide-map').css('display') !== 'none',
      maxBounds: L.latLngBounds(southWest, northEast),
      minZoom: 8
    })).setView([center[1], center[0]], config.geocode().zoom);

    L.amigo.auth.setToken(config.support_data_token());

    blurLayer = L.tileLayer(
    'https://www.amigocloud.com/api/v1/users/'+
	'23/projects/3019/datasets/23835/tiles/{z}/{x}/{y}.png?' +
	'token=' + config.support_data_token(),
      {
        name: 'Uncovered Area'
      }
    );

    map.addAuthLayer({
      id: config.mapbox_map_id(),
      accessToken: config.mapbox_access_token(),
      name: 'Gray',
      provider: 'mapbox'
    });
    map.addBaseLayer(L.amigo.AmigoGray);
    map.layersControl.addBaseLayer(
      L.bingLayer(
        config.bing_key(),
	{
	  type: 'Road',
	  attribution: 'Bing Maps'
	}
      ),
      'Bing Road'
    );
    map.layersControl.addOverlay(blurLayer);
    blurLayer.addTo(map);

    module.exports.activeMap = map;

    map.realtimeControl = L.control.toggleRealTime().addTo(map);

    realtime = mapModule.realtime();

  } else {

    map = L.mapbox.map(el, config.mapbox_map_id(), {
      attributionControl: false,
      inertia: false,
      zoomAnimation: false
    }).setView([center[1], center[0]], config.geocode().zoom);
  }

  return map;
};

module.exports.getMap = function () {
  return this.activeMap;
};

module.exports.cleanRoute = function() {
    module.exports.activeRoute.removeLayer();
    module.exports.activeRoute = null;
};

module.exports.polyline_creadas = [];
module.exports.marker_creadas = [];
module.exports.makerpoint_creadas = [];
module.exports.collision_group = {};
module.exports.marker_collision_group = [];

module.exports.drawMakerCollision = function () {
    var collision_group = L.layerGroup.collision({margin:5});
    collision_group.addLayer(this.marker_collision_group);
    console.log("final -> collision_group", collision_group);
    collision_group.addTo(this.activeMap).eachLayer(function(layer){layer.showLabel()});
};

module.exports.getpolyline_creadas = function () {
  return this.polyline_creadas;
};

module.exports.getMarker_creadas = function () {
  return this.marker_creadas;
};

module.exports.cleanPolyline = function() {
    var polyline_creadas = this.getpolyline_creadas();
    var map = this.activeMap;
    for (i in polyline_creadas) {
        try {
                map.removeLayer(polyline_creadas[i]);

            } catch (e) {
                console.log("problema al eliminar " + e);
            }

  }
  this.polyline_creadas = [];

};

module.exports.cleanMarker = function() {
    var map = this.activeMap;
    for (i in this.marker_creadas) {
        try {
                map.removeLayer(this.marker_creadas[i]);

            } catch (e) {
                console.log("problema al eliminar " + e);
            }
    }

  this.marker_creadas = [];

};

module.exports.cleanMarkerpoint = function() {
    var map = this.activeMap;
    for (i in this.makerpoint_creadas) {
        try {
                map.removeLayer(this.makerpoint_creadas[i]);

            } catch (e) {
                console.log("problema al eliminar " + e);
            }
    }

  this.makerpoint_creadas = [];

};

module.exports.marker_map = function(from, to){
     var IconStart = L.icon({
        iconUrl: 'assets/images/graphics/start.svg',
        iconSize: [40, 55],
        iconAnchor: [20, 50],
        popupAnchor:  [0, -50]
    });
    var IconEnd = L.icon({
        iconUrl: 'assets/images/graphics/end.svg',
        iconSize: [40, 55],
        iconAnchor: [20, 50],
        popupAnchor:  [0, -50]
    });

    var markerform = new L.marker([from[0],from[1]], {icon: IconStart, draggable: true})
        .addTo(this.activeMap);
    var markerto = new L.marker([to[0],to[1]], {icon: IconEnd, draggable: true})
        .addTo(this.activeMap);
    var _this = this;

    markerform.on('dragend', function(e){
       var marker = e.target;
       var result = marker.getLatLng();
       _this.cleanPolyline();
       _this.cleanMarkerpoint();
       var plan = session.plan();

            plan.setAddress('from', result.lng + ',' + result.lat, function(err, rees) {
                plan.updateRoutes();
          });
    });

    markerto.on('dragend', function(e){
       var marker = e.target;
       var result = marker.getLatLng();
       _this.cleanPolyline();
       _this.cleanMarkerpoint();
       var plan = session.plan();
            plan.setAddress('to', result.lng + ',' + result.lat, function(err, rees) {
                plan.updateRoutes();
          });
    });

    this.marker_creadas.push(markerform);
    this.marker_creadas.push(markerto);
};

module.exports.marker_map_point = function(to, map){

    var name = to[2];

    var IconEnd = L.icon({
        iconUrl: 'assets/images/graphics/icono.png',
        iconSize: [20, 20],
        iconAnchor: [0, 0],
        popupAnchor:  [-3, -76]
    });

    var markers = [
      L.marker([to[0], to[1]], {icon: IconEnd}).bindLabel(name)
    ];

    //var marker = L.marker([to[0], to[1]], {icon: IconEnd}).bindLabel(name);
    console.log("lat - lng ->" , {"lat":to[0], "lng": to[1]});
    var marker = L.marker({"lat":to[0], "lng": to[1]}, {
				icon: L.divIcon({
					html:
						"<span>" +
						name +
						"</span>"
				})
				,interactive: false
				,clickable:   false
				});
    //var layer = L.layerGroup(markers).addTo(map).eachLayer(function(layer){layer.showLabel()});

    //console.log("antes del marker ->", this.collision_group);
    //this.collision_group.addLayer(marker);
    //console.log("inserto marker->", marker);
    //console.log("despues del marker ->", this.collision_group);
    //console.log("group ->", L.layerGroup(markers));

    //this.makerpoint_creadas.push(layer);

    //var collision_group = L.layerGroup.collision({margin:5});
    //collision_group.addLayer(marker);
    //collision_group.onAdd(this.activeMap);
    //this.collision_group = collision_group;
    //console.log("collision_group -> ",collision_group);
    //this.marker_collision_group.push(marker);

    this.marker_collision_group.push(marker);
};

module.exports.drawRouteAmigo = function(legs,mode) {

    var route = legs.legGeometry.points;
    var circle_from = [legs.from.lat, legs.from.lon, legs.from.name];
    var circle_to = [legs.to.lat, legs.to.lon, legs.to.name];
    var color = '#000';
    var weight = 5;
    var dasharray= '';

        if (mode=="CAR") {
            color = '#9E9E9E';
            dasharray= '6';
            weight = 3;

        }else if(mode=="BICYCLE") {
            color = '#FF0000';
            if(!(legs.routeColor === undefined)) {
                color = "#"+legs.routeColor;
             }
            dasharray= '6';
            weight = 3;

        }else if(mode=="SUBWAY" || mode=="RAIL") {
             if(!(legs.routeColor === undefined)) {
                if (legs.routeColor != "" || legs.routeColor.length == 6) {
                    color = "#"+legs.routeColor;
                }

             }
             weight = 8;
             console.log("circle from ->", circle_from);
             console.log("circle to ->", circle_to);
             this.marker_map_point(circle_from, this.activeMap);
             this.marker_map_point(circle_to, this.activeMap);

        }
        else if(mode == "WALK") {
            color = '#0BC8F4';
            dasharray= '6';
             weight = 3;
        }

        else if(mode=="BUS") {
            //color = '#FEF0B5';
            if(!(legs.routeColor === undefined)) {
                if (legs.routeColor != "" || legs.routeColor.length == 6) {
                    color = "#"+legs.routeColor;
                }
             }
             weight = 5;
             console.log("circle from ->", circle_from);
             console.log("circle to ->", circle_to);
             this.marker_map_point(circle_from, this.activeMap);
             this.marker_map_point(circle_to, this.activeMap);
        }

       var color_options = {
            color: color,
            opacity: 1,
            weight: weight,
            dashArray: dasharray
        };

      var argpolyline = L.PolylineUtil.decode(route, 5);
      argpolyline.unshift(circle_from);
      console.log("color ruta ->" , color);
      route = new L.Polyline(argpolyline, color_options);
      this.polyline_creadas.push(route);
      var boxes = L.RouteBoxer.box(route, 5);
      var boxpolys = new Array(boxes.length);
      route.addTo(this.activeMap);
};

<|endoftext|>


<commit_before>var _ = require('underscore');
var cheerio = require('cheerio');
var he = require('he');
var request = require('request');

var config = require('../config');
var h = require('../helper');
var log = require('../log');
var Plugin = require('../plugin');
var queue = require('../queue');
var session = require('../session');

var plugin = new Plugin(10, 'leetcode', '',
    'Plugin to talk with leetcode APIs.');

// update options with user credentials
function signOpts(opts, user) {
  opts.headers.Cookie = 'LEETCODE_SESSION=' + user.sessionId +
                        ';csrftoken=' + user.sessionCSRF + ';';
  opts.headers['X-CSRFToken'] = user.sessionCSRF;
  opts.headers['X-Requested-With'] = 'XMLHttpRequest';
}

function makeOpts(url) {
  var opts = {};
  opts.url = url;
  opts.headers = {};

  if (session.isLogin())
    signOpts(opts, session.getUser());
  return opts;
}

function checkError(e, resp, expectedStatus) {
  if (!e && resp && resp.statusCode !== expectedStatus) {
    var code = resp.statusCode;
    log.debug('http error: ' + code);

    if (code === 403 || code === 401) {
      e = session.errors.EXPIRED;
    } else {
      e = {msg: 'http error', statusCode: code};
    }
  }
  return e;
}

plugin.getProblems = function(cb) {
  log.debug('running leetcode.getProblems');

  var problems = [];
  var doTask = function(category, taskDone) {
    plugin.getCategoryProblems(category, function(e, _problems) {
      if (e) {
        log.debug(category + ': failed to getProblems: ' + e.msg);
      } else {
        log.debug(category + ': getProblems got ' + _problems.length + ' problems');
        problems = problems.concat(_problems);
      }
      return taskDone(e);
    });
  };

  queue.run(config.CATEGORIES, doTask, function(e) {
    return cb(e, problems);
  });
};

plugin.getCategoryProblems = function(category, cb) {
  log.debug('running leetcode.getCategoryProblems: ' + category);
  var opts = makeOpts(config.URL_PROBLEMS.replace('$category', category));

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    var json = JSON.parse(body);

    // leetcode permits anonymous access to the problem list
    // while we require login first to make a better experience.
    if (json.user_name.length === 0) {
      log.debug('no user info in list response, maybe session expired...');
      return cb(session.errors.EXPIRED);
    }

    var user = session.getUser();
    user.paid = json.is_paid;
    session.saveUser(user);

    var problems = json.stat_status_pairs
        .filter(function(p) {
          return !p.stat.question__hide;
        })
        .map(function(p) {
          return {
            state:    p.status || 'None',
            id:       p.stat.question_id,
            name:     p.stat.question__title,
            slug:     p.stat.question__title_slug,
            link:     config.URL_PROBLEM.replace('$slug', p.stat.question__title_slug),
            locked:   p.paid_only,
            percent:  p.stat.total_acs * 100 / p.stat.total_submitted,
            level:    h.levelToName(p.difficulty.level),
            starred:  p.is_favor,
            category: json.category_slug
          };
        });

    return cb(null, problems);
  });
};

plugin.getProblem = function(problem, cb) {
  log.debug('running leetcode.getProblem');
  var opts = makeOpts(problem.link);

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    var $ = cheerio.load(body);
    var spans = $('ul[class=side-bar-list] li[class=list-item] span');

    problem.totalAC = $(spans[3]).text();
    problem.totalSubmit = $(spans[5]).text();

    // TODO: revisit this if later leetcode remove this element.
    //       Then we need parse the body to get the description.
    problem.desc = $('meta[name="description"]').attr('content');
    problem.desc = he.decode(problem.desc);

    var pageData;
    var r = /(var pageData[^;]+;)/m;
    var result = body.match(r);
    if (!result) {
      var user = session.getUser();
      if (problem.locked && user.paid) {
        e = session.errors.EXPIRED;
      } else {
        e = 'failed to load' + (problem.locked ? ' locked' : '') + ' problem!';
      }
      return cb(e);
    }

    eval(result[1]);
    problem.templates = pageData.codeDefinition;
    problem.testcase = pageData.sampleTestCase;
    problem.testable = pageData.enableRunCode;
    problem.templateMeta = eval(pageData.metaData);

    return cb(null, problem);
  });
};

function runCode(opts, problem, cb) {
  opts.method = 'POST';
  opts.headers.Origin = config.URL_BASE;
  opts.headers.Referer = problem.link;
  opts.json = true;
  opts._delay = opts._delay || 1; // in seconds

  opts.body = opts.body || {};
  _.extendOwn(opts.body, {
    lang:        h.extToLang(problem.file),
    question_id: parseInt(problem.id, 10),
    test_mode:   false,
    typed_code:  h.getFileData(problem.file)
  });

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    if (body.error) {
      if (body.error.indexOf('run code too soon') < 0)
        return cb(body.error);

      // hit 'run code too soon' error, have to wait a bit
      log.debug(body.error);

      // linear wait
      ++opts._delay;
      log.debug('Will retry after %d seconds...', opts._delay);

      var reRun = _.partial(runCode, opts, problem, cb);
      return setTimeout(reRun, opts._delay * 1000);
    }

    opts.json = false;
    opts.body = null;

    return cb(null, body);
  });
}

function verifyResult(opts, jobs, results, cb) {
  if (jobs.length === 0) return cb(null, results);

  opts.method = 'GET';
  opts.url = config.URL_VERIFY.replace('$id', jobs[0].id);

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    var result = JSON.parse(body);
    if (result.state === 'SUCCESS') {
      result.name = jobs[0].name;
      result.id = jobs[0].id;
      results.push(result);
      jobs.shift();
    }

    setImmediate(verifyResult, opts, jobs, results, cb);
  });
}

plugin.testProblem = function(problem, cb) {
  log.debug('running leetcode.testProblem');
  var opts = makeOpts(config.URL_TEST.replace('$slug', problem.slug));
  opts.body = {data_input: problem.testcase};

  runCode(opts, problem, function(e, task) {
    if (e) return cb(e);

    var jobs = [
      {name: 'Your',     id: task.interpret_id},
      {name: 'Expected', id: task.interpret_expected_id}
    ];
    verifyResult(opts, jobs, [], cb);
  });
};

plugin.submitProblem = function(problem, cb) {
  log.debug('running leetcode.submitProblem');
  var opts = makeOpts(config.URL_SUBMIT.replace('$slug', problem.slug));
  opts.body = {judge_type: 'large'};

  runCode(opts, problem, function(e, task) {
    if (e) return cb(e);

    var jobs = [{name: 'Your', id: task.submission_id}];
    verifyResult(opts, jobs, [], cb);
  });
};

plugin.getSubmissions = function(problem, cb) {
  log.debug('running leetcode.getSubmissions');
  var opts = makeOpts(config.URL_SUBMISSIONS.replace('$slug', problem.slug));
  opts.headers.Referer = config.URL_PROBLEM.replace('$slug', problem.slug);

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    // FIXME: this only return the 1st 20 submissions, we should get next if necessary.
    var submissions = JSON.parse(body).submissions_dump;
    _.each(submissions, function(submission) {
      submission.id = _.last(_.compact(submission.url.split('/')));
    });

    return cb(null, submissions);
  });
};

plugin.getSubmission = function(submission, cb) {
  log.debug('running leetcode.getSubmission');
  var opts = makeOpts(config.URL_SUBMISSION.replace('$id', submission.id));

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    var re = body.match(/submissionCode:\s('[^']*')/);
    if (re) submission.code = eval(re[1]);

    re = body.match(/distribution_formatted:\s('[^']*')/);
    if (re) submission.distributionChart = JSON.parse(eval(re[1]));
    return cb(null, submission);
  });
};

plugin.starProblem = function(problem, starred, cb) {
  log.debug('running leetcode.starProblem');
  var opts = makeOpts();
  opts.headers.Origin = config.URL_BASE;
  opts.headers.Referer = problem.link;

  var user = session.getUser();
  if (starred) {
    opts.url = config.URL_FAVORITES;
    opts.method = 'POST';
    opts.json = true;
    opts.body = {
      favorite_id_hash: user.hash,
      question_id:      problem.id
    };
  } else {
    opts.url = config.URL_FAVORITE_DELETE
      .replace('$hash', user.hash)
      .replace('$id', problem.id);
    opts.method = 'DELETE';
  }

  var req = request(opts, function(e, resp, body) {
    // FIXME: not sure why we hit HPE_INVALID_CONSTANT error?
    if (req && req.response && req.response.statusCode === 204)
      return cb(null, starred);

    e = checkError(e, resp, 204);
    if (e) return cb(e);

    cb(null, starred);
  });
};

plugin.getFavorites = function(cb) {
  log.debug('running leetcode.getFavorites');
  var opts = makeOpts(config.URL_FAVORITES);

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    var favorites = JSON.parse(body);
    return cb(null, favorites);
  });
};

plugin.login = function(user, cb) {
  log.debug('running leetcode.login');
  request(config.URL_LOGIN, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    user.loginCSRF = h.getSetCookieValue(resp, 'csrftoken');

    var opts = {
      url:     config.URL_LOGIN,
      headers: {
        Origin:  config.URL_BASE,
        Referer: config.URL_LOGIN,
        Cookie:  'csrftoken=' + user.loginCSRF + ';'
      },
      form: {
        csrfmiddlewaretoken: user.loginCSRF,
        login:               user.login,
        password:            user.pass
      }
    };
    request.post(opts, function(e, resp, body) {
      if (e) return cb(e);
      if (resp.statusCode !== 302) return cb('invalid password?');

      user.sessionCSRF = h.getSetCookieValue(resp, 'csrftoken');
      user.sessionId = h.getSetCookieValue(resp, 'LEETCODE_SESSION');
      user.name = h.getSetCookieValue(resp, 'messages')
                   .match('Successfully signed in as ([^.]*)')[1];

      return cb(null, user);
    });
  });
};

module.exports = plugin;
<commit_msg>[Plugin] enrich problem info.<commit_after>var _ = require('underscore');
var cheerio = require('cheerio');
var he = require('he');
var request = require('request');

var config = require('../config');
var h = require('../helper');
var log = require('../log');
var Plugin = require('../plugin');
var queue = require('../queue');
var session = require('../session');

var plugin = new Plugin(10, 'leetcode', '',
    'Plugin to talk with leetcode APIs.');

// update options with user credentials
function signOpts(opts, user) {
  opts.headers.Cookie = 'LEETCODE_SESSION=' + user.sessionId +
                        ';csrftoken=' + user.sessionCSRF + ';';
  opts.headers['X-CSRFToken'] = user.sessionCSRF;
  opts.headers['X-Requested-With'] = 'XMLHttpRequest';
}

function makeOpts(url) {
  var opts = {};
  opts.url = url;
  opts.headers = {};

  if (session.isLogin())
    signOpts(opts, session.getUser());
  return opts;
}

function checkError(e, resp, expectedStatus) {
  if (!e && resp && resp.statusCode !== expectedStatus) {
    var code = resp.statusCode;
    log.debug('http error: ' + code);

    if (code === 403 || code === 401) {
      e = session.errors.EXPIRED;
    } else {
      e = {msg: 'http error', statusCode: code};
    }
  }
  return e;
}

plugin.getProblems = function(cb) {
  log.debug('running leetcode.getProblems');

  var problems = [];
  var doTask = function(category, taskDone) {
    plugin.getCategoryProblems(category, function(e, _problems) {
      if (e) {
        log.debug(category + ': failed to getProblems: ' + e.msg);
      } else {
        log.debug(category + ': getProblems got ' + _problems.length + ' problems');
        problems = problems.concat(_problems);
      }
      return taskDone(e);
    });
  };

  queue.run(config.CATEGORIES, doTask, function(e) {
    return cb(e, problems);
  });
};

plugin.getCategoryProblems = function(category, cb) {
  log.debug('running leetcode.getCategoryProblems: ' + category);
  var opts = makeOpts(config.URL_PROBLEMS.replace('$category', category));

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    var json = JSON.parse(body);

    // leetcode permits anonymous access to the problem list
    // while we require login first to make a better experience.
    if (json.user_name.length === 0) {
      log.debug('no user info in list response, maybe session expired...');
      return cb(session.errors.EXPIRED);
    }

    var user = session.getUser();
    user.paid = json.is_paid;
    session.saveUser(user);

    var problems = json.stat_status_pairs
        .filter(function(p) {
          return !p.stat.question__hide;
        })
        .map(function(p) {
          return {
            state:    p.status || 'None',
            id:       p.stat.question_id,
            name:     p.stat.question__title,
            slug:     p.stat.question__title_slug,
            link:     config.URL_PROBLEM.replace('$slug', p.stat.question__title_slug),
            locked:   p.paid_only,
            percent:  p.stat.total_acs * 100 / p.stat.total_submitted,
            level:    h.levelToName(p.difficulty.level),
            starred:  p.is_favor,
            category: json.category_slug
          };
        });

    return cb(null, problems);
  });
};

plugin.getProblem = function(problem, cb) {
  log.debug('running leetcode.getProblem');
  var opts = makeOpts(problem.link);

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    var $ = cheerio.load(body);
    var spans = $('ul[class=side-bar-list] li[class=list-item] span');

    problem.totalAC = $(spans[3]).text();
    problem.totalSubmit = $(spans[5]).text();

    // TODO: revisit this if later leetcode remove this element.
    //       Then we need parse the body to get the description.
    problem.desc = $('meta[name="description"]').attr('content');
    problem.desc = he.decode(problem.desc);

    var pageData;
    var r = /(var pageData[^;]+;)/m;
    var re = body.match(r);
    if (!re) {
      var user = session.getUser();
      if (problem.locked && user.paid) {
        e = session.errors.EXPIRED;
      } else {
        e = 'failed to load' + (problem.locked ? ' locked' : '') + ' problem!';
      }
      return cb(e);
    }

    eval(re[1]);
    problem.templates = pageData.codeDefinition;
    problem.testcase = pageData.sampleTestCase;
    problem.testable = pageData.enableRunCode;
    problem.templateMeta = eval(pageData.metaData);

    r = /https:\/\/discuss.leetcode.com\/category\/(\d+)/;
    re = body.match(r);
    if (re) problem.discuss = re[1];

    return cb(null, problem);
  });
};

function runCode(opts, problem, cb) {
  opts.method = 'POST';
  opts.headers.Origin = config.URL_BASE;
  opts.headers.Referer = problem.link;
  opts.json = true;
  opts._delay = opts._delay || 1; // in seconds

  opts.body = opts.body || {};
  _.extendOwn(opts.body, {
    lang:        h.extToLang(problem.file),
    question_id: parseInt(problem.id, 10),
    test_mode:   false,
    typed_code:  h.getFileData(problem.file)
  });

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    if (body.error) {
      if (body.error.indexOf('run code too soon') < 0)
        return cb(body.error);

      // hit 'run code too soon' error, have to wait a bit
      log.debug(body.error);

      // linear wait
      ++opts._delay;
      log.debug('Will retry after %d seconds...', opts._delay);

      var reRun = _.partial(runCode, opts, problem, cb);
      return setTimeout(reRun, opts._delay * 1000);
    }

    opts.json = false;
    opts.body = null;

    return cb(null, body);
  });
}

function verifyResult(opts, jobs, results, cb) {
  if (jobs.length === 0) return cb(null, results);

  opts.method = 'GET';
  opts.url = config.URL_VERIFY.replace('$id', jobs[0].id);

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    var result = JSON.parse(body);
    if (result.state === 'SUCCESS') {
      result.name = jobs[0].name;
      result.id = jobs[0].id;
      results.push(result);
      jobs.shift();
    }

    setImmediate(verifyResult, opts, jobs, results, cb);
  });
}

plugin.testProblem = function(problem, cb) {
  log.debug('running leetcode.testProblem');
  var opts = makeOpts(config.URL_TEST.replace('$slug', problem.slug));
  opts.body = {data_input: problem.testcase};

  runCode(opts, problem, function(e, task) {
    if (e) return cb(e);

    var jobs = [
      {name: 'Your',     id: task.interpret_id},
      {name: 'Expected', id: task.interpret_expected_id}
    ];
    verifyResult(opts, jobs, [], cb);
  });
};

plugin.submitProblem = function(problem, cb) {
  log.debug('running leetcode.submitProblem');
  var opts = makeOpts(config.URL_SUBMIT.replace('$slug', problem.slug));
  opts.body = {judge_type: 'large'};

  runCode(opts, problem, function(e, task) {
    if (e) return cb(e);

    var jobs = [{name: 'Your', id: task.submission_id}];
    verifyResult(opts, jobs, [], cb);
  });
};

plugin.getSubmissions = function(problem, cb) {
  log.debug('running leetcode.getSubmissions');
  var opts = makeOpts(config.URL_SUBMISSIONS.replace('$slug', problem.slug));
  opts.headers.Referer = config.URL_PROBLEM.replace('$slug', problem.slug);

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    // FIXME: this only return the 1st 20 submissions, we should get next if necessary.
    var submissions = JSON.parse(body).submissions_dump;
    _.each(submissions, function(submission) {
      submission.id = _.last(_.compact(submission.url.split('/')));
    });

    return cb(null, submissions);
  });
};

plugin.getSubmission = function(submission, cb) {
  log.debug('running leetcode.getSubmission');
  var opts = makeOpts(config.URL_SUBMISSION.replace('$id', submission.id));

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    var re = body.match(/submissionCode:\s('[^']*')/);
    if (re) submission.code = eval(re[1]);

    re = body.match(/distribution_formatted:\s('[^']*')/);
    if (re) submission.distributionChart = JSON.parse(eval(re[1]));
    return cb(null, submission);
  });
};

plugin.starProblem = function(problem, starred, cb) {
  log.debug('running leetcode.starProblem');
  var opts = makeOpts();
  opts.headers.Origin = config.URL_BASE;
  opts.headers.Referer = problem.link;

  var user = session.getUser();
  if (starred) {
    opts.url = config.URL_FAVORITES;
    opts.method = 'POST';
    opts.json = true;
    opts.body = {
      favorite_id_hash: user.hash,
      question_id:      problem.id
    };
  } else {
    opts.url = config.URL_FAVORITE_DELETE
      .replace('$hash', user.hash)
      .replace('$id', problem.id);
    opts.method = 'DELETE';
  }

  var req = request(opts, function(e, resp, body) {
    // FIXME: not sure why we hit HPE_INVALID_CONSTANT error?
    if (req && req.response && req.response.statusCode === 204)
      return cb(null, starred);

    e = checkError(e, resp, 204);
    if (e) return cb(e);

    cb(null, starred);
  });
};

plugin.getFavorites = function(cb) {
  log.debug('running leetcode.getFavorites');
  var opts = makeOpts(config.URL_FAVORITES);

  request(opts, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    var favorites = JSON.parse(body);
    return cb(null, favorites);
  });
};

plugin.login = function(user, cb) {
  log.debug('running leetcode.login');
  request(config.URL_LOGIN, function(e, resp, body) {
    e = checkError(e, resp, 200);
    if (e) return cb(e);

    user.loginCSRF = h.getSetCookieValue(resp, 'csrftoken');

    var opts = {
      url:     config.URL_LOGIN,
      headers: {
        Origin:  config.URL_BASE,
        Referer: config.URL_LOGIN,
        Cookie:  'csrftoken=' + user.loginCSRF + ';'
      },
      form: {
        csrfmiddlewaretoken: user.loginCSRF,
        login:               user.login,
        password:            user.pass
      }
    };
    request.post(opts, function(e, resp, body) {
      if (e) return cb(e);
      if (resp.statusCode !== 302) return cb('invalid password?');

      user.sessionCSRF = h.getSetCookieValue(resp, 'csrftoken');
      user.sessionId = h.getSetCookieValue(resp, 'LEETCODE_SESSION');
      user.name = h.getSetCookieValue(resp, 'messages')
                   .match('Successfully signed in as ([^.]*)')[1];

      return cb(null, user);
    });
  });
};

module.exports = plugin;
<|endoftext|>


<commit_before>/**
    Framework for building object relational database apps
    Copyright (C) 2019  John Rogelstad

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**/
import catalog from "./catalog.js";
import model from "./model.js";

function feather(data, spec) {
    spec = spec || catalog.getFeather("Feather");
    let that;
    let modules;

    // ..........................................................
    // PUBLIC
    //

    that = model(data, spec);

    function featherList() {
        let feathers = catalog.store().feathers();
        let keys = Object.keys(feathers);

        keys = keys.filter(function (key) {
            return !feathers[key].isSystem;
        }).sort();

        return keys.map(function (key) {
            return {
                value: key,
                label: key
            };
        });
    }

    that.addCalculated({
        name: "feathers",
        type: "array",
        function: featherList
    });

    modules = function () {
        let feathers = catalog.store().feathers();
        let keys = Object.keys(feathers);
        let ary = [];

        keys.forEach(function (key) {
            let mod = feathers[key].module;

            if (mod && ary.indexOf(mod) === -1) {
                ary.push(mod);
            }
        });

        return ary.map(function (item) {
            return {
                value: item,
                label: item
            };
        });
    };
    that.addCalculated({
        name: "modules",
        type: "array",
        function: modules
    });

    return that;
}

catalog.registerModel("Feather", feather, true);

<commit_msg>Relint<commit_after>/**
    Framework for building object relational database apps
    Copyright (C) 2019  John Rogelstad

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**/
/*jslint browser*/
import catalog from "./catalog.js";
import model from "./model.js";
import list from "./list.js";

const f = window.f;

function feather(data, spec) {
    spec = spec || catalog.getFeather("Feather");
    let that;
    let modules;

    // ..........................................................
    // PUBLIC
    //

    that = model(data, spec);

    function featherList() {
        let feathers = catalog.store().feathers();
        let keys = Object.keys(feathers);

        keys = keys.filter(function (key) {
            return !feathers[key].isSystem;
        }).sort();

        return keys.map(function (key) {
            return {
                value: key,
                label: key
            };
        });
    }

    that.addCalculated({
        name: "feathers",
        type: "array",
        function: featherList
    });

    modules = function () {
        let feathers = catalog.store().feathers();
        let keys = Object.keys(feathers);
        let ary = [];

        keys.forEach(function (key) {
            let mod = feathers[key].module;

            if (mod && ary.indexOf(mod) === -1) {
                ary.push(mod);
            }
        });

        return ary.map(function (item) {
            return {
                value: item,
                label: item
            };
        });
    };
    that.addCalculated({
        name: "modules",
        type: "array",
        function: modules
    });

    return that;
}

feather.list = list("Feather");
feather.static = f.prop({});

catalog.register("models", "feather", feather);

<|endoftext|>