<commit_before>// Copyright 2011 Timothy J Fontaine <tjfontaine@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE

'use strict';

var fs = require('fs'),
    EventEmitter = require('events').EventEmitter,
    net = require('net'),
    os = require('os'),
    util = require('util'),
    Cache = require('./cache').Cache,
    consts = require('./consts'),
    path = require('./path'),
    utils = require('./utils');

var A = consts.NAME_TO_QTYPE.A,
    AAAA = consts.NAME_TO_QTYPE.AAAA,
    PTR = consts.NAME_TO_QTYPE.PTR;

var Platform = function() {
  this._nsReady = false;
  this._hostsReady = false;

  Object.defineProperty(this, 'ready', {
    get: function() {
      return this._nsReady && this._hostsReady;
    }
  });

  this._watches = {};

  Object.defineProperty(this, 'watching', {
    get: function() {
      return Object.keys(this._watches).length > 0;
    },
    set: function(value) {
      if (value)
        this._watchFiles();
      else {
        for (k in this._watches) {
          this._watches[k].close();
          delete this._watches[k];
        }
      }
    }
  });

  this.hosts = new Cache();

  this._initNameServers();
  this._initHostsFile();
  this._populate();

  this.cache = new Cache();
};
util.inherits(Platform, EventEmitter);

Platform.prototype.reload = function() {
  this.emit('unready');
  this._initNameServers();
  this._initHostsFile();
  this._populate();
};

Platform.prototype._initNameServers = function() {
  this._nsReady = false;
  this.name_servers = [];
  this.search_path = [];
  this.timeout = 5 * 1000;
  this.attempts = 5;
  this.edns = false;
};

Platform.prototype._initHostsFile = function() {
  this._hostsReady = false;
  this.hosts.purge();
};

Platform.prototype._populate = function() {
  var hostsfile, self = this;

  switch (os.platform()) {
    case 'win32':
      this.name_servers = [
        {
          address: '8.8.8.8',
          port: 53
        },
        {
          address: '8.8.4.4.',
          port: 53
        }
      ];
      hosts = path.join(process.env.SystemRoot,
                        '\\System32\\drivers\\etc\\hosts');
      break;
    default:
      this.parseResolv();
      hostsfile = '/etc/hosts';
      break;
  }

  this._parseHosts(hostsfile);
};

Platform.prototype._watchFiles = function() {
  var self = this, watchParams;

  watchParams = {persistent: false};

  switch (os.platform()) {
    case 'win32':
      //TODO XXX FIXME: it would be nice if this existed
      break;
    default:
      this._watches.resolve = fs.watch('/etc/resolv.conf', watchParams,
          function(event, filename) {
            if (event === 'change') {
              self.emit('unready');
              self._initNameServers();
              self.parseResolv();
            }
          });
      this._watches.hosts = fs.watch('/etc/hosts', watchParams,
          function(event, filename) {
            if (event === 'change') {
              self.emit('unready');
              self._initHostsFile();
              self._parseHosts(hostsfile);
            }
          });
      break;
  }
};

Platform.prototype._checkReady = function() {
  if (this.ready) {
    this.emit('ready');
  }
};

