<commit_before>/*
 * This Source Code is subject to the terms of the Mozilla Public License
 * version 2.0 (the "License"). You can obtain a copy of the License at
 * http://mozilla.org/MPL/2.0/.
 */

/**
 * @fileOverview Stores Adblock Edge data to be attached to a window.
 */

Cu.import("resource://gre/modules/Services.jsm");

let {Utils} = require("utils");
let {BlockingFilter, WhitelistFilter, ElemHideBase, ElemHideFilter, ElemHideException} = require("filterClasses");

let nodeData = new WeakMap();
let windowStats = new WeakMap();
let windowSelection = new WeakMap();

let setEntry, hasEntry, getEntry;
if (Services.vc.compare(Utils.platformVersion, "20.0") >= 0)
{
  setEntry = function(map, key, value) map.set(key, value);
  hasEntry = function(map, key) map.has(key);
  getEntry = function(map, key) map.get(key);
}
else
{
  // Fall back to user data
  let dataSeed = Math.random();
  let nodeDataProp = "abpNodeData" + dataSeed;
  let windowStatsProp = "abpWindowStats" + dataSeed;
  let windowSelectionProp = "abpWindowSelection" + dataSeed;
  let getProp = function(map)
  {
    switch (map)
    {
      case nodeData:
        return nodeDataProp;
      case windowStats:
        return windowStatsProp;
      case windowSelection:
        return windowSelectionProp;
      default:
        return null;
    }
  };

  setEntry = function(map, key, value) key.setUserData(getProp(map), value, null);
  hasEntry = function(map, key) key.getUserData(getProp(map));
  getEntry = function(map, key) key.getUserData(getProp(map)) || undefined;
}

/**
 * List of notifiers in use - these notifiers need to receive notifications on
 * new requests.
 * @type RequestNotifier[]
 */
let activeNotifiers = [];

/**
 * Creates a notifier object for a particular window. After creation the window
 * will first be scanned for previously saved requests. Once that scan is
 * complete only new requests for this window will be reported.
 * @param {Window} wnd  window to attach the notifier to
 * @param {Function} listener  listener to be called whenever a new request is found
 * @param {Object} [listenerObj]  "this" pointer to be used when calling the listener
 */
function RequestNotifier(wnd, listener, listenerObj)
{
  this.window = wnd;
  this.listener = listener;
  this.listenerObj = listenerObj || null;
  activeNotifiers.push(this);
  if (wnd)
    this.startScan(wnd);
  else
    this.scanComplete = true;
}
exports.RequestNotifier = RequestNotifier;

RequestNotifier.prototype =
{
  /**
   * The window this notifier is associated with.
   * @type Window
   */
  window: null,

  /**
   * The listener to be called when a new request is found.
   * @type Function
   */
  listener: null,

  /**
   * "this" pointer to be used when calling the listener.
   * @type Object
   */
  listenerObj: null,

  /**
   * Will be set to true once the initial window scan is complete.
   * @type Boolean
   */
  scanComplete: false,

  /**
   * Shuts down the notifier once it is no longer used. The listener
   * will no longer be called after that.
   */
  shutdown: function()
  {
    delete this.window;
    delete this.listener;
    delete this.listenerObj;

    for (let i = activeNotifiers.length - 1; i >= 0; i--)
      if (activeNotifiers[i] == this)
        activeNotifiers.splice(i, 1);
  },

  /**
   * Notifies listener about a new request.
   */
  notifyListener: function(/**Window*/ wnd, /**Node*/ node, /**RequestEntry*/ entry)
  {
    this.listener.call(this.listenerObj, wnd, node, entry, this.scanComplete);
  },

  /**
   * Number of currently posted scan events (will be 0 when the scan finishes
   * running).
   */
  eventsPosted: 0,

  /**
   * Starts the initial scan of the window (will recurse into frames).
   * @param {Window} wnd  the window to be scanned
   */
  startScan: function(wnd)
  {
    let doc = wnd.document;
    let walker = doc.createTreeWalker(doc, Ci.nsIDOMNodeFilter.SHOW_ELEMENT, null, false);

    let process = function()
    {
      if (!this.listener)
        return;

      let node = walker.currentNode;
      let data = getEntry(nodeData, node);
      if (typeof data != "undefined")
        for (let k in data)
          this.notifyListener(wnd, node, data[k]);

      if (walker.nextNode())
        Utils.runAsync(process);
      else
      {
        // Done with the current window, start the scan for its frames
        for (let i = 0; i < wnd.frames.length; i++)
          this.startScan(wnd.frames[i]);
        this.eventsPosted--;
        if (!this.eventsPosted)
        {
          this.scanComplete = true;
          this.notifyListener(wnd, null, null);
        }
      }
    }.bind(this);

    // Process each node in a separate event to allow other events to process
    this.eventsPosted++;
    Utils.runAsync(process);
  }
};

RequestNotifier.storeSelection = function(/**Window*/ wnd, /**String*/ selection)
{
  setEntry(windowSelection, wnd.document, selection);
};
RequestNotifier.getSelection = function(/**Window*/ wnd) /**String*/
{
  if (hasEntry(windowSelection, wnd.document))
    return getEntry(windowSelection, wnd.document);
  else
    return null;
};

/**
 * Attaches request data to a DOM node.
 * @param {Node} node   node to attach data to
 * @param {Window} topWnd   top-level window the node belongs to
 * @param {Integer} contentType   request type, one of the Policy.type.* constants
 * @param {String} docDomain  domain of the document that initiated the request
 * @param {Boolean} thirdParty  will be true if a third-party server has been requested
 * @param {String} location   the address that has been requested
 * @param {Filter} filter   filter applied to the request or null if none
 */
RequestNotifier.addNodeData = function(/**Node*/ node, /**Window*/ topWnd, /**Integer*/ contentType, /**String*/ docDomain, /**Boolean*/ thirdParty, /**String*/ location, /**Filter*/ filter)
{
  return new RequestEntry(node, topWnd, contentType, docDomain, thirdParty, location, filter);
}

/**
 * Retrieves the statistics for a window.
 * @result {Object} Object with the properties items, blocked, whitelisted, hidden, filters containing statistics for the window (might be null)
 */
RequestNotifier.getWindowStatistics = function(/**Window*/ wnd)
{
  if (hasEntry(windowStats, wnd.document))
    return getEntry(windowStats, wnd.document);
  else
    return null;
}

/**
 * Retrieves the request entry associated with a DOM node.
 * @param {Node} node
 * @param {Boolean} noParent  if missing or false, the search will extend to the parent nodes until one is found that has data associated with it
 * @param {Integer} [type] request type to be looking for
 * @param {String} [location] request location to be looking for
 * @result {[Node, RequestEntry]}
 * @static
 */
RequestNotifier.getDataForNode = function(node, noParent, type, location)
{
  while (node)
  {
    let data = getEntry(nodeData, node);
    if (typeof data != "undefined")
    {
      // Look for matching entry
      for (let k in data)
      {
        let entry = data[k];
        if ((typeof type == "undefined" || entry.type == type) &&
            (typeof location == "undefined" || entry.location == location))
        {
          return [node, entry];
        }
      }
    }

    // If we don't have any match on this node then maybe its parent will do
    if ((typeof noParent != "boolean" || !noParent) &&
        node.parentNode instanceof Ci.nsIDOMElement)
    {
      node = node.parentNode;
    }
    else
    {
      node = null;
    }
  }

  return null;
};

function RequestEntry(node, topWnd, contentType, docDomain, thirdParty, location, filter)
{
  this.type = contentType;
  this.docDomain = docDomain;
  this.thirdParty = thirdParty;
  this.location = location;
  this.filter = filter;

  this.attachToNode(node);

  // Update window statistics
  if (!hasEntry(windowStats, topWnd.document))
  {
    setEntry(windowStats, topWnd.document, {
      items: 0,
      hidden: 0,
      blocked: 0,
      whitelisted: 0,
      filters: {}
    });
  }

  let stats = getEntry(windowStats, topWnd.document);
  if (!filter || !(filter instanceof ElemHideBase))
    stats.items++;
  if (filter)
  {
    if (filter instanceof BlockingFilter)
      stats.blocked++;
    else if (filter instanceof WhitelistFilter || filter instanceof ElemHideException)
      stats.whitelisted++;
    else if (filter instanceof ElemHideFilter)
      stats.hidden++;

    if (filter.text in stats.filters)
      stats.filters[filter.text]++;
    else
      stats.filters[filter.text] = 1;
  }

  // Notify listeners
  for (let notifier of activeNotifiers)
    if (!notifier.window || notifier.window == topWnd)
      notifier.notifyListener(topWnd, node, this);
}
RequestEntry.prototype =
{
  /**
   * Content type of the request (one of the nsIContentPolicy constants)
   * @type Integer
   */
  type: null,
  /**
   * Domain name of the requesting document
   * @type String
   */
  docDomain: null,
  /**
   * True if the request goes to a different domain than the domain of the containing document
   * @type Boolean
   */
  thirdParty: false,
  /**
   * Address being requested
   * @type String
   */
  location: null,
  /**
   * Filter that was applied to this request (if any)
   * @type Filter
   */
  filter: null,
  /**
   * String representation of the content type, e.g. "subdocument"
   * @type String
   */
  get typeDescr() require("contentPolicy").Policy.typeDescr[this.type],
  /**
   * User-visible localized representation of the content type, e.g. "frame"
   * @type String
   */
  get localizedDescr() require("contentPolicy").Policy.localizedDescr[this.type],

  /**
   * Attaches this request object to a DOM node.
   */
  attachToNode: function(/**Node*/ node)
  {
    let existingData = getEntry(nodeData, node);
    if (typeof existingData == "undefined")
    {
      existingData = {};
      setEntry(nodeData, node, existingData);
    }

    // Add this request to the node data
    existingData[this.type + " " + this.location] = this;
  }
};
<commit_msg>issue 47 - use WeakMap instead of setUserData and getUserData methods https://hg.adblockplus.org/adblockplus/rev/05d8110fe5ea Author: Manvel Saroyan<commit_after>/*
 * This Source Code is subject to the terms of the Mozilla Public License
 * version 2.0 (the "License"). You can obtain a copy of the License at
 * http://mozilla.org/MPL/2.0/.
 */

/**
 * @fileOverview Stores Adblock Edge data to be attached to a window.
 */

Cu.import("resource://gre/modules/Services.jsm");

let {Utils} = require("utils");
let {BlockingFilter, WhitelistFilter, ElemHideBase, ElemHideFilter, ElemHideException} = require("filterClasses");

let nodeData = new WeakMap();
let windowStats = new WeakMap();
let windowSelection = new WeakMap();

let setEntry, hasEntry, getEntry;
// Last issue(Bug 982561) preventing us from using WeakMap fixed for FF version 32
if (Services.vc.compare(Utils.platformVersion, "32.0a1") >= 0)
{
  setEntry = function(map, key, value) map.set(key, value);
  hasEntry = function(map, key) map.has(key);
  getEntry = function(map, key) map.get(key);
}
else
{
  // Fall back to user data
  let dataSeed = Math.random();
  let nodeDataProp = "abpNodeData" + dataSeed;
  let windowStatsProp = "abpWindowStats" + dataSeed;
  let windowSelectionProp = "abpWindowSelection" + dataSeed;
  let getProp = function(map)
  {
    switch (map)
    {
      case nodeData:
        return nodeDataProp;
      case windowStats:
        return windowStatsProp;
      case windowSelection:
        return windowSelectionProp;
      default:
        return null;
    }
  };

  setEntry = function(map, key, value) key.setUserData(getProp(map), value, null);
  hasEntry = function(map, key) key.getUserData(getProp(map));
  getEntry = function(map, key) key.getUserData(getProp(map)) || undefined;
}

/**
 * List of notifiers in use - these notifiers need to receive notifications on
 * new requests.
 * @type RequestNotifier[]
 */
let activeNotifiers = [];

/**
 * Creates a notifier object for a particular window. After creation the window
 * will first be scanned for previously saved requests. Once that scan is
 * complete only new requests for this window will be reported.
 * @param {Window} wnd  window to attach the notifier to
 * @param {Function} listener  listener to be called whenever a new request is found
 * @param {Object} [listenerObj]  "this" pointer to be used when calling the listener
 */
