<commit_before>const wolfram = require('wolfram-alpha');

let wc = null;

module.exports.init = function (bot) {
  bot.getConfig('wolfram.json', (err, conf) => {
    if (err) console.log(`Unable to load wolfram module: ${err}`);
    try {
      wc = new wolfram.createClient(conf.appid); // eslint-disable-line new-cap
    } catch (ex) {
      bot.say(`Error loading wolfram library: ${ex}`);
    }
  });
};

// subpodValue, given a subpod, attempts to figure out the correct thing to print.
// Currently, that just means any non-empty item from value, text, image,
// preferring them in that order.
// In the future, it's quite plausible the image may be useful for some queries.
// Right now, it's often a duplicate of the text content if text is available.
function subpodValue(subpod) {
  return [
    subpod.value,
    subpod.text,
    subpod.image,
  ].find(val => val);
}

module.exports.commands = ['wolf', 'wolfram', 'wolframalpha', 'wa'];

module.exports.run = function (remainder, parts, reply) {
  if (wc === null) {
    reply('Unable to handle wolfram request; lib not loaded');
    return;
  }

  wc.query(remainder, (err, res) => {
    if (err) {
      reply(`Wolfram error: ${err}`);
      return;
    }
    if (!(res && res.length)) {
      reply('Wolfram error, response is dicked');
      return;
    }

    if (res.length === 1) {
      reply(`No result for query: ${res[0].subpods[0].text}`);
      return;
    }

    const r = function (...args) {
      reply.custom({ lines: 5, pmExtra: true, replaceNewlines: true }, ...args);
    };

    const primary_pods = res.filter(x => x.primary);
    if (primary_pods.length === 0) {
      try {
        r(`${res[0].subpods[0].text}: ${res[1].subpods[0].text}`);
        return;
      } catch (ex) {
        r(`No primary pod, try http://www.wolframalpha.com/input/?i=${encodeURIComponent(remainder)}`);
        return;
      }
    }

    const ppod = primary_pods[0];
    if (!ppod.title) {
      this.log.error('unrecognized primary pod: ', ppod);
      r('Not sure how to handle primary pod, someone should pull request this');
      return;
    }
    let title = '';
    if (ppod.title !== 'Result') {
      title = ppod.title;
    }
    const subval = subpodValue(ppod.subpods[0]);

    if (title && subval) {
      r(`${title}: ${subval}`);
    } else if (title) {
      r(title);
    } else {
      r(subval);
    }
  });
};

<commit_msg>modules/wolf: print query interpretation<commit_after>const wolfram = require('wolfram-alpha');

let wc = null;

module.exports.init = function (bot) {
  bot.getConfig('wolfram.json', (err, conf) => {
    if (err) console.log(`Unable to load wolfram module: ${err}`);
    try {
      wc = new wolfram.createClient(conf.appid); // eslint-disable-line new-cap
    } catch (ex) {
      bot.say(`Error loading wolfram library: ${ex}`);
    }
  });
};

// subpodValue, given a subpod, attempts to figure out the correct thing to print.
// Currently, that just means any non-empty item from value, text, image,
// preferring them in that order.
// In the future, it's quite plausible the image may be useful for some queries.
// Right now, it's often a duplicate of the text content if text is available.
function subpodValue(subpod) {
  return [
    subpod.value,
    subpod.text,
    subpod.image,
  ].find(val => val);
}

module.exports.commands = ['wolf', 'wolfram', 'wolframalpha', 'wa'];

module.exports.run = function (remainder, parts, reply) {
  if (wc === null) {
    reply('Unable to handle wolfram request; lib not loaded');
    return;
  }

  wc.query(remainder, (err, res) => {
    if (err) {
      reply(`Wolfram error: ${err}`);
      return;
    }
    if (!(res && res.length)) {
      reply('Wolfram error, response is dicked');
      return;
    }

    if (res.length === 1) {
      reply(`No result for query: ${res[0].subpods[0].text}`);
      return;
    }

    const interp = subpodValue(res[0].subpods[0]);

    const r = function (...args) {
      reply.custom({ lines: 5, pmExtra: true, replaceNewlines: true }, ...args);
    };

    const primary_pods = res.filter(x => x.primary);
    if (primary_pods.length === 0) {
      try {
        r(`${interp}: ${res[1].subpods[0].text}`);
        return;
      } catch (ex) {
        r(`No primary pod, try http://www.wolframalpha.com/input/?i=${encodeURIComponent(remainder)}`);
        return;
      }
    }

    const ppod = primary_pods[0];
    if (!ppod.title) {
      this.log.error('unrecognized primary pod: ', ppod);
      r('Not sure how to handle primary pod, someone should pull request this');
      return;
    }
    const titleParts = [];
    if (interp !== remainder) {
      titleParts.push(interp);
    }
    if (ppod.title !== 'Result' && ppod.title !== 'Response') {
      titleParts.push(ppod.title);
    }
    const subval = subpodValue(ppod.subpods[0]);

    const title = titleParts.join(': ');

    if (title && subval) {
      r(`${title}: ${subval}`);
    } else if (title) {
      r(title);
    } else {
      r(subval);
    }
  });
};

<|endoftext|>


<commit_before>'use babel';
import { CompositeDisposable } from 'atom';

import * as helpers from  'atom-linter';
import * as trigParser from 'js-trig-parser';

export default {

  subscriptions: null,

  activate(state) {

    require('atom-package-deps').install('trig-linter-atom')
    // Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
    this.subscriptions = new CompositeDisposable();

    // Register command that toggles this view
    this.subscriptions.add(atom.commands.add('atom-workspace', {
      'trig-linter:toggle': () => this.toggle()
    }));
  },

  deactivate() {
    // this.modalPanel.destroy();
    this.subscriptions.dispose();
    // this.trigLinterView.destroy();
  },

  provideLinter() {

    return {
      name: "TrigLinter",
      grammarScopes : ['source.trig','source.trtl','source.turtle'],
      scope: 'file',
      lintOnFly: true,
      gutterEnabled: true,
      underlineIssues: true,
      lintOnFlyInterval: 1500,
      showErrorPanel:true,
      showErrorInline:true,
      lint: async (textEditor) => {
        const filePath = textEditor.getPath();
        const text = textEditor.getText();

        if (text.length === 0) {
          return Promise.resolve([]);
        }

        return new Promise(function(resolve, reject){
            setTimeout(function(){
              reject('Timeout on lint of : ' + filePath);
            },5000);

            var results = trigParser.loaders.graphLoader.fromString(text);
            var syntaxErrors = results.syntaxErrors.map(function(se){
              console.log('syntaxErrors')
              console.log(se)
                var line = se.line - 1;
                var col = se.column;
                return {
                  type: 'Error',
                  text: se.msg, filePath,
                  range: helpers.rangeFromLineNumber(textEditor, line, col)
                };
            });

            var analysisErrors = results.analysisErrors.map(function(se){

                var line = se.line - 1;
                var col = se.column;
                var len = se.len || (se.start ? se.start.stop - se.start.start: 1);
                var range = [[line,col],[line, col + len]];
                return {
                  type: 'Warning',
                  text: se.message , filePath,
                  range: range
                };
            });
            var errors = results.errors.map(function(se){
                console.log('error')
                console.log(se)
                var line = se.symbol.line - 1;
                var col = se.symbol.column;
                var len = se.len || (se.symbolstart ? se.start.symbol.stop - se.symbol.start.start: 1);
                var range = [[line,col],[line, col + len]]
                return {
                    type: 'Error',
                    text: se.symbol._text, filePath,
                    range: range
                };
            });

            var allErrors = errors.concat(syntaxErrors).concat(analysisErrors).filter(function(m){
              if(!m.text){
                console.error("error without text");
                console.error(m);
              }
              return m.text;
            });
            console.log(allErrors);
            resolve(allErrors);
        });

      }
    }
  }
};
<commit_msg>removed subscription to toggel button<commit_after>'use babel';
import { CompositeDisposable } from 'atom';

import * as helpers from  'atom-linter';
import * as trigParser from 'js-trig-parser';

export default {

  subscriptions: null,

  activate(state) {

    require('atom-package-deps').install('trig-linter-atom')
    // Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
    this.subscriptions = new CompositeDisposable();

    // Register command that toggles this view

  },

  deactivate() {
    // this.modalPanel.destroy();
    this.subscriptions.dispose();
    // this.trigLinterView.destroy();
  },

  provideLinter() {

    return {
      name: "TrigLinter",
      grammarScopes : ['source.trig','source.trtl','source.turtle'],
      scope: 'file',
      lintOnFly: true,
      gutterEnabled: true,
      underlineIssues: true,
      lintOnFlyInterval: 1500,
      showErrorPanel:true,
      showErrorInline:true,
      lint: async (textEditor) => {
        const filePath = textEditor.getPath();
        const text = textEditor.getText();

        if (text.length === 0) {
          return Promise.resolve([]);
        }

        return new Promise(function(resolve, reject){
            setTimeout(function(){
              reject('Timeout on lint of : ' + filePath);
            },5000);

            var results = trigParser.loaders.graphLoader.fromString(text);
            var syntaxErrors = results.syntaxErrors.map(function(se){
              console.log('syntaxErrors')
              console.log(se)
                var line = se.line - 1;
                var col = se.column;
                return {
                  type: 'Error',
                  text: se.msg, filePath,
                  range: helpers.rangeFromLineNumber(textEditor, line, col)
                };
            });

            var analysisErrors = results.analysisErrors.map(function(se){

                var line = se.line - 1;
                var col = se.column;
                var len = se.len || (se.start ? se.start.stop - se.start.start: 1);
                var range = [[line,col],[line, col + len]];
                return {
                  type: 'Warning',
                  text: se.message , filePath,
                  range: range
                };
            });
            var errors = results.errors.map(function(se){
                console.log('error')
                console.log(se)
                var line = se.symbol.line - 1;
                var col = se.symbol.column;
                var len = se.len || (se.symbolstart ? se.start.symbol.stop - se.symbol.start.start: 1);
                var range = [[line,col],[line, col + len]]
                return {
                    type: 'Error',
                    text: se.symbol._text, filePath,
                    range: range
                };
            });

            var allErrors = errors.concat(syntaxErrors).concat(analysisErrors).filter(function(m){
              if(!m.text){
                console.error("error without text");
                console.error(m);
              }
              return m.text;
            });
            console.log(allErrors);
            resolve(allErrors);
        });

      }
    }
  }
};
<|endoftext|>


<commit_before>var util = require('util'),
    fs = require('fs'),
    Sync = require('sync'),
    request = require('request'),
    moment = require('moment'),
    helpers = require('./helpers'),
    constants = require('./constants');