Platform.prototype.parseResolv = function() {
  var self = this;

  fs.readFile('/etc/resolv.conf', 'ascii', function(err, file) {
    if (err) {
      throw err;
    }

    file.split(/\n/).forEach(function(line) {
      var i, parts, subparts;
      line = line.replace(/^\s+|\s+$/g, '');
      if (!line.match(/^#/)) {
        parts = line.split(/\s+/);
        switch (parts[0]) {
          case 'nameserver':
            self.name_servers.push({
              address: parts[1],
              port: 53
            });
            break;
          case 'domain':
            self.search_path = [parts[1]];
            break;
          case 'search':
            self.search_path = [parts.slice(1)];
            break;
          case 'options':
            for (i = 1; i < parts.length; i++) {
              subparts = parts[i].split(/:/);
              switch (subparts[0]) {
                case 'timeout':
                  self.timeout = parseInt(subparts[1], 10) * 1000;
                  break;
                case 'attempts':
                  self.attempts = parseInt(subparts[1], 10);
                  break;
                case 'edns0':
                  self.edns = true;
                  break;
              }
            }
            break;
        }
      }
    });

    self._nsReady = true;
    self._checkReady();
  });
};

Platform.prototype._parseHosts = function(hostsfile) {
  var self = this;

  fs.readFile(hostsfile, 'ascii', function(err, file) {
    if (err) {
      throw err;
    }

    file.split(/\n/).forEach(function(line) {
      var i, parts, ip, revip, kind;
      line = line.replace(/^\s+|\s+$/g, '');
      if (!line.match(/^#/)) {
        parts = line.split(/\s+/);
        ip = parts[0];
        parts = parts.slice(1);
        kind = net.isIP(ip);

        if (parts.length && ip && kind) {
          /* IP -> Domain */
          revip = utils.reverseIP(ip);
          parts.forEach(function(domain) {
            self.hosts._store.set({
              type: PTR,
              name: revip,
              data: domain,
              ttl: false
            });
          });

          /* Domain -> IP */
          parts.forEach(function(domain) {
            self.hosts._store.set({
              type: kind === 4 ? A : AAAA,
              name: domain.toLowerCase(),
              address: ip,
              ttl: false
            });
          });
        }
      }
    });

    self._hostsReady = true;
    self._checkReady();
  });
};

module.exports = new Platform();
<commit_msg>what were you smoking, it's global path re #24<commit_after>// Copyright 2011 Timothy J Fontaine <tjfontaine@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE

'use strict';

var fs = require('fs'),
    EventEmitter = require('events').EventEmitter,
    net = require('net'),
    os = require('os'),
    util = require('util'),
    Cache = require('./cache').Cache,
    consts = require('./consts'),
    path = require('path'),
    utils = require('./utils');

var A = consts.NAME_TO_QTYPE.A,
    AAAA = consts.NAME_TO_QTYPE.AAAA,
    PTR = consts.NAME_TO_QTYPE.PTR;

var Platform = function() {
  this._nsReady = false;
  this._hostsReady = false;

  Object.defineProperty(this, 'ready', {
    get: function() {
      return this._nsReady && this._hostsReady;
    }
  });

  this._watches = {};

  Object.defineProperty(this, 'watching', {
    get: function() {
      return Object.keys(this._watches).length > 0;
    },
    set: function(value) {
      if (value)
        this._watchFiles();
      else {
        for (k in this._watches) {
          this._watches[k].close();
          delete this._watches[k];
        }
      }
    }
  });

  this.hosts = new Cache();

  this._initNameServers();
  this._initHostsFile();
  this._populate();

  this.cache = new Cache();
};
util.inherits(Platform, EventEmitter);

Platform.prototype.reload = function() {
  this.emit('unready');
  this._initNameServers();
  this._initHostsFile();
  this._populate();
};

Platform.prototype._initNameServers = function() {
  this._nsReady = false;
  this.name_servers = [];
  this.search_path = [];
  this.timeout = 5 * 1000;
  this.attempts = 5;
  this.edns = false;
};

Platform.prototype._initHostsFile = function() {
  this._hostsReady = false;
  this.hosts.purge();
};

Platform.prototype._populate = function() {
  var hostsfile, self = this;

  switch (os.platform()) {
    case 'win32':
      this.name_servers = [
        {
          address: '8.8.8.8',
          port: 53
        },
        {
          address: '8.8.4.4.',
          port: 53
        }
      ];
      hosts = path.join(process.env.SystemRoot,
                        '\\System32\\drivers\\etc\\hosts');
      break;
    default:
      this.parseResolv();
      hostsfile = '/etc/hosts';
      break;
  }

  this._parseHosts(hostsfile);
};

Platform.prototype._watchFiles = function() {
  var self = this, watchParams;

  watchParams = {persistent: false};

  switch (os.platform()) {
    case 'win32':
      //TODO XXX FIXME: it would be nice if this existed
      break;
    default:
      this._watches.resolve = fs.watch('/etc/resolv.conf', watchParams,
          function(event, filename) {
            if (event === 'change') {
              self.emit('unready');
              self._initNameServers();
              self.parseResolv();
            }
          });
      this._watches.hosts = fs.watch('/etc/hosts', watchParams,
          function(event, filename) {
            if (event === 'change') {
              self.emit('unready');
              self._initHostsFile();
              self._parseHosts(hostsfile);
            }
          });
      break;
  }
};

Platform.prototype._checkReady = function() {
  if (this.ready) {
    this.emit('ready');
  }
};

Platform.prototype.parseResolv = function() {
  var self = this;

  fs.readFile('/etc/resolv.conf', 'ascii', function(err, file) {
    if (err) {
      throw err;
    }

    file.split(/\n/).forEach(function(line) {
      var i, parts, subparts;
      line = line.replace(/^\s+|\s+$/g, '');
      if (!line.match(/^#/)) {
        parts = line.split(/\s+/);
        switch (parts[0]) {
          case 'nameserver':
            self.name_servers.push({
              address: parts[1],
              port: 53
            });
            break;
          case 'domain':
            self.search_path = [parts[1]];
            break;
          case 'search':
            self.search_path = [parts.slice(1)];
            break;
          case 'options':
            for (i = 1; i < parts.length; i++) {
              subparts = parts[i].split(/:/);
              switch (subparts[0]) {
                case 'timeout':
                  self.timeout = parseInt(subparts[1], 10) * 1000;
                  break;
                case 'attempts':
                  self.attempts = parseInt(subparts[1], 10);
                  break;
                case 'edns0':
                  self.edns = true;
                  break;
              }
            }
            break;
        }
      }
    });

    self._nsReady = true;
    self._checkReady();
  });
};

Platform.prototype._parseHosts = function(hostsfile) {
  var self = this;

  fs.readFile(hostsfile, 'ascii', function(err, file) {
    if (err) {
      throw err;
    }

    file.split(/\n/).forEach(function(line) {
      var i, parts, ip, revip, kind;
      line = line.replace(/^\s+|\s+$/g, '');
      if (!line.match(/^#/)) {
        parts = line.split(/\s+/);
        ip = parts[0];
        parts = parts.slice(1);
        kind = net.isIP(ip);

        if (parts.length && ip && kind) {
          /* IP -> Domain */
          revip = utils.reverseIP(ip);
          parts.forEach(function(domain) {
            self.hosts._store.set({
              type: PTR,
              name: revip,
              data: domain,
              ttl: false
            });
          });

          /* Domain -> IP */
          parts.forEach(function(domain) {
            self.hosts._store.set({
              type: kind === 4 ? A : AAAA,
              name: domain.toLowerCase(),
              address: ip,
              ttl: false
            });
          });
        }
      }
    });

    self._hostsReady = true;
    self._checkReady();
  });
};

module.exports = new Platform();
<|endoftext|>


<commit_before>//     (c) 2012 Airbnb, Inc.
//
//     polyglot.js may be freely distributed under the terms of the BSD
//     license. For all licensing information, details, and documention:
//     http://airbnb.github.com/polyglot.js
//
//
// Polyglot.js is an I18n helper library written in JavaScript, made to
// work both in the browser and in Node. It provides a simple solution for
// interpolation and pluralization, based off of Airbnb's
// experience adding I18n functionality to its Backbone.js and Node apps.
//
// Polylglot is agnostic to your translation backend. It doesn't perform any
// translation; it simply gives you a way to manage translated phrases from
// your client- or server-side JavaScript application.
//

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([], function() {
      return factory(root);
    });
  } else if (typeof exports === 'object') {
    module.exports = factory(root);
  } else {
    root.Polyglot = factory(root);
  }
}(this, function(root) {
  'use strict';

  // ### Polyglot class constructor
  function Polyglot(options) {
    options = options || {};
    this.phrases = {};
    this.extend(options.phrases || {});
    this.currentLocale = options.locale || 'en';
    this.allowMissing = !!options.allowMissing;
    this.warn = options.warn || warn;
  }

  // ### Version
  Polyglot.VERSION = '0.4.3';

  // ### polyglot.locale([locale])
  //
  // Get or set locale. Internally, Polyglot only uses locale for pluralization.
  Polyglot.prototype.locale = function(newLocale) {
    if (newLocale) this.currentLocale = newLocale;
    return this.currentLocale;
  };

  // ### polyglot.extend(phrases)
  //
  // Use `extend` to tell Polyglot how to translate a given key.
  //
  //     polyglot.extend({
  //       "hello": "Hello",
  //       "hello_name": "Hello, %{name}"
  //     });
  //
  // The key can be any string.  Feel free to call `extend` multiple times;
  // it will override any phrases with the same key, but leave existing phrases
  // untouched.
  //
  // It is also possible to pass nested phrase objects, which get flattened
  // into an object with the nested keys concatenated using dot notation.
  //
  //     polyglot.extend({
  //       "nav": {
  //         "hello": "Hello",
  //         "hello_name": "Hello, %{name}",
  //         "sidebar": {
  //           "welcome": "Welcome"
  //         }
  //       }
  //     });
  //
  //     console.log(polyglot.phrases);
  //     // {
  //     //   'nav.hello': 'Hello',
  //     //   'nav.hello_name': 'Hello, %{name}',
  //     //   'nav.sidebar.welcome': 'Welcome'
  //     // }
  //
  // `extend` accepts an optional second argument, `prefix`, which can be used
  // to prefix every key in the phrases object with some string, using dot
  // notation.
  //
  //     polyglot.extend({
  //       "hello": "Hello",
  //       "hello_name": "Hello, %{name}"
  //     }, "nav");
  //
  //     console.log(polyglot.phrases);
  //     // {
  //     //   'nav.hello': 'Hello',
  //     //   'nav.hello_name': 'Hello, %{name}'
  //     // }
  //
  // This feature is used internally to support nested phrase objects.
  Polyglot.prototype.extend = function(morePhrases, prefix) {
    var phrase;

    for (var key in morePhrases) {
      if (morePhrases.hasOwnProperty(key)) {
        phrase = morePhrases[key];
        if (prefix) key = prefix + '.' + key;
        if (typeof phrase === 'object') {
          this.extend(phrase, key);
        } else {
          this.phrases[key] = phrase;
        }
      }
    }
  };

  // ### polyglot.unset(phrases)
  // Use `unset` to selectively remove keys from a polyglot instance.
  //
  //     polyglot.unset("some_key");
  //     polyglot.unset({
  //       "hello": "Hello",
  //       "hello_name": "Hello, %{name}"
  //     });
  //
  // The unset method can take either a string (for the key), or an object hash with
  // the keys that you would like to unset.
  Polyglot.prototype.unset = function(morePhrases, prefix) {
    var phrase;

    if (typeof morePhrases === 'string') {
      delete this.phrases[morePhrases];
    } else {
      for (var key in morePhrases) {
        if (morePhrases.hasOwnProperty(key)) {
          phrase = morePhrases[key];
          if (prefix) key = prefix + '.' + key;
          if (typeof phrase === 'object') {
            this.unset(phrase, key);
          } else {
            delete this.phrases[key];
          }
        }
      }
    }
  };

  // ### polyglot.clear()
  //
  // Clears all phrases. Useful for special cases, such as freeing
  // up memory if you have lots of phrases but no longer need to
  // perform any translation. Also used internally by `replace`.
  Polyglot.prototype.clear = function() {
    this.phrases = {};
  };

  // ### polyglot.replace(phrases)
  //
  // Completely replace the existing phrases with a new set of phrases.
  // Normally, just use `extend` to add more phrases, but under certain
  // circumstances, you may want to make sure no old phrases are lying around.
  Polyglot.prototype.replace = function(newPhrases) {
    this.clear();
    this.extend(newPhrases);
  };

  // ### polyglot.t(key, options)
  //
  // The most-used method. Provide a key, and `t` will return the
  // phrase.
  //
  //     polyglot.t("hello");
  //     => "Hello"
  //
  // The phrase value is provided first by a call to `polyglot.extend()` or
  // `polyglot.replace()`.
  //
  // Pass in an object as the second argument to perform interpolation.
  //
  //     polyglot.t("hello_name", {name: "Spike"});
  //     => "Hello, Spike"
  //
  // If you like, you can provide a default value in case the phrase is missing.
  // Use the special option key "_" to specify a default.
  //
  //     polyglot.t("i_like_to_write_in_language", {
  //       _: "I like to write in %{language}.",
  //       language: "JavaScript"
  //     });
  //     => "I like to write in JavaScript."
  //
  Polyglot.prototype.t = function(key, options) {
    var phrase, result;
    options = options == null ? {} : options;
    // allow number as a pluralization shortcut
    if (typeof options === 'number') {
      options = {smart_count: options};
    }
    if (typeof this.phrases[key] === 'string') {
      phrase = this.phrases[key];
    } else if (typeof options._ === 'string') {
      phrase = options._;
    } else if (this.allowMissing) {
      phrase = key;
    } else {
      this.warn('Missing translation for key: "'+key+'"');
      result = key;
    }
    if (typeof phrase === 'string') {
      options = clone(options);
      result = choosePluralForm(phrase, this.currentLocale, options.smart_count);
      result = interpolate(result, options);
    }
    return result;
  };

  // ### polyglot.has(key)
  //
  // Check if polyglot has a translation for given key
  Polyglot.prototype.has = function(key) {
    return key in this.phrases;
  };

  // #### Pluralization methods
  // The string that separates the different phrase possibilities.
  var delimeter = '||||';

  // Mapping from pluralization group plural logic.
  var pluralTypes = {
    chinese:   function(n) { return 0; },
    german:    function(n) { return n !== 1 ? 1 : 0; },
    french:    function(n) { return n > 1 ? 1 : 0; },
    russian:   function(n) { return n % 10 === 1 && n % 100 !== 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2; },
    czech:     function(n) { return (n === 1) ? 0 : (n >= 2 && n <= 4) ? 1 : 2; },
    polish:    function(n) { return (n === 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); },
    icelandic: function(n) { return (n % 10 !== 1 || n % 100 === 11) ? 1 : 0; }
  };

  // Mapping from pluralization group to individual locales.
  var pluralTypeToLanguages = {
    chinese:   ['fa', 'id', 'ja', 'ko', 'lo', 'ms', 'th', 'tr', 'zh'],
    german:    ['da', 'de', 'en', 'es', 'fi', 'el', 'he', 'hu', 'it', 'nl', 'no', 'pt', 'sv'],
    french:    ['fr', 'tl', 'pt-br'],
    russian:   ['hr', 'ru'],
    czech:     ['cs'],
    polish:    ['pl'],
    icelandic: ['is']
  };

  function langToTypeMap(mapping) {
    var type, langs, l, ret = {};
    for (type in mapping) {
      if (mapping.hasOwnProperty(type)) {
        langs = mapping[type];
        for (l in langs) {
          ret[langs[l]] = type;
        }
      }
    }
    return ret;
  }

  // Trim a string.
  function trim(str){
    var trimRe = /^\s+|\s+$/g;
    return str.replace(trimRe, '');
  }

  // Based on a phrase text that contains `n` plural forms separated
  // by `delimeter`, a `locale`, and a `count`, choose the correct
  // plural form, or none if `count` is `null`.
  function choosePluralForm(text, locale, count){
    var ret, texts, chosenText;
    if (count != null && text) {
      texts = text.split(delimeter);
      chosenText = texts[pluralTypeIndex(locale, count)] || texts[0];
      ret = trim(chosenText);
    } else {
      ret = text;
    }
    return ret;
  }

  function pluralTypeName(locale) {
    var langToPluralType = langToTypeMap(pluralTypeToLanguages);
    return langToPluralType[locale] || langToPluralType.en;
  }

  function pluralTypeIndex(locale, count) {
    return pluralTypes[pluralTypeName(locale)](count);
  }

  // ### interpolate
  //
  // Does the dirty work. Creates a `RegExp` object for each
  // interpolation placeholder.
  function interpolate(phrase, options) {
    for (var arg in options) {
      if (arg !== '_' && options.hasOwnProperty(arg)) {
        // Ensure replacement value is escaped to prevent special $-prefixed regex replace tokens
        // the "$$$$" is needed because each "$" needs to be escaped with "$" itself, and we need two in the resulting output.
        var replacement = typeof options[arg] === 'string' ? String.prototype.replace.call(options[arg], /\$/g, '$$$$') : options[arg];
        // We create a new `RegExp` each time instead of using a more-efficient
        // string replace so that the same argument can be replaced multiple times
        // in the same phrase.
        phrase = phrase.replace(new RegExp('%\\{'+arg+'\\}', 'g'), replacement);
      }
    }
    return phrase;
  }

  // ### warn
  //
  // Provides a warning in the console if a phrase key is missing.
  function warn(message) {
    root.console && root.console.warn && root.console.warn('WARNING: ' + message);
  }

  // ### clone
  //
  // Clone an object.
  function clone(source) {
    var ret = {};
    for (var prop in source) {
      ret[prop] = source[prop];
    }
    return ret;
  }

  return Polyglot;
}));
<commit_msg>Cache `String#replace` rather than relying on it being unmodified.<commit_after>//     (c) 2012 Airbnb, Inc.
//
//     polyglot.js may be freely distributed under the terms of the BSD
//     license. For all licensing information, details, and documention:
//     http://airbnb.github.com/polyglot.js
//
//
// Polyglot.js is an I18n helper library written in JavaScript, made to
// work both in the browser and in Node. It provides a simple solution for
// interpolation and pluralization, based off of Airbnb's
// experience adding I18n functionality to its Backbone.js and Node apps.
//
// Polylglot is agnostic to your translation backend. It doesn't perform any
// translation; it simply gives you a way to manage translated phrases from
// your client- or server-side JavaScript application.
//

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([], function() {
      return factory(root);
    });
  } else if (typeof exports === 'object') {
    module.exports = factory(root);
  } else {
    root.Polyglot = factory(root);
  }
}(this, function(root) {
  'use strict';

  var replace = String.prototype.replace;

  // ### Polyglot class constructor
  function Polyglot(options) {
    options = options || {};
    this.phrases = {};
    this.extend(options.phrases || {});
    this.currentLocale = options.locale || 'en';
    this.allowMissing = !!options.allowMissing;
    this.warn = options.warn || warn;
  }

  // ### Version
  Polyglot.VERSION = '0.4.3';

  // ### polyglot.locale([locale])
  //
  // Get or set locale. Internally, Polyglot only uses locale for pluralization.
  Polyglot.prototype.locale = function(newLocale) {
    if (newLocale) this.currentLocale = newLocale;
    return this.currentLocale;
  };

  // ### polyglot.extend(phrases)
  //
  // Use `extend` to tell Polyglot how to translate a given key.
  //
  //     polyglot.extend({
  //       "hello": "Hello",
  //       "hello_name": "Hello, %{name}"
  //     });
  //
  // The key can be any string.  Feel free to call `extend` multiple times;
  // it will override any phrases with the same key, but leave existing phrases
  // untouched.
  //
  // It is also possible to pass nested phrase objects, which get flattened
  // into an object with the nested keys concatenated using dot notation.
  //
  //     polyglot.extend({
  //       "nav": {
  //         "hello": "Hello",
  //         "hello_name": "Hello, %{name}",
  //         "sidebar": {
  //           "welcome": "Welcome"
  //         }
  //       }
  //     });
  //
  //     console.log(polyglot.phrases);
  //     // {
  //     //   'nav.hello': 'Hello',
  //     //   'nav.hello_name': 'Hello, %{name}',
  //     //   'nav.sidebar.welcome': 'Welcome'
  //     // }
  //
  // `extend` accepts an optional second argument, `prefix`, which can be used
  // to prefix every key in the phrases object with some string, using dot
  // notation.
  //
  //     polyglot.extend({
  //       "hello": "Hello",
  //       "hello_name": "Hello, %{name}"
  //     }, "nav");
  //
  //     console.log(polyglot.phrases);
  //     // {
  //     //   'nav.hello': 'Hello',
  //     //   'nav.hello_name': 'Hello, %{name}'
  //     // }
  //
  // This feature is used internally to support nested phrase objects.
  Polyglot.prototype.extend = function(morePhrases, prefix) {
    var phrase;

    for (var key in morePhrases) {
      if (morePhrases.hasOwnProperty(key)) {
        phrase = morePhrases[key];
        if (prefix) key = prefix + '.' + key;
        if (typeof phrase === 'object') {
          this.extend(phrase, key);
        } else {
          this.phrases[key] = phrase;
        }
      }
    }
  };

  // ### polyglot.unset(phrases)
  // Use `unset` to selectively remove keys from a polyglot instance.
  //
  //     polyglot.unset("some_key");
  //     polyglot.unset({
  //       "hello": "Hello",
  //       "hello_name": "Hello, %{name}"
  //     });
  //
  // The unset method can take either a string (for the key), or an object hash with
  // the keys that you would like to unset.
  Polyglot.prototype.unset = function(morePhrases, prefix) {
    var phrase;

    if (typeof morePhrases === 'string') {
      delete this.phrases[morePhrases];
    } else {
      for (var key in morePhrases) {
        if (morePhrases.hasOwnProperty(key)) {
          phrase = morePhrases[key];
          if (prefix) key = prefix + '.' + key;
          if (typeof phrase === 'object') {
            this.unset(phrase, key);
          } else {
            delete this.phrases[key];
          }
        }
      }
    }
  };

  // ### polyglot.clear()
  //
  // Clears all phrases. Useful for special cases, such as freeing
  // up memory if you have lots of phrases but no longer need to
  // perform any translation. Also used internally by `replace`.
  Polyglot.prototype.clear = function() {
    this.phrases = {};
  };

  // ### polyglot.replace(phrases)
  //
  // Completely replace the existing phrases with a new set of phrases.
  // Normally, just use `extend` to add more phrases, but under certain
  // circumstances, you may want to make sure no old phrases are lying around.
  Polyglot.prototype.replace = function(newPhrases) {
    this.clear();
    this.extend(newPhrases);
  };

  // ### polyglot.t(key, options)
  //
  // The most-used method. Provide a key, and `t` will return the
  // phrase.
  //
  //     polyglot.t("hello");
  //     => "Hello"
  //
  // The phrase value is provided first by a call to `polyglot.extend()` or
  // `polyglot.replace()`.
  //
  // Pass in an object as the second argument to perform interpolation.
  //
  //     polyglot.t("hello_name", {name: "Spike"});
  //     => "Hello, Spike"
  //
  // If you like, you can provide a default value in case the phrase is missing.
  // Use the special option key "_" to specify a default.
  //
  //     polyglot.t("i_like_to_write_in_language", {
  //       _: "I like to write in %{language}.",
  //       language: "JavaScript"
  //     });
  //     => "I like to write in JavaScript."
  //
  Polyglot.prototype.t = function(key, options) {
    var phrase, result;
    options = options == null ? {} : options;
    // allow number as a pluralization shortcut
    if (typeof options === 'number') {
      options = {smart_count: options};
    }
    if (typeof this.phrases[key] === 'string') {
      phrase = this.phrases[key];
    } else if (typeof options._ === 'string') {
      phrase = options._;
    } else if (this.allowMissing) {
      phrase = key;
    } else {
      this.warn('Missing translation for key: "'+key+'"');
      result = key;
    }
    if (typeof phrase === 'string') {
      options = clone(options);
      result = choosePluralForm(phrase, this.currentLocale, options.smart_count);
      result = interpolate(result, options);
    }
    return result;
  };

  // ### polyglot.has(key)
  //
  // Check if polyglot has a translation for given key
  Polyglot.prototype.has = function(key) {
    return key in this.phrases;
  };

  // #### Pluralization methods
  // The string that separates the different phrase possibilities.
  var delimeter = '||||';

  // Mapping from pluralization group plural logic.
  var pluralTypes = {
    chinese:   function(n) { return 0; },
    german:    function(n) { return n !== 1 ? 1 : 0; },
    french:    function(n) { return n > 1 ? 1 : 0; },
    russian:   function(n) { return n % 10 === 1 && n % 100 !== 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2; },
    czech:     function(n) { return (n === 1) ? 0 : (n >= 2 && n <= 4) ? 1 : 2; },
    polish:    function(n) { return (n === 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); },
    icelandic: function(n) { return (n % 10 !== 1 || n % 100 === 11) ? 1 : 0; }
  };

  // Mapping from pluralization group to individual locales.
  var pluralTypeToLanguages = {
    chinese:   ['fa', 'id', 'ja', 'ko', 'lo', 'ms', 'th', 'tr', 'zh'],
    german:    ['da', 'de', 'en', 'es', 'fi', 'el', 'he', 'hu', 'it', 'nl', 'no', 'pt', 'sv'],
    french:    ['fr', 'tl', 'pt-br'],
    russian:   ['hr', 'ru'],
    czech:     ['cs'],
    polish:    ['pl'],
    icelandic: ['is']
  };

  function langToTypeMap(mapping) {
    var type, langs, l, ret = {};
    for (type in mapping) {
      if (mapping.hasOwnProperty(type)) {
        langs = mapping[type];
        for (l in langs) {
          ret[langs[l]] = type;
        }
      }
    }
    return ret;
  }

  // Trim a string.
  function trim(str){
    var trimRe = /^\s+|\s+$/g;
    return replace.call(str, trimRe, '');
  }

  // Based on a phrase text that contains `n` plural forms separated
  // by `delimeter`, a `locale`, and a `count`, choose the correct
  // plural form, or none if `count` is `null`.
  function choosePluralForm(text, locale, count){
    var ret, texts, chosenText;
    if (count != null && text) {
      texts = text.split(delimeter);
      chosenText = texts[pluralTypeIndex(locale, count)] || texts[0];
      ret = trim(chosenText);
    } else {
      ret = text;
    }
    return ret;
  }

  function pluralTypeName(locale) {
    var langToPluralType = langToTypeMap(pluralTypeToLanguages);
    return langToPluralType[locale] || langToPluralType.en;
  }

  function pluralTypeIndex(locale, count) {
    return pluralTypes[pluralTypeName(locale)](count);
  }

  // ### interpolate
  //
  // Does the dirty work. Creates a `RegExp` object for each
  // interpolation placeholder.
  function interpolate(phrase, options) {
    for (var arg in options) {
      if (arg !== '_' && options.hasOwnProperty(arg)) {
        // Ensure replacement value is escaped to prevent special $-prefixed regex replace tokens
        // the "$$$$" is needed because each "$" needs to be escaped with "$" itself, and we need two in the resulting output.
        var replacement = typeof options[arg] === 'string' ? replace.call(options[arg], /\$/g, '$$$$') : options[arg];
        // We create a new `RegExp` each time instead of using a more-efficient
        // string replace so that the same argument can be replaced multiple times
        // in the same phrase.
        phrase = replace.call(phrase, new RegExp('%\\{'+arg+'\\}', 'g'), replacement);
      }
    }
    return phrase;
  }

  // ### warn
  //
  // Provides a warning in the console if a phrase key is missing.
  function warn(message) {
    root.console && root.console.warn && root.console.warn('WARNING: ' + message);
  }

  // ### clone
  //
  // Clone an object.
  function clone(source) {
    var ret = {};
    for (var prop in source) {
      ret[prop] = source[prop];
    }
    return ret;
  }

  return Polyglot;
}));
<|endoftext|>