function RequestNotifier(wnd, listener, listenerObj)
{
  this.window = wnd;
  this.listener = listener;
  this.listenerObj = listenerObj || null;
  activeNotifiers.push(this);
  if (wnd)
    this.startScan(wnd);
  else
    this.scanComplete = true;
}
exports.RequestNotifier = RequestNotifier;

RequestNotifier.prototype =
{
  /**
   * The window this notifier is associated with.
   * @type Window
   */
  window: null,

  /**
   * The listener to be called when a new request is found.
   * @type Function
   */
  listener: null,

  /**
   * "this" pointer to be used when calling the listener.
   * @type Object
   */
  listenerObj: null,

  /**
   * Will be set to true once the initial window scan is complete.
   * @type Boolean
   */
  scanComplete: false,

  /**
   * Shuts down the notifier once it is no longer used. The listener
   * will no longer be called after that.
   */
  shutdown: function()
  {
    delete this.window;
    delete this.listener;
    delete this.listenerObj;

    for (let i = activeNotifiers.length - 1; i >= 0; i--)
      if (activeNotifiers[i] == this)
        activeNotifiers.splice(i, 1);
  },

  /**
   * Notifies listener about a new request.
   */
  notifyListener: function(/**Window*/ wnd, /**Node*/ node, /**RequestEntry*/ entry)
  {
    this.listener.call(this.listenerObj, wnd, node, entry, this.scanComplete);
  },

  /**
   * Number of currently posted scan events (will be 0 when the scan finishes
   * running).
   */
  eventsPosted: 0,

  /**
   * Starts the initial scan of the window (will recurse into frames).
   * @param {Window} wnd  the window to be scanned
   */
  startScan: function(wnd)
  {
    let doc = wnd.document;
    let walker = doc.createTreeWalker(doc, Ci.nsIDOMNodeFilter.SHOW_ELEMENT, null, false);

    let process = function()
    {
      if (!this.listener)
        return;

      let node = walker.currentNode;
      let data = getEntry(nodeData, node);
      if (typeof data != "undefined")
        for (let k in data)
          this.notifyListener(wnd, node, data[k]);

      if (walker.nextNode())
        Utils.runAsync(process);
      else
      {
        // Done with the current window, start the scan for its frames
        for (let i = 0; i < wnd.frames.length; i++)
          this.startScan(wnd.frames[i]);
        this.eventsPosted--;
        if (!this.eventsPosted)
        {
          this.scanComplete = true;
          this.notifyListener(wnd, null, null);
        }
      }
    }.bind(this);

    // Process each node in a separate event to allow other events to process
    this.eventsPosted++;
    Utils.runAsync(process);
  }
};

RequestNotifier.storeSelection = function(/**Window*/ wnd, /**String*/ selection)
{
  setEntry(windowSelection, wnd.document, selection);
};
RequestNotifier.getSelection = function(/**Window*/ wnd) /**String*/
{
  if (hasEntry(windowSelection, wnd.document))
    return getEntry(windowSelection, wnd.document);
  else
    return null;
};

/**
 * Attaches request data to a DOM node.
 * @param {Node} node   node to attach data to
 * @param {Window} topWnd   top-level window the node belongs to
 * @param {Integer} contentType   request type, one of the Policy.type.* constants
 * @param {String} docDomain  domain of the document that initiated the request
 * @param {Boolean} thirdParty  will be true if a third-party server has been requested
 * @param {String} location   the address that has been requested
 * @param {Filter} filter   filter applied to the request or null if none
 */
RequestNotifier.addNodeData = function(/**Node*/ node, /**Window*/ topWnd, /**Integer*/ contentType, /**String*/ docDomain, /**Boolean*/ thirdParty, /**String*/ location, /**Filter*/ filter)
{
  return new RequestEntry(node, topWnd, contentType, docDomain, thirdParty, location, filter);
}

/**
 * Retrieves the statistics for a window.
 * @result {Object} Object with the properties items, blocked, whitelisted, hidden, filters containing statistics for the window (might be null)
 */
RequestNotifier.getWindowStatistics = function(/**Window*/ wnd)
{
  if (hasEntry(windowStats, wnd.document))
    return getEntry(windowStats, wnd.document);
  else
    return null;
}

/**
 * Retrieves the request entry associated with a DOM node.
 * @param {Node} node
 * @param {Boolean} noParent  if missing or false, the search will extend to the parent nodes until one is found that has data associated with it
 * @param {Integer} [type] request type to be looking for
 * @param {String} [location] request location to be looking for
 * @result {[Node, RequestEntry]}
 * @static
 */
RequestNotifier.getDataForNode = function(node, noParent, type, location)
{
  while (node)
  {
    let data = getEntry(nodeData, node);
    if (typeof data != "undefined")
    {
      // Look for matching entry
      for (let k in data)
      {
        let entry = data[k];
        if ((typeof type == "undefined" || entry.type == type) &&
            (typeof location == "undefined" || entry.location == location))
        {
          return [node, entry];
        }
      }
    }

    // If we don't have any match on this node then maybe its parent will do
    if ((typeof noParent != "boolean" || !noParent) &&
        node.parentNode instanceof Ci.nsIDOMElement)
    {
      node = node.parentNode;
    }
    else
    {
      node = null;
    }
  }

  return null;
};

function RequestEntry(node, topWnd, contentType, docDomain, thirdParty, location, filter)
{
  this.type = contentType;
  this.docDomain = docDomain;
  this.thirdParty = thirdParty;
  this.location = location;
  this.filter = filter;

  this.attachToNode(node);

  // Update window statistics
  if (!hasEntry(windowStats, topWnd.document))
  {
    setEntry(windowStats, topWnd.document, {
      items: 0,
      hidden: 0,
      blocked: 0,
      whitelisted: 0,
      filters: {}
    });
  }

  let stats = getEntry(windowStats, topWnd.document);
  if (!filter || !(filter instanceof ElemHideBase))
    stats.items++;
  if (filter)
  {
    if (filter instanceof BlockingFilter)
      stats.blocked++;
    else if (filter instanceof WhitelistFilter || filter instanceof ElemHideException)
      stats.whitelisted++;
    else if (filter instanceof ElemHideFilter)
      stats.hidden++;

    if (filter.text in stats.filters)
      stats.filters[filter.text]++;
    else
      stats.filters[filter.text] = 1;
  }

  // Notify listeners
  for (let notifier of activeNotifiers)
    if (!notifier.window || notifier.window == topWnd)
      notifier.notifyListener(topWnd, node, this);
}
RequestEntry.prototype =
{
  /**
   * Content type of the request (one of the nsIContentPolicy constants)
   * @type Integer
   */
  type: null,
  /**
   * Domain name of the requesting document
   * @type String
   */
  docDomain: null,
  /**
   * True if the request goes to a different domain than the domain of the containing document
   * @type Boolean
   */
  thirdParty: false,
  /**
   * Address being requested
   * @type String
   */
  location: null,
  /**
   * Filter that was applied to this request (if any)
   * @type Filter
   */
  filter: null,
  /**
   * String representation of the content type, e.g. "subdocument"
   * @type String
   */
  get typeDescr() require("contentPolicy").Policy.typeDescr[this.type],
  /**
   * User-visible localized representation of the content type, e.g. "frame"
   * @type String
   */
  get localizedDescr() require("contentPolicy").Policy.localizedDescr[this.type],

  /**
   * Attaches this request object to a DOM node.
   */
  attachToNode: function(/**Node*/ node)
  {
    let existingData = getEntry(nodeData, node);
    if (typeof existingData == "undefined")
    {
      existingData = {};
      setEntry(nodeData, node, existingData);
    }

    // Add this request to the node data
    existingData[this.type + " " + this.location] = this;
  }
};
<|endoftext|>


<commit_before>var errors = require('../errors');
var util = require('../util');
var models = require('../models');

var Tag = models.Tag,
    Post = models.Post,
    logging = models.logging,
    onError = util.onError;

function countBySlug(slug, success, error) {
  Post.count({where: {slug: slug}}).success(success).error(error);
}
exports.countBySlug = countBySlug;

function findBySlug(slug, success, error) {
  Post.find({where: {slug: slug}}).success(success).error(error);
}
exports.findBySlug = findBySlug;

function findById(id, success, error) {
  Post.find(id).success(success).error(error);
}
exports.findById = findById;

function findByAuto(param) {
  var fn, asInt = parseInt(param, 10);
  fn = isNaN(asInt) ? findBySlug : findById;
  fn.apply(null, arguments);
}
exports.findByAuto = findByAuto;

// Resources
function create(req, res) {
  var body = req.body;
  body.slug = util.slugify(body.title);

  countBySlug(body.slug, function(count) {
    if(count > 0) {
      res.json(409, errors.alreadyExists);
    } else {
      Post.create(body)
        .success(function(post) {
          res.json(201, post);
        })
        .error(onError(res));
    }
  }, onError(res));
}
exports.create = util.loginRequired(create);

function update(req, res) {
  var body = req.body;

  findById(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      post.updateAttributes(body).success(function() {
        res.json(201, {ok: true});
      }).error(onError(res));
    }
  }, onError(res));
}
exports.update = util.loginRequired(update);

exports.index = function index(req, res) {
  var options = {
    limit: req.query.limit,
    offset: req.query.offset,
    order: 'id DESC'
  };

  if(!req.session) {
    options.where = { published: true };
  }

  Post.findAll(options)
    .success(res.json.bind(res))
    .error(onError(res));
};

exports.show = function show(req, res) {
  findByAuto(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      res.json(post);
    }
  }, onError(res));
};

function destroy(req, res) {
  findById(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      post.destroy().success(function() {
        res.send(204);
      }).error(onError(res));
    }
  }, onError(res));
}
exports.destroy = util.loginRequired(destroy);

// Associations

function setUser(req, res) {
  findById(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      if(!req.body.id) {
        res.json(400, errors.badRequest);
      } else {
        post.setUser(req.body).success(function() {
          res.json(201, {ok: true});
        }).error(onError(res));
      }
    }
  }, onError(res));
}

function getUser(req, res) {
  findById(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      post.getUser().success(function(user) {
        res.json(user)
      }).error(onError(res));
    }
  }, onError(res));
}

function getTags(req, res) {
  findById(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      post.getTags().success(function(tags) {
        res.json(tags);
      }).error(onError(res));
    }
  }, onError(res));
}

function setTags(req, res) {
  findById(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      if(!util.isArray(req.body.data)) {
        res.json(400, errors.badRequest);
      } else {
        var ids = util.pluck(req.body.data, 'id');
        Tag.findAll({where: { id: ids }}).success(function(tags) {
          post.setTags(tags).success(function() {
            res.json(201, {ok: true});
          }).error(onError(res));
        }).error(onError(res));
      }
    }
  }, onError(res));
}

exports.user = {
  'set': util.loginRequired(setUser),
  'get': util.loginRequired(getUser)
};

exports.tags = {
  'get': util.loginRequired(getTags),
  'set': util.loginRequired(setTags)
};<commit_msg>Associating current user with newly created posts<commit_after>var errors = require('../errors');
var util = require('../util');
var models = require('../models');

var Tag = models.Tag,
    Post = models.Post,
    logging = models.logging,
    onError = util.onError;

function countBySlug(slug, success, error) {
  Post.count({where: {slug: slug}}).success(success).error(error);
}
exports.countBySlug = countBySlug;

function findBySlug(slug, success, error) {
  Post.find({where: {slug: slug}}).success(success).error(error);
}
exports.findBySlug = findBySlug;

function findById(id, success, error) {
  Post.find(id).success(success).error(error);
}
exports.findById = findById;

function findByAuto(param) {
  var fn, asInt = parseInt(param, 10);
  fn = isNaN(asInt) ? findBySlug : findById;
  fn.apply(null, arguments);
}
exports.findByAuto = findByAuto;

// Resources
function create(req, res) {
  var body = req.body;
  body.slug = util.slugify(body.title);

  countBySlug(body.slug, function(count) {
    if(count > 0) {
      res.json(409, errors.alreadyExists);
    } else {
      Post.create(body)
        .success(function(post) {
          post.setUser(req.session.user);
          res.json(201, post);
        })
        .error(onError(res));
    }
  }, onError(res));
}
exports.create = util.loginRequired(create);

function update(req, res) {
  var body = req.body;

  findById(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      post.updateAttributes(body).success(function() {
        res.json(201, {ok: true});
      }).error(onError(res));
    }
  }, onError(res));
}
exports.update = util.loginRequired(update);

