<commit_before>var inherit = require('../inherit');
var registerFeature = require('../registry').registerFeature;
var pointFeature = require('../pointFeature');

/**
 * Create a new instance of vtkjs.pointFeature.
 *
 * @class
 * @alias geo.vtkjs.pointFeature
 * @extends geo.pointFeature
 * @param {geo.pointFeature.spec} arg
 * @returns {geo.vtkjs.pointFeature}
 */
var vtkjs_pointFeature = function (arg) {
  'use strict';
  if (!(this instanceof vtkjs_pointFeature)) {
    return new vtkjs_pointFeature(arg);
  }
  arg = arg || {};
  pointFeature.call(this, arg);

  var transform = require('../transform');
  var object = require('../object');
  var vtk = require('./vtkjsRenderer').vtkjs;
  var vtkActor = vtk.Rendering.Core.vtkActor;
  var vtkMapper = vtk.Rendering.Core.vtkGlyph3DMapper;
  var vtkPointSet = vtk.Common.DataModel.vtkPointSet;
  var vtkSphereSource = vtk.Filters.Sources.vtkSphereSource;

  object.call(this);

  /**
   * @private
   */
  var m_this = this,
      m_actor,
      m_pointSet,
      m_source,
      s_init = this._init,
      s_exit = this._exit,
      s_update = this._update;

  /**
   * Create pipeline.
   */
  this._createPipeline = function () {
    m_pointSet = vtkPointSet.newInstance();
    m_source = vtkSphereSource.newInstance();
    m_source.setThetaResolution(30);
    m_source.setPhiResolution(30);
    var mapper = vtkMapper.newInstance();
    mapper.setInputData(m_pointSet, 0);
    mapper.setInputConnection(m_source.getOutputPort(), 1);
    m_actor = vtkActor.newInstance();
    m_actor.setMapper(mapper);
    m_actor.getProperty().setAmbient(1);
    this.renderer().contextRenderer().addActor(m_actor);
  };

  /**
   * Initialize.
   */
  this._init = function () {
    s_init.call(m_this, arg);
    m_this.renderer().contextRenderer().setLayer(1);
    this._createPipeline();
  };

  /**
   * Build this feature.
   */
  this._build = function () {
    var i, i3, posVal,
        nonzeroZ,
        numPts = m_this.data().length,
        position = new Array(numPts * 3),
        data = m_this.data(),
        posFunc = m_this.position(),
        radFunc = m_this.style.get('radius'),
        colorFunc = m_this.style.get('fillColor'),
        opacityFunc = m_this.style.get('fillOpacity');

    /* It is more efficient to do a transform on a single array rather than on
      * an array of arrays or an array of objects. */
    for (i = i3 = 0; i < numPts; i += 1, i3 += 3) {
      posVal = posFunc(data[i], i);
      position[i3] = posVal.x;
      position[i3 + 1] = posVal.y;
      position[i3 + 2] = posVal.z || 0;
      nonzeroZ = nonzeroZ || position[i3 + 2];
      // TODO: fix the opacity per point.
      m_actor.getProperty().setOpacity(opacityFunc(data[i], i));
    }
    position = transform.transformCoordinates(
      m_this.gcs(), m_this.layer().map().gcs(),
      position, 3);

    /* Some transforms modify the z-coordinate.  If we started with all zero z
     * coordinates, don't modify them.  This could be changed if the
     * z-coordinate space of the gl cube is scaled appropriately. */
    if (!nonzeroZ && m_this.gcs() !== m_this.layer().map().gcs()) {
      for (i = i3 = 0; i < numPts; i += 1, i3 += 3) {
        position[i3 + 2] = 0;
      }
    }

    // TODO: points can vary, this needs to be refactors to have a distinct
    // size per point.  What should be done with the strokeColor, strokeWidth,
    // and strokeOpacity?  Honor the fill/stroke options or document that we
    // don't honot them.  Handle the zero-data-itmes condition.
    var rad = radFunc(data[0], 0), clr = colorFunc(data[0], 0);
    rad *= m_this.layer().map().unitsPerPixel(m_this.layer().map().zoom());
    m_pointSet.getPoints().setData(position, 3);
    m_source.setRadius(rad);
    m_actor.getProperty().setColor(clr.r, clr.g, clr.b);
    m_this.buildTime().modified();
  };

  /**
   * Update.
   */
  this._update = function () {
    s_update.call(m_this);

    if (m_this.dataTime().getMTime() >= m_this.buildTime().getMTime() ||
        m_this.updateTime().getMTime() < m_this.getMTime()) {
      m_this._build();
    } else {
      var data = m_this.data(),
          radFunc = m_this.style.get('radius'),
          rad = radFunc(data[0], 0);
      rad *= m_this.layer().map().unitsPerPixel(m_this.layer().map().zoom());
      m_source.setRadius(rad);
    }

    m_this.updateTime().modified();
  };

  /**
   * Destroy.
   */
  this._exit = function () {
    m_this.renderer().contextRenderer().removeActor(m_actor);
    s_exit();
  };

  m_this._init();
  return this;
};

inherit(vtkjs_pointFeature, pointFeature);

// Now register it
registerFeature('vtkjs', 'point', vtkjs_pointFeature);

module.exports = vtkjs_pointFeature;
<commit_msg>Update vtk.js pointFeature<commit_after>var inherit = require('../inherit');
var registerFeature = require('../registry').registerFeature;
var pointFeature = require('../pointFeature');

/**
 * Create a new instance of vtkjs.pointFeature.
 *
 * @class
 * @alias geo.vtkjs.pointFeature
 * @extends geo.pointFeature
 * @param {geo.pointFeature.spec} arg
 * @returns {geo.vtkjs.pointFeature}
 */
var vtkjs_pointFeature = function (arg) {
  'use strict';
  if (!(this instanceof vtkjs_pointFeature)) {
    return new vtkjs_pointFeature(arg);
  }
  arg = arg || {};
  pointFeature.call(this, arg);

  var transform = require('../transform');
  var object = require('../object');
  var vtk = require('./vtkjsRenderer').vtkjs;
  var vtkActor = vtk.Rendering.Core.vtkActor;
  var vtkMapper = vtk.Rendering.Core.vtkGlyph3DMapper;
  var vtkPointSet = vtk.Common.DataModel.vtkPointSet;
  var vtkSphereSource = vtk.Filters.Sources.vtkSphereSource;

  object.call(this);

  /**
   * @private
   */
  var m_this = this,
      m_actor,
      m_pointSet,
      m_source,
      s_init = this._init,
      s_exit = this._exit,
      s_update = this._update;

  /**
   * Create pipeline.
   */
  this._createPipeline = function () {
    m_pointSet = vtkPointSet.newInstance();
    m_source = vtkSphereSource.newInstance();
    m_source.setThetaResolution(30);
    m_source.setPhiResolution(30);
    var mapper = vtkMapper.newInstance({
      // Orientation
      orient: false,

      // Color
      // useLookupTableScalarRange: true,  // FIXME <----
      // lookupTable,                      // FIXME <----
      colorByArrayName: 'color',
      colorMode: vtkMapper.ColorMode.MAP_SCALARS,
      scalarMode: vtkMapper.ScalarMode.USE_POINT_FIELD_DATA,
      scalarVisibility: true,

      // Opactity
      // => not available yet

      // Scaling
      scaling: true,
      scaleArray: 'radius',
      scaleMode: vtkGlyph3DMapper.ScaleModes.SCALE_BY_MAGNITUDE,
    });
    mapper.setInputData(m_pointSet, 0);
    mapper.setInputConnection(m_source.getOutputPort(), 1);
    m_actor = vtkActor.newInstance();
    m_actor.setMapper(mapper);
    m_actor.getProperty().setAmbient(1);
    this.renderer().contextRenderer().addActor(m_actor);
  };

  /**
   * Initialize.
   */
  this._init = function () {
    s_init.call(m_this, arg);
    m_this.renderer().contextRenderer().setLayer(1);
    this._createPipeline();
  };

  /**
   * Build this feature.
   */
  this._build = function () {
    var i, i3, posVal,
        nonzeroZ,
        numPts = m_this.data().length,
        data = m_this.data(),
        posFunc = m_this.position(),
        radFunc = m_this.style.get('radius'),
        colorFunc = m_this.style.get('fillColor'),
        opacityFunc = m_this.style.get('fillOpacity');

    const position = new Float64Array(numPts * 3);
    const opacityArray = new Float32Array(numPts);
    const colorArray = new Float32Array(numPts); // FIXME maybe not the right type
    const radiusArray = new Float32Array(numPts);

    /* It is more efficient to do a transform on a single array rather than on
      * an array of arrays or an array of objects. */
    for (i = i3 = 0; i < numPts; i += 1, i3 += 3) {
      posVal = posFunc(data[i], i);
      position[i3] = posVal.x;
      position[i3 + 1] = posVal.y;
      position[i3 + 2] = posVal.z || 0;
      nonzeroZ = nonzeroZ || position[i3 + 2];

      // Register opacity/color/radius
      opacityArray[i] = opacityFunc(data[i], i);
      colorArray[i] = colorFunc(data[i], i);
      radiusArray[i] = radFunc(data[i], i)
    }
    position = transform.transformCoordinates(
      m_this.gcs(), m_this.layer().map().gcs(),
      position, 3);

    /* Some transforms modify the z-coordinate.  If we started with all zero z
     * coordinates, don't modify them.  This could be changed if the
     * z-coordinate space of the gl cube is scaled appropriately. */
    if (!nonzeroZ && m_this.gcs() !== m_this.layer().map().gcs()) {
      for (i = i3 = 0; i < numPts; i += 1, i3 += 3) {
        position[i3 + 2] = 0;
      }
    }

    // TODO: points can vary, this needs to be refactors to have a distinct
    // size per point.  What should be done with the strokeColor, strokeWidth,
    // and strokeOpacity?  Honor the fill/stroke options or document that we
    // don't honot them.  Handle the zero-data-itmes condition.
    rad *= m_this.layer().map().unitsPerPixel(m_this.layer().map().zoom());
    m_pointSet.getPoints().setData(position, 3);

    // Attach fields
    m_pointSet.getPointData().addArray(vtkDataArray.newInstance({ name: 'color', values: colorArray }));
    m_pointSet.getPointData().addArray(vtkDataArray.newInstance({ name: 'opacity', values: opacityArray }));
    m_pointSet.getPointData().addArray(vtkDataArray.newInstance({ name: 'radius', values: radiusArray }));

    m_this.buildTime().modified();
  };

  /**
   * Update.
   */
  this._update = function () {
    s_update.call(m_this);

    if (m_this.dataTime().getMTime() >= m_this.buildTime().getMTime() ||
        m_this.updateTime().getMTime() < m_this.getMTime()) {
      m_this._build();
    } else {
      var data = m_this.data(),
          radFunc = m_this.style.get('radius');

      const scalingFactor = m_this.layer().map().unitsPerPixel(m_this.layer().map().zoom());
      const dataArray = m_pointSet.getPointData().getArray('radius');
      const newScaleArray = dataArray.getData().map((v, i) => radFunc(data[i], i) * scalingFactor);

      dataArray.setData(newScaleArray);
    }

    m_this.updateTime().modified();
  };

  /**
   * Destroy.
   */
  this._exit = function () {
    m_this.renderer().contextRenderer().removeActor(m_actor);
    s_exit();
  };

  m_this._init();
  return this;
};