<commit_before>var pg = require("pg");
var _ = require("underscore")._;
var util = require("util");
var events = require("events");
var massiveQuery = require("./query");
var _ = require("underscore")._;

//default it, cause we're nice

var Client = function(){
  var _connectionString = "tcp://postgres@localhost/postgres";
  events.EventEmitter.call(this);
};

util.inherits(Client,events.EventEmitter);

Client.prototype.connect = function(connection) {
  _connectionString = connection;
};

//think I need a better home for this... but for now
//this will do
Client.prototype.run = function(sql,params){
  return new massiveQuery(sql,params);
};

//break this apart please...
Client.prototype.execute = function(query, callback) {

  pg.connect(_connectionString, function(err,db){
    query.emit("beforeExecute", query);
    db.on("error", function(err){throw err});
    if(callback){

      db.query(query.sql, query.params,function(err, results){
        if(err) callback(err,null);
        else {
          if(results.rows.length > 0){
            callback(null,results.rows);
          }else{
            callback(null,results);
          }
        }
      });
    }else{
      if(query.isSelect()) {
        var dbQuery = db.query(query.sql, query.params);
        dbQuery.on("row", function(row){query.emit("row", row)});
        dbQuery.on("end", function() {
          query.emit("executed");
          console.log("closing");
          db.end();
        });
      }else{
        var dbQuery = db.query(query.sql, query.params, function(err,result){

          if(err) throw err;//query.emit("error", err);
          if(result.rows.length > 0) {

            _.each(result.rows, function(r){
              query.emit("row", r);
            });
          }
          query.emit("executed");
          console.log("closing...");
          db.end();
        });
      }

    }
  });
};