exports.index = function index(req, res) {
  var options = {
    limit: req.query.limit,
    offset: req.query.offset,
    order: 'id DESC'
  };

  if(!req.session) {
    options.where = { published: true };
  }

  Post.findAll(options)
    .success(res.json.bind(res))
    .error(onError(res));
};

exports.show = function show(req, res) {
  findByAuto(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      res.json(post);
    }
  }, onError(res));
};

function destroy(req, res) {
  findById(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      post.destroy().success(function() {
        res.send(204);
      }).error(onError(res));
    }
  }, onError(res));
}
exports.destroy = util.loginRequired(destroy);

// Associations

function setUser(req, res) {
  findById(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      if(!req.body.id) {
        res.json(400, errors.badRequest);
      } else {
        post.setUser(req.body).success(function() {
          res.json(201, {ok: true});
        }).error(onError(res));
      }
    }
  }, onError(res));
}

function getUser(req, res) {
  findById(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      post.getUser().success(function(user) {
        res.json(user)
      }).error(onError(res));
    }
  }, onError(res));
}

function getTags(req, res) {
  findById(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      post.getTags().success(function(tags) {
        res.json(tags);
      }).error(onError(res));
    }
  }, onError(res));
}

function setTags(req, res) {
  findById(req.params.post, function(post) {
    if(post === null) {
      res.json(404, errors.notFound);
    } else {
      if(!util.isArray(req.body.data)) {
        res.json(400, errors.badRequest);
      } else {
        var ids = util.pluck(req.body.data, 'id');
        Tag.findAll({where: { id: ids }}).success(function(tags) {
          post.setTags(tags).success(function() {
            res.json(201, {ok: true});
          }).error(onError(res));
        }).error(onError(res));
      }
    }
  }, onError(res));
}

exports.user = {
  'set': util.loginRequired(setUser),
  'get': util.loginRequired(getUser)
};

exports.tags = {
  'get': util.loginRequired(getTags),
  'set': util.loginRequired(setTags)
};<|endoftext|>


<commit_before>var path = require('path');
var dirty = require('dirty');
var plugins = require('../plugins');

module.exports = database;

var dbFileName = path.resolve(process.env.LOG_DIR || require('os').tmpDir(), 'liftie.db');

// persistent storage status for each resort
function database(cache) {
  var db = dirty(dbFileName),
    loaded,
    onloadFn;

  function write(id) {
    var info = {
      timestamp: cache[id].data.timestamp
    };
    plugins.forEach(function(plugin) {
      var chunk = cache[id].data[plugin];
      if (chunk) {
        info[plugin] = chunk;
      }
    });
    db.set(id, info);
  }

  function read(id) {
    var info = db.get(id);
    if (!info) {
      return;
    }
    plugins.forEach(function(plugin) {
      var chunk = info[plugin];
      if (chunk) {
        cache[id].data[plugin] = chunk;
        if (info.timestamp) {
          cache[id].data.timestamp[plugin] = info.timestamp[plugin] || 0;
        }
      }
    });
  }

  function onload(fn) {
    if (typeof loaded == 'number') {
      process.nextTick(fn.bind(null, loaded));
    }
    else {
      // store handler to be called when event fires
      onloadFn = fn;
    }
  }

  db.on('load', function(count) {
    loaded = count;
    if (onloadFn) {
      onloadFn(loaded);
    }
  });

  return {
    write: write,
    read: read,
    onload: onload
  };
}
<commit_msg>fix deprecated function name<commit_after>var path = require('path');
var dirty = require('dirty');
var plugins = require('../plugins');

module.exports = database;

var dbFileName = path.resolve(process.env.LOG_DIR || require('os').tmpdir(), 'liftie.db');

// persistent storage status for each resort
function database(cache) {
  var db = dirty(dbFileName),
    loaded,
    onloadFn;

  function write(id) {
    var info = {
      timestamp: cache[id].data.timestamp
    };
    plugins.forEach(function(plugin) {
      var chunk = cache[id].data[plugin];
      if (chunk) {
        info[plugin] = chunk;
      }
    });
    db.set(id, info);
  }

  function read(id) {
    var info = db.get(id);
    if (!info) {
      return;
    }
    plugins.forEach(function(plugin) {
      var chunk = info[plugin];
      if (chunk) {
        cache[id].data[plugin] = chunk;
        if (info.timestamp) {
          cache[id].data.timestamp[plugin] = info.timestamp[plugin] || 0;
        }
      }
    });
  }

  function onload(fn) {
    if (typeof loaded == 'number') {
      process.nextTick(fn.bind(null, loaded));
    }
    else {
      // store handler to be called when event fires
      onloadFn = fn;
    }
  }

  db.on('load', function(count) {
    loaded = count;
    if (onloadFn) {
      onloadFn(loaded);
    }
  });

  return {
    write: write,
    read: read,
    onload: onload
  };
}
<|endoftext|>


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

    if(!global.cloudcmd)
        return console.log(
             '# appcache.js'                                    + '\n'  +
             '# -----------'                                    + '\n'  +
             '# Module is part of Cloud Commander,'             + '\n'  +
             '# used for work with Aplication Cache.'           + '\n'  +
             '# If you wont to see at work set appcache: true'  + '\n'  +
             '# in config.json and start cloudcmd.js'           + '\n'  +
             '# http://cloudcmd.io'                             + '\n');

    var main        = global.cloudcmd.main,
        fs          = main.fs,
        Util        = main.util,

    /* varible contain all watched file names
     * {name: true}
     */
        FileNames           = {},
        NamesList_s         = '',
        FallBack_s         = '',

    /* function thet use for crossplatform
     * access to fs.watch or fs.watchFile function
     */
        fs_watch            = null,
        on_fs_watch         = null,
        firstFileRead_b     = true,
        Manifest = '';

    setWatachFunctions();

    /* function add file or files to manifest
     * Examples:
     * exports.addFiles('jquery.js'),
     * exports.addFiles(['jquery.js', 'client.js']);
     * exports.addFiles([{'http://cdn.jquery/jq.js':'jquery.js'}, 'client.js']);
     */
    exports.addFiles = function(pFileNames){
        /* if a couple files */
        if(pFileNames instanceof Array)
            for(var i=0; i < pFileNames.length; i++){
                /* if fallback setted up */
                var lCurrentName = pFileNames[i];
                if(typeof lCurrentName === 'object')
                    for(var lName in lCurrentName){
                        FallBack_s += lName + ' ' + lCurrentName[lName] + '\n';
                        exports.watch(lCurrentName[lName]);
                    }

                else exports.watch(pFileNames[i]);
            }
        else exports.watch(pFileNames);

    };

    exports.createManifest = function(){
        var lAllNames = main.require('node_modules/minify/hashes');
        if(lAllNames)
            for(var lName in lAllNames){
                if(lName.indexOf('min') > 0)
                    lName = 'node_modules/minify/min/' + lName;
                exports.watch(lName);
            }
        processManifest();
    };

    exports.watch = function(pFileName){
        console.log(pFileName + ' is watched');

        if(!FileNames[pFileName] &&
            pFileName !== './cloudcmd.appcache'){

            /* adding try...catch
             * if watched files would be more then system limit
             */
            var lWatch_f = function(){
                Util.tryCatch(function(){
                    fs_watch(pFileName, on_fs_watch(pFileName));
                });
            };

            /* if file.exists function exist and
             * file actually exists
             */
            if(fs.exists)
                fs.exists(pFileName, lWatch_f);
            else lWatch_f();

            NamesList_s += pFileName + '\n';
            FileNames[pFileName] = true;
        }
        else if(firstFileRead_b){
            processManifest();
            firstFileRead_b = false;
        }
    };

    function setWatachFunctions(){
        if(main.WIN32){
            /* good on windows  */
            fs_watch    = fs.watch;
            on_fs_watch = onWatch;
        }
        else{
            /* good on linux    */
            fs_watch    = fs.watchFile;
            on_fs_watch = onWatchFile;
        }

    }

    function onWatch (){
        return function(pEvent, pFileName){
            console.log(pEvent);
            console.log('file ' + pFileName + ' is changed');
            processManifest();
        };
    }

    function onWatchFile(pFileName){
        return function(pCurr, pPrev){
            if(pCurr.mtime !== pPrev.mtime){
                console.log('file ' + pFileName + ' is changed');
                processManifest();
            }
        };
    }

    function processManifest(){
        Manifest = 'CACHE MANIFEST\n'   +
            '#' + new Date()   + '\n'   +
            'CACHE:\n'                  +
            NamesList_s                 +
            'NETWORK:\n'                +
            '*\n'                       +
            'FALLBACK:\n'               +
            FallBack_s;

        fs.writeFile('cloudcmd.appcache', Manifest, function(){
            console.log('cloudcmd.appcache refreshed');
        });
    }
})();
<commit_msg>refactor(appcache) addFiles<commit_after>
(function(){
    "use strict";

    if(!global.cloudcmd)
        return console.log(
             '# appcache.js'                                    + '\n'  +
             '# -----------'                                    + '\n'  +
             '# Module is part of Cloud Commander,'             + '\n'  +
             '# used for work with Aplication Cache.'           + '\n'  +
             '# If you wont to see at work set appcache: true'  + '\n'  +
             '# in config.json and start cloudcmd.js'           + '\n'  +
             '# http://cloudcmd.io'                             + '\n');

    var main        = global.cloudcmd.main,
        fs          = main.fs,
        Util        = main.util,

    /* varible contain all watched file names
     * {name: true}
     */
        FileNames           = {},
        NamesList_s         = '',
        FallBack_s         = '',

    /* function thet use for crossplatform
     * access to fs.watch or fs.watchFile function
     */
        fs_watch            = null,
        on_fs_watch         = null,
        firstFileRead_b     = true,
        Manifest = '';

    setWatachFunctions();

    /* function add file or files to manifest
     * Examples:
     * exports.addFiles('jquery.js'),
     * exports.addFiles(['jquery.js', 'client.js']);
     * exports.addFiles([{'http://cdn.jquery/jq.js':'jquery.js'}, 'client.js']);
     */
    exports.addFiles = function(pFileNames) {
        var i, n, lName, lCurrentName;
        /* if a couple files */
        if (Util.isArray(pFileNames)) {
            n = pFilesNames.length;

            for (i = 0; i < n; i++) {
                /* if fallback setted up */
                lCurrentName = pFileNames[i];

                if (Util.isObject(lCurrentName))
                    for(lName in lCurrentName) {
                        FallBack_s += lName + ' ' + lCurrentName[lName] + '\n';
                        exports.watch(lCurrentName[lName]);
                    }
                else
                    exports.watch(pFileNames[i]);
            }
        } else
            exports.watch(pFileNames);

    };

    exports.createManifest = function(){
        var lAllNames = main.require('node_modules/minify/hashes');
        if(lAllNames)
            for(var lName in lAllNames){
                if(lName.indexOf('min') > 0)
                    lName = 'node_modules/minify/min/' + lName;
                exports.watch(lName);
            }
        processManifest();
    };

    exports.watch = function(pFileName){
        console.log(pFileName + ' is watched');

        if(!FileNames[pFileName] &&
            pFileName !== './cloudcmd.appcache'){

            /* adding try...catch
             * if watched files would be more then system limit
             */
            var lWatch_f = function(){
                Util.tryCatch(function(){
                    fs_watch(pFileName, on_fs_watch(pFileName));
                });
            };

            /* if file.exists function exist and
             * file actually exists
             */
            if(fs.exists)
                fs.exists(pFileName, lWatch_f);
            else lWatch_f();

            NamesList_s += pFileName + '\n';
            FileNames[pFileName] = true;
        }
        else if(firstFileRead_b){
            processManifest();
            firstFileRead_b = false;
        }
    };

    function setWatachFunctions(){
        if(main.WIN32){
            /* good on windows  */
            fs_watch    = fs.watch;
            on_fs_watch = onWatch;
        }
        else{
            /* good on linux    */
            fs_watch    = fs.watchFile;
            on_fs_watch = onWatchFile;
        }

    }

    function onWatch (){
        return function(pEvent, pFileName){
            console.log(pEvent);
            console.log('file ' + pFileName + ' is changed');
            processManifest();
        };
    }

    function onWatchFile(pFileName){
        return function(pCurr, pPrev){
            if(pCurr.mtime !== pPrev.mtime){
                console.log('file ' + pFileName + ' is changed');
                processManifest();
            }
        };
    }

    function processManifest(){
        Manifest = 'CACHE MANIFEST\n'   +
            '#' + new Date()   + '\n'   +
            'CACHE:\n'                  +
            NamesList_s                 +
            'NETWORK:\n'                +
            '*\n'                       +
            'FALLBACK:\n'               +
            FallBack_s;

        fs.writeFile('cloudcmd.appcache', Manifest, function(){
            console.log('cloudcmd.appcache refreshed');
        });
    }
})();
<|endoftext|>


