<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": "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": "$"
};

<commit_msg>Change Moldova's currency from L to MDL<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": "MDL",
    "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>'use strict';

const fs = require('fs-extra');
const path = require('path');
const natural = require('natural');

const config = require('./config');
const utils = require('./utils');
const index = require('./index');
const platform = require('./platform');

const CACHE_FOLDER = path.join(config.get().cache, 'cache');

const filepath = CACHE_FOLDER + '/search-corpus.json';

let corpus = {};

corpus.fileWords = {};
corpus.fileLengths = {};
corpus.invertedIndex = {};
corpus.allTokens = new Set();
corpus.tfidf = {};

let query = {};

query.raw = null;
query.tokens = null;
query.frequency = {};
query.score = {};
query.ranks = [];

let getTokens = (data) => {
  let tokenizer = new natural.WordTokenizer();
  let tokens = tokenizer.tokenize(data);
  tokens.forEach((word, index) => {
    word = word.toLowerCase();
    word = natural.PorterStemmer.stem(word);
    tokens[index] = word;
  });

  return tokens;
};

let createFileIndex = (tokens, name) => {
  // Creates word frequency index for each file.
  corpus.fileWords[name] = {};
  tokens.forEach((word) => {
    corpus.allTokens.add(word);
    if (corpus.fileWords[name][word]) { // Word already exists. Increment count.
      corpus.fileWords[name][word]++;
    } else {
      corpus.fileWords[name][word] = 1;
    }
  });
};

let createInvertedIndex = (tokens) => {
  tokens.forEach((word) => {
    Object.keys(corpus.fileWords).forEach((name) => {
      if (corpus.fileWords[name][word]) {
        if (corpus.invertedIndex[word]) {
          corpus.invertedIndex[word].push(name);
        } else {
          corpus.invertedIndex[word] = [name];
        }
      }
    });
  });
};

let getTf = (word, filename) => {
  let worddata = corpus.fileWords[filename];
  let frequency = worddata[word] || 0;
  let length = 0;
  Object.keys(worddata).forEach((key) => {
    length += worddata[key];
  });
  let tf = frequency / length;
  return tf;
};

let getIdf = (word) => {
  let allFiles = Object.keys(corpus.fileWords).length;
  let wordFiles = corpus.invertedIndex[word].length;
  let idf = Math.log(allFiles / wordFiles);
  return idf;
};

let createTfIdf = () => {
  corpus.tfidf = {};
  Object.keys(corpus.fileWords).forEach((file) => {
    corpus.tfidf[file] = {};
    Object.keys(corpus.fileWords[file]).forEach((word) => {
      let tfidf = getTf(word, file) * getIdf(word);
      corpus.tfidf[file][word] = tfidf;
    });
  });
};

let processRawDocument = (data, name) => {
  let tokens = getTokens(data);
  createFileIndex(tokens, name);
};

let createFileLengths = () => {
  Object.keys(corpus.tfidf).forEach((name) => {
    let len = 0;
    Object.keys(corpus.tfidf[name]).forEach((word) => {
      len += corpus.tfidf[name][word] * corpus.tfidf[name][word];
    });
    corpus.fileLengths[name] = Math.sqrt(len);
  });
};

let writeCorpus = () => {
  corpus.allTokens = Array.from(corpus.allTokens);
  let json = JSON.stringify(corpus);
  return fs.writeFile(filepath, json, 'utf8')
    .then(() => {
      return Promise.resolve('JSON written to disk at: ' + filepath);
    })
    .catch((err) => {
      return Promise.reject(err);
    });
};

let readCorpus = () => {
  return fs.readFile(filepath, 'utf8')
    .then((data) => {
      corpus = JSON.parse(data.toString());
      return Promise.resolve();
    })
    .catch((err) => {
      return Promise.reject(err);
    });
};

let processQuery = (rawquery) => {
  query.raw = rawquery;
  query.tokens = getTokens(rawquery);
  //calculate word frequency in the query
  query.frequency = {};
  query.tokens.forEach((word) => {
    if (query.frequency[word]) { // Word already exists. Increment count.
      query.frequency[word]++;
    } else {
      query.frequency[word] = 1;
    }
  });
  let numberOfFiles = Object.keys(corpus.fileWords).length;
  // calculate score of each file for the query.
  query.score = {};
  query.tokens.forEach((word) => {
    if (corpus.invertedIndex[word]) {
      let logbase = 10;
      let df = corpus.invertedIndex[word].length;
      let idf = Math.log(numberOfFiles / df, logbase);
      let wordWeight = idf * (1 + Math.log(query.frequency[word], logbase));
      corpus.invertedIndex[word].forEach((file) => {
        let fileWeight = corpus.tfidf[file][word];
        if (query.score[file]) {
          query.score[file] += fileWeight * wordWeight;
        } else {
          query.score[file] = fileWeight * wordWeight;
        }
      });
    }
  });
  // rank the files by the score and sort
  Object.keys(query.score).forEach((file) => {
    query.score[file] = query.score[file] / corpus.fileLengths[file];
    let rankobj = {};
    rankobj.file = file;
    rankobj.score = query.score[file];
    query.ranks.push(rankobj);
  });
  query.ranks.sort((a, b) => {
    if (a.score > b.score) {
      return -1;
    }
    if (a.score < b.score) {
      return 1;
    }
    return 0;
  });
};

exports.printResults = (results, config) => {
  // Prints the passed results to the console.
  // If the command is not available for the current platform,
  // it lists the available platforms instead.
  // Example: tldr --search print directory tree --os sunos prints:
  //              $ tree (Available on: linux, osx)
  index.getShortIndex().then((shortIndex) => {
    let outputs = new Set();
    let preferredPlatform = platform.getPreferredPlatform(config);
    results.forEach((elem) => {
      let cmdname = utils.parsePagename(elem.file);
      let output = '    $ ' + cmdname;
      let array = shortIndex[cmdname]['platforms'];
      if (array.indexOf('common') === -1 && array.indexOf(preferredPlatform) === -1) {
        output += ' (Available on: ' + array.join(', ') + ')';
      }
      outputs.add(output);
    });

    console.log('Searching for:', query.raw.trim());
    console.log();
    Array.from(outputs).forEach((elem) => {
      console.log(elem);
    });
    console.log();
    console.log('Run tldr <command> to see specific pages.');
  });
};

exports.createIndex = () => {
  return utils.glob(CACHE_FOLDER + '/pages/**/*.md', {})
    .then((files) => {
      let promises = [];
      files.forEach((file) => {
        let promise = fs.readFile(file).then((data) => {
          processRawDocument(data.toString(), file);
        });
        promises.push(promise);
      });
      return Promise.all(promises)
        .then(() => {
          createInvertedIndex(corpus.allTokens);
          createTfIdf();
          createFileLengths();
          return writeCorpus();
        })
        .then(() => {
          return Promise.resolve(corpus);
        })
        .catch((error) => {
          console.error('Error in creating corpus. Exiting.');
          return Promise.reject(error);
        });
    });
};

exports.getResults = (rawquery) => {
  query.ranks = [];
  return readCorpus()
    .then(() => {
      processQuery(rawquery);
      let resultcount = 10;
      let results = query.ranks.slice(0, resultcount);
      return Promise.resolve(results);
    })
    .catch((error) => {
      return Promise.reject(error);
    });
};
<commit_msg>Fix bug for search<commit_after>'use strict';

const fs = require('fs-extra');
const path = require('path');
const natural = require('natural');

const config = require('./config');
const utils = require('./utils');
const index = require('./index');
const platform = require('./platform');

const CACHE_FOLDER = path.join(config.get().cache, 'cache');

const filepath = CACHE_FOLDER + '/search-corpus.json';

let corpus = {};

corpus.fileWords = {};
corpus.fileLengths = {};
corpus.invertedIndex = {};
corpus.allTokens = new Set();
corpus.tfidf = {};

let query = {};

query.raw = null;
query.tokens = null;
query.frequency = {};
query.score = {};
query.ranks = [];

let getTokens = (data) => {
  let tokenizer = new natural.WordTokenizer();
  let tokens = tokenizer.tokenize(data);
  tokens.forEach((word, index) => {
    word = word.toLowerCase();
    word = natural.PorterStemmer.stem(word);
    tokens[index] = word;
  });

  return tokens;
};

let createFileIndex = (tokens, name) => {
  // Creates word frequency index for each file.
  corpus.fileWords[name] = {};
  tokens.forEach((word) => {
    corpus.allTokens.add(word);
    if (corpus.fileWords[name][word]) { // Word already exists. Increment count.
      corpus.fileWords[name][word]++;
    } else {
      corpus.fileWords[name][word] = 1;
    }
  });
};

let createInvertedIndex = (tokens) => {
  tokens.forEach((word) => {
    Object.keys(corpus.fileWords).forEach((name) => {
      if (corpus.fileWords[name][word]) {
        if (corpus.invertedIndex[word]) {
          corpus.invertedIndex[word].push(name);
        } else {
          corpus.invertedIndex[word] = [name];
        }
      }
    });
  });
};