var _translateType = function(typeName) {
  var _result = typeName;

  switch(typeName){
    case "pk" :
      _result ="serial PRIMARY KEY";
      break;
    case "money" :
      _result ="decimal(8,2)";
      break;
    case "date" :
      _result = "timestamptz";
      break;
    case "string" :
      _result ="varchar(255)";
      break;
    case "search" :
      _result ="tsvector";
      break;
    case "int" :
      _result ="int4";
      break;
  }
  return _result;
}

var _containsPK = function(columns) {
  return _.any(columns.values,"pk");
}

Client.prototype.dropTable = function(tableName) {
  return new massiveQuery("DROP TABLE IF EXISTS " + tableName + ";");
}

Client.prototype.createTable = function(tableName, columns) {

  var _sql ="CREATE TABLE " + tableName + "(";
  var _cols = [];

  //force a PK
  if(!_containsPK(columns)){
    columns.id = "pk";
  }

  for(var c in columns){

    if(c == "timestamps"){
      _cols.push("created_at timestamptz not null default 'now'");
      _cols.push("updated_at timestamptz not null default 'now'");
    }else{
      var colName = c;
      var colParts = columns[c].split(" ");
      var colType = colParts[0];
      var translated = _translateType(colType);
      var extras = _.without(colParts,colType).join(" ");
      var declaration = colName + " " + translated + " " + extras;
      //console.log(declaration);
      _cols.push(declaration);
    }
  }

  _sql+= _cols.join(",") + ");";
  //console.log(_sql);
  return new massiveQuery(_sql);
};

module.exports = new Client();<commit_msg>removed double require<commit_after>var pg = require("pg");
var _ = require("underscore")._;
var util = require("util");
var events = require("events");
var massiveQuery = require("./query");

//default it, cause we're nice

var Client = function(){
  var _connectionString = "tcp://postgres@localhost/postgres";
  events.EventEmitter.call(this);
};

util.inherits(Client,events.EventEmitter);

Client.prototype.connect = function(connection) {
  _connectionString = connection;
};

//think I need a better home for this... but for now
//this will do
Client.prototype.run = function(sql,params){
  return new massiveQuery(sql,params);
};

//break this apart please...
Client.prototype.execute = function(query, callback) {

  pg.connect(_connectionString, function(err,db){
    query.emit("beforeExecute", query);
    db.on("error", function(err){throw err});
    if(callback){

      db.query(query.sql, query.params,function(err, results){
        if(err) callback(err,null);
        else {
          if(results.rows.length > 0){
            callback(null,results.rows);
          }else{
            callback(null,results);
          }
        }
      });
    }else{
      if(query.isSelect()) {
        var dbQuery = db.query(query.sql, query.params);
        dbQuery.on("row", function(row){query.emit("row", row)});
        dbQuery.on("end", function() {
          query.emit("executed");
          console.log("closing");
          db.end();
        });
      }else{
        var dbQuery = db.query(query.sql, query.params, function(err,result){

          if(err) throw err;//query.emit("error", err);
          if(result.rows.length > 0) {

            _.each(result.rows, function(r){
              query.emit("row", r);
            });
          }
          query.emit("executed");
          console.log("closing...");
          db.end();
        });
      }

    }
  });
};

var _translateType = function(typeName) {
  var _result = typeName;

  switch(typeName){
    case "pk" :
      _result ="serial PRIMARY KEY";
      break;
    case "money" :
      _result ="decimal(8,2)";
      break;
    case "date" :
      _result = "timestamptz";
      break;
    case "string" :
      _result ="varchar(255)";
      break;
    case "search" :
      _result ="tsvector";
      break;
    case "int" :
      _result ="int4";
      break;
  }
  return _result;
}

var _containsPK = function(columns) {
  return _.any(columns.values,"pk");
}

Client.prototype.dropTable = function(tableName) {
  return new massiveQuery("DROP TABLE IF EXISTS " + tableName + ";");
}

Client.prototype.createTable = function(tableName, columns) {

  var _sql ="CREATE TABLE " + tableName + "(";
  var _cols = [];

  //force a PK
  if(!_containsPK(columns)){
    columns.id = "pk";
  }

  for(var c in columns){

    if(c == "timestamps"){
      _cols.push("created_at timestamptz not null default 'now'");
      _cols.push("updated_at timestamptz not null default 'now'");
    }else{
      var colName = c;
      var colParts = columns[c].split(" ");
      var colType = colParts[0];
      var translated = _translateType(colType);
      var extras = _.without(colParts,colType).join(" ");
      var declaration = colName + " " + translated + " " + extras;
      //console.log(declaration);
      _cols.push(declaration);
    }
  }

  _sql+= _cols.join(",") + ");";
  //console.log(_sql);
  return new massiveQuery(_sql);
};

module.exports = new Client();<|endoftext|>


<commit_before>'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Provider = undefined;

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _utils = require('./utils');

var _bluebird = require('bluebird');

var _bluebird2 = _interopRequireDefault(_bluebird);

var _request = require('request');

var _request2 = _interopRequireDefault(_request);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

/**
 * Default provider
 */
var Provider = exports.Provider = function () {
  function Provider(config) {
    _classCallCheck(this, Provider);

    this.config = config;
  }

  _createClass(Provider, [{
    key: 'signin',
    value: function signin(_ref, callback) {
      var signin_uri = _ref.signin_uri;
      var scope = _ref.scope;
      var state = _ref.state;
      var response_type = _ref.response_type;
      var access_type = _ref.access_type;
      var prompt = _ref.prompt;
      var _config = this.config;
      var id = _config.id;
      var redirect_uri = _config.redirect_uri;

      var params = {
        client_id: id,
        redirect_uri: redirect_uri
      };
      if (response_type) {
        params.response_type = response_type;
      }
      if (scope) {
        params.scope = scope;
      }
      if (state) {
        params.state = state;
      }
      if (access_type) {
        params.access_type = access_type
      }
      if (approval_prompt) {
        params.prompt = prompt
      }
      if (!params.client_id || !params.redirect_uri) {
        callback('Invalid sign in params. ' + params.client_id + ' ' + params.redirect_uri);
      } else {
        var url = _utils.Utils.urlBuilder(signin_uri, params);
        callback(null, { url: url });
      }
    }
  }, {
    key: 'callback',
    value: function callback(_ref2, _ref3, additionalParams, cb) {
      var code = _ref2.code;
      var state = _ref2.state;
      var authorization_uri = _ref3.authorization_uri;
      var profile_uri = _ref3.profile_uri;
      var profileMap = _ref3.profileMap;
      var authorizationMethod = _ref3.authorizationMethod;
      var authorization = additionalParams.authorization;
      var profile = additionalParams.profile;
      var _config2 = this.config;
      var id = _config2.id;
      var redirect_uri = _config2.redirect_uri;
      var secret = _config2.secret;
      var provider = _config2.provider;

      var attemptAuthorize = function attemptAuthorize() {
        return new _bluebird2.default(function (resolve, reject) {
          var mandatoryParams = {
            client_id: id,
            redirect_uri: redirect_uri,
            client_secret: secret,
            code: code
          };
          var payload = Object.assign(mandatoryParams, authorization);
          if (authorizationMethod === 'GET') {
            var url = _utils.Utils.urlBuilder(authorization_uri, payload);
            _request2.default.get(url, function (error, response, accessData) {
              if (error) {
                return reject(error);
              }
              return resolve(accessData);
            });
          } else {
            _request2.default.post(authorization_uri, { form: payload }, function (error, response, accessData) {
              if (error) {
                return reject(error);
              }
              return resolve(accessData);
            });
          }
        });
      };

      var createMappedProfile = function createMappedProfile(accessData) {
        return new _bluebird2.default(function (resolve, reject) {
          if (!accessData) {
            reject(new Error('No access data'));
          }
          var _JSON$parse = JSON.parse(accessData);

          var access_token = _JSON$parse.access_token;
          var refresh_token = _JSON$parse.refresh_token ? _JSON$parse.refresh_token : '';

          var url = _utils.Utils.urlBuilder(profile_uri, Object.assign({ access_token: access_token }, profile));
          _request2.default.get(url, function (error, httpResponse, profileData) {
            if (error) {
              reject(error);
            } else if (!profileData) {
              reject(new Error('No profile data'));
            } else {
              var profileJson = JSON.parse(profileData);
              profileJson.provider = provider;
              profileJson.at_hash = access_token;
              profileJson.offline_access = refresh_token;
              var mappedProfile = profileMap ? profileMap(profileJson) : profileJson;
              resolve(mappedProfile);
            }
          });
        });
      };

      attemptAuthorize().then(createMappedProfile).then(function (data) {
        return cb(null, data, state);
      }).catch(function (error) {
        return cb(error);
      });
    }
  }]);

  return Provider;
}();
<commit_msg>3rd spelling correction... Its too late...<commit_after>'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Provider = undefined;

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _utils = require('./utils');

