<commit_before>var Hand = exports.Hand = function(data) {
  this.id = data.id
  this.palmPosition = data.palmPosition
  this.palmDirection = data.palmDirection
  this.palmVelocity = data.palmVelocity
  this.palmNormal = data.palmNormal
  this.sphereCenter = data.sphereCenter
  this.sphereRadius = data.sphereRadius
  this.valid = true
  this.pointables = []
  this.fingers = []
  this.tools = []
  this._translation = data.t;
  this.rotation = data.r;
  this._scaleFactor = data.s;
  Leap.extend(Hand.prototype, Motion)
}

Hand.prototype.finger = function(id) {
  for ( var i = 0; i < this.fingers.length; i++ ) {
    if (this.fingers[i].id === id) {
      return this.fingers[i];
    }
  }
  Leap.Pointable.Invalid
}

Hand.prototype.toString = function() {
  return "Hand [ id: "+ this.id + " data:"+JSON.stringify(this.data)+"] ";
}

Hand.Invalid = { valid: false }
<commit_msg>added return<commit_after>var Hand = exports.Hand = function(data) {
  this.id = data.id
  this.palmPosition = data.palmPosition
  this.palmDirection = data.palmDirection
  this.palmVelocity = data.palmVelocity
  this.palmNormal = data.palmNormal
  this.sphereCenter = data.sphereCenter
  this.sphereRadius = data.sphereRadius
  this.valid = true
  this.pointables = []
  this.fingers = []
  this.tools = []
  this._translation = data.t;
  this.rotation = data.r;
  this._scaleFactor = data.s;
  Leap.extend(Hand.prototype, Motion)
}

Hand.prototype.finger = function(id) {
  for ( var i = 0; i < this.fingers.length; i++ ) {
    if (this.fingers[i].id === id) {
      return this.fingers[i];
    }
  }
  return Leap.Pointable.Invalid
}

Hand.prototype.toString = function() {
  return "Hand [ id: "+ this.id + " data:"+JSON.stringify(this.data)+"] ";
}

Hand.Invalid = { valid: false }
<|endoftext|>


<commit_before>/**
 * Copyright 2015, Marnus Weststrate
 * Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
 */
'use strict';
var _ = require('lodash');

var updateStrategies = {
  'update-connection': require('./config-strategies/update-connection')
};

/**
 * The hook can be configured by exporting the `modelDefinitions` property on the Sails config object.
 * The exported object will be set as the current configs, so it should be an object of config objects
 * indexed by update config id.
 *
 * @param sails
 * @returns {Object} The Hook definition.
 * @constructor
 */
module.exports = function ModelDefinitionsHook(sails) {

  var modelDefs;
  var configs;

  var updatedDefs = {};

  // Hook Definition
  var ModelDefsHook = {

    defaults: {
      modelDefinitions: {
        transforms: {}
      }
    },

    configure: function() {
      configs = sails.config.modelDefinitions.transforms;
    },

    /**
     * Loads the model definitions after the Sails ORM has loaded. When the ORM is reloaded
     * the model definitions are reloaded here as well.
     * @param done
     */
    initialize: function(done) {
      sails.after('hook:orm:loaded', function() {
        loadModelDefs(done);
      });
      sails.on('hook:orm:reloaded', loadModelDefs);
    },

    /**
     * Get the original model definitions as they were read from disk.
     */
    getModelDefs: function() {
      return modelDefs;
    },

    /**
     * Get the model definitions with the updates associated with `id` applied. If an updated configuration
     * is provided on the second parameter that config will replace any previous configs on this id and the
     * updated results will be according to the new config.
     *
     * @param id The id that will identify these updates in the future.
     * @param [config] The configuration for the update, an object specifying `updateType` and associated options.
     * @returns {Object} The updated model definitions directory.
     */
    getUpdatedDefs: function(id, config) {
      if (config && !_.isEqual(config, configs[id]) || !updatedDefs[id]) {
        updatedDefs[id] = updateStrategies[config.updateType](modelDefs, config);
        configs[id] = config;
      }
      return updatedDefs[id];
    }
  };

  /**
   * Use the Sails.js module loader to load model definitions from disk and then apply any updates
   * configured thus far. Since this is an async operation a callback can be provided as a first
   * argument.
   *
   * @param cb
   */
  function loadModelDefs(cb) {
    sails.modules.loadModels(function(err, models) {
      if (err) {
        return cb && cb(err);
      }

      modelDefs = models;

      Object.keys(configs).forEach(function(id) {
        ModelDefsHook.getUpdatedDefs(id, configs[id]);
      });

      if (cb) {
        cb();
      }
    });
  }

  return ModelDefsHook;
};
<commit_msg>When loading model definitions they are properly merged with sails.config.models.<commit_after>/**
 * Copyright 2015, Marnus Weststrate
 * Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
 */
'use strict';
var _ = require('lodash');

var updateStrategies = {
  'update-connection': require('./config-strategies/update-connection')
};

/**
 * The hook can be configured by exporting the `modelDefinitions` property on the Sails config object.
 * The exported object will be set as the current configs, so it should be an object of config objects
 * indexed by update config id.
 *
 * @param sails
 * @returns {Object} The Hook definition.
 * @constructor
 */
module.exports = function ModelDefinitionsHook(sails) {

  var modelDefs = {};
  var configs;

  var updatedDefs = {};

  // Hook Definition
  var ModelDefsHook = {

    defaults: {
      modelDefinitions: {
        transforms: {}
      }
    },

    configure: function() {
      configs = sails.config.modelDefinitions.transforms;
    },

    /**
     * Loads the model definitions after the Sails ORM has loaded. When the ORM is reloaded
     * the model definitions are reloaded here as well.
     * @param done
     */
    initialize: function(done) {
      sails.after('hook:orm:loaded', function() {
        loadModelDefs(done);
      });
      sails.on('hook:orm:reloaded', loadModelDefs);
    },

    /**
     * Get the original model definitions as they were read from disk.
     */
    getModelDefs: function() {
      return modelDefs;
    },

    /**
     * Get the model definitions with the updates associated with `id` applied. If an updated configuration
     * is provided on the second parameter that config will replace any previous configs on this id and the
     * updated results will be according to the new config.
     *
     * @param id The id that will identify these updates in the future.
     * @param [config] The configuration for the update, an object specifying `updateType` and associated options.
     * @returns {Object} The updated model definitions directory.
     */
    getUpdatedDefs: function(id, config) {
      if (config && !_.isEqual(config, configs[id]) || !updatedDefs[id]) {
        updatedDefs[id] = updateStrategies[config.updateType](modelDefs, config);
        configs[id] = config;
      }
      return updatedDefs[id];
    }
  };

  /**
   * Use the Sails.js module loader to load model definitions from disk and then apply any updates
   * configured thus far. Since this is an async operation a callback can be provided as a first
   * argument.
   *
   * @param cb
   */
  function loadModelDefs(cb) {
    sails.modules.loadModels(function(err, models) {
      if (err) {
        return cb && cb(err);
      }

      Object.keys(models).forEach(function(identity) {
        modelDefs[identity] = _.extend({}, sails.config.models, models[identity]);
      });

      Object.keys(configs).forEach(function(id) {
        ModelDefsHook.getUpdatedDefs(id, configs[id]);
      });

      if (cb) {
        cb();
      }
    });
  }

  return ModelDefsHook;
};
<|endoftext|>


<commit_before>const http = require("http");
const https = require("https");
const parseurl = require("url").parse;
const Stream = require("./stream");
const assign = Object.assign;
const keys = Object.keys;

/**
 * Read header value from headers object.
 * @param {object} headers
 * @param {string} name
 * @returns {string}
 */
function readHeader(headers, name) {
    return keys(headers)
        .filter(key => key.toLowerCase() === name.toLowerCase())
        .map(key => headers[key])
        .join(",");
}

/**
 * Read content type from headers.
 * @param {object} headers
 * @returns {string}
 */
function type(headers) {
    return readHeader(headers, "content-type").split(";")[0];
}

/**
 * Read links from headers.
 * @param {object} headers
 * @returns {object}
 */
function links(headers) {
    var links = {};

    readHeader(headers, "link").split(",")
        .filter(link => link)
        .map(link => /<(.*)>;\s*rel="(.*)"/.exec(link).slice(1,3))
        .forEach(linkinfo => {
            var uri = linkinfo[0],
                rel = linkinfo[1];

            switch (typeof links[rel]) {
                case "undefined": links[rel] = url; break;
                case "string": links[rel] = [links[rel], url]; break;
                case "object": links[rel].push(url); break;
                default: throw new Error("unexpected link type");
            }
        });

    return links;
}

/**
 * Make HTTP request.
 * @param {string} [method]
 * @param {string} url
 * @param {object} [headers]
 * @param {object|string} [body]
 */
function request(method, url, headers, body) {
    var args = Array.prototype.slice.call(arguments);

    switch (args.length) {
        case 0: throw new TypeError("expects string");
        case 1: url = String(method), method = undefined; break;
        case 2:
        case 3: method = typeof args[1] === "string" ? args.shift() : undefined;
                url = args.shift();
                body = args.pop();
                headers = args.shift();
                break;
        case 4: break;
        default: throw new TypeError("unexpected argument");
    }

    body = body || (body === "" ? body : undefined);
    method = method || (body === undefined ? "GET" : "POST");
    url = String(url);
    headers = headers || {};

    if (typeof body === "object" && !type(headers)) {
        headers["content-type"] === "application/json";
    }

    if (typeof body === "object" && type(headers) === "application/json") {
        body = JSON.stringify(body);
    }

    return new Promise((resolve, reject) => {
        var opts = parseurl(url),
            proto = opts.protocol === "https:" ? https : http,
            req;

        opts.method = method;
        opts.headers = headers;

        req = proto.request(opts);
        req.on("error", reject);
        req.on("response", res => {
            Stream.read(res).then(body =>{
                if (type(res.headers) === "application/json") {
                    body = JSON.parse(body);
                }

                resolve(assign(links(res.headers), {
                    status: res.statusCode,
                    headers: res.headers,
                    body: body
                }));
            }).catch(reject);
        });
        req.end(body);
    });
}

/**
 * Make HTTP GET request.
 * @param {string} uri
 * @param {object} [headers]
 * @returns {Promise}
 */
function get(uri, headers) {
    return request("GET", uri, headers, null);
}

/**
 * Make HTTP POST request.
 * @param {string} uri
 * @param {object} [headers]
 * @param {object|string} [body]
 */
function post(uri, headers, body) {
    return request("POST", uri, headers, body);
}

/**
 * Make HTTP DELETE request.
 * @param {string} uri
 * @param {object} [headers]
 */
function delete_(uri, headers) {
    return request("DELETE", uri, headers, null);
}

/**
 * Make HTTP PATCH request.
 * @param {string} uri
 * @param {object} [headers]
 * @param {object|string} [body]
 */
function patch(uri, headers, body) {
    return request("PATCH", uri, headers, body);
}

/**
 * Create headers object with User-Agent.
 * @param {string} agent
 * @returns {object}
 */
function ua(agent) {
    return {"User-Agent": agent ? String(agent) : ""};
}

/**
 * Create headers object with Authorization header.
 * @param {string} ident
 * @param {string} secret
 * @returns {object}
 */
function basic(ident, secret) {
    var creds = new Buffer(`${ident}:${secret}`).toString("base64");
    return {Authorization: `Basic ${creds}`};
}