let getTf = (word, filename) => {
  let worddata = corpus.fileWords[filename];
  let frequency = worddata[word] || 0;
  let length = 0;
  Object.keys(worddata).forEach((key) => {
    length += worddata[key];
  });
  let tf = frequency / length;
  return tf;
};

let getIdf = (word) => {
  let allFiles = Object.keys(corpus.fileWords).length;
  let wordFiles = corpus.invertedIndex[word].length;
  let idf = Math.log(allFiles / wordFiles);
  return idf;
};

let createTfIdf = () => {
  corpus.tfidf = {};
  Object.keys(corpus.fileWords).forEach((file) => {
    corpus.tfidf[file] = {};
    Object.keys(corpus.fileWords[file]).forEach((word) => {
      let tfidf = getTf(word, file) * getIdf(word);
      corpus.tfidf[file][word] = tfidf;
    });
  });
};

let processRawDocument = (data, name) => {
  let tokens = getTokens(data);
  createFileIndex(tokens, name);
};

let createFileLengths = () => {
  Object.keys(corpus.tfidf).forEach((name) => {
    let len = 0;
    Object.keys(corpus.tfidf[name]).forEach((word) => {
      len += corpus.tfidf[name][word] * corpus.tfidf[name][word];
    });
    corpus.fileLengths[name] = Math.sqrt(len);
  });
};

let writeCorpus = () => {
  corpus.allTokens = Array.from(corpus.allTokens);
  let json = JSON.stringify(corpus);
  return fs.writeFile(filepath, json, 'utf8')
    .then(() => {
      return Promise.resolve('JSON written to disk at: ' + filepath);
    })
    .catch((err) => {
      return Promise.reject(err);
    });
};

let readCorpus = () => {
  return fs.readFile(filepath, 'utf8')
    .then((data) => {
      corpus = JSON.parse(data.toString());
      return Promise.resolve();
    })
    .catch((err) => {
      return Promise.reject(err);
    });
};

let processQuery = (rawquery) => {
  query.raw = rawquery;
  query.tokens = getTokens(rawquery);
  //calculate word frequency in the query
  query.frequency = {};
  query.tokens.forEach((word) => {
    if (query.frequency[word]) { // Word already exists. Increment count.
      query.frequency[word]++;
    } else {
      query.frequency[word] = 1;
    }
  });
  let numberOfFiles = Object.keys(corpus.fileWords).length;
  // calculate score of each file for the query.
  query.score = {};
  query.tokens.forEach((word) => {
    if (corpus.invertedIndex[word]) {
      let logbase = 10;
      let df = corpus.invertedIndex[word].length;
      let idf = Math.log(numberOfFiles / df, logbase);
      let wordWeight = idf * (1 + Math.log(query.frequency[word], logbase));
      corpus.invertedIndex[word].forEach((file) => {
        let fileWeight = corpus.tfidf[file][word];
        if (query.score[file]) {
          query.score[file] += fileWeight * wordWeight;
        } else {
          query.score[file] = fileWeight * wordWeight;
        }
      });
    }
  });
  // rank the files by the score and sort
  Object.keys(query.score).forEach((file) => {
    query.score[file] = query.score[file] / corpus.fileLengths[file];
    let rankobj = {};
    rankobj.file = file;
    rankobj.score = query.score[file];
    query.ranks.push(rankobj);
  });
  query.ranks.sort((a, b) => {
    if (a.score > b.score) {
      return -1;
    }
    if (a.score < b.score) {
      return 1;
    }
    return 0;
  });
};

exports.printResults = (results, config) => {
  // Prints the passed results to the console.
  // If the command is not available for the current platform,
  // it lists the available platforms instead.
  // Example: tldr --search print directory tree --os sunos prints:
  //              $ tree (Available on: linux, osx)
  index.getShortIndex().then((shortIndex) => {
    let outputs = new Set();
    let preferredPlatform = platform.getPreferredPlatform(config);
    results.forEach((elem) => {
      let cmdname = utils.parsePagename(elem.file);
      let output = '    $ ' + cmdname;
      let targets = shortIndex[cmdname]['targets'];
      let platforms = targets.map((t) => {return t.os;});
      if (platforms.indexOf('common') === -1 && platforms.indexOf(preferredPlatform) === -1) {
        output += ' (Available on: ' + platforms.join(', ') + ')';
      }
      outputs.add(output);
    });

    console.log('Searching for:', query.raw.trim());
    console.log();
    Array.from(outputs).forEach((elem) => {
      console.log(elem);
    });
    console.log();
    console.log('Run tldr <command> to see specific pages.');
  });
};

exports.createIndex = () => {
  return utils.glob(CACHE_FOLDER + '/pages/**/*.md', {})
    .then((files) => {
      let promises = [];
      files.forEach((file) => {
        let promise = fs.readFile(file).then((data) => {
          processRawDocument(data.toString(), file);
        });
        promises.push(promise);
      });
      return Promise.all(promises)
        .then(() => {
          createInvertedIndex(corpus.allTokens);
          createTfIdf();
          createFileLengths();
          return writeCorpus();
        })
        .then(() => {
          return Promise.resolve(corpus);
        })
        .catch((error) => {
          console.error('Error in creating corpus. Exiting.');
          return Promise.reject(error);
        });
    });
};

exports.getResults = (rawquery) => {
  query.ranks = [];
  return readCorpus()
    .then(() => {
      processQuery(rawquery);
      let resultcount = 10;
      let results = query.ranks.slice(0, resultcount);
      return Promise.resolve(results);
    })
    .catch((error) => {
      return Promise.reject(error);
    });
};
<|endoftext|>


<commit_before>var tessel = require('tessel');
var http = require('http');

// Replace the [websitename] with the name of the website
// your are connecting to.
// var apiUrl = "https://[websitename].azurewebsites.net";
var apiUrl = "https://tessel.azurewebsites.net";

console.log();
console.log('blinky-websites');
console.log('----------------------');
console.log('check: your tessel should be connected to wifi (orange led)');
console.log('check: make sure you have changed the url to your service');
console.log('using: ', apiUrl);
console.log();
console.log('press the config-button on your tessel to invoke service call');

tessel.button.on('press', function(time) {
	console.log('main - button pressed');

	httpGetJSON(apiUrl, function(err, obj) {
		if (!err) {
			console.log('main - received random number:', obj.rnd);
			console.log('main - flashing led %d times', obj.rnd);

			blink(1, obj.rnd, function() {
				console.log('main - done');
				console.log();
			});
		}
		else {
			console.error('error -', err.message);
		}
	});
});

function httpGetJSON(url, callback) {
	http.get(url, function(res) {
		var body = '';

		res.on('data', function(data) {
			console.log('httpGetJSON - data received', data);
			body += data;
		});

		res.on('end', function() {
			console.log('httpGetJSON - all data received', body);
			callback(null, JSON.parse(body));
		});

	}).on('error', function (err) {
		// An error occurred while calling url
		callback(err, null);
	});
}

function blink(ledNo, noTimes, callback) {
	if (noTimes > 0) {
		var led = tessel.led[ledNo].output(0);
		var lightOnDelay = 500;
		var lightOffDelay = 1000;

		console.log('blink - turning on led (%d)', noTimes);
		led.write(true);
		setTimeout(function(){
			console.log('blink - turning off led');
			led.write(false);
			setTimeout(blink, lightOffDelay, ledNo, noTimes - 1, callback);
		}, lightOnDelay);
	}
	else {
		callback();
	}
}<commit_msg>fixed url that pointed to wrong endpoint<commit_after>var tessel = require('tessel');
var http = require('http');

// Replace the [websitename] with the name of the website
// your are connecting to.
var apiUrl = "https://[websitename].azurewebsites.net";

console.log();
console.log('blinky-websites');
console.log('----------------------');
console.log('check: your tessel should be connected to wifi (orange led)');
console.log('check: make sure you have changed the url to your service');
console.log('using: ', apiUrl);
console.log();
console.log('press the config-button on your tessel to invoke service call');

tessel.button.on('press', function(time) {
	console.log('main - button pressed');

	httpGetJSON(apiUrl, function(err, obj) {
		if (!err) {
			console.log('main - received random number:', obj.rnd);
			console.log('main - flashing led %d times', obj.rnd);

			blink(1, obj.rnd, function() {
				console.log('main - done');
				console.log();
			});
		}
		else {
			console.error('error -', err.message);
		}
	});
});

function httpGetJSON(url, callback) {
	http.get(url, function(res) {
		var body = '';

		res.on('data', function(data) {
			console.log('httpGetJSON - data received', data);
			body += data;
		});

		res.on('end', function() {
			console.log('httpGetJSON - all data received', body);
			callback(null, JSON.parse(body));
		});

	}).on('error', function (err) {
		// An error occurred while calling url
		callback(err, null);
	});
}