<commit_before>var
  rp = require('request-promise'),
  _ = require('lodash'),
  util = require('util');

module.exports = logger =  {

  init: function () {
  },

  /**
   * return the process Data about Kuzzle
   */
  getProcessData: function(){
    var processData = {

      pid : process.pid,
      memory: process.memoryUsage()
    };

    //undefined in non POSIX OS
    if(process.getgid){
      processData.gid = process.getgid();
    }
    return processData;
  },

  /**
   * send data from log with kuzzle state
   * @param object a RequestObject,  or relevant info for event
   * @param hookEvent hook from log  (exemple : "data:delete")
   * @param metaData (optional) metaData (for kuzzle, the nbRooms, the nbCustomers,...)
   */
  log: function (object, hookEvent, metaData) {
    var dataFromObject = {};
    if(object && object.duration){
      dataFromObjec t.duration = object.duration;
    }

    var log = {
      hookEvent : hookEvent,
      processData : this.getProcessData(),
      dataFromObject : dataFromObject,
      timestamp : Date.now(),
      metaData : metaData
    };

    rp({
      url: 'http://' + process.env.LOG_ENGINE_HOST,
      method: 'GET',
      json: {message : log}
    });
  },

  error: function (error, hookEvent, metaData) {
    var log = {
      hookEvent : hookEvent,
      processData : this.getProcessData(),
      timestamp : Date.now(),
      metaData : metaData
    };

    rp({
      url: 'http://' + process.env.LOG_ENGINE_HOST,
      method: 'GET',
      json: {message : log}
    });
  }

};
<commit_msg>correct var name<commit_after>var
  rp = require('request-promise'),
  _ = require('lodash'),
  util = require('util');

module.exports = logger =  {

  init: function () {
  },

  /**
   * return the process Data about Kuzzle
   */
  getProcessData: function(){
    var processData = {

      pid : process.pid,
      memory: process.memoryUsage()
    };

    //undefined in non POSIX OS
    if(process.getgid){
      processData.gid = process.getgid();
    }
    return processData;
  },

  /**
   * send data from log with kuzzle state
   * @param object a RequestObject,  or relevant info for event
   * @param hookEvent hook from log  (exemple : "data:delete")
   * @param metaData (optional) metaData (for kuzzle, the nbRooms, the nbCustomers,...)
   */
  log: function (object, hookEvent, metaData) {
    var dataFromObject = {};
    if(object && object.duration){
      dataFromObject.duration = object.duration;
    }

    var log = {
      hookEvent : hookEvent,
      processData : this.getProcessData(),
      dataFromObject : dataFromObject,
      timestamp : Date.now(),
      metaData : metaData
    };

    rp({
      url: 'http://' + process.env.LOG_ENGINE_HOST,
      method: 'GET',
      json: {message : log}
    });
  },

  error: function (error, hookEvent, metaData) {
    var log = {
      hookEvent : hookEvent,
      processData : this.getProcessData(),
      timestamp : Date.now(),
      metaData : metaData
    };

    rp({
      url: 'http://' + process.env.LOG_ENGINE_HOST,
      method: 'GET',
      json: {message : log}
    });
  }

};
<|endoftext|>


<commit_before>/* global Log, Config */
'use strict';

const Crypto = require('crypto');
const Path = require('path');
const Aws = require('aws-sdk');

const METADATA_LIST = /^(\d+)=(.+)$/;
const METADATA_TIMEOUT = 500;

const Source = require('./common');
const Parser = require('./metadata/parser');
const Util = require('./metadata/util');

/**
 * Metadata Source
 *
 * Expose EC2 metadata to the property-set
 *
 * @class Source.Metadata
 * @extends EventEmitter
 *
 * @param {Parser} parser
 * @param {Object} options
 *      - {Number} interval Polling interval. Default 30s.
 */
class Metadata extends Source(Parser) { // eslint-disable-line new-cap
  constructor(opts) {
    // Inject defaults into options
    const options = Object.assign({
      type: 'ec2-metadata',
      namespace: 'instance'
    }, opts);

    super(options);

    /**
     * Initialize the metadata-service client
     */
    this.service = new Aws.MetadataService({
      httpOptions: {
        timeout: METADATA_TIMEOUT
      },
      host: options.host || Config.get('metadata:host')
    });

    this.signature = null;
  }

  /**
   * Metadata version
   *
   * Used to prepend paths for calls to the EC2 Metadata Service,
   * e.g. /<version>/meta-data/ami-id
   *
   * @returns {string}
   * @private
   */
  get _version() {
    return this.constructor.version;
  }

  /**
   * For Metadata, start a polling loop
   *
   * @return {Promise<Metadata>} Resolves when the source has been initialized
   */
  initialize() {
    if (this._running) {
      return Promise.resolve(this);
    }

    this.emit('init');
    this.emit('startup');

    return this.start();
  }

  /**
   * Stop the polling loop
   *
   * @returns {Metadata} Metadata instance
   */
  shutdown() {
    if (!this._running) {
      return this;
    }

    this.stop();

    this._ok = false;
    this.signature = null;

    this.emit('shutdown');

    return this;
  }

  /**
   * Return an object describing the source-instance's current status
   *
   * @return {Object}
   */
  status() {
    return {
      ok: this._ok,
      updated: this._updated,
      interval: this.interval,
      running: this._running
    };
  }

  /**
   * Fetch all values from the EC2 metadata tree
   *
   * @param  {Function} callback(err, paths) Return an error or a hash of paths and their values
   * @private
   */
  _traverse(callback) {
    const values = {};
    const paths = ['/meta-data/', '/dynamic/'];

    Util.each(paths, (path, next) => {
      this.service.request(Path.join('/', this._version, path), (err, data) => {
        if (err) {
          return next(err);
        }

        // This is a list! Split new-line delimited strings into an array and add to tail of paths
        if (path.slice(-1) === '/') {
          const items = data.trim().split('\n');

          // Is this a list?
          if (items.reduce((memo, item) => memo && METADATA_LIST.test(item), true)) {
            const list = values[path.slice(1, -1)] = [];

            items.forEach((item) => {
              const match = item.match(METADATA_LIST);

              if (match) {
                list[match[1]] = match[2];
              }
            });

            return next();
          }

          items.forEach((node) => paths.push(Path.join(path, node)));
          return next();
        }

        // Remove leading `/`
        values[path.slice(1)] = data;
        next();
      });
    }, (err) => callback(err, values), null);
  }

  /**
   *
   * Fetch implementation for EC2 Metadata
   * @param {Function} callback
   * @private
   */
  _fetch(callback) {
    this._traverse((err, data) => {
      if (err) {
        return callback(err);
      }

      // Detect change by hashing the fetched data
      const hash = Crypto.createHash('sha1');

      Object.keys(data)
        .sort()
        .forEach((key) => {
          hash.update(`${key}:${data[key]}`);
        });

      const signature = hash.digest('base64');

      if (this.signature === signature) {
        return callback(null, false);
      }

      this.signature = signature;
      callback(null, data);
    });
  }
}

Metadata.version = 'latest';

/* Export */
module.exports = Metadata;
<commit_msg>Move initialize and shutdown into the common module<commit_after>/* global Log, Config */
'use strict';

const Crypto = require('crypto');
const Path = require('path');
const Aws = require('aws-sdk');

const METADATA_LIST = /^(\d+)=(.+)$/;
const METADATA_TIMEOUT = 500;

const Source = require('./common');
const Parser = require('./metadata/parser');
const Util = require('./metadata/util');

/**
 * Metadata Source
 *
 * Expose EC2 metadata to the property-set
 *
 * @class Source.Metadata
 * @extends EventEmitter
 *
 * @param {Parser} parser
 * @param {Object} options
 *      - {Number} interval Polling interval. Default 30s.
 */
class Metadata extends Source(Parser) { // eslint-disable-line new-cap
  constructor(opts) {
    // Inject defaults into options
    const options = Object.assign({
      type: 'ec2-metadata',
      namespace: 'instance'
    }, opts);

    super(options);

    /**
     * Initialize the metadata-service client
     */
    this.service = new Aws.MetadataService({
      httpOptions: {
        timeout: METADATA_TIMEOUT
      },
      host: options.host || Config.get('metadata:host')
    });

    this.signature = null;
  }

  shutdown() {
    super.shutdown();
    this.signature = null;

    return this;
  }

  /**
   * Metadata version
   *
   * Used to prepend paths for calls to the EC2 Metadata Service,
   * e.g. /<version>/meta-data/ami-id
   *
   * @returns {string}
   * @private
   */
  get _version() {
    return this.constructor.version;
  }

  /**
   * Fetch all values from the EC2 metadata tree
   *
   * @param  {Function} callback(err, paths) Return an error or a hash of paths and their values
   * @private
   */
  _traverse(callback) {
    const values = {};
    const paths = ['/meta-data/', '/dynamic/'];

    Util.each(paths, (path, next) => {
      this.service.request(Path.join('/', this._version, path), (err, data) => {
        if (err) {
          return next(err);
        }

        // This is a tree! Split new-line delimited strings into an array and add to tail of paths
        if (path.slice(-1) === '/') {
          const items = data.trim().split('\n');

          // Is this a list?
          if (items.reduce((memo, item) => memo && METADATA_LIST.test(item), true)) {
            const list = values[path.slice(1, -1)] = [];

            items.forEach((item) => {
              const match = item.match(METADATA_LIST);

              if (match) {
                list[match[1]] = match[2];
              }
            });

            return next();
          }

          items.forEach((node) => paths.push(Path.join(path, node)));
          return next();
        }

        // Remove leading `/`
        values[path.slice(1)] = data;
        next();
      });
    }, (err) => callback(err, values), null);
  }

  /**
   *
   * Fetch implementation for EC2 Metadata
   * @param {Function} callback
   * @private
   */
  _fetch(callback) {
    this._traverse((err, data) => {
      if (err) {
        return callback(err);
      }

      // Detect change by hashing the fetched data
      const hash = Crypto.createHash('sha1');

      Object.keys(data)
        .sort()
        .forEach((key) => {
          hash.update(`${key}:${data[key]}`);
        });

      const signature = hash.digest('base64');

      if (this.signature === signature) {
        return callback(null, false);
      }

      this.signature = signature;
      callback(null, data);
    });
  }
}

Metadata.version = 'latest';

/* Export */
module.exports = Metadata;
<|endoftext|>