module.exports = {
    request: request,
    get: get,
    post: post,
    delete: delete_,
    patch: patch,
    type: type,
    links: links,
    ua: ua,
    basic: basic
};
<commit_msg>fix equality test which should be assignment<commit_after>const http = require("http");
const https = require("https");
const parseurl = require("url").parse;
const Stream = require("./stream");
const assign = Object.assign;
const keys = Object.keys;

/**
 * Read header value from headers object.
 * @param {object} headers
 * @param {string} name
 * @returns {string}
 */
function readHeader(headers, name) {
    return keys(headers)
        .filter(key => key.toLowerCase() === name.toLowerCase())
        .map(key => headers[key])
        .join(",");
}

/**
 * Read content type from headers.
 * @param {object} headers
 * @returns {string}
 */
function type(headers) {
    return readHeader(headers, "content-type").split(";")[0];
}

/**
 * Read links from headers.
 * @param {object} headers
 * @returns {object}
 */
function links(headers) {
    var links = {};

    readHeader(headers, "link").split(",")
        .filter(link => link)
        .map(link => /<(.*)>;\s*rel="(.*)"/.exec(link).slice(1,3))
        .forEach(linkinfo => {
            var uri = linkinfo[0],
                rel = linkinfo[1];

            switch (typeof links[rel]) {
                case "undefined": links[rel] = url; break;
                case "string": links[rel] = [links[rel], url]; break;
                case "object": links[rel].push(url); break;
                default: throw new Error("unexpected link type");
            }
        });

    return links;
}

/**
 * Make HTTP request.
 * @param {string} [method]
 * @param {string} url
 * @param {object} [headers]
 * @param {object|string} [body]
 */
function request(method, url, headers, body) {
    var args = Array.prototype.slice.call(arguments);

    switch (args.length) {
        case 0: throw new TypeError("expects string");
        case 1: url = String(method), method = undefined; break;
        case 2:
        case 3: method = typeof args[1] === "string" ? args.shift() : undefined;
                url = args.shift();
                body = args.pop();
                headers = args.shift();
                break;
        case 4: break;
        default: throw new TypeError("unexpected argument");
    }

    body = body || (body === "" ? body : undefined);
    method = method || (body === undefined ? "GET" : "POST");
    url = String(url);
    headers = headers || {};

    if (typeof body === "object" && !type(headers)) {
        headers["content-type"] = "application/json";
    }

    if (typeof body === "object" && type(headers) === "application/json") {
        body = JSON.stringify(body);
    }

    return new Promise((resolve, reject) => {
        var opts = parseurl(url),
            proto = opts.protocol === "https:" ? https : http,
            req;

        opts.method = method;
        opts.headers = headers;

        req = proto.request(opts);
        req.on("error", reject);
        req.on("response", res => {
            Stream.read(res).then(body =>{
                if (type(res.headers) === "application/json") {
                    body = JSON.parse(body);
                }

                resolve(assign(links(res.headers), {
                    status: res.statusCode,
                    headers: res.headers,
                    body: body
                }));
            }).catch(reject);
        });
        req.end(body);
    });
}

/**
 * Make HTTP GET request.
 * @param {string} uri
 * @param {object} [headers]
 * @returns {Promise}
 */
function get(uri, headers) {
    return request("GET", uri, headers, null);
}

/**
 * Make HTTP POST request.
 * @param {string} uri
 * @param {object} [headers]
 * @param {object|string} [body]
 */
function post(uri, headers, body) {
    return request("POST", uri, headers, body);
}

/**
 * Make HTTP DELETE request.
 * @param {string} uri
 * @param {object} [headers]
 */
function delete_(uri, headers) {
    return request("DELETE", uri, headers, null);
}

/**
 * Make HTTP PATCH request.
 * @param {string} uri
 * @param {object} [headers]
 * @param {object|string} [body]
 */
function patch(uri, headers, body) {
    return request("PATCH", uri, headers, body);
}

/**
 * Create headers object with User-Agent.
 * @param {string} agent
 * @returns {object}
 */
function ua(agent) {
    return {"User-Agent": agent ? String(agent) : ""};
}

/**
 * Create headers object with Authorization header.
 * @param {string} ident
 * @param {string} secret
 * @returns {object}
 */
function basic(ident, secret) {
    var creds = new Buffer(`${ident}:${secret}`).toString("base64");
    return {Authorization: `Basic ${creds}`};
}

module.exports = {
    request: request,
    get: get,
    post: post,
    delete: delete_,
    patch: patch,
    type: type,
    links: links,
    ua: ua,
    basic: basic
};
<|endoftext|>


<commit_before>/**
 * Localization!
 *
 */
var Vue = require('vue');

function Localize () {
    var self = this;

    self.defaultLang = 'en-US';

    self.currentLang = '';
    self.dictionary =  {};
    self.dictionaries = {};
    self.url = '';

    self.bind = function (langs, vue) {
        var html = document.querySelector('html');
        self.dictionaries = langs;
        self.currentLang = navigator.language || navigator.userLanguage || self.defaultLang;
        console.log(navigator.language);
        self.dictionary = self. dictionaries[self.currentLang] || self.dictionaries[self.defaultLang];
        if (html) {
            html.setAttribute('lang', self.currentLang);
        }

        // Bind directives/filters
        if (vue) {
            vue.filter('i18n', self.i18nFilter);
            vue.directive('bind-html', self.bindHtml);
        }
    };

    self.get = function (key) {
        return self.dictionary[key] || self.dictionaries[self.defaultLang][key] || key;
    };

    self.i18nFilter = function (key) {
        return self.get(key);
    };

    self.bindHtml = function (key) {
        var raw = self.get(key);
        var compiler = this.compiler;
        this.el.innerHTML = raw;
    };
}

module.exports = new Localize();
<commit_msg>spooflocale<commit_after>/**
 * Localization!
 *
 */
var Vue = require('vue');

function Localize () {
    var self = this;

    self.defaultLang = 'en-US';

    self.currentLang = '';
    self.dictionary =  {};
    self.dictionaries = {};
    self.url = '';

    self.bind = function (langs, vue) {
        var html = document.querySelector('html');
        self.dictionaries = langs;
        // Spoof because navigator.language sucks
        function getLocaleFromQueryString() {
            var regex = new RegExp("[\\?&]locale=([^&#]*)");
            var results = regex.exec(location.search);
            return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
        }
        var spoofLocale = getLocaleFromQueryString();
        self.currentLang = spoofLocale || navigator.language || self.defaultLang;

        self.dictionary = self. dictionaries[self.currentLang] || self.dictionaries[self.defaultLang];
        if (html) {
            html.setAttribute('lang', self.currentLang);
        }

        // Bind directives/filters
        if (vue) {
            vue.filter('i18n', self.i18nFilter);
            vue.directive('bind-html', self.bindHtml);
        }
    };

    self.get = function (key) {
        return self.dictionary[key] || self.dictionaries[self.defaultLang][key] || key;
    };

    self.i18nFilter = function (key) {
        return self.get(key);
    };

    self.bindHtml = function (key) {
        var raw = self.get(key);
        var compiler = this.compiler;
        this.el.innerHTML = raw;
    };
}

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


<commit_before>const urllib      = require('url');
const querystring = require('querystring');
const sax         = require('sax');
const request     = require('miniget');
const util        = require('./util');
const sig         = require('./sig');
const FORMATS     = require('./formats');

const VIDEO_URL = 'https://www.youtube.com/watch?v=';
const EMBED_URL = 'https://www.youtube.com/embed/';
const VIDEO_EURL = 'https://youtube.googleapis.com/v/';
const INFO_HOST = 'www.youtube.com';
const INFO_PATH = '/get_video_info';
const KEYS_TO_SPLIT = [
  'keywords',
  'fmt_list',
  'fexp',
  'watermark'
];

/**
 * Gets info from a video.
 *
 * @param {String} link
 * @param {Object} options
 * @param {Function(Error, Object)} callback
 */