function blink(ledNo, noTimes, callback) {
	if (noTimes > 0) {
		var led = tessel.led[ledNo].output(0);
		var lightOnDelay = 500;
		var lightOffDelay = 1000;

		console.log('blink - turning on led (%d)', noTimes);
		led.write(true);
		setTimeout(function(){
			console.log('blink - turning off led');
			led.write(false);
			setTimeout(blink, lightOffDelay, ledNo, noTimes - 1, callback);
		}, lightOnDelay);
	}
	else {
		callback();
	}
}<|endoftext|>


<commit_before>'use strict';
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var msgpack = require('msgpack-lite');
var net = require('net');
var stream = require('stream');
var crypto = require('crypto');
var FluentLoggerError = require('./logger-error');
var EventTime = require('./event-time').EventTime;

var codec = msgpack.createCodec();
codec.addExtPacker(0x00, EventTime, EventTime.pack);
codec.addExtUnpacker(0x00, EventTime.unpack);

function FluentSender(tag_prefix, options){
  options = options || {};
  this.tag_prefix = tag_prefix;
  this.host = options.host || 'localhost';
  this.port = options.port || 24224;
  this.path = options.path;
  this.timeout = options.timeout || 3.0;
  this.reconnectInterval = options.reconnectInterval || 600000; // Default is 10 minutes
  this.requireAckResponse = options.requireAckResponse;
  this.ackResponseTimeout = options.ackResponseTimeout || 190000; // Default is 190 seconds
  this.internalLogger = options.internalLogger || console;
  this._timeResolution = options.milliseconds ? 1 : 1000;
  this._socket = null;
  this._sendQueue = []; // queue for items waiting for being sent.
  this._eventEmitter = new EventEmitter();
  // options.security = { clientHostname: "client.localdomain", sharedKey: "very-secret-shared-key" }
  this.security = options.security || {
    clientHostname: null,
    sharedKey: null,
    username: '',
    passwort: ''
  };
  this.sharedKeySalt = crypto.randomBytes(16).toString('hex');
  // helo, pingpong, established
  this._status = null;
  this._connecting = false;
}

FluentSender.prototype.emit = function(/*[label] <data>, [timestamp], [callback] */){
  var label, data, timestamp, callback;
  var args = Array.prototype.slice.call(arguments);
  // Label must be string always
  if (typeof args[0] === 'string') label = args.shift();

  // Data can be almost anything
  data = args.shift();

  // Date can be either timestamp number or Date object
  if (typeof args[0] !== 'function') timestamp = args.shift();

  // Last argument is an optional callback
  if (typeof args[0] === 'function') callback = args.shift();

  var item = this._makePacketItem(label, data, timestamp);

  var error;
  var options;
  if (item.tag === null) {
    options = {
      tag_prefix: this.tag_prefix,
      label: label
    };
    error = new FluentLoggerError.MissingTag('tag is missing', options);
    this._handleEvent('error', error, callback);
    return;
  }
  if (typeof item.data !== 'object') {
    options = {
      tag_prefix: this.tag_prefix,
      label: label,
      record: item.data
    };
    error = new FluentLoggerError.DataTypeError('data must be an object', options);
    this._handleEvent('error', error, callback);
    return;
  }

  item.callback = callback;

  this._sendQueue.push(item);
  this._connect(() => {
    this._flushSendQueue();
  });
};

['addListener', 'on', 'once', 'removeListener', 'removeAllListeners', 'setMaxListeners', 'getMaxListeners'].forEach(function(attr, i){
  FluentSender.prototype[attr] = function(){
    return this._eventEmitter[attr].apply(this._eventEmitter, Array.prototype.slice.call(arguments));
  };
});

FluentSender.prototype.end = function(label, data, callback){
  if ((label != null && data != null)) {
    this.emit(label, data, (err) => {
      this._close();
      if (err) {
        this._handleEvent('error', err, callback);
      } else {
        callback && callback();
      }
    });
  } else {
    process.nextTick(() => {
      this._close();
      callback && callback();
    });
  }
};

FluentSender.prototype._close = function() {
  if (this._socket) {
    this._socket.end();
    this._socket = null;
    this._status = null;
  }
};

FluentSender.prototype._makeTag = function(label) {
  let tag = null;
  if (this.tag_prefix && label) {
    tag = [this.tag_prefix, label].join('.');
  } else if (this.tag_prefix) {
    tag = this.tag_prefix;
  } else if (label) {
    tag = label;
  }
  return tag;
};

FluentSender.prototype._makePacketItem = function(label, data, time){
  let tag = this._makeTak(label);

  if (typeof time !== 'number' && !(time instanceof EventTime)) {
    time = Math.floor((time ? time.getTime() : Date.now()) / this._timeResolution);
  }

  var packet = [tag, time, data];
  var options = {};
  if (this.requireAckResponse) {
    options = {
      chunk: crypto.randomBytes(16).toString('base64')
    };
    packet.push(options);
  }
  return {
    packet: msgpack.encode(packet, { codec: codec }),
    tag: tag,
    time: time,
    data: data,
    options: options
  };
};

FluentSender.prototype._makeEventEntry = function(time, data) {
  if (typeof time !== 'number' && !(time instanceof EventTime)) {
    time = Math.floor((time ? time.getTime() : Date.now()) / this._timeResolution);
  }

  return msgpack.encode([time, data], { codec: codec });
};

FluentSender.prototype._connect = function(callback){
  if (this._connecting) {
    return;
  }

  this._connecting = true;
  process.nextTick(() => {
    if (this._socket === null) {
      this._doConnect(() => {
        this._connecting = false;
        callback();
      });
    } else {
      if (!this._socket.writable) {
        this._disconnect();
        process.nextTick(() => {
          this._connecting = false;
          this._connect(callback);
        });
      } else {
        process.nextTick(() => {
          this._connecting = false;
          callback();
        });
      }
    }
  });
};

FluentSender.prototype._doConnect = function(callback) {
  this._socket = new net.Socket();
  this._socket.setTimeout(this.timeout);
  this._socket.on('error', (err) => {
    if (this._socket) {
      this._disconnect();
      this._handleEvent('error', err);
    }
  });
  this._socket.on('connect', () => {
    this._handleEvent('connect');
  });
  if (this.path) {
    this._socket.connect(this.path, () => {
      callback();
    });
  } else {
    this._socket.connect(this.port, this.host, () => {
      if (this.security.clientHostname && this.security.sharedKey) {
        this._handshake(callback);
      } else {
        this._status = 'established';
        callback();
      }
    });
  }
};

FluentSender.prototype._disconnect = function() {
  this._socket && this._socket.destroy();
  this._socket = null;
  this._status = null;
  this._connecting = false;
};

FluentSender.prototype._handshake = function(callback) {
  if (this._status === 'established') {
    return;
  }
  this._status = 'helo';
  this._socket.once('data', (data) => {
    this._socket.pause();
    let heloStatus = this._checkHelo(data);
    if (!heloStatus.succeeded) {
      this.internalLogger.error("Received invalid HELO message from " + this._socket.remoteAddress);
      this._disconnect();
      return;
    }
    this._status = 'pingpong';
    this._socket.write(new Buffer(this._generatePing()), () => {
      this._socket.resume();
      this._socket.once('data', (data) => {
        let pongStatus = this._checkPong(data);
        if (!pongStatus.succeeded) {
          this.internalLogger.error(pongStatus.message);
          let error = new FluentLoggerError.HandshakeError(pongStatus.message);
          this._handleEvent('error', error);
          this._disconnect();
          return;
        }
        this._status = 'established';
        this.internalLogger.info('Established');
        callback();
      });
    });
  });
};

FluentSender.prototype._flushSendQueue = function() {
  if (this._flushingSendQueue)
    return;

  this._flushingSendQueue = true;
  process.nextTick(() => {
    if (!this._socket) {
      this._flushingSendQueue = false;
      return;
    }

    if (this._socket.writable) {
      this._doFlushSendQueue();
    } else {
      process.nextTick(waitToWrite);
    }
  });
};

FluentSender.prototype._doFlushSendQueue = function() {
  var item = this._sendQueue.shift();
  var timeoutId = null;
  if (item === undefined) {
    this._flushingSendQueue = false;
    // nothing written;
  } else {
    this._socket.write(new Buffer(item.packet), () => {
      if (this.requireAckResponse) {
        this._socket.once('data', (data) => {
          timeoutId && clearTimeout(timeoutId);
          var response = msgpack.decode(data, { codec: codec });
          if (response.ack !== item.options.chunk) {
            var error = new FluentLoggerError.ResponseError('ack in response and chunk id in sent data are different',
                                                            { ack: response.ack, chunk: item.options.chunk });
            this._handleEvent('error', error, item.callback);
          }
          item.callback && item.callback();
          process.nextTick(() => {
            this._doFlushSendQueue(); // if socket is still available
          });
        });
        timeoutId = setTimeout(() => {
          var error = new FluentLoggerError.ResponseTimeout('ack response timeout');
          this._handleEvent('error', error, item.callback);
        }, this.ackResponseTimeout);
      } else {
        item.callback && item.callback();
        process.nextTick(() => {
          this._doFlushSendQueue(); // if socket is still available
        });
      }
    });
    // TODO: how should we recorver if dequeued items are not sent.
  }
};