<commit_before>let spinner = {
  'dots': '⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏',
  'dots2': '⣾⣽⣻⢿⡿⣟⣯⣷',
  'dots3': '⠋⠙⠚⠞⠖⠦⠴⠲⠳⠓',
  'dots4': '⠄⠆⠇⠋⠙⠸⠰⠠⠰⠸⠙⠋⠇⠆',
  'dots5': '⠋⠙⠚⠒⠂⠂⠒⠲⠴⠦⠖⠒⠐⠐⠒⠓⠋',
  'dots6': '⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠴⠲⠒⠂⠂⠒⠚⠙⠉⠁',
  'dots7': '⠈⠉⠋⠓⠒⠐⠐⠒⠖⠦⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈',
  'dots8': ['⠁', '⠁', '⠉', '⠙', '⠚', '⠒', '⠂', '⠂', '⠒', '⠲', '⠴', '⠤', '⠄', '⠄', '⠤', '⠠', '⠠', '⠤', '⠦', '⠖', '⠒', '⠐', '⠐', '⠒', '⠓', '⠋', '⠉', '⠈', '⠈'],
  'dots9': ['⢹', '⢺', '⢼', '⣸', '⣇', '⡧', '⡗', '⡏'],
  'dots10': ['⢄', '⢂', '⢁', '⡁', '⡈', '⡐', '⡠'],
  'dots11': ['⠁', '⠂', '⠄', '⡀', '⢀', '⠠', '⠐', '⠈'],
  'dots12': ['⢀⠀', '⡀⠀', '⠄⠀', '⢂⠀', '⡂⠀', '⠅⠀', '⢃⠀', '⡃⠀', '⠍⠀', '⢋⠀', '⡋⠀', '⠍⠁', '⢋⠁', '⡋⠁', '⠍⠉', '⠋⠉', '⠋⠉', '⠉⠙', '⠉⠙', '⠉⠩', '⠈⢙', '⠈⡙', '⢈⠩', '⡀⢙', '⠄⡙', '⢂⠩', '⡂⢘', '⠅⡘', '⢃⠨', '⡃⢐', '⠍⡐', '⢋⠠', '⡋⢀', '⠍⡁', '⢋⠁', '⡋⠁', '⠍⠉', '⠋⠉', '⠋⠉', '⠉⠙', '⠉⠙', '⠉⠩', '⠈⢙', '⠈⡙', '⠈⠩', '⠀⢙', '⠀⡙', '⠀⠩', '⠀⢘', '⠀⡘', '⠀⠨', '⠀⢐', '⠀⡐', '⠀⠠', '⠀⢀', '⠀⡀'],
  'line':
     [
       '-',
       '\\',
       '|',
       '/'
     ],
  'line2':
     [
       '⠂',
       '-',
       '–',
       '—',
       '–',
       '-'
     ],
  'pipe':
     [
       '┤',
       '┘',
       '┴',
       '└',
       '├',
       '┌',
       '┬',
       '┐'
     ],
  'simpleDots':
     [
       '.  ',
       '.. ',
       '...',
       '   '
     ],
  'simpleDotsScrolling':
     [
       '.  ',
       '.. ',
       '...',
       ' ..',
       '  .',
       '   '
     ],
  'star': [
    '✶',
    '✸',
    '✹',
    '✺',
    '✹',
    '✷'
  ],
  'star2': [
    '+',
    'x',
    '*'
  ],
  'flip': [
    '_',
    '_',
    '_',
    '-',
    '`',
    '`',
    '\'',
    '´',
    '-',
    '_',
    '_',
    '_'
  ],
  'hamburger':
     [
       '☱',
       '☲',
       '☴'
     ],
  'growVertical':
     [
       '▁',
       '▃',
       '▄',
       '▅',
       '▆',
       '▇',
       '▆',
       '▅',
       '▄',
       '▃'
     ],
  'growHorizontal':
     [
       '▏',
       '▎',
       '▍',
       '▌',
       '▋',
       '▊',
       '▉',
       '▊',
       '▋',
       '▌',
       '▍',
       '▎'
     ],
  'balloon':
     [
       ' ',
       '.',
       'o',
       'O',
       '@',
       '*',
       ' '
     ],
  'balloon2':
     [
       '.',
       'o',
       'O',
       '°',
       'O',
       'o',
       '.'
     ],
  'noise':
     [
       '▓',
       '▒',
       '░'
     ],
  'bounce':
     [
       '⠁',
       '⠂',
       '⠄',
       '⠂'
     ],
  'boxBounce':
     [
       '▖',
       '▘',
       '▝',
       '▗'
     ],
  'boxBounce2':
     [
       '▌',
       '▀',
       '▐',
       '▄'
     ],
  'triangle': [
    '◢',
    '◣',
    '◤',
    '◥'
  ],
  'arc':
     [
       '◜',
       '◠',
       '◝',
       '◞',
       '◡',
       '◟'
     ],
  'circle':
     [
       '◡',
       '⊙',
       '◠'
     ],
  'squareCorners':
     [
       '◰',
       '◳',
       '◲',
       '◱'
     ],
  'circleQuarters':
     [
       '◴',
       '◷',
       '◶',
       '◵'
     ],
  'circleHalves': [
    '◐',
    '◓',
    '◑',
    '◒'
  ],
  'squish':
     [
       '╫',
       '╪'
     ],
  'toggle':
     [
       '⊶',
       '⊷'
     ],
  'toggle2': [
    '▫',
    '▪'
  ],
  'toggle3':
     [
       '□',
       '■'
     ],
  'toggle4':
     [
       '■',
       '□',
       '▪',
       '▫'
     ],
  'toggle5':
     [
       '▮',
       '▯'
     ],
  'toggle6':
     [
       'ဝ',
       '၀'
     ],
  'toggle7': [
    '⦾',
    '⦿'
  ],
  'toggle8':
     [
       '◍',
       '◌'
     ],
  'toggle9':
     [
       '◉',
       '◎'
     ],
  'toggle10':
     [
       '㊂',
       '㊀',
       '㊁'
     ],
  'toggle11': [
    '⧇',
    '⧆'
  ],
  'toggle12':
     [
       '☗',
       '☖'
     ],
  'toggle13': [
    '=',
    '*',
    '-'
  ],
  'arrow':
     [
       '←',
       '↖',
       '↑',
       '↗',
       '→',
       '↘',
       '↓',
       '↙'
     ],
  'arrow2': [
    '⬆ ',
    '↗ ',
    '➡ ',
    '↘ ',
    '⬇ ',
    '↙ ',
    '⬅ ',
    '↖ '
  ],
  'arrow3':
     [
       '▹▹▹▹▹',
       '▸▹▹▹▹',
       '▹▸▹▹▹',
       '▹▹▸▹▹',
       '▹▹▹▸▹',
       '▹▹▹▹▸'
     ],
  'bouncingBar': [
    '[    ]',
    '[=   ]',
    '[==  ]',
    '[=== ]',
    '[ ===]',
    '[  ==]',
    '[   =]',
    '[    ]',
    '[   =]',
    '[  ==]',
    '[ ===]',
    '[====]',
    '[=== ]',
    '[==  ]',
    '[=   ]'
  ],
  'bouncingBall': [
    '( ●    )',
    '(  ●   )',
    '(   ●  )',
    '(    ● )',
    '(     ●)',
    '(    ● )',
    '(   ●  )',
    '(  ●   )',
    '( ●    )',
    '(●     )'
  ],
  'smiley':
     [
       '😄 ',
       '😝 '
     ],
  'monkey':
     [
       '🙈 ',
       '🙈 ',
       '🙉 ',
       '🙊 '
     ],
  'hearts':
     [
       '💛 ',
       '💙 ',
       '💜 ',
       '💚 ',
       '❤ '
     ],
  'clock':
     [
       '🕛 ',
       '🕐 ',
       '🕑 ',
       '🕒 ',
       '🕓 ',
       '🕔 ',
       '🕕 ',
       '🕖 ',
       '🕗 ',
       '🕘 ',
       '🕙 ',
       '🕚 '
     ],
  'earth':
     [
       '🌍 ',
       '🌎 ',
       '🌏 '
     ],
  'moon': [
    '🌑 ',
    '🌒 ',
    '🌓 ',
    '🌔 ',
    '🌕 ',
    '🌖 ',
    '🌗 ',
    '🌘 '
  ],
  'runner':
     [
       '🚶 ',
       '🏃 '
     ],
  'pong': [
    '▐⠂       ▌',
    '▐⠈       ▌',
    '▐ ⠂      ▌',
    '▐ ⠠      ▌',
    '▐  ⡀     ▌',
    '▐  ⠠     ▌',
    '▐   ⠂    ▌',
    '▐   ⠈    ▌',
    '▐    ⠂   ▌',
    '▐    ⠠   ▌',
    '▐     ⡀  ▌',
    '▐     ⠠  ▌',
    '▐      ⠂ ▌',
    '▐      ⠈ ▌',
    '▐       ⠂▌',
    '▐       ⠠▌',
    '▐       ⡀▌',
    '▐      ⠠ ▌',
    '▐      ⠂ ▌',
    '▐     ⠈  ▌',
    '▐     ⠂  ▌',
    '▐    ⠠   ▌',
    '▐    ⡀   ▌',
    '▐   ⠠    ▌',
    '▐   ⠂    ▌',
    '▐  ⠈     ▌',
    '▐  ⠂     ▌',
    '▐ ⠠      ▌',
    '▐ ⡀      ▌',
    '▐⠠       ▌'
  ],
  'shark':
     [
       '▐|\\____________▌',
       '▐_|\\___________▌',
       '▐__|\\__________▌',
       '▐___|\\_________▌',
       '▐____|\\________▌',
       '▐_____|\\_______▌',
       '▐______|\\______▌',
       '▐_______|\\_____▌',
       '▐________|\\____▌',
       '▐_________|\\___▌',
       '▐__________|\\__▌',
       '▐___________|\\_▌',
       '▐____________|\\▌',
       '▐____________/|▌',
       '▐___________/|_▌',
       '▐__________/|__▌',
       '▐_________/|___▌',
       '▐________/|____▌',
       '▐_______/|_____▌',
       '▐______/|______▌',
       '▐_____/|_______▌',
       '▐____/|________▌',
       '▐___/|_________▌',
       '▐__/|__________▌',
       '▐_/|___________▌',
       '▐/|____________▌'
     ],
  'dqpb':
     [
       'd',
       'q',
       'p',
       'b'
     ],
  'weather':
     [
       '☀ ',
       '☀ ',
       '☀ ',
       '🌤 ',
       '⛅ ',
       '🌥 ',
       '☁ ',
       '🌧 ',
       '🌨 ',
       '🌧 ',
       '🌨 ',
       '🌧 ',
       '🌨 ',
       '⛈ ',
       '🌨 ',
       '🌧 ',
       '🌨 ',
       '☁ ',
       '🌥 ',
       '⛅ ',
       '🌤 ',
       '☀ ',
       '☀ '
     ],
  'christmas':
     [
       '🌲',
       '🎄'
     ],
  'grenade': [
    '،   ',
    '′   ',
    ' ´ ',
    ' ‾ ',
    '  ⸌',
    '  ⸊',
    '  |',
    '  ⁎',
    '  ⁕',
    ' ෴ ',
    '  ⁓',
    '   ',
    '   ',
    '   '
  ],
  'point':
     [
       '∙∙∙',
       '●∙∙',
       '∙●∙',
       '∙∙●',
       '∙∙∙'
     ],
  'layer':
     [
       '-',
       '=',
       '≡'
     ]

}
module.exports = spinner
<commit_msg>:pencil2:<commit_after>let spinner = {
  'dots': '⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏',
  'dots2': '⣾⣽⣻⢿⡿⣟⣯⣷',
  'dots3': '⠋⠙⠚⠞⠖⠦⠴⠲⠳⠓',
  'dots4': '⠄⠆⠇⠋⠙⠸⠰⠠⠰⠸⠙⠋⠇⠆',
  'dots5': '⠋⠙⠚⠒⠂⠂⠒⠲⠴⠦⠖⠒⠐⠐⠒⠓⠋',
  'dots6': '⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠴⠲⠒⠂⠂⠒⠚⠙⠉⠁',
  'dots7': '⠈⠉⠋⠓⠒⠐⠐⠒⠖⠦⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈',
  'dots8': ['⠁', '⠁', '⠉', '⠙', '⠚', '⠒', '⠂', '⠂', '⠒', '⠲', '⠴', '⠤', '⠄', '⠄', '⠤', '⠠', '⠠', '⠤', '⠦', '⠖', '⠒', '⠐', '⠐', '⠒', '⠓', '⠋', '⠉', '⠈', '⠈'],
  'dots9': ['⢹', '⢺', '⢼', '⣸', '⣇', '⡧', '⡗', '⡏'],
  'dots10': ['⢄', '⢂', '⢁', '⡁', '⡈', '⡐', '⡠'],
  'dots11': ['⠁', '⠂', '⠄', '⡀', '⢀', '⠠', '⠐', '⠈'],
  'dots12': ['⢀⠀', '⡀⠀', '⠄⠀', '⢂⠀', '⡂⠀', '⠅⠀', '⢃⠀', '⡃⠀', '⠍⠀', '⢋⠀', '⡋⠀', '⠍⠁', '⢋⠁', '⡋⠁', '⠍⠉', '⠋⠉', '⠋⠉', '⠉⠙', '⠉⠙', '⠉⠩', '⠈⢙', '⠈⡙', '⢈⠩', '⡀⢙', '⠄⡙', '⢂⠩', '⡂⢘', '⠅⡘', '⢃⠨', '⡃⢐', '⠍⡐', '⢋⠠', '⡋⢀', '⠍⡁', '⢋⠁', '⡋⠁', '⠍⠉', '⠋⠉', '⠋⠉', '⠉⠙', '⠉⠙', '⠉⠩', '⠈⢙', '⠈⡙', '⠈⠩', '⠀⢙', '⠀⡙', '⠀⠩', '⠀⢘', '⠀⡘', '⠀⠨', '⠀⢐', '⠀⡐', '⠀⠠', '⠀⢀', '⠀⡀'],
  'line': ['-', '\\', '|', '/'],
  'line2': ['⠂', '-', '–', '—', '–', '-'],
  'pipe': ['┤', '┘', '┴', '└', '├', '┌', '┬', '┐'],
  'simpleDots': ['.  ', '.. ', '...', '   '],
  'simpleDotsScrolling': ['.  ', '.. ', '...', ' ..', '  .', '   '],
  'star': [
    '✶',
    '✸',
    '✹',
    '✺',
    '✹',
    '✷'
  ],
  'star2': [
    '+',
    'x',
    '*'
  ],
  'flip': [
    '_',
    '_',
    '_',
    '-',
    '`',
    '`',
    '\'',
    '´',
    '-',
    '_',
    '_',
    '_'
  ],
  'hamburger': ['☱', '☲', '☴'],
  'growVertical': ['▁', '▃', '▄', '▅', '▆', '▇', '▆', '▅', '▄', '▃'],
  'growHorizontal': ['▏', '▎', '▍', '▌', '▋', '▊', '▉', '▊', '▋', '▌', '▍', '▎'],
  'balloon': [' ', '.', 'o', 'O', '@', '*', ' '],
  'balloon2': ['.', 'o', 'O', '°', 'O', 'o', '.'],
  'noise': ['▓', '▒', '░'],
  'bounce': ['⠁', '⠂', '⠄', '⠂'],
  'boxBounce': ['▖', '▘', '▝', '▗'],
  'boxBounce2': ['▌', '▀', '▐', '▄'],
  'triangle': [
    '◢',
    '◣',
    '◤',
    '◥'
  ],
  'arc': ['◜', '◠', '◝', '◞', '◡', '◟'],
  'circle': ['◡', '⊙', '◠'],
  'squareCorners': ['◰', '◳', '◲', '◱'],
  'circleQuarters': ['◴', '◷', '◶', '◵'],
  'circleHalves': [
    '◐',
    '◓',
    '◑',
    '◒'
  ],
  'squish': ['╫', '╪'],
  'toggle': ['⊶', '⊷'],
  'toggle2': [
    '▫',
    '▪'
  ],
  'toggle3': ['□', '■'],
  'toggle4': ['■', '□', '▪', '▫'],
  'toggle5': ['▮', '▯'],
  'toggle6': ['ဝ', '၀'],
  'toggle7': [
    '⦾',
    '⦿'
  ],
  'toggle8': ['◍', '◌'],
  'toggle9': ['◉', '◎'],
  'toggle10': ['㊂', '㊀', '㊁'],
  'toggle11': [
    '⧇',
    '⧆'
  ],
  'toggle12': ['☗', '☖'],
  'toggle13': [
    '=',
    '*',
    '-'
  ],
  'arrow': ['←', '↖', '↑', '↗', '→', '↘', '↓', '↙'],
  'arrow2': [
    '⬆ ',
    '↗ ',
    '➡ ',
    '↘ ',
    '⬇ ',
    '↙ ',
    '⬅ ',
    '↖ '
  ],
  'arrow3': ['▹▹▹▹▹', '▸▹▹▹▹', '▹▸▹▹▹', '▹▹▸▹▹', '▹▹▹▸▹', '▹▹▹▹▸'],
  'bouncingBar': [
    '[    ]',
    '[=   ]',
    '[==  ]',
    '[=== ]',
    '[ ===]',
    '[  ==]',
    '[   =]',
    '[    ]',
    '[   =]',
    '[  ==]',
    '[ ===]',
    '[====]',
    '[=== ]',
    '[==  ]',
    '[=   ]'
  ],
  'bouncingBall': [
    '( ●    )',
    '(  ●   )',
    '(   ●  )',
    '(    ● )',
    '(     ●)',
    '(    ● )',
    '(   ●  )',
    '(  ●   )',
    '( ●    )',
    '(●     )'
  ],
  'smiley': ['😄 ', '😝 '],
  'monkey': ['🙈 ', '🙈 ', '🙉 ', '🙊 '],
  'hearts': ['💛 ', '💙 ', '💜 ', '💚 ', '❤ '],
  'clock': ['🕛 ', '🕐 ', '🕑 ', '🕒 ', '🕓 ', '🕔 ', '🕕 ', '🕖 ', '🕗 ', '🕘 ', '🕙 ', '🕚 '],
  'earth': ['🌍 ', '🌎 ', '🌏 '],
  'moon': [
    '🌑 ',
    '🌒 ',
    '🌓 ',
    '🌔 ',
    '🌕 ',
    '🌖 ',
    '🌗 ',
    '🌘 '
  ],
  'runner': ['🚶 ', '🏃 '],
  'pong': [
    '▐⠂       ▌',
    '▐⠈       ▌',
    '▐ ⠂      ▌',
    '▐ ⠠      ▌',
    '▐  ⡀     ▌',
    '▐  ⠠     ▌',
    '▐   ⠂    ▌',
    '▐   ⠈    ▌',
    '▐    ⠂   ▌',
    '▐    ⠠   ▌',
    '▐     ⡀  ▌',
    '▐     ⠠  ▌',
    '▐      ⠂ ▌',
    '▐      ⠈ ▌',
    '▐       ⠂▌',
    '▐       ⠠▌',
    '▐       ⡀▌',
    '▐      ⠠ ▌',
    '▐      ⠂ ▌',
    '▐     ⠈  ▌',
    '▐     ⠂  ▌',
    '▐    ⠠   ▌',
    '▐    ⡀   ▌',
    '▐   ⠠    ▌',
    '▐   ⠂    ▌',
    '▐  ⠈     ▌',
    '▐  ⠂     ▌',
    '▐ ⠠      ▌',
    '▐ ⡀      ▌',
    '▐⠠       ▌'
  ],
  'shark': ['▐|\\____________▌', '▐_|\\___________▌', '▐__|\\__________▌', '▐___|\\_________▌', '▐____|\\________▌', '▐_____|\\_______▌', '▐______|\\______▌', '▐_______|\\_____▌', '▐________|\\____▌', '▐_________|\\___▌', '▐__________|\\__▌', '▐___________|\\_▌', '▐____________|\\▌', '▐____________/|▌', '▐___________/|_▌', '▐__________/|__▌', '▐_________/|___▌', '▐________/|____▌', '▐_______/|_____▌', '▐______/|______▌', '▐_____/|_______▌', '▐____/|________▌', '▐___/|_________▌', '▐__/|__________▌', '▐_/|___________▌', '▐/|____________▌'],
  'dqpb': ['d', 'q', 'p', 'b'],
  'weather': ['☀ ', '☀ ', '☀ ', '🌤 ', '⛅ ', '🌥 ', '☁ ', '🌧 ', '🌨 ', '🌧 ', '🌨 ', '🌧 ', '🌨 ', '⛈ ', '🌨 ', '🌧 ', '🌨 ', '☁ ', '🌥 ', '⛅ ', '🌤 ', '☀ ', '☀ '],
  'christmas': ['🌲', '🎄'],
  'grenade': [
    '،   ',
    '′   ',
    ' ´ ',
    ' ‾ ',
    '  ⸌',
    '  ⸊',
    '  |',
    '  ⁎',
    '  ⁕',
    ' ෴ ',
    '  ⁓',
    '   ',
    '   ',
    '   '
  ],
  'point': ['∙∙∙', '●∙∙', '∙●∙', '∙∙●', '∙∙∙'],
  'layer': ['-', '=', '≡'
  ]

}
module.exports = spinner
<|endoftext|>