function TwitterAdsAPI(options) {
  var self = this;

  // Default values
  self.config = {
    api_version: '1',
    ton_api_version: '1.1',
    sandbox: true,
    consumer_key: null,
    consumer_secret: null,
    access_token: null,
    access_token_secret: null,
  };

  self._oauthObj = {};

  self._validateConfigOrThrow = function(config) {
    if (config && typeof config !== 'object') throw new TypeError('TwitterAdsAPI: Config must be object, got ' + typeof config);

    constants.CONFIGURABLE_KEYS.forEach(function(k) {
      if (config[k] !== undefined) self.config[k] = config[k];
      else if (constants.REQUIRED_KEYS.indexOf(k) > -1) throw new Error(util.format('TwitterAdsAPI: Config must include `%s`.', k));
    });

    self._oauthObj = {
      consumer_key: self.config.consumer_key,
      consumer_secret: self.config.consumer_secret,
      token: self.config.access_token,
      token_secret: self.config.access_token_secret,
    };
  };

  if (options) self._validateConfigOrThrow(options);

  self._makeRequest = function(type, url, params, cb) {
    if (!url) throw new Error('TwitterAdsAPI: URL must be provided when making an API call.');
    if (typeof params == 'function') {
      cb = params;
      params = {};
    }
    if (!cb) throw new Error('TwitterAdsAPI: Callback must be provided when making an API call.');

    // Let's not change the params object user passes
    var paramsClone = JSON.parse(JSON.stringify(params)),
        finalURL = Object.keys(paramsClone).length ? helpers.moveParamsIntoPath(url, paramsClone) : url;

    paramsClone = helpers.normalizeParams(paramsClone);
    request({
      baseUrl: (self.config.sandbox ? constants.API_SANDBOX_HOST : constants.API_HOST) + self.config.api_version + '/',
      url: Object.keys(paramsClone).length ? finalURL + '?' + helpers.makeQueryString(paramsClone) : finalURL,
      method: type.toUpperCase(),
      //useQuerystring: true,
      //gzip: true,
      oauth: self._oauthObj
    }, function(err, resp, body) {
      if (err) return cb(err);
      helpers.parseResponse(resp, body, cb);
    });
  };

  self._uploadTonChunks = function(fd, chunkSize, url, params, cb) {
    Sync(function() {
      var fsStats = fs.fstatSync(fd),
          chunkNum = 1,
          bytesBuffer = new Buffer(chunkSize),
          bytesRead = 0,
          totalBytesRead = 0,
          totalBytes = fsStats.size,
          finalLocation = null;

      while (totalBytesRead < totalBytes) {
        bytesRead = fs.readSync(fd, bytesBuffer, 0, chunkSize, totalBytesRead);

        //console.log('Uploading chunk #' + chunkNum + ' (' + totalBytesRead + '-' + ((totalBytesRead + bytesRead) - 1) + '/' + totalBytes + ')');

        var headers = {
          'Content-Type': params.content_type,
          'Content-Length': bytesRead,
          'Content-Range': 'bytes ' + totalBytesRead + '-' + ((totalBytesRead + bytesRead) - 1) + '/' + totalBytes
        };

        var requestResult = request.put.sync(null, {
          baseUrl: constants.TON_API_HOST,
          url: url,
          body: bytesBuffer,
          headers: headers,
          oauth: self._oauthObj
        });

        var resp = requestResult, body = {};
        if (Array.isArray(requestResult)) resp = requestResult[0], body = requestResult[1];
        if (resp.statusCode != 308 && resp.statusCode != 201)
          throw new Error('Twitter did not accept chunk upload, Should return status code 308 or 201 but instead returned: ' + resp.statusCode);

        if (resp.statusCode == 201) finalLocation = constants.TON_API_HOST + resp.headers.location;
        totalBytesRead += bytesRead;
        chunkNum++;
        bytesBuffer = new Buffer(chunkSize);
      }

      fs.closeSync(fd);
      return finalLocation;
    }, function(err, result) {
      if (err) {
        fs.closeSync(fd);
        return cb(err);
      }
      cb(null, result);
    });
  };

  self._uploadTonFile = function(params, cb) {
    if (!params) throw new Error('TwitterAdsAPI: Parameters must be provided when making TON API call.');
    if (!cb) throw new Error('TwitterAdsAPI: Callback must be provided when making an API call.');

    constants.REQUIRED_TON_UPLOAD_PARAMS.forEach(function(k) {
      if (params[k] === undefined) throw new Error(util.format('TwitterAdsAPI: Parameters must include `%s`.', k));
    });

    var defaultExpireTime = moment().utc().add(7, 'days').toDate().toUTCString();

    var fd, fsStats;

    try {
      fd = fs.openSync(params.file, 'r');
      fsStats = fs.fstatSync(fd);
    } catch (e) {
      return cb(e);
    }

    var headers = {
      'Content-Length': 0,
      'Content-Type': params.content_type,
      'X-TON-Content-Type': params.content_type,
      'X-TON-Content-Length': fsStats.size,
      'X-TON-Expires': params.expire_time || defaultExpireTime
    };

    request.post({
      url: constants.TON_API_HOST + self.config.ton_api_version + '/ton/bucket/' + params.bucket_name + '?resumable=true',
      headers: headers,
      oauth: self._oauthObj
    }, function(err, resp, body) {
      if (err) return cb(err);
      if (resp.statusCode === 201) {
        var urlPathForChunks = resp.headers.location;
        var minChunkSize = Number(resp.headers['X-TON-Min-Chunk-Size'.toLowerCase()]);
        return self._uploadTonChunks(fd, minChunkSize, urlPathForChunks, params, cb);
      } else {
        fs.closeSync(fd);
        return cb(new Error('TwitterAdsAPI: Twitter TON API returned HTTP status code: ' + resp.statusCode));
      }
    });
  };

  self._downloadTonFile = function(params, cb) {
    if (!params) throw new Error('TwitterAdsAPI: Parameters must be provided when making TON API call.');
    if (!cb) throw new Error('TwitterAdsAPI: Callback must be provided when making an API call.');

    constants.REQUIRED_TON_DOWNLOAD_PARAMS.forEach(function(k) {
      if (params[k] === undefined) throw new Error(util.format('TwitterAdsAPI: Parameters must include `%s`.', k));
    });

    var fd, fsStats;

    try {
      fd = fs.openSync(params.file, 'w');
      fsStats = fs.fstatSync(fd);
    } catch (e) {
      return cb(e);
    }

    request.post({
      url: params.url,
      oauth: self._oauthObj
    }, function(err, resp, body) {
      if (err) return cb(err);
      if (resp.statusCode === 200) {
        try {
          fs.writeSync(fd, body, 0, 'utf-8');
          fs.closeSync(fd);
          return body.length;
        } catch (e) {
          return cb(e);
        }
      } else {
        fs.closeSync(fd);
        return cb(new Error('TwitterAdsAPI: Twitter TON API returned HTTP status code: ' + resp.statusCode));
      }
    });
  };

  return self;
}

TwitterAdsAPI.prototype.setOptions = function(options) {
  this._validateConfigOrThrow(options);
  return this;
};

TwitterAdsAPI.prototype.getOptions = function() { return this.config; };

TwitterAdsAPI.prototype.get = function(url, params, cb) {
  this._makeRequest('get', url, params, cb);
};

TwitterAdsAPI.prototype.post = function(url, params, cb) {
  this._makeRequest('post', url, params, cb);
};

TwitterAdsAPI.prototype.put = function(url, params, cb) {
  this._makeRequest('put', url, params, cb);
};

TwitterAdsAPI.prototype.delete = function(url, params, cb) {
  this._makeRequest('delete', url, params, cb);
};

TwitterAdsAPI.prototype.tonUpload = function(params, cb) {
  this._uploadTonFile(params, cb);
};

TwitterAdsAPI.prototype.tonDownload = function(params, cb) {
  this._downloadTonFile(params, cb);
};

exports = module.exports = TwitterAdsAPI;<commit_msg>bump version and some fixes<commit_after>var util = require('util'),
    fs = require('fs'),
    Sync = require('sync'),
    request = require('request'),
    moment = require('moment'),
    helpers = require('./helpers'),
    constants = require('./constants');

function TwitterAdsAPI(options) {
  var self = this;

  // Default values
  self.config = {
    api_version: '1',
    ton_api_version: '1.1',
    sandbox: true,
    consumer_key: null,
    consumer_secret: null,
    access_token: null,
    access_token_secret: null,
  };

  self._oauthObj = {};

  self._validateConfigOrThrow = function(config) {
    if (config && typeof config !== 'object') throw new TypeError('TwitterAdsAPI: Config must be object, got ' + typeof config);

    constants.CONFIGURABLE_KEYS.forEach(function(k) {
      if (config[k] !== undefined) self.config[k] = config[k];
      else if (constants.REQUIRED_KEYS.indexOf(k) > -1) throw new Error(util.format('TwitterAdsAPI: Config must include `%s`.', k));
    });

    self._oauthObj = {
      consumer_key: self.config.consumer_key,
      consumer_secret: self.config.consumer_secret,
      token: self.config.access_token,
      token_secret: self.config.access_token_secret,
    };
  };

  if (options) self._validateConfigOrThrow(options);

  self._makeRequest = function(type, url, params, cb) {
    if (!url) throw new Error('TwitterAdsAPI: URL must be provided when making an API call.');
    if (typeof params == 'function') {
      cb = params;
      params = {};
    }
    if (!cb) throw new Error('TwitterAdsAPI: Callback must be provided when making an API call.');

    // Let's not change the params object user passes
    var paramsClone = JSON.parse(JSON.stringify(params)),
        finalURL = Object.keys(paramsClone).length ? helpers.moveParamsIntoPath(url, paramsClone) : url;

    paramsClone = helpers.normalizeParams(paramsClone);
    request({
      baseUrl: (self.config.sandbox ? constants.API_SANDBOX_HOST : constants.API_HOST) + self.config.api_version + '/',
      url: Object.keys(paramsClone).length ? finalURL + '?' + helpers.makeQueryString(paramsClone) : finalURL,
      method: type.toUpperCase(),
      //useQuerystring: true,
      //gzip: true,
      oauth: self._oauthObj
    }, function(err, resp, body) {
      if (err) return cb(err);
      helpers.parseResponse(resp, body, cb);
    });
  };

  self._uploadTonChunks = function(fd, chunkSize, url, params, cb) {
    Sync(function() {
      var fsStats = fs.fstatSync(fd),
          chunkNum = 1,
          bytesBuffer = new Buffer(chunkSize),
          bytesRead = 0,
          totalBytesRead = 0,
          totalBytes = fsStats.size,
          finalLocation = null;

      while (totalBytesRead < totalBytes) {
        bytesRead = fs.readSync(fd, bytesBuffer, 0, chunkSize, totalBytesRead);

        // console.log('Uploading chunk #' + chunkNum + ' (' + totalBytesRead + '-' + ((totalBytesRead + bytesRead) - 1) + '/' + totalBytes + ')');

        var headers = {
          'Content-Type': params.content_type,
          'Content-Length': bytesRead,
          'Content-Range': 'bytes ' + totalBytesRead + '-' + ((totalBytesRead + bytesRead) - 1) + '/' + totalBytes
        };

        var requestResult = request.put.sync(null, {
          baseUrl: constants.TON_API_HOST,
          url: url,
          body: bytesBuffer,
          headers: headers,
          oauth: self._oauthObj
        });

        var resp = requestResult, body = {};
        if (Array.isArray(requestResult)) resp = requestResult[0], body = requestResult[1];
        if (resp.statusCode !== 308 && resp.statusCode !== 201)
          throw new Error('Twitter did not accept chunk upload, Should return status code 308 or 201 but instead returned: ' + resp.statusCode);

        if (resp.statusCode === 201) finalLocation = constants.TON_API_HOST + self.config.ton_api_version + resp.headers.location.substring(1);
        totalBytesRead += bytesRead;
        chunkNum++;
        bytesBuffer = new Buffer(chunkSize);
      }

      fs.closeSync(fd);
      return finalLocation;
    }, function(err, result) {
      if (err) {
        fs.closeSync(fd);
        return cb(err);
      }
      cb(null, result);
    });
  };

  self._uploadTonFile = function(params, cb) {
    if (!params) throw new Error('TwitterAdsAPI: Parameters must be provided when making TON API call.');
    if (!cb) throw new Error('TwitterAdsAPI: Callback must be provided when making an API call.');

    constants.REQUIRED_TON_UPLOAD_PARAMS.forEach(function(k) {
      if (params[k] === undefined) throw new Error(util.format('TwitterAdsAPI: Parameters must include `%s`.', k));
    });

    var defaultExpireTime = moment().utc().add(7, 'days').toDate().toUTCString();

    var fd, fsStats;

    try {
      fd = fs.openSync(params.file, 'r');
      fsStats = fs.fstatSync(fd);
    } catch (e) {
      return cb(e);
    }

    var headers = {
      'Content-Length': 0,
      'Content-Type': params.content_type,
      'X-TON-Content-Type': params.content_type,
      'X-TON-Content-Length': fsStats.size,
      'X-TON-Expires': params.expire_time || defaultExpireTime
    };

    request.post({
      url: constants.TON_API_HOST + self.config.ton_api_version + '/ton/bucket/' + params.bucket_name + '?resumable=true',
      headers: headers,
      oauth: self._oauthObj
    }, function(err, resp, body) {
      if (err) return cb(err);
      if (resp.statusCode === 201) {
        var urlPathForChunks = resp.headers.location;
        var minChunkSize = Number(resp.headers['X-TON-Min-Chunk-Size'.toLowerCase()]);
        return self._uploadTonChunks(fd, minChunkSize, urlPathForChunks, params, cb);
      } else {
        fs.closeSync(fd);
        console.log('Error Body: ', body);
        return cb(new Error('TwitterAdsAPI: Twitter TON API returned HTTP status code: ' + resp.statusCode));
      }
    });
  };

  self._downloadTonFile = function(params, cb) {
    if (!params) throw new Error('TwitterAdsAPI: Parameters must be provided when making TON API call.');
    if (!cb) throw new Error('TwitterAdsAPI: Callback must be provided when making an API call.');

    constants.REQUIRED_TON_DOWNLOAD_PARAMS.forEach(function(k) {
      if (params[k] === undefined) throw new Error(util.format('TwitterAdsAPI: Parameters must include `%s`.', k));
    });

    var fd, fsStats;

    try {
      fd = fs.openSync(params.file, 'w');
      fsStats = fs.fstatSync(fd);
    } catch (e) {
      return cb(e);
    }

    request.post({
      url: params.url,
      oauth: self._oauthObj
    }, function(err, resp, body) {
      if (err) return cb(err);
      if (resp.statusCode === 200) {
        try {
          fs.writeSync(fd, body, 0, 'utf-8');
          fs.closeSync(fd);
          return body.length;
        } catch (e) {
          return cb(e);
        }
      } else {
        fs.closeSync(fd);
        return cb(new Error('TwitterAdsAPI: Twitter TON API returned HTTP status code: ' + resp.statusCode));
      }
    });
  };

  return self;
}