FluentSender.prototype._handleEvent = function _handleEvent(signal, data, callback) {
  callback && callback(data);
  if (this._eventEmitter.listenerCount(signal) > 0) {
    this._eventEmitter.emit(signal, data);
  }
};

FluentSender.prototype._setupErrorHandler = function _setupErrorHandler() {
  if (!this.reconnectInterval) {
    return;
  }
  this.on('error', (error) => {
    this._flushingSendQueue = false;
    this._status = null;
    this.internalLogger.error('Fluentd error', error);
    this.internalLogger.info('Fluentd will reconnect after ' + this.reconnectInterval / 1000 + ' seconds');
    setTimeout(() => {
      this.internalLogger.info('Fluentd is reconnecting...');
      this._connect(() => {
        this.internalLogger.info('Fluentd reconnection finished!!');
      });
    }, this.reconnectInterval);
  });
};

FluentSender.prototype._checkHelo = function _checkHelo(data) {
  // ['HELO', options(hash)]
  this.internalLogger.info('Checking HELO...');
  var message = msgpack.decode(data);
  if (message.length !== 2) {
    return { succeeded: false, message: 'Invalid format for HELO message' };
  }
  if (message[0] !== 'HELO') {
    return { succeeded: false, message: 'Invalid format for HELO message' };
  }
  var options = message[1] || {};
  this.sharedKeyNonce = options['nonce'] || '';
  this.authentication = options['auth'] || '';
  return { succeeded: true };
};

FluentSender.prototype._generatePing = function _generatePing() {
  // [
  //   'PING',
  //   client_hostname,
  //   shared_key_salt,
  //   sha512_hex(sharedkey_salt + client_hostname + nonce + shared_key),
  //   username || '',
  //   sha512_hex(auth_salt + username + password) || ''
  // ]
  var sharedKeyHexdigest = crypto.createHash('sha512')
      .update(this.sharedKeySalt)
      .update(this.security.clientHostname)
      .update(this.sharedKeyNonce)
      .update(this.security.sharedKey)
      .digest('hex');
  var ping = ['PING', this.security.clientHostname, this.sharedKeySalt, sharedKeyHexdigest];
  if (Buffer.isBuffer(this.authentication) && Buffer.byteLength(this.authentication) !== 0) {
    var passwordHexDigest = crypto.createHash('sha512')
        .update(this.authentication)
        .update(this.security.username || '')
        .update(this.security.password || '')
        .digest('hex');
    ping.push(this.username, passwordHexDigest);
  } else {
    ping.push('', '');
  }
  return msgpack.encode(ping);
};

FluentSender.prototype._checkPong = function _checkPong(data) {
  // [
  //   'PONG',
  //   bool(authentication result),
  //   'reason if authentication failed',
  //   server_hostname,
  //   sha512_hex(salt + server_hostname + nonce + sharedkey)
  // ]
  this.internalLogger.info('Checking PONG...');
  var message = msgpack.decode(data);
  if (message.length !== 5) {
    return false;
  }
  if (message[0] !== 'PONG') {
    return { succeeded: false, message: 'Invalid format for PONG message' };
  }
  var _pong = message[0];
  var authResult = message[1];
  var reason = message[2];
  var hostname = message[3];
  var sharedKeyHexdigest = message[4];
  if (!authResult) {
    return { succeeded: false, message: 'Authentication failed: ' + reason };
  }
  if (hostname === this.security.clientHostname) {
    return { succeeded: false, message: 'Same hostname between input and output: invalid configuration' };
  }
  var clientsideHexdigest = crypto.createHash('sha512')
      .update(this.sharedKeySalt)
      .update(hostname)
      .update(this.sharedKeyNonce)
      .update(this.security.sharedKey)
      .digest('hex');
  if (sharedKeyHexdigest !== clientsideHexdigest) {
    return { succeeded: false, message: 'Sharedkey mismatch' };
  }
  return { succeeded: true };
};

FluentSender.prototype.toStream = function(options) {
  if (typeof options === 'string') {
    options = {label: options};
  } else {
    options = options || {};
  }
  var label = options.label;
  if (!label) {
    throw new Error('label is needed');
  }
  var defaultEncoding = options.encoding || 'UTF-8';
  var writable = new stream.Writable();
  var dataString = '';
  writable._write = (chunk, encoding, callback) => {
    var dataArray = chunk.toString(defaultEncoding).split(/\n/);
    var next = () => {
      if (dataArray.length) {
        dataString += dataArray.shift();
      }
      if (!dataArray.length) {
        process.nextTick(callback);
        return;
      }
      this.emit(label, { message: dataString }, (err) => {
        if (err) {
          this._handleEvent('error', err, callback);
          return;
        }
        dataString = '';
        next();
      });
    };
    next();
  };
  return writable;
};

module.exports = exports = {};
exports.FluentSender = FluentSender;
<commit_msg>Change FluentSender._makePacketItem signature<commit_after>'use strict';
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var msgpack = require('msgpack-lite');
var net = require('net');
var stream = require('stream');
var crypto = require('crypto');
var FluentLoggerError = require('./logger-error');
var EventTime = require('./event-time').EventTime;

var codec = msgpack.createCodec();
codec.addExtPacker(0x00, EventTime, EventTime.pack);
codec.addExtUnpacker(0x00, EventTime.unpack);

function FluentSender(tag_prefix, options){
  options = options || {};
  this.tag_prefix = tag_prefix;
  this.host = options.host || 'localhost';
  this.port = options.port || 24224;
  this.path = options.path;
  this.timeout = options.timeout || 3.0;
  this.reconnectInterval = options.reconnectInterval || 600000; // Default is 10 minutes
  this.requireAckResponse = options.requireAckResponse;
  this.ackResponseTimeout = options.ackResponseTimeout || 190000; // Default is 190 seconds
  this.internalLogger = options.internalLogger || console;
  this._timeResolution = options.milliseconds ? 1 : 1000;
  this._socket = null;
  this._sendQueue = []; // queue for items waiting for being sent.
  this._eventEmitter = new EventEmitter();
  // options.security = { clientHostname: "client.localdomain", sharedKey: "very-secret-shared-key" }
  this.security = options.security || {
    clientHostname: null,
    sharedKey: null,
    username: '',
    passwort: ''
  };
  this.sharedKeySalt = crypto.randomBytes(16).toString('hex');
  // helo, pingpong, established
  this._status = null;
  this._connecting = false;
}

FluentSender.prototype.emit = function(/*[label] <data>, [timestamp], [callback] */){
  var label, data, timestamp, callback;
  var args = Array.prototype.slice.call(arguments);
  // Label must be string always
  if (typeof args[0] === 'string') label = args.shift();

  // Data can be almost anything
  data = args.shift();

  // Date can be either timestamp number or Date object
  if (typeof args[0] !== 'function') timestamp = args.shift();

  // Last argument is an optional callback
  if (typeof args[0] === 'function') callback = args.shift();

  var item = this._makePacketItem(label, data, timestamp);

  var error;
  var options;
  if (item.tag === null) {
    options = {
      tag_prefix: this.tag_prefix,
      label: label
    };
    error = new FluentLoggerError.MissingTag('tag is missing', options);
    this._handleEvent('error', error, callback);
    return;
  }
  if (typeof item.data !== 'object') {
    options = {
      tag_prefix: this.tag_prefix,
      label: label,
      record: item.data
    };
    error = new FluentLoggerError.DataTypeError('data must be an object', options);
    this._handleEvent('error', error, callback);
    return;
  }

  item.callback = callback;

  this._sendQueue.push(item);
  this._connect(() => {
    this._flushSendQueue();
  });
};

['addListener', 'on', 'once', 'removeListener', 'removeAllListeners', 'setMaxListeners', 'getMaxListeners'].forEach(function(attr, i){
  FluentSender.prototype[attr] = function(){
    return this._eventEmitter[attr].apply(this._eventEmitter, Array.prototype.slice.call(arguments));
  };
});

FluentSender.prototype.end = function(label, data, callback){
  if ((label != null && data != null)) {
    this.emit(label, data, (err) => {
      this._close();
      if (err) {
        this._handleEvent('error', err, callback);
      } else {
        callback && callback();
      }
    });
  } else {
    process.nextTick(() => {
      this._close();
      callback && callback();
    });
  }
};

FluentSender.prototype._close = function() {
  if (this._socket) {
    this._socket.end();
    this._socket = null;
    this._status = null;
  }
};

FluentSender.prototype._makeTag = function(label) {
  let tag = null;
  if (this.tag_prefix && label) {
    tag = [this.tag_prefix, label].join('.');
  } else if (this.tag_prefix) {
    tag = this.tag_prefix;
  } else if (label) {
    tag = label;
  }
  return tag;
};