var _bluebird = require('bluebird');

var _bluebird2 = _interopRequireDefault(_bluebird);

var _request = require('request');

var _request2 = _interopRequireDefault(_request);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

/**
 * Default provider
 */
var Provider = exports.Provider = function () {
  function Provider(config) {
    _classCallCheck(this, Provider);

    this.config = config;
  }

  _createClass(Provider, [{
    key: 'signin',
    value: function signin(_ref, callback) {
      var signin_uri = _ref.signin_uri;
      var scope = _ref.scope;
      var state = _ref.state;
      var response_type = _ref.response_type;
      var access_type = _ref.access_type;
      var prompt = _ref.prompt;
      var _config = this.config;
      var id = _config.id;
      var redirect_uri = _config.redirect_uri;

      var params = {
        client_id: id,
        redirect_uri: redirect_uri
      };
      if (response_type) {
        params.response_type = response_type;
      }
      if (scope) {
        params.scope = scope;
      }
      if (state) {
        params.state = state;
      }
      if (access_type) {
        params.access_type = access_type
      }
      if (prompt) {
        params.prompt = prompt
      }
      if (!params.client_id || !params.redirect_uri) {
        callback('Invalid sign in params. ' + params.client_id + ' ' + params.redirect_uri);
      } else {
        var url = _utils.Utils.urlBuilder(signin_uri, params);
        callback(null, { url: url });
      }
    }
  }, {
    key: 'callback',
    value: function callback(_ref2, _ref3, additionalParams, cb) {
      var code = _ref2.code;
      var state = _ref2.state;
      var authorization_uri = _ref3.authorization_uri;
      var profile_uri = _ref3.profile_uri;
      var profileMap = _ref3.profileMap;
      var authorizationMethod = _ref3.authorizationMethod;
      var authorization = additionalParams.authorization;
      var profile = additionalParams.profile;
      var _config2 = this.config;
      var id = _config2.id;
      var redirect_uri = _config2.redirect_uri;
      var secret = _config2.secret;
      var provider = _config2.provider;

      var attemptAuthorize = function attemptAuthorize() {
        return new _bluebird2.default(function (resolve, reject) {
          var mandatoryParams = {
            client_id: id,
            redirect_uri: redirect_uri,
            client_secret: secret,
            code: code
          };
          var payload = Object.assign(mandatoryParams, authorization);
          if (authorizationMethod === 'GET') {
            var url = _utils.Utils.urlBuilder(authorization_uri, payload);
            _request2.default.get(url, function (error, response, accessData) {
              if (error) {
                return reject(error);
              }
              return resolve(accessData);
            });
          } else {
            _request2.default.post(authorization_uri, { form: payload }, function (error, response, accessData) {
              if (error) {
                return reject(error);
              }
              return resolve(accessData);
            });
          }
        });
      };

      var createMappedProfile = function createMappedProfile(accessData) {
        return new _bluebird2.default(function (resolve, reject) {
          if (!accessData) {
            reject(new Error('No access data'));
          }
          var _JSON$parse = JSON.parse(accessData);

          var access_token = _JSON$parse.access_token;
          var refresh_token = _JSON$parse.refresh_token ? _JSON$parse.refresh_token : '';

          var url = _utils.Utils.urlBuilder(profile_uri, Object.assign({ access_token: access_token }, profile));
          _request2.default.get(url, function (error, httpResponse, profileData) {
            if (error) {
              reject(error);
            } else if (!profileData) {
              reject(new Error('No profile data'));
            } else {
              var profileJson = JSON.parse(profileData);
              profileJson.provider = provider;
              profileJson.at_hash = access_token;
              profileJson.offline_access = refresh_token;
              var mappedProfile = profileMap ? profileMap(profileJson) : profileJson;
              resolve(mappedProfile);
            }
          });
        });
      };

      attemptAuthorize().then(createMappedProfile).then(function (data) {
        return cb(null, data, state);
      }).catch(function (error) {
        return cb(error);
      });
    }
  }]);

  return Provider;
}();
<|endoftext|>


<commit_before>'use babel';

import { denamespace, packagify } from './util';

class Provider {
  IMPORT_REGEX = /import\s+([^;]+);/g;
  selector = '.source.java';
  disableForSelector = '.source.java .comment, .source.java .string';
  inclusionPriority = 1000;
  excludeLowerPriority = false;

  constructor(dictionary) {
    this.dictionary = dictionary;
  }

  setImportHandler(importHandler) {
    this.importHandler = importHandler;
  }

  /**
   * Returns an array of all the imports in the specified editor.
   */
  getImports(editor) {
    const imports = [];
    editor.scan(this.IMPORT_REGEX, ({ match }) => imports.push(match[1]));
    return imports;
  }

  /**
   * Finds the dot prefix.
   * `instance.prefix` will find `instance`.
   * `instance.` will find ``
   * `instance` will return null.
   */
  getDotPrefix(editor, bufferPosition) {
    const lineText = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition]);
    const match = lineText.match(/(\w+)\.\w*$/);
    return match ? match[1] : null;
  }

  hasNewPrefix(editor, bufferPosition) {
    const lineText = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition]);
    return !!lineText.match(/new \w*$/);
  }

  /**
   * Retrieves the fully qualified class be examining the imports
   * in the specified editor. For instance:
   * klass = `Arrays`
   * if import statements at least hold `java.util.*;` or `java.util.Arrays`
   * then `java.util.Arrays` will be returned.
   */
  getFullyQualifiedClass(editor, klass) {
    const imports = this.getImports(editor);
    const importCandidates = imports.filter(imp => {
      return (denamespace(imp) === klass || denamespace(imp) === '*');
    });

    const existingImport = importCandidates.find(importCandidate =>
      this.dictionary.get(`${packagify(importCandidate)}.${klass}`)
    );

    return existingImport ? `${packagify(existingImport)}.${klass}` : null;
  }

  /**
   * Gets the suggestions when a dot is added to a prefix.
   * Example:
   *  - Row is: `myList.sort`
   *  - dotPrefix = myList
   *  - prefix = sort
   *
   * `editor` is the current editor
   */
  getStaticClassDotPrefixedSuggestions(editor, dotPrefix, prefix) {
    const fullyQualifiedClass = this.getFullyQualifiedClass(editor, dotPrefix);
    if (null === fullyQualifiedClass) {
      return [];
    }

    return this.dictionary.get(fullyQualifiedClass).methods
      .filter(method =>
          method.modifiers.includes('public') &&
          method.modifiers.includes('static') &&
          (prefix === '.' || method.name.startsWith(prefix)));
  }

  getClassSuggestions(prefix) {
    return this.dictionary.find(prefix);
  }

  getPublicConstructorClassSuggestions(prefix) {
    return this.getClassSuggestions(prefix)
      .filter(entry => entry.methods.find(method => method.name === '<init>' && method.modifiers.includes('public')));
  }

  getSuggestions({ editor, bufferPosition, scopeDescriptor, prefix, activatedManually }) {
    let entries;
    let mapper;

    const dotPrefix = this.getDotPrefix(editor, bufferPosition);
    const hasNewPrefix = this.hasNewPrefix(editor, bufferPosition);
    if (dotPrefix) {
      entries = this.getStaticClassDotPrefixedSuggestions(editor, dotPrefix, prefix);
      mapper = this.mapMethodEntryToSuggestion;
    } else if (hasNewPrefix) {
      entries = this.getPublicConstructorClassSuggestions(prefix);
      mapper = this.mapClassEntryToConstructorSuggestion;
    } else {
      entries = this.getClassSuggestions(prefix);
      mapper = this.mapClassEntryToSuggestion;
    }

    return [].concat.apply([], entries
      .slice(0, atom.config.get('autocomplete-plus.maxVisibleSuggestions')) // Don't do more work than necessary
      .map(mapper.bind(this))
      .sort((lhs, rhs) => (lhs.snippet || lhs.text).length - (rhs.snippet || rhs.text).length));
  }

  methodEntryToSnippet(entry) {
    const args = entry.signature.arguments;
    const mapArg = (arg, index) => `\${${index + 1}:${arg}}`;
    return `${entry.name}(${args.map(mapArg)})\$${args.length + 1}`;
  }

  mapClassEntryToSuggestion(klass) {
    return {
      // The `text`/`snippet` thingie here is quite hacky. Snippet will be inserted into editor.
      // Setting `text` as the fully qualified class will make any duplicate class names,
      // but from different packages show up in suggestion list.
      // Issue: https://github.com/atom/autocomplete-plus/issues/615
      text: klass.name,
      snippet: denamespace(klass.name),
      rightLabel: packagify(klass.name),
      type: 'class',

      // Not part of autocomplete-api, passed so that the classname can be given to importHandler.
      klass
    };
  }

  mapMethodEntryToSuggestion(method) {
    return {
      snippet: this.methodEntryToSnippet(method),
      leftLabel: method.signature.returnValue,
      type: 'method'
    };
  }

  mapClassEntryToConstructorSuggestion(klass) {
    const constructors = klass.methods.filter(method => method.name === '<init>');
    return constructors
      .sort((lhs, rhs) => lhs.signature.arguments.length - rhs.signature.arguments.length)
      .map(constructor => ({
        snippet: this.methodEntryToSnippet({ ...constructor, name: denamespace(klass.name) }),
        rightLabel: packagify(klass.name),
        leftLabel: klass.name,
        type: 'class',

        // Not part of autocomplete-api, passed so that the classname can be given to importHandler.
        klass
      }));
  }

  onDidInsertSuggestion({ editor, triggerPosition, suggestion }) {
    if (!this.importHandler || suggestion.type !== 'class') {
      return;
    }

    this.importHandler(editor, suggestion.klass.name);
  }
}