TwitterAdsAPI.prototype.setOptions = function(options) {
  this._validateConfigOrThrow(options);
  return this;
};

TwitterAdsAPI.prototype.getOptions = function() { return this.config; };

TwitterAdsAPI.prototype.get = function(url, params, cb) {
  this._makeRequest('get', url, params, cb);
};

TwitterAdsAPI.prototype.post = function(url, params, cb) {
  this._makeRequest('post', url, params, cb);
};

TwitterAdsAPI.prototype.put = function(url, params, cb) {
  this._makeRequest('put', url, params, cb);
};

TwitterAdsAPI.prototype.delete = function(url, params, cb) {
  this._makeRequest('delete', url, params, cb);
};

TwitterAdsAPI.prototype.tonUpload = function(params, cb) {
  this._uploadTonFile(params, cb);
};

TwitterAdsAPI.prototype.tonDownload = function(params, cb) {
  this._downloadTonFile(params, cb);
};

exports = module.exports = TwitterAdsAPI;<|endoftext|>


<commit_before>'use strict';

var Types = module.exports = {};

Types.swagger_1 = require('./swagger_1.js');
Types.swagger_2 = require('./swagger_2.js');
Types.api_blueprint = require('./api_blueprint.js');
Types.io_docs = require('./io_docs.js');
Types.google = require('./google.js');
Types.wadl = require('./wadl.js');
<commit_msg>add raml<commit_after>'use strict';

var Types = module.exports = {};

Types.swagger_1 = require('./swagger_1.js');
Types.swagger_2 = require('./swagger_2.js');
Types.api_blueprint = require('./api_blueprint.js');
Types.io_docs = require('./io_docs.js');
Types.google = require('./google.js');
Types.raml = require('./raml.js');
Types.wadl = require('./wadl.js');
<|endoftext|>


<commit_before>const cli = require('commander')
const moment = require('moment')
const chalk = require('chalk')
const apiCall = require('./apiCall')

const periods = []

cli
  .option('-f, --from <date>', 'select from <date>.', validateDate)
  .option('-t, --to <date>', 'select to <date>.', validateDate)
  .parse(process.argv)

function printReports () {
  definePeriods()
  periods.forEach(period => {
    apiCall('completed', '', {
      start_date: period[0].format('YYYY-MM-DDTHH:MM:ssZ'),
      end_date: period[1].format('YYYY-MM-DDTHH:MM:ssZ')
    })
    .then(res => {
      let report = new Report(res.body, period)
      report.create()
      report.print()
    })
  })
}

function definePeriods () {
  // Add one hour to the default end time to take inconsistencies into account.
  const defaultEndTime = moment.utc().add(1, 'h')
  // Make default periods if the user didn't input any.
  if (!cli.args.length && !cli.to && !cli.from) {
    let month = formatMonth((moment().month() + 1).toString())
    periods.push([moment.utc('2014-01-01'), defaultEndTime])
    periods.push([moment.utc(month), defaultEndTime])
  }
  // Make options periods.
  if (cli.from || cli.to) {
    let start = cli.from ? cli.from : moment.utc('2014-01-01')
    let end = cli.to ? cli.to : defaultEndTime
    periods.push([start, end])
  }
  // Regex expressions to match user input.
  // Matches numbers from 1-12.
  const matchMonth = /^[1-9]|1[012]$/
  // Matches the format YYYY-MM.
  const matchYearMonth = /^(19|20)\d\d[- /.](0[1-9]|1[012])$/

  cli.args.forEach(arg => {
    // Testing what arguments we got from the user.
    if (matchYearMonth.test(arg)) {
       let start = moment(arg).utc()
       let end = moment(arg).utc().add(1, 'M')
       periods.push([start, end])
    } else if (matchMonth.test(arg)) {
      let start = moment().utc().month(arg - 1).startOf('month')
      let end = moment().utc().month(arg - 1).startOf('month').add(1, 'M')
      periods.push([start, end])
    }  else if (arg === 'today') {
      let start = moment.utc().startOf('day')
      let end = moment.utc().endOf('day')
      periods.push([start, end])
    } else if (arg === 'yesterday') {
      let start = moment.utc().subtract(1, 'd').startOf('day')
      let end = moment.utc().subtract(1, 'd').endOf('day')
      periods.push([start, end])
    }
  })
}

function formatMonth (month) {
  return month.length === 1 ? `${moment().year()}-0${month}`
                            : `${moment().year()}-${month}`
}

function validateDate (date) {
  date = moment.utc(date)
  if (!date.isValid()) {
    throw new Error(`Invalid date: ${date}`)
  }
  return date
}

class Report {
  constructor (reviews, period) {
    this.period = period
    this.reviews = reviews
    this.projects = {}
    this.totalEarned = 0
  }

  create () {
    this.reviews.forEach(review => {
      this.countReview(review)
    })
  }

  countReview (review) {
    let id = review.project_id
    let price = parseInt(review.price)

    // If the report does not yet contain an entry for the project type, create
    // the entry and try counting the review again.
    if (!this.projects.hasOwnProperty(id)) {
      this.projects[id] = {
        name: review.project.name,
        id: id,
        passed: 0,
        failed: 0,
        ungradeable: 0,
        earned: 0
      }
      this.countReview(review)
    } else {
      this.projects[id][review.result] += 1
      this.projects[id].earned += price
      this.totalEarned += price
    }
  }

  print () {
    let startDate = moment(this.period[0]).format('YYYY-MM-DD')
    let endDate = moment(this.period[1]).format('YYYY-MM-DD')

    console.log('========================================')
    console.log(chalk.blue(`Earnings Report for ${startDate} to ${endDate}:`))

    for (let p in this.projects) {
      let {name, id, ungradeable, passed, failed, earned} = this.projects[p]
      console.log(`
      ${chalk.white(`Project: ${name} (${id}):`)}
          ${chalk.white(`Total reviewed: ${passed + failed}`)}
          ${chalk.white(`Ungradeable: ${ungradeable}`)}
          ${chalk.white(`Earned: ${earned}`)}
          `)
    }
    console.log(chalk.bgBlack.white(`Total Earned: ${this.totalEarned}`))
    console.log('========================================')
  }
}

printReports()
<commit_msg>Fix bug when retrieving earnings for a month<commit_after>const cli = require('commander')
const moment = require('moment')
const chalk = require('chalk')
const apiCall = require('./apiCall')

const periods = []

cli
  .option('-f, --from <date>', 'select from <date>.', validateDate)
  .option('-t, --to <date>', 'select to <date>.', validateDate)
  .parse(process.argv)

function printReports () {
  definePeriods()
  periods.forEach(period => {
    apiCall('completed', '', {
      start_date: period[0].format('YYYY-MM-DDTHH:MM:ssZ'),
      end_date: period[1].format('YYYY-MM-DDTHH:MM:ssZ')
    })
    .then(res => {
      let report = new Report(res.body, period)
      report.create()
      report.print()
    })
  })
}