inherit(vtkjs_pointFeature, pointFeature);

// Now register it
registerFeature('vtkjs', 'point', vtkjs_pointFeature);

module.exports = vtkjs_pointFeature;
<|endoftext|>


<commit_before>/* by Oratio.io */

//Node Standard Modules
var child_process = require('child_process');
var path = require('path');
var fs = require('fs');

//NPM Modules
var Promise = require('bluebird');
var messenger = require('messenger');

//safe-instances Modules
var util = require('./util');

function Child(code, pool, options){
  this.encoding = 'utf8';
  this.timeout = options.timeout || 60; //Defaults to 60 seconds
  this.logs = options.logs || true;
  this.code = code;
  this.pool = pool || null;
  this.speakerPort = options.speakerPort || util.getRandomInt(25010, 25400);
  this.listenerPort = options.listenerPort || this.speakerPort;
  this.speaker = messenger.createSpeaker(this.speakerPort);
  this.listener = messenger.createListener(this.listenerPort);

  //Private Properties
  this._messageHandler = {};
  this._errorHandler = {};
}

Child.prototype.setPool = function(pool){
  this.pool = pool;
}

Child.prototype.start = function(){
  var timeout = this.timeout.toString();
  var childProcess = this.pool.getProcess();

  childProcess.process.send({code: code, timeout: timeout})
  this.process = childProcess;
  return this.process;
}

Child.prototype.contact = function(messageType, message){
  return new Promise(function(resolve, reject){
    var requestId = util.getRandomInt(10001, 99999);

    var self = this;
    var handler = function(error, message){
      self.pool.inUse = false;
      if(error){
        return reject(error);
      }
      return resolve(message)
    }

    child.pool._handlers[requestId] = handler;
    this.process.send({messageType: message, id: requestId});
  })
}
Child.commandType = 'node';

//File Based.
function ChildFile(location, timeout){
  this.encoding = 'utf8';
  this.timeout = timeout || 60; //Defaults to 60 seconds
  this.logs = true;
  this.code = code;
  this.pool = null;

  var self = this;
  return new Promise(function(resolve, reject){
    if(ChildFile.usesCache === false || (ChildFile.usesCache === true && cache[location] == undefined)){
      fs.readFile(location, self.encoding, function(error, file){
        if(error)
          throw error;

        self.code = file;
        cache[location] = file;
        resolve();
      });
    }else{
      self.code = cache[location];
      process.nextTick(function(){
        resolve();
      });
    }
  });
}

ChildFile.usesCache = true;
ChildFile.prototype.setPool = Child.prototype.setPool;
ChildFile.prototype.contact = Child.prototype.contact;
ChildFile.prototype.start = Child.prototype.start;

Child.File = ChildFile;

module.exports = Child;
<commit_msg>Update parent.js<commit_after>/* by Oratio.io */

//Node Standard Modules
var child_process = require('child_process');
var path = require('path');
var fs = require('fs');

//NPM Modules
var Promise = require('bluebird');
var messenger = require('messenger');

//safe-instances Modules
var util = require('./util');

function Child(code, pool, options){
  this.timeout = options.timeout || 60; //Defaults to 60 seconds
  this.logs = options.logs || true;
  this.code = code;
  this.pool = pool || null;
  this.speakerPort = options.speakerPort || util.getRandomInt(25010, 25400);
  this.listenerPort = options.listenerPort || this.speakerPort;
  this.speaker = messenger.createSpeaker(this.speakerPort);
  this.listener = messenger.createListener(this.listenerPort);

  //Private Properties
  this._messageHandler = {};
  this._errorHandler = {};
}

Child.prototype.setPool = function(pool){
  this.pool = pool;
}

Child.prototype.start = function(){
  var timeout = this.timeout.toString();
  var childProcess = this.pool.getProcess();

  childProcess.process.send({
    code: code,
    timeout: timeout,
    speakerPort: this.speakerPort,
    listenerPort: this.listenerPort
  });

  this.process = childProcess;
  return this.process;
}

Child.prototype.contact = function(messageType, message){
  return new Promise(function(resolve, reject){
    var requestId = util.getRandomInt(10001, 99999);

    var self = this;
    var handler = function(error, message){
      self.pool.inUse = false;
      if(error){
        return reject(error);
      }
      return resolve(message)
    }

    child.pool._handlers[requestId] = handler;
    this.process.send({messageType: message, id: requestId});
  })
}
Child.commandType = 'node';

//File Based.
function ChildFile(location, timeout){
  this.encoding = 'utf8';
  this.timeout = options.timeout || 60; //Defaults to 60 seconds
  this.logs = options.logs || true;
  this.code = code;
  this.pool = pool || null;
  this.speakerPort = options.speakerPort || util.getRandomInt(25010, 25400);
  this.listenerPort = options.listenerPort || this.speakerPort;
  this.speaker = messenger.createSpeaker(this.speakerPort);
  this.listener = messenger.createListener(this.listenerPort);
  var self = this;
  return new Promise(function(resolve, reject){
    if(ChildFile.usesCache === false || (ChildFile.usesCache === true && cache[location] == undefined)){
      fs.readFile(location, self.encoding, function(error, file){
        if(error)
          throw error;

        self.code = file;
        cache[location] = file;
        resolve();
      });
    }else{
      self.code = cache[location];
      process.nextTick(function(){
        resolve();
      });
    }
  });
}

ChildFile.usesCache = true;
ChildFile.prototype.setPool = Child.prototype.setPool;
ChildFile.prototype.contact = Child.prototype.contact;
ChildFile.prototype.start = Child.prototype.start;

Child.File = ChildFile;

module.exports = Child;
<|endoftext|>


<commit_before>"use strict";

var getItemURL = require('./get_item_url')
  , regex = /^document (\d+)$/

module.exports = function (md, opts) {

  opts = opts || {};

  md.use(require('markdown-it-container'), 'document', {
    validate: function (params) {
      return params.trim().match(regex)
    },
    render: function (tokens, idx) {
      var match = tokens[idx].info.trim().match(regex)

      if (tokens[idx].nesting === 1) {
        let documentURL = getItemURL(opts.projectBaseURL, 'document', match[1])
          , documentText = opts.makeCitationText(documentURL)

        tokens[idx].meta = { enItemType: 'document', enItemID: match[1] }

        return '

' + documentText + '
';
      } else {
        return '
';
      }
    }
  });
}
<commit_msg>Store document meta properties in document block extension<commit_after>"use strict";

var getItemURL = require('./get_item_url')
  , regex = /^document (\d+)$/

function createRule(md, projectBaseURL, makeCitationText) {
  return function enDocumentBlockMetaRule(state) {
    var blockTokens = state.tokens

    blockTokens.forEach(function (token) {
      if (token.type === 'container_document_open') {
        let match = token.info.trim().match(regex)
          , documentURL = getItemURL(projectBaseURL, 'document', match[1])
          , documentText = makeCitationText(documentURL)

        token.meta = {
          enCitationText: documentText,
          enItemType: 'document',
          enItemID: match[1]
        }
      }
    })
  }
}

module.exports = function (md, opts) {

  opts = opts || {};

  md.use(require('markdown-it-container'), 'document', {
    validate: function (params) {
      return params.trim().match(regex)
    },
    render: function (tokens, idx) {
      if (tokens[idx].nesting === 1) {
        return '

' + tokens[idx].meta.enCitationText + '
';
      } else {
        return '
';
      }
    }
  });

  md.core.ruler.push(
    'en_document_block_meta',
    createRule(md, opts.projectBaseURL, opts.makeCitationText)
  )
}
<|endoftext|>


<commit_before>// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
// License: New BSD License
// Reference: http://dev.w3.org/html5/websockets/
// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol

(function() {

  if (window.WebSocket) return;

  var console = window.console;
  if (!console) console = {log: function(){ }, error: function(){ }};

  function hasFlash() {
    if ('navigator' in window && 'plugins' in navigator && navigator.plugins['Shockwave Flash']) {
      return !!navigator.plugins['Shockwave Flash'].description;
    }
    if ('ActiveXObject' in window) {
      try {
        return !!new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
      } catch (e) {}
    }
    return false;
  }

  if (!hasFlash()) {
    console.error("Flash Player is not installed.");
    return;
  }

  WebSocket = function(url, protocol, proxyHost, proxyPort, headers) {
    var self = this;
    self.readyState = WebSocket.CONNECTING;
    self.bufferedAmount = 0;
    WebSocket.__addTask(function() {
      self.__flash =
        WebSocket.__flash.create(url, protocol, proxyHost || null, proxyPort || 0, headers || null);

      self.__flash.addEventListener("open", function(fe) {
        try {
          if (self.onopen) self.onopen();
        } catch (e) {
          console.error(e.toString());
        }
      });

      self.__flash.addEventListener("close", function(fe) {
        try {
          if (self.onclose) self.onclose();
        } catch (e) {
          console.error(e.toString());
        }
      });

      self.__flash.addEventListener("message", function(fe) {
        var data = decodeURIComponent(fe.getData());
        try {
          if (self.onmessage) {
            var e;
            if (window.MessageEvent) {
              e = document.createEvent("MessageEvent");
              e.initMessageEvent("message", false, false, data, null, null, window);
            } else { // IE
              e = {data: data};
            }
            self.onmessage(e);
          }
        } catch (e) {
          console.error(e.toString());
        }
      });

      self.__flash.addEventListener("error", function(fe) {
        try {
          if (self.onerror) self.onerror();
        } catch (e) {
          console.error(e.toString());
        }
      });

      self.__flash.addEventListener("stateChange", function(fe) {
        try {
          self.readyState = fe.getReadyState();
          self.bufferedAmount = fe.getBufferedAmount();
        } catch (e) {
          console.error(e.toString());
        }
      });

      //console.log("[WebSocket] Flash object is ready");
    });
  }

  WebSocket.prototype.send = function(data) {
    if (!this.__flash || this.readyState == WebSocket.CONNECTING) {
      throw "INVALID_STATE_ERR: Web Socket connection has not been established";
    }
    var result = this.__flash.send(data);
    if (result < 0) { // success
      return true;
    } else {
      this.bufferedAmount = result;
      return false;
    }
  };

  WebSocket.prototype.close = function() {
    if (!this.__flash) return;
    if (this.readyState != WebSocket.OPEN) return;
    this.__flash.close();
    // Sets/calls them manually here because Flash WebSocketConnection.close cannot fire events
    // which causes weird error:
    // > You are trying to call recursively into the Flash Player which is not allowed.
    this.readyState = WebSocket.CLOSED;
    if (this.onclose) this.onclose();
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {string} type
   * @param {function} listener
   * @param {boolean} useCapture !NB Not implemented yet
   * @return void
   */
  WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
    if (!('__events' in this)) {
      this.__events = {};
    }
    if (!(type in this.__events)) {
      this.__events[type] = [];
      if ('function' == typeof this['on' + type]) {
        this.__events[type].defaultHandler = this['on' + type];
        this['on' + type] = WebSocket_FireEvent(this, type);
      }
    }
    this.__events[type].push(listener);
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {string} type
   * @param {function} listener
   * @param {boolean} useCapture NB! Not implemented yet
   * @return void
   */
  WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
    if (!('__events' in this)) {
      this.__events = {};
    }
    if (!(type in this.__events)) return;
    for (var i = this.__events.length; i > -1; --i) {
      if (listener === this.__events[type][i]) {
        this.__events[type].splice(i, 1);
        break;
      }
    }
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {WebSocketEvent} event
   * @return void
   */
  WebSocket.prototype.dispatchEvent = function(event) {
    if (!('__events' in this)) throw 'UNSPECIFIED_EVENT_TYPE_ERR';
    if (!(event.type in this.__events)) throw 'UNSPECIFIED_EVENT_TYPE_ERR';

    for (var i = 0, l = this.__events[event.type].length; i < l; ++ i) {
      this.__events[event.type][i](event);
      if (event.cancelBubble) break;
    }

    if (false !== event.returnValue &&
        'function' == typeof this.__events[event.type].defaultHandler)
    {
      this.__events[event.type].defaultHandler(event);
    }
  };

  /**
   *
   * @param {object} object
   * @param {string} type
   */
  function WebSocket_FireEvent(object, type) {
    return function(data) {
      var event = new WebSocketEvent();
      event.initEvent(type, true, true);
      event.target = event.currentTarget = object;
      for (var key in data) {
        event[key] = data[key];
      }
      object.dispatchEvent(event, arguments);
    };
  }

  /**
   * Basic implementation of {@link DOM 2 EventInterface}
   *
   * @class
   * @constructor
   */
  function WebSocketEvent(){}

  /**
   *
   * @type boolean
   */
  WebSocketEvent.prototype.cancelable = true;

  /**
   *
   * @type boolean
   */
  WebSocketEvent.prototype.cancelBubble = false;

  /**
   *
   * @return void
   */
  WebSocketEvent.prototype.preventDefault = function() {
    if (this.cancelable) {
      this.returnValue = false;
    }
  };

  /**
   *
   * @return void
   */
  WebSocketEvent.prototype.stopPropagation = function() {
    this.cancelBubble = true;
  };

  /**
   *
   * @param {string} eventTypeArg
   * @param {boolean} canBubbleArg
   * @param {boolean} cancelableArg
   * @return void
   */
  WebSocketEvent.prototype.initEvent = function(eventTypeArg, canBubbleArg, cancelableArg) {
    this.type = eventTypeArg;
    this.cancelable = cancelableArg;
    this.timeStamp = new Date();
  };

  WebSocket.CONNECTING = 0;
  WebSocket.OPEN = 1;
  WebSocket.CLOSING = 2;
  WebSocket.CLOSED = 3;

  WebSocket.__tasks = [];

  WebSocket.__initialize = function() {
    if (!WebSocket.__swfLocation) {
      console.error("[WebSocket] set WebSocket.__swfLocation to location of WebSocketMain.swf");
      return;
    }
    var container = document.createElement("div");
    container.id = "webSocketContainer";
    // Puts the Flash out of the window. Note that we cannot use display: none or visibility: hidden
    // here because it prevents Flash from loading at least in IE.
    container.style.position = "absolute";
    container.style.left = "-100px";
    container.style.top = "-100px";
    var holder = document.createElement("div");
    holder.id = "webSocketFlash";
    container.appendChild(holder);
    document.body.appendChild(container);
    swfobject.embedSWF(
      WebSocket.__swfLocation, "webSocketFlash", "8", "8", "9.0.0",
      null, {bridgeName: "webSocket"}, null, null,
      function(e) {
        if (!e.success) console.error("[WebSocket] swfobject.embedSWF failed");
      }
    );
    FABridge.addInitializationCallback("webSocket", function() {
      try {
        //console.log("[WebSocket] FABridge initializad");
        WebSocket.__flash = FABridge.webSocket.root();
        WebSocket.__flash.setCallerUrl(location.href);
        for (var i = 0; i < WebSocket.__tasks.length; ++i) {
          WebSocket.__tasks[i]();
        }
        WebSocket.__tasks = [];
      } catch (e) {
        console.error("[WebSocket] " + e.toString());
      }
    });
  };

  WebSocket.__addTask = function(task) {
    if (WebSocket.__flash) {
      task();
    } else {
      WebSocket.__tasks.push(task);
    }
  }

  // called from Flash
  window.webSocketLog = function(message) {
    console.log(decodeURIComponent(message));
  };

  // called from Flash
  window.webSocketError = function(message) {
    console.error(decodeURIComponent(message));
  };

  if (window.addEventListener) {
    window.addEventListener("load", WebSocket.__initialize, false);
  } else {
    window.attachEvent("onload", WebSocket.__initialize);
  }

})();
<commit_msg>Adding an argument to e.initMessageEvent(), per http://github.com/gimite/web-socket-js/issues#issue/16 .<commit_after>// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
// License: New BSD License
// Reference: http://dev.w3.org/html5/websockets/
// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol

(function() {

  if (window.WebSocket) return;

  var console = window.console;
  if (!console) console = {log: function(){ }, error: function(){ }};

  function hasFlash() {
    if ('navigator' in window && 'plugins' in navigator && navigator.plugins['Shockwave Flash']) {
      return !!navigator.plugins['Shockwave Flash'].description;
    }
    if ('ActiveXObject' in window) {
      try {
        return !!new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
      } catch (e) {}
    }
    return false;
  }

  if (!hasFlash()) {
    console.error("Flash Player is not installed.");
    return;
  }

  WebSocket = function(url, protocol, proxyHost, proxyPort, headers) {
    var self = this;
    self.readyState = WebSocket.CONNECTING;
    self.bufferedAmount = 0;
    WebSocket.__addTask(function() {
      self.__flash =
        WebSocket.__flash.create(url, protocol, proxyHost || null, proxyPort || 0, headers || null);

      self.__flash.addEventListener("open", function(fe) {
        try {
          if (self.onopen) self.onopen();
        } catch (e) {
          console.error(e.toString());
        }
      });

      self.__flash.addEventListener("close", function(fe) {
        try {
          if (self.onclose) self.onclose();
        } catch (e) {
          console.error(e.toString());
        }
      });

      self.__flash.addEventListener("message", function(fe) {
        var data = decodeURIComponent(fe.getData());
        try {
          if (self.onmessage) {
            var e;
            if (window.MessageEvent) {
              e = document.createEvent("MessageEvent");
              e.initMessageEvent("message", false, false, data, null, null, window, null);
            } else { // IE
              e = {data: data};
            }
            self.onmessage(e);
          }
        } catch (e) {
          console.error(e.toString());
        }
      });

      self.__flash.addEventListener("error", function(fe) {
        try {
          if (self.onerror) self.onerror();
        } catch (e) {
          console.error(e.toString());
        }
      });

      self.__flash.addEventListener("stateChange", function(fe) {
        try {
          self.readyState = fe.getReadyState();
          self.bufferedAmount = fe.getBufferedAmount();
        } catch (e) {
          console.error(e.toString());
        }
      });

      //console.log("[WebSocket] Flash object is ready");
    });
  }

  WebSocket.prototype.send = function(data) {
    if (!this.__flash || this.readyState == WebSocket.CONNECTING) {
      throw "INVALID_STATE_ERR: Web Socket connection has not been established";
    }
    var result = this.__flash.send(data);
    if (result < 0) { // success
      return true;
    } else {
      this.bufferedAmount = result;
      return false;
    }
  };

  WebSocket.prototype.close = function() {
    if (!this.__flash) return;
    if (this.readyState != WebSocket.OPEN) return;
    this.__flash.close();
    // Sets/calls them manually here because Flash WebSocketConnection.close cannot fire events
    // which causes weird error:
    // > You are trying to call recursively into the Flash Player which is not allowed.
    this.readyState = WebSocket.CLOSED;
    if (this.onclose) this.onclose();
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {string} type
   * @param {function} listener
   * @param {boolean} useCapture !NB Not implemented yet
   * @return void
   */
  WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
    if (!('__events' in this)) {
      this.__events = {};
    }
    if (!(type in this.__events)) {
      this.__events[type] = [];
      if ('function' == typeof this['on' + type]) {
        this.__events[type].defaultHandler = this['on' + type];
        this['on' + type] = WebSocket_FireEvent(this, type);
      }
    }
    this.__events[type].push(listener);
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {string} type
   * @param {function} listener
   * @param {boolean} useCapture NB! Not implemented yet
   * @return void
   */
  WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
    if (!('__events' in this)) {
      this.__events = {};
    }
    if (!(type in this.__events)) return;
    for (var i = this.__events.length; i > -1; --i) {
      if (listener === this.__events[type][i]) {
        this.__events[type].splice(i, 1);
        break;
      }
    }
  };

  /**
   * Implementation of {@link DOM 2 EventTarget Interface}
   *
   * @param {WebSocketEvent} event
   * @return void
   */
  WebSocket.prototype.dispatchEvent = function(event) {
    if (!('__events' in this)) throw 'UNSPECIFIED_EVENT_TYPE_ERR';
    if (!(event.type in this.__events)) throw 'UNSPECIFIED_EVENT_TYPE_ERR';

    for (var i = 0, l = this.__events[event.type].length; i < l; ++ i) {
      this.__events[event.type][i](event);
      if (event.cancelBubble) break;
    }

    if (false !== event.returnValue &&
        'function' == typeof this.__events[event.type].defaultHandler)
    {
      this.__events[event.type].defaultHandler(event);
    }
  };

  /**
   *
   * @param {object} object
   * @param {string} type
   */
  function WebSocket_FireEvent(object, type) {
    return function(data) {
      var event = new WebSocketEvent();
      event.initEvent(type, true, true);
      event.target = event.currentTarget = object;
      for (var key in data) {
        event[key] = data[key];
      }
      object.dispatchEvent(event, arguments);
    };
  }

  /**
   * Basic implementation of {@link DOM 2 EventInterface}
   *
   * @class
   * @constructor
   */
  function WebSocketEvent(){}

  /**
   *
   * @type boolean
   */
  WebSocketEvent.prototype.cancelable = true;

  /**
   *
   * @type boolean
   */
  WebSocketEvent.prototype.cancelBubble = false;

  /**
   *
   * @return void
   */
  WebSocketEvent.prototype.preventDefault = function() {
    if (this.cancelable) {
      this.returnValue = false;
    }
  };

  /**
   *
   * @return void
   */
  WebSocketEvent.prototype.stopPropagation = function() {
    this.cancelBubble = true;
  };

  /**
   *
   * @param {string} eventTypeArg
   * @param {boolean} canBubbleArg
   * @param {boolean} cancelableArg
   * @return void
   */
  WebSocketEvent.prototype.initEvent = function(eventTypeArg, canBubbleArg, cancelableArg) {
    this.type = eventTypeArg;
    this.cancelable = cancelableArg;
    this.timeStamp = new Date();
  };

  WebSocket.CONNECTING = 0;
  WebSocket.OPEN = 1;
  WebSocket.CLOSING = 2;
  WebSocket.CLOSED = 3;

  WebSocket.__tasks = [];

  WebSocket.__initialize = function() {
    if (!WebSocket.__swfLocation) {
      console.error("[WebSocket] set WebSocket.__swfLocation to location of WebSocketMain.swf");
      return;
    }
    var container = document.createElement("div");
    container.id = "webSocketContainer";
    // Puts the Flash out of the window. Note that we cannot use display: none or visibility: hidden
    // here because it prevents Flash from loading at least in IE.
    container.style.position = "absolute";
    container.style.left = "-100px";
    container.style.top = "-100px";
    var holder = document.createElement("div");
    holder.id = "webSocketFlash";
    container.appendChild(holder);
    document.body.appendChild(container);
    swfobject.embedSWF(
      WebSocket.__swfLocation, "webSocketFlash", "8", "8", "9.0.0",
      null, {bridgeName: "webSocket"}, null, null,
      function(e) {
        if (!e.success) console.error("[WebSocket] swfobject.embedSWF failed");
      }
    );
    FABridge.addInitializationCallback("webSocket", function() {
      try {
        //console.log("[WebSocket] FABridge initializad");
        WebSocket.__flash = FABridge.webSocket.root();
        WebSocket.__flash.setCallerUrl(location.href);
        for (var i = 0; i < WebSocket.__tasks.length; ++i) {
          WebSocket.__tasks[i]();
        }
        WebSocket.__tasks = [];
      } catch (e) {
        console.error("[WebSocket] " + e.toString());
      }
    });
  };

  WebSocket.__addTask = function(task) {
    if (WebSocket.__flash) {
      task();
    } else {
      WebSocket.__tasks.push(task);
    }
  }

  // called from Flash
  window.webSocketLog = function(message) {
    console.log(decodeURIComponent(message));
  };

  // called from Flash
  window.webSocketError = function(message) {
    console.error(decodeURIComponent(message));
  };

  if (window.addEventListener) {
    window.addEventListener("load", WebSocket.__initialize, false);
  } else {
    window.attachEvent("onload", WebSocket.__initialize);
  }

})();
<|endoftext|>


<commit_before>const _ = require('underscore')
const marked = require('marked')
const Doc = require('./doc')
const {getLinkMatch, multiplyString} = require('./utils')

const SpecialHeadingDepth = 2
const SpecialHeadings = '^Arguments|Events|Examples'

const VisibilityRegexStr = '^\\s*([a-zA-Z]+):\\s*'
const VisibilityRegex = new RegExp(VisibilityRegexStr)
const ReturnsRegex = new RegExp(`(${VisibilityRegexStr})?\\s*Returns`)
const ArgumentListItemRegex = /^\s*`([\w\\.-]+)`(\s*[:-])?(\s*\(optional\))?\s*/

/*
Section: Parsing

Translating things from markdown into our json format.
*/

// Public: Parses a docString
//
// * `docString` a string from the documented object to be parsed
//
// Returns a {Doc} object
const parse = function (docString) {
  const lexer = new marked.Lexer()
  const tokens = lexer.lex(docString)
  const firstToken = _.first(tokens)

  if (!firstToken || (firstToken.type !== 'paragraph')) {
    throw new Error('Doc string must start with a paragraph!')
  }

  const doc = new Doc(docString)

  _.extend(doc, parseSummaryAndDescription(tokens))

  while (tokens.length) {
    let args, events, examples, returnValues, titledArgs
    if ((titledArgs = parseTitledArgumentsSection(tokens))) {
      if (doc.titledArguments == null) { doc.titledArguments = [] }
      doc.titledArguments.push(titledArgs)
    } else if ((args = parseArgumentsSection(tokens))) {
      doc.arguments = args
    } else if ((events = parseEventsSection(tokens))) {
      doc.events = events
    } else if ((examples = parseExamplesSection(tokens))) {
      doc.examples = examples
    } else if ((returnValues = parseReturnValues(tokens, true))) {
      doc.setReturnValues(returnValues)
    } else {
      // These tokens are basically in no-mans land. We'll add them to the
      // description so they dont get lost.
      const extraDescription = generateDescription(tokens, stopOnSectionBoundaries)
      doc.description += `\n\n${extraDescription}`
    }
  }

  return doc
}

var parseSummaryAndDescription = function (tokens, tokenCallback) {
  if (tokenCallback == null) { tokenCallback = stopOnSectionBoundaries }
  let summary = ''
  let description = ''
  let visibility = 'Private'

  let rawVisibility = null
  let rawSummary = tokens[0].text
  if (rawSummary) {
    const visibilityMatch = VisibilityRegex.exec(rawSummary)
    if (visibilityMatch) {
      visibility = visibilityMatch[1]
      rawVisibility = visibilityMatch[0]
      if (rawVisibility) { rawSummary = rawSummary.replace(rawVisibility, '') }
    }
  }

  if (isReturnValue(rawSummary)) {
    const returnValues = parseReturnValues(tokens, false)
    return {summary, description, visibility, returnValues}
  } else {
    summary = rawSummary
    description = generateDescription(tokens, tokenCallback)
    if (rawVisibility) { description = description.replace(rawVisibility, '') }
    return {description, summary, visibility}
  }
}

var parseArgumentsSection = function (tokens) {
  const firstToken = _.first(tokens)
  if (firstToken && (firstToken.type === 'heading')) {
    if ((firstToken.text !== 'Arguments') || (firstToken.depth !== SpecialHeadingDepth)) {
      return
    }
  } else if (firstToken && (firstToken.type === 'list_start')) {
    if (!isAtArgumentList(tokens)) { return }
  } else {
    return
  }

  let args = null

  if (firstToken.type === 'list_start') {
    args = parseArgumentList(tokens)
  } else {
    tokens.shift() // consume the header
    generateDescription(tokens, stopOnSectionBoundaries) // consume any BS before the args list
    args = parseArgumentList(tokens)
  }

  return args
}

var parseTitledArgumentsSection = function (tokens) {
  const firstToken = _.first(tokens)
  if (!firstToken || (firstToken.type !== 'heading')) { return }
  if ((firstToken.text.indexOf('Arguments:') !== 0) || (firstToken.depth !== SpecialHeadingDepth)) { return }

  return {
    title: tokens.shift().text.replace('Arguments:', '').trim(),
    description: generateDescription(tokens, stopOnSectionBoundaries),
    arguments: parseArgumentList(tokens)
  }
}

var parseEventsSection = function (tokens) {
  let firstToken = _.first(tokens)
  if (!firstToken || (firstToken.type !== 'heading') || (firstToken.text !== 'Events') || (firstToken.depth !== SpecialHeadingDepth)) { return }

  const eventHeadingDepth = SpecialHeadingDepth + 1

  // We consume until there is a heading of h3 which denotes the beginning of an event.
  const stopTokenCallback = function (token, tokens) {
    if ((token.type === 'heading') && (token.depth === eventHeadingDepth)) { return false }
    return stopOnSectionBoundaries(token, tokens)
  }

  const events = []
  tokens.shift() // consume the header

  while (tokens.length) {
    // We consume until there is a heading of h3 which denotes the beginning of an event.
    generateDescription(tokens, stopTokenCallback)

    firstToken = _.first(tokens)
    if (firstToken && firstToken.type === 'heading' && firstToken.depth === eventHeadingDepth) {
      tokens.shift() // consume the header
      const {summary, description, visibility} = parseSummaryAndDescription(tokens, stopTokenCallback)
      const name = firstToken.text
      let args = parseArgumentList(tokens)
      if (args.length === 0) { args = null }
      events.push({name, summary, description, visibility, arguments: args})
    } else {
      break
    }
  }

  if (events.length) { return events }
}

var parseExamplesSection = function (tokens) {
  let firstToken = _.first(tokens)
  if (!firstToken || (firstToken.type !== 'heading') || (firstToken.text !== 'Examples') || (firstToken.depth !== SpecialHeadingDepth)) { return }

  const examples = []
  tokens.shift() // consume the header

  while (tokens.length) {
    const description = generateDescription(tokens, function (token, tokens) {
      if (token.type === 'code') { return false }
      return stopOnSectionBoundaries(token, tokens)
    })

    firstToken = _.first(tokens)
    if (firstToken.type === 'code') {
      const example = {
        description,
        lang: firstToken.lang,
        code: firstToken.text,
        raw: generateCode(tokens)
      }
      examples.push(example)
    } else {
      break
    }
  }

  if (examples.length) { return examples }
}

var parseReturnValues = function (tokens, consumeTokensAfterReturn) {
  let normalizedString
  if (consumeTokensAfterReturn == null) { consumeTokensAfterReturn = false }
  const firstToken = _.first(tokens)
  if (!firstToken || !['paragraph', 'text'].includes(firstToken.type) || !isReturnValue(firstToken.text)) { return }

  const returnsMatches = ReturnsRegex.exec(firstToken.text) // there might be a `Public: ` in front of the return.
  if (consumeTokensAfterReturn) {
    normalizedString = generateDescription(tokens, () => true)
    if (returnsMatches[1]) {
      normalizedString = normalizedString.replace(returnsMatches[1], '')
    }
  } else {
    const token = tokens.shift()
    normalizedString = token.text
    if (returnsMatches[1]) {
      normalizedString = normalizedString.replace(returnsMatches[1], '')
    }
    normalizedString = normalizedString.replace(/\s{2,}/g, ' ')
  }

  let returnValues = null

  while (normalizedString) {
    const nextIndex = normalizedString.indexOf('Returns', 1)
    let returnString = normalizedString
    if (nextIndex > -1) {
      returnString = normalizedString.substring(0, nextIndex)
      normalizedString = normalizedString.substring(nextIndex, normalizedString.length)
    } else {
      normalizedString = null
    }

    if (returnValues == null) { returnValues = [] }
    returnValues.push({
      type: getLinkMatch(returnString),
      description: returnString.trim()
    })
  }

  return returnValues
}

// Parses argument lists like this one:
//
// * `something` A {Bool}
//   * `somethingNested` A nested object
var parseArgumentList = function (tokens) {
  let depth = 0
  let args = []
  let argumentsList = null
  const argumentsListStack = []
  let argument = null
  const argumentStack = []

  while (tokens.length && ((tokens[0].type === 'list_start') || depth)) {
    const token = tokens[0]
    switch (token.type) {
      case 'list_start':
        // This list might not be a argument list. Check...
        var parseAsArgumentList = isAtArgumentList(tokens)

        if (parseAsArgumentList) {
          depth++
          if (argumentsList) { argumentsListStack.push(argumentsList) }
          argumentsList = []
          tokens.shift()
        } else if (argument) {
          // If not, consume the list as part of the description
          if (!argument.text) {
            argument.text = []
          }
          argument.text.push(`\n${generateList(tokens)}`)
        }
        break

      case 'list_item_start': case 'loose_item_start':
        if (argument) { argumentStack.push(argument) }
        argument = {}
        tokens.shift()
        break

      case 'code':
        if (!argument.text) { argument.text = [] }
        argument.text.push(`\n${generateCode(tokens)}`)
        break

      case 'text':
        if (!argument.text) { argument.text = [] }
        argument.text.push(token.text)
        tokens.shift()
        break

      case 'list_item_end': case 'loose_item_end':
        if (argument) {
          _.extend(argument, parseListItem(argument.text.join(' ').replace(/ \n/g, '\n')))
          argumentsList.push(argument)
          delete argument.text
        }

        argument = argumentStack.pop()
        tokens.shift()
        break

      case 'list_end':
        depth--
        if (argument) {
          argument.children = argumentsList
          argumentsList = argumentsListStack.pop()
        } else {
          args = argumentsList
        }
        tokens.shift()
        break

      default: tokens.shift()
    }
  }

  return args
}

var parseListItem = function (argumentString) {
  let isOptional
  let name = null
  let type = null
  let description = argumentString

  const nameMatches = ArgumentListItemRegex.exec(argumentString)
  if (nameMatches) {
    name = nameMatches[1]
    description = description.replace(nameMatches[0], '')
    type = getLinkMatch(description)
    isOptional = !!nameMatches[3]
  }

  return {name, description, type, isOptional}
}

module.exports = {parse}

/*
Section: Generation

These methods will consume tokens and return a markdown representation of the
tokens. Yeah, it generates markdown from the lexed markdown tokens.
*/

const isReturnValue = string => ReturnsRegex.test(string)

const isArgumentListItem = string => ArgumentListItemRegex.test(string)

const isAtArgumentList = function (tokens) {
  let foundListStart = false
  for (let token of tokens) {
    if (['list_item_start', 'loose_item_start'].includes(token.type)) {
      foundListStart = true
    } else if ((token.type === 'text') && foundListStart) {
      return isArgumentListItem(token.text)
    }
  }
}

const stopOnSectionBoundaries = function (token, tokens) {
  if (['paragraph', 'text'].includes(token.type)) {
    if (isReturnValue(token.text)) {
      return false
    }
  } else if (token.type === 'heading') {
    if ((token.depth === SpecialHeadingDepth) && new RegExp(SpecialHeadings).test(token.text)) {
      return false
    }
  } else if (token.type === 'list_start') {
    let listToken = null
    for (listToken of tokens) {
      if (listToken.type === 'text') { break }
    }

    // Check if list is an arguments list. If it starts with `someVar`, it is.
    if (listToken && ArgumentListItemRegex.test(listToken.text)) {
      return false
    }
  }

  return true
}

// Will read / consume tokens down to a special section (args, events, examples)
const generateDescription = function (tokens, tokenCallback) {
  let token
  const description = []
  while ((token = _.first(tokens))) {
    if ((tokenCallback) && (tokenCallback(token, tokens) === false)) { break }

    if (['paragraph', 'text'].includes(token.type)) {
      description.push(generateParagraph(tokens))
    } else if (token.type === 'blockquote_start') {
      description.push(generateBlockquote(tokens))
    } else if (token.type === 'code') {
      description.push(generateCode(tokens))
    } else if (token.type === 'heading') {
      description.push(generateHeading(tokens))
    } else if (token.type === 'list_start') {
      description.push(generateList(tokens))
    } else { break }
  }

  return description.join('\n\n')
}

const generateParagraph = tokens => tokens.shift().text

const generateHeading = function (tokens) {
  const token = tokens.shift()
  return `${multiplyString('#', token.depth)} ${token.text}`
}

const generateBlockquote = function (tokens) {
  let token
  const lines = []

  while ((token = tokens.shift())) {
    if (token.type === 'blockquote_end') { break }
    if (token.text) {
      for (let line of token.text.split('\n')) {
        lines.push(`> ${line}`)
      }
    }
  }

  return lines.join('\n')
}

const generateCode = function (tokens) {
  const token = tokens.shift()
  const lines = []
  lines.push(token.lang ? `\`\`\`${token.lang}` : '```')
  lines.push(token.text)
  lines.push('```')
  return lines.join('\n')
}

const generateList = function (tokens) {
  let token
  let depth = -1
  const lines = []
  let linePrefix = null

  let ordered = null
  const orderedStack = []

  const indent = () => multiplyString('  ', depth)

  while ((token = _.first(tokens))) {
    let textLines
    switch (token.type) {
      case 'list_start':
        depth++
        orderedStack.push(ordered);
        ({ ordered } = token)
        break

      case 'list_item_start': case 'loose_item_start':
        linePrefix = ordered ? `${indent()}1. ` : `${indent()}* `
        break

      case 'text': case 'code': case 'blockquote_start':
        if (token.type === 'code') {
          textLines = generateCode(tokens).split('\n')
        } else if (token.type === 'blockquote_start') {
          textLines = generateBlockquote(tokens).split('\n')
        } else {
          textLines = token.text.split('\n')
        }

        for (let line of textLines) {
          const prefix = linePrefix || `${indent()}  `
          lines.push(prefix + line)
          linePrefix = null
        } // we used the bullet!
        break

      case 'list_end':
        depth--
        ordered = orderedStack.pop()
        break
    }

    token = tokens.shift()
    if (depth < 0) { break }
  }

  return lines.join('\n')
}
<commit_msg>:art: Modernize and cleanup the code a bit<commit_after>const _ = require('underscore')
const marked = require('marked')
const Doc = require('./doc')
const {getLinkMatch, multiplyString} = require('./utils')

const SpecialHeadingDepth = 2
const SpecialHeadings = /^Arguments|Events|Examples/

const VisibilityRegexStr = '^\\s*([a-zA-Z]+):\\s*'
const VisibilityRegex = new RegExp(VisibilityRegexStr)
const ReturnsRegex = new RegExp(`(${VisibilityRegexStr})?\\s*Returns`)
const ArgumentListItemRegex = /^\s*`([\w\\.-]+)`(\s*[:-])?(\s*\(optional\))?\s*/

/*
Section: Parsing

Translating things from markdown into our json format.
*/

// Public: Parses a docString
//
// * `docString` a string from the documented object to be parsed
//
// Returns a {Doc} object
const parse = function (docString) {
  const lexer = new marked.Lexer()
  const tokens = lexer.lex(docString)
  const firstToken = _.first(tokens)

  if (!firstToken || (firstToken.type !== 'paragraph')) {
    throw new Error('Doc string must start with a paragraph!')
  }

  const doc = new Doc(docString)

  _.extend(doc, parseSummaryAndDescription(tokens))

  while (tokens.length) {
    let args, events, examples, returnValues, titledArgs
    if ((titledArgs = parseTitledArgumentsSection(tokens))) {
      if (doc.titledArguments == null) { doc.titledArguments = [] }
      doc.titledArguments.push(titledArgs)
    } else if ((args = parseArgumentsSection(tokens))) {
      doc.arguments = args
    } else if ((events = parseEventsSection(tokens))) {
      doc.events = events
    } else if ((examples = parseExamplesSection(tokens))) {
      doc.examples = examples
    } else if ((returnValues = parseReturnValues(tokens, true))) {
      doc.setReturnValues(returnValues)
    } else {
      // These tokens are basically in no-mans land. We'll add them to the
      // description so they dont get lost.
      const extraDescription = generateDescription(tokens, stopOnSectionBoundaries)
      doc.description += `\n\n${extraDescription}`
    }
  }

  return doc
}

var parseSummaryAndDescription = function (tokens, tokenCallback) {
  if (tokenCallback == null) { tokenCallback = stopOnSectionBoundaries }
  let summary = ''
  let description = ''
  let visibility = 'Private'

  let rawVisibility = null
  let rawSummary = tokens[0].text
  if (rawSummary) {
    const visibilityMatch = VisibilityRegex.exec(rawSummary)
    if (visibilityMatch) {
      visibility = visibilityMatch[1]
      rawVisibility = visibilityMatch[0]
      if (rawVisibility) { rawSummary = rawSummary.replace(rawVisibility, '') }
    }
  }

  if (isReturnValue(rawSummary)) {
    const returnValues = parseReturnValues(tokens, false)
    return {summary, description, visibility, returnValues}
  } else {
    summary = rawSummary
    description = generateDescription(tokens, tokenCallback)
    if (rawVisibility) { description = description.replace(rawVisibility, '') }
    return {description, summary, visibility}
  }
}

var parseArgumentsSection = function (tokens) {
  const firstToken = _.first(tokens)
  if (firstToken && (firstToken.type === 'heading')) {
    if (firstToken.text !== 'Arguments' ||
      firstToken.depth !== SpecialHeadingDepth
    ) {
      return
    }
  } else if (firstToken && firstToken.type === 'list_start') {
    if (!isAtArgumentList(tokens)) { return }
  } else {
    return
  }

  let args = null

  if (firstToken.type === 'list_start') {
    args = parseArgumentList(tokens)
  } else {
    tokens.shift() // consume the header
    // consume any BS before the args list
    generateDescription(tokens, stopOnSectionBoundaries)
    args = parseArgumentList(tokens)
  }

  return args
}

var parseTitledArgumentsSection = function (tokens) {
  const firstToken = _.first(tokens)
  if (!firstToken || firstToken.type !== 'heading') { return }
  if (!firstToken.text.startsWith('Arguments:') ||
    firstToken.depth !== SpecialHeadingDepth
  ) {
    return
  }

  return {
    title: tokens.shift().text.replace('Arguments:', '').trim(),
    description: generateDescription(tokens, stopOnSectionBoundaries),
    arguments: parseArgumentList(tokens)
  }
}

var parseEventsSection = function (tokens) {
  let firstToken = _.first(tokens)
  if (
    !firstToken ||
    firstToken.type !== 'heading' ||
    firstToken.text !== 'Events' ||
    firstToken.depth !== SpecialHeadingDepth
  ) { return }

  const eventHeadingDepth = SpecialHeadingDepth + 1

  // We consume until there is a heading of h3 which denotes the beginning of an event.
  const stopTokenCallback = function (token, tokens) {
    if ((token.type === 'heading') && (token.depth === eventHeadingDepth)) {
      return false
    }
    return stopOnSectionBoundaries(token, tokens)
  }

  const events = []
  tokens.shift() // consume the header

  while (tokens.length) {
    // We consume until there is a heading of h3 which denotes the beginning of an event.
    generateDescription(tokens, stopTokenCallback)

    firstToken = _.first(tokens)
    if (
      firstToken &&
      firstToken.type === 'heading' &&
      firstToken.depth === eventHeadingDepth
    ) {
      tokens.shift() // consume the header
      const {summary, description, visibility} = parseSummaryAndDescription(
        tokens, stopTokenCallback)
      const name = firstToken.text
      let args = parseArgumentList(tokens)
      if (args.length === 0) { args = null }
      events.push({name, summary, description, visibility, arguments: args})
    } else {
      break
    }
  }

  if (events.length) { return events }
}

var parseExamplesSection = function (tokens) {
  let firstToken = _.first(tokens)
  if (
    !firstToken ||
    firstToken.type !== 'heading' ||
    firstToken.text !== 'Examples' ||
    firstToken.depth !== SpecialHeadingDepth
  ) { return }

  const examples = []
  tokens.shift() // consume the header

  while (tokens.length) {
    const description = generateDescription(tokens, function (token, tokens) {
      if (token.type === 'code') { return false }
      return stopOnSectionBoundaries(token, tokens)
    })

    firstToken = _.first(tokens)
    if (firstToken.type === 'code') {
      const example = {
        description,
        lang: firstToken.lang,
        code: firstToken.text,
        raw: generateCode(tokens)
      }
      examples.push(example)
    } else {
      break
    }
  }

  if (examples.length) { return examples }
}

var parseReturnValues = function (tokens, consumeTokensAfterReturn) {
  let normalizedString
  if (consumeTokensAfterReturn == null) { consumeTokensAfterReturn = false }
  const firstToken = _.first(tokens)
  if (
    !firstToken ||
    !['paragraph', 'text'].includes(firstToken.type) ||
    !isReturnValue(firstToken.text)
  ) { return }

  // there might be a `Public: ` in front of the return.
  const returnsMatches = ReturnsRegex.exec(firstToken.text)
  if (consumeTokensAfterReturn) {
    normalizedString = generateDescription(tokens, () => true)
    if (returnsMatches[1]) {
      normalizedString = normalizedString.replace(returnsMatches[1], '')
    }
  } else {
    const token = tokens.shift()
    normalizedString = token.text
    if (returnsMatches[1]) {
      normalizedString = normalizedString.replace(returnsMatches[1], '')
    }
    normalizedString = normalizedString.replace(/\s{2,}/g, ' ')
  }

  let returnValues = null

  while (normalizedString) {
    const nextIndex = normalizedString.indexOf('Returns', 1)
    let returnString = normalizedString
    if (nextIndex > -1) {
      returnString = normalizedString.substring(0, nextIndex)
      normalizedString = normalizedString.substring(nextIndex, normalizedString.length)
    } else {
      normalizedString = null
    }

    if (returnValues == null) { returnValues = [] }
    returnValues.push({
      type: getLinkMatch(returnString),
      description: returnString.trim()
    })
  }

  return returnValues
}

// Parses argument lists like this one:
//
// * `something` A {Bool}
//   * `somethingNested` A nested object
var parseArgumentList = function (tokens) {
  let depth = 0
  let args = []
  let argumentsList = null
  const argumentsListStack = []
  let argument = null
  const argumentStack = []

  while (tokens.length && (tokens[0].type === 'list_start' || depth)) {
    const token = tokens[0]
    switch (token.type) {
      case 'list_start':
        // This list might not be a argument list. Check...
        var parseAsArgumentList = isAtArgumentList(tokens)

        if (parseAsArgumentList) {
          depth++
          if (argumentsList) { argumentsListStack.push(argumentsList) }
          argumentsList = []
          tokens.shift()
        } else if (argument) {
          // If not, consume the list as part of the description
          if (!argument.text) {
            argument.text = []
          }
          argument.text.push(`\n${generateList(tokens)}`)
        }
        break

      case 'list_item_start':
      case 'loose_item_start':
        if (argument) { argumentStack.push(argument) }
        argument = {}
        tokens.shift()
        break

      case 'code':
        if (!argument.text) { argument.text = [] }
        argument.text.push(`\n${generateCode(tokens)}`)
        break

      case 'text':
        if (!argument.text) { argument.text = [] }
        argument.text.push(token.text)
        tokens.shift()
        break

      case 'list_item_end':
      case 'loose_item_end':
        if (argument) {
          _.extend(argument,
            parseListItem(argument.text.join(' ').replace(/ \n/g, '\n')))
          argumentsList.push(argument)
          delete argument.text
        }

        argument = argumentStack.pop()
        tokens.shift()
        break

      case 'list_end':
        depth--
        if (argument) {
          argument.children = argumentsList
          argumentsList = argumentsListStack.pop()
        } else {
          args = argumentsList
        }
        tokens.shift()
        break

      default: tokens.shift()
    }
  }

  return args
}

var parseListItem = function (argumentString) {
  let isOptional
  let name = null
  let type = null
  let description = argumentString

  const nameMatches = ArgumentListItemRegex.exec(argumentString)
  if (nameMatches) {
    name = nameMatches[1]
    description = description.replace(nameMatches[0], '')
    type = getLinkMatch(description)
    isOptional = !!nameMatches[3]
  }

  return {name, description, type, isOptional}
}

module.exports = {parse}

/*
Section: Generation

These methods will consume tokens and return a markdown representation of the
tokens. Yeah, it generates markdown from the lexed markdown tokens.
*/

const isReturnValue = string => ReturnsRegex.test(string)

const isArgumentListItem = string => ArgumentListItemRegex.test(string)

const isAtArgumentList = function (tokens) {
  let foundListStart = false
  for (let token of tokens) {
    if (['list_item_start', 'loose_item_start'].includes(token.type)) {
      foundListStart = true
    } else if (token.type === 'text' && foundListStart) {
      return isArgumentListItem(token.text)
    }
  }
}

const stopOnSectionBoundaries = function (token, tokens) {
  if (['paragraph', 'text'].includes(token.type)) {
    if (isReturnValue(token.text)) {
      return false
    }
  } else if (token.type === 'heading') {
    if (token.depth === SpecialHeadingDepth && SpecialHeadings.test(token.text)) {
      return false
    }
  } else if (token.type === 'list_start') {
    let listToken = null
    for (listToken of tokens) {
      if (listToken.type === 'text') { break }
    }

    // Check if list is an arguments list. If it starts with `someVar`, it is.
    if (listToken && ArgumentListItemRegex.test(listToken.text)) {
      return false
    }
  }

  return true
}

// Will read / consume tokens down to a special section (args, events, examples)
const generateDescription = function (tokens, tokenCallback) {
  let token
  const description = []
  while ((token = _.first(tokens))) {
    if ((tokenCallback) && (tokenCallback(token, tokens) === false)) { break }

    if (['paragraph', 'text'].includes(token.type)) {
      description.push(generateParagraph(tokens))
    } else if (token.type === 'blockquote_start') {
      description.push(generateBlockquote(tokens))
    } else if (token.type === 'code') {
      description.push(generateCode(tokens))
    } else if (token.type === 'heading') {
      description.push(generateHeading(tokens))
    } else if (token.type === 'list_start') {
      description.push(generateList(tokens))
    } else { break }
  }

  return description.join('\n\n')
}

const generateParagraph = tokens => tokens.shift().text

const generateHeading = function (tokens) {
  const token = tokens.shift()
  return `${multiplyString('#', token.depth)} ${token.text}`
}

const generateBlockquote = function (tokens) {
  let token
  const lines = []

  while ((token = tokens.shift())) {
    if (token.type === 'blockquote_end') { break }
    if (token.text) {
      for (let line of token.text.split('\n')) {
        lines.push(`> ${line}`)
      }
    }
  }

  return lines.join('\n')
}

const generateCode = function (tokens) {
  const token = tokens.shift()
  const lines = []
  lines.push(token.lang ? `\`\`\`${token.lang}` : '```')
  lines.push(token.text)
  lines.push('```')
  return lines.join('\n')
}

const generateList = function (tokens) {
  let token
  let depth = -1
  const lines = []
  let linePrefix = null

  let ordered = null
  const orderedStack = []

  const indent = () => multiplyString('  ', depth)

  while ((token = _.first(tokens))) {
    let textLines
    switch (token.type) {
      case 'list_start':
        depth++
        orderedStack.push(ordered);
        ({ ordered } = token)
        break

      case 'list_item_start':
      case 'loose_item_start':
        linePrefix = ordered ? `${indent()}1. ` : `${indent()}* `
        break

      case 'text':
      case 'code':
      case 'blockquote_start':
        if (token.type === 'code') {
          textLines = generateCode(tokens).split('\n')
        } else if (token.type === 'blockquote_start') {
          textLines = generateBlockquote(tokens).split('\n')
        } else {
          textLines = token.text.split('\n')
        }

        for (let line of textLines) {
          const prefix = linePrefix || `${indent()}  `
          lines.push(prefix + line)
          linePrefix = null
        } // we used the bullet!
        break

      case 'list_end':
        depth--
        ordered = orderedStack.pop()
        break
    }

    token = tokens.shift()
    if (depth < 0) { break }
  }

  return lines.join('\n')
}
<|endoftext|>


<commit_before>'use strict';

module.exports = parse;

const PARSERS = {
    'text': parseTextItem,
    'boolean': parseBooleanItem,
    'attribute': parseAttributeItem,
    'detailedProfileInformation': parseDetailedProfileInformation,
    'counters': parseCounters,
    'contentCounters': parseContentCounters
};

function parse(type) {
    const parser = PARSERS[type];
    if (typeof parser === 'function') {
        let args = [].slice.call(arguments, 1);
        return parser.apply(null, args);
    }

    console.error('No parser for type', type);
}

function parseTextItem($, item) {
    const text = $(item.selector).text().trim();
    return {
        key: item.name,
        value: text
    };
}

function parseBooleanItem($, item) {
    let text = $(item.selector).length > 0;
    return {
        key: item.name,
        value: text
    };
}

function parseAttributeItem($, item) {
    const value = $(item.selector).attr(item.attribute).trim();
    return {
        key: item.name,
        value: value
    };
}

function parseDetailedProfileInformation($) {
    let data = {};
    $('.profile_info_block').each((i, el) => {
        $(el).find('.profile_info_row').each((i, el) => {
            let title = $(el).find('.label').text();
            let content = $(el).find('.labeled').text();
            if (data[title]) {
                console.error(`Conflicting data title <${title}>.\nExisting: ${data[title]}\nNew: ${content}`);
            }
            data[title] = content;
        });
    });

    return data;
}

function parseCounters($) {
    let data = {};
    $('.counts_module .page_counter').each((i, el) => {
        let title = $(el).find('.label').text();
        let content = $(el).find('.count').text();
        if (data[title]) {
            console.error(`Conflicting data title <${title}>.\nExisting: ${data[title]}\nNew: ${content}`);
        }
        data[title] = content;
    });

    return data;
}

function parseContentCounters($) {
    let data = {};
    $('.header_top').each((i, el) => {
        let title = $(el).find('.header_label').text().trim();
        let content = $(el).find('.header_count').text().trim();
        if (data[title]) {
            console.error(`Conflicting data title <${title}>.\nExisting: ${data[title]}\nNew: ${content}`);
        }
        data[title] = content;
    });

    return data;
}
<commit_msg>Update selector for profile info parser, from .profile_info_block to .profile_info<commit_after>'use strict';

module.exports = parse;

const PARSERS = {
    'text': parseTextItem,
    'boolean': parseBooleanItem,
    'attribute': parseAttributeItem,
    'detailedProfileInformation': parseDetailedProfileInformation,
    'counters': parseCounters,
    'contentCounters': parseContentCounters
};

function parse(type) {
    const parser = PARSERS[type];
    if (typeof parser === 'function') {
        let args = [].slice.call(arguments, 1);
        return parser.apply(null, args);
    }

    console.error('No parser for type', type);
}

function parseTextItem($, item) {
    const text = $(item.selector).text().trim();
    return {
        key: item.name,
        value: text
    };
}

function parseBooleanItem($, item) {
    let text = $(item.selector).length > 0;
    return {
        key: item.name,
        value: text
    };
}

function parseAttributeItem($, item) {
    const value = $(item.selector).attr(item.attribute).trim();
    return {
        key: item.name,
        value: value
    };
}

function parseDetailedProfileInformation($) {
    let data = {};
    $('.profile_info').each((i, el) => {
        $(el).find('.profile_info_row').each((i, el) => {
            let title = $(el).find('.label').text();
            let content = $(el).find('.labeled').text();
            if (data[title]) {
                console.error(`Conflicting data title <${title}>.\nExisting: ${data[title]}\nNew: ${content}`);
            }
            data[title] = content;
        });
    });

    return data;
}

function parseCounters($) {
    let data = {};
    $('.counts_module .page_counter').each((i, el) => {
        let title = $(el).find('.label').text();
        let content = $(el).find('.count').text();
        if (data[title]) {
            console.error(`Conflicting data title <${title}>.\nExisting: ${data[title]}\nNew: ${content}`);
        }
        data[title] = content;
    });

    return data;
}

function parseContentCounters($) {
    let data = {};
    $('.header_top').each((i, el) => {
        let title = $(el).find('.header_label').text().trim();
        let content = $(el).find('.header_count').text().trim();
        if (data[title]) {
            console.error(`Conflicting data title <${title}>.\nExisting: ${data[title]}\nNew: ${content}`);
        }
        data[title] = content;
    });

    return data;
}
<|endoftext|>


<commit_before>const Wire = require('./wire');
const config = require('./../config');
const net = require('net');

const clean = (data) => {
	if (Buffer.isBuffer(data)) {
		return data.toString();
	} else if (Array.isArray(data)) {
		return data.map(clean);
	} else if (typeof data === 'object') {
		return Object.keys(data).reduce((result, key) => Object.assign(result, { [key]: clean(data[key]) }), {});
	}

	return data;
};

const filterTorrent = (names) =>
	names.filter((name) => config.filters.findIndex((element) => name.toLowerCase().includes(element)) > -1);
const getType = (names) => {
	const weights = names.reduce(
		(result, name) =>
			Object.keys(config.formats)
				.filter((key) => {
					const ext = name ? name.split('.').pop() : '';

					return config.formats[key].find((format) => format === ext);
				})
				.reduce(
					(weight, type) => Object.assign(weight, { [type]: weight[type] ? weight[type] + 1 : 1 }),
					result,
				),
		{},
	);

	return Object.keys(weights).reduce(
		(result, type) => (result && weights[result] > weights[type] ? result : type),
		'',
	);
};
const getTags = (names, type) =>
	names.reduce((result, name) => {
		const tags = config.tags
			.filter((tag) => {
				if (tag.type !== type) {
					return false;
				} else if (tag.includes && name.indexOf(tag.includes) > -1) {
					return true;
				} else if (tag.match && name.match(tag.match)) {
					return true;
				}
				return false;
			})
			.map(({ tag }) => tag);

		return result.concat(tags);
	}, []);

const upsertTorrent = async (torrent, knex) => {
	try {
		const records = await knex('torrents').where({ infohash: torrent.infohash });

		if (config.debug) {
			console.log(`${torrent.infohash} - ${records.length > 0 ? 'Updated' : 'Inserted'}`);
		}
		if (records.length > 0) {
			await knex('torrents')
				.update(Object.assign(torrent, { updated: new Date() }))
				.where({ infohash: torrent.infohash });
		} else {
			await knex('torrents')
				.insert(Object.assign(torrent, { created: new Date(), updated: new Date() }))
				.where({ infohash: torrent.infohash });
		}
	} catch (error) {
		if (config.debug) {
			console.log(error);
		}
	}
};

const buildRecord = (names, knex, { files, infohash, name }) => {
	try {
		const type = getType(names);
		const tags = [...new Set(getTags(names, type))];

		const record = {
			files: JSON.stringify(files),
			infohash: infohash.toString('hex'),
			length: files.reduce((result, { length: fileLength }) => result + fileLength, 0),
			name,
			tags: tags.join(','),
			type,
		};

		upsertTorrent(record, knex);
	} catch (error) {
		console.log(error);
	}
};

const onMetadata = (metadata, infohash, knex) => {
	try {
		const { info = {} } = clean(metadata);
		const { files = [], length, name } = info;
		const names = files.map(({ path }) => (Array.isArray(path) ? path.join('/') : path)).concat(name);
		const invalid = filterTorrent(names);
		const filesWithOriginal = name && length ? [{ length, path: name }, ...files] : files;

		if (!invalid.length > 0) {
			buildRecord(invalid, knex, { files: filesWithOriginal, infohash, name });
		}
	} catch (error) {
		console.log(error);
	}
};

const getMetadata = (infohash, rinfo, knex) => {
	const socket = new net.Socket();

	socket.setTimeout(config.timeout || 5000);
	socket.connect(
		rinfo.port,
		rinfo.address,
		() => {
			const wire = new Wire(infohash);

			socket.pipe(wire).pipe(socket);

			wire.on('metadata', (metadata, hash) => {
				onMetadata(metadata, hash, knex);
				socket.destroy();
			});

			wire.on('fail', () => {
				socket.destroy();
			});

			wire.sendHandshake();
		},
	);

	socket.on('error', () => {
		socket.destroy();
	});

	socket.on('timeout', () => {
		socket.destroy();
	});
};

module.exports = getMetadata;
<commit_msg>Fixes blank type and tags and deny torrents with 0 size.<commit_after>const Wire = require('./wire');
const config = require('./../config');
const net = require('net');

const clean = (data) => {
	if (Buffer.isBuffer(data)) {
		return data.toString();
	} else if (Array.isArray(data)) {
		return data.map(clean);
	} else if (typeof data === 'object') {
		return Object.keys(data).reduce((result, key) => Object.assign(result, { [key]: clean(data[key]) }), {});
	}

	return data;
};

const filterTorrent = (names) =>
	names.filter((name) => config.filters.findIndex((element) => name.toLowerCase().includes(element)) > -1);
const getType = (names) => {
	const weights = names.reduce(
		(result, name) =>
			Object.keys(config.formats)
				.filter((key) => {
					const ext = name ? name.split('.').pop() : '';

					return config.formats[key].find((format) => format === ext);
				})
				.reduce(
					(weight, type) => Object.assign(weight, { [type]: weight[type] ? weight[type] + 1 : 1 }),
					result,
				),
		{},
	);

	return Object.keys(weights).reduce(
		(result, type) => (result && weights[result] > weights[type] ? result : type),
		'',
	);
};
const getTags = (names, type) =>
	names.reduce((result, name) => {
		const tags = config.tags
			.filter((tag) => {
				if (tag.type !== type) {
					return false;
				} else if (tag.includes && name.indexOf(tag.includes) > -1) {
					return true;
				} else if (tag.match && name.match(tag.match)) {
					return true;
				}
				return false;
			})
			.map(({ tag }) => tag);

		return result.concat(tags);
	}, []);

const upsertTorrent = async (torrent, knex) => {
	try {
		const records = await knex('torrents').where({ infohash: torrent.infohash });

		if (config.debug) {
			console.log(`${torrent.infohash} - ${records.length > 0 ? 'Updated' : 'Inserted'}`);
		}
		if (records.length > 0) {
			await knex('torrents')
				.update(Object.assign(torrent, { updated: new Date() }))
				.where({ infohash: torrent.infohash });
		} else {
			await knex('torrents')
				.insert(Object.assign(torrent, { created: new Date(), updated: new Date() }))
				.where({ infohash: torrent.infohash });
		}
	} catch (error) {
		if (config.debug) {
			console.log(error);
		}
	}
};

const buildRecord = (names, knex, { files, infohash, name }) => {
	try {
		const type = getType(names);
		const tags = [...new Set(getTags(names, type))];

		const record = {
			count: files.length,
			files: JSON.stringify(files),
			infohash: infohash.toString('hex'),
			length: files.reduce((result, { length: fileLength }) => result + fileLength, 0),
			name,
			tags: tags.join(','),
			type,
		};

		upsertTorrent(record, knex);
	} catch (error) {
		console.log(error);
	}
};

const onMetadata = (metadata, infohash, knex) => {
	try {
		const { info = {} } = clean(metadata);
		const { files = [], length, name } = info;
		const names = files.map(({ path }) => (Array.isArray(path) ? path.join('/') : path)).concat(name);
		const invalid = filterTorrent(names);
		const filesWithOriginal = name && length ? [{ length, path: name }, ...files] : files;

		console.log(length);
		if (!invalid.length > 0) {
			buildRecord(names, knex, { files: filesWithOriginal, infohash, name });
		}
	} catch (error) {
		console.log(error);
	}
};

const getMetadata = (infohash, rinfo, knex) => {
	const socket = new net.Socket();

	socket.setTimeout(config.timeout || 5000);
	socket.connect(
		rinfo.port,
		rinfo.address,
		() => {
			const wire = new Wire(infohash);

			socket.pipe(wire).pipe(socket);

			wire.on('metadata', (metadata, hash) => {
				onMetadata(metadata, hash, knex);
				socket.destroy();
			});

			wire.on('fail', () => {
				socket.destroy();
			});

			wire.sendHandshake();
		},
	);

	socket.on('error', () => {
		socket.destroy();
	});

	socket.on('timeout', () => {
		socket.destroy();
	});
};

module.exports = getMetadata;
<|endoftext|>


<commit_before>function node(head) {
    return {
        prefix: t => {
            return {
                head: head,
                args: [t.value],
                line: t.line
            };
        }
    }
}

let symbols = {
    name: node('name'),
    number: node('number'),
    string: node('string'),
    newline: {},
    leftParen: {
        power: 1,
        infix: (tokens, left, token) => {
            let args = [];
            while (true) {
                let next = tokens[0];
                if (!next) {
                    throw 'expected: , or )';
                }
                if (next.type == 'rightParen') {
                    return {head: left.args[0], args: args, line: left.line};
                }
                if ('comma' != next.type) {
                    args.push(expression(tokens, 1));
                } else {
                    tokens.shift();
                }
           }
        }
    },
    rightParen: {},
    comma: {},
};

function expression(tokens, power=0) {
    let token = tokens.shift();
    let symbol = symbols[token.type];
    if (!symbol) {
        throw token.line + ': could not parse "' + token.type + '"';
    }
    let left = symbol.prefix && symbol.prefix(token);
    while (tokens.length > 0 && power < (symbols[tokens[0].type].power || 0)) {
        token = tokens.shift();
        left = symbols[token.type].infix(tokens, left, token);
    }
    return left;
}

export default function parse(tokens) {
    let ast = [];
    while (tokens.length > 0) {
        let node = expression(tokens);
        if (node) {
            ast.push(node);
        }
    }
    return ast;
}
<commit_msg>changed symbol to parselet<commit_after>function node(head) {
    return {
        prefix: t => {
            return {
                head: head,
                args: [t.value],
                line: t.line
            };
        }
    }
}

let parselets = {
    name: node('name'),
    number: node('number'),
    string: node('string'),
    newline: {},
    leftParen: {
        power: 1,
        infix: (tokens, left, token) => {
            let args = [];
            while (true) {
                let next = tokens[0];
                if (!next) {
                    throw 'expected: , or )';
                }
                if (next.type == 'rightParen') {
                    return {head: left.args[0], args: args, line: left.line};
                }
                if ('comma' != next.type) {
                    args.push(expression(tokens, 1));
                } else {
                    tokens.shift();
                }
           }
        }
    },
    rightParen: {},
    comma: {},
};

function expression(tokens, power=0) {
    let token = tokens.shift();
    let parselet = parselets[token.type];
    if (!parselet) {
        throw token.line + ': could not parse "' + token.type + '"';
    }
    let left = parselet.prefix && parselet.prefix(token);
    while (tokens.length > 0 && power < (parselets[tokens[0].type].power || 0)) {
        token = tokens.shift();
        left = parselets[token.type].infix(tokens, left, token);
    }
    return left;
}

export default function parse(tokens) {
    let ast = [];
    while (tokens.length > 0) {
        let node = expression(tokens);
        if (node) {
            ast.push(node);
        }
    }
    return ast;
}
<|endoftext|>


<commit_before>var ContactImporter = require('../../../lib/helpers/contact-importer/contact-importer.js')
var sendgrid = require('../../../')

var chai = require('chai')
var sinon = require('sinon')

chai.should()
var expect = chai.expect
chai.use(require('sinon-chai'))

require('mocha-sinon')

describe.only('test_contact_importer', function() {
  beforeEach(function() {
    // Create a new SendGrid instance.
    var API_KEY = process.env.API_KEY
    var sg = sendgrid(API_KEY)

    // Create a new importer with a batch size of 2.
    this.contactImporter = new ContactImporter(sg, {
      batchSize: 2,
    })
    // this.spy = sinon.spy(ContactImporter.prototype, '_sendBatch')
    this.sinon.spy(ContactImporter.prototype, '_sendBatch')

    // Generate some test data.
    var data = []
    for (i = 0; i < 5; i++) {
      var item = {
        email: 'example' + i + '@example.com',
        first_name: 'Test',
        last_name: 'User'
      }
      // Lets make the first user produce an error.
      if (i === 1) {
        item.invalid_field= 'some value'
      }
      data.push(item)
    }
    this.contactImporter.push(data)
  })

  it('test_contact_importer sends items in batches', function(done) {
    var self = this
    this.timeout(30000)
    this.contactImporter.on('success', function(result, batch) {
      console.log('SUCCESS result', result)
      console.log('SUCCESS batch', batch)
    })
    this.contactImporter.on('error', function(error, batch) {
      console.log('SUCCESS error', error)
      console.log('SUCCESS batch', batch)
    })
    this.contactImporter.on('drain', function() {
      expect(self.contactImporter._sendBatch).to.have.callCount(3)
      done()
    })

    // assert.equal(sg.limiters['/v3/contactdb/recipients'].queue.length, 2)
    // assert.equal(sg.limiters['/v3/contactdb/recipients'].pendingItems.length, 5)
    // done()
  })
})
<commit_msg>Remove unused assertions<commit_after>var ContactImporter = require('../../../lib/helpers/contact-importer/contact-importer.js')
var sendgrid = require('../../../')

var chai = require('chai')
var sinon = require('sinon')

chai.should()
var expect = chai.expect
chai.use(require('sinon-chai'))

require('mocha-sinon')

describe.only('test_contact_importer', function() {
  beforeEach(function() {
    // Create a new SendGrid instance.
    var API_KEY = process.env.API_KEY
    var sg = sendgrid(API_KEY)

    // Create a new importer with a batch size of 2.
    this.contactImporter = new ContactImporter(sg, {
      batchSize: 2,
    })
    // this.spy = sinon.spy(ContactImporter.prototype, '_sendBatch')
    this.sinon.spy(ContactImporter.prototype, '_sendBatch')

    // Generate some test data.
    var data = []
    for (i = 0; i < 5; i++) {
      var item = {
        email: 'example' + i + '@example.com',
        first_name: 'Test',
        last_name: 'User'
      }
      // Lets make the first user produce an error.
      if (i === 1) {
        item.invalid_field= 'some value'
      }
      data.push(item)
    }
    this.contactImporter.push(data)
  })

  it('test_contact_importer sends items in batches', function(done) {
    var self = this
    this.timeout(30000)
    this.contactImporter.on('success', function(result, batch) {
      console.log('SUCCESS result', result)
      console.log('SUCCESS batch', batch)
    })
    this.contactImporter.on('error', function(error, batch) {
      console.log('SUCCESS error', error)
      console.log('SUCCESS batch', batch)
    })
    this.contactImporter.on('drain', function() {
      expect(self.contactImporter._sendBatch).to.have.callCount(3)
      done()
    })
  })
})
<|endoftext|>


<commit_before>'use strict';

// Small utility that throttles calls to a Node function with callback to a
// maximum number of concurrent calls.

const _ = require('underscore');
const yieldable = require('abacus-yieldable');

const initial = _.initial;
const last = _.last;
const extend = _.extend;
const isFunction = _.isFunction;
const map = _.map;
const object = _.object;
const pairs = _.pairs;
const functions = _.functions;
const bind = _.bind;
const defaults = _.defaults;

// Setup debug log
const debug = require('abacus-debug')('abacus-throttle');

// Throttle the execution of an application function with callback to a
// maximum number of calls, defaults to 1000
const throttlefn = function(fn, max) {
  const fcb = yieldable.functioncb(fn);
  const opt = defaults({
    max: max
  }, {
    max: 1000
  });

  let running = 0;
  let queue = [];

  const run = (callargs) => {
    // Queue calls to the application function if we have reached the
    // max allowed concurrent calls
    if(running === opt.max) {
      debug(
        'Queuing function call, reached max concurrent calls %d, queue size %d',
        opt.max, queue.length + 1);
      return queue.push(callargs);
    }

    // Call the application function
    running = running + 1;
    const cb = last(callargs);
    return fcb.apply(null, initial(callargs).concat([function(err, val) {

      // Call the application callback
      cb(err, val);

      // Schedule the execution of any queued call
      running = running - 1;
      if(queue.length) {
        debug('Scheduling execution of queued function call, queue size %d',
          queue.length - 1);
        const next = queue.shift();
        process.nextTick(() => run(next));
      }
    }]));
  };

  return function() {
    return run(arguments);
  };
};

// Bind a function to an object while retaining the function name
const nbind = (o, k) => extend(bind(o[k], o), {
    fname: (o.name || o.fname ? (o.name || o.fname) + '.' : '') + (o[k].name ||
      o[k].fname || k)
  });

// Convert an application function to a throttled function, if the given
// function is a module then convert all the module's exported functions as
// well.
const throttle = (fn, max) => extend(isFunction(fn) ? throttlefn(fn, max) : {},
  object(pairs(fn)), object(map(functions(fn),
    (k) => [k, throttlefn(nbind(fn, k), max)])));

// Export our public functions
module.exports = throttle;

<commit_msg>Fix throttle queuing and call scheduling<commit_after>'use strict';

// Small utility that throttles calls to a Node function with callback to a
// maximum number of concurrent calls.

const _ = require('underscore');
const yieldable = require('abacus-yieldable');

const initial = _.initial;
const last = _.last;
const extend = _.extend;
const isFunction = _.isFunction;
const map = _.map;
const object = _.object;
const pairs = _.pairs;
const functions = _.functions;
const bind = _.bind;
const defaults = _.defaults;

// Setup debug log
const debug = require('abacus-debug')('abacus-throttle');

// Throttle the execution of an application function with callback to a
// maximum number of calls, defaults to 1000
const throttlefn = function(fn, max) {
  const fcb = yieldable.functioncb(fn);
  const opt = defaults({
    max: max
  }, {
    max: 1000
  });

  let running = 0;
  let queue = [];

  const run = (args) => {
    // Call the application function
    const cb = last(args);
    try {
      return fcb.apply(null, initial(args).concat([function(err, val) {
        // Call the application callback
        try {
          cb(err, val);
        }
        finally {
          // Schedule the execution of the next queued call
          next();
        }
      }]));
    }
    catch(e) {
      // Schedule the execution of the next queued call
      next();
    }
  };

  // Schedule the execution of the next queued call
  const next = () => {
    if(queue.length) {
      debug('Scheduling execution of queued function call, queue size %d',
        queue.length - 1);
      const args = queue.shift();
      process.nextTick(() => run(args));
    }
    else running = running - 1;
  };

  return function() {
    // Queue calls to the application function if we have reached the
    // max allowed concurrent calls
    if(running === opt.max) {
      debug(
        'Queuing function call, reached max concurrent calls %d, queue size %d',
        opt.max, queue.length + 1);
      return queue.push(arguments);
    }

    // Run the application function right away
    running = running + 1;
    return run(arguments);
  };
};

// Bind a function to an object while retaining the function name
const nbind = (o, k) => extend(bind(o[k], o), {
    fname: (o.name || o.fname ? (o.name || o.fname) + '.' : '') + (o[k].name ||
      o[k].fname || k)
  });

// Convert an application function to a throttled function, if the given
// function is a module then convert all the module's exported functions as
// well.
const throttle = (fn, max) => extend(isFunction(fn) ? throttlefn(fn, max) : {},
  object(pairs(fn)), object(map(functions(fn),
    (k) => [k, throttlefn(nbind(fn, k), max)])));

// Export our public functions
module.exports = throttle;

<|endoftext|>


<commit_before>import React from 'react';
import Board from '@/modules/core/client/components/Board.js';
import { Trans, useTranslation } from 'react-i18next';

export default function Contribute() {
  const { t } = useTranslation('pages');

  return (
    <>
      <Board names="forestpath">

{t('Support Trustroots')}

      </Board>

              <Trans t={t} ns="pages">
                Trustroots is a non-profit foundation{' '}
                registered in the United Kingdom in{' '}

                  March 2015

                . At the moment our costs are mainly for servers and other
                technical aspects, currently between €1000 and €2000 per year.
                As accepting donations would lead to higher total costs (due to
                accounting etc.) and require more effort than it seems worth,
                everything is currently being covered by the board.
              </Trans>

              <Trans t={t} ns="pages">
                That said, there are still other ways to support us!
              </Trans>

{t('Volunteering')}

              <Trans t={t} ns="pages">
                Whether you’re a hardcore techie or know nothing of coding, we
                can use your help! Head over to the{' '}

                  volunteer chat
                {' '}
                to get an idea of what’s in the making and what you can do to
                help out.
              </Trans>

{t('Referal Programs')}

              <Trans t={t} ns="pages">
                We use and recommend Namecheap for domains,
                partly because they're a{' '}

                  responsible company
                {' '}
                and foremost as they do a great job. Sign up via{' '}
                this link and
                we'll get little bit in return.
              </Trans>

              <Trans t={t} ns="pages">
                Our servers are hosted at reliable and easy to use{' '}
                DigitalOcean. Sign up via{' '}

                  this link
                {' '}
                and when you start using their VPS service, we get 25$ to cover
                our hosting, you get 100$.
              </Trans>

      {/* /.container */}
    </>
  );
}

Contribute.propTypes = {};
<commit_msg>Adding mention of donations in form of media (#2028)<commit_after>import React from 'react';
import Board from '@/modules/core/client/components/Board.js';
import { Trans, useTranslation } from 'react-i18next';

export default function Contribute() {
  const { t } = useTranslation('pages');

  return (
    <>
      <Board names="forestpath">

{t('Support Trustroots')}

      </Board>

              <Trans t={t} ns="pages">
                Trustroots is a non-profit foundation{' '}
                registered in the United Kingdom in{' '}

                  March 2015

                . At the moment our costs are mainly for servers and other
                technical aspects, currently between €1000 and €2000 per year.
                As accepting donations would lead to higher total costs (due to
                accounting etc.) and require more effort than it seems worth,
                everything is currently being covered by the board.
              </Trans>

              <Trans t={t} ns="pages">
                That said, there are still other ways to support us!
              </Trans>

{t('Volunteering')}

              <Trans t={t} ns="pages">
                Whether you’re a hardcore techie or know nothing of coding, we
                can use your help! See{' '}

                  volunteer page
                {' '}
                get an idea of what’s in the making and what you can do to help
                out. You could help Trustroots out with as little effort as
                donating your photo's to use for our website or create
                content. If you're a (semi-)professional photographer or
                have any questions you can contact us.
              </Trans>

{t('Referal Programs')}

              <Trans t={t} ns="pages">
                We use and recommend Namecheap for domains,
                partly because they're a{' '}

                  responsible company
                {' '}
                and foremost as they do a great job. Sign up via{' '}
                this link and
                we'll get little bit in return.
              </Trans>

              <Trans t={t} ns="pages">
                Our servers are hosted at reliable and easy to use{' '}
                DigitalOcean. Sign up via{' '}

                  this link
                {' '}
                and when you start using their VPS service, we get 25$ to cover
                our hosting, you get 100$.
              </Trans>

      {/* /.container */}
    </>
  );
}

Contribute.propTypes = {};
<|endoftext|>