<commit_before>// freetext.js
//  - States for free text entry.

var Q = require('q');

var utils = require('../utils');
var state = require("./state");
var State = state.State;

var FreeText = State.extend(function(self, name, opts) {
    /**class:FreeText(opts)
    A state which displays a text, then allows the user to respond with
    any text.

    :param string name:
        name used to identify and refer to the state
    :param fn_or_str opts.next:
        state that the user should visit after this state. Functions should
        have the form ``f(message_content)`` and return the name of the next
        state (or a promise that will return the name). The value of ``this``
        inside ``f`` will be the calling :class:`FreeText` instance.
    :param string opts.question:
        text to display to the user.
    :param function opts.check:
        a function ``func(content)`` for validating a user's response. Should
        return ``true`` if the response is considered valid, and ``false`` if
        otherwise.
    :param string opts.error:
        error text to display to the user if we reach this state in error.
        Optional.
    :param boolean opts.send_reply:
        whether or not a reply should be sent to the user's message. Defaults
        to `true`.
    :param boolean opts.continue_session:
        whether or not this is the last state in a session. Defaults to `true`.
    */
    opts = utils.set_defaults(opts || {}, {
        check: null,
        error: ''
    });

    State.call(self, name, opts);
    self.next = opts.next;
    self.question_text = opts.question;
    self.check = opts.check;
    self.error_text = opts.error;
    self.in_error = false;

    self.on('state:enter', function() {
        self.in_error = false;
    });

    self.on('state:input', function(event) {
        var content = event.content;

        if (!content) { content = ""; }
        content = content.trim();

        if (!self.check_content(content)) {
            self.in_error = true;
            return Q();
        }

        var p = Q(utils.maybe_call(self.next, self, [content]));
        return p.then(function(next) {
            self.im.user.state.change(next),
            self.save_response(content);
        });
    });

    self.check_content = function(content) {
        if (!self.check) {
            return true;
        }

        return self.check.call(self, content);
    };

    self.translate = function(i18n) {
        self.question_text = i18n.gettext(self.question_text);

        if (self.error_text) {
            self.error_text = i18n.gettext(self.error_text);
        }
    };

    self.display = function() {
        return self.in_error
            ? self.error_text
            : self.question_text;
    };
});

this.FreeText = FreeText;
<commit_msg>Allow FreeText.check_content() to be able to return a promise<commit_after>// freetext.js
//  - States for free text entry.

var Q = require('q');

var utils = require('../utils');
var state = require("./state");
var State = state.State;

var FreeText = State.extend(function(self, name, opts) {
    /**class:FreeText(opts)
    A state which displays a text, then allows the user to respond with
    any text.

    :param string name:
        name used to identify and refer to the state
    :param fn_or_str opts.next:
        state that the user should visit after this state. Functions should
        have the form ``f(message_content)`` and return the name of the next
        state (or a promise that will return the name). The value of ``this``
        inside ``f`` will be the calling :class:`FreeText` instance.
    :param string opts.question:
        text to display to the user.
    :param function opts.check:
        a function ``func(content)`` for validating a user's response. Should
        return ``true`` if the response is considered valid, and ``false`` if
        otherwise. May return a promise.
    :param string opts.error:
        error text to display to the user if we reach this state in error.
        Optional.
    :param boolean opts.send_reply:
        whether or not a reply should be sent to the user's message. Defaults
        to `true`.
    :param boolean opts.continue_session:
        whether or not this is the last state in a session. Defaults to `true`.
    */
    opts = utils.set_defaults(opts || {}, {
        check: null,
        error: ''
    });

    State.call(self, name, opts);
    self.next = opts.next;
    self.question_text = opts.question;
    self.check_content = opts.check || utils.functor(true);
    self.error_text = opts.error;
    self.in_error = false;

    self.on('state:enter', function() {
        self.in_error = false;
    });

    self.on('state:input', function(event) {
        var content = event.content;

        if (!content) { content = ""; }
        content = content.trim();

        return Q()
            .then(function() {
                return self.check_content(content);
            })
            .then(function(valid) {
                if (!valid) {
                    self.in_error = true;
                    return;
                }

                var p = Q(utils.maybe_call(self.next, self, [content]));
                return p.then(function(next) {
                    self.im.user.state.change(next),
                    self.save_response(content);
                });
            });
    });

    self.translate = function(i18n) {
        self.question_text = i18n.gettext(self.question_text);

        if (self.error_text) {
            self.error_text = i18n.gettext(self.error_text);
        }
    };

    self.display = function() {
        return self.in_error
            ? self.error_text
            : self.question_text;
    };
});

this.FreeText = FreeText;
<|endoftext|>