function definePeriods () {
  // Add one hour to the default end time to take inconsistencies into account.
  const defaultEndTime = moment.utc().add(1, 'h')
  // Make default periods if the user didn't input any.
  if (!cli.args.length && !cli.to && !cli.from) {
    let month = formatMonth((moment().month() + 1).toString())
    periods.push([moment.utc('2014-01-01'), defaultEndTime])
    periods.push([moment.utc(month), defaultEndTime])
  }
  // Make options periods.
  if (cli.from || cli.to) {
    let start = cli.from ? cli.from : moment.utc('2014-01-01')
    let end = cli.to ? cli.to : defaultEndTime
    periods.push([start, end])
  }
  // Regex expressions to match user input.
  // Matches numbers from 1-12.
  const matchMonth = /^[1-9]|1[012]$/
  // Matches the format YYYY-MM.
  const matchYearMonth = /^(19|20)\d\d[- /.](0[1-9]|1[012])$/

  cli.args.forEach(arg => {
    // Testing what arguments we got from the user.
    if (matchYearMonth.test(arg)) {
      let start = moment(arg).utc()
      let end = moment(arg).utc().add(1, 'M')
      periods.push([start, end])
    } else if (matchMonth.test(arg)) {
      let year = moment().year()
      const month = moment().month() + 1
      if (arg > month) {
        year -= 1
      }
      const yearAndMonth = arg < 9 ? `${year}-0${arg}` : `${year}-${arg}`
      let start = moment(yearAndMonth).utc()
      let end = moment(yearAndMonth).utc().add(1, 'M')
      periods.push([start, end])
    }  else if (arg === 'today') {
      let start = moment.utc().startOf('day')
      let end = moment.utc().endOf('day')
      periods.push([start, end])
    } else if (arg === 'yesterday') {
      let start = moment.utc().subtract(1, 'd').startOf('day')
      let end = moment.utc().subtract(1, 'd').endOf('day')
      periods.push([start, end])
    }
  })
}

function formatMonth (month) {
  return month.length === 1 ? `${moment().year()}-0${month}`
                            : `${moment().year()}-${month}`
}

function validateDate (date) {
  date = moment.utc(date)
  if (!date.isValid()) {
    throw new Error(`Invalid date: ${date}`)
  }
  return date
}

class Report {
  constructor (reviews, period) {
    this.period = period
    this.reviews = reviews
    this.projects = {}
    this.totalEarned = 0
  }

  create () {
    this.reviews.forEach(review => {
      this.countReview(review)
    })
  }

  countReview (review) {
    let id = review.project_id
    let price = parseInt(review.price)

    // If the report does not yet contain an entry for the project type, create
    // the entry and try counting the review again.
    if (!this.projects.hasOwnProperty(id)) {
      this.projects[id] = {
        name: review.project.name,
        id: id,
        passed: 0,
        failed: 0,
        ungradeable: 0,
        earned: 0
      }
      this.countReview(review)
    } else {
      this.projects[id][review.result] += 1
      this.projects[id].earned += price
      this.totalEarned += price
    }
  }

  print () {
    let startDate = moment(this.period[0]).format('YYYY-MM-DD')
    let endDate = moment(this.period[1]).format('YYYY-MM-DD')

    console.log('========================================')
    console.log(chalk.blue(`Earnings Report for ${startDate} to ${endDate}:`))

    for (let p in this.projects) {
      let {name, id, ungradeable, passed, failed, earned} = this.projects[p]
      console.log(`
      ${chalk.white(`Project: ${name} (${id}):`)}
          ${chalk.white(`Total reviewed: ${passed + failed}`)}
          ${chalk.white(`Ungradeable: ${ungradeable}`)}
          ${chalk.white(`Earned: ${earned}`)}
          `)
    }
    console.log(chalk.bgBlack.white(`Total Earned: ${this.totalEarned}`))
    console.log('========================================')
  }
}

printReports()
<|endoftext|>


<commit_before>'use strict';

const logging = require('./logging');

const $ = Object.assign(logging, {
	defer: require('./defer'),
	find: require('./find'),
	read: require('./read'),
	write: require('./write')
});

module.exports = $;
<commit_msg>disable utils/defer<commit_after>'use strict';

const logging = require('./logging');

const $ = Object.assign(logging, {
	// defer: require('./defer'),
	find: require('./find'),
	read: require('./read'),
	write: require('./write')
});

module.exports = $;
<|endoftext|>


<commit_before>var DEBUG;

var DEFAULT_PALETTE = ["#CA221D", "#C22769", "#3F93E1", "#481B79", "#6AAC32",
    "#42928F", "#D32645", "#CD531C", "#EDC92D", "#A5B425", "#211D79",
    "#449256", "#7A2077", "#CA221D", "#E29826", "#44913D", "#2458A3",
    "#2458A3", "#14388C"];

function debug(message) {
  var console = window['console'];
  if (console && console.log) {
    console.log(message);
  }
}

var OpenSpending = OpenSpending || {};
OpenSpending.Utils = OpenSpending.Utils || {};

OpenSpending.Utils.formatAmount = function (num) {
  var billion = 1000000000;
  var million = 1000000;
  var thousand = 1000;
  var numabs = Math.abs(num);
  if (numabs > billion) {
    return OpenSpending.Utils.formatAmountWithCommas(num / billion) + 'bn';
  } if (numabs > (million / 2)) {
    return OpenSpending.Utils.formatAmountWithCommas(num / million) + 'm';
  } if (numabs > thousand) {
    return OpenSpending.Utils.formatAmountWithCommas(num / thousand) + 'k';
  } else {
    return OpenSpending.Utils.formatAmountWithCommas(num, 2);
  }
};

OpenSpending.Utils.formatAmountWithCommas = function (num, decimalPlaces, currency) {
  currency = OpenSpending.Utils.currencySymbol(currency);
  return accounting.formatMoney(num, currency, decimalPlaces||0,
    OpenSpending.localeGroupSeparator,
    OpenSpending.localeDecimalSeparator);
};

OpenSpending.Utils.currencySymbol = function (currency) {
  if(currency) {
    return OpenSpending.Utils.CurrencySymbols[currency] || currency;
  } else {
    return '';
  }
};

OpenSpending.Utils.getColorPalette = function (num) {
  var colors = [];
  for (var i = 0; i < num; i++) {
    colors.push(DEFAULT_PALETTE[i % (DEFAULT_PALETTE.length-1)]);
  }
  return colors;
}

/*
	Parse a URL query string (?xyz=abc...) into a dictionary.
*/

function parseQueryString() {
  var q = arguments.length > 0 ? arguments[0] : window.location.search.substring(1);
  var urlParams = [],
    e, d = function (s) {
      return unescape(s.replace(/\+/g, " "));
    },
    r = /([^&=]+)=?([^&]*)/g;

  while (e = r.exec(q)) {
    urlParams.push([d(e[1]), d(e[2])]);
  }
  return urlParams;
}