export default Provider;
<commit_msg>Less autocomplete when not expected<commit_after>'use babel';

import { denamespace, packagify } from './util';

class Provider {
  IMPORT_REGEX = /import\s+([^;]+);/g;
  selector = '.source.java';
  disableForSelector = '.source.java .comment, .source.java .string';
  inclusionPriority = 1000;
  excludeLowerPriority = false;

  constructor(dictionary) {
    this.dictionary = dictionary;
  }

  setImportHandler(importHandler) {
    this.importHandler = importHandler;
  }

  /**
   * Returns an array of all the imports in the specified editor.
   */
  getImports(editor) {
    const imports = [];
    editor.scan(this.IMPORT_REGEX, ({ match }) => imports.push(match[1]));
    return imports;
  }

  /**
   * Finds the dot prefix.
   * `instance.prefix` will find `instance`.
   * `instance.` will find ``
   * `instance` will return null.
   */
  getDotPrefix(editor, bufferPosition) {
    const lineText = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition]);
    const match = lineText.match(/(\w+)\.\w*$/);
    return match ? match[1] : null;
  }

  hasNewPrefix(editor, bufferPosition) {
    const lineText = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition]);
    return !!lineText.match(/new \w*$/);
  }

  /**
   * Retrieves the fully qualified class be examining the imports
   * in the specified editor. For instance:
   * klass = `Arrays`
   * if import statements at least hold `java.util.*;` or `java.util.Arrays`
   * then `java.util.Arrays` will be returned.
   */
  getFullyQualifiedClass(editor, klass) {
    const imports = this.getImports(editor);
    const importCandidates = imports.filter(imp => {
      return (denamespace(imp) === klass || denamespace(imp) === '*');
    });

    const existingImport = importCandidates.find(importCandidate =>
      this.dictionary.get(`${packagify(importCandidate)}.${klass}`)
    );

    return existingImport ? `${packagify(existingImport)}.${klass}` : null;
  }

  /**
   * Gets the suggestions when a dot is added to a prefix.
   * Example:
   *  - Row is: `myList.sort`
   *  - dotPrefix = myList
   *  - prefix = sort
   *
   * `editor` is the current editor
   */
  getStaticClassDotPrefixedSuggestions(editor, dotPrefix, prefix) {
    const fullyQualifiedClass = this.getFullyQualifiedClass(editor, dotPrefix);
    if (null === fullyQualifiedClass) {
      return [];
    }

    return this.dictionary.get(fullyQualifiedClass).methods
      .filter(method =>
          method.modifiers.includes('public') &&
          method.modifiers.includes('static') &&
          (prefix === '.' || method.name.startsWith(prefix)));
  }

  getClassSuggestions(prefix) {
    return this.dictionary.find(prefix);
  }

  getPublicConstructorClassSuggestions(prefix) {
    return this.getClassSuggestions(prefix)
      .filter(entry => entry.methods.find(method => method.name === '<init>' && method.modifiers.includes('public')));
  }

  getSuggestions({ editor, bufferPosition, scopeDescriptor, prefix, activatedManually }) {
    if (!prefix || prefix.length === 0) {
      // Happens when typing e.g. `>`
      return [];
    }

    const dotPrefix = this.getDotPrefix(editor, bufferPosition);
    const hasNewPrefix = this.hasNewPrefix(editor, bufferPosition);
    if (dotPrefix) {
      /**
       * Dot prefixed, e.g. `variable.prefix`.
       * This should show members of the variable.
       */
      return this.getStaticClassDotPrefixedSuggestions(editor, dotPrefix, prefix)
        .sort(this.sortByNameKey)
        .slice(0, atom.config.get('autocomplete-plus.maxVisibleSuggestions'))
        .map(entry => this.mapMethodEntryToSuggestion(entry));
    } else if (hasNewPrefix) {
      /**
       * Prefix is immediately preceded by the word `new`, eg. `new Prefix`
       * This should return public constructors.
       */
      return [].concat.apply([], this.getPublicConstructorClassSuggestions(prefix)
        .sort(this.sortByNameKey)
        .slice(0, atom.config.get('autocomplete-plus.maxVisibleSuggestions'))
        .map(entry => this.mapClassEntryToConstructorSuggestion(entry))
      );
    }

    /* The default case where a class is plainly typed out */
    return this.getClassSuggestions(prefix)
      .sort(this.sortByNameKey)
      .slice(0, atom.config.get('autocomplete-plus.maxVisibleSuggestions'))
      .map(entry => this.mapClassEntryToSuggestion(entry));
  }

  methodEntryToSnippet(entry) {
    const args = entry.signature.arguments;
    const mapArg = (arg, index) => `\${${index + 1}:${arg}}`;
    return `${entry.name}(${args.map(mapArg)})\$${args.length + 1}`;
  }

  mapClassEntryToSuggestion(klass) {
    return {
      // The `text`/`snippet` thingie here is quite hacky. Snippet will be inserted into editor.
      // Setting `text` as the fully qualified class will make any duplicate class names,
      // but from different packages show up in suggestion list.
      // Issue: https://github.com/atom/autocomplete-plus/issues/615
      text: klass.name,
      snippet: denamespace(klass.name),
      rightLabel: packagify(klass.name),
      type: 'class',

      // Not part of autocomplete-api, passed so that the classname can be given to importHandler.
      klass
    };
  }

  mapMethodEntryToSuggestion(method) {
    return {
      snippet: this.methodEntryToSnippet(method),
      leftLabel: method.signature.returnValue,
      type: 'method'
    };
  }

  sortByNameKey(lhs, rhs) {
    return lhs.name.length - rhs.name.length;
  }

  mapClassEntryToConstructorSuggestion(klass) {
    const constructors = klass.methods.filter(method => method.name === '<init>');
    return constructors
      .map(constructor => ({
        snippet: this.methodEntryToSnippet({ ...constructor, name: denamespace(klass.name) }),
        rightLabel: packagify(klass.name),
        leftLabel: klass.name,
        type: 'class',

        // Not part of autocomplete-api, passed so that the classname can be given to importHandler.
        klass
      }));
  }

  onDidInsertSuggestion({ editor, triggerPosition, suggestion }) {
    if (!this.importHandler || suggestion.type !== 'class') {
      return;
    }

    this.importHandler(editor, suggestion.klass.name);
  }
}

export default Provider;
<|endoftext|>


<commit_before>/**
 * class Renderer
 *
 * Generates HTML from parsed token stream. Each instance has independent
 * copy of rules. Those can be rewritten with ease. Also, you can add new
 * rules if you create plugin and adds new token types.
 **/
'use strict';

var assign          = require('./common/utils').assign;
var unescapeAll     = require('./common/utils').unescapeAll;
var escapeHtml      = require('./common/utils').escapeHtml;

////////////////////////////////////////////////////////////////////////////////

var default_rules = {};

default_rules.code_inline = function (tokens, idx /*, options, env */) {
  return '' + escapeHtml(tokens[idx].content) + '';
};

default_rules.code_block = function (tokens, idx /*, options, env */) {
  return '
' + escapeHtml(tokens[idx].content) + '
\n';
};

default_rules.fence = function (tokens, idx, options, env, self) {
  var token = tokens[idx],
      info = token.info ? unescapeAll(token.info).trim() : '',
      langName = '',
      highlighted;

  if (info) {
    langName = info.split(/\s+/g)[0];
    token.attrPush([ 'class', options.langPrefix + langName ]);
  }

  if (options.highlight) {
    highlighted = options.highlight(token.content, langName) || escapeHtml(token.content);
  } else {
    highlighted = escapeHtml(token.content);
  }

  return  '
'
        + highlighted
        + '
\n';
};

default_rules.image = function (tokens, idx, options, env, self) {
  var token = tokens[idx];

  // "alt" attr MUST be set, even if empty. Because it's mandatory and
  // should be placed on proper position for tests.
  //
  // Replace content with actual value

  token.attrs[token.attrIndex('alt')][1] =
    self.renderInlineAsText(token.children, options, env);

  return self.renderToken(tokens, idx, options);
};

