<commit_before>/*    Copyright 2021 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    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/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename);

const Sensor = require('./Sensor.js').Sensor;

const _ = require('lodash');

const validator = require('validator');

const IntelTool = require('../net2/IntelTool');
const intelTool = new IntelTool();

const rclient = require('../util/redis_manager.js').getRedisClient();

const flowUtil = require('../net2/FlowUtil');

const sys = require('sys'),
      Buffer = require('buffer').Buffer,
      dgram = require('dgram');

// slices a single byte into bits
// assuming only single bytes
const sliceBits = function(b, off, len) {
    var s = 7 - (off + len - 1);

    b = b >>> s;
    return b & ~(0xff << len);
};

const qnameToDomain = (qname) => {
  var domain= '';
  for(var i=0;i<qname.length;i++) {
    if (qname[i] == 0) {
      //last char chop trailing .
      domain = domain.substring(0, domain.length - 1);
      break;
    }

    var tmpBuf = qname.slice(i+1, i+qname[i]+1);
    domain += tmpBuf.toString('binary', 0, tmpBuf.length);
    domain += '.';

    i = i + qname[i];
  }

  return domain;
}

const expireTime = 48 * 3600; // expire in two days, by default
const allowKey = "fastdns:allow_list";
const blockKey = "fastdns:block_list";
const defaultListenPort = 9963;

class DNSProxyPlugin extends Sensor {
  async run() {
    this.hookFeature("dns_proxy");
  }

  async globalOn() {
    this.launchServer();
  }

  async globalOff() {
    if(this.server) {
      this.server.close();
      this.server = null;
    }
  }

  launchServer() {
    this.server = dgram.createSocket('udp4');

    this.server.on('message', async (msg, info) => {
      const qname = this.parseRequest(msg);
      if(qname) {
        await this.processRequest(qname);
      }
      // never need to reply back to client as this is not a true dns server
    });

    this.server.on('close', () => {
      log.info("DNS proxy server is closed.");
    });

    let port = this.config.listenPort || defaultListenPort;
    if(!_.isNumber(port)) {
      log.warn("Invalid port", port, ", reverting back to default port.");
      port = defaultListenPort;
    }

    this.server.bind(port, '127.0.0.1');
    log.info("DNS proxy server is now running at port:", port);
  }

  parseRequest(req) {
    //see rfc1035 for more details
    //http://tools.ietf.org/html/rfc1035#section-4.1.1
    if(req.length < 16) {
      return null;
    }
    return req.slice(12, req.length - 4);
  }

  async checkCache(domain) { // only return if there is exact-match intel in redis
    return intelTool.getDomainIntel(domain);
  }

  async processRequest(qname) {
    const domain = qnameToDomain(qname);
    log.info("dns request is", domain);
    const begin = new Date() / 1;
    const cache = await this.checkCache(domain);
    if(cache) {
      log.info("domain info is already cached locally:", cache);
      return; // do need to do anything
    }
    const result = await intelTool.checkIntelFromCloud(undefined, domain); // parameter ip is undefined since it's a dns request only
    await this.updateCache(domain, result);
    const end = new Date() / 1;
    log.info("dns intel result is", result, "took", Math.floor(end - begin), "ms");
  }

  async updateCache(domain, result) {
    if(_.isEmpty(result)) { // empty intel, means the domain is good
      const domains = flowUtil.getSubDomains(domain);
      if(!domains) {
        log.warn("Invalid Domain", domain, "skipped.");
        return;
      }

      // since result is empty, it means all sub domains of this domain are good
      const placeholder = {c: 'x', a: '1'};
      for(const dn of domains) {
        await intelTool.addDomainIntel(dn, placeholder, expireTime);
      }

      // only last dn be added to allow key for better performance
      if(domains.length > 0) {
        const dn = domains[domains.length - 1];
        await rclient.saddAsync(allowKey, dn);
        await rclient.sremAsync(blockKey, dn);
      }

    } else {
      for(const item of result) {
        const dn = item.originIP; // originIP is the domain
        const isDomain = validator.isFQDN(dn);
        if(!isDomain) {
          continue;
        }

        for(const k in item) { // to suppress redis error
          const v = item[k];
          if(_.isBoolean(v) || _.isNumber(v) || _.isString(v)) {
            continue;
          }
          item[k] = JSON.stringify(v);
        }

        await intelTool.addDomainIntel(dn, item, item.e || expireTime);
        if(item.c === 'intel') { // need to decide the criteria better
          item.a = '0';
          await rclient.saddAsync(blockKey, dn);
          // either allow or block, the same domain can't stay in both set at the same time
          await rclient.sremAsync(allowKey, dn);
        } else {
          item.a = '1';
          await rclient.saddAsync(allowKey, dn);
          await rclient.sremAsync(blockKey, dn);
        }
      }
    }
  }
}

module.exports = DNSProxyPlugin;
<commit_msg>adjust allow strategoy<commit_after>/*    Copyright 2021 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    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/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename);

const Sensor = require('./Sensor.js').Sensor;

const _ = require('lodash');

const validator = require('validator');

const IntelTool = require('../net2/IntelTool');
const intelTool = new IntelTool();

const rclient = require('../util/redis_manager.js').getRedisClient();

const flowUtil = require('../net2/FlowUtil');

const sys = require('sys'),
      Buffer = require('buffer').Buffer,
      dgram = require('dgram');

// slices a single byte into bits
// assuming only single bytes
const sliceBits = function(b, off, len) {
    var s = 7 - (off + len - 1);

    b = b >>> s;
    return b & ~(0xff << len);
};

const qnameToDomain = (qname) => {
  var domain= '';
  for(var i=0;i<qname.length;i++) {
    if (qname[i] == 0) {
      //last char chop trailing .
      domain = domain.substring(0, domain.length - 1);
      break;
    }

    var tmpBuf = qname.slice(i+1, i+qname[i]+1);
    domain += tmpBuf.toString('binary', 0, tmpBuf.length);
    domain += '.';

    i = i + qname[i];
  }

  return domain;
}

const expireTime = 48 * 3600; // expire in two days, by default
const allowKey = "fastdns:allow_list";
const blockKey = "fastdns:block_list";
const defaultListenPort = 9963;

class DNSProxyPlugin extends Sensor {
  async run() {
    this.hookFeature("dns_proxy");
  }

  async globalOn() {
    this.launchServer();
  }

  async globalOff() {
    if(this.server) {
      this.server.close();
      this.server = null;
    }
  }

  launchServer() {
    this.server = dgram.createSocket('udp4');

    this.server.on('message', async (msg, info) => {
      const qname = this.parseRequest(msg);
      if(qname) {
        await this.processRequest(qname);
      }
      // never need to reply back to client as this is not a true dns server
    });

    this.server.on('close', () => {
      log.info("DNS proxy server is closed.");
    });

    let port = this.config.listenPort || defaultListenPort;
    if(!_.isNumber(port)) {
      log.warn("Invalid port", port, ", reverting back to default port.");
      port = defaultListenPort;
    }

    this.server.bind(port, '127.0.0.1');
    log.info("DNS proxy server is now running at port:", port);
  }

  parseRequest(req) {
    //see rfc1035 for more details
    //http://tools.ietf.org/html/rfc1035#section-4.1.1
    if(req.length < 16) {
      return null;
    }
    return req.slice(12, req.length - 4);
  }

  async checkCache(domain) { // only return if there is exact-match intel in redis
    return intelTool.getDomainIntel(domain);
  }

  async processRequest(qname) {
    const domain = qnameToDomain(qname);
    log.info("dns request is", domain);
    const begin = new Date() / 1;
    const cache = await this.checkCache(domain);
    if(cache) {
      log.info("domain info is already cached locally:", cache);
      return; // do need to do anything
    }
    const result = await intelTool.checkIntelFromCloud(undefined, domain); // parameter ip is undefined since it's a dns request only
    await this.updateCache(domain, result);
    const end = new Date() / 1;
    log.info("dns intel result is", result, "took", Math.floor(end - begin), "ms");
  }

  async updateCache(domain, result) {
    if(_.isEmpty(result)) { // empty intel, means the domain is good
      const domains = flowUtil.getSubDomains(domain);
      if(!domains) {
        log.warn("Invalid Domain", domain, "skipped.");
        return;
      }

      // since result is empty, it means all sub domains of this domain are good
      const placeholder = {c: 'x', a: '1'};
      for(const dn of domains) {
        await intelTool.addDomainIntel(dn, placeholder, expireTime);
      }

      // only the exact dn is added to the allow and block list
      // generic domains can't be added, because another sub domain may be malicous
      // example:
      //   domain1.blogspot.com may be good
      //   and domain2.blogspot.com may be malicous
      // when domain1 is checked to be good, we should NOT add blogspot.com to allow_list
      await rclient.saddAsync(allowKey, domain);
      await rclient.sremAsync(blockKey, domain);

    } else {
      for(const item of result) {
        const dn = item.originIP; // originIP is the domain
        const isDomain = validator.isFQDN(dn);
        if(!isDomain) {
          continue;
        }

        for(const k in item) { // to suppress redis error
          const v = item[k];
          if(_.isBoolean(v) || _.isNumber(v) || _.isString(v)) {
            continue;
          }
          item[k] = JSON.stringify(v);
        }

        await intelTool.addDomainIntel(dn, item, item.e || expireTime);
        if(item.c === 'intel') { // need to decide the criteria better
          item.a = '0';
          await rclient.saddAsync(blockKey, dn);
          // either allow or block, the same domain can't stay in both set at the same time
          await rclient.sremAsync(allowKey, dn);
        } else {
          item.a = '1';
          await rclient.saddAsync(allowKey, dn);
          await rclient.sremAsync(blockKey, dn);
        }
      }
    }
  }
}

module.exports = DNSProxyPlugin;
<|endoftext|>


<commit_before>import lazypipe from 'lazypipe';
import {listen} from './server';
import {resolve} from 'path';
import {stringify} from 'qs';
import {spawn} from 'child_process';
import {obj as through} from 'through2';
import {obj as reduce} from 'through2-reduce';
import ProfileReporter from 'jasmine-profile-reporter';
import TerminalReporter from 'jasmine-terminal-reporter';
import toReporter from 'jasmine-json-stream-reporter/to-reporter';
import split from 'split2';
import flatMap from 'flat-map';
import once from 'lodash.once';
import ChromeDriver from './drivers/chrome';
import PhantomJsDriver from './drivers/phantomjs';
import PhantomJs1Driver from './drivers/phantomjs1';
import SlimerJsDriver from './drivers/slimerjs';
import portastic from 'portastic';
import {compact, parse} from './helper';

const DEFAULT_JASMINE_PORT = 8888;

const drivers = {
  chrome: ChromeDriver,
  phantomjs: PhantomJsDriver,
  phantomjs1: PhantomJs1Driver,
  slimerjs: SlimerJsDriver,
  _default: PhantomJsDriver
};

function onError(message) {
  try {
    const {PluginError} = require('gulp-util');
    return new PluginError('gulp-jasmine-browser', {message, showProperties: false});
  } catch(e) {
    return new Error(message);
  }
}

function startServer(files, options) {
  const {port} = options;
  if (!port) return portastic.find({min: 8000, max: DEFAULT_JASMINE_PORT, retrieve: 1}).then(([port]) => listen(port, files, options));
  return listen(port, files, options);
}

function defaultReporters(options, profile) {
  return compact([new TerminalReporter(options), profile && new ProfileReporter(options)]);
}

function findOrStartServer(options) {
  function helper(port, files) {
    if (!port) return startServer(files, options);
    return portastic.test(port).then(isOpen => {
      if (!isOpen) return {server: {close: () => {}}, port};
      return startServer(files, options);
    });
  }

  return through((files, enc, next) => helper(options.port, files).then(i => next(null, i)).catch(next));
}

function createServer(options) {
  const {driver = 'phantomjs', random, throwFailures, spec, seed, reporter, profile, onCoverage, onSnapshot, onConsoleMessage = (...args) => console.log(...args), ...opts} = options;
  const query = stringify({catch: options.catch, random, throwFailures, spec, seed});
  const {command, runner, output} = drivers[driver in drivers ? driver : '_default']();
  const stream = lazypipe()
    .pipe(() => reduce((memo, file) => (memo[file.relative] = file.contents, memo), {}))
    .pipe(() => findOrStartServer(options))
    .pipe(() => flatMap(({server, port}, next) => {
      const stdio = ['pipe', output === 'stdout' ? 'pipe' : 1, output === 'stderr' ? 'pipe' : 2];
      const phantomProcess = spawn(command, compact([runner, port, query]), {cwd: resolve(__dirname, './runners'), stdio});
      phantomProcess.on('close', () => server.close());
      ['SIGINT', 'SIGTERM'].forEach(e => process.once(e, () => phantomProcess && phantomProcess.kill()));
      next(null, phantomProcess[output].pipe(split(parse)));
    }))
    .pipe(() => toReporter(reporter || defaultReporters(opts, profile), {onError, onConsoleMessage, onCoverage, onSnapshot}));
  return stream();
}

function createServerWatch(options) {
  const files = {};
  const createServerOnce = once(() => startServer(files, options));
  return lazypipe().pipe(() => {
    return through((file, enc, next) => {
      files[file.relative] = file.contents;
      createServerOnce();
      next(null, file);
    });
  })();
}

function headless(options = {}) {
  return createServer(options);
}

function server(options = {}) {
  return createServerWatch({port: DEFAULT_JASMINE_PORT, ...options});
}

const [slimerjs, phantomjs, chrome] = ['slimerjs', 'phantomjs', 'chrome'].map(driver => {
  return function(options = {}) {
    return headless({...options, driver});
  };
});

export {headless, server, slimerjs, phantomjs, chrome};<commit_msg>add a file option for the headless runner<commit_after>import lazypipe from 'lazypipe';
import {listen} from './server';
import {resolve} from 'path';
import {stringify} from 'qs';
import {spawn} from 'child_process';
import {obj as through} from 'through2';
import {obj as reduce} from 'through2-reduce';
import ProfileReporter from 'jasmine-profile-reporter';
import TerminalReporter from 'jasmine-terminal-reporter';
import toReporter from 'jasmine-json-stream-reporter/to-reporter';
import split from 'split2';
import flatMap from 'flat-map';
import once from 'lodash.once';
import ChromeDriver from './drivers/chrome';
import PhantomJsDriver from './drivers/phantomjs';
import PhantomJs1Driver from './drivers/phantomjs1';
import SlimerJsDriver from './drivers/slimerjs';
import portastic from 'portastic';
import {compact, parse} from './helper';

const DEFAULT_JASMINE_PORT = 8888;

const drivers = {
  chrome: ChromeDriver,
  phantomjs: PhantomJsDriver,
  phantomjs1: PhantomJs1Driver,
  slimerjs: SlimerJsDriver,
  _default: PhantomJsDriver
};

function onError(message) {
  try {
    const {PluginError} = require('gulp-util');
    return new PluginError('gulp-jasmine-browser', {message, showProperties: false});
  } catch(e) {
    return new Error(message);
  }
}

function startServer(files, options) {
  const {port} = options;
  if (!port) return portastic.find({min: 8000, max: DEFAULT_JASMINE_PORT, retrieve: 1}).then(([port]) => listen(port, files, options));
  return listen(port, files, options);
}

function defaultReporters(options, profile) {
  return compact([new TerminalReporter(options), profile && new ProfileReporter(options)]);
}

function findOrStartServer(options) {
  function helper(port, files) {
    if (!port) return startServer(files, options);
    return portastic.test(port).then(isOpen => {
      if (!isOpen) return {server: {close: () => {}}, port};
      return startServer(files, options);
    });
  }

  return through((files, enc, next) => helper(options.port, files).then(i => next(null, i)).catch(next));
}

function createServer(options) {
  const {driver = 'phantomjs', file, random, throwFailures, spec, seed, reporter, profile, onCoverage, onSnapshot, onConsoleMessage = (...args) => console.log(...args), ...opts} = options;
  const query = stringify({catch: options.catch, file, random, throwFailures, spec, seed});
  const {command, runner, output} = drivers[driver in drivers ? driver : '_default']();
  const stream = lazypipe()
    .pipe(() => reduce((memo, file) => (memo[file.relative] = file.contents, memo), {}))
    .pipe(() => findOrStartServer(options))
    .pipe(() => flatMap(({server, port}, next) => {
      const stdio = ['pipe', output === 'stdout' ? 'pipe' : 1, output === 'stderr' ? 'pipe' : 2];
      const phantomProcess = spawn(command, compact([runner, port, query]), {cwd: resolve(__dirname, './runners'), stdio});
      phantomProcess.on('close', () => server.close());
      ['SIGINT', 'SIGTERM'].forEach(e => process.once(e, () => phantomProcess && phantomProcess.kill()));
      next(null, phantomProcess[output].pipe(split(parse)));
    }))
    .pipe(() => toReporter(reporter || defaultReporters(opts, profile), {onError, onConsoleMessage, onCoverage, onSnapshot}));
  return stream();
}

function createServerWatch(options) {
  const files = {};
  const createServerOnce = once(() => startServer(files, options));
  return lazypipe().pipe(() => {
    return through((file, enc, next) => {
      files[file.relative] = file.contents;
      createServerOnce();
      next(null, file);
    });
  })();
}

function headless(options = {}) {
  return createServer(options);
}

function server(options = {}) {
  return createServerWatch({port: DEFAULT_JASMINE_PORT, ...options});
}

const [slimerjs, phantomjs, chrome] = ['slimerjs', 'phantomjs', 'chrome'].map(driver => {
  return function(options = {}) {
    return headless({...options, driver});
  };
});

export {headless, server, slimerjs, phantomjs, chrome};<|endoftext|>


<commit_before>/*    Copyright 2019-2022 Firewalla Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    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/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename)
const rclient = require('../util/redis_manager.js').getRedisClient();
const Sensor = require('./Sensor.js').Sensor
const Promise = require('bluebird')
const extensionManager = require('./ExtensionManager.js')
const guardianListKey = "guardian:alias:list";
const Guardian = require('./Guardian');
const _ = require('lodash');

class GuardianSensor extends Sensor {
  constructor() {
    super();
    this.guardianMap = {};
  }

  async apiRun() {
    await this.startGuardians();

    extensionManager.onGet("guardianSocketioServer", (msg, data) => {
      return this.getServer(data);
    });

    extensionManager.onSet("guardianSocketioServer", async (msg, data) => {
      return this.setServer(data);
    });

    extensionManager.onGet("guardian.business", async (msg, data) => {
      return this.getBusiness(data);
    });

    extensionManager.onSet("guardian.business", async (msg, data) => {
      return this.setBusiness(data);
    });

    extensionManager.onGet("guardianSocketioRegion", (msg, data) => {
      return this.getRegion(data);
    });

    extensionManager.onCmd("startGuardianSocketioServer", (msg, data) => {
      return this.start(data);
    });

    extensionManager.onCmd("stopGuardianSocketioServer", (msg, data) => {
      return this.stop(data);
    });

    extensionManager.onCmd("resetGuardian", (msg, data) => {
      return this.reset(data);
    });

    extensionManager.onCmd("setAndStartGuardianService", async (msg, data) => {
      return this.setAndStartGuardianService(data);
    });

    extensionManager.onGet("guardians", async (msg, data) => {
      return this.getGuardians(data);
    });

    extensionManager.onGet("guardian", async (msg, data) => {
      return this.getGuardian(data);
    })
  }

  async startGuardians() {
    let aliases = await rclient.zrangeAsync(guardianListKey, 0, -1);
    aliases = _.uniq((aliases || []).concat("default"));

    log.forceInfo('Start guardian for these alias', aliases);

    await Promise.all(aliases.map(async alias => {
      const guardian = new Guardian(alias);
      await guardian.init();
      this.guardianMap[alias] = guardian;
    }))
  }

  async getGuardianByAlias(alias = "default") {
    let guardian = this.guardianMap[alias];
    if (!guardian) {
      guardian = new Guardian(alias);
      this.guardianMap[alias] = guardian;
      await rclient.zadd(guardianListKey, Date.now() / 1000, alias);
    }
    return guardian;
  }

  async getGuardianByMspId(mspId) {
    if (!mspId) return this.getGuardianByAlias("default") // if mspId undefined, get default guardian
    for (const key in this.guardianMap) {
      const guardian = this.guardianMap[key];
      const id = await guardian.getMspId();
      if (id == mspId) {
        return guardian;
      }
    }
  }

  async getServer(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.getServer();
  }

  async setServer(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.setServer(data);
  }

  async getBusiness(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.getBusiness();
  }

  async setBusiness(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.setBusiness(data);
  }

  async getRegion(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.getRegion();
  }

  async start(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.start();
  }

  async stop(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.stop();
  }

  async reset(data = {}) {
    const guardian = await this.getGuardianByMspId(data.mspId);
    if (!guardian) {
      throw new Error(`The guardian ${data.mspId} doesn't exist, please check`);
    }
    await guardian.reset();
    await rclient.zremAsync(guardianListKey, guardian.name);
  }

  async setAndStartGuardianService(data) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.setAndStartGuardianService(data);
  }

  async getGuardians() {
    const result = [];
    await Promise.all(Object.keys(this.guardianMap).map(async (alias) => {
      const guarndian = await this.getGuardianByAlias(alias);
      const info = await guarndian.getGuardianInfo();
      info && result.push(info);
    }))
    return result
  }

  async getGuardian(data) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.getGuardianInfo();
  }
}

module.exports = GuardianSensor;
<commit_msg>delete guardian instance from map<commit_after>/*    Copyright 2019-2022 Firewalla Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    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/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename)
const rclient = require('../util/redis_manager.js').getRedisClient();
const Sensor = require('./Sensor.js').Sensor
const Promise = require('bluebird')
const extensionManager = require('./ExtensionManager.js')
const guardianListKey = "guardian:alias:list";
const Guardian = require('./Guardian');
const _ = require('lodash');

class GuardianSensor extends Sensor {
  constructor() {
    super();
    this.guardianMap = {};
  }

  async apiRun() {
    await this.startGuardians();

    extensionManager.onGet("guardianSocketioServer", (msg, data) => {
      return this.getServer(data);
    });

    extensionManager.onSet("guardianSocketioServer", async (msg, data) => {
      return this.setServer(data);
    });

    extensionManager.onGet("guardian.business", async (msg, data) => {
      return this.getBusiness(data);
    });

    extensionManager.onSet("guardian.business", async (msg, data) => {
      return this.setBusiness(data);
    });

    extensionManager.onGet("guardianSocketioRegion", (msg, data) => {
      return this.getRegion(data);
    });

    extensionManager.onCmd("startGuardianSocketioServer", (msg, data) => {
      return this.start(data);
    });

    extensionManager.onCmd("stopGuardianSocketioServer", (msg, data) => {
      return this.stop(data);
    });

    extensionManager.onCmd("resetGuardian", (msg, data) => {
      return this.reset(data);
    });

    extensionManager.onCmd("setAndStartGuardianService", async (msg, data) => {
      return this.setAndStartGuardianService(data);
    });

    extensionManager.onGet("guardians", async (msg, data) => {
      return this.getGuardians(data);
    });

    extensionManager.onGet("guardian", async (msg, data) => {
      return this.getGuardian(data);
    })
  }

  async startGuardians() {
    let aliases = await rclient.zrangeAsync(guardianListKey, 0, -1);
    aliases = _.uniq((aliases || []).concat("default"));

    log.forceInfo('Start guardian for these alias', aliases);

    await Promise.all(aliases.map(async alias => {
      const guardian = new Guardian(alias);
      await guardian.init();
      this.guardianMap[alias] = guardian;
    }))
  }

  async getGuardianByAlias(alias = "default") {
    let guardian = this.guardianMap[alias];
    if (!guardian) {
      guardian = new Guardian(alias);
      this.guardianMap[alias] = guardian;
      await rclient.zadd(guardianListKey, Date.now() / 1000, alias);
    }
    return guardian;
  }

  async getGuardianByMspId(mspId) {
    if (!mspId) return this.getGuardianByAlias("default") // if mspId undefined, get default guardian
    for (const key in this.guardianMap) {
      const guardian = this.guardianMap[key];
      const id = await guardian.getMspId();
      if (id == mspId) {
        return guardian;
      }
    }
  }

  async getServer(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.getServer();
  }

  async setServer(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.setServer(data);
  }

  async getBusiness(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.getBusiness();
  }

  async setBusiness(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.setBusiness(data);
  }

  async getRegion(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.getRegion();
  }

  async start(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.start();
  }

  async stop(data = {}) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.stop();
  }

  async reset(data = {}) {
    const guardian = await this.getGuardianByMspId(data.mspId);
    if (!guardian) {
      throw new Error(`The guardian ${data.mspId} doesn't exist, please check`);
    }
    await guardian.reset();
    await rclient.zremAsync(guardianListKey, guardian.name);
    delete this.guardianMap[guardian.name];
  }

  async setAndStartGuardianService(data) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.setAndStartGuardianService(data);
  }

  async getGuardians() {
    const result = [];
    await Promise.all(Object.keys(this.guardianMap).map(async (alias) => {
      const guarndian = await this.getGuardianByAlias(alias);
      const info = await guarndian.getGuardianInfo();
      info && result.push(info);
    }))
    return result
  }

  async getGuardian(data) {
    const guardian = await this.getGuardianByAlias(data.alias);
    return guardian.getGuardianInfo();
  }
}

module.exports = GuardianSensor;
<|endoftext|>


<commit_before>import MACDTooltip from "./MACDTooltip";
// import TooltipContainer from "./TooltipContainer";
import OHLCTooltip from "./OHLCTooltip";
import SingleValueTooltip from "./SingleValueTooltip";
import MovingAverageTooltip from "./MovingAverageTooltip";
import BollingerBandTooltip from "./BollingerBandTooltip";
import RSITooltip from "./RSITooltip";
import StochasticTooltip from "./StochasticTooltip";
import HoverTooltip from "./HoverTooltip";

export {
	MACDTooltip,
//	TooltipContainer,
	OHLCTooltip,
	SingleValueTooltip,
	MovingAverageTooltip,
	BollingerBandTooltip,
	RSITooltip,
	StochasticTooltip,
	HoverTooltip
};<commit_msg>Fix #143: Export ToolTip helper components<commit_after>import MACDTooltip from "./MACDTooltip";
// import TooltipContainer from "./TooltipContainer";
import OHLCTooltip from "./OHLCTooltip";
import SingleValueTooltip from "./SingleValueTooltip";
import MovingAverageTooltip from "./MovingAverageTooltip";
import BollingerBandTooltip from "./BollingerBandTooltip";
import RSITooltip from "./RSITooltip";
import StochasticTooltip from "./StochasticTooltip";
import HoverTooltip from "./HoverTooltip";
import ToolTipText from "./ToolTipText";
import ToolTipTSpanLabel from "./ToolTipTSpanLabel";

export {
	MACDTooltip,
//	TooltipContainer,
	OHLCTooltip,
	SingleValueTooltip,
	MovingAverageTooltip,
	BollingerBandTooltip,
	RSITooltip,
	StochasticTooltip,
	HoverTooltip,
	ToolTipText,
	ToolTipTSpanLabel
};<|endoftext|>


<commit_before>var fs = require('fs')
var path = require('path')

var cosmiconfig = require('cosmiconfig')
var repeatString = require('repeat-string')
var editorconfig = require('editorconfig')

var isEmptyObject = require('./util').isEmptyObject

var defaultIndentWidth = repeatString(' ', 2)
// same as the options in stylelint
var cosmiconfigOpts = {
  argv: false,
  rcExtensions: true
}

function hasScssInWorkingDir (wd) {
  var dirs = fs.readdirSync(wd)
  return dirs.some(function (dir) {
    return dir.match(/.*\.scss/)
  })
}

function getIndentationFromEditorConfig (from, hasScss) {
  var config
  if (hasScss) {
    config = editorconfig.parseSync(path.resolve(process.cwd(), '*.scss'))
  } else {
    config = editorconfig.parseSync(path.resolve(process.cwd(), '*.css'))
  }
  switch ((config || {}).indent_style) {
    case 'tab':
      return '\t'
    case 'space':
      return repeatString(' ', config.indent_size)
    default:
      return defaultIndentWidth
  }
}

function getIndentationFromStylelintRules (rules) {
  var indentaiton = rules['indentation']
  switch (typeof indentaiton) {
    case 'string':
      return '\t'
    case 'number':
      return repeatString(' ', indentaiton)
    default:
      return defaultIndentWidth
  }
}

function augmentParams (originParams, extentions) {
  var initialValue = Promise.resolve(originParams || {})
  var promise = extentions.reduce(function (promise, extention) {
    return promise.then(function (mergedParams) {
      return cosmiconfig(extention, cosmiconfigOpts).then(function (stylelint) {
        var params = {}
        var rules = stylelint.config.rules
        params.indentWidth = getIndentationFromStylelintRules(rules)
        params.stylelint = rules
        return Object.assign({}, mergedParams, params)
      })
    })
  }, initialValue)
  return promise
}

function parmas (from) {
  var wd = path.dirname(from) || process.cwd()
  var params = {}

  var hasScss = hasScssInWorkingDir(wd)
  params.hasScss = hasScss

  return cosmiconfig('stylelint', cosmiconfigOpts).then(function (stylelint) {
    if (isEmptyObject(stylelint) || isEmptyObject(stylelint.config)) {
      params.indentWidth = getIndentationFromEditorConfig(wd, hasScss)
      params.stylelint = {}
      return Promise.resolve(params)
    }

    var rules = stylelint.config.rules
    if (!stylelint.config.extends) {
      params.indentWidth = getIndentationFromStylelintRules(rules)
      params.stylelint = rules
      return Promise.resolve(params)
    }

    var extentions = [].concat(stylelint.config.extends)
    return augmentParams(rules, extentions)
  })
}

module.exports = parmas
<commit_msg>modify default values<commit_after>var fs = require('fs')
var path = require('path')

var cosmiconfig = require('cosmiconfig')
var repeatString = require('repeat-string')
var editorconfig = require('editorconfig')

var isEmptyObject = require('./util').isEmptyObject

var defaultIndentWidth = repeatString(' ', 2)
// same as the options in stylelint
var cosmiconfigOpts = {
  argv: false,
  rcExtensions: true
}

function hasScssInWorkingDir (wd) {
  var dirs = fs.readdirSync(wd)
  return dirs.some(function (dir) {
    return dir.match(/.*\.scss/)
  })
}

function getIndentationFromEditorConfig (from, hasScss) {
  var config
  if (hasScss) {
    config = editorconfig.parseSync(path.resolve(process.cwd(), '*.scss'))
  } else {
    config = editorconfig.parseSync(path.resolve(process.cwd(), '*.css'))
  }
  switch ((config || {}).indent_style) {
    case 'tab':
      return '\t'
    case 'space':
      return repeatString(' ', config.indent_size)
    default:
      return defaultIndentWidth
  }
}

function getIndentationFromStylelintRules (rules) {
  var indentaiton = rules['indentation']
  switch (typeof indentaiton) {
    case 'string':
      return '\t'
    case 'number':
      return repeatString(' ', indentaiton)
    default:
      return defaultIndentWidth
  }
}

function augmentParams (originParams, extentions) {
  var initialValue = Promise.resolve(originParams)
  var promise = extentions.reduce(function (promise, extention) {
    return promise.then(function (mergedParams) {
      var opts = Object.assign({}, cosmiconfigOpts, { configPath: extention })
      return cosmiconfig(null, opts).then(function (stylelint) {
        if (!stylelint) {
          return mergedParams
        }
        var params = {}
        var rules = stylelint.config.rules
        params.indentWidth = getIndentationFromStylelintRules(rules)
        params.stylelint = rules
        return Object.assign({}, mergedParams, params)
      })
    })
  }, initialValue)
  return promise
}

function parmas (from) {
  var wd = path.dirname(from) || process.cwd()
  return cosmiconfig('stylelint', cosmiconfigOpts).then(function (stylelint) {
    var params = {}

    var hasScss = hasScssInWorkingDir(wd)
    params.hasScss = hasScss

    if (isEmptyObject(stylelint)) {
      params.indentWidth = getIndentationFromEditorConfig(wd, hasScss)
      params.stylelint = {}
      return Promise.resolve(params)
    }

    var extentions = [].concat(stylelint.config.extends)
    var rules = stylelint.config.rules
    if (!isEmptyObject(rules)) {
      params.indentWidth = getIndentationFromStylelintRules(rules)
      params.stylelint = rules
    }
    return augmentParams(params, extentions)
  })
}

module.exports = parmas
<|endoftext|>


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

define([
    'jquery',
    'knockout',
    'bootbox',
    'utils/utils',
    'models/host-definition'
], function ($, ko, bootbox, utils, HostDefinition) {
    'use strict';

    // Define the snapshot model.
    function Snapshot(raw, parent) {
        var needReload = false;
        if (typeof raw === 'string') {
            raw = parseInt(raw);
        }
        if (typeof raw === 'number') {
            needReload = true;
            // Set the things we need for the reload
            raw = {
                id: raw,
                url: '/api/cloud/snapshots/' + raw + '/'
            }
        }

        // Save the raw in order to get things like URLs
        this.raw = raw;

        // Save the parent VM
        this.parent = parent;

        // Save the id
        this.id = raw.id;

        // Editable fields
        this.title = ko.observable();
        this.description = ko.observable();
        this.accountId = ko.observable();
        this.snapshotId = ko.observable();
        this.sizeInGB = ko.observable();
        this.filesystemType = ko.observable();

        if (needReload) {
            this.waiting = this.reload();
        } else {
            this._process(raw);
        }
    }

    Snapshot.constructor = Snapshot;

    Snapshot.prototype._process = function (raw) {
        this.title(raw.title);
        this.description(raw.description);
        this.accountId(raw.account);
        this.snapshotId(raw.snapshot_id);
        this.sizeInGB(raw.size_in_gb);
        this.filesystemType(raw.filesystem_type);
    };

    // Reload the current snapshot
    Snapshot.prototype.reload = function () {
        var self = this;
        return $.ajax({
            method: 'GET',
            url: this.raw.url
        }).done(function (snapshot) {
            self.raw = snapshot;
            self._process(snapshot);
        });
    };

    Snapshot.prototype.save = function () {
        var self = this;
        var keys = ['title', 'description', 'snapshot_id', 'size_in_gb', 'filesystem_type'];

        keys.forEach(function (key) {
            var el = $('#' + key);
            el.removeClass('has-error');
            var help = el.find('.help-block');
            help.remove();
        });

        $.ajax({
            method: 'PUT',
            url: self.raw.url,
            data: JSON.stringify({
                title: self.title(),
                description: self.description(),
                snapshot_id: self.snapshotId(),
                size_in_gb: self.sizeInGB(),
                filesystem_type: self.filesystemType()
            })
        }).done(function (snapshot) {
            utils.growlAlert('Successfully saved snapshot!', 'success');
            try {
                self.parent.snapshotTitle(snapshot.title);
            } catch (e) {}
        }).fail(function (jqxhr) {
            utils.parseSaveError(jqxhr, 'snapshot', keys);
        });
    };

    Snapshot.prototype.delete = function () {
        var self = this;
        var snapshotTitle = this.title();
        bootbox.confirm({
            title: 'Confirm delete of ' + snapshotTitle + '',
            message: 'Are you sure you want to delete ' + snapshotTitle + '?',
            buttons: {
                confirm: {
                    label: 'Delete',
                    className: 'btn-danger'
                }
            },
            callback: function (result) {
                if (result) {
                    $.ajax({
                        method: 'DELETE',
                        url: self.raw.url
                    }).done(function (snapshot) {
                        // Nothing to do here?
                    }).fail(function (jqxhr) {
                        var message;
                        try {
                            var resp = JSON.parse(jqxhr.responseText);
                            message = resp.detail.join('
');
                        } catch (e) {
                            message = 'Oops... there was a server error.  This has been reported ' +
                                'to your administrators.';
                        }
                        bootbox.alert({
                            title: 'Error deleting snapshot',
                            message: message
                        });
                    });
                }
            }
        });
    };

    return Snapshot;
});<commit_msg>PI-497 go back to the list page after deletion<commit_after>
/*!
  * Copyright 2014,  Digital Reasoning
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
*/