/*
Write tabular data as HTML table.

	:tabular: tabular data object (dict with header and data keys).
	:options: optional keyword arguments:
		colTypes: types of columns keyed by column name
		displayNames: ditto for display names for columns
*/
writeTabularAsHtml = function (tabular) {
  var options = {};
  if (arguments.length > 1) {
    options = arguments[1];
  }
  var colTypes = {};
  var displayNames = {};
  if (options.colTypes) {
    colTypes = options.colTypes;
  }
  if (options.displayNames) {
    displayNames = options.displayNames;
  }
  // knows how to format and justify based on combination of col type labelling (via colTypes)
  // and value based logic
  var _ColType = [];
  var _thead = $('

');
  $.each(tabular.header, function (i, col) {
    var tempDisplayName = displayNames[col] ? displayNames[col] : col;
    _thead.append($('	').append(tempDisplayName));
    if (colTypes[col]) {
      _ColType[i] = colTypes[col];
    }
  });
  var _tbody = $('

');
  // var red = /^(19|20)\d{2}$/; - replaced by _ColType
  // var rep = /^([\d\.\-]+)\%$/; - replaced by _ColType
  var ren = /^[\d\.\-]+$/;
  var reb = /^$/;
  $.each(tabular.data, function (i, row) {
    var _newrow = $('

');
    $.each(row, function (j, cell) {
      // decide action depending on type
      var cell2;
      if (_ColType[j] == 'range') {
        // year range
        var cell3 = parseFloat(cell);
        cell3++;
        cell2 = cell + '-' + cell3;
        _newrow.append($('	').append(cell2));
      } else if (reb.test(cell)) {
        // blank
        cell2 = '';
        _newrow.append($('	').append(cell2));
      } else if (_ColType[j] == 'percent') {
        // percent
        // 20.5% saved as 0.205. Converted back here to 20.5%
        var cell3 = cell * 100;
        cell2 = cell3.toFixed(1) + '%';
        _newrow.append($('	').append(cell2));
      } else if (ren.test(cell)) {
        // number
        var cell3 = parseFloat(cell);
        cell2 = cell3.toFixed(0);
        _newrow.append($('	').append(cell2));
      } else {
        // other
        cell2 = cell;
        _newrow.append($('	').append(cell2));
      }
    });
    _tbody.append(_newrow);
  });
  return {
    'thead': _thead,
    'tbody': _tbody
  };
}

function loadingMessage() {
  $.blockUI({
    message: 'Please wait, loading ...',
    timeout: 30000,
    css: {
      border: 'none',
      padding: '15px',
      backgroundColor: '#000',
      '-webkit-border-radius': '10px',
      '-moz-border-radius': '10px',
      opacity: .5,
      color: '#fff'
    }
  });
  $('.blockMsg').attr('title', 'Click to unblock').click($.unblockUI);
}

OpenSpending.Utils.CurrencySymbols = {
    "AED": "د.إ",
    "AFN": "؋",
    "ALL": "L",
    "AMD": "դր.",
    "ANG": "ƒ",
    "AOA": "Kz",
    "ARS": "$",
    "AUD": "$",
    "AWG": "ƒ",
    "AZN": "m",
    "BAM": "KM",
    "BBD": "$",
    "BDT": "৳",
    "BGN": "лв",
    "BHD": "ب.د",
    "BIF": "Fr",
    "BMD": "$",
    "BND": "$",
    "BOB": "Bs.",
    "BRL": "R$",
    "BSD": "$",
    "BTN": "Nu",
    "BWP": "P",
    "BYR": "Br",
    "BZD": "$",
    "CAD": "$",
    "CDF": "Fr",
    "CHF": "Fr",
    "CLP": "$",
    "CNY": "¥",
    "COP": "$",
    "CRC": "₡",
    "CUP": "$",
    "CVE": "$, Esc",
    "CZK": "Kč",
    "DJF": "Fr",
    "DKK": "kr",
    "DOP": "$",
    "DZD": "د.ج",
    "EEK": "KR",
    "EGP": "£,ج.م",
    "ERN": "Nfk",
    "ETB": "Br",
    "EUR": "€",
    "FJD": "$",
    "FKP": "£",
    "GBP": "£",
    "GEL": "ლ",
    "GHS": "₵",
    "GIP": "£",
    "GMD": "D",
    "GNF": "Fr",
    "GTQ": "Q",
    "GYD": "$",
    "HKD": "$",
    "HNL": "L",
    "HRK": "kn",
    "HTG": "G",
    "HUF": "Ft",
    "IDR": "Rp",
    "ILS": "₪",
    "INR": "₨",
    "IQD": "ع.د",
    "IRR": "﷼",
    "ISK": "kr",
    "JMD": "$",
    "JOD": "د.ا",
    "JPY": "¥",
    "KES": "Sh",
    "KGS": "лв",
    "KHR": "៛",
    "KMF": "Fr",
    "KPW": "₩",
    "KRW": "₩",
    "KWD": "د.ك",
    "KYD": "$",
    "KZT": "Т",
    "LAK": "₭",
    "LBP": "ل.ل",
    "LKR": "ரூ",
    "LRD": "$",
    "LSL": "L",
    "LTL": "Lt",
    "LVL": "Ls",
    "LYD": "ل.د",
    "MAD": "د.م.",
    "MDL": "L",
    "MGA": "Ar",
    "MKD": "ден",
    "MMK": "K",
    "MNT": "₮",
    "MOP": "P",
    "MRO": "UM",
    "MUR": "₨",
    "MVR": "ރ.",
    "MWK": "MK",
    "MXN": "$",
    "MYR": "RM",
    "MZN": "MT",
    "NAD": "$",
    "NGN": "₦",
    "NIO": "C$",
    "NOK": "kr",
    "NPR": "₨",
    "NZD": "$",
    "OMR": "ر.ع.",
    "PAB": "B/.",
    "PEN": "S/.",
    "PGK": "K",
    "PHP": "₱",
    "PKR": "₨",
    "PLN": "zł",
    "PYG": "₲",
    "QAR": "ر.ق",
    "RON": "RON",
    "RSD": "RSD",
    "RUB": "р.",
    "RWF": "Fr",
    "SAR": "ر.س",
    "SBD": "$",
    "SCR": "₨",
    "SDG": "S$",
    "SEK": "kr",
    "SGD": "$",
    "SHP": "£",
    "SLL": "Le",
    "SOS": "Sh",
    "SRD": "$",
    "STD": "Db",
    "SYP": "£, ل.س",
    "SZL": "L",
    "THB": "฿",
    "TJS": "ЅМ",
    "TMT": "m",
    "TND": "د.ت",
    "TOP": "T$",
    "TRY": "₤",
    "TTD": "$",
    "TWD": "$",
    "TZS": "Sh",
    "UAH": "₴",
    "UGX": "Sh",
    "USD": "$",
    "UYU": "$",
    "UZS": "лв",
    "VEF": "Bs",
    "VND": "₫",
    "VUV": "Vt",
    "WST": "T",
    "XAF": "Fr",
    "XCD": "$",
    "XOF": "Fr",
    "XPF": "Fr",
    "YER": "﷼",
    "ZAR": "R",
    "ZMK": "ZK",
    "ZWL": "$"
};

<commit_msg>Kenyan Shillings' symbol is Ksh, not Sh.<commit_after>var DEBUG;

var DEFAULT_PALETTE = ["#CA221D", "#C22769", "#3F93E1", "#481B79", "#6AAC32",
    "#42928F", "#D32645", "#CD531C", "#EDC92D", "#A5B425", "#211D79",
    "#449256", "#7A2077", "#CA221D", "#E29826", "#44913D", "#2458A3",
    "#2458A3", "#14388C"];

function debug(message) {
  var console = window['console'];
  if (console && console.log) {
    console.log(message);
  }
}

var OpenSpending = OpenSpending || {};
OpenSpending.Utils = OpenSpending.Utils || {};

OpenSpending.Utils.formatAmount = function (num) {
  var billion = 1000000000;
  var million = 1000000;
  var thousand = 1000;
  var numabs = Math.abs(num);
  if (numabs > billion) {
    return OpenSpending.Utils.formatAmountWithCommas(num / billion) + 'bn';
  } if (numabs > (million / 2)) {
    return OpenSpending.Utils.formatAmountWithCommas(num / million) + 'm';
  } if (numabs > thousand) {
    return OpenSpending.Utils.formatAmountWithCommas(num / thousand) + 'k';
  } else {
    return OpenSpending.Utils.formatAmountWithCommas(num, 2);
  }
};

OpenSpending.Utils.formatAmountWithCommas = function (num, decimalPlaces, currency) {
  currency = OpenSpending.Utils.currencySymbol(currency);
  return accounting.formatMoney(num, currency, decimalPlaces||0,
    OpenSpending.localeGroupSeparator,
    OpenSpending.localeDecimalSeparator);
};

OpenSpending.Utils.currencySymbol = function (currency) {
  if(currency) {
    return OpenSpending.Utils.CurrencySymbols[currency] || currency;
  } else {
    return '';
  }
};

OpenSpending.Utils.getColorPalette = function (num) {
  var colors = [];
  for (var i = 0; i < num; i++) {
    colors.push(DEFAULT_PALETTE[i % (DEFAULT_PALETTE.length-1)]);
  }
  return colors;
}

/*
	Parse a URL query string (?xyz=abc...) into a dictionary.
*/

function parseQueryString() {
  var q = arguments.length > 0 ? arguments[0] : window.location.search.substring(1);
  var urlParams = [],
    e, d = function (s) {
      return unescape(s.replace(/\+/g, " "));
    },
    r = /([^&=]+)=?([^&]*)/g;

  while (e = r.exec(q)) {
    urlParams.push([d(e[1]), d(e[2])]);
  }
  return urlParams;
}

/*
Write tabular data as HTML table.

	:tabular: tabular data object (dict with header and data keys).
	:options: optional keyword arguments:
		colTypes: types of columns keyed by column name
		displayNames: ditto for display names for columns
*/
writeTabularAsHtml = function (tabular) {
  var options = {};
  if (arguments.length > 1) {
    options = arguments[1];
  }
  var colTypes = {};
  var displayNames = {};
  if (options.colTypes) {
    colTypes = options.colTypes;
  }
  if (options.displayNames) {
    displayNames = options.displayNames;
  }
  // knows how to format and justify based on combination of col type labelling (via colTypes)
  // and value based logic
  var _ColType = [];
  var _thead = $('

');
  $.each(tabular.header, function (i, col) {
    var tempDisplayName = displayNames[col] ? displayNames[col] : col;
    _thead.append($('	').append(tempDisplayName));
    if (colTypes[col]) {
      _ColType[i] = colTypes[col];
    }
  });
  var _tbody = $('

');
  // var red = /^(19|20)\d{2}$/; - replaced by _ColType
  // var rep = /^([\d\.\-]+)\%$/; - replaced by _ColType
  var ren = /^[\d\.\-]+$/;
  var reb = /^$/;
  $.each(tabular.data, function (i, row) {
    var _newrow = $('

');
    $.each(row, function (j, cell) {
      // decide action depending on type
      var cell2;
      if (_ColType[j] == 'range') {
        // year range
        var cell3 = parseFloat(cell);
        cell3++;
        cell2 = cell + '-' + cell3;
        _newrow.append($('	').append(cell2));
      } else if (reb.test(cell)) {
        // blank
        cell2 = '';
        _newrow.append($('	').append(cell2));
      } else if (_ColType[j] == 'percent') {
        // percent
        // 20.5% saved as 0.205. Converted back here to 20.5%
        var cell3 = cell * 100;
        cell2 = cell3.toFixed(1) + '%';
        _newrow.append($('	').append(cell2));
      } else if (ren.test(cell)) {
        // number
        var cell3 = parseFloat(cell);
        cell2 = cell3.toFixed(0);
        _newrow.append($('	').append(cell2));
      } else {
        // other
        cell2 = cell;
        _newrow.append($('	').append(cell2));
      }
    });
    _tbody.append(_newrow);
  });
  return {
    'thead': _thead,
    'tbody': _tbody
  };
}

function loadingMessage() {
  $.blockUI({
    message: 'Please wait, loading ...',
    timeout: 30000,
    css: {
      border: 'none',
      padding: '15px',
      backgroundColor: '#000',
      '-webkit-border-radius': '10px',
      '-moz-border-radius': '10px',
      opacity: .5,
      color: '#fff'
    }
  });
  $('.blockMsg').attr('title', 'Click to unblock').click($.unblockUI);
}

OpenSpending.Utils.CurrencySymbols = {
    "AED": "د.إ",
    "AFN": "؋",
    "ALL": "L",
    "AMD": "դր.",
    "ANG": "ƒ",
    "AOA": "Kz",
    "ARS": "$",
    "AUD": "$",
    "AWG": "ƒ",
    "AZN": "m",
    "BAM": "KM",
    "BBD": "$",
    "BDT": "৳",
    "BGN": "лв",
    "BHD": "ب.د",
    "BIF": "Fr",
    "BMD": "$",
    "BND": "$",
    "BOB": "Bs.",
    "BRL": "R$",
    "BSD": "$",
    "BTN": "Nu",
    "BWP": "P",
    "BYR": "Br",
    "BZD": "$",
    "CAD": "$",
    "CDF": "Fr",
    "CHF": "Fr",
    "CLP": "$",
    "CNY": "¥",
    "COP": "$",
    "CRC": "₡",
    "CUP": "$",
    "CVE": "$, Esc",
    "CZK": "Kč",
    "DJF": "Fr",
    "DKK": "kr",
    "DOP": "$",
    "DZD": "د.ج",
    "EEK": "KR",
    "EGP": "£,ج.م",
    "ERN": "Nfk",
    "ETB": "Br",
    "EUR": "€",
    "FJD": "$",
    "FKP": "£",
    "GBP": "£",
    "GEL": "ლ",
    "GHS": "₵",
    "GIP": "£",
    "GMD": "D",
    "GNF": "Fr",
    "GTQ": "Q",
    "GYD": "$",
    "HKD": "$",
    "HNL": "L",
    "HRK": "kn",
    "HTG": "G",
    "HUF": "Ft",
    "IDR": "Rp",
    "ILS": "₪",
    "INR": "₨",
    "IQD": "ع.د",
    "IRR": "﷼",
    "ISK": "kr",
    "JMD": "$",
    "JOD": "د.ا",
    "JPY": "¥",
    "KES": "KSh",
    "KGS": "лв",
    "KHR": "៛",
    "KMF": "Fr",
    "KPW": "₩",
    "KRW": "₩",
    "KWD": "د.ك",
    "KYD": "$",
    "KZT": "Т",
    "LAK": "₭",
    "LBP": "ل.ل",
    "LKR": "ரூ",
    "LRD": "$",
    "LSL": "L",
    "LTL": "Lt",
    "LVL": "Ls",
    "LYD": "ل.د",
    "MAD": "د.م.",
    "MDL": "L",
    "MGA": "Ar",
    "MKD": "ден",
    "MMK": "K",
    "MNT": "₮",
    "MOP": "P",
    "MRO": "UM",
    "MUR": "₨",
    "MVR": "ރ.",
    "MWK": "MK",
    "MXN": "$",
    "MYR": "RM",
    "MZN": "MT",
    "NAD": "$",
    "NGN": "₦",
    "NIO": "C$",
    "NOK": "kr",
    "NPR": "₨",
    "NZD": "$",
    "OMR": "ر.ع.",
    "PAB": "B/.",
    "PEN": "S/.",
    "PGK": "K",
    "PHP": "₱",
    "PKR": "₨",
    "PLN": "zł",
    "PYG": "₲",
    "QAR": "ر.ق",
    "RON": "RON",
    "RSD": "RSD",
    "RUB": "р.",
    "RWF": "Fr",
    "SAR": "ر.س",
    "SBD": "$",
    "SCR": "₨",
    "SDG": "S$",
    "SEK": "kr",
    "SGD": "$",
    "SHP": "£",
    "SLL": "Le",
    "SOS": "Sh",
    "SRD": "$",
    "STD": "Db",
    "SYP": "£, ل.س",
    "SZL": "L",
    "THB": "฿",
    "TJS": "ЅМ",
    "TMT": "m",
    "TND": "د.ت",
    "TOP": "T$",
    "TRY": "₤",
    "TTD": "$",
    "TWD": "$",
    "TZS": "Sh",
    "UAH": "₴",
    "UGX": "Sh",
    "USD": "$",
    "UYU": "$",
    "UZS": "лв",
    "VEF": "Bs",
    "VND": "₫",
    "VUV": "Vt",
    "WST": "T",
    "XAF": "Fr",
    "XCD": "$",
    "XOF": "Fr",
    "XPF": "Fr",
    "YER": "﷼",
    "ZAR": "R",
    "ZMK": "ZK",
    "ZWL": "$"
};

<|endoftext|>


<commit_before>var _ = require('lodash');
var moment = require('moment');
var Promise = require('bluebird');
var request = Promise.promisifyAll(require('request'));
var debug = require('debug')('validate');
var os = require('os');
var nconf = require('nconf');
var cheerio = require('cheerio');
var fs = require('fs');

var mongo = require('./mongo');
var utils = require('./utils');
var error = require('./error');

function validateKey(req) {
    debug("optimize import here, take userId do cross check");
    var permalink = req.body.permalink;
    var publicKey = req.body.publicKey;
    console.log(JSON.stringify(req.body, undefined, 2));

    console.log("Looking for publicKey %s in %s", publicKey, permalink);
    return request
        .getAsync({
            'url': permalink,
            'headers': {
                'User-Agent': "User-Agent: curl/7.47.0"
            }
        })
        .then(function(page) {
            var mndx = page.body.indexOf(publicKey);
            if(mndx === -1) {
                return utils
                    .shmFileWrite('MatchError', page.body)
                    .return({ 'json': { "results": "Error",
                                        "reason": "match not found" }});
            }
            else {
                var $ = cheerio.load(page.body);
                var startUrl = page.body.indexOf("https://www.facebook.com/people/");
                var endUrl = page.body.indexOf('"', startUrl);
                var url = page.body.slice(startUrl, endUrl);
                var userId = url.split('?')[0].split('/').pop();

                // TODO CHECK is the same from API, TODO parseInt
                // Write in the Database the userId and its publicKey
                mongo.writeOne(nconf.get('schema').supporters, {
                    userId: userId,
                    publicKey: publicKey,
                    keyTime: new Date(),
                    lastInfo: new Date()
                });

                console.log("Connecting public key %s with user %s", publicKey, userId);
                return { "json": { "result": "success" } };
            }
        })
        .catch(function(a, b) {
            console.log("Something went bad");
            console.log(a);
            console.log(b);
            return { 'json': { "results": "Error",
                               "reason": "page.body ∉ expectation" }};

        });
};

module.exports = {
    validateKey: validateKey
};
<commit_msg>double check with user onboard<commit_after>var _ = require('lodash');
var moment = require('moment');
var Promise = require('bluebird');
var request = Promise.promisifyAll(require('request'));
var debug = require('debug')('validate');
var os = require('os');
var nconf = require('nconf');
var cheerio = require('cheerio');
var fs = require('fs');

var mongo = require('./mongo');
var utils = require('./utils');
var error = require('./error');

function validateKey(req) {
    var permalink = req.body.permalink;
    var publicKey = req.body.publicKey;
    var declaredSupId = _.parseInt(req.body.supporterId);

    console.log("TODO sanitiy check " + JSON.stringify(permalink.split('/')));
    debug("Looking for publicKey %s of %d in %s",
        publicKey, declaredSupId,permalink);

    return request
        .getAsync({
            'url': permalink,
            'headers': {
                'User-Agent': "User-Agent: curl/7.47.0"
            }
        })
        .then(function(page) {
            var mndx = page.body.indexOf(publicKey);
            if(mndx === -1) {
                return utils
                    .shmFileWrite('MatchError', page.body)
                    .return({ 'json': { "result": "Error",
                                        "reason": "match not found" }});
            }
            else {
                var $ = cheerio.load(page.body);
                var startUrl = page.body.indexOf("https://www.facebook.com/people/");
                var endUrl = page.body.indexOf('"', startUrl);
                var url = page.body.slice(startUrl, endUrl);
                var userId = url.split('?')[0].split('/').pop();

                if(_.parseInt(userId) !== declaredSupId) {
                    debug("consinstency error %d != %d, validation fail",
                        _.parseInt(userId), declaredSupId);
                    return { "json": { "result": "Error",
                                       "reason": "inconsinstency" }};
                }

                console.log("Connecting public key %s with user %s", publicKey, userId);
                return mongo.writeOne(nconf.get('schema').supporters, {
                    userId: declaredSupId,
                    publicKey: publicKey,
                    keyTime: new Date(),
                    lastInfo: new Date()
                })
                .return({ "json": { "result": "success" }});
            }
        })
        .catch(function(a, b) {
            console.log("facebook page retrive for validation: fail");
            console.error(a);
            console.error(b);
            return { 'json': { "result": "Error",
                               "reason": "page.body ∉ expectation" }};

        });
};

module.exports = {
    validateKey: validateKey
};
<|endoftext|>


<commit_before>'use strict';

var PARSE_TYPE = 'text/html';
var UID_KEY = 'uid';
var DO_CLONE_ATTRIBUTES = true;
var DOM_PARSER = new DOMParser();

var WRAPPER_NAME = 'wrapper';
var LEAF_NODES = {
    'famous:html-element': true
};

function create(str) {
    return document.createElement(str);
}

function transferChildNodes(from, to) {
    while (from.childNodes[0]) {
        to.appendChild(from.childNodes[0]);
    }
}

function parse(str) {
    var parsed = DOM_PARSER.parseFromString(str, PARSE_TYPE).body;
    var wrapper = create(WRAPPER_NAME);
    transferChildNodes(parsed, wrapper);
    return wrapper;
}

function clone(domNode) {
    return domNode.cloneNode(DO_CLONE_ATTRIBUTES);
}

function query(domNode, selector) {
    return domNode.querySelectorAll(selector);
}

function empty(domNode) {
    while (domNode.firstChild) {
        domNode.removeChild(domNode.firstChild);
    }
}

function getUID(domNode) {
    return domNode.getAttribute(UID_KEY);
}

function attachAttributeToNodes(domNode, key, value) {
    domNode.setAttribute(key, value);
    var name = domNode.tagName.toLowerCase();
    if (!(name in LEAF_NODES)) {
        for (var i = 0; i < domNode.children.length; i++) {
            attachAttributeToNodes(domNode.children[i], key, value);
        }
    }
}

module.exports = {
    create: create,
    parse: parse,
    clone: clone,
    query: query,
    empty: empty,
    transferChildNodes: transferChildNodes,
    getUID: getUID,
    attachAttributeToNodes: attachAttributeToNodes
};
<commit_msg>Update name of leaf node in VirtualDOM<commit_after>'use strict';

var PARSE_TYPE = 'text/html';
var UID_KEY = 'uid';
var DO_CLONE_ATTRIBUTES = true;
var DOM_PARSER = new DOMParser();

var WRAPPER_NAME = 'wrapper';
var LEAF_NODES = {
    'famous:core:dom-element': true
};

function create(str) {
    return document.createElement(str);
}

function transferChildNodes(from, to) {
    while (from.childNodes[0]) {
        to.appendChild(from.childNodes[0]);
    }
}

function parse(str) {
    var parsed = DOM_PARSER.parseFromString(str, PARSE_TYPE).body;
    var wrapper = create(WRAPPER_NAME);
    transferChildNodes(parsed, wrapper);
    return wrapper;
}

function clone(domNode) {
    return domNode.cloneNode(DO_CLONE_ATTRIBUTES);
}

function query(domNode, selector) {
    return domNode.querySelectorAll(selector);
}

function empty(domNode) {
    while (domNode.firstChild) {
        domNode.removeChild(domNode.firstChild);
    }
}

function getUID(domNode) {
    return domNode.getAttribute(UID_KEY);
}

function attachAttributeToNodes(domNode, key, value) {
    domNode.setAttribute(key, value);
    var name = domNode.tagName.toLowerCase();
    if (!(name in LEAF_NODES)) {
        for (var i = 0; i < domNode.children.length; i++) {
            attachAttributeToNodes(domNode.children[i], key, value);
        }
    }
}

module.exports = {
    create: create,
    parse: parse,
    clone: clone,
    query: query,
    empty: empty,
    transferChildNodes: transferChildNodes,
    getUID: getUID,
    attachAttributeToNodes: attachAttributeToNodes
};
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var $ = require('preconditions').singleton();
var sjcl = require('sjcl');

var Bitcore = require('bitcore');
var Address = Bitcore.Address;
var PrivateKey = Bitcore.PrivateKey;
var PublicKey = Bitcore.PublicKey;
var crypto = Bitcore.crypto;
var encoding = Bitcore.encoding;

function WalletUtils() {};

WalletUtils.PATHS = {
  BASE_ADDRESS_DERIVATION: "m/45'",
  REQUEST_KEY: "m/1'/0",
  TXPROPOSAL_KEY: "m/1'/1",
};

/* TODO: It would be nice to be compatible with bitcoind signmessage. How
 * the hash is calculated there? */
WalletUtils.hashMessage = function(text) {
  $.checkArgument(text);
  var buf = new Buffer(text);
  var ret = crypto.Hash.sha256sha256(buf);
  ret = new Bitcore.encoding.BufferReader(ret).readReverse();
  return ret;
};

WalletUtils.signMessage = function(text, privKey) {
  $.checkArgument(text);
  var priv = new PrivateKey(privKey);
  var hash = WalletUtils.hashMessage(text);
  return crypto.ECDSA.sign(hash, priv, 'little').toString();
};

WalletUtils.verifyMessage = function(text, signature, pubKey) {
  $.checkArgument(text);
  $.checkArgument(pubKey);

  if (!signature)
    return false;

  var pub = new PublicKey(pubKey);
  var hash = WalletUtils.hashMessage(text);

  try {
    var sig = new crypto.Signature.fromString(signature);
    return crypto.ECDSA.verify(hash, sig, pub, 'little');
  } catch (e) {
    return false;
  }
};

WalletUtils.deriveAddress = function(publicKeyRing, path, m, network) {
  var publicKeys = _.map(publicKeyRing, function(item) {
    var xpub = new Bitcore.HDPublicKey(item.xPubKey);
    return xpub.derive(path).publicKey;
  });

  var bitcoreAddress = Address.createMultisig(publicKeys, m, network);

  return {
    address: bitcoreAddress.toString(),
    path: path,
    publicKeys: _.invoke(publicKeys, 'toString'),
  };
};

WalletUtils.getProposalHash = function(toAddress, amount, message) {
  return [toAddress, amount, (message || '')].join('|');
};

WalletUtils.getCopayerHash = function(name, xPubKey, requestPubKey) {
  return [name, xPubKey, requestPubKey].join('|');
};

WalletUtils.xPubToCopayerId = function(xpub) {
  var hash = sjcl.hash.sha256.hash(xpub);
  return sjcl.codec.hex.fromBits(hash);
};

WalletUtils.toSecret = function(walletId, walletPrivKey, network) {
  if (_.isString(walletPrivKey)) {
    walletPrivKey = Bitcore.PrivateKey.fromString(walletPrivKey);
  }
  var widHex = new Buffer(walletId.replace(/-/g, ''), 'hex');
  var widBase58 = new encoding.Base58(widHex).toString();
  return _.padRight(widBase58, 22, '0') + walletPrivKey.toWIF() + (network == 'testnet' ? 'T' : 'L');
};

WalletUtils.fromSecret = function(secret) {
  $.checkArgument(secret);

  function split(str, indexes) {
    var parts = [];
    indexes.push(str.length);
    var i = 0;
    while (i < indexes.length) {
      parts.push(str.substring(i == 0 ? 0 : indexes[i - 1], indexes[i]));
      i++;
    };
    return parts;
  };

  try {
    var secretSplit = split(secret, [22, 74]);
    var widBase58 = secretSplit[0].replace(/0/g, '');
    var widHex = encoding.Base58.decode(widBase58).toString('hex');
    var walletId = split(widHex, [8, 12, 16, 20]).join('-');

    var walletPrivKey = Bitcore.PrivateKey.fromString(secretSplit[1]);
    var networkChar = secretSplit[2];

    return {
      walletId: walletId,
      walletPrivKey: walletPrivKey,
      network: networkChar == 'T' ? 'testnet' : 'livenet',
    };
  } catch (ex) {
    throw new Error('Invalid secret');
  }
};

WalletUtils.encryptMessage = function(message, encryptingKey) {
  var key = sjcl.codec.base64.toBits(encryptingKey);
  return sjcl.encrypt(key, message, {
    ks: 128,
    iter: 1
  });
};

WalletUtils.decryptMessage = function(cyphertextJson, encryptingKey) {
  var key = sjcl.codec.base64.toBits(encryptingKey);
  return sjcl.decrypt(key, cyphertextJson);
};

WalletUtils.privateKeyToAESKey = function(privKey) {
  $.checkArgument(privKey && _.isString(privKey));
  $.checkArgument(Bitcore.PrivateKey.isValid(privKey), 'The private key received is invalid');
  var pk = Bitcore.PrivateKey.fromString(privKey);
  return Bitcore.crypto.Hash.sha256(pk.toBuffer()).slice(0, 16).toString('base64');
};

WalletUtils.buildTx = function(txp) {
  var t = new Bitcore.Transaction();

  _.each(txp.inputs, function(i) {
    t.from(i, i.publicKeys, txp.requiredSignatures);
  });

  t.to(txp.toAddress, txp.amount)
    .change(txp.changeAddress.address);

  // Shuffle outputs for improved privacy
  t.sortOutputs(function(outputs) {
    return _.map(txp.outputOrder, function(i) {
      return outputs[i];
    });
  });

  return t;
};

WalletUtils.signTxp = function(txp, xPrivKey) {
  var self = this;
  $.checkArgument(txp);
  $.checkArgument(xPrivKey);
  $.checkArgument(txp.toAddress && Bitcore.Address.isValid(txp.toAddress), 'toAddress is invalid');
  $.checkArgument(txp.amount && _.isNumber(txp.amount) && txp.amount > 0, 'amount is invalid');
  $.checkArgument(txp.changeAddress && txp.changeAddress.address && Bitcore.Address.isValid(txp.changeAddress.address), 'changeAddress is invalid');
  $.checkArgument(txp.inputs && _.isArray(txp.inputs) && txp.inputs.length > 0, 'The transaction must have at least one input');
  $.checkArgument(txp.requiredSignatures && _.isNumber(txp.requiredSignatures) && txp.requiredSignatures > 0, 'requiredSignatures is invalid');

  $.checkArgument(Bitcore.Address(txp.toAddress).network.name === Bitcore.Address(txp.changeAddress.address).network.name, 'toAddress and changeAddress must be on the same network');

  //Derive proper key to sign, for each input
  var privs = [],
    derived = {};

  var network = new Bitcore.Address(txp.toAddress).network.name;
  var xpriv = new Bitcore.HDPrivateKey(xPrivKey, network).derive(WalletUtils.PATHS.BASE_ADDRESS_DERIVATION);

  _.each(txp.inputs, function(i) {
    if (!derived[i.path]) {
      derived[i.path] = xpriv.derive(i.path).privateKey;
      privs.push(derived[i.path]);
    }
  });

  var t = WalletUtils.buildTx(txp);

  var signatures = _.map(privs, function(priv, i) {
    return t.getSignatures(priv);
  });

  signatures = _.map(_.sortBy(_.flatten(signatures), 'inputIndex'), function(s) {
    return s.signature.toDER().toString('hex');
  });

  return signatures;
};

WalletUtils.getNetworkFromXPubKey = function(xPubKey) {
  $.checkArgument(xPubKey && _.isString(xPubKey));
  return xPubKey.substr(0, 4) == 'tpub' ? 'testnet' : 'livenet';
};

module.exports = WalletUtils;
<commit_msg>Fixes for the test #signTxp<commit_after>'use strict';

var _ = require('lodash');
var $ = require('preconditions').singleton();
var sjcl = require('sjcl');

var Bitcore = require('bitcore');
var Address = Bitcore.Address;
var PrivateKey = Bitcore.PrivateKey;
var PublicKey = Bitcore.PublicKey;
var crypto = Bitcore.crypto;
var encoding = Bitcore.encoding;

function WalletUtils() {};

WalletUtils.PATHS = {
  BASE_ADDRESS_DERIVATION: "m/45'",
  REQUEST_KEY: "m/1'/0",
  TXPROPOSAL_KEY: "m/1'/1",
};

/* TODO: It would be nice to be compatible with bitcoind signmessage. How
 * the hash is calculated there? */
WalletUtils.hashMessage = function(text) {
  $.checkArgument(text);
  var buf = new Buffer(text);
  var ret = crypto.Hash.sha256sha256(buf);
  ret = new Bitcore.encoding.BufferReader(ret).readReverse();
  return ret;
};

WalletUtils.signMessage = function(text, privKey) {
  $.checkArgument(text);
  var priv = new PrivateKey(privKey);
  var hash = WalletUtils.hashMessage(text);
  return crypto.ECDSA.sign(hash, priv, 'little').toString();
};

WalletUtils.verifyMessage = function(text, signature, pubKey) {
  $.checkArgument(text);
  $.checkArgument(pubKey);

  if (!signature)
    return false;

  var pub = new PublicKey(pubKey);
  var hash = WalletUtils.hashMessage(text);

  try {
    var sig = new crypto.Signature.fromString(signature);
    return crypto.ECDSA.verify(hash, sig, pub, 'little');
  } catch (e) {
    return false;
  }
};

WalletUtils.deriveAddress = function(publicKeyRing, path, m, network) {
  var publicKeys = _.map(publicKeyRing, function(item) {
    var xpub = new Bitcore.HDPublicKey(item.xPubKey);
    return xpub.derive(path).publicKey;
  });

  var bitcoreAddress = Address.createMultisig(publicKeys, m, network);

  return {
    address: bitcoreAddress.toString(),
    path: path,
    publicKeys: _.invoke(publicKeys, 'toString'),
  };
};

WalletUtils.getProposalHash = function(toAddress, amount, message) {
  return [toAddress, amount, (message || '')].join('|');
};

WalletUtils.getCopayerHash = function(name, xPubKey, requestPubKey) {
  return [name, xPubKey, requestPubKey].join('|');
};

WalletUtils.xPubToCopayerId = function(xpub) {
  var hash = sjcl.hash.sha256.hash(xpub);
  return sjcl.codec.hex.fromBits(hash);
};

WalletUtils.toSecret = function(walletId, walletPrivKey, network) {
  if (_.isString(walletPrivKey)) {
    walletPrivKey = Bitcore.PrivateKey.fromString(walletPrivKey);
  }
  var widHex = new Buffer(walletId.replace(/-/g, ''), 'hex');
  var widBase58 = new encoding.Base58(widHex).toString();
  return _.padRight(widBase58, 22, '0') + walletPrivKey.toWIF() + (network == 'testnet' ? 'T' : 'L');
};

WalletUtils.fromSecret = function(secret) {
  $.checkArgument(secret);

  function split(str, indexes) {
    var parts = [];
    indexes.push(str.length);
    var i = 0;
    while (i < indexes.length) {
      parts.push(str.substring(i == 0 ? 0 : indexes[i - 1], indexes[i]));
      i++;
    };
    return parts;
  };

  try {
    var secretSplit = split(secret, [22, 74]);
    var widBase58 = secretSplit[0].replace(/0/g, '');
    var widHex = encoding.Base58.decode(widBase58).toString('hex');
    var walletId = split(widHex, [8, 12, 16, 20]).join('-');

    var walletPrivKey = Bitcore.PrivateKey.fromString(secretSplit[1]);
    var networkChar = secretSplit[2];

    return {
      walletId: walletId,
      walletPrivKey: walletPrivKey,
      network: networkChar == 'T' ? 'testnet' : 'livenet',
    };
  } catch (ex) {
    throw new Error('Invalid secret');
  }
};

WalletUtils.encryptMessage = function(message, encryptingKey) {
  var key = sjcl.codec.base64.toBits(encryptingKey);
  return sjcl.encrypt(key, message, {
    ks: 128,
    iter: 1
  });
};

WalletUtils.decryptMessage = function(cyphertextJson, encryptingKey) {
  var key = sjcl.codec.base64.toBits(encryptingKey);
  return sjcl.decrypt(key, cyphertextJson);
};

WalletUtils.privateKeyToAESKey = function(privKey) {
  $.checkArgument(privKey && _.isString(privKey));
  $.checkArgument(Bitcore.PrivateKey.isValid(privKey), 'The private key received is invalid');
  var pk = Bitcore.PrivateKey.fromString(privKey);
  return Bitcore.crypto.Hash.sha256(pk.toBuffer()).slice(0, 16).toString('base64');
};

WalletUtils.buildTx = function(txp) {
  var t = new Bitcore.Transaction();

  _.each(txp.inputs, function(i) {
    t.from(i, i.publicKeys, txp.requiredSignatures);
  });

  t.to(txp.toAddress, txp.amount)
    .change(txp.changeAddress.address);

  // Shuffle outputs for improved privacy
  t.sortOutputs(function(outputs) {
    return _.map(txp.outputOrder, function(i) {
      return outputs[i];
    });
  });

  return t;
};

WalletUtils.signTxp = function(txp, xPrivKey) {
  var self = this;
  $.checkArgument(txp);
  $.checkArgument(xPrivKey);
  $.checkArgument(txp.toAddress && Bitcore.Address.isValid(txp.toAddress), 'toAddress is invalid');
  $.checkArgument(txp.amount && _.isNumber(txp.amount) && txp.amount > 0, 'amount is invalid');
  $.checkArgument(txp.changeAddress && txp.changeAddress.address && Bitcore.Address.isValid(txp.changeAddress.address), 'changeAddress is invalid');
  $.checkArgument(txp.inputs && _.isArray(txp.inputs) && txp.inputs.length > 0, 'The transaction must have at least one input');
  $.checkArgument(txp.requiredSignatures && _.isNumber(txp.requiredSignatures) && txp.requiredSignatures > 0, 'requiredSignatures is invalid');

  $.checkArgument(Bitcore.Address(txp.toAddress).network.name === Bitcore.Address(txp.changeAddress.address).network.name, 'toAddress and changeAddress must be on the same network');

  //Derive proper key to sign, for each input
  var privs = [],
    derived = {};

  var network = new Bitcore.Address(txp.toAddress).network.name;
  var xpriv = new Bitcore.HDPrivateKey(xPrivKey, network).derive(WalletUtils.PATHS.BASE_ADDRESS_DERIVATION);

  _.each(txp.inputs, function(i) {
    if (!derived[i.path]) {
      derived[i.path] = xpriv.derive(i.path).privateKey;
      privs.push(derived[i.path]);
    }
  });

  var t = WalletUtils.buildTx(txp);

  var signatures = _.map(privs, function(priv, i) {
    return t.getSignatures(priv);
  });

  signatures = _.map(_.sortBy(_.flatten(signatures), 'inputIndex'), function(s) {
    return s.signature.toDER().toString('hex');
  });

  return signatures;
};

WalletUtils.getNetworkFromXPubKey = function(xPubKey) {
  $.checkArgument(xPubKey && _.isString(xPubKey));
  return xPubKey.substr(0, 4) == 'tpub' ? 'testnet' : 'livenet';
};

module.exports = WalletUtils;
<|endoftext|>


<commit_before>'use strict';

const schedule = require('node-schedule');
const moment = require('moment');
const fs = require('fs');

module.exports = (bot, config) => {
    if (typeof config.data.channels === 'undefined') {
        config.data.channels = {};
    }
    if (typeof config.data.awardDelay === 'undefined') {
        config.data.awardDelay = {min: 1000, max: 60000};
    }
    if (typeof config.data.wordlist === 'undefined') {
        config.data.wordlist = 'wordlist.txt';
    }

    const jobs = {};

    const pickNewWord = () => {
        const filename = config.data.wordlist || '';
        try {
            const data = fs.readFileSync(filename, 'utf-8');
            const lines = data.split(/\s+/);
            return lines[Math.floor(Math.random() * lines.length)];
        } catch (error) {
            console.error(`Can't read wordlist at ${filename}`, error);
            return null;
        }
    };

    const stopJob = (channel) => {
        channel = channel.toLowerCase();
        const job = jobs[channel];
        if (typeof job !== 'undefined') {
            job.cancel();
            delete jobs[channel];
            delete config.data.channels[channel];
            return config.save();
        }
    };

    const startJob = (channel, cron, loading) => {
        channel = channel.toLowerCase();
        let job = jobs[channel];
        if (typeof job !== 'undefined') {
            job.reschedule(cron);
        } else {
            job = schedule.scheduleJob(cron, () => resetChannel(channel));
            jobs[channel] = job;
        }
        if (loading) {
            return job;
        } else {
            config.data.channels[channel] = {schedule: cron, word: pickNewWord(), winners: [], maxWinners: 3};
            return config.save().then(() => job);
        }
    };

    const getJob = (channel) => {
        return jobs[channel.toLowerCase()];
    };

    const resetChannel = (channel) => {
        channel = channel.toLowerCase();
        const info = config.data.channels[channel];
        if (typeof info === 'undefined') return;
        const time = moment(getJob(channel).nextInvocation()).fromNow(true);
        if (info.winners.length === 0) {
            bot.client.say(channel, `Aww, nobody guessed todays Word of the Day. The word was '${info.word}'. A new word has been chosen, you have ${time} to guess!`);
        } else {
            bot.client.say(channel, `Thanks for playing Word of the Day! Congratulations to all the winners. The word was '${info.word}'. A new word has been chosen, you have ${time} to guess!`);
            for (const i in info.winners) {
                bot.takeVoice(info.winners[i], channel);
            }
        }
        info.word = pickNewWord();
        info.winners = [];
        config.save();
    };

    const getAwardDelay = () => {
        const delay = config.data.awardDelay;
        return delay.min + Math.random() * (delay.max - delay.min);
    };

    const checkForWord = (nick, channel, message) => {
        channel = channel.toLowerCase();
        const info = config.data.channels[channel];
        if (typeof info === 'undefined') return;
        if (info.winners.length >= info.maxWinners) return;
        if (info.winners.indexOf(nick) > -1) return;

        if (message.toLowerCase().split(/ /).indexOf(info.word) > -1) {
            info.winners.push(nick);
            const next = moment(getJob(channel).nextInvocation());
            if (next.diff(moment()) > config.data.awardDelay.max) setTimeout(() => bot.giveVoice(nick, channel), getAwardDelay());
            bot.notify(nick, `You guessed the secret Word of The Day! It was '${info.word}', but shh! Don't tell anybody!`);
            if (info.winners.length === info.maxWinners) {
                bot.client.say(channel, `That's all the winners! The Word of The Day was '${info.word}'. Enjoy your voice until the next draw ${next.fromNow()}! <3`);
            }
            config.save();
        }
    };

    for (const channel in config.data.channels) {
        startJob(channel, config.data.channels[channel].schedule, true);
    }

    return {
        commands: {
            wotd: [
                {
                    pattern: /^set schedule (.+)$/,
                    requires: 'operator',
                    execute: (event, cron) => {
                        return startJob(event.channel, cron)
                            .then((job) => bot.notify(event.nick, `Schedule set. Next WOTD will be ${moment(job.nextInvocation()).fromNow()}.`));
                    }
                },
                {
                    pattern: /^set wordlist (.+)$/,
                    requires: 'admin',
                    execute: (event, wordlist) => {
                        config.data.wordlist = wordlist;
                        return config.save()
                            .then((job) => bot.notify(event.nick, `Wordlist set.`));
                    }
                },
                {
                    pattern: /^stop$/,
                    requires: 'operator',
                    execute: (event) => {
                        return stopJob(event.channel)
                            .then((job) => bot.notify(event.nick, `Schedule cleared. No more WOTDs will happen for this channel.`));
                    }
                },
                {
                    pattern: /^reset$/,
                    requires: 'operator',
                    execute: (event) => resetChannel(event.channel)
                },
                "Usage: wotd <set schedule CRON_SCHEDULE|stop|reset>"
            ]
        },
        listeners: {
            'message#': checkForWord
        }
    };
};<commit_msg>Fixed typo in wotd<commit_after>'use strict';

const schedule = require('node-schedule');
const moment = require('moment');
const fs = require('fs');

module.exports = (bot, config) => {
    if (typeof config.data.channels === 'undefined') {
        config.data.channels = {};
    }
    if (typeof config.data.awardDelay === 'undefined') {
        config.data.awardDelay = {min: 1000, max: 60000};
    }
    if (typeof config.data.wordlist === 'undefined') {
        config.data.wordlist = 'wordlist.txt';
    }

    const jobs = {};

    const pickNewWord = () => {
        const filename = config.data.wordlist || '';
        try {
            const data = fs.readFileSync(filename, 'utf-8');
            const lines = data.split(/\s+/);
            return lines[Math.floor(Math.random() * lines.length)];
        } catch (error) {
            console.error(`Can't read wordlist at ${filename}`, error);
            return null;
        }
    };

    const stopJob = (channel) => {
        channel = channel.toLowerCase();
        const job = jobs[channel];
        if (typeof job !== 'undefined') {
            job.cancel();
            delete jobs[channel];
            delete config.data.channels[channel];
            return config.save();
        }
    };

    const startJob = (channel, cron, loading) => {
        channel = channel.toLowerCase();
        let job = jobs[channel];
        if (typeof job !== 'undefined') {
            job.reschedule(cron);
        } else {
            job = schedule.scheduleJob(cron, () => resetChannel(channel));
            jobs[channel] = job;
        }
        if (loading) {
            return job;
        } else {
            config.data.channels[channel] = {schedule: cron, word: pickNewWord(), winners: [], maxWinners: 3};
            return config.save().then(() => job);
        }
    };

    const getJob = (channel) => {
        return jobs[channel.toLowerCase()];
    };

    const resetChannel = (channel) => {
        channel = channel.toLowerCase();
        const info = config.data.channels[channel];
        if (typeof info === 'undefined') return;
        const time = moment(getJob(channel).nextInvocation()).fromNow(true);
        if (info.winners.length === 0) {
            bot.client.say(channel, `Aww, nobody guessed today's Word of the Day. The word was '${info.word}'. A new word has been chosen, you have ${time} to guess!`);
        } else {
            bot.client.say(channel, `Thanks for playing Word of the Day! Congratulations to all the winners. The word was '${info.word}'. A new word has been chosen, you have ${time} to guess!`);
            for (const i in info.winners) {
                bot.takeVoice(info.winners[i], channel);
            }
        }
        info.word = pickNewWord();
        info.winners = [];
        config.save();
    };

    const getAwardDelay = () => {
        const delay = config.data.awardDelay;
        return delay.min + Math.random() * (delay.max - delay.min);
    };

    const checkForWord = (nick, channel, message) => {
        channel = channel.toLowerCase();
        const info = config.data.channels[channel];
        if (typeof info === 'undefined') return;
        if (info.winners.length >= info.maxWinners) return;
        if (info.winners.indexOf(nick) > -1) return;

        if (message.toLowerCase().split(/ /).indexOf(info.word) > -1) {
            info.winners.push(nick);
            const next = moment(getJob(channel).nextInvocation());
            if (next.diff(moment()) > config.data.awardDelay.max) setTimeout(() => bot.giveVoice(nick, channel), getAwardDelay());
            bot.notify(nick, `You guessed the secret Word of The Day! It was '${info.word}', but shh! Don't tell anybody!`);
            if (info.winners.length === info.maxWinners) {
                bot.client.say(channel, `That's all the winners! The Word of The Day was '${info.word}'. Enjoy your voice until the next draw ${next.fromNow()}! <3`);
            }
            config.save();
        }
    };

    for (const channel in config.data.channels) {
        startJob(channel, config.data.channels[channel].schedule, true);
    }

    return {
        commands: {
            wotd: [
                {
                    pattern: /^set schedule (.+)$/,
                    requires: 'operator',
                    execute: (event, cron) => {
                        return startJob(event.channel, cron)
                            .then((job) => bot.notify(event.nick, `Schedule set. Next WOTD will be ${moment(job.nextInvocation()).fromNow()}.`));
                    }
                },
                {
                    pattern: /^set wordlist (.+)$/,
                    requires: 'admin',
                    execute: (event, wordlist) => {
                        config.data.wordlist = wordlist;
                        return config.save()
                            .then((job) => bot.notify(event.nick, `Wordlist set.`));
                    }
                },
                {
                    pattern: /^stop$/,
                    requires: 'operator',
                    execute: (event) => {
                        return stopJob(event.channel)
                            .then((job) => bot.notify(event.nick, `Schedule cleared. No more WOTDs will happen for this channel.`));
                    }
                },
                {
                    pattern: /^reset$/,
                    requires: 'operator',
                    execute: (event) => resetChannel(event.channel)
                },
                "Usage: wotd <set schedule CRON_SCHEDULE|stop|reset>"
            ]
        },
        listeners: {
            'message#': checkForWord
        }
    };
};<|endoftext|>