FluentSender.prototype._makePacketItem = function(tag, time, data){
  if (typeof time !== 'number' && !(time instanceof EventTime)) {
    time = Math.floor((time ? time.getTime() : Date.now()) / this._timeResolution);
  }

  var packet = [tag, time, data];
  var options = {};
  if (this.requireAckResponse) {
    options = {
      chunk: crypto.randomBytes(16).toString('base64')
    };
    packet.push(options);
  }
  return {
    packet: msgpack.encode(packet, { codec: codec }),
    tag: tag,
    time: time,
    data: data,
    options: options
  };
};

FluentSender.prototype._makeEventEntry = function(time, data) {
  if (typeof time !== 'number' && !(time instanceof EventTime)) {
    time = Math.floor((time ? time.getTime() : Date.now()) / this._timeResolution);
  }

  return msgpack.encode([time, data], { codec: codec });
};

FluentSender.prototype._connect = function(callback){
  if (this._connecting) {
    return;
  }

  this._connecting = true;
  process.nextTick(() => {
    if (this._socket === null) {
      this._doConnect(() => {
        this._connecting = false;
        callback();
      });
    } else {
      if (!this._socket.writable) {
        this._disconnect();
        process.nextTick(() => {
          this._connecting = false;
          this._connect(callback);
        });
      } else {
        process.nextTick(() => {
          this._connecting = false;
          callback();
        });
      }
    }
  });
};

FluentSender.prototype._doConnect = function(callback) {
  this._socket = new net.Socket();
  this._socket.setTimeout(this.timeout);
  this._socket.on('error', (err) => {
    if (this._socket) {
      this._disconnect();
      this._handleEvent('error', err);
    }
  });
  this._socket.on('connect', () => {
    this._handleEvent('connect');
  });
  if (this.path) {
    this._socket.connect(this.path, () => {
      callback();
    });
  } else {
    this._socket.connect(this.port, this.host, () => {
      if (this.security.clientHostname && this.security.sharedKey) {
        this._handshake(callback);
      } else {
        this._status = 'established';
        callback();
      }
    });
  }
};

FluentSender.prototype._disconnect = function() {
  this._socket && this._socket.destroy();
  this._socket = null;
  this._status = null;
  this._connecting = false;
};

FluentSender.prototype._handshake = function(callback) {
  if (this._status === 'established') {
    return;
  }
  this._status = 'helo';
  this._socket.once('data', (data) => {
    this._socket.pause();
    let heloStatus = this._checkHelo(data);
    if (!heloStatus.succeeded) {
      this.internalLogger.error("Received invalid HELO message from " + this._socket.remoteAddress);
      this._disconnect();
      return;
    }
    this._status = 'pingpong';
    this._socket.write(new Buffer(this._generatePing()), () => {
      this._socket.resume();
      this._socket.once('data', (data) => {
        let pongStatus = this._checkPong(data);
        if (!pongStatus.succeeded) {
          this.internalLogger.error(pongStatus.message);
          let error = new FluentLoggerError.HandshakeError(pongStatus.message);
          this._handleEvent('error', error);
          this._disconnect();
          return;
        }
        this._status = 'established';
        this.internalLogger.info('Established');
        callback();
      });
    });
  });
};

FluentSender.prototype._flushSendQueue = function() {
  if (this._flushingSendQueue)
    return;

  this._flushingSendQueue = true;
  process.nextTick(() => {
    if (!this._socket) {
      this._flushingSendQueue = false;
      return;
    }

    if (this._socket.writable) {
      this._doFlushSendQueue();
    } else {
      process.nextTick(waitToWrite);
    }
  });
};

FluentSender.prototype._doFlushSendQueue = function() {
  var item = this._sendQueue.shift();
  var timeoutId = null;
  if (item === undefined) {
    this._flushingSendQueue = false;
    // nothing written;
  } else {
    this._socket.write(new Buffer(item.packet), () => {
      if (this.requireAckResponse) {
        this._socket.once('data', (data) => {
          timeoutId && clearTimeout(timeoutId);
          var response = msgpack.decode(data, { codec: codec });
          if (response.ack !== item.options.chunk) {
            var error = new FluentLoggerError.ResponseError('ack in response and chunk id in sent data are different',
                                                            { ack: response.ack, chunk: item.options.chunk });
            this._handleEvent('error', error, item.callback);
          }
          item.callback && item.callback();
          process.nextTick(() => {
            this._doFlushSendQueue(); // if socket is still available
          });
        });
        timeoutId = setTimeout(() => {
          var error = new FluentLoggerError.ResponseTimeout('ack response timeout');
          this._handleEvent('error', error, item.callback);
        }, this.ackResponseTimeout);
      } else {
        item.callback && item.callback();
        process.nextTick(() => {
          this._doFlushSendQueue(); // if socket is still available
        });
      }
    });
    // TODO: how should we recorver if dequeued items are not sent.
  }
};

FluentSender.prototype._handleEvent = function _handleEvent(signal, data, callback) {
  callback && callback(data);
  if (this._eventEmitter.listenerCount(signal) > 0) {
    this._eventEmitter.emit(signal, data);
  }
};

FluentSender.prototype._setupErrorHandler = function _setupErrorHandler() {
  if (!this.reconnectInterval) {
    return;
  }
  this.on('error', (error) => {
    this._flushingSendQueue = false;
    this._status = null;
    this.internalLogger.error('Fluentd error', error);
    this.internalLogger.info('Fluentd will reconnect after ' + this.reconnectInterval / 1000 + ' seconds');
    setTimeout(() => {
      this.internalLogger.info('Fluentd is reconnecting...');
      this._connect(() => {
        this.internalLogger.info('Fluentd reconnection finished!!');
      });
    }, this.reconnectInterval);
  });
};

FluentSender.prototype._checkHelo = function _checkHelo(data) {
  // ['HELO', options(hash)]
  this.internalLogger.info('Checking HELO...');
  var message = msgpack.decode(data);
  if (message.length !== 2) {
    return { succeeded: false, message: 'Invalid format for HELO message' };
  }
  if (message[0] !== 'HELO') {
    return { succeeded: false, message: 'Invalid format for HELO message' };
  }
  var options = message[1] || {};
  this.sharedKeyNonce = options['nonce'] || '';
  this.authentication = options['auth'] || '';
  return { succeeded: true };
};

FluentSender.prototype._generatePing = function _generatePing() {
  // [
  //   'PING',
  //   client_hostname,
  //   shared_key_salt,
  //   sha512_hex(sharedkey_salt + client_hostname + nonce + shared_key),
  //   username || '',
  //   sha512_hex(auth_salt + username + password) || ''
  // ]
  var sharedKeyHexdigest = crypto.createHash('sha512')
      .update(this.sharedKeySalt)
      .update(this.security.clientHostname)
      .update(this.sharedKeyNonce)
      .update(this.security.sharedKey)
      .digest('hex');
  var ping = ['PING', this.security.clientHostname, this.sharedKeySalt, sharedKeyHexdigest];
  if (Buffer.isBuffer(this.authentication) && Buffer.byteLength(this.authentication) !== 0) {
    var passwordHexDigest = crypto.createHash('sha512')
        .update(this.authentication)
        .update(this.security.username || '')
        .update(this.security.password || '')
        .digest('hex');
    ping.push(this.username, passwordHexDigest);
  } else {
    ping.push('', '');
  }
  return msgpack.encode(ping);
};

FluentSender.prototype._checkPong = function _checkPong(data) {
  // [
  //   'PONG',
  //   bool(authentication result),
  //   'reason if authentication failed',
  //   server_hostname,
  //   sha512_hex(salt + server_hostname + nonce + sharedkey)
  // ]
  this.internalLogger.info('Checking PONG...');
  var message = msgpack.decode(data);
  if (message.length !== 5) {
    return false;
  }
  if (message[0] !== 'PONG') {
    return { succeeded: false, message: 'Invalid format for PONG message' };
  }
  var _pong = message[0];
  var authResult = message[1];
  var reason = message[2];
  var hostname = message[3];
  var sharedKeyHexdigest = message[4];
  if (!authResult) {
    return { succeeded: false, message: 'Authentication failed: ' + reason };
  }
  if (hostname === this.security.clientHostname) {
    return { succeeded: false, message: 'Same hostname between input and output: invalid configuration' };
  }
  var clientsideHexdigest = crypto.createHash('sha512')
      .update(this.sharedKeySalt)
      .update(hostname)
      .update(this.sharedKeyNonce)
      .update(this.security.sharedKey)
      .digest('hex');
  if (sharedKeyHexdigest !== clientsideHexdigest) {
    return { succeeded: false, message: 'Sharedkey mismatch' };
  }
  return { succeeded: true };
};