define([
    'jquery',
    'knockout',
    'bootbox',
    'utils/utils',
    'models/host-definition'
], function ($, ko, bootbox, utils, HostDefinition) {
    'use strict';

    // Define the snapshot model.
    function Snapshot(raw, parent) {
        var needReload = false;
        if (typeof raw === 'string') {
            raw = parseInt(raw);
        }
        if (typeof raw === 'number') {
            needReload = true;
            // Set the things we need for the reload
            raw = {
                id: raw,
                url: '/api/cloud/snapshots/' + raw + '/'
            }
        }

        // Save the raw in order to get things like URLs
        this.raw = raw;

        // Save the parent VM
        this.parent = parent;

        // Save the id
        this.id = raw.id;

        // Editable fields
        this.title = ko.observable();
        this.description = ko.observable();
        this.accountId = ko.observable();
        this.snapshotId = ko.observable();
        this.sizeInGB = ko.observable();
        this.filesystemType = ko.observable();

        if (needReload) {
            this.waiting = this.reload();
        } else {
            this._process(raw);
        }
    }

    Snapshot.constructor = Snapshot;

    Snapshot.prototype._process = function (raw) {
        this.title(raw.title);
        this.description(raw.description);
        this.accountId(raw.account);
        this.snapshotId(raw.snapshot_id);
        this.sizeInGB(raw.size_in_gb);
        this.filesystemType(raw.filesystem_type);
    };

    // Reload the current snapshot
    Snapshot.prototype.reload = function () {
        var self = this;
        return $.ajax({
            method: 'GET',
            url: this.raw.url
        }).done(function (snapshot) {
            self.raw = snapshot;
            self._process(snapshot);
        });
    };

    Snapshot.prototype.save = function () {
        var self = this;
        var keys = ['title', 'description', 'snapshot_id', 'size_in_gb', 'filesystem_type'];

        keys.forEach(function (key) {
            var el = $('#' + key);
            el.removeClass('has-error');
            var help = el.find('.help-block');
            help.remove();
        });

        $.ajax({
            method: 'PUT',
            url: self.raw.url,
            data: JSON.stringify({
                title: self.title(),
                description: self.description(),
                snapshot_id: self.snapshotId(),
                size_in_gb: self.sizeInGB(),
                filesystem_type: self.filesystemType()
            })
        }).done(function (snapshot) {
            utils.growlAlert('Successfully saved snapshot!', 'success');
            try {
                self.parent.snapshotTitle(snapshot.title);
            } catch (e) {}
        }).fail(function (jqxhr) {
            utils.parseSaveError(jqxhr, 'snapshot', keys);
        });
    };

    Snapshot.prototype.delete = function () {
        var self = this;
        var snapshotTitle = this.title();
        bootbox.confirm({
            title: 'Confirm delete of ' + snapshotTitle + '',
            message: 'Are you sure you want to delete ' + snapshotTitle + '?',
            buttons: {
                confirm: {
                    label: 'Delete',
                    className: 'btn-danger'
                }
            },
            callback: function (result) {
                if (result) {
                    $.ajax({
                        method: 'DELETE',
                        url: self.raw.url
                    }).done(function (snapshot) {
                        window.location = '/snapshots/';
                    }).fail(function (jqxhr) {
                        var message;
                        try {
                            var resp = JSON.parse(jqxhr.responseText);
                            message = resp.detail.join('
');
                        } catch (e) {
                            message = 'Oops... there was a server error.  This has been reported ' +
                                'to your administrators.';
                        }
                        bootbox.alert({
                            title: 'Error deleting snapshot',
                            message: message
                        });
                    });
                }
            }
        });
    };

    return Snapshot;
});<|endoftext|>


<commit_before>'use strict';

// MODULES //

var isString = require( '@stdlib/utils/is-string' ).isPrimitive;
var hasOwnProp = require( '@stdlib/utils/has-own-property' );
var ABBRS = require( './abbreviations.json' );
var EMOJIS = require( './emojis.json' );
var CONTRACT = require( './contractions' );

// VARIABLES //

var REGEXP_PREFIXES = /^([,\(\[\{*<"“'`‘.])/gi;
var REGEXP_SUFFIXES = /([,.!?%*>:;"'”`\)\]\}])$/gi;

// FUNCTIONS //

/**
* Extends an array by the elements of another array.
*
* @param {Array} arr - input array
* @param {Array} ext - array to extend `arr` with
* @returns {Array} mutated input array
*
* @example
* var arr = [ 1, 2, 3 ];
* var out = extends( arr, [ 4, 5 ] );
* // returns [ 1, 2, 3, 4, 5 ]
*/
function extend( arr, ext ) {
	var i;
	for ( i = 0; i < ext.length; i++ ) {
		arr.push( ext[ i ] );
	}
	return arr;
} // end FUNCTION extend()

/**
* Tokenizes a substring.
*
* @param {string} substr - input string
* @returns {Array} token array
*
* @example
* var str = '(never)';
* var out = tokenizeSubstring( str );
* // returns [ '(', 'never', ')' ]
*/
function tokenizeSubstring( substr ) {
	var prefixes = [];
	var suffixes = [];
	var match;
	var done;
	var res;

	do {
		if (
			!EMOJIS[ substr ] &&
			!ABBRS[ substr ] &&
			!CONTRACT[ substr ]
		) {
			match = substr.split( REGEXP_PREFIXES );
			if ( match.length > 1 ) {
				prefixes.push( match[ 1 ] );
				substr = match[ 2 ];
			}
			else {
				match = substr.split( REGEXP_SUFFIXES );
				if ( match.length > 1 ) {
					substr = match[ 0 ];
					suffixes.push( match[ 1 ] );
				} else {
					done = true;
				}
			}
		}
		else {
			done = true;
		}
	} while ( !done );

	res = prefixes;
	res.push( substr );
	extend( res, suffixes );
	return res;
} // end FUNCTION tokenizeSubstring()

// TOKENIZE //

/**
* Tokenize a string.
*
* @param {string} str - input string
* @throws {TypeError} must provide a string primitive
* @returns {Array} array of tokens
*
* @example
* var str = 'Hello World!';
* var out = tokenize( str );
* // returns [ 'Hello', 'World', '!' ]
*
* @example
* var str = '';
* var out = tokenize( str );
* // returns []
*
* @example
* var str = 'Hello Mrs. Maple, could you call me back?';
* var out = tokenize( str );
* // returns  [ 'Hello', 'Mrs.', 'Maple', ',', 'could', 'you', 'call', 'me', 'back', '?' ]
*/
function tokenize( str ) {
	var subtkns;
	var substrs;
	var tokens;
	var substr;
	var cache;
	var i;
	if ( !isString( str ) ) {
		throw new TypeError( 'invalid input argument. First argument must be a string primitive. Value: `' + str + '`.' );
	}
	if ( !str ) {
		return [];
	}

	// Split on whitespace:
	substrs = str.split( /\s+/ );

	// Set up cache to hold tokens for substring matches:
	cache = {};

	// Initialize token array:
	tokens = [];

	for ( i = 0; i < substrs.length; i++ ) {
		substr = substrs[ i ];
		if ( hasOwnProp( cache, substr ) ) {
			extend( tokens, cache[ substr ] );
		}
		else {
			subtkns = tokenizeSubstring( substr );
			extend( tokens, subtkns );
			cache[ substr ] = subtkns;
		}
	}
	return tokens;
} // end FUNCTION tokenize()

// EXPORTS //

module.exports = tokenize;
<commit_msg>Change header<commit_after>'use strict';

// MODULES //

var isString = require( '@stdlib/utils/is-string' ).isPrimitive;
var hasOwnProp = require( '@stdlib/utils/has-own-property' );
var ABBRS = require( './abbreviations.json' );
var EMOJIS = require( './emojis.json' );
var CONTRACT = require( './contractions' );

// VARIABLES //

var REGEXP_PREFIXES = /^([,\(\[\{*<"“'`‘.])/gi;
var REGEXP_SUFFIXES = /([,.!?%*>:;"'”`\)\]\}])$/gi;

// FUNCTIONS //

/**
* Extends an array by the elements of another array.
*
* @param {Array} arr - input array
* @param {Array} ext - array to extend `arr` with
* @returns {Array} mutated input array
*
* @example
* var arr = [ 1, 2, 3 ];
* var out = extends( arr, [ 4, 5 ] );
* // returns [ 1, 2, 3, 4, 5 ]
*/
function extend( arr, ext ) {
	var i;
	for ( i = 0; i < ext.length; i++ ) {
		arr.push( ext[ i ] );
	}
	return arr;
} // end FUNCTION extend()

/**
* Tokenizes a substring.
*
* @param {string} substr - input string
* @returns {Array} token array
*
* @example
* var str = '(never)';
* var out = tokenizeSubstring( str );
* // returns [ '(', 'never', ')' ]
*/
function tokenizeSubstring( substr ) {
	var prefixes = [];
	var suffixes = [];
	var match;
	var done;
	var res;

	do {
		if (
			!EMOJIS[ substr ] &&
			!ABBRS[ substr ] &&
			!CONTRACT[ substr ]
		) {
			match = substr.split( REGEXP_PREFIXES );
			if ( match.length > 1 ) {
				prefixes.push( match[ 1 ] );
				substr = match[ 2 ];
			}
			else {
				match = substr.split( REGEXP_SUFFIXES );
				if ( match.length > 1 ) {
					substr = match[ 0 ];
					suffixes.push( match[ 1 ] );
				} else {
					done = true;
				}
			}
		}
		else {
			done = true;
		}
	} while ( !done );

	res = prefixes;
	res.push( substr );
	extend( res, suffixes );
	return res;
} // end FUNCTION tokenizeSubstring()

// MAIN //

/**
* Tokenize a string.
*
* @param {string} str - input string
* @throws {TypeError} must provide a string primitive
* @returns {Array} array of tokens
*
* @example
* var str = 'Hello World!';
* var out = tokenize( str );
* // returns [ 'Hello', 'World', '!' ]
*
* @example
* var str = '';
* var out = tokenize( str );
* // returns []
*
* @example
* var str = 'Hello Mrs. Maple, could you call me back?';
* var out = tokenize( str );
* // returns  [ 'Hello', 'Mrs.', 'Maple', ',', 'could', 'you', 'call', 'me', 'back', '?' ]
*/
function tokenize( str ) {
	var subtkns;
	var substrs;
	var tokens;
	var substr;
	var cache;
	var i;
	if ( !isString( str ) ) {
		throw new TypeError( 'invalid input argument. First argument must be a string primitive. Value: `' + str + '`.' );
	}
	if ( !str ) {
		return [];
	}

	// Split on whitespace:
	substrs = str.split( /\s+/ );

	// Set up cache to hold tokens for substring matches:
	cache = {};

	// Initialize token array:
	tokens = [];

	for ( i = 0; i < substrs.length; i++ ) {
		substr = substrs[ i ];
		if ( hasOwnProp( cache, substr ) ) {
			extend( tokens, cache[ substr ] );
		}
		else {
			subtkns = tokenizeSubstring( substr );
			extend( tokens, subtkns );
			cache[ substr ] = subtkns;
		}
	}
	return tokens;
} // end FUNCTION tokenize()

// EXPORTS //

module.exports = tokenize;
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Mansi Shah, Santosh Rajan
*/

var ast = {
        type: "Program",
        body: []
    }

module.exports = function(src) {

    var spaceRegEx = /^[ \t\r\n\b\f]+/,
        newLineRegEx = /\r?\n/g,
        nullRegEx = /^null\b/i,
        booleanRegEx = /^(true|false)\b/i,
        numberRegEx = /^[-+]?(\d+(\.\d*)?|\.\d+)([e][+-]?\d+)?/i,
        stringRegEx = /^('|").*?[^\\]\1/,
        identifierRegEx = /^[a-z\~]+[a-z0-9_\[\]\.\*]*/i,
        openParanthesesRegEx = /^\(/,
        closingParanthesesRegEx = /^\)/,
        operatorRegEx = /^(\*|\+|\-|\/|\%)/,
        functionKeywordRegEx = /^(\()(\s)*function/,
        macroKeywordRegEx = /^(\()(\s)*macro\b/,
        varKeywordRegEx = /^(\()?(\s)*var/,
        fatArrowRegEx = /^\=\>/,
        line = 1
        macros = {}

    function consumer(regex, process) {
        return function() {
            var matches = regex.exec(src)
            if(!matches) return null
            src = src.slice(matches[0].length)
            spaceParser()
            if(process)    return process(matches[0])
            return matches[0]
        }
    }

    function parserFactory() {
        var parsers = arguments
        return function() {
            for(index in parsers){
                var parser = parsers[index]
                spaceParser()
                var result = parser()
                if(result)  return result
            }
            return null
        }
    }

    var spaceParser = consumer(spaceRegEx, function(val){
            var match = val.match(newLineRegEx)
            var l = (match)? match.length : 0
            line+=l
            return true
        }),
        nullParser = consumer(nullRegEx, function(){
            return {type: "Literal", value: null}
        }),
        booleanParser = consumer(booleanRegEx, function(val){
            return {type: "Literal", value: val}
        }),
        numberParser = consumer(numberRegEx, function(val){
            return {type: "Literal", value: Number(val)}
        }),
        stringParser = consumer(stringRegEx, function(val){
            return {type: "Literal", value: val.slice(1,val.length-1)}
        }),
        literalParser = parserFactory(nullParser, booleanParser, numberParser, stringParser),
        identifierParser = consumer(identifierRegEx, function(val) {
            return {type: "Identifier", name: val}
        }),
        elementParser = parserFactory(literalParser, identifierParser),
        openParanthesesParser = consumer(openParanthesesRegEx, function(val){
            return true
        }),
        closingParanthesesParser = consumer(closingParanthesesRegEx, function(val){
            return true
        }),
        operatorParser = consumer(operatorRegEx),
        varKeywordParser = consumer(varKeywordRegEx),
        functionKeywordParser = consumer(functionKeywordRegEx),
        macroKeywordParser = consumer(macroKeywordRegEx),
        fatArrowParser = consumer(fatArrowRegEx)

    function argumentsParser() {
        var args = []
        spaceParser()
        while(!closingParanthesesParser()){
            arg = argStatementParser()
            if (!arg)
                throw new SyntaxError("argumentsParser : Unexpected character at line: "+line)
            args.push(arg)
            spaceParser()
        }
        spaceParser()
        if (args.length > 0)
            return args
        return []
    }

    function expressionParser() {
        if (!openParanthesesParser()) return null
        return callExpressionParser() || binaryExpressionParser() || statementParser()
    }

    function expressionStatementParser() {
        spaceParser()
        if (closingParanthesesParser())  return null
        return combinator({type: "ExpressionStatement"}, ["expression", expressionParser])
    }

    function dereferencer(macro, tree) {
        for(objs in tree){
            if (Array.isArray(tree[objs])) {
                var restArgs = []
                tree[objs].forEach(function(t, idx){
                    var persistObjs = objs
                    tree[objs][idx] = dereferencer(macro, t)
                    objs = persistObjs
                    if(Array.isArray(tree[objs][tree[objs].length-1]['deletenode'])){
                        restArgs = tree[objs][idx]['deletenode']
                    }
                })
                if(restArgs.length > 0){
                    tree[objs].pop()
                    restArgs.forEach(function(ele){
                        tree[objs].push(ele)
                    })
                }
            }
            else if (typeof tree[objs] === "object") {
                dereferencer(macro, tree[objs])
            }
            if (objs === "type" && tree[objs] === "Identifier") {
                if (tilde = /^\~(.*|\.\.\.rest)\b/.exec(tree.name)) {
                    var ref = tilde[0].slice(1)
                    // Fix this: Should be ...rest
                    if(ref === "...rest")    tree = {deletenode: macro.params[ref]}
                    else    tree = macro.params[ref]
                }
            }
        }

        return tree
    }

    function macroCallParser() {
        var temp = src
        if(!openParanthesesParser()) return null
        spaceParser()
        var expr = {}
        if (expr.callee = identifierParser()) {
            spaceParser()
            expr.arguments = argumentsParser() || []
            if (macroCopy = macros[expr.callee.name.toString()]) {
                var macro = JSON.parse(JSON.stringify(macroCopy))
                var macroName = expr.callee.name
                var args = expr.arguments.map(function(arg){
                    return arg
                })
                for(param in macro.params){
                    if (param != "...rest")
                        macro.params[param] = args.shift()
                }
                macro.params['...rest'] = args
                var macroExpr = dereferencer(macro, macro.body)
                return macroExpr
            }
        }

        src = temp
        return null
    }
    function callExpressionParser() {
        return combinator({type: "CallExpression"}, ["callee", identifierParser], ["arguments", argumentsParser])
    }

    function binaryExpressionParser() {
        return combinator({type: "BinaryExpression"}, ["operator", operatorParser], ["left", elementParser], ["right", elementParser], ["", closingParanthesesParser])
    }

    function extractExpression() {
        var found = false, parantheses = 1, i = 0
        while(!found){
            if (src[i] == '(')
                parantheses++
            if (src[i] == ')')
                parantheses--
            if (parantheses == 0)
                found = true
            i++
        }

        return src.slice(0,i)
    }

    function macroDeclarationParser() {
        if (!macroKeywordParser())    return null
        var snippet = extractExpression()
        var rest = src.slice(snippet.length)
        src = snippet
        spaceParser()

        //id
        if (id = identifierParser())
            macroId = id.name
        else
            throw new SyntaxError("Expecting a macro identifier")
        spaceParser()

        //params
        if (!openParanthesesParser())
            throw new SyntaxError("Expecting '(' after " + macroId)

        var macro = {}
        macro.params = {}
        while(!closingParanthesesParser()){
            if (param = identifierParser()) {
                var paramName = param.name
                // param[paramName.toString()] = null
                macro.params[paramName.toString()] = null
            }
            spaceParser()
        }
        macro.params["...rest"] = []
        spaceParser()

        //body
        macro.body = []

        //Fix this: Not very desirable, might go in infinite loop
        while(src.length != 0){
            macro.body.push(statementParser(src.slice(0,src.length-1)))
            spaceParser()
            closingParanthesesParser()
        }

        src = rest
        spaceParser()

        macros[macroId.toString()] = macro
        return null

    }

    function combinator(expr){
        for(var i=1; i<arguments.length; i++){
            var attr = arguments[i][0]
            var parser = arguments[i][1]
            var args = arguments[i][2]
            if(typeof parser == "function"){
                if(Array.isArray(args)){
                    var result = parser(args[0],args[1])
                }
                else
                    var result = parser()
                if(result == null) return null
            }
            else
                result = parser

            if(attr){
                expr[attr] = result
            }
        }
        return expr
    }

    function functionDeclarationParser() {
        if (!functionKeywordParser())    return null
        var snippet = extractExpression()
        var rest = src.slice(snippet.length)
        src = snippet
        var expr = combinator({type: "FunctionDeclaration"}, ["id", identifierParser], ["",openParanthesesParser], ["params",argumentsParser], ["defaults", []], ["body", combinator, [{type: "BlockStatement", body: []}, ["body", functionBodyParser]]], ["generator", false], ["expression", false])
        src = rest
        return expr
    }

    function initializerParser() {
        return elementParser() || expressionParser()
    }

    function variableDeclarationParser() {
        if (!varKeywordParser()) return null
        var expr = {type: "VariableDeclaration", declarations: [], kind: "var"}
        var innerExpr = combinator({type: "VariableDeclarator"}, ["id", identifierParser], ["init", initializerParser], ["", closingParanthesesParser])
        expr.declarations.push(innerExpr)
        closingParanthesesParser()
        return expr
    }

    function arrowFunctionParser() {
        if (!fatArrowParser())   return null
        var snippet = extractExpression()
        var rest = src.slice(snippet.length)
        src = snippet
        var expr = combinator({type: "ArrowFunctionExpression"}, ["id", null], ["", openParanthesesParser], ["params", argumentsParser], ["defaults", []], ["body", combinator, [{type: "BlockStatement"}, ["body", functionBodyParser]]], ["generator", false], ["expression", false])
        src = rest
        return expr
    }

    function functionBodyParser() {
        var stmts = []
        while(!closingParanthesesParser()){
            var stmt = argStatementParser()
            if(stmt != null)
                stmts.push(stmt)
        }
        stmts[stmts.length-1] = {type: "ReturnStatement", argument: stmts[stmts.length-1]}
        //Fix this: literal splitting up in characters
        //Fix this: what about ...rest in functions?

        return stmts
    }

    function statementParser() {
        return arrowFunctionParser() || macroDeclarationParser()|| functionDeclarationParser() || variableDeclarationParser() || elementParser() || macroCallParser() || expressionStatementParser()
    }

    //Fix this: Have to figure out a way to remove this function
    function argStatementParser() {
        return arrowFunctionParser() || macroDeclarationParser()|| functionDeclarationParser() || variableDeclarationParser() || elementParser() || expressionParser()
    }

    function bodyParser() {
        var body = []
        while(src.length != 0){
            spaceParser()
            var stmt = statementParser()
            if (!stmt)
                throw new SyntaxError("Cannot parse statement at line: " + line)
            if(Array.isArray(stmt))
                stmt.forEach(function(s){body.push(s)})
            else
                body.push(stmt)

        }
        return body
    }

    ast.body = bodyParser()
    return ast
}<commit_msg>Code cleanup<commit_after>/*
 * Copyright (c) 2015 Mansi Shah, Santosh Rajan
*/

var ast = {
        type: "Program",
        body: []
    }

module.exports = function(src) {

    var spaceRegEx = /^[ \t\r\n\b\f]+/,
        newLineRegEx = /\r?\n/g,
        nullRegEx = /^null\b/i,
        booleanRegEx = /^(true|false)\b/i,
        numberRegEx = /^[-+]?(\d+(\.\d*)?|\.\d+)([e][+-]?\d+)?/i,
        stringRegEx = /^('|").*?[^\\]\1/,
        identifierRegEx = /^[a-z\~]+[a-z0-9_\[\]\.\*]*/i,
        openParanthesesRegEx = /^\(/,
        closingParanthesesRegEx = /^\)/,
        operatorRegEx = /^(\*|\+|\-|\/|\%)/,
        functionKeywordRegEx = /^(\()(\s)*function/,
        macroKeywordRegEx = /^(\()(\s)*macro\b/,
        varKeywordRegEx = /^(\()?(\s)*var/,
        fatArrowRegEx = /^\=\>/,
        line = 1
        macros = {}

    function consumer(regex, process) {
        return function() {
            var matches = regex.exec(src)
            if(!matches) return null
            src = src.slice(matches[0].length)
            spaceParser()
            if(process)    return process(matches[0])
            return matches[0]
        }
    }

    function parserFactory() {
        var parsers = arguments
        return function() {
            for(index in parsers){
                var parser = parsers[index]
                spaceParser()
                var result = parser()
                if(result)  return result
            }
            return null
        }
    }

    var spaceParser = consumer(spaceRegEx, function(val){
            var match = val.match(newLineRegEx)
            var l = (match)? match.length : 0
            line+=l
            return true
        }),
        nullParser = consumer(nullRegEx, function(){
            return {type: "Literal", value: null}
        }),
        booleanParser = consumer(booleanRegEx, function(val){
            return {type: "Literal", value: val}
        }),
        numberParser = consumer(numberRegEx, function(val){
            return {type: "Literal", value: Number(val)}
        }),
        stringParser = consumer(stringRegEx, function(val){
            return {type: "Literal", value: val.slice(1,val.length-1)}
        }),
        literalParser = parserFactory(nullParser, booleanParser, numberParser, stringParser),
        identifierParser = consumer(identifierRegEx, function(val) {
            return {type: "Identifier", name: val}
        }),
        elementParser = parserFactory(literalParser, identifierParser),
        openParanthesesParser = consumer(openParanthesesRegEx, function(val){
            return true
        }),
        closingParanthesesParser = consumer(closingParanthesesRegEx, function(val){
            return true
        }),
        operatorParser = consumer(operatorRegEx),
        varKeywordParser = consumer(varKeywordRegEx),
        functionKeywordParser = consumer(functionKeywordRegEx),
        macroKeywordParser = consumer(macroKeywordRegEx),
        fatArrowParser = consumer(fatArrowRegEx)

    function argumentsParser() {
        var args = []
        spaceParser()
        while(!closingParanthesesParser()){
            arg = argStatementParser()
            if (!arg)
                throw new SyntaxError("argumentsParser : Unexpected character at line: "+line)
            args.push(arg)
            spaceParser()
        }
        spaceParser()
        if (args.length > 0)
            return args
        return []
    }

    function expressionParser() {
        if (!openParanthesesParser()) return null
        return callExpressionParser() || binaryExpressionParser() || statementParser()
    }

    function expressionStatementParser() {
        spaceParser()
        if (closingParanthesesParser())  return null
        return combinator({type: "ExpressionStatement"}, ["expression", expressionParser])
    }

    function dereferencer(macro, tree) {
        for(objs in tree){
            if (Array.isArray(tree[objs])) {
                var restArgs = []
                tree[objs].forEach(function(t, idx){
                    var persistObjs = objs
                    tree[objs][idx] = dereferencer(macro, t)
                    objs = persistObjs
                    if(Array.isArray(tree[objs][tree[objs].length-1]['deletenode'])){
                        restArgs = tree[objs][idx]['deletenode']
                    }
                })
                if(restArgs.length > 0){
                    tree[objs].pop()
                    restArgs.forEach(function(ele){
                        tree[objs].push(ele)
                    })
                }
            }
            else if (typeof tree[objs] === "object") {
                dereferencer(macro, tree[objs])
            }
            if (objs === "type" && tree[objs] === "Identifier") {
                if (tilde = /^\~(.*|\.\.\.rest)\b/.exec(tree.name)) {
                    var ref = tilde[0].slice(1)
                    if(ref === "...rest")    tree = {deletenode: macro.params[ref]}
                    else    tree = macro.params[ref]
                }
            }
        }

        return tree
    }

    function macroCallParser() {
        var temp = src
        if(!openParanthesesParser()) return null
        spaceParser()
        var expr = {}
        if (expr.callee = identifierParser()) {
            spaceParser()
            expr.arguments = argumentsParser() || []
            if (macroCopy = macros[expr.callee.name.toString()]) {
                var macro = JSON.parse(JSON.stringify(macroCopy))
                var macroName = expr.callee.name
                var args = expr.arguments.map(function(arg){
                    return arg
                })
                for(param in macro.params){
                    if (param != "...rest")
                        macro.params[param] = args.shift()
                }
                macro.params['...rest'] = args
                var macroExpr = dereferencer(macro, macro.body)
                return macroExpr
            }
        }

        src = temp
        return null
    }
    function callExpressionParser() {
        return combinator({type: "CallExpression"}, ["callee", identifierParser], ["arguments", argumentsParser])
    }

    function binaryExpressionParser() {
        return combinator({type: "BinaryExpression"}, ["operator", operatorParser], ["left", elementParser], ["right", elementParser], ["", closingParanthesesParser])
    }

    function extractExpression() {
        var found = false, parantheses = 1, i = 0
        while(!found){
            if (src[i] == '(')
                parantheses++
            if (src[i] == ')')
                parantheses--
            if (parantheses == 0)
                found = true
            i++
        }

        return src.slice(0,i)
    }

    function macroDeclarationParser() {
        if (!macroKeywordParser())    return null
        var snippet = extractExpression()
        var rest = src.slice(snippet.length)
        src = snippet
        spaceParser()

        //id
        if (id = identifierParser())
            macroId = id.name
        else
            throw new SyntaxError("Expecting a macro identifier")
        spaceParser()

        //params
        if (!openParanthesesParser())
            throw new SyntaxError("Expecting '(' after " + macroId)

        var macro = {}
        macro.params = {}
        while(!closingParanthesesParser()){
            if (param = identifierParser()) {
                var paramName = param.name
                // param[paramName.toString()] = null
                macro.params[paramName.toString()] = null
            }
            spaceParser()
        }
        macro.params["...rest"] = []
        spaceParser()

        //body
        macro.body = []

        //Fix this: Not very desirable, might go in infinite loop
        while(src.length != 0){
            macro.body.push(statementParser(src.slice(0,src.length-1)))
            spaceParser()
            closingParanthesesParser()
        }

        src = rest
        spaceParser()

        macros[macroId.toString()] = macro
        return null

    }

    function combinator(expr){
        for(var i=1; i<arguments.length; i++){
            var attr = arguments[i][0]
            var parser = arguments[i][1]
            var args = arguments[i][2]
            if(typeof parser == "function"){
                if(Array.isArray(args)){
                    var result = parser(args[0],args[1])
                }
                else
                    var result = parser()
                if(result == null) return null
            }
            else
                result = parser

            if(attr){
                expr[attr] = result
            }
        }
        return expr
    }

    function functionDeclarationParser() {
        if (!functionKeywordParser())    return null
        var snippet = extractExpression()
        var rest = src.slice(snippet.length)
        src = snippet
        var expr = combinator({type: "FunctionDeclaration"}, ["id", identifierParser], ["",openParanthesesParser], ["params",argumentsParser], ["defaults", []], ["body", combinator, [{type: "BlockStatement", body: []}, ["body", functionBodyParser]]], ["generator", false], ["expression", false])
        src = rest
        return expr
    }

    function initializerParser() {
        return elementParser() || expressionParser()
    }

    function variableDeclarationParser() {
        if (!varKeywordParser()) return null
        var expr = {type: "VariableDeclaration", declarations: [], kind: "var"}
        var innerExpr = combinator({type: "VariableDeclarator"}, ["id", identifierParser], ["init", initializerParser], ["", closingParanthesesParser])
        expr.declarations.push(innerExpr)
        closingParanthesesParser()
        return expr
    }

    function arrowFunctionParser() {
        if (!fatArrowParser())   return null
        var snippet = extractExpression()
        var rest = src.slice(snippet.length)
        src = snippet
        var expr = combinator({type: "ArrowFunctionExpression"}, ["id", null], ["", openParanthesesParser], ["params", argumentsParser], ["defaults", []], ["body", combinator, [{type: "BlockStatement"}, ["body", functionBodyParser]]], ["generator", false], ["expression", false])
        src = rest
        return expr
    }

    function functionBodyParser() {
        var stmts = []
        while(!closingParanthesesParser()){
            var stmt = argStatementParser()
            if(stmt != null)
                stmts.push(stmt)
        }
        stmts[stmts.length-1] = {type: "ReturnStatement", argument: stmts[stmts.length-1]}
        //Fix this: what about ...rest in functions?

        return stmts
    }

    function statementParser() {
        return arrowFunctionParser() || macroDeclarationParser()|| functionDeclarationParser() || variableDeclarationParser() || elementParser() || macroCallParser() || expressionStatementParser()
    }

    //Fix this: Have to figure out a way to remove this function
    function argStatementParser() {
        return arrowFunctionParser() || macroDeclarationParser()|| functionDeclarationParser() || variableDeclarationParser() || elementParser() || expressionParser()
    }

    function bodyParser() {
        var body = []
        while(src.length != 0){
            spaceParser()
            var stmt = statementParser()
            if (!stmt)
                throw new SyntaxError("Cannot parse statement at line: " + line)
            if(Array.isArray(stmt))
                stmt.forEach(function(s){body.push(s)})
            else
                body.push(stmt)

        }
        return body
    }

    ast.body = bodyParser()
    return ast
}<|endoftext|>


<commit_before>'use strict';

// MAIN //

/**
* Computes the minimum time.
*
* @private
* @param {ArrayArray} times - times
* @returns {NonNegativeIntegerArray} minimum time
*/
function min( times ) {
	var out;
	var t;
	var i;

	out = times[ 0 ];
	for ( i = 1; i < times.length; i++ ) {
		t = times[ i ];
		if (
			t[ 0 ] <= out[ 0 ] &&
			t[ 1 ] < out[ 1 ]
		) {
			out = t;
		}
	}
	return out;
} // end FUNCTION min()

// EXPORTS //

module.exports = min;
<commit_msg>Fix bug when calculating minimum time<commit_after>'use strict';

// MAIN //

/**
* Computes the minimum time.
*
* @private
* @param {ArrayArray} times - times
* @returns {NonNegativeIntegerArray} minimum time
*/
function min( times ) {
	var out;
	var t;
	var i;

	out = times[ 0 ];
	for ( i = 1; i < times.length; i++ ) {
		t = times[ i ];
		if (
			t[ 0 ] < out[ 0 ] ||
			(
				t[ 0 ] === out[ 0 ] &&
				t[ 1 ] < out[ 1 ]
			)
		) {
			out = t;
		}
	}
	return out;
} // end FUNCTION min()

// EXPORTS //

module.exports = min;
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import t from 't-component'
import { Link } from 'react-router'
import topicStore from 'lib/stores/topic-store/topic-store'
import userConnector from 'lib/site/connectors/user'
import ChangeVote from '../change-vote-button/component'
import CantComment from '../cant-comment/component'
import Required from '../required/component'

export class Poll extends Component {
  static getResults (topic, userVote) {
    const results = topic.action.results

    const winnerCount = Math.max(...results.map((opt) => opt.percentage))

    return results.map((opt) => Object.assign({
      winner: winnerCount === opt.percentage,
      voted: opt.value === userVote
    }, opt))
  }

  constructor (props) {
    super(props)

    this.state = {
      changingVote: false,
      selected: null,
      results: null
    }
  }

  handlePoll = (e) => {
    if (!this.state.changingVote) {
      if (!this.props.user.state.fulfilled) return
      if (this.state.showResults) return
    }

    if (!this.state.selected) return

    topicStore.vote(this.props.topic.id, this.state.selected)
      .then(() => {
        this.setState((prevState) => ({
          changingVote: false
        }))
      })
      .catch((err) => { throw err })
  }

  select = (option) => (e) => {
    if (this.state.changingVote || this.props.topic.voted === false) {
      this.setState({ selected: option })
    }
  }

  componentWillMount () {
    this.setStateFromProps(this.props)
  }

  componentWillReceiveProps (props) {
    this.setStateFromProps(props)
  }

  setStateFromProps (props) {
    const { topic } = props

    return this.setState({
      results: Poll.getResults(topic, topic.voted),
      selected: topic.voted
    })
  }

  changeVote = () => {
    this.setState({
      changingVote: true
    })
  }

  render () {
    if (this.props.user.state.pending) return null

    const { user, topic } = this.props
    const { results, changingVote, selected } = this.state

    if (!results) return null

    const showResults = topic.closed
    const showVoteBox = (user.state.fulfilled && !(showResults && !!selected)) || changingVote
    const showChangeVote = !showResults && !changingVote && !!topic.voted
    const showVoteButton = (user.state.fulfilled && !showResults) && !showChangeVote
    const cantComment = user.state.fulfilled && !topic.privileges.canVote
    const isRequired = !user.state.fulfilled && !showResults

    return (

          {
            showResults && results.map((result, i) => (
              <ResultBox
                key={i}
                selected={selected === result.value}
                value={result.value}
                percentage={result.percentage}
                winner={result.winner}
                voted={!!selected} />
            ))
          }
          {
            (showVoteBox && !showResults) && results.map((result, i) => (
              <Option
                key={i}
                onSelect={this.select(result.value)}
                value={result.value}
                selected={selected === result.value} />
            ))
          }
          { showChangeVote && <ChangeVote handleClick={this.changeVote} /> }
          {
            showVoteButton && <button
              className='btn btn-primary'
              onClick={this.handlePoll}
              disabled={!this.state.selected}>
              {t('topics.actions.poll.do')}
            </button>
          }

        {
          isRequired && (
            <Required />
          )
        }
        {
          cantComment && (
            <CantComment />
          )
        }

    )
  }
}

export default userConnector(Poll)

const Option = ({ onSelect, selected, value }) => (
  <button
    className={'btn btn-default poll-btn not-show-results'}
    onClick={onSelect}>
    {selected && }
    {!selected && }
    { value }
  </button>
)

const ResultBox = ({ winner, selected, percentage, value, voted }) => {
  return (
    <button className={
      'btn btn-default poll-btn show-results' +
      (winner ? ' winner' : '')
    }>
      {(selected || voted) && }
      { percentage }%
      { value }
      <div className='results-bar' style={{ width: `${percentage}%` }} />
    </button>
  )
}
<commit_msg>fix poll voted option<commit_after>import React, { Component } from 'react'
import t from 't-component'
import { Link } from 'react-router'
import topicStore from 'lib/stores/topic-store/topic-store'
import userConnector from 'lib/site/connectors/user'
import ChangeVote from '../change-vote-button/component'
import CantComment from '../cant-comment/component'
import Required from '../required/component'

export class Poll extends Component {
  static getResults (topic, userVote) {
    const results = topic.action.results

    const winnerCount = Math.max(...results.map((opt) => opt.percentage))

    return results.map((opt) => Object.assign({
      winner: winnerCount === opt.percentage,
      voted: opt.value === userVote
    }, opt))
  }

  constructor (props) {
    super(props)

    this.state = {
      changingVote: false,
      selected: null,
      results: null
    }
  }

  handlePoll = (e) => {
    if (!this.state.changingVote) {
      if (!this.props.user.state.fulfilled) return
      if (this.state.showResults) return
    }

    if (!this.state.selected) return

    topicStore.vote(this.props.topic.id, this.state.selected)
      .then(() => {
        this.setState((prevState) => ({
          changingVote: false
        }))
      })
      .catch((err) => { throw err })
  }

  select = (option) => (e) => {
    if (this.state.changingVote || this.props.topic.voted === false) {
      this.setState({ selected: option })
    }
  }

  componentWillMount () {
    this.setStateFromProps(this.props)
  }

  componentWillReceiveProps (props) {
    this.setStateFromProps(props)
  }

  setStateFromProps (props) {
    const { topic } = props

    return this.setState({
      results: Poll.getResults(topic, topic.voted),
      selected: topic.voted
    })
  }

  changeVote = () => {
    this.setState({
      changingVote: true
    })
  }

  render () {
    if (this.props.user.state.pending) return null

    const { user, topic } = this.props
    const { results, changingVote, selected } = this.state

    if (!results) return null

    const showResults = topic.closed
    const showVoteBox = (user.state.fulfilled && !(showResults && !!selected)) || changingVote
    const showChangeVote = !showResults && !changingVote && !!topic.voted
    const showVoteButton = (user.state.fulfilled && !showResults) && !showChangeVote
    const cantComment = user.state.fulfilled && !topic.privileges.canVote
    const isRequired = !user.state.fulfilled && !showResults

    return (

          {
            showResults && results.map((result, i) => (
              <ResultBox
                key={i}
                selected={selected === result.value}
                value={result.value}
                percentage={result.percentage}
                winner={result.winner} />
            ))
          }
          {
            (showVoteBox && !showResults) && results.map((result, i) => (
              <Option
                key={i}
                onSelect={this.select(result.value)}
                value={result.value}
                selected={selected === result.value} />
            ))
          }
          { showChangeVote && <ChangeVote handleClick={this.changeVote} /> }
          {
            showVoteButton && <button
              className='btn btn-primary'
              onClick={this.handlePoll}
              disabled={!this.state.selected}>
              {t('topics.actions.poll.do')}
            </button>
          }

        {
          isRequired && (
            <Required />
          )
        }
        {
          cantComment && (
            <CantComment />
          )
        }

    )
  }
}

export default userConnector(Poll)

const Option = ({ onSelect, selected, value }) => (
  <button
    className={'btn btn-default poll-btn not-show-results'}
    onClick={onSelect}>
    {selected && }
    {!selected && }
    { value }
  </button>
)

const ResultBox = ({ winner, selected, percentage, value }) => {
  return (
    <button className={
      'btn btn-default poll-btn show-results' +
      (winner ? ' winner' : '')
    }>
      {selected && }
      { percentage }%
      { value }
      <div className='results-bar' style={{ width: `${percentage}%` }} />
    </button>
  )
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Primewire Enhancer
// @namespace    https://github.com/nordinrahman/userscript
// @version      0.2
// @description  Enhance browsing experience on primewire.ag, unframe link, and disable ad when clicking link. Used best together with Adblock Plus, Anti Adblock Killer (AdBlock filter & greasemonkey/tampermonkey userscript).
// @author       Nordin Rahman
// @match        http://www.primewire.ag/*
// @grant        unsafeWindow
// @noframes
// ==/UserScript==

(function () {

    (function () {
        /// <summary>
        /// Trick page to disable FastPop 'feature'
        /// </summary>

        var loadTimeout = 1000;

        var currentTime = new Date();
        var nextYearTime = new Date(currentTime * 1 + 1000 * 60 * 60 * 24 * 365);
        var varInfNumFastPopsExpire = 'undefined__' + nextYearTime.toString();
        var varInfNumFastPops = 'undefined__999';

        unsafeWindow.addEventListener('load', function () {
            setTimeout(function () {
                try {
                    unsafeWindow.localStorage.setItem('InfNumFastPopsExpire', varInfNumFastPopsExpire)
                    unsafeWindow.localStorage.setItem('InfNumFastPops', varInfNumFastPops)
                    console.log('DONE disabling FastPop feature');
                } catch (ex) {
                    console.log('ERROR disabling FastPop feature');
                    console.log(ex);
                }
            }, loadTimeout);
        });
    })();

    (function () {
        /// <summary>
        // "Unframe" video host link URL
        /// =============================
        /// Code reference:
        ///  read query string http://stackoverflow.com/a/21152762/29669
        ///  decode base64 https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
        /// </summary>

        var getLinkUrl = function (href) {
            var qd = {};
            href.substring(href.indexOf('?')).substr(1).split("&").forEach(function (item) {
                var k = item.split("=")[0], v = item.split("=")[1];
                v = v && decodeURIComponent(v);
                (k in qd) ? qd[k].push(v) : qd[k] = [v]
            });

            var urlValues = qd['url'];
            var encodedUrl = urlValues && urlValues[urlValues.length - 1];

            return encodedUrl && atob(encodeURIComponent(encodedUrl).replace(/%([0-9A-F]{2})/g, function (match, p1) { return String.fromCharCode('0x' + p1); }));
        };

        var movieLinks = document.querySelectorAll('.movie_version_link > a');
        for (var i = 0; i < movieLinks.length; i++) {
            var movieLink = movieLinks[i];
            var movieUrl = getLinkUrl(movieLink.getAttribute('href'));
            movieUrl && movieLink.setAttribute('href', movieUrl);
        }
    })();

    (function () {
        /// <summary>
        /// Remove sponsor link video list
        /// </summary>

        var versionHostSpan = document.querySelectorAll('.version_host');
        for (var i = 0; i < versionHostSpan.length; i++) {
            if (versionHostSpan[i].textContent.match(/;Sponsor Host/)) {
                var el = versionHostSpan[i].parentElement;
                while (el && el.nodeName !== 'TABLE') el = el.parentElement;
                if (el) el.style.display = 'none';
            }
        }
    })();

    (function () {
        /// <summary>
        /// Remove sponsor link section
        /// </summary>

        var sponsorLinkIframe = document.querySelector('iframe[src="/additional_content.php"]');
        var sponsorLinkHeading = sponsorLinkIframe.previousElementSibling;

        sponsorLinkIframe.style.display = 'none';
        sponsorLinkHeading.style.display = 'none';
    })();

    (function () {
        /// <summary>
        /// Remove hoax download link div
        /// </summary>

        var hoaxDownloadLinkDiv = document.querySelector('.download_link');

        hoaxDownloadLinkDiv.style.display = 'none';
    })();

    (function () {
        /// <summary>
        /// Remove Message to follow on FaceBook
        /// </summary>

        var infoMessageDivs = document.querySelectorAll('.info_message');
        for (var i = 0; i < infoMessageDivs.length; i++) {
            if (infoMessageDivs[i].textContent.match(/Follow us on Facebook/)) {
                var el = infoMessageDivs[i];
                el.style.display = 'none';
            }
        }
    })();
})();<commit_msg>Fix removal of sponsored host to also remove promo host<commit_after>// ==UserScript==
// @name         Primewire Enhancer
// @namespace    https://github.com/nordinrahman/userscript
// @version      0.2
// @description  Enhance browsing experience on primewire.ag, unframe link, and disable ad when clicking link. Used best together with Adblock Plus, Anti Adblock Killer (AdBlock filter & greasemonkey/tampermonkey userscript).
// @author       Nordin Rahman
// @match        http://www.primewire.ag/*
// @grant        unsafeWindow
// @noframes
// ==/UserScript==

(function () {

    (function () {
        /// <summary>
        /// Trick page to disable FastPop 'feature'
        /// </summary>

        var loadTimeout = 1000;

        var currentTime = new Date();
        var nextYearTime = new Date(currentTime * 1 + 1000 * 60 * 60 * 24 * 365);
        var varInfNumFastPopsExpire = 'undefined__' + nextYearTime.toString();
        var varInfNumFastPops = 'undefined__999';

        unsafeWindow.addEventListener('load', function () {
            setTimeout(function () {
                try {
                    unsafeWindow.localStorage.setItem('InfNumFastPopsExpire', varInfNumFastPopsExpire)
                    unsafeWindow.localStorage.setItem('InfNumFastPops', varInfNumFastPops)
                    console.log('DONE disabling FastPop feature');
                } catch (ex) {
                    console.log('ERROR disabling FastPop feature');
                    console.log(ex);
                }
            }, loadTimeout);
        });
    })();

    (function () {
        /// <summary>
        // "Unframe" video host link URL
        /// =============================
        /// Code reference:
        ///  read query string http://stackoverflow.com/a/21152762/29669
        ///  decode base64 https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
        /// </summary>

        var getLinkUrl = function (href) {
            var qd = {};
            href.substring(href.indexOf('?')).substr(1).split("&").forEach(function (item) {
                var k = item.split("=")[0], v = item.split("=")[1];
                v = v && decodeURIComponent(v);
                (k in qd) ? qd[k].push(v) : qd[k] = [v]
            });

            var urlValues = qd['url'];
            var encodedUrl = urlValues && urlValues[urlValues.length - 1];

            return encodedUrl && atob(encodeURIComponent(encodedUrl).replace(/%([0-9A-F]{2})/g, function (match, p1) { return String.fromCharCode('0x' + p1); }));
        };

        var movieLinks = document.querySelectorAll('.movie_version_link > a');
        for (var i = 0; i < movieLinks.length; i++) {
            var movieLink = movieLinks[i];
            var movieUrl = getLinkUrl(movieLink.getAttribute('href'));
            movieUrl && movieLink.setAttribute('href', movieUrl);
        }
    })();

    (function () {
        /// <summary>
        /// Remove sponsor link video list
        /// </summary>

        var versionHostSpan = document.querySelectorAll('.version_host');
        for (var i = 0; i < versionHostSpan.length; i++) {
            if (versionHostSpan[i].textContent.match(/;\w+ Host/)) {
                var el = versionHostSpan[i].parentElement;
                while (el && el.nodeName !== 'TABLE') el = el.parentElement;
                if (el) el.style.display = 'none';
            }
        }
    })();

    (function () {
        /// <summary>
        /// Remove sponsor link section
        /// </summary>

        var sponsorLinkIframe = document.querySelector('iframe[src="/additional_content.php"]');
        var sponsorLinkHeading = sponsorLinkIframe.previousElementSibling;

        sponsorLinkIframe.style.display = 'none';
        sponsorLinkHeading.style.display = 'none';
    })();

    (function () {
        /// <summary>
        /// Remove hoax download link div
        /// </summary>

        var hoaxDownloadLinkDiv = document.querySelector('.download_link');

        hoaxDownloadLinkDiv.style.display = 'none';
    })();

    (function () {
        /// <summary>
        /// Remove Message to follow on FaceBook
        /// </summary>

        var infoMessageDivs = document.querySelectorAll('.info_message');
        for (var i = 0; i < infoMessageDivs.length; i++) {
            if (infoMessageDivs[i].textContent.match(/Follow us on Facebook/)) {
                var el = infoMessageDivs[i];
                el.style.display = 'none';
            }
        }
    })();
})();<|endoftext|>