module.exports = function getInfo(link, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = {};
  } else if (!options) {
    options = {};
  }
  if (!callback) {
    return new Promise((resolve, reject) => {
      getInfo(link, options, (err, info) => {
        if (err) return reject(err);
        resolve(info);
      });
    });
  }

  var id = util.getVideoID(link);
  if (id instanceof Error) return callback(id);

  // Try getting config from the video page first.
  var params = 'hl=' + (options.lang || 'en');
  var url = VIDEO_URL + id + '&' + params;

  request(url, options.requestOptions, (err, res, body) => {
    if (err) return callback(err);

    // Check if there are any errors with this video page.
    var unavailableMsg = util.between(body, '
');
    if (unavailableMsg &&
        !/\bhid\b/.test(util.between(unavailableMsg, 'class="', '"'))) {
      // Ignore error about age restriction.
      if (!body.includes('<div id="watch7-player-age-gate-content"')) {
        return callback(new Error(util.between(body,
          '
', '
').trim()));
      }
    }

    // Parse out additional metadata from this page.
    var additional = {
      // Get the author/uploader.
      author: util.getAuthor(body),

      // Get the day the vid was published.
      published: util.getPublished(body),

      // Get description.
      description: util.getVideoDescription(body),

      // Get related videos.
      related_videos: util.getRelatedVideos(body),

      // Give the standard link to the video.
      video_url: VIDEO_URL + id,
    };

    var jsonStr = util.between(body, 'ytplayer.config = ', '</script>');
    var config;
    if (jsonStr) {
      config = jsonStr.slice(0, jsonStr.lastIndexOf(';ytplayer.load'));
      gotConfig(id, options, additional, config, false, callback);

    } else {
      // If the video page doesn't work, maybe because it has mature content.
      // and requires an account logged in to view, try the embed page.
      url = EMBED_URL + id + '?' + params;
      request(url, options.requestOptions, (err, res, body) => {
        if (err) return callback(err);
        config = util.between(body, 't.setConfig({\'PLAYER_CONFIG\': ', '},\'');
        gotConfig(id, options, additional, config, true, callback);
      });
    }
  });
};

/**
 * @param {Object} id
 * @param {Object} options
 * @param {Object} additional
 * @param {Object} config
 * @param {Boolean} fromEmbed
 * @param {Function(Error, Object)} callback
 */
function gotConfig(id, options, additional, config, fromEmbed, callback) {
  if (!config) {
    return callback(new Error('Could not find player config'));
  }
  try {
    config = JSON.parse(config + (fromEmbed ? '}' : ''));
  } catch (err) {
    return callback(new Error('Error parsing config: ' + err.message));
  }
  var url = urllib.format({
    protocol: 'https',
    host: INFO_HOST,
    pathname: INFO_PATH,
    query: {
      video_id: id,
      eurl: VIDEO_EURL + id,
      ps: 'default',
      gl: 'US',
      hl: (options.lang || 'en'),
      sts: config.sts,
    },
  });
  request(url, options.requestOptions, (err, res, body) => {
    if (err) return callback(err);
    var info = querystring.parse(body);
    if (info.requires_purchase === '1') {
      return callback(new Error('Video requires purchase'));
    } else if (info.status === 'fail') {
      if (info.errorcode === '150' && config.args) {
        info = config.args;
      } else {
        return callback(
          new Error(`Code ${info.errorcode}: ${util.stripHTML(info.reason)}`));
      }
    }

    // Split some keys by commas.
    KEYS_TO_SPLIT.forEach((key) => {
      if (!info[key]) return;
      info[key] = info[key]
        .split(',')
        .filter((v) => v !== '');
    });

    if (config.args.player_response) {
      try {
        info.player_response = JSON.parse(config.args.player_response);
      } catch (err) {
        return callback(
          new Error('Error parsing `player_response`: ' + err.message));
      }
    }

    info.fmt_list = info.fmt_list ?
      info.fmt_list.map((format) => format.split('/')) : [];

    info.formats = util.parseFormats(info);

    // Add additional properties to info.
    Object.assign(info, additional);

    if (info.formats.length ||
        config.args.dashmpd || info.dashmpd || info.hlsvp) {
      var html5playerfile = urllib.resolve(VIDEO_URL, config.assets.js);
      sig.getTokens(html5playerfile, options, (err, tokens) => {
        if (err) return callback(err);

        sig.decipherFormats(info.formats, tokens, options.debug);

        var funcs = [];

        if (config.args.dashmpd) {
          let dashmpd = decipherURL(config.args.dashmpd, tokens);
          funcs.push(getDashManifest.bind(null, dashmpd, options));
        }

        if (info.dashmpd && info.dashmpd !== config.args.dashmpd) {
          let dashmpd = decipherURL(info.dashmpd, tokens);
          funcs.push(getDashManifest.bind(null, dashmpd, options));
        }

        if (info.hlsvp) {
          info.hlsvp = decipherURL(info.hlsvp, tokens);
          funcs.push(getM3U8.bind(null, info.hlsvp, options));
        }

        util.parallel(funcs, (err, results) => {
          if (err) return callback(err);
          if (results[0]) { mergeFormats(info, results[0]); }
          if (results[1]) { mergeFormats(info, results[1]); }
          if (results[2]) { mergeFormats(info, results[2]); }
          if (!info.formats.length) {
            callback(new Error('No formats found'));
            return;
          }

          if (options.debug) {
            info.formats.forEach((format) => {
              var itag = format.itag;
              if (!FORMATS[itag]) {
                console.warn(`No format metadata for itag ${itag} found`);
              }
            });
          }

          info.formats.forEach(util.addFormatMeta);
          info.formats.sort(util.sortFormats);
          callback(null, info);

        });
      });
    } else {
      callback(new Error('This video is unavailable'));
    }
  });
}

/**
 * @param {String} url
 * @param {Array.<String>} tokens
 */
function decipherURL(url, tokens) {
  return url.replace(/\/s\/([a-fA-F0-9.]+)/, (_, s) => {
    return '/signature/' + sig.decipher(tokens, s);
  });
}

/**
 * Merges formats from DASH or M3U8 with formats from video info page.
 *
 * @param {Object} info
 * @param {Object} formatsMap
 */
function mergeFormats(info, formatsMap) {
  info.formats.forEach((f) => {
    var cf = formatsMap[f.itag];
    if (cf) {
      for (let key in f) { cf[key] = f[key]; }
    } else {
      formatsMap[f.itag] = f;
    }
  });
  info.formats = [];
  for (let itag in formatsMap) { info.formats.push(formatsMap[itag]); }
}

/**
 * Gets additional DASH formats.
 *
 * @param {String} url
 * @param {Object} options
 * @param {Function(!Error, Array.<Object>)} callback
 */
function getDashManifest(url, options, callback) {
  var formats = {};
  var currentFormat = null;
  var expectUrl = false;

  var parser = sax.parser(false);
  parser.onerror = callback;
  parser.onopentag = (node) => {
    if (node.name === 'REPRESENTATION') {
      var itag = node.attributes.ID;
      currentFormat = { itag: itag };
      formats[itag] = currentFormat;
    }
    expectUrl = node.name === 'BASEURL';
  };
  parser.ontext = (text) => {
    if (expectUrl) {
      currentFormat.url = text;
    }
  };
  parser.onend = () => { callback(null, formats); };

  var req = request(urllib.resolve(VIDEO_URL, url), options.requestOptions);
  req.setEncoding('utf8');
  req.on('error', callback);
  req.on('data', (chunk) => { parser.write(chunk); });
  req.on('end', parser.close.bind(parser));
}

/**
 * Gets additional formats.
 *
 * @param {String} url
 * @param {Object} options
 * @param {Function(!Error, Array.<Object>)} callback
 */
function getM3U8(url, options, callback) {
  url = urllib.resolve(VIDEO_URL, url);
  request(url, options.requestOptions, (err, res, body) => {
    if (err) return callback(err);

    var formats = {};
    body
      .split('\n')
      .filter((line) => /https?:\/\//.test(line))
      .forEach((line) => {
        var itag = line.match(/\/itag\/(\d+)\//)[1];
        formats[itag] = { itag: itag, url: line };
      });
    callback(null, formats);
  });
}
<commit_msg>fix: parse `player_response` in age restricted videos<commit_after>const urllib      = require('url');
const querystring = require('querystring');
const sax         = require('sax');
const request     = require('miniget');
const util        = require('./util');
const sig         = require('./sig');
const FORMATS     = require('./formats');

const VIDEO_URL = 'https://www.youtube.com/watch?v=';
const EMBED_URL = 'https://www.youtube.com/embed/';
const VIDEO_EURL = 'https://youtube.googleapis.com/v/';
const INFO_HOST = 'www.youtube.com';
const INFO_PATH = '/get_video_info';
const KEYS_TO_SPLIT = [
  'keywords',
  'fmt_list',
  'fexp',
  'watermark'
];

/**
 * Gets info from a video.
 *
 * @param {String} link
 * @param {Object} options
 * @param {Function(Error, Object)} callback
 */
module.exports = function getInfo(link, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = {};
  } else if (!options) {
    options = {};
  }
  if (!callback) {
    return new Promise((resolve, reject) => {
      getInfo(link, options, (err, info) => {
        if (err) return reject(err);
        resolve(info);
      });
    });
  }

  var id = util.getVideoID(link);
  if (id instanceof Error) return callback(id);

  // Try getting config from the video page first.
  var params = 'hl=' + (options.lang || 'en');
  var url = VIDEO_URL + id + '&' + params;

  request(url, options.requestOptions, (err, res, body) => {
    if (err) return callback(err);

    // Check if there are any errors with this video page.
    var unavailableMsg = util.between(body, '
');
    if (unavailableMsg &&
        !/\bhid\b/.test(util.between(unavailableMsg, 'class="', '"'))) {
      // Ignore error about age restriction.
      if (!body.includes('<div id="watch7-player-age-gate-content"')) {
        return callback(new Error(util.between(body,
          '
', '
').trim()));
      }
    }

    // Parse out additional metadata from this page.
    var additional = {
      // Get the author/uploader.
      author: util.getAuthor(body),

      // Get the day the vid was published.
      published: util.getPublished(body),

      // Get description.
      description: util.getVideoDescription(body),

      // Get related videos.
      related_videos: util.getRelatedVideos(body),

      // Give the standard link to the video.
      video_url: VIDEO_URL + id,
    };

    var jsonStr = util.between(body, 'ytplayer.config = ', '</script>');
    var config;
    if (jsonStr) {
      config = jsonStr.slice(0, jsonStr.lastIndexOf(';ytplayer.load'));
      gotConfig(id, options, additional, config, false, callback);

    } else {
      // If the video page doesn't work, maybe because it has mature content.
      // and requires an account logged in to view, try the embed page.
      url = EMBED_URL + id + '?' + params;
      request(url, options.requestOptions, (err, res, body) => {
        if (err) return callback(err);
        config = util.between(body, 't.setConfig({\'PLAYER_CONFIG\': ', '},\'');
        gotConfig(id, options, additional, config, true, callback);
      });
    }
  });
};

/**
 * @param {Object} id
 * @param {Object} options
 * @param {Object} additional
 * @param {Object} config
 * @param {Boolean} fromEmbed
 * @param {Function(Error, Object)} callback
 */
function gotConfig(id, options, additional, config, fromEmbed, callback) {
  if (!config) {
    return callback(new Error('Could not find player config'));
  }
  try {
    config = JSON.parse(config + (fromEmbed ? '}' : ''));
  } catch (err) {
    return callback(new Error('Error parsing config: ' + err.message));
  }
  var url = urllib.format({
    protocol: 'https',
    host: INFO_HOST,
    pathname: INFO_PATH,
    query: {
      video_id: id,
      eurl: VIDEO_EURL + id,
      ps: 'default',
      gl: 'US',
      hl: (options.lang || 'en'),
      sts: config.sts,
    },
  });
  request(url, options.requestOptions, (err, res, body) => {
    if (err) return callback(err);
    var info = querystring.parse(body);
    if (info.requires_purchase === '1') {
      return callback(new Error('Video requires purchase'));
    } else if (info.status === 'fail') {
      if (info.errorcode === '150' && config.args) {
        info = config.args;
      } else {
        return callback(
          new Error(`Code ${info.errorcode}: ${util.stripHTML(info.reason)}`));
      }
    }

    // Split some keys by commas.
    KEYS_TO_SPLIT.forEach((key) => {
      if (!info[key]) return;
      info[key] = info[key]
        .split(',')
        .filter((v) => v !== '');
    });

    var player_response = config.args.player_response || info.player_response;
    if (player_response) {
      try {
        info.player_response = JSON.parse(player_response);
      } catch (err) {
        return callback(
          new Error('Error parsing `player_response`: ' + err.message));
      }
    }

    info.fmt_list = info.fmt_list ?
      info.fmt_list.map((format) => format.split('/')) : [];

    info.formats = util.parseFormats(info);

    // Add additional properties to info.
    Object.assign(info, additional);

    if (info.formats.length ||
        config.args.dashmpd || info.dashmpd || info.hlsvp) {
      var html5playerfile = urllib.resolve(VIDEO_URL, config.assets.js);
      sig.getTokens(html5playerfile, options, (err, tokens) => {
        if (err) return callback(err);

        sig.decipherFormats(info.formats, tokens, options.debug);

        var funcs = [];

        if (config.args.dashmpd) {
          let dashmpd = decipherURL(config.args.dashmpd, tokens);
          funcs.push(getDashManifest.bind(null, dashmpd, options));
        }

        if (info.dashmpd && info.dashmpd !== config.args.dashmpd) {
          let dashmpd = decipherURL(info.dashmpd, tokens);
          funcs.push(getDashManifest.bind(null, dashmpd, options));
        }

        if (info.hlsvp) {
          info.hlsvp = decipherURL(info.hlsvp, tokens);
          funcs.push(getM3U8.bind(null, info.hlsvp, options));
        }

        util.parallel(funcs, (err, results) => {
          if (err) return callback(err);
          if (results[0]) { mergeFormats(info, results[0]); }
          if (results[1]) { mergeFormats(info, results[1]); }
          if (results[2]) { mergeFormats(info, results[2]); }
          if (!info.formats.length) {
            callback(new Error('No formats found'));
            return;
          }

          if (options.debug) {
            info.formats.forEach((format) => {
              var itag = format.itag;
              if (!FORMATS[itag]) {
                console.warn(`No format metadata for itag ${itag} found`);
              }
            });
          }

          info.formats.forEach(util.addFormatMeta);
          info.formats.sort(util.sortFormats);
          callback(null, info);

        });
      });
    } else {
      callback(new Error('This video is unavailable'));
    }
  });
}

/**
 * @param {String} url
 * @param {Array.<String>} tokens
 */
function decipherURL(url, tokens) {
  return url.replace(/\/s\/([a-fA-F0-9.]+)/, (_, s) => {
    return '/signature/' + sig.decipher(tokens, s);
  });
}

/**
 * Merges formats from DASH or M3U8 with formats from video info page.
 *
 * @param {Object} info
 * @param {Object} formatsMap
 */
function mergeFormats(info, formatsMap) {
  info.formats.forEach((f) => {
    var cf = formatsMap[f.itag];
    if (cf) {
      for (let key in f) { cf[key] = f[key]; }
    } else {
      formatsMap[f.itag] = f;
    }
  });
  info.formats = [];
  for (let itag in formatsMap) { info.formats.push(formatsMap[itag]); }
}

/**
 * Gets additional DASH formats.
 *
 * @param {String} url
 * @param {Object} options
 * @param {Function(!Error, Array.<Object>)} callback
 */
function getDashManifest(url, options, callback) {
  var formats = {};
  var currentFormat = null;
  var expectUrl = false;

  var parser = sax.parser(false);
  parser.onerror = callback;
  parser.onopentag = (node) => {
    if (node.name === 'REPRESENTATION') {
      var itag = node.attributes.ID;
      currentFormat = { itag: itag };
      formats[itag] = currentFormat;
    }
    expectUrl = node.name === 'BASEURL';
  };
  parser.ontext = (text) => {
    if (expectUrl) {
      currentFormat.url = text;
    }
  };
  parser.onend = () => { callback(null, formats); };

  var req = request(urllib.resolve(VIDEO_URL, url), options.requestOptions);
  req.setEncoding('utf8');
  req.on('error', callback);
  req.on('data', (chunk) => { parser.write(chunk); });
  req.on('end', parser.close.bind(parser));
}

/**
 * Gets additional formats.
 *
 * @param {String} url
 * @param {Object} options
 * @param {Function(!Error, Array.<Object>)} callback
 */
function getM3U8(url, options, callback) {
  url = urllib.resolve(VIDEO_URL, url);
  request(url, options.requestOptions, (err, res, body) => {
    if (err) return callback(err);

    var formats = {};
    body
      .split('\n')
      .filter((line) => /https?:\/\//.test(line))
      .forEach((line) => {
        var itag = line.match(/\/itag\/(\d+)\//)[1];
        formats[itag] = { itag: itag, url: line };
      });
    callback(null, formats);
  });
}
<|endoftext|>


<commit_before>var path = require('path');
/**
 * Create npm object for options
 */
module.exports = function (shipit) {
  shipit.currentPath = path.join(shipit.config.deployTo, 'current');
  shipit.config.npm = shipit.config.npm || {};
  shipit.config.npm.remote = shipit.config.npm.remote || true;
  shipit.config.npm.installArgs = shipit.config.npm.installArgs || [];
  shipit.config.npm.installFlags = shipit.config.npm.installFlags || [];
  //shipit.config.npm.installOn = shipit.config.npm.installOn || 'updated';
  return shipit;
};
<commit_msg>removed yet to be built feature<commit_after>var path = require('path');
/**
 * Create npm object for options
 */
module.exports = function (shipit) {
  shipit.currentPath = path.join(shipit.config.deployTo, 'current');
  shipit.config.npm = shipit.config.npm || {};
  shipit.config.npm.remote = shipit.config.npm.remote || true;
  shipit.config.npm.installArgs = shipit.config.npm.installArgs || [];
  shipit.config.npm.installFlags = shipit.config.npm.installFlags || [];
  return shipit;
};
<|endoftext|>


<commit_before>'use babel';

// eslint-disable-next-line import/no-extraneous-dependencies, import/extensions
import { CompositeDisposable } from 'atom';
import path from 'path';
import tmp from 'tmp';

export default {
  config: {
    executablePath: {
      type: 'string',
      default: '',
    },
    includeDirs: {
      type: 'array',
      default: [],
      items: {
        type: 'string',
      },
    },
    pa: {
      type: 'array',
      default: [],
      items: {
        type: 'string',
      },
    },
  },

  activate() {
    require('atom-package-deps').install();
    this.subscriptions = new CompositeDisposable();

    this.subscriptions.add(
      atom.config.observe('linter-erlc.executablePath', (executablePath) => {
        this.executablePath = executablePath;
      }),
    );

    this.subscriptions.add(
      atom.config.observe('linter-erlc.pa', (pa) => {
        this.erlcPa = pa;
      }),
    );

    this.subscriptions.add(
      atom.config.observe('linter-erlc.includeDirs', (includeDirs) => {
        this.erlcIncludeDirs = includeDirs;
      }),
    );
  },

  deactivate() {
    this.subscriptions.dispose();
  },

  provideLinter() {
    const helpers = require('atom-linter');
    return {
      name: 'erlc',
      grammarScopes: ['source.erlang'],
      scope: 'file',
      lintOnFly: false,
      lint: (textEditor) => {
        const tmpPathObj = tmp.dirSync({ unsafeCleanup: true });
        const filePath = textEditor.getPath();
        const args = ['-Wall', '-v', '-o', tmpPathObj.name];
        let projectPath = null;

        if (!filePath.match(/\.erl$/)) {
            return;
        }

        this.erlcPa.forEach((paPath) => {
          args.push('-pa');
          args.push(paPath);
        });

        const dirName = path.basename(path.dirname(filePath));
        if (dirName === 'src' | dirName === 'test') {
          projectPath = path.dirname(path.dirname(filePath));
        }

        this.erlcIncludeDirs.forEach((includePath) => {
          args.push('-I');
          if (projectPath && !includePath.match(/^\//)) {
            args.push(path.join(projectPath, includePath));
          } else {
            args.push(includePath);
          }
        });

        args.push(filePath);

        return helpers.exec(this.executablePath, args, { ignoreExitCode: true }).then((result) => {
          const toReturn = [];
          const patterns = [
            {
              regex: /(.+):(\d+):\s(.+)/,
              cb: m => ({ lineNo: m[2], text: m[3] }),
            },
            {
              regex: /(.+): (.+)/,
              cb: m => ({ lineNo: 1, text: m[2] }),
            },
          ];
          const lines = result.split('\n');
          const sourceLines = textEditor.getBuffer().getLines();
          for (const line of lines) {
            if (!line) {
              continue;
            }

            const matches = patterns.map((x) => {
              const match = line.match(x.regex);
              return match ? x.cb(match) : null;
            });
            const match = matches[0];
            const lineNo = Number.parseInt(match.lineNo, 10) - 1;
            let message = match.text;
            let type;
            if (message.match(/Warning:/)) {
              message = message.replace(/Warning: (.+)/, '$1');
              type = 'Warning';
            } else {
              type = 'Error';
            }

            const beforeMatch = message.match(/before: '?(.+?)'?/);
            const unUsedMatch = message.match(/variable '(.+)' is unused/);
            const sourceLine = sourceLines[lineNo];
            let column1 = 0;
            let column2 = sourceLine.length;
            if (beforeMatch) {
              column2 = sourceLine.lastIndexOf(beforeMatch[1]);
            } else if (unUsedMatch) {
              column1 = sourceLine.indexOf(unUsedMatch[1]);
              column2 = column1 + unUsedMatch[1].length;
            }

            toReturn.push({
              type,
              text: message,
              range: [[lineNo, column1], [lineNo, column2]],
              filePath,
            });
          }
          tmpPathObj.removeCallback();
          return toReturn;
        });
      },
    };
  },
};
<commit_msg>Properly return an empty array for unsupported files<commit_after>'use babel';

// eslint-disable-next-line import/no-extraneous-dependencies, import/extensions
import { CompositeDisposable } from 'atom';
import path from 'path';
import tmp from 'tmp';

export default {
  config: {
    executablePath: {
      type: 'string',
      default: '',
    },
    includeDirs: {
      type: 'array',
      default: [],
      items: {
        type: 'string',
      },
    },
    pa: {
      type: 'array',
      default: [],
      items: {
        type: 'string',
      },
    },
  },

  activate() {
    require('atom-package-deps').install();
    this.subscriptions = new CompositeDisposable();

    this.subscriptions.add(
      atom.config.observe('linter-erlc.executablePath', (executablePath) => {
        this.executablePath = executablePath;
      }),
    );

    this.subscriptions.add(
      atom.config.observe('linter-erlc.pa', (pa) => {
        this.erlcPa = pa;
      }),
    );

    this.subscriptions.add(
      atom.config.observe('linter-erlc.includeDirs', (includeDirs) => {
        this.erlcIncludeDirs = includeDirs;
      }),
    );
  },

  deactivate() {
    this.subscriptions.dispose();
  },

  provideLinter() {
    const helpers = require('atom-linter');
    return {
      name: 'erlc',
      grammarScopes: ['source.erlang'],
      scope: 'file',
      lintOnFly: false,
      lint: (textEditor) => {
        const tmpPathObj = tmp.dirSync({ unsafeCleanup: true });
        const filePath = textEditor.getPath();
        const args = ['-Wall', '-v', '-o', tmpPathObj.name];
        let projectPath = null;

        if (!filePath.match(/\.erl$/)) {
          return [];
        }

        this.erlcPa.forEach((paPath) => {
          args.push('-pa');
          args.push(paPath);
        });

        const dirName = path.basename(path.dirname(filePath));
        if (dirName === 'src' | dirName === 'test') {
          projectPath = path.dirname(path.dirname(filePath));
        }

        this.erlcIncludeDirs.forEach((includePath) => {
          args.push('-I');
          if (projectPath && !includePath.match(/^\//)) {
            args.push(path.join(projectPath, includePath));
          } else {
            args.push(includePath);
          }
        });

        args.push(filePath);

        return helpers.exec(this.executablePath, args, { ignoreExitCode: true }).then((result) => {
          const toReturn = [];
          const patterns = [
            {
              regex: /(.+):(\d+):\s(.+)/,
              cb: m => ({ lineNo: m[2], text: m[3] }),
            },
            {
              regex: /(.+): (.+)/,
              cb: m => ({ lineNo: 1, text: m[2] }),
            },
          ];
          const lines = result.split('\n');
          const sourceLines = textEditor.getBuffer().getLines();
          for (const line of lines) {
            if (!line) {
              continue;
            }

            const matches = patterns.map((x) => {
              const match = line.match(x.regex);
              return match ? x.cb(match) : null;
            });
            const match = matches[0];
            const lineNo = Number.parseInt(match.lineNo, 10) - 1;
            let message = match.text;
            let type;
            if (message.match(/Warning:/)) {
              message = message.replace(/Warning: (.+)/, '$1');
              type = 'Warning';
            } else {
              type = 'Error';
            }

            const beforeMatch = message.match(/before: '?(.+?)'?/);
            const unUsedMatch = message.match(/variable '(.+)' is unused/);
            const sourceLine = sourceLines[lineNo];
            let column1 = 0;
            let column2 = sourceLine.length;
            if (beforeMatch) {
              column2 = sourceLine.lastIndexOf(beforeMatch[1]);
            } else if (unUsedMatch) {
              column1 = sourceLine.indexOf(unUsedMatch[1]);
              column2 = column1 + unUsedMatch[1].length;
            }

            toReturn.push({
              type,
              text: message,
              range: [[lineNo, column1], [lineNo, column2]],
              filePath,
            });
          }
          tmpPathObj.removeCallback();
          return toReturn;
        });
      },
    };
  },
};
<|endoftext|>


<commit_before>
/*!
 * Jade
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Parser = require('./parser'),
    Compiler = require('./compiler'),
    fs = require('fs');

/**
 * Library version.
 */

exports.version = '0.6.3';

/**
 * Intermediate JavaScript cache.
 *
 * @type Object
 */

var cache = exports.cache = {};

/**
 * Expose self closing tags.
 *
 * @type Object
 */

exports.selfClosing = require('./self-closing');

/**
 * Default supported doctypes.
 *
 * @type Object
 */

exports.doctypes = require('./doctypes');

/**
 * Text filters.
 *
 * @type Object
 */

exports.filters = require('./filters');

/**
 * Utilities.
 *
 * @type Object
 */

exports.utils = require('./utils');

/**
 * Compiler.
 *
 * @type Function
 */

exports.Compiler = Compiler;

/**
 * Nodes.
 *
 * @type Object
 */

exports.nodes = require('./nodes');

/**
 * Render the given attributes object.
 *
 * @param {Object} obj
 * @return {String}
 * @api private
 */

function attrs(obj){
    var buf = [],
        terse = obj.terse;
    delete obj.terse;
    var keys = Object.keys(obj),
        len = keys.length;
    if (len) {
        buf.push('');
        for (var i = 0; i < len; ++i) {
            var key = keys[i],
                val = obj[key];
            if (typeof val === 'boolean' || val === '' || val == null) {
                if (val) {
                    terse
                        ? buf.push(key)
                        : buf.push(key + '="' + key + '"');
                }
            } else {
                buf.push(key + '="' + escape(val) + '"');
            }
        }
    }
    return buf.join(' ');
}

/**
 * Escape the given string of `html`.
 *
 * @param {String} html
 * @return {String}
 * @api private
 */

function escape(html){
    return String(html)
        .replace(/&(?!\w+;)/g, '&')
        .replace(/</g, '<')
        .replace(/>/g, '>')
        .replace(/"/g, '"');
}

/**
 * Re-throw the given `err` in context to the
 * `str` of jade, `filename`, and `lineno`.
 *
 * @param {Error} err
 * @param {String} str
 * @param {String} filename
 * @param {String} lineno
 * @api private
 */

function rethrow(err, str, filename, lineno){
    var start = lineno - 3 > 0
        ? lineno - 3
        : 0;

    // Error context
    var context = str.split('\n').slice(start, lineno).map(function(line, i){
        return '    '
            + (i + start + 1)
            + ". '"
            + line.replace("'", "\\'")
            + "'";
    }).join('\n');

    // Alter exception message
    err.path = filename;
    err.message = (filename || 'Jade') + ':' + lineno
        + '\n' + context + '\n\n' + err.message;
    throw err;
}

/**
 * Parse the given `str` of jade and return a function body.
 *
 * @param {String} str
 * @param {Object} options
 * @return {String}
 * @api private
 */

function parse(str, options){
    var filename = options.filename;
    try {
        // Parse
        var parser = new Parser(str, filename);
        if (options.debug) parser.debug();

        // Compile
        var compiler = new (options.compiler || Compiler)(parser.parse(), options),
            js = compiler.compile();

        // Debug compiler
        if (options.debug) {
            console.log('\n\x1b[1mCompiled Function\x1b[0m:\n\n%s', js.replace(/^/gm, '  '));
        }

        try {
            return ''
                + attrs.toString() + '\n\n'
                + escape.toString()  + '\n\n'
                + 'var buf = [];\n'
                + 'with (locals || {}) {' + js + '}'
                + 'return buf.join("");';
        } catch (err) {
            process.compile(js, filename || 'Jade');
            return;
        }
    } catch (err) {
        rethrow(err, str, filename, parser.lexer.lineno);
    }
}

/**
 * Compile a `Function` representation of the given jade `str`.
 *
 * @param {String} str
 * @param {Options} options
 * @return {Function}
 * @api public
 */

exports.compile = function(str, options){
    var options = options || {},
        input = JSON.stringify(str),
        filename = options.filename
            ? JSON.stringify(options.filename)
            : 'undefined';

    // Reduce closure madness by injecting some locals
    var fn = [
        'var __ = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };',
        rethrow.toString(),
        'try {',
        parse(String(str), options || {}),
        '} catch (err) {',
        '  rethrow(err, __.input, __.filename, __.lineno);',
        '}'
    ].join('\n');

    return new Function('locals', fn);
};

/**
 * Render the given `str` of jade.
 *
 * Options:
 *
 *   - `scope`     Evaluation scope (`this`)
 *   - `locals`    Local variable object
 *   - `filename`  Used in exceptions, and required by `cache`
 *   - `cache`     Cache intermediate JavaScript in memory keyed by `filename`
 *   - `compiler`  Compiler to replade jade's default
 *
 * @param {String|Buffer} str
 * @param {Object} options
 * @return {String}
 * @api public
 */

exports.render = function(str, options){
    var fn,
        options = options || {},
        filename = options.filename;

    // Accept Buffers
    str = String(str);

    // Cache support
    if (options.cache) {
        if (filename) {
            if (cache[filename]) {
                fn = cache[filename];
            } else {
                fn = cache[filename] = new Function('locals', parse(str, options));
            }
        } else {
            throw new Error('filename is required when using the cache option');
        }
    } else {
        fn = new Function('locals', parse(str, options));
    }

    // Render the template
    try {
        var locals = options.locals || {}
          , meta = { lineno: 1 };
        locals.__ = meta;
        return fn.call(options.scope, locals);
    } catch (err) {
        rethrow(err, str, filename, meta.lineno);
    }
};

/**
 * Render jade template at the given `path`.
 *
 * @param {String} path
 * @param {Object} options
 * @param {Function} fn
 * @api public
 */

exports.renderFile = function(path, options, fn){
    if (typeof options === 'function') {
        fn = options;
        options = {};
    }
    options.filename = path;

    // Primed cache
    if (options.cache && cache[path]) {
        try {
            fn(null, exports.render('', options));
        } catch (err) {
            fn(err);
        }
    } else {
        fs.readFile(path, 'utf8', function(err, str){
            if (err) return fn(err);
            try {
                fn(null, exports.render(str, options));
            } catch (err) {
                fn(err);
            }
        });
    }
};<commit_msg>refactored jade.js<commit_after>
/*!
 * Jade
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Parser = require('./parser')
  , Compiler = require('./compiler')
  , fs = require('fs');

/**
 * Library version.
 */

exports.version = '0.6.3';

/**
 * Intermediate JavaScript cache.
 *
 * @type Object
 */

var cache = exports.cache = {};

/**
 * Expose self closing tags.
 *
 * @type Object
 */

exports.selfClosing = require('./self-closing');

/**
 * Default supported doctypes.
 *
 * @type Object
 */

exports.doctypes = require('./doctypes');

/**
 * Text filters.
 *
 * @type Object
 */

exports.filters = require('./filters');

/**
 * Utilities.
 *
 * @type Object
 */

exports.utils = require('./utils');

/**
 * Compiler.
 *
 * @type Function
 */

exports.Compiler = Compiler;

/**
 * Nodes.
 *
 * @type Object
 */

exports.nodes = require('./nodes');

/**
 * Render the given attributes object.
 *
 * @param {Object} obj
 * @return {String}
 * @api private
 */

function attrs(obj){
  var buf = []
    , terse = obj.terse;
  delete obj.terse;
  var keys = Object.keys(obj)
    , len = keys.length;
  if (len) {
    buf.push('');
    for (var i = 0; i < len; ++i) {
      var key = keys[i]
        , val = obj[key];
      if (typeof val === 'boolean' || val === '' || val == null) {
        if (val) {
          terse
            ? buf.push(key)
            : buf.push(key + '="' + key + '"');
        }
      } else {
        buf.push(key + '="' + escape(val) + '"');
      }
    }
  }
  return buf.join(' ');
}

/**
 * Escape the given string of `html`.
 *
 * @param {String} html
 * @return {String}
 * @api private
 */

function escape(html){
  return String(html)
    .replace(/&(?!\w+;)/g, '&')
    .replace(/</g, '<')
    .replace(/>/g, '>')
    .replace(/"/g, '"');
}

/**
 * Re-throw the given `err` in context to the
 * `str` of jade, `filename`, and `lineno`.
 *
 * @param {Error} err
 * @param {String} str
 * @param {String} filename
 * @param {String} lineno
 * @api private
 */

function rethrow(err, str, filename, lineno){
  var start = lineno - 3 > 0
    ? lineno - 3
    : 0;

  // Error context
  var context = str.split('\n').slice(start, lineno).map(function(line, i){
    return '    '
      + (i + start + 1)
      + ". '"
      + line.replace("'", "\\'")
      + "'";
  }).join('\n');

  // Alter exception message
  err.path = filename;
  err.message = (filename || 'Jade') + ':' + lineno
    + '\n' + context + '\n\n' + err.message;
  throw err;
}

/**
 * Parse the given `str` of jade and return a function body.
 *
 * @param {String} str
 * @param {Object} options
 * @return {String}
 * @api private
 */

function parse(str, options){
  var filename = options.filename;
  try {
    // Parse
    var parser = new Parser(str, filename);
    if (options.debug) parser.debug();

    // Compile
    var compiler = new (options.compiler || Compiler)(parser.parse(), options)
      , js = compiler.compile();

    // Debug compiler
    if (options.debug) {
      console.log('\n\x1b[1mCompiled Function\x1b[0m:\n\n%s', js.replace(/^/gm, '  '));
    }

    try {
      return ''
        + attrs.toString() + '\n\n'
        + escape.toString()  + '\n\n'
        + 'var buf = [];\n'
        + 'with (locals || {}) {' + js + '}'
        + 'return buf.join("");';
    } catch (err) {
      process.compile(js, filename || 'Jade');
      return;
    }
  } catch (err) {
    rethrow(err, str, filename, parser.lexer.lineno);
  }
}

/**
 * Compile a `Function` representation of the given jade `str`.
 *
 * @param {String} str
 * @param {Options} options
 * @return {Function}
 * @api public
 */

exports.compile = function(str, options){
  var options = options || {}
    , input = JSON.stringify(str)
    , filename = options.filename
      ? JSON.stringify(options.filename)
      : 'undefined';

  // Reduce closure madness by injecting some locals
  var fn = [
      'var __ = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };'
    , rethrow.toString()
    , 'try {'
    , parse(String(str), options || {})
    , '} catch (err) {'
    , '  rethrow(err, __.input, __.filename, __.lineno);'
    , '}'
  ].join('\n');

  return new Function('locals', fn);
};

/**
 * Render the given `str` of jade.
 *
 * Options:
 *
 *   - `scope`     Evaluation scope (`this`)
 *   - `locals`    Local variable object
 *   - `filename`  Used in exceptions, and required by `cache`
 *   - `cache`     Cache intermediate JavaScript in memory keyed by `filename`
 *   - `compiler`  Compiler to replade jade's default
 *
 * @param {String|Buffer} str
 * @param {Object} options
 * @return {String}
 * @api public
 */

exports.render = function(str, options){
  var fn
    , options = options || {}
    , filename = options.filename;

  // Accept Buffers
  str = String(str);

  // Cache support
  if (options.cache) {
    if (filename) {
      if (cache[filename]) {
        fn = cache[filename];
      } else {
        fn = cache[filename] = new Function('locals', parse(str, options));
      }
    } else {
      throw new Error('filename is required when using the cache option');
    }
  } else {
    fn = new Function('locals', parse(str, options));
  }

  // Render the template
  try {
    var locals = options.locals || {}
      , meta = { lineno: 1 };
    locals.__ = meta;
    return fn.call(options.scope, locals);
  } catch (err) {
    rethrow(err, str, filename, meta.lineno);
  }
};

/**
 * Render jade template at the given `path`.
 *
 * @param {String} path
 * @param {Object} options
 * @param {Function} fn
 * @api public
 */

exports.renderFile = function(path, options, fn){
  if (typeof options === 'function') {
    fn = options;
    options = {};
  }
  options.filename = path;

  // Primed cache
  if (options.cache && cache[path]) {
    try {
      fn(null, exports.render('', options));
    } catch (err) {
      fn(err);
    }
  } else {
    fs.readFile(path, 'utf8', function(err, str){
      if (err) return fn(err);
      try {
        fn(null, exports.render(str, options));
      } catch (err) {
        fn(err);
      }
    });
  }
};<|endoftext|>


<commit_before>(function() {
  'use strict';

  var L20n;

  if (typeof exports !== 'undefined') {
    L20n = exports;
    L20n.Parser = require('./parser.js');
    L20n.Compiler = require('./compiler.js');
  } else {
    L20n = this.L20n = {};
  }

  L20n.getContext = function L20n_getContext() {
    return new Context();
  };

  var globals = {
    get hour() {
      return new Date().getHours();
    },
    get os() {
      if (/^MacIntel/.test(navigator.platform)) {
        return 'mac';
      }
      if (/^Linux/.test(navigator.platform)) {
        return 'linux';
      }
      if (/^Win/.test(navigatgor.platform)) {
        return 'win';
      }
      return 'unknown';
    },
  };

  function Cache() {
    this.resources = {};
    this.preprocessed = {};
  }

  Cache.prototype.getResource = function Cache_getResource(uri) {
    if (!this.resources[uri]) {
      this.resources[uri] = new Resource(uri);
    }
    return this.resources[uri];
  };

  Cache.prototype.getProcessedResource = function Cache_getProcessedResource(relpath, basepath) {
    var uri = this.normalizeURL(relpath, basepath);
    if (!this.preprocessed[uri]) {
      this.preprocessed[uri] = new ProcessedResource(this, uri);
    }
    return this.preprocessed[uri];
  };

  Cache.prototype.normalizeURL = function Cache_normalizeURL(relpath, basepath) {
    var parts;
    if (relpath[0] == '/') {
      parts = relpath.split('/');
    } else if (basepath) {
      // strip the trailing slash if present
      if (basepath[basepath.length - 1] == '/') {
        basepath = basepath.slice(0, basepath.length - 1);
      }
      parts = (basepath + '/' + relpath).split('/');
    } else {
      parts = ('./' + relpath).split('/');
    }
    var normalized = [];
    parts.forEach(function(part, i) {
      if (part == '.') {
        // don't do anything
      } else if (part == '..' && normalized[normalized.length - 1]) {
        // remove the last element of `normalized`
        normalized.splice(normalized.length - 1, 1);
      } else {
        normalized.push(part);
      }
    });
    return normalized.join('/');
  };

  function _ifComplete(self, fn) {
    return function ifComplete() {
      if (self.isComplete()) {
        fn.apply(self, arguments);
      }
    }
  }

  function _fire(callbacks, args) {
    callbacks.forEach(function(callback) {
      callback.apply(this, args);
    });
    callbacks.length = 0;
  }

  function Resource(uri) {
    //var uri = uri;
    var ast = null;
    var imports = null;
    var callbacks = [];
    var isDownloading = false;

    function download(uri, callback) {
      var xhr = new XMLHttpRequest();
      xhr.overrideMimeType('text/plain');
      xhr.addEventListener("load", function() {
        callback(xhr.responseText)
      });
      xhr.open('GET', uri, true);
      xhr.send('');
    }

    function parse(data) {
      ast = L20n.Parser.parse(data).body;
      imports = ast.filter(function(elem) {
        return elem.type == 'ImportStatement';
      });
      _fire(callbacks, [ast, imports]);
    }

    this.get = function r_get(callback) {
      if (ast) {
        callback(ast, imports);
      } else {
        callbacks.push(callback);
        if (!isDownloading) {
          isDownloading = true;
          download(uri, parse);
        }
      }
    }
  }

  function ProcessedResource(cache, uri) {

    var rawast = [];
    var callbacks = [];

    this.ast = [];
    this.imports = []; // imported resources in order
    // a preprocessed resource is ready when all its child resources are ready
    // and it has been preprocessed to include their ASTs.
    this.isReady = false;

    this.cache = cache;
    this.dirname = uri ? uri.split('/').slice(0, -1).join('/') : null;
    this.resource = uri ? this.cache.getResource(uri) : null;

    var self = this;

    function preprocess() {
      if (this.isReady) {
        return;
      }
      rawast.forEach(function(node) {
        if (node.type == 'ImportStatement') {
          var importedAST = this.imports.shift().ast;
          this.ast = self.ast.concat(importedAST);
        } else {
          this.ast.push(node);
        }
      }, this);
      this.isReady = true;
      _fire(callbacks);
    }

    this.load = function pr_load(callback, nesting) {
      if (this.isPreprocessed) {
        callback();
      } else {
        callbacks.push(callback);
        this.resource.get(function resolveImports(ast, imports) {
          rawast = ast;
          if (imports.length) {
            imports.forEach(function(node){
              self.import(node.uri.content, _ifComplete(self, preprocess),
                nesting + 1);
            });
          } else {
            self.ast = rawast;
            self.isReady = true;
            _fire(callbacks);
          }
        });
      }
    }

    this.import = function pr_import(relpath, callback, nesting) {
      nesting = nesting || 0;
      if (nesting > 7) {
        throw "Too many nested imports";
      }
      var imported = this.cache.getProcessedResource(relpath, self.dirname);
      this.imports.push(imported);
      imported.load(callback, nesting);
    }

    this.isComplete = function pr_isComplete() {
      for (var i in this.imports) {
        if (!this.imports[i].isReady) {
          return false;
        }
      }
      return true;
    }
  }

  function Context() {

    var entries = {}; // resource entries
    var ctxdata = {}; // context variables
    var settings = {
      'paths': null,    // path schemas in form of: {root, schema}
      'locales': null,  // list of locale codes in priority order
      'timeout': 500, // timeout for asynchronous resource loading
    };

    var isFrozen = false;
    // context is ready when all the resources have been downloaded,
    // preprocessed and compiled
    var isReady = false;

    var self = this;

    var cache = new Cache();

    // Context is a top-level resource that imports other resources.  The only
    // difference is that a regular resource is a file, and the EOF marks the
    // moment when the resource no longer accepts new imports.  For the
    // context's meta resource we need the `freeze` method to simulate this
    // behavior.
    var meta = new ProcessedResource(cache);

    meta.isComplete = function m_isComplete() {
      if (!isFrozen) {
        return false;
      }
      for (var i in this.imports) {
        if (!this.imports[i].isReady) {
          return false;
        }
      }
      return true;
    }

    function compile() {
      if (isReady) {
        return;
      }
      // flatten the AST
      meta.ast = meta.imports.reduce(function(prev, curr) {
        return prev.concat(curr.ast);
      }, []);
      L20n.Compiler.compile(meta.ast, entries, globals);
      isReady = true;
      fireReadyEvent();
    }

    function fireReadyEvent() {
      var event = document.createEvent('Event');
      event.initEvent('LocalizationReady', false, false);
      event.ctx = self;
      document.dispatchEvent(event);
    }

    function getArgs(data) {
      var args = Object.create(ctxdata);
      if (data) {
        for (var i in data) {
          args[i] = data[i];
        }
      }
      return args;
    }

    function getSync(id, data) {
      if (!isReady) {
        throw "Error: context not ready";
      }
      var entity = entries[id];
      if (!entity || entity.local) {
        console.warn("No such entity: " + id);
        return null;
      }
      var args = getArgs(data);
      return entity.toString(args);
    };

    function getAsync(id, data, callback, fallback) {
      if (isReady) {
        callback(getSync(id, data));
      }
      var overdue = false;
      var ttl = window.setTimeout(function() {
        overdue = true;
        // fallback is just a string, can't interpolate context data
        callback(fallback);
      }, settings.timeout);

      document.addEventListener('LocalizationReady', function(event) {
        if (overdue || event.ctx !== self) {
          return;
        }
        window.clearTimeout(ttl);
        callback(getSync(id, data));
      });
    };

    this.__defineSetter__('data', function(data) {
      ctxdata = data;
    });

    this.__defineGetter__('data', function() {
      return ctxdata;
    });

    Object.defineProperty(this, 'settings', {
      value: Object.create(Object.prototype, {
        locales: {
          get: function() { return settings.locales },
          set: function(val) {
            if (!Array.isArray(val)) {
              throw "Locales must be a list";
            }
            if (settings.locales !== null) {
              throw "Can't overwrite locales";
            }
            settings.locales = val;
            Object.freeze(settings.locales);
          },
          configurable: false,
          enumerable: true,
        },
        paths: {
          get: function() { return settings.paths },
          set: function(val) {
            if (!Array.isArray(val)) {
              throw "Paths must be a list";
            }
            if (settings.paths !== null) {
              throw "Can't overwrite paths";
            }
            settings.paths = val;
            Object.freeze(settings.paths);
          },
          configurable: false,
          enumerable: true,
        },
        timeout: {
          get: function() { return settings.timeout },
          set: function(val) {
            if (typeof(val) !== 'number') {
              throw "Timeout must be a number";
            }
            settings.timeout = val;
          },
          configurable: false,
          enumerable: true,
        },
      }),
      writable: false,
      enumerable: false,
      configurable: false,
    });

    this.getLocale = function ctx_getLocale() {
      if (settings.locales.length == 0) {
        return null;
      }
      return settings.locales[0];
    };

    this.addResource = function ctx_addResource(url) {
      if (isFrozen) {
        throw "Context is frozen, can't add more resources";
      }
      meta.import(url, _ifComplete(meta, compile));
    };

    this.freeze = function ctx_freeze() {
      isFrozen = true;
      _ifComplete(meta, compile);
    };

    this.get = function ctx_get(id, data, callback, fallback) {
      if (isReady || callback === undefined) {
        return getSync(id, data);
      } else {
        getAsync(id, data, callback, fallback);
        return null;
      }
    };

    this.getAttribute = function ctx_getAttribute(id, attr, data) {
      if (!isReady) {
        throw "Error: context not ready";
      }
      var entity = entries[id];
      if (!entity || entity.local) {
        console.warn("No such entity: " + id);
        return null;
      }
      var attribute = entity.attributes[attr]
      if (!attribute || attribute.local) {
        console.warn("No such attribute: " + attr);
        return null;
      }
      var args = getArgs(data);
      return attribute.toString(args);
    };

    this.getAttributes = function ctx_getAttributes(id, data) {
      if (!isReady) {
        throw "Error: context not ready";
      }
      var entity = entries[id];
      if (!entity || entity.local) {
        console.warn("No such entity: " + id);
        return null;
      }
      var args = getArgs(data);
      var attributes = {};
      for (var attr in entity.attributes) {
        var attribute = entity.attributes[attr];
        if (!attribute.local) {
          attributes[attr] = attribute.toString(args);
        }
      }
      return attributes;
    }
  }
}).call(this);
<commit_msg>add resolveUrl to resolve schema urls<commit_after>(function() {
  'use strict';

  var L20n;

  if (typeof exports !== 'undefined') {
    L20n = exports;
    L20n.Parser = require('./parser.js');
    L20n.Compiler = require('./compiler.js');
  } else {
    L20n = this.L20n = {};
  }

  L20n.getContext = function L20n_getContext() {
    return new Context();
  };

  var globals = {
    get hour() {
      return new Date().getHours();
    },
    get os() {
      if (/^MacIntel/.test(navigator.platform)) {
        return 'mac';
      }
      if (/^Linux/.test(navigator.platform)) {
        return 'linux';
      }
      if (/^Win/.test(navigatgor.platform)) {
        return 'win';
      }
      return 'unknown';
    },
  };

  function Cache() {
    this.resources = {};
    this.preprocessed = {};
  }

  Cache.prototype.getResource = function Cache_getResource(uri) {
    if (!this.resources[uri]) {
      this.resources[uri] = new Resource(uri);
    }
    return this.resources[uri];
  };

  Cache.prototype.getProcessedResource = function Cache_getProcessedResource(relpath, basepath) {
    var uri = this.normalizeURL(relpath, basepath);
    if (!this.preprocessed[uri]) {
      this.preprocessed[uri] = new ProcessedResource(this, uri);
    }
    return this.preprocessed[uri];
  };

  Cache.prototype.normalizeURL = function Cache_normalizeURL(relpath, basepath) {
    var parts;
    if (relpath[0] == '/') {
      parts = relpath.split('/');
    } else if (basepath) {
      // strip the trailing slash if present
      if (basepath[basepath.length - 1] == '/') {
        basepath = basepath.slice(0, basepath.length - 1);
      }
      parts = (basepath + '/' + relpath).split('/');
    } else {
      parts = ('./' + relpath).split('/');
    }
    var normalized = [];
    parts.forEach(function(part, i) {
      if (part == '.') {
        // don't do anything
      } else if (part == '..' && normalized[normalized.length - 1]) {
        // remove the last element of `normalized`
        normalized.splice(normalized.length - 1, 1);
      } else {
        normalized.push(part);
      }
    });
    return normalized.join('/');
  };

  function _ifComplete(self, fn) {
    return function ifComplete() {
      if (self.isComplete()) {
        fn.apply(self, arguments);
      }
    }
  }

  function _fire(callbacks, args) {
    callbacks.forEach(function(callback) {
      callback.apply(this, args);
    });
    callbacks.length = 0;
  }

  function Resource(uri) {
    //var uri = uri;
    var ast = null;
    var imports = null;
    var callbacks = [];
    var isDownloading = false;

    function download(uri, callback) {
      var xhr = new XMLHttpRequest();
      xhr.overrideMimeType('text/plain');
      xhr.addEventListener("load", function() {
        callback(xhr.responseText)
      });
      xhr.open('GET', uri, true);
      xhr.send('');
    }

    function parse(data) {
      ast = L20n.Parser.parse(data).body;
      imports = ast.filter(function(elem) {
        return elem.type == 'ImportStatement';
      });
      _fire(callbacks, [ast, imports]);
    }

    this.get = function r_get(callback) {
      if (ast) {
        callback(ast, imports);
      } else {
        callbacks.push(callback);
        if (!isDownloading) {
          isDownloading = true;
          download(uri, parse);
        }
      }
    }
  }

  function ProcessedResource(cache, uri) {

    var rawast = [];
    var callbacks = [];

    this.ast = [];
    this.imports = []; // imported resources in order
    // a preprocessed resource is ready when all its child resources are ready
    // and it has been preprocessed to include their ASTs.
    this.isReady = false;

    this.cache = cache;
    this.dirname = uri ? uri.split('/').slice(0, -1).join('/') : null;
    this.resource = uri ? this.cache.getResource(uri) : null;

    var self = this;

    function preprocess() {
      if (this.isReady) {
        return;
      }
      rawast.forEach(function(node) {
        if (node.type == 'ImportStatement') {
          var importedAST = this.imports.shift().ast;
          this.ast = self.ast.concat(importedAST);
        } else {
          this.ast.push(node);
        }
      }, this);
      this.isReady = true;
      _fire(callbacks);
    }

    this.load = function pr_load(callback, nesting) {
      if (this.isPreprocessed) {
        callback();
      } else {
        callbacks.push(callback);
        this.resource.get(function resolveImports(ast, imports) {
          rawast = ast;
          if (imports.length) {
            imports.forEach(function(node){
              self.import(node.uri.content, _ifComplete(self, preprocess),
                nesting + 1);
            });
          } else {
            self.ast = rawast;
            self.isReady = true;
            _fire(callbacks);
          }
        });
      }
    }

    this.import = function pr_import(relpath, callback, nesting) {
      nesting = nesting || 0;
      if (nesting > 7) {
        throw "Too many nested imports";
      }
      var imported = this.cache.getProcessedResource(relpath, self.dirname);
      this.imports.push(imported);
      imported.load(callback, nesting);
    }

    this.isComplete = function pr_isComplete() {
      for (var i in this.imports) {
        if (!this.imports[i].isReady) {
          return false;
        }
      }
      return true;
    }
  }

  function Context() {

    var entries = {}; // resource entries
    var ctxdata = {}; // context variables
    var settings = {
      'paths': null,    // path schemas in form of: {root, schema}
      'locales': null,  // list of locale codes in priority order
      'timeout': 500, // timeout for asynchronous resource loading
    };

    var isFrozen = false;
    // context is ready when all the resources have been downloaded,
    // preprocessed and compiled
    var isReady = false;

    var self = this;

    var cache = new Cache();

    // Context is a top-level resource that imports other resources.  The only
    // difference is that a regular resource is a file, and the EOF marks the
    // moment when the resource no longer accepts new imports.  For the
    // context's meta resource we need the `freeze` method to simulate this
    // behavior.
    var meta = new ProcessedResource(cache);

    meta.isComplete = function m_isComplete() {
      if (!isFrozen) {
        return false;
      }
      for (var i in this.imports) {
        if (!this.imports[i].isReady) {
          return false;
        }
      }
      return true;
    }

    function compile() {
      if (isReady) {
        return;
      }
      // flatten the AST
      meta.ast = meta.imports.reduce(function(prev, curr) {
        return prev.concat(curr.ast);
      }, []);
      L20n.Compiler.compile(meta.ast, entries, globals);
      isReady = true;
      fireReadyEvent();
    }

    function fireReadyEvent() {
      var event = document.createEvent('Event');
      event.initEvent('LocalizationReady', false, false);
      event.ctx = self;
      document.dispatchEvent(event);
    }

    function getArgs(data) {
      var args = Object.create(ctxdata);
      if (data) {
        for (var i in data) {
          args[i] = data[i];
        }
      }
      return args;
    }

    function getSync(id, data) {
      if (!isReady) {
        throw "Error: context not ready";
      }
      var entity = entries[id];
      if (!entity || entity.local) {
        console.warn("No such entity: " + id);
        return null;
      }
      var args = getArgs(data);
      return entity.toString(args);
    };

    function getAsync(id, data, callback, fallback) {
      if (isReady) {
        callback(getSync(id, data));
      }
      var overdue = false;
      var ttl = window.setTimeout(function() {
        overdue = true;
        // fallback is just a string, can't interpolate context data
        callback(fallback);
      }, settings.timeout);

      document.addEventListener('LocalizationReady', function(event) {
        if (overdue || event.ctx !== self) {
          return;
        }
        window.clearTimeout(ttl);
        callback(getSync(id, data));
      });
    };

    function resolveUrl(url) {
      if (/^l10n:/.test(url)) {
        if (settings.locales === null ||
            settings.paths === null) {
          throw "Can't use schema urls without settings.locales|paths";
        }

        // temporary stub
        var path = settings.paths[0];

        var vars = {
          'locale': self.getLocale(),
          'urn': url.substr(5)
        }
        var schema = path.schema.replace(/(\{\{\s*(\w+)\s*\}\})/g,
          function(match, p1, p2, offset, string) {
            if (vars.hasOwnProperty(p2)) {
              return vars[p2];
            }
            return p1
        });
        return path.root + schema;
      }
      return url;
    }

    this.__defineSetter__('data', function(data) {
      ctxdata = data;
    });

    this.__defineGetter__('data', function() {
      return ctxdata;
    });

    Object.defineProperty(this, 'settings', {
      value: Object.create(Object.prototype, {
        locales: {
          get: function() { return settings.locales },
          set: function(val) {
            if (!Array.isArray(val)) {
              throw "Locales must be a list";
            }
            if (settings.locales !== null) {
              throw "Can't overwrite locales";
            }
            settings.locales = val;
            Object.freeze(settings.locales);
          },
          configurable: false,
          enumerable: true,
        },
        paths: {
          get: function() { return settings.paths },
          set: function(val) {
            if (!Array.isArray(val)) {
              throw "Paths must be a list";
            }
            if (settings.paths !== null) {
              throw "Can't overwrite paths";
            }
            settings.paths = val;
            Object.freeze(settings.paths);
          },
          configurable: false,
          enumerable: true,
        },
        timeout: {
          get: function() { return settings.timeout },
          set: function(val) {
            if (typeof(val) !== 'number') {
              throw "Timeout must be a number";
            }
            settings.timeout = val;
          },
          configurable: false,
          enumerable: true,
        },
      }),
      writable: false,
      enumerable: false,
      configurable: false,
    });

    this.getLocale = function ctx_getLocale() {
      if (settings.locales.length == 0) {
        return null;
      }
      return settings.locales[0];
    };

    this.addResource = function ctx_addResource(url) {
      if (isFrozen) {
        throw "Context is frozen, can't add more resources";
      }
      meta.import(resolveUrl(url), _ifComplete(meta, compile));
    };

    this.freeze = function ctx_freeze() {
      isFrozen = true;
      _ifComplete(meta, compile);
    };

    this.get = function ctx_get(id, data, callback, fallback) {
      if (isReady || callback === undefined) {
        return getSync(id, data);
      } else {
        getAsync(id, data, callback, fallback);
        return null;
      }
    };

    this.getAttribute = function ctx_getAttribute(id, attr, data) {
      if (!isReady) {
        throw "Error: context not ready";
      }
      var entity = entries[id];
      if (!entity || entity.local) {
        console.warn("No such entity: " + id);
        return null;
      }
      var attribute = entity.attributes[attr]
      if (!attribute || attribute.local) {
        console.warn("No such attribute: " + attr);
        return null;
      }
      var args = getArgs(data);
      return attribute.toString(args);
    };

    this.getAttributes = function ctx_getAttributes(id, data) {
      if (!isReady) {
        throw "Error: context not ready";
      }
      var entity = entries[id];
      if (!entity || entity.local) {
        console.warn("No such entity: " + id);
        return null;
      }
      var args = getArgs(data);
      var attributes = {};
      for (var attr in entity.attributes) {
        var attribute = entity.attributes[attr];
        if (!attribute.local) {
          attributes[attr] = attribute.toString(args);
        }
      }
      return attributes;
    }
  }
}).call(this);
<|endoftext|>


<commit_before>/**
 * lib/lint.js - gulp-jslint
 * Copyright (C) 2014-2016 Karim Alibhai.
 */

'use strict';

const LintStream = require('jslint').LintStream,
      map = require('map-stream'),
      path = require('path'),
      rc = require('rc');

/**
 * The outer linting function that creates an output
 * object.
 *
 * @param options a JSON object containing defined options
 */
module.exports = function (options) {
    // fallback to empty object
    options = options || {};

    // extend .jslintrc; give options
    // the priority for directives
    options = rc('jslint', options);

    // use 'global' for consistency prefer 'predef' because of JSLint
    options.predef = options.predef || options.global || {};

    // freeze to user's prefered edition or use latest
    options.edition = options.edition || 'latest';

    // create a new lint stream
    const lintStream = new LintStream(options);

    // map the incoming vinyl object to the object
    // expected by the lint stream
    const stream = map(function (data, next) {
        const source = data.source;

        // only continue with file inputs
        if (source.isNull()) return next(null, source);
        if (source.isStream()) return next(new gutil.PluginError('gulp-jslint', 'Not sure how to handle stream as input file.'));
        next(null, {
            file: data,
            body: source.contents.toString('utf8')
        });
    });

    // begin linting
    stream.pipe(lintStream)

        // map the lint stream results object back to the
        // vinyl object expected by the reporter and rest
        // of the gulp stream
        .pipe(map(function (data, next) {
            const source = data.file.source;
            if (source.isNull()) return next(null, source);

            // map over the properties required by a lint reporter
            source.jslint = {
                filename: source.path,
                success: data.linted.ok === true,
                errors: data.linted.errors
            };

            // continue the stream process
            next(null, source);
            data.file.done();
        }));

    // create a gulp-able stream that allows for chunked linting
    return map((source, next) => stream.write({
        source: source,
        done: () => next(null, source)
    }));
};<commit_msg>fix predef variable default<commit_after>/**
 * lib/lint.js - gulp-jslint
 * Copyright (C) 2014-2016 Karim Alibhai.
 */

'use strict';

const LintStream = require('jslint').LintStream,
      map = require('map-stream'),
      path = require('path'),
      rc = require('rc');

/**
 * The outer linting function that creates an output
 * object.
 *
 * @param options a JSON object containing defined options
 */
module.exports = function (options) {
    // fallback to empty object
    options = options || {};

    // extend .jslintrc; give options
    // the priority for directives
    options = rc('jslint', options);

    // use 'global' for consistency prefer 'predef' because of JSLint
    options.predef = options.predef || options.global || [];

    // freeze to user's prefered edition or use latest
    options.edition = options.edition || 'latest';

    // create a new lint stream
    const lintStream = new LintStream(options);

    // map the incoming vinyl object to the object
    // expected by the lint stream
    const stream = map(function (data, next) {
        const source = data.source;

        // only continue with file inputs
        if (source.isNull()) return next(null, source);
        if (source.isStream()) return next(new gutil.PluginError('gulp-jslint', 'Not sure how to handle stream as input file.'));
        next(null, {
            file: data,
            body: source.contents.toString('utf8')
        });
    });

    // begin linting
    stream.pipe(lintStream)

        // map the lint stream results object back to the
        // vinyl object expected by the reporter and rest
        // of the gulp stream
        .pipe(map(function (data, next) {
            const source = data.file.source;
            if (source.isNull()) return next(null, source);

            // map over the properties required by a lint reporter
            source.jslint = {
                filename: source.path,
                success: data.linted.ok === true,
                errors: data.linted.errors
            };

            // continue the stream process
            next(null, source);
            data.file.done();
        }));

    // create a gulp-able stream that allows for chunked linting
    return map((source, next) => stream.write({
        source: source,
        done: () => next(null, source)
    }));
};<|endoftext|>


<commit_before>// The logic to load the javascript file of a package
//////////////////////////////////////////////////////////////////////

// server: 'http://localhost/abc',
// -> http://localhost/abc/<relative>
// @param {string} relative relative module url
function absolutizeURL(pathname) {
  var base = NEURON_CONF.path;
  if (!base) {
    err('config.path must be specified');
  }

  base = base.replace('{n}', pathname.length % 3 + 1);

  return pathResolve(base, pathname);
}

// This function should be defined with neuron.config({combo: fn})
// neuron.conf.combo =
// function generateComboURL (mods) {
//     return '../concat/' + mods.map(function (mod) {
//         return '~mod~' + (mod.pkg + '/' + mod.name).replace(/\/|@/g, '~') + '.js';
//     }).join(',');
// }

// Scenarios:
// 1. facade('a/path');
// -> load a/path -> always
// 2. facade('a');
// -> load a.main
// 3. require('a');
// -> deps on a
// 4. require('./path')
// -> deps on a
// 5. require.async('a')
// -> load a.main ->
// 6. require.async('./path')
// -> load a/path
// 7. require.async('b/path'): the entry of a foreign module
// -> forbidden

var pkgs = [];

// Load the script file of a module into the current document
// @param {string} id module identifier
function loadByModule(mod) {
  if (mod.l) {
    return;
  }

  // flag to mark the status that a module has already been loaded
  mod.l = true;

  var isFacade = mod.f;
  var isAsync = mod.a;
  var pkg = mod.pkg;

  // if one of the current package's entries has already been loaded,
  // and if the current module is not an entry(facade or async)
  if (~pkgs.indexOf(pkg)) {
    if (!isFacade && !isAsync) {
      return;
    }
  } else {
    pkgs.push(pkg);
  }

  var loaded = NEURON_CONF.loaded;
  var pathname;

  // is facade ?
  var evidence = isFacade
    // if a facade is loaded, we will push `mod.id` of the facade instead of package id
    // into `loaded`
    ? mod.id
    : pkg;

  if (~loaded.indexOf(evidence)) {
    // If the main entrance of the package is already loaded
    // and the current module is not an async module, skip loading.
    // see: declaration of `require.async`
    if (isAsync) {
      pathname = generateModulePathname(mod);
    } else {
      return;
    }

    // load packages
  } else {
    var combine = NEURON_CONF.combo;

    if (combine) {
      var modules = getAllUnloadedSyncDeps(
        mod.name,
        mod.version,

        // If is a facade, we should always load it by `mod.id` not `mod.pkg`
        isFacade && mod.path
      );

      if (modules.length > 1) {
        pathname = combine(modules);
      }

      // `getAllUnloadedSyncDeps` will push loaded.
    } else {
      loaded.push(evidence);
    }

    // If no combine configuration, or there's less than 2 packages,
    // load the package file directly
    pathname = pathname
      || generateModulePathname(mod);
  }

  loadJS(absolutizeURL(pathname));
}

function generateModulePathname(mod) {
  return mod.main
    // if is a main module, we will load the source file by package

    // 1.
    // on use: 'a@1.0.0' (async or sync)
    // -> 'a/1.0.0/a.js'

    // 2.
    // on use: 'a@1.0.0/relative' (sync)
    // -> not an async module, so the module is already packaged inside:
    // -> 'a/1.0.0/a.js'
    ? moduleId2RelativeURLPath(mod.pkg + '/' + mod.name) + '.js'

    // if is an async module, we will load the source file by module id
    // mod.r -> already resolved by `commonjs-walker`
    : moduleId2RelativeURLPath(mod.id) + (mod.r ? '' : '.js');
}

// 'a@1.0.0/a' -> './a/1.0.0/a.js'
function moduleId2RelativeURLPath (id) {
  return './' + id.replace('@', '/');
}
<commit_msg>load: no longer deal legacy when loading; #117<commit_after>// The logic to load the javascript file of a package
//////////////////////////////////////////////////////////////////////

// server: 'http://localhost/abc',
// -> http://localhost/abc/<relative>
// @param {string} relative relative module url
function absolutizeURL(pathname) {
  var base = NEURON_CONF.path;
  if (!base) {
    err('config.path must be specified');
  }

  base = base.replace('{n}', pathname.length % 3 + 1);

  return pathResolve(base, pathname);
}

// This function should be defined with neuron.config({combo: fn})
// neuron.conf.combo =
// function generateComboURL (mods) {
//     return '../concat/' + mods.map(function (mod) {
//         return '~mod~' + (mod.pkg + '/' + mod.name).replace(/\/|@/g, '~') + '.js';
//     }).join(',');
// }

// Scenarios:
// 1. facade('a/path');
// -> load a/path -> always
// 2. facade('a');
// -> load a.main
// 3. require('a');
// -> deps on a
// 4. require('./path')
// -> deps on a
// 5. require.async('a')
// -> load a.main ->
// 6. require.async('./path')
// -> load a/path
// 7. require.async('b/path'): the entry of a foreign module
// -> forbidden

var pkgs = [];

// Load the script file of a module into the current document
// @param {string} id module identifier
function loadByModule(mod) {
  if (mod.l) {
    return;
  }

  // flag to mark the status that a module has already been loaded
  mod.l = true;

  var isFacade = mod.f;
  var isAsync = mod.a;
  var pkg = mod.pkg;

  // if one of the current package's entries has already been loaded,
  // and if the current module is not an entry(facade or async)
  if (~pkgs.indexOf(pkg)) {
    if (!isFacade && !isAsync) {
      return;
    }
  } else {
    pkgs.push(pkg);
  }

  var loaded = NEURON_CONF.loaded;
  var pathname;

  // is facade ?
  var evidence = isFacade
    // if a facade is loaded, we will push `mod.id` of the facade instead of package id
    // into `loaded`
    ? mod.id
    : pkg;

  if (~loaded.indexOf(evidence)) {
    // If the main entrance of the package is already loaded
    // and the current module is not an async module, skip loading.
    // see: declaration of `require.async`
    if (isAsync) {
      pathname = generateModulePathname(mod);
    } else {
      return;
    }

    // load packages
  } else {
    var combine = NEURON_CONF.combo;

    if (combine) {
      var modules = getAllUnloadedSyncDeps(
        mod.name,
        mod.version,

        // If is a facade, we should always load it by `mod.id` not `mod.pkg`
        isFacade && removesLeadingSlash(mod.path)
      );

      if (modules.length > 1) {
        pathname = combine(modules);
      }

      // `getAllUnloadedSyncDeps` will push loaded.
    } else {
      loaded.push(evidence);
    }

    // If no combine configuration, or there's less than 2 packages,
    // load the package file directly
    pathname = pathname
      || generateModulePathname(mod);
  }

  loadJS(absolutizeURL(pathname));
}

function generateModulePathname(mod) {
  var id = mod.main
    // if is a main module, we will load the source file by package

    // 1.
    // on use: 'a@1.0.0' (async or sync)
    // -> 'a/1.0.0/a.js'

    // 2.
    // on use: 'a@1.0.0/relative' (sync)
    // -> not an async module, so the module is already packaged inside:
    // -> 'a/1.0.0/a.js'
    ? mod.pkg + '/' + mod.name + '.js'

    // if is an async module, we will load the source file by module id
    : mod.id;

  return moduleId2RelativeURLPath(id);
}

// 'a@1.0.0/a' -> './a/1.0.0/a.js'
function moduleId2RelativeURLPath (id) {
  return './' + id.replace('@', '/');
}
<|endoftext|>