FluentSender.prototype.toStream = function(options) {
  if (typeof options === 'string') {
    options = {label: options};
  } else {
    options = options || {};
  }
  var label = options.label;
  if (!label) {
    throw new Error('label is needed');
  }
  var defaultEncoding = options.encoding || 'UTF-8';
  var writable = new stream.Writable();
  var dataString = '';
  writable._write = (chunk, encoding, callback) => {
    var dataArray = chunk.toString(defaultEncoding).split(/\n/);
    var next = () => {
      if (dataArray.length) {
        dataString += dataArray.shift();
      }
      if (!dataArray.length) {
        process.nextTick(callback);
        return;
      }
      this.emit(label, { message: dataString }, (err) => {
        if (err) {
          this._handleEvent('error', err, callback);
          return;
        }
        dataString = '';
        next();
      });
    };
    next();
  };
  return writable;
};

module.exports = exports = {};
exports.FluentSender = FluentSender;
<|endoftext|>


<commit_before>(function () {
    'use strict';
    angular
        .module('app.form')
        .controller('indFormController', indFormController);

    function indFormController() {
        console.log('load indFormController');
        var vm = this;

        function setIndividualForm() {
            vm.resultsShown = null;
            vm.form = {
                premium: 0,
                deductible: 0,
                copay: 0,
                expenses: 0,
                income: 0,
                SS: 0,
                gross: 0,
                you: {
                    receiveSS: 0,
                    monthlySS: 0,
                    retirement: 0,
                    age: null
                },
                spouse: {
                    receiveSS: 0,
                    monthlySS: 0,
                    retirement: 0,
                    age: null
                }
            };
            vm.other = 0;
            vm.social = 0;
            vm.medicaid = 0;
            vm.medicare = 0;
            vm.filing = 0;
            vm.results = {
                you: {
                    annualSS: 0,
                    applicableSS: 0,
                    applicableRet: 0,
                    postApplicableRet: 0,
                    SSRetirementIncome: 0,
                    calcRetirement: 0,
                    healthcareCost: 0,
                    CCCost: 0,
                    savings: 0
                },
                spouse: {
                    annualSS: 0,
                    applicableSS: 0,
                    applicableRet: 0,
                    postApplicableRet: 0,
                    SSRetirementIncome: 0,
                    calcRetirement: 0,
                    healthcareCost: 0,
                    CCCost: 0,
                    savings: 0
                },
                joint: {
                    applicableSS: 0,
                    SSRetirementIncome: 0
                }

            };
            vm.result1 = 0;
            vm.result2 = 0;
            vm.result3 = 0;
            vm.difference = 0;
            vm.resultFiling = 0;
        }

        setIndividualForm();

        var baseCalculation = function baseCalculation() {
            var results = vm.form.premium * 12 + vm.form.deductible + vm.form.copay + vm.form.expenses;
            console.log('baseCalculation return', results);
            return results;
        };

        var indDeduction = function indDeduction(a, b) {
            return (12 * a) - 9000 + b;
        };

        var jointDeduction = function jointDeduction(a, b, c) {
            console.log('Check a', a);
            console.log('check b', b);
            console.log('check c', c);
            return (12 * a) - a / (c + a) * 12000 + b;
        };

        var singleCalculation = function singleCalculation() {
            var individualDeductionFinal = indDeduction(vm.form.you.monthlySS, vm.form.you.retirement);
            console.log('individualDeductionFinal', individualDeductionFinal);
            if (vm.other && vm.social && vm.form.you.age === 'under65') {
                if (individualDeductionFinal > 20000) {
                    individualDeductionFinal = 20000;
                }
                var deductionFinal = vm.form.gross - individualDeductionFinal;
                if(deductionFinal > 350000 - vm.form.income){
                    deductionFinal = 350000 - vm.form.income;
                }
                return (vm.form.income * 0.0333) + (deductionFinal * 0.10);
            }
            else if (vm.other && vm.social && vm.form.you.age === 'over65') {
                if (individualDeductionFinal > 24000) {
                    individualDeductionFinal = 24000;
                }
                return (vm.form.income * 0.0333) + (0.10 * (vm.form.gross - individualDeductionFinal));
            }
        };
        var jointCalculation = function jointCalculation() {
            var jointDeductionFinalYou = jointDeduction(vm.form.you.monthlySS, vm.form.you.retirement, vm.form.spouse.monthlySS);
            var jointDeductionFinalSpouse = jointDeduction(vm.form.spouse.monthlySS, vm.form.spouse.retirement, vm.form.you.monthlySS);
            console.log('jointDeductionFinalYou', jointDeductionFinalYou);
            console.log('jointDeductionFinalSpouse', jointDeductionFinalSpouse);
            if (vm.other && vm.social && !vm.form.you.age) {
                jointDeductionFinalYou = 0;
                vm.resultJointYou = jointDeductionFinalYou;
            }
            else if (vm.other && vm.social && vm.form.you.age === 'under65' && jointDeductionFinalYou > 20000) {
                jointDeductionFinalYou = 20000;
                //console.log('over 20000 for you', jointDeductionFinalYou);
                vm.resultJointYou = jointDeductionFinalYou;
            }
            else if (vm.other && vm.social && vm.form.you.age === 'over65' && jointDeductionFinalYou > 24000) {
                jointDeductionFinalYou = 24000;
                //console.log('over 24000 for you', jointDeductionFinalYou);
                vm.resultJointYou = jointDeductionFinalYou;
            }

            if (vm.other && vm.social && !vm.form.spouse.age) {
                jointDeductionFinalSpouse = 0;
                vm.resultJointSpouse = jointDeductionFinalSpouse;
            }
            else if (vm.other && vm.social && vm.form.spouse.age === 'under65' && jointDeductionFinalSpouse > 20000) {
                jointDeductionFinalSpouse = 20000;
                //console.log('over 20000 for spouse', jointDeductionFinalSpouse);
                vm.resultJointSpouse = jointDeductionFinalSpouse;
            }
            else if (vm.other && vm.social && vm.form.spouse.age === 'over65' && jointDeductionFinalSpouse > 24000) {
                jointDeductionFinalSpouse = 24000;
                //console.log('over 24000 for spouse', jointDeductionFinalSpouse);
                vm.resultJointSpouse = jointDeductionFinalSpouse;
            }
            //console.log('Check you final', jointDeductionFinalYou);
            //console.log('Check spouse final', jointDeductionFinalSpouse);
            var deductionFinal = vm.form.gross - jointDeductionFinalYou - jointDeductionFinalSpouse;
            if(deductionFinal > 450000 - vm.form.income){
                deductionFinal = 450000 - vm.form.income;
            }
            return (vm.form.income * 0.0333) + (0.10 * deductionFinal);
        };

        vm.calculate = function calculate() {
            vm.resultsShown = true;
            var sum1 = baseCalculation();
            vm.result1 = sum1.toFixed(2);
            if (!vm.result1) {
                vm.result1 = 'There has been an error calculating the result.  Please notify the webmaster';
            }

            var sum2 = 0;
            if (!vm.other && !vm.social) {
                sum2 = vm.form.income * 0.0333;
                vm.result2 = sum2.toFixed(2);
            }
            else if (vm.other && !vm.social) {
                var adjgross = 0;
                if(vm.form.gross > 350000 - vm.form.income) {
                    adjgross = 350000 - vm.form.income;
                }
                else {
                    adjgross = vm.form.gross;
                }
                sum2 = (vm.form.income * 0.0333) + (0.10 * adjgross);
                vm.result2 = sum2.toFixed(2);
            }
            else if (vm.other && vm.social && vm.filing === 'single') {
                sum2 = singleCalculation();
                if (sum2 < 0) {
                    sum2 = 0;
                }
                vm.result2 = sum2.toFixed(2);
            }
            else if (vm.other && vm.social && vm.filing === 'joint') {
                sum2 = jointCalculation();
                if (sum2 < 0) {
                    sum2 = 0;
                }
                vm.result2 = sum2.toFixed(2);
            }
            if (!vm.result2) {
                vm.result2 = 'There has been an error calculating the result.  Please notify the webmaster';
            }

            var sum3 = vm.result1 - vm.result2;
            vm.difference = sum3.toFixed(2);
            if (!vm.difference) {
                vm.difference = 'There has been an error calculating the result.  Please notify the webmaster';
            }
        };

        vm.clear = function clear() {
            setIndividualForm();
        };
    }
})();<commit_msg>missed a deductionFinal<commit_after>(function () {
    'use strict';
    angular
        .module('app.form')
        .controller('indFormController', indFormController);

    function indFormController() {
        console.log('load indFormController');
        var vm = this;

        function setIndividualForm() {
            vm.resultsShown = null;
            vm.form = {
                premium: 0,
                deductible: 0,
                copay: 0,
                expenses: 0,
                income: 0,
                SS: 0,
                gross: 0,
                you: {
                    receiveSS: 0,
                    monthlySS: 0,
                    retirement: 0,
                    age: null
                },
                spouse: {
                    receiveSS: 0,
                    monthlySS: 0,
                    retirement: 0,
                    age: null
                }
            };
            vm.other = 0;
            vm.social = 0;
            vm.medicaid = 0;
            vm.medicare = 0;
            vm.filing = 0;
            vm.results = {
                you: {
                    annualSS: 0,
                    applicableSS: 0,
                    applicableRet: 0,
                    postApplicableRet: 0,
                    SSRetirementIncome: 0,
                    calcRetirement: 0,
                    healthcareCost: 0,
                    CCCost: 0,
                    savings: 0
                },
                spouse: {
                    annualSS: 0,
                    applicableSS: 0,
                    applicableRet: 0,
                    postApplicableRet: 0,
                    SSRetirementIncome: 0,
                    calcRetirement: 0,
                    healthcareCost: 0,
                    CCCost: 0,
                    savings: 0
                },
                joint: {
                    applicableSS: 0,
                    SSRetirementIncome: 0
                }

            };
            vm.result1 = 0;
            vm.result2 = 0;
            vm.result3 = 0;
            vm.difference = 0;
            vm.resultFiling = 0;
        }

        setIndividualForm();

        var baseCalculation = function baseCalculation() {
            var results = vm.form.premium * 12 + vm.form.deductible + vm.form.copay + vm.form.expenses;
            console.log('baseCalculation return', results);
            return results;
        };

        var indDeduction = function indDeduction(a, b) {
            return (12 * a) - 9000 + b;
        };

        var jointDeduction = function jointDeduction(a, b, c) {
            console.log('Check a', a);
            console.log('check b', b);
            console.log('check c', c);
            return (12 * a) - a / (c + a) * 12000 + b;
        };

        var singleCalculation = function singleCalculation() {
            var individualDeductionFinal = indDeduction(vm.form.you.monthlySS, vm.form.you.retirement);
            console.log('individualDeductionFinal', individualDeductionFinal);
            if (vm.other && vm.social && vm.form.you.age === 'under65') {
                if (individualDeductionFinal > 20000) {
                    individualDeductionFinal = 20000;
                }
                var deductionFinal = vm.form.gross - individualDeductionFinal;
                if(deductionFinal > 350000 - vm.form.income){
                    deductionFinal = 350000 - vm.form.income;
                }
                return (vm.form.income * 0.0333) + (deductionFinal * 0.10);
            }
            else if (vm.other && vm.social && vm.form.you.age === 'over65') {
                if (individualDeductionFinal > 24000) {
                    individualDeductionFinal = 24000;
                }
                var deductionFinal = vm.form.gross - individualDeductionFinal;
                if(deductionFinal > 350000 - vm.form.income){
                    deductionFinal = 350000 - vm.form.income;
                }
                return (vm.form.income * 0.0333) + (deductionFinal * 0.10);
            }
        };
        var jointCalculation = function jointCalculation() {
            var jointDeductionFinalYou = jointDeduction(vm.form.you.monthlySS, vm.form.you.retirement, vm.form.spouse.monthlySS);
            var jointDeductionFinalSpouse = jointDeduction(vm.form.spouse.monthlySS, vm.form.spouse.retirement, vm.form.you.monthlySS);
            console.log('jointDeductionFinalYou', jointDeductionFinalYou);
            console.log('jointDeductionFinalSpouse', jointDeductionFinalSpouse);
            if (vm.other && vm.social && !vm.form.you.age) {
                jointDeductionFinalYou = 0;
                vm.resultJointYou = jointDeductionFinalYou;
            }
            else if (vm.other && vm.social && vm.form.you.age === 'under65' && jointDeductionFinalYou > 20000) {
                jointDeductionFinalYou = 20000;
                //console.log('over 20000 for you', jointDeductionFinalYou);
                vm.resultJointYou = jointDeductionFinalYou;
            }
            else if (vm.other && vm.social && vm.form.you.age === 'over65' && jointDeductionFinalYou > 24000) {
                jointDeductionFinalYou = 24000;
                //console.log('over 24000 for you', jointDeductionFinalYou);
                vm.resultJointYou = jointDeductionFinalYou;
            }

            if (vm.other && vm.social && !vm.form.spouse.age) {
                jointDeductionFinalSpouse = 0;
                vm.resultJointSpouse = jointDeductionFinalSpouse;
            }
            else if (vm.other && vm.social && vm.form.spouse.age === 'under65' && jointDeductionFinalSpouse > 20000) {
                jointDeductionFinalSpouse = 20000;
                //console.log('over 20000 for spouse', jointDeductionFinalSpouse);
                vm.resultJointSpouse = jointDeductionFinalSpouse;
            }
            else if (vm.other && vm.social && vm.form.spouse.age === 'over65' && jointDeductionFinalSpouse > 24000) {
                jointDeductionFinalSpouse = 24000;
                //console.log('over 24000 for spouse', jointDeductionFinalSpouse);
                vm.resultJointSpouse = jointDeductionFinalSpouse;
            }
            //console.log('Check you final', jointDeductionFinalYou);
            //console.log('Check spouse final', jointDeductionFinalSpouse);
            var deductionFinal = vm.form.gross - jointDeductionFinalYou - jointDeductionFinalSpouse;
            if(deductionFinal > 450000 - vm.form.income){
                deductionFinal = 450000 - vm.form.income;
            }
            return (vm.form.income * 0.0333) + (0.10 * deductionFinal);
        };

        vm.calculate = function calculate() {
            vm.resultsShown = true;
            var sum1 = baseCalculation();
            vm.result1 = sum1.toFixed(2);
            if (!vm.result1) {
                vm.result1 = 'There has been an error calculating the result.  Please notify the webmaster';
            }

            var sum2 = 0;
            if (!vm.other && !vm.social) {
                sum2 = vm.form.income * 0.0333;
                vm.result2 = sum2.toFixed(2);
            }
            else if (vm.other && !vm.social) {
                var adjgross = 0;
                if(vm.form.gross > 350000 - vm.form.income) {
                    adjgross = 350000 - vm.form.income;
                }
                else {
                    adjgross = vm.form.gross;
                }
                sum2 = (vm.form.income * 0.0333) + (0.10 * adjgross);
                vm.result2 = sum2.toFixed(2);
            }
            else if (vm.other && vm.social && vm.filing === 'single') {
                sum2 = singleCalculation();
                if (sum2 < 0) {
                    sum2 = 0;
                }
                vm.result2 = sum2.toFixed(2);
            }
            else if (vm.other && vm.social && vm.filing === 'joint') {
                sum2 = jointCalculation();
                if (sum2 < 0) {
                    sum2 = 0;
                }
                vm.result2 = sum2.toFixed(2);
            }
            if (!vm.result2) {
                vm.result2 = 'There has been an error calculating the result.  Please notify the webmaster';
            }

            var sum3 = vm.result1 - vm.result2;
            vm.difference = sum3.toFixed(2);
            if (!vm.difference) {
                vm.difference = 'There has been an error calculating the result.  Please notify the webmaster';
            }
        };

        vm.clear = function clear() {
            setIndividualForm();
        };
    }
})();<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var ws = require('websocket.io')
  , qs = require('querystring')
  , parse = require('url').parse
  , readFileSync = require('fs').readFileSync
  , transports = require('./transports')
  , debug = require('debug')('engine')
  , EventEmitter = require('events').EventEmitter
  , Socket = require('./socket')