default_rules.hardbreak = function (tokens, idx, options /*, env */) {
  return options.xhtmlOut ? '
\n' : '
\n';
};
default_rules.softbreak = function (tokens, idx, options /*, env */) {
  return options.breaks ? (options.xhtmlOut ? '
\n' : '
\n') : '\n';
};

default_rules.text = function (tokens, idx /*, options, env */) {
  return escapeHtml(tokens[idx].content);
};

default_rules.html_block = function (tokens, idx /*, options, env */) {
  return tokens[idx].content;
};
default_rules.html_inline = function (tokens, idx /*, options, env */) {
  return tokens[idx].content;
};

/**
 * new Renderer()
 *
 * Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults.
 **/
function Renderer() {

  /**
   * Renderer#rules -> Object
   *
   * Contains render rules for tokens. Can be updated and extended.
   *
   * ##### Example
   *
   * ```javascript
   * var md = require('markdown-it')();
   *
   * md.renderer.rules.strong_open  = function () { return '<b>'; };
   * md.renderer.rules.strong_close = function () { return '</b>'; };
   *
   * var result = md.renderInline(...);
   * ```
   *
   * Each rule is called as independed static function with fixed signature:
   *
   * ```javascript
   * function my_token_render(tokens, idx, options, env, renderer) {
   *   // ...
   *   return renderedHTML;
   * }
   * ```
   *
   * See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js)
   * for more details and examples.
   **/
  this.rules = assign({}, default_rules);
}

/**
 * Renderer.renderAttrs(token) -> String
 *
 * Render token attributes to string.
 **/
Renderer.prototype.renderAttrs = function renderAttrs(token) {
  var i, l, result;

  if (!token.attrs) { return ''; }

  result = '';

  for (i = 0, l = token.attrs.length; i < l; i++) {
    result += ' ' + escapeHtml(token.attrs[i][0]) + '="' + escapeHtml(token.attrs[i][1]) + '"';
  }

  return result;
};

/**
 * Renderer.renderToken(tokens, idx, options) -> String
 * - tokens (Array): list of tokens
 * - idx (Numbed): token index to render
 * - options (Object): params of parser instance
 *
 * Default token renderer. Can be overriden by custom function
 * in [[Renderer#rules]].
 **/
Renderer.prototype.renderToken = function renderToken(tokens, idx, options) {
  var nextToken,
      result = '',
      needLf = false,
      token = tokens[idx];

  // Tight list paragraphs
  if (token.hidden) {
    return '';
  }

  // Insert a newline between hidden paragraph and subsequent opening
  // block-level tag.
  //
  // For example, here we should insert a newline before blockquote:
  //  - a
  //    >
  //
  if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) {
    result += '\n';
  }

  // Add token name, e.g. `<img`
  result += (token.nesting === -1 ? '</' : '<') + token.tag;

  // Encode attributes, e.g. `<img src="foo"`
  result += this.renderAttrs(token);

  // Add a slash for self-closing tags, e.g. `<img src="foo" /`
  if (token.nesting === 0 && options.xhtmlOut) {
    result += ' /';
  }

  // Check if we need to add a newline after this tag
  if (token.block) {
    needLf = true;

    if (token.nesting === 1) {
      if (idx + 1 < tokens.length) {
        nextToken = tokens[idx + 1];

        if (nextToken.type === 'inline' || nextToken.hidden) {
          // Block-level tag containing an inline tag.
          //
          needLf = false;

        } else if (nextToken.nesting === -1 && nextToken.tag === token.tag) {
          // Opening tag + closing tag of the same type. E.g. `<li></li>`.
          //
          needLf = false;
        }
      }
    }
  }

  result += needLf ? '>\n' : '>';

  return result;
};

/**
 * Renderer.renderInline(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to renter
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * The same as [[Renderer.render]], but for single token of `inline` type.
 **/
Renderer.prototype.renderInline = function (tokens, options, env) {
  var type,
      result = '',
      rules = this.rules;

  return tokens.map(function(token, i) {
    type = token.type;

    if (typeof rules[type] !== 'undefined') {
      return rules[type](tokens, i, options, env, this);
    } else {
      return this.renderToken(tokens, i, options);
    }
  }, this);

  for (var i = 0, len = tokens.length; i < len; i++) {
    type = tokens[i].type;

    if (typeof rules[type] !== 'undefined') {
      result += rules[type](tokens, i, options, env, this);
    } else {
      result += this.renderToken(tokens, i, options);
    }
  }

  return result;
};

/** internal
 * Renderer.renderInlineAsText(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to renter
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * Special kludge for image `alt` attributes to conform CommonMark spec.
 * Don't try to use it! Spec requires to show `alt` content with stripped markup,
 * instead of simple escaping.
 **/
Renderer.prototype.renderInlineAsText = function (tokens, options, env) {
  var result = '',
      rules = this.rules;

  for (var i = 0, len = tokens.length; i < len; i++) {
    if (tokens[i].type === 'text') {
      result += rules.text(tokens, i, options, env, this);
    } else if (tokens[i].type === 'image') {
      result += this.renderInlineAsText(tokens[i].children, options, env);
    }
  }

  return result;
};

/**
 * Renderer.render(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to renter
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * Takes token stream and generates HTML. Probably, you will never need to call
 * this method directly.
 **/
Renderer.prototype.render = function (tokens, options, env) {
  return this.renderTokens(tokens, options, env).reduce(function(collector, token) {
    return collector + token;
  }, '');
};

/**
 * Renderer.renderTokens(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to renter
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * Takes token stream and generates html-like tokens. Probably, you will never need to call
 * this method directly.
 **/
Renderer.prototype.renderTokens = function (tokens, options, env) {
  var i, len, type,
      result = '',
      rules = this.rules;

  return tokens.reduce(function(collector, token, i) {
    type = token.type;

    if (type === 'inline') {
      console.log('inline: ', this.renderInline(token.children, options, env));
      return collector.concat(this.renderInline(token.children, options, env));
    } else if (typeof rules[type] !== 'undefined') {
      collector.push(rules[type](tokens, i, options, env, this));
      return collector;
    } else {
      collector.push(this.renderToken(tokens, i, options, env));
      return collector;
    }
  }.bind(this), []);
};

module.exports = Renderer;
<commit_msg>cleaned up the rendered file. Loose code.<commit_after>/**
 * class Renderer
 *
 * Generates HTML from parsed token stream. Each instance has independent
 * copy of rules. Those can be rewritten with ease. Also, you can add new
 * rules if you create plugin and adds new token types.
 **/
'use strict';

var assign          = require('./common/utils').assign;
var unescapeAll     = require('./common/utils').unescapeAll;
var escapeHtml      = require('./common/utils').escapeHtml;

////////////////////////////////////////////////////////////////////////////////

var default_rules = {};

default_rules.code_inline = function (tokens, idx /*, options, env */) {
  return '' + escapeHtml(tokens[idx].content) + '';
};

default_rules.code_block = function (tokens, idx /*, options, env */) {
  return '
' + escapeHtml(tokens[idx].content) + '
\n';
};

default_rules.fence = function (tokens, idx, options, env, self) {
  var token = tokens[idx],
      info = token.info ? unescapeAll(token.info).trim() : '',
      langName = '',
      highlighted;

  if (info) {
    langName = info.split(/\s+/g)[0];
    token.attrPush([ 'class', options.langPrefix + langName ]);
  }

  if (options.highlight) {
    highlighted = options.highlight(token.content, langName) || escapeHtml(token.content);
  } else {
    highlighted = escapeHtml(token.content);
  }

  return  '
'
        + highlighted
        + '
\n';
};

default_rules.image = function (tokens, idx, options, env, self) {
  var token = tokens[idx];

  // "alt" attr MUST be set, even if empty. Because it's mandatory and
  // should be placed on proper position for tests.
  //
  // Replace content with actual value

  token.attrs[token.attrIndex('alt')][1] =
    self.renderInlineAsText(token.children, options, env);

  return self.renderToken(tokens, idx, options);
};

default_rules.hardbreak = function (tokens, idx, options /*, env */) {
  return options.xhtmlOut ? '
\n' : '
\n';
};
default_rules.softbreak = function (tokens, idx, options /*, env */) {
  return options.breaks ? (options.xhtmlOut ? '
\n' : '
\n') : '\n';
};

default_rules.text = function (tokens, idx /*, options, env */) {
  return escapeHtml(tokens[idx].content);
};

default_rules.html_block = function (tokens, idx /*, options, env */) {
  return tokens[idx].content;
};
default_rules.html_inline = function (tokens, idx /*, options, env */) {
  return tokens[idx].content;
};

/**
 * new Renderer()
 *
 * Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults.
 **/
function Renderer() {

  /**
   * Renderer#rules -> Object
   *
   * Contains render rules for tokens. Can be updated and extended.
   *
   * ##### Example
   *
   * ```javascript
   * var md = require('markdown-it')();
   *
   * md.renderer.rules.strong_open  = function () { return '<b>'; };
   * md.renderer.rules.strong_close = function () { return '</b>'; };
   *
   * var result = md.renderInline(...);
   * ```
   *
   * Each rule is called as independed static function with fixed signature:
   *
   * ```javascript
   * function my_token_render(tokens, idx, options, env, renderer) {
   *   // ...
   *   return renderedHTML;
   * }
   * ```
   *
   * See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js)
   * for more details and examples.
   **/
  this.rules = assign({}, default_rules);
}

/**
 * Renderer.renderAttrs(token) -> String
 *
 * Render token attributes to string.
 **/
Renderer.prototype.renderAttrs = function renderAttrs(token) {
  var i, l, result;

  if (!token.attrs) { return ''; }

  result = '';

  for (i = 0, l = token.attrs.length; i < l; i++) {
    result += ' ' + escapeHtml(token.attrs[i][0]) + '="' + escapeHtml(token.attrs[i][1]) + '"';
  }

  return result;
};

/**
 * Renderer.renderToken(tokens, idx, options) -> String
 * - tokens (Array): list of tokens
 * - idx (Numbed): token index to render
 * - options (Object): params of parser instance
 *
 * Default token renderer. Can be overriden by custom function
 * in [[Renderer#rules]].
 **/
Renderer.prototype.renderToken = function renderToken(tokens, idx, options) {
  var nextToken,
      result = '',
      needLf = false,
      token = tokens[idx];

  // Tight list paragraphs
  if (token.hidden) {
    return '';
  }

  // Insert a newline between hidden paragraph and subsequent opening
  // block-level tag.
  //
  // For example, here we should insert a newline before blockquote:
  //  - a
  //    >
  //
  if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) {
    result += '\n';
  }

  // Add token name, e.g. `<img`
  result += (token.nesting === -1 ? '</' : '<') + token.tag;

  // Encode attributes, e.g. `<img src="foo"`
  result += this.renderAttrs(token);

  // Add a slash for self-closing tags, e.g. `<img src="foo" /`
  if (token.nesting === 0 && options.xhtmlOut) {
    result += ' /';
  }

  // Check if we need to add a newline after this tag
  if (token.block) {
    needLf = true;

    if (token.nesting === 1) {
      if (idx + 1 < tokens.length) {
        nextToken = tokens[idx + 1];

        if (nextToken.type === 'inline' || nextToken.hidden) {
          // Block-level tag containing an inline tag.
          //
          needLf = false;

        } else if (nextToken.nesting === -1 && nextToken.tag === token.tag) {
          // Opening tag + closing tag of the same type. E.g. `<li></li>`.
          //
          needLf = false;
        }
      }
    }
  }

  result += needLf ? '>\n' : '>';

  return result;
};

/**
 * Renderer.renderInline(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to renter
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * The same as [[Renderer.render]], but for single token of `inline` type.
 **/