<commit_before>/*jshint node:true strict:false*/
// Dependencies
var parse = require('../node_modules/connect/lib/utils').parseUrl,
    fs = require('fs'),
    join = require('path').join;

/*
Options must contain the following keys:
  root: The root directory in which to open files
  match: A regular expression denoting which files to open
  transform: A function which takes two arguments.
    The first argument is the text or buffer from the read file.
    The second argument is a callback function which accepts two arguments:
      The first argument is the transformed text / buffer
      The second argument (optional) is an object containing HTTP headers where keys (header names) map to values
Optionally, the following keys may be specified:
  normalize: May be a string or a function
    Example of string usage:
      match is set to /(.+)\.js/, normalize may be "$1.coffee".
      If the file "foo.js" is requested, then the file "foo.coffee" will be opened for transformation
    Example of function usage:
      match is set to /.+\.js/, normalize may be function (name) { return name.substring(0, name.length - 2) + 'coffee' }
      If the file "foo.js" is requested, then the file "foo.coffee" will be opened for transformation
  cache: if true then the transformed text will be cached
  encoding: defaults to 'utf-8', may be set to "buffer" to indicate that the transformation function is expecting a buffer
*/
module.exports = function (options) {
  // Check for required options
  if (!(options.root || options.match || options.transform)) {
    throw new Error('options.{root,match,transform} must be defined');
  }

  // Set encoding if not set and set to undefined if set to 'buffer'
  var e = options.encoding;
  options.encoding = e ? (e === 'buffer' ? undefined : e) : 'utf-8';

  // Create cache object
  var cache = {};

  // Return middleware function
  return function (req, res, next) {
    // Check request method
    if (req.method !== 'GET' && req.method !== 'HEAD') {
      return next();
    }
    // Check request path
    var path = parse(req).pathname;
    if (!options.match.test(path)) {
      return next();
    }
    // Normalize path if necessary
    if (options.normalize) {
      if (typeof options.normalize === 'string') {
        path = path.replace(options.match, options.normalize);
      } else if (typeof options.normalize === 'function') {
        path = options.normalize(path);
      }
    }
    // Join path
    path = join(options.root, path);
    if (options.cache && cache[path]) {
      // Check for 'If-Modified-Since' and write 304 if present
      if (req.headers['if-modified-since']) {
        res.writeHead(304);
        return res.end();
      }
      // Write out cached value
      var cacheVal = cache[path];
      writeOut(res, cacheVal.out, cacheVal.headers, options);
    } else {
      // Read and transform file
      fs.readFile(path, options.encoding, function (err, data) {
        if (err) {
          next();
        }
        options.transform(data, function (out, headers) {
          // Cache transformed value
          cache[path] = {out: out, headers: headers};
          // Write out transformed value
          writeOut(res, out, headers, options);
        });
      });
    }
  };
};

// Write output
function writeOut(res, out, headers, options) {
  res.writeHead(200, headers);
  res.end(out, options.encoding);
};
<commit_msg>Added support for HTTP HEAD.<commit_after>/*jshint node:true strict:false*/
// Dependencies
var parse = require('../node_modules/connect/lib/utils').parseUrl,
    fs = require('fs'),
    join = require('path').join;

/*
Options must contain the following keys:
  root: The root directory in which to open files
  match: A regular expression denoting which files to open
  transform: A function which takes two arguments.
    The first argument is the text or buffer from the read file.
    The second argument is a callback function which accepts two arguments:
      The first argument is the transformed text / buffer
      The second argument (optional) is an object containing HTTP headers where keys (header names) map to values
Optionally, the following keys may be specified:
  normalize: May be a string or a function
    Example of string usage:
      match is set to /(.+)\.js/, normalize may be "$1.coffee".
      If the file "foo.js" is requested, then the file "foo.coffee" will be opened for transformation
    Example of function usage:
      match is set to /.+\.js/, normalize may be function (name) { return name.substring(0, name.length - 2) + 'coffee' }
      If the file "foo.js" is requested, then the file "foo.coffee" will be opened for transformation
  cache: if true then the transformed text will be cached
  encoding: defaults to 'utf-8', may be set to "buffer" to indicate that the transformation function is expecting a buffer
*/
module.exports = function (options) {
  // Check for required options
  if (!(options.root || options.match || options.transform)) {
    throw new Error('options.{root,match,transform} must be defined');
  }

  // Set encoding if not set and set to undefined if set to 'buffer'
  var e = options.encoding;
  options.encoding = e ? (e === 'buffer' ? undefined : e) : 'utf-8';

  // Create cache object
  var cache = {};

  // Return middleware function
  return function (req, res, next) {
    // Check request method
    if (req.method !== 'GET' && req.method !== 'HEAD') {
      return next();
    }
    // Check request path
    var path = parse(req).pathname;
    if (!options.match.test(path)) {
      return next();
    }
    // Normalize path if necessary
    if (options.normalize) {
      if (typeof options.normalize === 'string') {
        path = path.replace(options.match, options.normalize);
      } else if (typeof options.normalize === 'function') {
        path = options.normalize(path);
      }
    }
    // Join path
    path = join(options.root, path);
    if (options.cache && cache[path]) {
      // Check for 'If-Modified-Since' and write 304 if present
      if (req.headers['if-modified-since']) {
        return writeOut(304, res, out, headers, options);
      }
      // Write out cached value
      var cacheVal = cache[path];
      writeOut(200, res, cacheVal.out, cacheVal.headers, options);
    } else {
      // Read and transform file
      fs.readFile(path, options.encoding, function (err, data) {
        if (err) {
          next();
        }
        options.transform(data, function (out, headers) {
          // Cache transformed value
          cache[path] = {out: out, headers: headers};
          // Write out transformed value
          writeOut(200, res, out, headers, options);
        });
      });
    }
  };
};

// Write output
function writeOut(code, res, out, headers, options) {
  res.writeHead(code, headers);
  if (code === 200) {
    res.end(out, options.encoding);
  } else {
    res.end();
  }
};
<|endoftext|>


<commit_before>var app       = require('app');
var browser   = require('browser-window');
var electrify = require('electrify')(__dirname);

var window    = null;

app.on('ready', function() {

  // electrify start
  electrify.start(function(meteor_root_url) {

    // creates a new electron window
    window = new browser({
      width: 1200, height: 900,
      'node-integration': false // node integration must to be off
    });

    // open up meteor root url
    window.loadUrl(meteor_root_url);
  });
});

app.on('window-all-closed', function() {
  app.quit();
});

app.on('will-quit', function terminate_and_quit(event) {

  // if electrify is up, cancel exiting with `preventDefault`,
  // so we can terminate electrify gracefully without leaving child
  // processes hanging in background
  if(electrify.isup() && event) {

    // holds electron termination
    event.preventDefault();

    // gracefully stops electrify
    electrify.stop(function(){

      // and then finally quit app
      app.quit();
    });
  }
});

// =============================================================================
//
// the methods bellow can be called seamlessly from your Meteor's
// client and server code, using:
//
//    Electrify.call('methodname', [..args..], callback);
//
// ATENTION:
//    From meteor, you can only call these methods after electrify is fully
//    started, use the Electrify.startup() convenience method for this
//
//
// Electrify.startup(function(){
//   Electrify.call(...);
// });
//
// =============================================================================

electrify.methods({
  'method.name': function(name, done) {
    // do things... and call done(err, arg1, ..., argN)
    done(null);
  }
});<commit_msg>commenting method example<commit_after>var app       = require('app');
var browser   = require('browser-window');
var electrify = require('electrify')(__dirname);

var window    = null;

app.on('ready', function() {

  // electrify start
  electrify.start(function(meteor_root_url) {

    // creates a new electron window
    window = new browser({
      width: 1200, height: 900,
      'node-integration': false // node integration must to be off
    });

    // open up meteor root url
    window.loadUrl(meteor_root_url);
  });
});

app.on('window-all-closed', function() {
  app.quit();
});

app.on('will-quit', function terminate_and_quit(event) {

  // if electrify is up, cancel exiting with `preventDefault`,
  // so we can terminate electrify gracefully without leaving child
  // processes hanging in background
  if(electrify.isup() && event) {

    // holds electron termination
    event.preventDefault();

    // gracefully stops electrify
    electrify.stop(function(){

      // and then finally quit app
      app.quit();
    });
  }
});

// =============================================================================
//
// the methods bellow can be called seamlessly from your Meteor's
// client and server code, using:
//
//    Electrify.call('methodname', [..args..], callback);
//
// ATENTION:
//    From meteor, you can only call these methods after electrify is fully
//    started, use the Electrify.startup() convenience method for this
//
//
// Electrify.startup(function(){
//   Electrify.call(...);
// });
//
// =============================================================================
//
// electrify.methods({
//   'method.name': function(name, done) {
//     // do things... and call done(err, arg1, ..., argN)
//     done(null);
//   }
// });
//
<|endoftext|>


<commit_before>// transform
// Functions for transformation matrices, and to be exact,
// affine non-reflective similarity transformation matrices.
//

// Identity transform, a kind of multiplication by 1.
exports.IDENTITY = {
  a: 1,
  b: 0,
  x: 0,
  y: 0
}

// Useful transformations
const isqrt2 = 1 / Math.sqrt(2)
exports.ROT45 = { a: isqrt2, b: isqrt2, x: 0, y: 0 }
exports.ROT90 = { a: 0, b: 1, x: 0, y: 0 }
exports.ROT180 = { a: -1, b: 0, x: 0, y: 0 }
exports.ROT270 = { a: 0, b: -1, x: 0, y: 0 }
exports.HALF = { a: 0.5, b: 0, x: 0, y: 0 }
exports.X2 = { a: 2, b: 0, x: 0, y: 0 }

// ### Functions ###

exports.almostEqual =
exports.almostEquals = require('./almostEqual')

exports.compose = require('./compose')

exports.create = require('./create')

exports.equal =
exports.equals = require('./equal')

exports.fromPolar = require('./fromPolar')

exports.fromArray = require('./fromArray')

exports.getRotation = require('./getRotation')

exports.getScale = require('./getScale')

exports.getTranslation = require('./getTranslation')

exports.multiply = exports.compose

exports.inverse = require('./inverse')

exports.rotateBy = require('./rotateBy')
exports.rotateTo = require('./rotateTo')

exports.scaleBy = require('./scaleBy')
exports.scaleTo = require('./scaleTo')

exports.toArray = require('./toArray')

exports.toMatrix = require('./toMatrix')

exports.toString = require('./toString')

// exports.addVector = ?
// exports.translate =
exports.translateBy = require('./translateBy')
exports.translateTo = require('./translateTo')

exports.validate = require('./validate')
<commit_msg>transform.SINGULAR<commit_after>// transform
// Functions for transformation matrices, and to be exact,
// affine non-reflective similarity transformation matrices.
//

// Singular transform, resembles multiplication by 0.
exports.SINGULAR = {
  a: 0,
  b: 0,
  x: 0,
  y: 0
}
// Identity transform, resembles multiplication by 1.
exports.IDENTITY = {
  a: 1,
  b: 0,
  x: 0,
  y: 0
}

// Useful transformations
const isqrt2 = 1 / Math.sqrt(2)
exports.ROT45 = { a: isqrt2, b: isqrt2, x: 0, y: 0 }
exports.ROT90 = { a: 0, b: 1, x: 0, y: 0 }
exports.ROT180 = { a: -1, b: 0, x: 0, y: 0 }
exports.ROT270 = { a: 0, b: -1, x: 0, y: 0 }
exports.HALF = { a: 0.5, b: 0, x: 0, y: 0 }
exports.X2 = { a: 2, b: 0, x: 0, y: 0 }

// ### Functions ###

exports.almostEqual =
exports.almostEquals = require('./almostEqual')

exports.compose = require('./compose')

exports.create = require('./create')

exports.equal =
exports.equals = require('./equal')

exports.fromPolar = require('./fromPolar')

exports.fromArray = require('./fromArray')

exports.getRotation = require('./getRotation')

exports.getScale = require('./getScale')

exports.getTranslation = require('./getTranslation')

exports.multiply = exports.compose

exports.inverse = require('./inverse')

exports.rotateBy = require('./rotateBy')
exports.rotateTo = require('./rotateTo')

exports.scaleBy = require('./scaleBy')
exports.scaleTo = require('./scaleTo')

exports.toArray = require('./toArray')

exports.toMatrix = require('./toMatrix')

exports.toString = require('./toString')