/**
 * Module exports.
 */

module.exports = Server;

/**
 * Server constructor.
 *
 * @param {Object} options
 * @api public
 */

function Server (opts) {
  this.clients = {};
  this.clientsCount = 0;

  opts = opts || {};
  this.pingTimeout = opts.pingTimeout || 10000;
  this.pingInterval = opts.pingInterval || 30000;
  this.transports = opts.transports || Object.keys(transports);
  this.allowUpgrades = false !== opts.allowUpgrades;

  // initialize websocket server
  if (~this.transports.indexOf('websocket')) {
    this.ws = new ws.Server;
    this.ws.on('connection', this.onWebSocket.bind(this));
  }
};

/**
 * Inherits from EventEmitter.
 */

Server.prototype.__proto__ = EventEmitter.prototype;

/**
 * Hash of open clients.
 *
 * @api public
 */

Server.prototype.clients;

/**
 * Returns a list of available transports for upgrade given a certain transport.
 *
 * @return {Array}
 * @api public
 */

Server.prototype.upgrades = function (transport) {
  if (!this.allowUpgrades) return [];
  return transports[transport].upgradesTo || [];
};

/**
 * Verifies a request.
 *
 * @param {http.ServerRequest}
 * @return {Boolean} whether the request is valid
 * @api private
 */

Server.prototype.verify = function (req) {
  // transport check
  var transport = req.query.transport;
  if (!~this.transports.indexOf(transport)) {
    debug('unknown transport "%s"', transport);
    return false;
  }

  // sid check
  if (req.query.sid) {
    return this.clients.hasOwnProperty(req.query.sid);
  }

  return true;
};

/**
 * Prepares a request by processing the query string.
 *
 * @api private
 */

Server.prototype.prepare = function (req) {
  // try to leverage pre-existing `req.query` (e.g: from connect)
  if (!req.query) {
    req.query = ~req.url.indexOf('?')
      ? qs.parse(parse(req.url).query)
      : {};
  }
};