Renderer.prototype.renderInline = function (tokens, options, env) {
  var type,
      result = '',
      rules = this.rules;

  return tokens.map(function(token, i) {
    type = token.type;

    if (typeof rules[type] !== 'undefined') {
      return rules[type](tokens, i, options, env, this);
    } else {
      return this.renderToken(tokens, i, options);
    }
  }, this);
};

/** internal
 * Renderer.renderInlineAsText(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to renter
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * Special kludge for image `alt` attributes to conform CommonMark spec.
 * Don't try to use it! Spec requires to show `alt` content with stripped markup,
 * instead of simple escaping.
 **/
Renderer.prototype.renderInlineAsText = function (tokens, options, env) {
  var result = '',
      rules = this.rules;

  for (var i = 0, len = tokens.length; i < len; i++) {
    if (tokens[i].type === 'text') {
      result += rules.text(tokens, i, options, env, this);
    } else if (tokens[i].type === 'image') {
      result += this.renderInlineAsText(tokens[i].children, options, env);
    }
  }

  return result;
};

/**
 * Renderer.render(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to renter
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * Takes token stream and generates HTML. Probably, you will never need to call
 * this method directly.
 **/
Renderer.prototype.render = function (tokens, options, env) {
  return this.renderTokens(tokens, options, env).reduce(function(collector, token) {
    return collector + token;
  }, '');
};

/**
 * Renderer.renderTokens(tokens, options, env) -> String
 * - tokens (Array): list on block tokens to renter
 * - options (Object): params of parser instance
 * - env (Object): additional data from parsed input (references, for example)
 *
 * Takes token stream and generates html-like tokens. Probably, you will never need to call
 * this method directly.
 **/
Renderer.prototype.renderTokens = function (tokens, options, env) {
  var i, len, type,
      result = '',
      rules = this.rules;

  return tokens.reduce(function(collector, token, i) {
    type = token.type;

    if (type === 'inline') {
      console.log('inline: ', this.renderInline(token.children, options, env));
      return collector.concat(this.renderInline(token.children, options, env));
    } else if (typeof rules[type] !== 'undefined') {
      collector.push(rules[type](tokens, i, options, env, this));
      return collector;
    } else {
      collector.push(this.renderToken(tokens, i, options, env));
      return collector;
    }
  }.bind(this), []);
};

module.exports = Renderer;
<|endoftext|>


<commit_before>'use strict';

var request = require("request");

function Resource(vhx) {
  var _this = this;

  _this._vhx = vhx;
  _this.init();
}

Resource.prototype = {
  init: function() {
    var _this = this;

    _this.methods.forEach(function(method) {
      var http_method = _this.getHTTPMethod(method),
          params = {
            http_method: http_method,
            client_method: method
          };

      if (method.match(/retrieve|update|items|files/)) {
        _this[method] = function(id, options, callback) {
          if (id.id && _this.isFunction(options)) {
            params.callback = options;
            params.id = id.id;
            delete options.id;
            params.options = id;
          }
          else {
            params.id = id;
            if (_this.isFunction(options)) {
              params.callback = options;
            } else {
              params.options = options;
              params.callback = callback;
            }
          }

          _this.makeRequest(params);
        };
      }
      else {
        _this[method] = function(options, callback) {
          params.options = options;
          params.callback = callback;

          _this.makeRequest(params);
        };
      }
    });
  },

  getHTTPMethod: function(method) {
    if (method === 'create') {
      return 'post';
    }
    if (method === 'update') {
      return 'put';
    }
    return 'get';
  },

  getParams: function(client_method, id, options) {
    var _this = this,
        params = {};

    params.url = _this._vhx._api.protocol + _this._vhx._api.host + '/' + _this.path;
    params.timeout = _this._vhx._api.timeout;
    params.headers = {
      'Authorization': _this._vhx._api.auth,
      'User-Agent': 'VHX/v1 NodeJS/'
    };

    if (client_method.match(/create|update/)) {
      params.form = options;
    }
    if (client_method.match(/list|items|retrieve|files/)) {
      params.qs = options;
    }
    if (client_method.match(/retrieve|items|update|files/)) {
      params.url += '/' + id;
    }
    if (client_method.match(/items/)) {
      params.url += '/items';
    }
    if (client_method.match(/files/)) {
      params.url += '/files';
    }

    return params;
  },

  makeRequest: function(args) {
    var _this = this,
        params = _this.getParams(args.client_method, args.id || null, args.options);

    if (_this.isCallbackFunction(args.options)) {
      args.callback = args.options;
    }

    request[args.http_method](params, function (error, response, body) {
      if (error && error.code === 'ETIMEDOUT') {
        _this.errorHandler({
          status: 408,
          body: '{"message": "The request timed out.","documentation_url": "http://dev.vhx.tv/docs/api"}',
          callback: args.callback
        });
      }
      else if (!error && response.statusCode >= 200 && response.statusCode < 300) {
        _this.successHandler({
          body: body || null,
          callback: args.callback
        });
      }
      else {
        _this.errorHandler({
          status: response.statusCode,
          body: body,
          callback: args.callback
        });
      }
    });
  },

  successHandler: function(args) {
    args.callback(false, JSON.parse(args.body));
  },

  errorHandler: function(args) {
    var error = JSON.parse(args.body),
        error_types = {
          400: 'VHXInvalidRequestError',
          401: 'VHXAuthenticationError',
          404: 'VHXResourceNotFound',
          408: 'VHXConnectionError',
          500: 'VHXAPIError'
        };

    error.status = args.status;
    error.type = error_types[error.status];
    args.callback(error, null);
  },

  isCallbackFunction: function(obj) {
    return !!(obj && obj.constructor && obj.call && obj.apply);
  },

  isFunction: function(obj) {
    return !!(obj && obj.constructor && obj.call && obj.apply);
  }
};

Resource.extend = function(sub) {
  var Super = this,
      hasOwn = {}.hasOwnProperty,
      Constructor;

  Constructor = hasOwn.call(sub, 'constructor') ? sub.constructor : function() {
    Super.apply(this, arguments);
  };

  Constructor.prototype = Object.create(Super.prototype);

  for (var i in sub) {
    if (hasOwn.call(sub, i)) {
      Constructor.prototype[i] = sub[i];
    }
  }

  for (i in Super) {
    if (hasOwn.call(Super, i)) {
      Constructor[i] = Super[i];
    }
  }

  return Constructor;
};

module.exports = Resource;
<commit_msg>already have function check for callbacks<commit_after>'use strict';

var request = require("request");

function Resource(vhx) {
  var _this = this;

  _this._vhx = vhx;
  _this.init();
}

Resource.prototype = {
  init: function() {
    var _this = this;

    _this.methods.forEach(function(method) {
      var http_method = _this.getHTTPMethod(method),
          params = {
            http_method: http_method,
            client_method: method
          };

      if (method.match(/retrieve|update|items|files/)) {
        _this[method] = function(id, options, callback) {
          if (id.id && _this.isCallbackFunction(options)) {
            params.callback = options;
            params.id = id.id;
            delete options.id;
            params.options = id;
          }
          else {
            params.id = id;
            if (_this._this.isCallbackFunction(options)) {
              params.callback = options;
            } else {
              params.options = options;
              params.callback = callback;
            }
          }

          _this.makeRequest(params);
        };
      }
      else {
        _this[method] = function(options, callback) {
          params.options = options;
          params.callback = callback;

          _this.makeRequest(params);
        };
      }
    });
  },

  getHTTPMethod: function(method) {
    if (method === 'create') {
      return 'post';
    }
    if (method === 'update') {
      return 'put';
    }
    return 'get';
  },

  getParams: function(client_method, id, options) {
    var _this = this,
        params = {};

    params.url = _this._vhx._api.protocol + _this._vhx._api.host + '/' + _this.path;
    params.timeout = _this._vhx._api.timeout;
    params.headers = {
      'Authorization': _this._vhx._api.auth,
      'User-Agent': 'VHX/v1 NodeJS/'
    };

    if (client_method.match(/create|update/)) {
      params.form = options;
    }
    if (client_method.match(/list|items|retrieve|files/)) {
      params.qs = options;
    }
    if (client_method.match(/retrieve|items|update|files/)) {
      params.url += '/' + id;
    }
    if (client_method.match(/items/)) {
      params.url += '/items';
    }
    if (client_method.match(/files/)) {
      params.url += '/files';
    }

    return params;
  },

  makeRequest: function(args) {
    var _this = this,
        params = _this.getParams(args.client_method, args.id || null, args.options);

    if (_this.isCallbackFunction(args.options)) {
      args.callback = args.options;
    }

    request[args.http_method](params, function (error, response, body) {
      if (error && error.code === 'ETIMEDOUT') {
        _this.errorHandler({
          status: 408,
          body: '{"message": "The request timed out.","documentation_url": "http://dev.vhx.tv/docs/api"}',
          callback: args.callback
        });
      }
      else if (!error && response.statusCode >= 200 && response.statusCode < 300) {
        _this.successHandler({
          body: body || null,
          callback: args.callback
        });
      }
      else {
        _this.errorHandler({
          status: response.statusCode,
          body: body,
          callback: args.callback
        });
      }
    });
  },

  successHandler: function(args) {
    args.callback(false, JSON.parse(args.body));
  },

  errorHandler: function(args) {
    var error = JSON.parse(args.body),
        error_types = {
          400: 'VHXInvalidRequestError',
          401: 'VHXAuthenticationError',
          404: 'VHXResourceNotFound',
          408: 'VHXConnectionError',
          500: 'VHXAPIError'
        };

    error.status = args.status;
    error.type = error_types[error.status];
    args.callback(error, null);
  },

  isCallbackFunction: function(obj) {
    return !!(obj && obj.constructor && obj.call && obj.apply);
  }
};

Resource.extend = function(sub) {
  var Super = this,
      hasOwn = {}.hasOwnProperty,
      Constructor;

  Constructor = hasOwn.call(sub, 'constructor') ? sub.constructor : function() {
    Super.apply(this, arguments);
  };

  Constructor.prototype = Object.create(Super.prototype);

  for (var i in sub) {
    if (hasOwn.call(sub, i)) {
      Constructor.prototype[i] = sub[i];
    }
  }

  for (i in Super) {
    if (hasOwn.call(Super, i)) {
      Constructor[i] = Super[i];
    }
  }

  return Constructor;
};

module.exports = Resource;
<|endoftext|>