// exports.addVector = ?
// exports.translate =
exports.translateBy = require('./translateBy')
exports.translateTo = require('./translateTo')

exports.validate = require('./validate')
<|endoftext|>


<commit_before>var util = require('util')
var JSONStream = require('JSONStream')
var fs = require('fs')
var endOfLine = require('os').EOL

var file = function (parent, file, options) {
  this.options = options
  this.parent = parent
  this.file = file
  this.lineCounter = 0
  this.localLineCounter = 0
  this.stream = null
  this.elementsToSkip = 0
}

// accept callback
// return (error, arr) where arr is an array of objects
file.prototype.get = function (limit, offset, callback) {
  var self = this
  self.thisGetLimit = limit
  self.thisGetCallback = callback
  self.localLineCounter = 0

  if (self.lineCounter === 0) {
    self.setupGet(offset)
  } else {
    self.metaStream.resume()
  }

  if (!self.metaStream.readable) {
    self.completeBatch(null, self.thisGetCallback)
  }
}

file.prototype.setupGet = function (offset) {
  var self = this

  self.bufferedData = []
  self.stream = JSONStream.parse()

  if (!self.elementsToSkip) { self.elementsToSkip = offset }

  if (self.file === '$') {
    self.metaStream = process.stdin
  } else {
    self.metaStream = fs.createReadStream(self.file)
  }

  self.stream.on('data', function (elem) {
    if (self.elementsToSkip > 0) {
      self.elementsToSkip--
    } else {
      self.bufferedData.push(elem)
    }

    self.localLineCounter++
    self.lineCounter++

    if (self.localLineCounter === self.thisGetLimit) {
      self.completeBatch(null, self.thisGetCallback)
    }
  })

  self.stream.on('error', function (e) {
    self.parent.emit('error', e)
  })

  self.stream.on('end', function () {
    self.completeBatch(null, self.thisGetCallback, true)
  })

  self.metaStream.pipe(self.stream)
}

file.prototype.completeBatch = function (error, callback, streamEnded) {
  var self = this
  var data = []

  self.metaStream.pause()

  if (error) { return callback(error) }

  // if we are skipping, have no data, and there is more to read we should continue on
  if (!streamEnded && self.elementsToSkip > 0 && self.bufferedData.length === 0) {
    return self.metaStream.resume()
  }

  while (self.bufferedData.length > 0) {
    data.push(self.bufferedData.pop())
  }

  return callback(null, data)
}

// accept arr, callback where arr is an array of objects
// return (error, writes)
file.prototype.set = function (data, limit, offset, callback) {
  var self = this
  var error = null
  var targetElem

  self.lineCounter = 0

  if (!self.stream) {
    if (self.file === '$') {
      self.stream = process.stdout
    } else {
      // TODO: add options to append and replace the file
      if (fs.existsSync(self.file)) {
        return callback(new Error('File `' + self.file + '` already exists, quitting'))
      } else {
        self.stream = fs.createWriteStream(self.file)
      }
    }
  }

  if (data.length === 0) {
    if (self.file === '$') {
      process.nextTick(callback(null, self.lineCounter))
    } else {
      self.stream.on('close', function () {
        delete self.stream
        return callback(null, self.lineCounter)
      })

      self.stream.end()
    }
  } else {
    data.forEach(function (elem) {
      // Select _source if sourceOnly
      if (self.parent.options.sourceOnly === true) {
        targetElem = elem._source
      } else {
        targetElem = elem
      }

      if (self.parent.options.format && self.parent.options.format.toLowerCase() === 'human') {
        self.log(util.inspect(targetElem, false, 10, true))
      } else {
        self.log(JSON.stringify(targetElem))
      }

      self.lineCounter++
    })

    process.nextTick(function () {
      callback(error, self.lineCounter)
    })
  }
}

file.prototype.log = function (line) {
  this.stream.write(line + endOfLine)
}

exports.file = file
<commit_msg>Ensures that callback is called on nextTick(), rather than immediately.<commit_after>var util = require('util')
var JSONStream = require('JSONStream')
var fs = require('fs')
var endOfLine = require('os').EOL

var file = function (parent, file, options) {
  this.options = options
  this.parent = parent
  this.file = file
  this.lineCounter = 0
  this.localLineCounter = 0
  this.stream = null
  this.elementsToSkip = 0
}

// accept callback
// return (error, arr) where arr is an array of objects
file.prototype.get = function (limit, offset, callback) {
  var self = this
  self.thisGetLimit = limit
  self.thisGetCallback = callback
  self.localLineCounter = 0

  if (self.lineCounter === 0) {
    self.setupGet(offset)
  } else {
    self.metaStream.resume()
  }

  if (!self.metaStream.readable) {
    self.completeBatch(null, self.thisGetCallback)
  }
}

file.prototype.setupGet = function (offset) {
  var self = this

  self.bufferedData = []
  self.stream = JSONStream.parse()

  if (!self.elementsToSkip) { self.elementsToSkip = offset }

  if (self.file === '$') {
    self.metaStream = process.stdin
  } else {
    self.metaStream = fs.createReadStream(self.file)
  }

  self.stream.on('data', function (elem) {
    if (self.elementsToSkip > 0) {
      self.elementsToSkip--
    } else {
      self.bufferedData.push(elem)
    }

    self.localLineCounter++
    self.lineCounter++

    if (self.localLineCounter === self.thisGetLimit) {
      self.completeBatch(null, self.thisGetCallback)
    }
  })

  self.stream.on('error', function (e) {
    self.parent.emit('error', e)
  })

  self.stream.on('end', function () {
    self.completeBatch(null, self.thisGetCallback, true)
  })

  self.metaStream.pipe(self.stream)
}

file.prototype.completeBatch = function (error, callback, streamEnded) {
  var self = this
  var data = []

  self.metaStream.pause()

  if (error) { return callback(error) }

  // if we are skipping, have no data, and there is more to read we should continue on
  if (!streamEnded && self.elementsToSkip > 0 && self.bufferedData.length === 0) {
    return self.metaStream.resume()
  }

  while (self.bufferedData.length > 0) {
    data.push(self.bufferedData.pop())
  }

  return callback(null, data)
}

// accept arr, callback where arr is an array of objects
// return (error, writes)
file.prototype.set = function (data, limit, offset, callback) {
  var self = this
  var error = null
  var targetElem

  self.lineCounter = 0

  if (!self.stream) {
    if (self.file === '$') {
      self.stream = process.stdout
    } else {
      // TODO: add options to append and replace the file
      if (fs.existsSync(self.file)) {
        return callback(new Error('File `' + self.file + '` already exists, quitting'))
      } else {
        self.stream = fs.createWriteStream(self.file)
      }
    }
  }

  if (data.length === 0) {
    if (self.file === '$') {
      process.nextTick(() => callback(null, self.lineCounter))
    } else {
      self.stream.on('close', function () {
        delete self.stream
        return callback(null, self.lineCounter)
      })

      self.stream.end()
    }
  } else {
    data.forEach(function (elem) {
      // Select _source if sourceOnly
      if (self.parent.options.sourceOnly === true) {
        targetElem = elem._source
      } else {
        targetElem = elem
      }

      if (self.parent.options.format && self.parent.options.format.toLowerCase() === 'human') {
        self.log(util.inspect(targetElem, false, 10, true))
      } else {
        self.log(JSON.stringify(targetElem))
      }

      self.lineCounter++
    })

    process.nextTick(function () {
      callback(error, self.lineCounter)
    })
  }
}

file.prototype.log = function (line) {
  this.stream.write(line + endOfLine)
}

exports.file = file
<|endoftext|>


<commit_before>
/*!
 * socket.io-node
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module requirements.
 */

var Transport = require('../transport')
  , parser = require('../parser')
  , qs = require('querystring');

/**
 * Export the constructor.
 */

exports = module.exports = HTTPTransport;

/**
 * HTTP interface constructor. For all non-websocket transports.
 *
 * @api public
 */

function HTTPTransport (mng, data, req) {
  Transport.call(this, mng, data, req);
};

/**
 * Inherits from Transport.
 */

HTTPTransport.prototype.__proto__ = Transport.prototype;

/**
 * Handles a request.
 *
 * @api private
 */

HTTPTransport.prototype.handleRequest = function (req) {

  // Always set the response in case an error is returned to the client
  this.response = req.res;

  if (req.method == 'POST') {
    var buffer = ''
      , res = req.res
      , origin = req.headers.origin
      , headers = { 'Content-Length': 1, 'Content-Type': 'application/javascript; charset=UTF-8' }
      , self = this;

    req.on('data', function (data) {
      buffer += data;

      if (Buffer.byteLength(buffer) >= self.manager.get('destroy buffer size')) {
        buffer = '';
        req.connection.destroy();
      }
    });

    req.on('end', function () {
      res.writeHead(200, headers);
      res.end('1');

      self.onData(self.postEncoded ? qs.parse(buffer).d : buffer);
    });

    // prevent memory leaks for uncompleted requests
    req.on('close', function () {
      buffer = '';
      self.onClose();
    });

    if (origin) {
      // https://developer.mozilla.org/En/HTTP_Access_Control
      headers['Access-Control-Allow-Origin'] = origin;
      headers['Access-Control-Allow-Credentials'] = 'true';
    }
  } else {
    Transport.prototype.handleRequest.call(this, req);
  }
};

/**
 * Handles data payload.
 *
 * @api private
 */

HTTPTransport.prototype.onData = function (data) {
  var messages = parser.decodePayload(data);
  this.log.debug(this.name + ' received data packet', data);

  for (var i = 0, l = messages.length; i < l; i++) {
    this.onMessage(messages[i]);
  }
};

/**
 * Closes the request-response cycle
 *
 * @api private
 */

HTTPTransport.prototype.doClose = function () {
  this.response.end();
};

/**
 * Writes a payload of messages
 *
 * @api private
 */

HTTPTransport.prototype.payload = function (msgs) {
  this.write(parser.encodePayload(msgs));
};
<commit_msg>header text/plain on post response<commit_after>
/*!
 * socket.io-node
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module requirements.
 */

var Transport = require('../transport')
  , parser = require('../parser')
  , qs = require('querystring');

/**
 * Export the constructor.
 */

exports = module.exports = HTTPTransport;

/**
 * HTTP interface constructor. For all non-websocket transports.
 *
 * @api public
 */

function HTTPTransport (mng, data, req) {
  Transport.call(this, mng, data, req);
};

/**
 * Inherits from Transport.
 */

HTTPTransport.prototype.__proto__ = Transport.prototype;

/**
 * Handles a request.
 *
 * @api private
 */

HTTPTransport.prototype.handleRequest = function (req) {

  // Always set the response in case an error is returned to the client
  this.response = req.res;

  if (req.method == 'POST') {
    var buffer = ''
      , res = req.res
      , origin = req.headers.origin
      , headers = { 'Content-Length': 1, 'Content-Type': 'text/plain; charset=UTF-8' }
      , self = this;

    req.on('data', function (data) {
      buffer += data;

      if (Buffer.byteLength(buffer) >= self.manager.get('destroy buffer size')) {
        buffer = '';
        req.connection.destroy();
      }
    });

    req.on('end', function () {
      res.writeHead(200, headers);
      res.end('1');

      self.onData(self.postEncoded ? qs.parse(buffer).d : buffer);
    });

    // prevent memory leaks for uncompleted requests
    req.on('close', function () {
      buffer = '';
      self.onClose();
    });

    if (origin) {
      // https://developer.mozilla.org/En/HTTP_Access_Control
      headers['Access-Control-Allow-Origin'] = origin;
      headers['Access-Control-Allow-Credentials'] = 'true';
    }
  } else {
    Transport.prototype.handleRequest.call(this, req);
  }
};

/**
 * Handles data payload.
 *
 * @api private
 */

HTTPTransport.prototype.onData = function (data) {
  var messages = parser.decodePayload(data);
  this.log.debug(this.name + ' received data packet', data);

  for (var i = 0, l = messages.length; i < l; i++) {
    this.onMessage(messages[i]);
  }
};

/**
 * Closes the request-response cycle
 *
 * @api private
 */

HTTPTransport.prototype.doClose = function () {
  this.response.end();
};

/**
 * Writes a payload of messages
 *
 * @api private
 */

HTTPTransport.prototype.payload = function (msgs) {
  this.write(parser.encodePayload(msgs));
};
<|endoftext|>