/**
 * Generates an id.
 *
 * @api private
 */

Server.prototype.id = function () {
  return String(Math.random() * Math.random()).substr(3);
};

/**
 * Closes all clients.
 *
 * @api public
 */

Server.prototype.close = function () {
  debug('closing all open clients');
  for (var i in this.clients) {
    this.clients[i].close();
  }
  return this;
};

/**
 * Handles an Engine.IO HTTP request.
 *
 * @param {http.ServerRequest} request
 * @param {http.ServerResponse|http.OutgoingMessage} response
 * @api public
 */

Server.prototype.handleRequest = function (req, res) {
  this.prepare(req);
  req.res = res;

  if (!this.verify(req)) {
    res.writeHead(500);
    res.end();
    return;
  }

  if (req.query.sid) {
    this.clients[req.query.sid].transport().onRequest(req);
  } else {
    this.handshake(req);
  }
};

/**
 * Handshakes a new client.
 *
 * @api private
 */

Server.prototype.handshake = function (req) {
  // generate sid
  var id = this.id()
    , socket = new Socket(id, this, new transports[req.query.transport](req))
    , self = this

  socket.once('open', function () {
    // debug: handshake completed for client %d, id
    self.clients[id] = socket;
    self.emit('connection', socket);
  });
};

/**
 * Handles an Engine.IO HTTP Upgrade.
 *
 * @api public
 */

Server.prototype.handleUpgrade = function (req, socket, head) {
  this.prepare(req);

  if (!this.verify(req)) {
    socket.end();
    return;
  }

  // delegate to websocket.io
  this.ws.handleUpgrade(req, socket, head);
};

/**
 * Called upon a ws.io connection.
 *
 * @param {wsio.Socket} websocket
 * @api private
 */

Server.prototype.onWebSocket = function (socket) {
  var req = socket.req
    , id = req.query.sid

  // debug: upgrading existing client to websocket
  if (this.clients[id].upgraded) {
    // debug: transport had already been upgraded
    socket.close();
  } else {
    this.clients[id].upgrade(new transports[req.query.transport](socket));
  }
};

/**
 * Handles a regular connection. Required that we parse the first few bytes
 * of each stream for flashsocket policy requests.
 */

var policy = readFileSync(__dirname + '/transports/flashsocket.xml');

Server.prototype.handleSocket = function (socket) {
  var chunks = ''
    , buffer = false

  socket.on('data', function onData (data) {
    if (!buffer && 60 == data[0]) {
      buffer = true;
    } else {
      socket.removeListener('data', onData);
      return;
    }

    if (chunks.length < 23) {
      chunks += data.toString('ascii');
    }

    if (chunks.length >= 23) {
      if ('<policy-file-request/>\0' == chunks.substr(0, 23)) {
        socket.end(policy);
      } else {
        chunks = null;
        socket.removeListener('data', onData);
      }
    }
  });
};
<commit_msg>Added debug to handleRequest<commit_after>
/**
 * Module dependencies.
 */

var ws = require('websocket.io')
  , qs = require('querystring')
  , parse = require('url').parse
  , readFileSync = require('fs').readFileSync
  , transports = require('./transports')
  , debug = require('debug')('engine')
  , EventEmitter = require('events').EventEmitter
  , Socket = require('./socket')

/**
 * Module exports.
 */

module.exports = Server;

/**
 * Server constructor.
 *
 * @param {Object} options
 * @api public
 */

function Server (opts) {
  this.clients = {};
  this.clientsCount = 0;

  opts = opts || {};
  this.pingTimeout = opts.pingTimeout || 10000;
  this.pingInterval = opts.pingInterval || 30000;
  this.transports = opts.transports || Object.keys(transports);
  this.allowUpgrades = false !== opts.allowUpgrades;

  // initialize websocket server
  if (~this.transports.indexOf('websocket')) {
    this.ws = new ws.Server;
    this.ws.on('connection', this.onWebSocket.bind(this));
  }
};

/**
 * Inherits from EventEmitter.
 */

Server.prototype.__proto__ = EventEmitter.prototype;

/**
 * Hash of open clients.
 *
 * @api public
 */

Server.prototype.clients;

/**
 * Returns a list of available transports for upgrade given a certain transport.
 *
 * @return {Array}
 * @api public
 */

Server.prototype.upgrades = function (transport) {
  if (!this.allowUpgrades) return [];
  return transports[transport].upgradesTo || [];
};

/**
 * Verifies a request.
 *
 * @param {http.ServerRequest}
 * @return {Boolean} whether the request is valid
 * @api private
 */

Server.prototype.verify = function (req) {
  // transport check
  var transport = req.query.transport;
  if (!~this.transports.indexOf(transport)) {
    debug('unknown transport "%s"', transport);
    return false;
  }

  // sid check
  if (req.query.sid) {
    return this.clients.hasOwnProperty(req.query.sid);
  }

  return true;
};

/**
 * Prepares a request by processing the query string.
 *
 * @api private
 */

Server.prototype.prepare = function (req) {
  // try to leverage pre-existing `req.query` (e.g: from connect)
  if (!req.query) {
    req.query = ~req.url.indexOf('?')
      ? qs.parse(parse(req.url).query)
      : {};
  }
};

/**
 * Generates an id.
 *
 * @api private
 */

Server.prototype.id = function () {
  return String(Math.random() * Math.random()).substr(3);
};

/**
 * Closes all clients.
 *
 * @api public
 */

Server.prototype.close = function () {
  debug('closing all open clients');
  for (var i in this.clients) {
    this.clients[i].close();
  }
  return this;
};

/**
 * Handles an Engine.IO HTTP request.
 *
 * @param {http.ServerRequest} request
 * @param {http.ServerResponse|http.OutgoingMessage} response
 * @api public
 */

Server.prototype.handleRequest = function (req, res) {
  debug('handling http request "%s"', req.url);
  this.prepare(req);
  req.res = res;

  if (!this.verify(req)) {
    res.writeHead(500);
    res.end();
    return;
  }

  if (req.query.sid) {
    this.clients[req.query.sid].transport().onRequest(req);
  } else {
    this.handshake(req);
  }
};

/**
 * Handshakes a new client.
 *
 * @api private
 */

Server.prototype.handshake = function (req) {
  // generate sid
  var id = this.id()
    , socket = new Socket(id, this, new transports[req.query.transport](req))
    , self = this

  socket.once('open', function () {
    // debug: handshake completed for client %d, id
    self.clients[id] = socket;
    self.emit('connection', socket);
  });
};

/**
 * Handles an Engine.IO HTTP Upgrade.
 *
 * @api public
 */

Server.prototype.handleUpgrade = function (req, socket, head) {
  this.prepare(req);

  if (!this.verify(req)) {
    socket.end();
    return;
  }

  // delegate to websocket.io
  this.ws.handleUpgrade(req, socket, head);
};

/**
 * Called upon a ws.io connection.
 *
 * @param {wsio.Socket} websocket
 * @api private
 */

Server.prototype.onWebSocket = function (socket) {
  var req = socket.req
    , id = req.query.sid

  // debug: upgrading existing client to websocket
  if (this.clients[id].upgraded) {
    // debug: transport had already been upgraded
    socket.close();
  } else {
    this.clients[id].upgrade(new transports[req.query.transport](socket));
  }
};

/**
 * Handles a regular connection. Required that we parse the first few bytes
 * of each stream for flashsocket policy requests.
 */

var policy = readFileSync(__dirname + '/transports/flashsocket.xml');

Server.prototype.handleSocket = function (socket) {
  var chunks = ''
    , buffer = false

  socket.on('data', function onData (data) {
    if (!buffer && 60 == data[0]) {
      buffer = true;
    } else {
      socket.removeListener('data', onData);
      return;
    }

    if (chunks.length < 23) {
      chunks += data.toString('ascii');
    }

    if (chunks.length >= 23) {
      if ('<policy-file-request/>\0' == chunks.substr(0, 23)) {
        socket.end(policy);
      } else {
        chunks = null;
        socket.removeListener('data', onData);
      }
    }
  });
};
<|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) {
  var pk = Bitcore.PrivateKey.fromString(privKey);
  return Bitcore.crypto.Hash.sha256(pk.toBuffer()).slice(0, 16).toString('base64');
};

WalletUtils.signTxp = function(txp, xPrivKey) {
  var self = this;

  //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 = 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);

  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) {
  return xPubKey.substr(0, 4) == 'tpub' ? 'testnet' : 'livenet';
};

WalletUtils.Bitcore = Bitcore;

module.exports = WalletUtils;
<commit_msg>extract tx creation on a separate method<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) {
  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);

  return t;
};

WalletUtils.signTxp = function(txp, xPrivKey) {
  var self = this;

  //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) {
  return xPubKey.substr(0, 4) == 'tpub' ? 'testnet' : 'livenet';
};

WalletUtils.Bitcore = Bitcore;

module.exports = WalletUtils;
<|endoftext|>