<commit_before>/*!
 * ws: a node.js websocket client
 * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
 * MIT Licensed
 */

'use strict';

const ErrorCodes = require('./ErrorCodes');
const bufferUtil = require('./BufferUtil').BufferUtil;
const PerMessageDeflate = require('./PerMessageDeflate');

/**
 * HyBi Sender implementation.
 */
class Sender {
  /**
   * Creates a Sender instance.
   *
   * @param {net.Socket} socket The connection socket
   * @param {Object} extensions An object containing the negotiated extensions
   */
  constructor (socket, extensions) {
    this._socket = socket;
    this.extensions = extensions || {};
    this.firstFragment = true;
    this.compress = false;
    this.messageHandlers = [];
    this.processing = false;
    this.onerror = null;
  }

  /**
   * Sends a close message to the other peer.
   *
   * @param {(Number|undefined)} code The status code component of the body
   * @param {String} data The message component of the body
   * @param {Boolean} mask Specifies whether or not to mask the message
   * @param {Function} cb Callback
   * @public
   */
  close (code, data, mask, cb) {
    if (code !== undefined && (typeof code !== 'number' || !ErrorCodes.isValidErrorCode(code))) {
      throw new Error('first argument must be a valid error code number');
    }
    code = code || 1000;
    var dataBuffer = new Buffer(2 + (data ? Buffer.byteLength(data) : 0));
    dataBuffer.writeUInt16BE(code, 0);
    if (dataBuffer.length > 2) dataBuffer.write(data, 2);

    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.enqueue([this.doClose, [dataBuffer, mask, cb]]);
    } else {
      this.doClose(dataBuffer, mask, cb);
    }
  }

  /**
   * Frames and sends a close message.
   *
   * @param {Buffer} data The message to send
   * @param {Boolean} mask Specifies whether or not to mask `data`
   * @param {Function} cb Callback
   * @private
   */
  doClose (data, mask, cb) {
    this.frameAndSend(0x8, data, true, mask);
    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.messageHandlerCallback();
    }
    if (cb) cb();
  }

  /**
   * Sends a ping message to the other peer.
   *
   * @param {*} data The message to send
   * @param {Object} options Options object
   * @param {Boolean} options.mask Specifies whether or not to mask `data`
   * @public
   */
  ping (data, options) {
    if (data) data = toBuffer(data);
    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.enqueue([this.doPing, [data, options]]);
    } else {
      this.doPing(data, options);
    }
  }

  /**
   * Frames and sends a ping message.
   *
   * @param {Buffer} data The message to send
   * @param {Object} options Options object
   * @param {Boolean} options.mask Specifies whether or not to mask `data`
   * @private
   */
  doPing (data, options) {
    this.frameAndSend(0x9, data, true, options.mask);
    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.messageHandlerCallback();
    }
  }

  /**
   * Sends a pong message to the other peer.
   *
   * @param {*} data The message to send
   * @param {Object} options Options object
   * @param {Boolean} options.mask Specifies whether or not to mask `data`
   * @public
   */
  pong (data, options) {
    if (data) data = toBuffer(data);
    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.enqueue([this.doPong, [data, options]]);
    } else {
      this.doPong(data, options);
    }
  }

  /**
   * Frames and sends a pong message.
   *
   * @param {Buffer} data The message to send
   * @param {Object} options Options object
   * @param {Boolean} options.mask Specifies whether or not to mask `data`
   * @private
   */
  doPong (data, options) {
    this.frameAndSend(0xa, data, true, options.mask);
    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.messageHandlerCallback();
    }
  }

  /**
   * Sends a data message to the other peer.
   *
   * @param {*} data The message to send
   * @param {Object} options Options object
   * @param {Boolean} options.compress Specifies whether or not to compress `data`
   * @param {Boolean} options.mask Specifies whether or not to mask `data`
   * @param {Boolean} options.fin Specifies whether the fragment is the last one
   * @param {Function} cb Callback
   * @public
   */
  send (data, options, cb) {
    var finalFragment = !options || options.fin !== false;
    var mask = options && options.mask;
    var compress = options && options.compress;
    var opcode = options && options.binary ? 2 : 1;

    if (data) data = toBuffer(data);

    if (this.firstFragment === false) {
      opcode = 0;
      compress = false;
    } else {
      this.firstFragment = false;
      if (compress && this.extensions[PerMessageDeflate.extensionName]) {
        compress = data && data.length > this.extensions[PerMessageDeflate.extensionName].threshold;
      }
      this.compress = compress;
    }

    if (finalFragment) this.firstFragment = true;

    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.enqueue([this.sendCompressed, [opcode, data, finalFragment, mask, compress, cb]]);
    } else {
      this.frameAndSend(opcode, data, finalFragment, mask, false, cb);
    }
  }

  /**
   * Compresses, frames and sends a data message.
   *
   * @param {Number} opcode The opcode
   * @param {Buffer} data The message to send
   * @param {Boolean} finalFragment Specifies whether or not to set the FIN bit
   * @param {Boolean} mask Specifies whether or not to mask `data`
   * @param {Boolean} compress Specifies whether or not to set the RSV1 bit
   * @param {Function} cb Callback
   * @private
   */
  sendCompressed (opcode, data, finalFragment, mask, compress, cb) {
    if (!this.compress || !data) {
      this.frameAndSend(opcode, data, finalFragment, mask, compress, cb);
      this.messageHandlerCallback();
      return;
    }
    this.extensions[PerMessageDeflate.extensionName].compress(data, finalFragment, (err, data) => {
      if (err) {
        if (cb) cb(err);
        else this.onerror(err);
        return;
      }
      this.frameAndSend(opcode, data, finalFragment, mask, compress, cb);
      this.messageHandlerCallback();
    });
  }

  /**
   * Frames and sends a piece of data according to the HyBi WebSocket protocol.
   *
   * @param {Number} opcode The opcode
   * @param {Buffer} data The data to send
   * @param {Boolean} finalFragment Specifies whether or not to set the FIN bit
   * @param {Boolean} maskData Specifies whether or not to mask `data`
   * @param {Boolean} compressed Specifies whether or not to set the RSV1 bit
   * @param {Function} cb Callback
   * @private
   */
  frameAndSend (opcode, data, finalFragment, maskData, compressed, cb) {
    if (!data) {
      var buff = [opcode | (finalFragment ? 0x80 : 0), 0 | (maskData ? 0x80 : 0)]
        .concat(maskData ? [0, 0, 0, 0] : []);
      sendFramedData(this, new Buffer(buff), null, cb);
      return;
    }

    var dataLength = data.length;
    var dataOffset = maskData ? 6 : 2;
    var secondByte = dataLength;

    if (dataLength >= 65536) {
      dataOffset += 8;
      secondByte = 127;
    } else if (dataLength > 125) {
      dataOffset += 2;
      secondByte = 126;
    }

    var canModifyData = compressed;
    var mergeBuffers = dataLength < 32768 || (maskData && !canModifyData);
    var totalLength = mergeBuffers ? dataLength + dataOffset : dataOffset;
    var outputBuffer = new Buffer(totalLength);
    outputBuffer[0] = finalFragment ? opcode | 0x80 : opcode;
    if (compressed) outputBuffer[0] |= 0x40;

    switch (secondByte) {
      case 126:
        outputBuffer.writeUInt16BE(dataLength, 2);
        break;
      case 127:
        outputBuffer.writeUInt32BE(0, 2);
        outputBuffer.writeUInt32BE(dataLength, 6);
    }

    if (maskData) {
      outputBuffer[1] = secondByte | 0x80;
      var mask = getRandomMask();
      outputBuffer[dataOffset - 4] = mask[0];
      outputBuffer[dataOffset - 3] = mask[1];
      outputBuffer[dataOffset - 2] = mask[2];
      outputBuffer[dataOffset - 1] = mask[3];
      if (mergeBuffers) {
        bufferUtil.mask(data, mask, outputBuffer, dataOffset, dataLength);
      } else {
        bufferUtil.mask(data, mask, data, 0, dataLength);
      }
    } else {
      outputBuffer[1] = secondByte;
      if (mergeBuffers) {
        data.copy(outputBuffer, dataOffset);
      }
    }
    sendFramedData(this, outputBuffer, mergeBuffers ? null : data, cb);
  }

  /**
   * Executes a queued send operation.
   *
   * @private
   */
  flush () {
    if (this.processing) return;

    var handler = this.messageHandlers.shift();
    if (!handler) return;

    this.processing = true;

    handler[0].apply(this, handler[1]);
  }

  /**
   * Signals the completion of a send operation.
   *
   * @private
   */
  messageHandlerCallback () {
    this.processing = false;
    process.nextTick(() => this.flush());
  }

  /**
   * Enqueues a send operation.
   *
   * @private
   */
  enqueue (params) {
    this.messageHandlers.push(params);
    this.flush();
  }
}

module.exports = Sender;

/**
 * Converts `data` into a buffer.
 *
 * @param {*} data Data to convert
 * @return {Buffer} Converted data
 * @private
 */
function toBuffer (data) {
  if (Buffer.isBuffer(data)) return data;

  if (data instanceof ArrayBuffer) return Buffer.from(data);

  if (ArrayBuffer.isView(data)) {
    const buf = Buffer.from(data.buffer);

    if (data.byteLength !== data.buffer.byteLength) {
      return buf.slice(data.byteOffset, data.byteOffset + data.byteLength);
    }

    return buf;
  }

  return Buffer.from(typeof data === 'number' ? data.toString() : data);
}

/**
 * Generates a random mask.
 *
 * @return {Buffer} The mask
 * @private
 */
function getRandomMask () {
  return new Buffer([
    ~~(Math.random() * 255),
    ~~(Math.random() * 255),
    ~~(Math.random() * 255),
    ~~(Math.random() * 255)
  ]);
}

/**
 * Sends a frame.
 *
 * @param {Sender} sender Sender instance
 * @param {Buffer} outputBuffer The data to send
 * @param {Buffer} data Additional data to send if frame is split into two buffers
 * @param {Function} cb Callback
 * @private
 */
function sendFramedData (sender, outputBuffer, data, cb) {
  try {
    if (data) {
      sender._socket.write(outputBuffer);
      sender._socket.write(data, cb);
    } else {
      sender._socket.write(outputBuffer, cb);
    }
  } catch (e) {
    if (cb) cb(e);
    else sender.onerror(e);
  }
}
<commit_msg>Allow compressed empty first fragment<commit_after>/*!
 * ws: a node.js websocket client
 * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
 * MIT Licensed
 */

'use strict';

const ErrorCodes = require('./ErrorCodes');
const bufferUtil = require('./BufferUtil').BufferUtil;
const PerMessageDeflate = require('./PerMessageDeflate');

/**
 * HyBi Sender implementation.
 */
class Sender {
  /**
   * Creates a Sender instance.
   *
   * @param {net.Socket} socket The connection socket
   * @param {Object} extensions An object containing the negotiated extensions
   */
  constructor (socket, extensions) {
    this._socket = socket;
    this.extensions = extensions || {};
    this.firstFragment = true;
    this.compress = false;
    this.messageHandlers = [];
    this.processing = false;
    this.onerror = null;
  }

  /**
   * Sends a close message to the other peer.
   *
   * @param {(Number|undefined)} code The status code component of the body
   * @param {String} data The message component of the body
   * @param {Boolean} mask Specifies whether or not to mask the message
   * @param {Function} cb Callback
   * @public
   */
  close (code, data, mask, cb) {
    if (code !== undefined && (typeof code !== 'number' || !ErrorCodes.isValidErrorCode(code))) {
      throw new Error('first argument must be a valid error code number');
    }
    code = code || 1000;
    var dataBuffer = new Buffer(2 + (data ? Buffer.byteLength(data) : 0));
    dataBuffer.writeUInt16BE(code, 0);
    if (dataBuffer.length > 2) dataBuffer.write(data, 2);

    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.enqueue([this.doClose, [dataBuffer, mask, cb]]);
    } else {
      this.doClose(dataBuffer, mask, cb);
    }
  }

  /**
   * Frames and sends a close message.
   *
   * @param {Buffer} data The message to send
   * @param {Boolean} mask Specifies whether or not to mask `data`
   * @param {Function} cb Callback
   * @private
   */
  doClose (data, mask, cb) {
    this.frameAndSend(0x8, data, true, mask);
    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.messageHandlerCallback();
    }
    if (cb) cb();
  }

  /**
   * Sends a ping message to the other peer.
   *
   * @param {*} data The message to send
   * @param {Object} options Options object
   * @param {Boolean} options.mask Specifies whether or not to mask `data`
   * @public
   */
  ping (data, options) {
    if (data) data = toBuffer(data);
    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.enqueue([this.doPing, [data, options]]);
    } else {
      this.doPing(data, options);
    }
  }

  /**
   * Frames and sends a ping message.
   *
   * @param {Buffer} data The message to send
   * @param {Object} options Options object
   * @param {Boolean} options.mask Specifies whether or not to mask `data`
   * @private
   */
  doPing (data, options) {
    this.frameAndSend(0x9, data, true, options.mask);
    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.messageHandlerCallback();
    }
  }

  /**
   * Sends a pong message to the other peer.
   *
   * @param {*} data The message to send
   * @param {Object} options Options object
   * @param {Boolean} options.mask Specifies whether or not to mask `data`
   * @public
   */
  pong (data, options) {
    if (data) data = toBuffer(data);
    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.enqueue([this.doPong, [data, options]]);
    } else {
      this.doPong(data, options);
    }
  }

  /**
   * Frames and sends a pong message.
   *
   * @param {Buffer} data The message to send
   * @param {Object} options Options object
   * @param {Boolean} options.mask Specifies whether or not to mask `data`
   * @private
   */
  doPong (data, options) {
    this.frameAndSend(0xa, data, true, options.mask);
    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.messageHandlerCallback();
    }
  }

  /**
   * Sends a data message to the other peer.
   *
   * @param {*} data The message to send
   * @param {Object} options Options object
   * @param {Boolean} options.compress Specifies whether or not to compress `data`
   * @param {Boolean} options.mask Specifies whether or not to mask `data`
   * @param {Boolean} options.fin Specifies whether the fragment is the last one
   * @param {Function} cb Callback
   * @public
   */
  send (data, options, cb) {
    var finalFragment = !options || options.fin !== false;
    var mask = options && options.mask;
    var compress = options && options.compress;
    var opcode = options && options.binary ? 2 : 1;

    if (data) data = toBuffer(data);

    if (this.firstFragment === false) {
      opcode = 0;
      compress = false;
    } else {
      this.firstFragment = false;
      if (compress && data && this.extensions[PerMessageDeflate.extensionName]) {
        compress = data.length > this.extensions[PerMessageDeflate.extensionName].threshold;
      }
      this.compress = compress;
    }

    if (finalFragment) this.firstFragment = true;

    if (this.extensions[PerMessageDeflate.extensionName]) {
      this.enqueue([this.sendCompressed, [opcode, data, finalFragment, mask, compress, cb]]);
    } else {
      this.frameAndSend(opcode, data, finalFragment, mask, false, cb);
    }
  }

  /**
   * Compresses, frames and sends a data message.
   *
   * @param {Number} opcode The opcode
   * @param {Buffer} data The message to send
   * @param {Boolean} finalFragment Specifies whether or not to set the FIN bit
   * @param {Boolean} mask Specifies whether or not to mask `data`
   * @param {Boolean} compress Specifies whether or not to set the RSV1 bit
   * @param {Function} cb Callback
   * @private
   */
  sendCompressed (opcode, data, finalFragment, mask, compress, cb) {
    if (!this.compress || !data) {
      this.frameAndSend(opcode, data, finalFragment, mask, compress, cb);
      this.messageHandlerCallback();
      return;
    }
    this.extensions[PerMessageDeflate.extensionName].compress(data, finalFragment, (err, data) => {
      if (err) {
        if (cb) cb(err);
        else this.onerror(err);
        return;
      }
      this.frameAndSend(opcode, data, finalFragment, mask, compress, cb);
      this.messageHandlerCallback();
    });
  }

  /**
   * Frames and sends a piece of data according to the HyBi WebSocket protocol.
   *
   * @param {Number} opcode The opcode
   * @param {Buffer} data The data to send
   * @param {Boolean} finalFragment Specifies whether or not to set the FIN bit
   * @param {Boolean} maskData Specifies whether or not to mask `data`
   * @param {Boolean} compressed Specifies whether or not to set the RSV1 bit
   * @param {Function} cb Callback
   * @private
   */
  frameAndSend (opcode, data, finalFragment, maskData, compressed, cb) {
    if (!data) {
      var buff = [opcode | (finalFragment ? 0x80 : 0), 0 | (maskData ? 0x80 : 0)]
        .concat(maskData ? [0, 0, 0, 0] : []);
      sendFramedData(this, new Buffer(buff), null, cb);
      return;
    }

    var dataLength = data.length;
    var dataOffset = maskData ? 6 : 2;
    var secondByte = dataLength;

    if (dataLength >= 65536) {
      dataOffset += 8;
      secondByte = 127;
    } else if (dataLength > 125) {
      dataOffset += 2;
      secondByte = 126;
    }

    var canModifyData = compressed;
    var mergeBuffers = dataLength < 32768 || (maskData && !canModifyData);
    var totalLength = mergeBuffers ? dataLength + dataOffset : dataOffset;
    var outputBuffer = new Buffer(totalLength);
    outputBuffer[0] = finalFragment ? opcode | 0x80 : opcode;
    if (compressed) outputBuffer[0] |= 0x40;

    switch (secondByte) {
      case 126:
        outputBuffer.writeUInt16BE(dataLength, 2);
        break;
      case 127:
        outputBuffer.writeUInt32BE(0, 2);
        outputBuffer.writeUInt32BE(dataLength, 6);
    }

    if (maskData) {
      outputBuffer[1] = secondByte | 0x80;
      var mask = getRandomMask();
      outputBuffer[dataOffset - 4] = mask[0];
      outputBuffer[dataOffset - 3] = mask[1];
      outputBuffer[dataOffset - 2] = mask[2];
      outputBuffer[dataOffset - 1] = mask[3];
      if (mergeBuffers) {
        bufferUtil.mask(data, mask, outputBuffer, dataOffset, dataLength);
      } else {
        bufferUtil.mask(data, mask, data, 0, dataLength);
      }
    } else {
      outputBuffer[1] = secondByte;
      if (mergeBuffers) {
        data.copy(outputBuffer, dataOffset);
      }
    }
    sendFramedData(this, outputBuffer, mergeBuffers ? null : data, cb);
  }

  /**
   * Executes a queued send operation.
   *
   * @private
   */
  flush () {
    if (this.processing) return;

    var handler = this.messageHandlers.shift();
    if (!handler) return;

    this.processing = true;

    handler[0].apply(this, handler[1]);
  }

  /**
   * Signals the completion of a send operation.
   *
   * @private
   */
  messageHandlerCallback () {
    this.processing = false;
    process.nextTick(() => this.flush());
  }

  /**
   * Enqueues a send operation.
   *
   * @private
   */
  enqueue (params) {
    this.messageHandlers.push(params);
    this.flush();
  }
}

module.exports = Sender;

/**
 * Converts `data` into a buffer.
 *
 * @param {*} data Data to convert
 * @return {Buffer} Converted data
 * @private
 */
function toBuffer (data) {
  if (Buffer.isBuffer(data)) return data;

  if (data instanceof ArrayBuffer) return Buffer.from(data);

  if (ArrayBuffer.isView(data)) {
    const buf = Buffer.from(data.buffer);

    if (data.byteLength !== data.buffer.byteLength) {
      return buf.slice(data.byteOffset, data.byteOffset + data.byteLength);
    }

    return buf;
  }

  return Buffer.from(typeof data === 'number' ? data.toString() : data);
}

/**
 * Generates a random mask.
 *
 * @return {Buffer} The mask
 * @private
 */
function getRandomMask () {
  return new Buffer([
    ~~(Math.random() * 255),
    ~~(Math.random() * 255),
    ~~(Math.random() * 255),
    ~~(Math.random() * 255)
  ]);
}

/**
 * Sends a frame.
 *
 * @param {Sender} sender Sender instance
 * @param {Buffer} outputBuffer The data to send
 * @param {Buffer} data Additional data to send if frame is split into two buffers
 * @param {Function} cb Callback
 * @private
 */
function sendFramedData (sender, outputBuffer, data, cb) {
  try {
    if (data) {
      sender._socket.write(outputBuffer);
      sender._socket.write(data, cb);
    } else {
      sender._socket.write(outputBuffer, cb);
    }
  } catch (e) {
    if (cb) cb(e);
    else sender.onerror(e);
  }
}
<|endoftext|>


<commit_before>var path = require('path'),
    HtmlWebpackPlugin = require('html-webpack-plugin'),
    CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin'),
    // DedupePlugin = require('webpack/lib/optimize/DedupePlugin'),
    jade = require('jade');

var baseDir = path.resolve(__dirname),
    srcDir = path.resolve(baseDir, 'src'),
    demoDir = path.resolve(baseDir, 'demo'),

    nodeModulesDir = path.resolve(baseDir, 'node_modules'),
    reactDir = path.resolve(nodeModulesDir, 'react'),

    pathToEntry = path.resolve(baseDir, 'demo/demo.js'),
    indexHtml = jade.compileFile(path.resolve(baseDir, 'demo/index.jade'));

    // jsLoader = ['react-hot', 'babel?whitelist[]=flow', 'flowcheck', babel + '&blacklist[]=flow']; // hack from flowcheck/issues#18

var config = {
  entry: {
    /* NOTE: React hot loader doesn't work with higher-order components :( */
    app: ['webpack/hot/dev-server', pathToEntry],
    vendor: ['react']
  },
  resolve: {
    alias: {
      // npm link + webpack doesn't dedupe peerDependencies properly
      react: reactDir,
      'keyboard-shortcuts': path.resolve(nodeModulesDir, 'keyboard-shortcuts')
    }
  },
  devtool: 'eval',
  debug: true,
  output: {
    path: path.resolve(baseDir, 'build'),
    filename: 'bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Circuit-Simulator',
      templateContent: function(templateParams) {
        var files = templateParams.htmlWebpackPlugin.files; // js, css, chunks
        return indexHtml(files);
      }
    }),
    new CommonsChunkPlugin('vendor', 'common.js')
    // new DedupePlugin()
  ],
  module: {
    loaders: [
      {
        test: /\.css$/,
        loaders: ['style', 'css']
      },
      {
        test: /\.scss$/,
        loaders: ['style', 'css', 'sass']
      },
      {
        test: /\.(js|jsx)$/,
        include: [srcDir, demoDir],
        exclude: [nodeModulesDir],
        loaders: ['react-hot', 'babel'] // until https://github.com/facebook/flow/issues/349 is fixed
      },
      { // will be run before loaders above
        test: /\.(js|jsx)$/,
        include: [srcDir, demoDir],
        exclude: [nodeModulesDir],
        loader: 'eslint-loader'
      },
      {
        test: /\.json$/,
        loader: 'json'
      },
      {
        // Expose React - react-router requires this
        test: require.resolve('react'),
        loader: 'expose?React'
      }
    ],
    eslint: {
      'emitWarning': true,
      'emitError': true,
      'quiet': false
    }
  }
};

module.exports = config;
<commit_msg>Try to improve build speed (I have no idea what I'm doing)<commit_after>var path = require('path'),
    HtmlWebpackPlugin = require('html-webpack-plugin'),
    CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin'),
    DedupePlugin = require('webpack/lib/optimize/DedupePlugin'),
    jade = require('jade');

var baseDir = path.resolve(__dirname),
    srcDir = path.resolve(baseDir, 'src'),
    demoDir = path.resolve(baseDir, 'demo'),

    nodeModulesDir = path.resolve(baseDir, 'node_modules'),
    reactDir = path.resolve(nodeModulesDir, 'react'),

    pathToEntry = path.resolve(baseDir, 'demo/demo.js'),
    indexHtml = jade.compileFile(path.resolve(baseDir, 'demo/index.jade'));

    // jsLoader = ['react-hot', 'babel?whitelist[]=flow', 'flowcheck', babel + '&blacklist[]=flow']; // hack from flowcheck/issues#18

var config = {
  entry: {
    /* NOTE: React hot loader doesn't work with higher-order components :( */
    app: ['webpack/hot/dev-server', pathToEntry],
    vendor: ['react']
  },
  resolve: {
    alias: {
      // npm link + webpack doesn't dedupe peerDependencies properly
      react: reactDir,
      'keyboard-shortcuts': path.resolve(nodeModulesDir, 'keyboard-shortcuts'),
      'babel-runtime': path.resolve(nodeModulesDir, 'babel-runtime')
    }
  },
  devtool: 'eval',
  debug: true,
  output: {
    path: path.resolve(baseDir, 'build'),
    filename: 'bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Circuit-Simulator',
      templateContent: function(templateParams) {
        var files = templateParams.htmlWebpackPlugin.files; // js, css, chunks
        return indexHtml(files);
      }
    }),
    new CommonsChunkPlugin('vendor', 'common.js'),
    new DedupePlugin()
  ],
  module: {
    loaders: [
      {
        test: /\.css$/,
        loaders: ['style', 'css']
      },
      {
        test: /\.scss$/,
        loaders: ['style', 'css', 'sass']
      },
      {
        test: /\.(js|jsx)$/,
        include: [srcDir, demoDir],
        exclude: [nodeModulesDir],
        loaders: ['react-hot', 'babel'] // until https://github.com/facebook/flow/issues/349 is fixed
      },
      { // will be run before loaders above
        test: /\.(js|jsx)$/,
        include: [srcDir, demoDir],
        exclude: [nodeModulesDir],
        loader: 'eslint-loader'
      },
      {
        test: /\.json$/,
        loader: 'json'
      },
      {
        // Expose React - react-router requires this
        test: require.resolve('react'),
        loader: 'expose?React'
      }
    ],
    eslint: {
      'emitWarning': true,
      'emitError': true,
      'quiet': false
    }
  }
};

module.exports = config;
<|endoftext|>


<commit_before>'use strict';

const EventEmitter = require('events');
const net = require('net');

const Connection = require('./Connection');
const packet = require('./packet');

class Server extends EventEmitter {

  constructor(cb) {
    super();

    this._server = net.createServer((socket) => {
      cb(new Session(socket));
    });
  }

  listen(port, hostname, cb) {
    this._server.listen(port, hostname, cb);
  }

  address() {
    return this._server.address();
  }

  close(cb) {
    this._server.close(cb);
  }

};

class Session extends EventEmitter {

  constructor(socket) {
    super();

    this._connection = new Connection(socket, {
      heartbeatPacketType: packet.SERVER_HEARTBEAT,
    });

    this._connection.on('packet', (packetType, payload) => {
      switch (packetType) {
        case packet.DEBUG:
          break;
        case packet.LOGIN_REQUEST:
          this.emit('login', packet.parseLoginRequest(payload));
          break;
        case packet.LOGOUT_REQUEST:
          this.emit('logout');
          break;
        case packet.UNSEQUENCED_DATA:
          this.emit('message', payload);
          break;
        case packet.CLIENT_HEARTBEAT:
          break;
        default:
          this.emit('error', new Error('Unknown packet type: ' + packetType));
      }
    });

    this._connection.on('error', (err) => {
      this.emit('error', err);
    });

    this._connection.on('end', () => {
      this.emit('end');
    });
  }

  accept(payload, cb) {
    this._connection.send(packet.LOGIN_ACCEPTED, packet.formatLoginAccepted(payload), cb);
  }

  reject(payload, cb) {
    this._connection.send(packet.LOGIN_REJECTED, packet.formatLoginRejected(payload), cb);
  }

  send(payload, cb) {
    this._connection.send(packet.SEQUENCED_DATA, payload, cb);
  }

  ending(cb) {
    this._connection.send(packet.END_OF_SESSION);
  }

  end() {
    this._connection.end();
  }

}

module.exports = Server;
<commit_msg>Add 'listening' event for server<commit_after>'use strict';

const EventEmitter = require('events');
const net = require('net');

const Connection = require('./Connection');
const packet = require('./packet');

class Server extends EventEmitter {

  constructor(cb) {
    super();

    this._server = net.createServer((socket) => {
      cb(new Session(socket));
    });
  }

  listen(port, hostname, cb) {
    this._server.listen(port, hostname, () => {
      this.emit('listening');

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

  address() {
    return this._server.address();
  }

  close(cb) {
    this._server.close(cb);
  }

};

class Session extends EventEmitter {

  constructor(socket) {
    super();

    this._connection = new Connection(socket, {
      heartbeatPacketType: packet.SERVER_HEARTBEAT,
    });

    this._connection.on('packet', (packetType, payload) => {
      switch (packetType) {
        case packet.DEBUG:
          break;
        case packet.LOGIN_REQUEST:
          this.emit('login', packet.parseLoginRequest(payload));
          break;
        case packet.LOGOUT_REQUEST:
          this.emit('logout');
          break;
        case packet.UNSEQUENCED_DATA:
          this.emit('message', payload);
          break;
        case packet.CLIENT_HEARTBEAT:
          break;
        default:
          this.emit('error', new Error('Unknown packet type: ' + packetType));
      }
    });

    this._connection.on('error', (err) => {
      this.emit('error', err);
    });

    this._connection.on('end', () => {
      this.emit('end');
    });
  }

  accept(payload, cb) {
    this._connection.send(packet.LOGIN_ACCEPTED, packet.formatLoginAccepted(payload), cb);
  }

  reject(payload, cb) {
    this._connection.send(packet.LOGIN_REJECTED, packet.formatLoginRejected(payload), cb);
  }

  send(payload, cb) {
    this._connection.send(packet.SEQUENCED_DATA, payload, cb);
  }

  ending(cb) {
    this._connection.send(packet.END_OF_SESSION);
  }

  end() {
    this._connection.end();
  }

}

module.exports = Server;
<|endoftext|>


<commit_before>import D from './D';
import Super from './Super';
import constructors from './constants/constructors';
import regexpSpecialCharacters from './constants/regexpSpecialCharacters';
import {
	isDateLike, isFunction, isNumberLike, isObject, isString,
	validate
} from './helpers';

const NativeString = global.String;
const htmlSpecials = {
	'&': '&',
	'<': '<',
	'>': '>'
};
const regexpSpecialsRegexp = new RegExp(new Super(regexpSpecialCharacters)
  .word((x) => '\\' + x + '|')
  .replace(/\|$/, ''), 'g'
);

export class String extends Super {
	constructor(string = '') {
		super(string);
	}

	capitalizeFirst() {
		const string = this.$;

		return new String(string[0].toUpperCase() + string.substring(1));
	}
	endsWith(string) {
		return this.revert().startsWith(new String(string).revert().$);
	}
	escapeHtml() {
		let string = this.$;

		for (const symbol in htmlSpecials) {
			if (htmlSpecials.hasOwnProperty(symbol)) {
				string = string.replace(new RegExp(symbol, 'g'), htmlSpecials[symbol]);
			}
		}

		return new String(string);
	}
	escapeRegExp() {
		return this.replace(regexpSpecialsRegexp, '\\$&');
	}
	in(object) {
		if (!isObject(object)) {
			return false;
		}

		return this.$ in object;
	}
	indexOf() {
		return this.$.indexOf.apply(this.$, arguments);
	}
  get length() {
    return this.$.length;
  }
	match() {
		const match = this.$.match.apply(this.$, arguments);

    return D(match);
	}
  parseJSON(options = {}, mapFn) {
    if (!arguments.length) {
      return D(JSON.parse(this.$));
    }

    if (isFunction(options)) {
      mapFn = options;
      options = {};
    }

    const { numbers, dates } = options;
    const parsed = JSON.parse(this.$, function (key, value) {
      if (dates && isDateLike(value) && !isNumberLike(value)) {
        value = new Date(value);
      } else if (numbers && isNumberLike(value) && isString(value)) {
        value = Number(value);
      }

      return mapFn ? mapFn.apply(this, arguments) : value;
    });

    return D(parsed);
  }
	repeat(n) {
		validate([n], [['intLike', '>=0']], 'String#repeat');

		n = Number(n);

		const string = this.$;

    let s = '';

		for (let i = 0; i < n; i++) {
			s += string;
		}

		return new String(s);
	}
	replace(regexp, replacer = '') {
		return new String(this.$.replace(regexp, replacer));
	}
	replaceString(string, replacer = '') {
		string = new Super(string).$;

		validate([string], ['string'], 'String#replaceString');

		return new String(this.$.split(string).join(replacer));
	}
	revert() {
		const Str = String;
		const string = this.$;
		let str = '';

		for (let i = string.length - 1; i >= 0; i--) {
			str += string[i];
		}

		return new Str(str);
	}
  slice() {
    const string = this.$;

    return new String(string.slice.apply(string, arguments));
  }
	split(delimiter) {
		return D(this.$.split(delimiter));
	}
	startsWith(string) {
		return this.$.indexOf(string) === 0;
	}
	substr() {
		const string = this.$;

		return new String(string.substr.apply(string, arguments));
	}
  substring() {
    const string = this.$;

    return new String(string.substring.apply(string, arguments));
  }
  toCamelCase() {
		return new String(trim(this.$)
			.replace(/[\s\-_\.]+/g, '-')
			.replace(/\-[^\-]/g, (match) => {
				return match[1].toUpperCase();
			})
			.replace(/^[\S]/, (match) => {
				return match.toLowerCase();
			})
		);
	}
	toCapitalCase() {
		return new String(trim(this.$)
			.replace(/[\s\-_\.]+/g, ' ')
			.replace(/[\S]/g, (match) => {
				if (match.toLowerCase() !== match) {
					return ' ' + match;
				}

				return match;
			})
			.replace(/\s[\S]/g, (match) => {
				return match.toUpperCase();
			})
			.replace(/\s+/g, ' ')
			.replace(/^\s/, '')
			.replace(/^[\S]/, (match) => {
				return match.toUpperCase();
			})
		);
	}
	toDotCase() {
		return new String(trim(this.$)
			.replace(/[\s\-_\.]+/g, '.')
			.replace(/[^\.]/g, (match) => {
				if (match.toLowerCase() !== match) {
					return '.' + match;
				}

				return match;
			})
			.replace(/\.+/g, '.')
			.replace(/^\./, '')
			.toLowerCase()
		);
	}
	toLowerCase() {
		return new String(this.$.toLowerCase());
	}
	toSnakeCase() {
		return new String(trim(this.$)
			.replace(/[\s\-_\.]+/g, '_')
			.replace(/[^_]/g, (match) => {
				if (match.toLowerCase() !== match) {
					return '_' + match;
				}

				return match;
			})
			.replace(/_+/g, '_')
			.replace(/^_/, '')
			.toLowerCase()
		);
	}
	toSpaceCase() {
		return new String(trim(this.$)
			.replace(/[\s\-_\.]+/g, ' ')
			.replace(/[\S]/g, (match) => {
				if (match.toLowerCase() !== match) {
					return ' ' + match;
				}

				return match;
			})
			.replace(/\s+/g, ' ')
			.replace(/^\s/, '')
			.toLowerCase()
		);
	}
	toSpinalCase() {
		return new String(trim(this.$)
			.replace(/[\s\-_\.]+/g, '-')
			.replace(/[^\-]/g, (match) => {
				if (match.toLowerCase() !== match) {
					return '-' + match;
				}

				return match;
			})
			.replace(/\-+/g, '-')
			.replace(/^\-/, '')
			.toLowerCase()
		);
	}
	toString() {
		return this.$;
	}
	toUpperCase() {
		return new String(this.$.toUpperCase());
	}
	trim() {
		return new String(this.$.replace(/^\s+|\s+$/g, ''));
	}
	trimLeft() {
		return new String(this.$.replace(/^\s+/, ''));
	}
	trimRight() {
		return new String(this.$.replace(/\s+$/, ''));
	}
  valueOf() {
    return this.$.toString().valueOf();
  }
}

function trim(string) {
	return string.replace(/^[\s\-_\.]+|[\s\-_\.]+$/g, '');
}

constructors[2].push({
	check: isString,
	cls: String
});

export default String;
<commit_msg>String: use String instead Str.<commit_after>import D from './D';
import Super from './Super';
import constructors from './constants/constructors';
import regexpSpecialCharacters from './constants/regexpSpecialCharacters';
import {
	isDateLike, isFunction, isNumberLike, isObject, isString,
	validate
} from './helpers';

const NativeString = global.String;
const htmlSpecials = {
	'&': '&',
	'<': '<',
	'>': '>'
};
const regexpSpecialsRegexp = new RegExp(new Super(regexpSpecialCharacters)
  .word((x) => '\\' + x + '|')
  .replace(/\|$/, ''), 'g'
);

export class String extends Super {
	constructor(string = '') {
		super(string);
	}

	capitalizeFirst() {
		const string = this.$;

		return new String(string[0].toUpperCase() + string.substring(1));
	}
	endsWith(string) {
		return this.revert().startsWith(new String(string).revert().$);
	}
	escapeHtml() {
		let string = this.$;

		for (const symbol in htmlSpecials) {
			if (htmlSpecials.hasOwnProperty(symbol)) {
				string = string.replace(new RegExp(symbol, 'g'), htmlSpecials[symbol]);
			}
		}

		return new String(string);
	}
	escapeRegExp() {
		return this.replace(regexpSpecialsRegexp, '\\$&');
	}
	in(object) {
		if (!isObject(object)) {
			return false;
		}

		return this.$ in object;
	}
	indexOf() {
		return this.$.indexOf.apply(this.$, arguments);
	}
  get length() {
    return this.$.length;
  }
	match() {
		const match = this.$.match.apply(this.$, arguments);

    return D(match);
	}
  parseJSON(options = {}, mapFn) {
    if (!arguments.length) {
      return D(JSON.parse(this.$));
    }

    if (isFunction(options)) {
      mapFn = options;
      options = {};
    }

    const { numbers, dates } = options;
    const parsed = JSON.parse(this.$, function (key, value) {
      if (dates && isDateLike(value) && !isNumberLike(value)) {
        value = new Date(value);
      } else if (numbers && isNumberLike(value) && isString(value)) {
        value = Number(value);
      }

      return mapFn ? mapFn.apply(this, arguments) : value;
    });

    return D(parsed);
  }
	repeat(n) {
		validate([n], [['intLike', '>=0']], 'String#repeat');

		n = Number(n);

		const string = this.$;

    let s = '';

		for (let i = 0; i < n; i++) {
			s += string;
		}

		return new String(s);
	}
	replace(regexp, replacer = '') {
		return new String(this.$.replace(regexp, replacer));
	}
	replaceString(string, replacer = '') {
		string = new Super(string).$;

		validate([string], ['string'], 'String#replaceString');

		return new String(this.$.split(string).join(replacer));
	}
	revert() {
		const string = this.$;
		let str = '';

		for (let i = string.length - 1; i >= 0; i--) {
			str += string[i];
		}

		return new String(str);
	}
  slice() {
    const string = this.$;

    return new String(string.slice.apply(string, arguments));
  }
	split(delimiter) {
		return D(this.$.split(delimiter));
	}
	startsWith(string) {
		return this.$.indexOf(string) === 0;
	}
	substr() {
		const string = this.$;

		return new String(string.substr.apply(string, arguments));
	}
  substring() {
    const string = this.$;

    return new String(string.substring.apply(string, arguments));
  }
  toCamelCase() {
		return new String(trim(this.$)
			.replace(/[\s\-_\.]+/g, '-')
			.replace(/\-[^\-]/g, (match) => {
				return match[1].toUpperCase();
			})
			.replace(/^[\S]/, (match) => {
				return match.toLowerCase();
			})
		);
	}
	toCapitalCase() {
		return new String(trim(this.$)
			.replace(/[\s\-_\.]+/g, ' ')
			.replace(/[\S]/g, (match) => {
				if (match.toLowerCase() !== match) {
					return ' ' + match;
				}

				return match;
			})
			.replace(/\s[\S]/g, (match) => {
				return match.toUpperCase();
			})
			.replace(/\s+/g, ' ')
			.replace(/^\s/, '')
			.replace(/^[\S]/, (match) => {
				return match.toUpperCase();
			})
		);
	}
	toDotCase() {
		return new String(trim(this.$)
			.replace(/[\s\-_\.]+/g, '.')
			.replace(/[^\.]/g, (match) => {
				if (match.toLowerCase() !== match) {
					return '.' + match;
				}

				return match;
			})
			.replace(/\.+/g, '.')
			.replace(/^\./, '')
			.toLowerCase()
		);
	}
	toLowerCase() {
		return new String(this.$.toLowerCase());
	}
	toSnakeCase() {
		return new String(trim(this.$)
			.replace(/[\s\-_\.]+/g, '_')
			.replace(/[^_]/g, (match) => {
				if (match.toLowerCase() !== match) {
					return '_' + match;
				}

				return match;
			})
			.replace(/_+/g, '_')
			.replace(/^_/, '')
			.toLowerCase()
		);
	}
	toSpaceCase() {
		return new String(trim(this.$)
			.replace(/[\s\-_\.]+/g, ' ')
			.replace(/[\S]/g, (match) => {
				if (match.toLowerCase() !== match) {
					return ' ' + match;
				}

				return match;
			})
			.replace(/\s+/g, ' ')
			.replace(/^\s/, '')
			.toLowerCase()
		);
	}
	toSpinalCase() {
		return new String(trim(this.$)
			.replace(/[\s\-_\.]+/g, '-')
			.replace(/[^\-]/g, (match) => {
				if (match.toLowerCase() !== match) {
					return '-' + match;
				}

				return match;
			})
			.replace(/\-+/g, '-')
			.replace(/^\-/, '')
			.toLowerCase()
		);
	}
	toString() {
		return this.$;
	}
	toUpperCase() {
		return new String(this.$.toUpperCase());
	}
	trim() {
		return new String(this.$.replace(/^\s+|\s+$/g, ''));
	}
	trimLeft() {
		return new String(this.$.replace(/^\s+/, ''));
	}
	trimRight() {
		return new String(this.$.replace(/\s+$/, ''));
	}
  valueOf() {
    return this.$.toString().valueOf();
  }
}

function trim(string) {
	return string.replace(/^[\s\-_\.]+|[\s\-_\.]+$/g, '');
}

constructors[2].push({
	check: isString,
	cls: String
});

export default String;
<|endoftext|>


<commit_before>require('dotenv').config();

const path = require('path');
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const validate = require('webpack-validator');

const PATHS = {
  src: path.join(__dirname, 'src'),
  dist: path.join(__dirname, 'dist'),
  img: path.join(__dirname, 'src/assets/images')
};

let dev_config = {
  entry: {
    app: PATHS.src
  },
  output: {
    path: PATHS.dist,
    publicPath: "/assets/",
    filename: '[name].js',
    sourceMapFilename: '[file].map',
    devtoolModuleFilenameTemplate: 'webpack:///[resource-path]?[loaders]'
  },
  devtool: 'eval-source-map',
  module: {
    loaders: [
      {
        test: /\.scss$/,
        loaders: ["style", "css?sourceMap", "sass?sourceMap"],
        include: PATHS.src
      },
      {
        test: /\.(jpg|png)$/,
        loader: 'url-loader?limit=100000',
        include: PATHS.img
      }
    ]
  },
  devServer: {
    contentBase: PATHS.dist,
    historyApiFallback: true,
    hot: true,
    inline: true,
    stats: {
      colors: true
    },
    host: process.env.HOST,
    port: process.env.PORT
  },
  plugins: [
    new HTMLWebpackPlugin({
      title: 'React Redux Scaffold'
    }),
    new webpack.HotModuleReplacementPlugin({
      multiStep: true
    })
  ]
};

module.exports = validate(dev_config, {
  quiet: true
});

<commit_msg>Add html template for html webpack plugin<commit_after>require('dotenv').config();

const path = require('path');
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const validate = require('webpack-validator');

const PATHS = {
  src: path.join(__dirname, 'src'),
  dist: path.join(__dirname, 'dist'),
  img: path.join(__dirname, 'src/assets/images')
};

let dev_config = {
  entry: {
    app: PATHS.src
  },
  output: {
    path: PATHS.dist,
    publicPath: "/assets/",
    filename: '[name].js',
    sourceMapFilename: '[file].map',
    devtoolModuleFilenameTemplate: 'webpack:///[resource-path]?[loaders]'
  },
  devtool: 'eval-source-map',
  module: {
    loaders: [
      {
        test: /\.scss$/,
        loaders: ["style", "css?sourceMap", "sass?sourceMap"],
        include: PATHS.src
      },
      {
        test: /\.(jpg|png)$/,
        loader: 'url-loader?limit=100000',
        include: PATHS.img
      }
    ]
  },
  devServer: {
    contentBase: PATHS.dist,
    historyApiFallback: true,
    hot: true,
    inline: true,
    stats: {
      colors: true
    },
    host: process.env.HOST,
    port: process.env.PORT
  },
  plugins: [
    new HTMLWebpackPlugin({
      title: 'React Redux Scaffold',
      template: './src/index.ejs'
    }),
    new webpack.HotModuleReplacementPlugin({
      multiStep: true
    })
  ]
};

module.exports = validate(dev_config, {
  quiet: true
});

<|endoftext|>


<commit_before>/**
 * Created by Konstantin Yakushin.
 * react-native-underline-tabbar
 */
// @flow
import React, { Component } from 'react';
import { Text, TouchableOpacity, View, Animated, ScrollView } from 'react-native';
import MatrixMath from 'react-native/Libraries/Utilities/MatrixMath';

import styles from './Styles';

function transformOrigin(matrix, origin) {
  const { x, y, z } = origin;

  const translate = MatrixMath.createIdentityMatrix();
  MatrixMath.reuseTranslate3dCommand(translate, x, y, z);
  MatrixMath.multiplyInto(matrix, translate, matrix);

  const untranslate = MatrixMath.createIdentityMatrix();
  MatrixMath.reuseTranslate3dCommand(untranslate, -x, -y, -z);
  MatrixMath.multiplyInto(matrix, matrix, untranslate);
}

function createTranslateXScaleX(scaleXFactor, x) {
  // prettier-ignore
  return [
    scaleXFactor, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    x, 0, 0, 1,
  ];
}

type TabType = {
  label: string,
  badge: string,
  badgeColor?: string,
};

type Props = {
  goToPage: Function,
  activeTab: number,
  tabs: TabType[],
  underlineColor: string,
  backgroundColor: string,
  activeTextColor: string,
  inactiveTextColor: string,
  tabBadgeColor: string,
  scrollValue: Animated.Value,
  scrollContainerStyle: Object,
  tabStyles: Object,
  tabMargin: number,
  style: Object,
  activeTabTextStyle: Object,
  tabBarTextStyle: Object,
  tabBarStyle: Object,
};

type State = {
  renderUnderline: boolean,
  tabScrollValue: number,
};

type LayoutType = {
  x: number,
  y: number,
  width: number,
  height: number,
};

type TabStateType = {
  [string | number]: LayoutType,
};

class TabBar extends Component<Props, State> {
  static defaultProps = {
    tabBarTextStyle: {},
    tabStyles: {
      tab: {},
    },
    scrollContainerStyle: {},
    style: {},
  };
  tabState: TabStateType = {};
  tabContainerLayout: LayoutType = {
    width: 0,
    height: 0,
    x: 0,
    y: 0,
  };
  scrollContainerLayout: LayoutType = {
    width: 0,
    height: 0,
    x: 0,
    y: 0,
  };
  underlineRef: ?any = null;
  scrollView: ?any = null;
  _animateListenedId: ?string = null;
  offsetCollection: ?Object = null;
  widthCollection: ?Object = null;
  scrollOffsetsCollection: ?Object = null;
  state = {
    renderUnderline: false,
    tabScrollValue: 0,
  };

  componentDidMount() {
    this._animateListenedId = this.props.scrollValue.addListener((event: { value: number }) => {
      const { value } = event;
      const dx = (this.offsetCollection && this.offsetCollection._interpolation(value)) || 0;
      const scaleX = (this.widthCollection && this.widthCollection._interpolation(value)) || 0;
      this.applyTransformToUnderline(this.underlineRef, scaleX, dx);
      if (this.scrollOffsetsCollection) {
        const scrollOffset =
          this.scrollOffsetsCollection && this.scrollOffsetsCollection._interpolation(value);
        if (this.scrollView) {
          this.scrollView.scrollTo({ x: scrollOffset, animated: false });
        }
      }
    });
  }

  componentWillUnmount() {
    if (this._animateListenedId) {
      this.props.scrollValue.removeListener(this._animateListenedId);
    }
  }

  measureTabsContainer = (event: Object) => {
    this.tabContainerLayout = event.nativeEvent.layout;
    this.checkMeasures();
  };

  onScrollContentSizeChange = (width: number, height: number) => {
    this.scrollContainerLayout = { width, height, x: 0, y: 0 };
    this.checkMeasures();
  };

  setUnderlineRef = (ref: any) => {
    this.underlineRef = ref;
  };

  applyTransformToUnderline(ref: any, scaleXFactor: number, dx: number) {
    const matrix = createTranslateXScaleX(scaleXFactor, dx);
    transformOrigin(matrix, { x: -0.5, y: 0, z: 0 });
    ref.setNativeProps({
      style: {
        transform: [
          {
            matrix,
          },
        ],
      },
    });
  }

  onTabLayout(event: Object, page: number) {
    const { x, y, width, height } = event.nativeEvent.layout;
    this.tabState[page] = { x, y, width, height };
    if (this.props.tabs.length === Object.keys(this.tabState).length) {
      this.setState({ renderUnderline: true }, () => {
        this.applyTransformToUnderline(
          this.underlineRef,
          this.tabState[0].width,
          this.tabState[0].x,
        );
        this.checkMeasures();
      });
    }
  }

  checkMeasures = () => {
    if (
      this.state.renderUnderline &&
      this.tabContainerLayout.width !== 0 &&
      this.scrollContainerLayout.width !== 0
    ) {
      this.calculateInterpolations();
    }
  };

  calculateInterpolations = () => {
    const inputRange = Object.keys(this.tabState);
    const outputRangeLeft = [];
    const outputRangeWidth = [];
    const tabContainerWidth = this.tabContainerLayout.width;
    const scrollWidth = this.scrollContainerLayout.width;
    const marginValue = 20;
    for (let i = 0, len = inputRange.length; i < len; i += 1) {
      const key = inputRange[i];
      outputRangeLeft.push(this.tabState[key].x);
      outputRangeWidth.push(this.tabState[key].width);
    }
    // $FlowFixMe
    this.offsetCollection = this.props.scrollValue.interpolate({
      inputRange, // $FlowFixMe
      outputRange: outputRangeLeft, // $FlowFixMe
    });
    // $FlowFixMe
    this.widthCollection = this.props.scrollValue.interpolate({
      inputRange, // $FlowFixMe
      outputRange: outputRangeWidth, // $FlowFixMe
    });
    if (scrollWidth <= tabContainerWidth) {
      return;
    }
    const outputRangeScroll = [];
    for (let i = 0, len = inputRange.length; i < len; i += 1) {
      if (i === 0) {
        outputRangeScroll.push(0);
        continue; // eslint-disable-line
      }
      const isLast = i === len - 1;
      const offset = outputRangeLeft[i];
      const tabWidth = outputRangeWidth[i];
      const nextTabWidth = outputRangeWidth[i + 1] || 0;
      let scrollOffset = offset;

      if (offset + tabWidth + nextTabWidth + 20 + 20 >= scrollWidth) {
        if (isLast) {
          scrollOffset = offset - (tabContainerWidth - (tabWidth + marginValue));
        } else {
          scrollOffset =
            offset -
            (tabContainerWidth - (tabWidth + marginValue) + (nextTabWidth + 2 * marginValue)) / 2;
        }
      } else {
        scrollOffset =
          offset -
          (tabContainerWidth - (tabWidth + marginValue) + (nextTabWidth + 2 * marginValue)) / 2;
        scrollOffset = scrollOffset >= 0 ? scrollOffset : 0;
      }
      outputRangeScroll.push(scrollOffset);
    }
    // $FlowFixMe
    this.scrollOffsetsCollection = this.props.scrollValue.interpolate({
      inputRange: [-1, ...inputRange], // $FlowFixMe
      outputRange: [-40, ...outputRangeScroll], // $FlowFixMe
    });
  };

  renderUnderline() {
    const tabUnderlineStyle = {
      position: 'absolute',
      backgroundColor: this.props.underlineColor || 'navy',
      height: 2,
      width: 1,
      bottom: 0,
      padding: 0,
    };

    return <Animated.View ref={this.setUnderlineRef} style={[tabUnderlineStyle]} />;
  }

  renderTab = (tab: TabType, page: number) => {
    const { activeTab, tabBadgeColor, activeTabTextStyle } = this.props;
    const { label, badge, badgeColor } = tab;
    const isTabActive = activeTab === page;
    const activeTextColor = this.props.activeTextColor || 'navy';
    const inactiveTextColor = this.props.inactiveTextColor || 'black';
    const textStyle = this.props.tabBarTextStyle;
    return (
      <TouchableOpacity
        style={[
          styles.tab,
          this.props.tabMargin && { marginLeft: this.props.tabMargin },
          this.props.tabStyles.tab,
        ]}
        key={page}
        onPress={() => this.props.goToPage(page)}
        onLayout={event => this.onTabLayout(event, page)}
      >
        <Text
          style={[
            {
              color: isTabActive ? activeTextColor : inactiveTextColor,
            },
            isTabActive && activeTabTextStyle,
            textStyle,
          ]}
        >
          {label}
        </Text>
        {badge != null &&
          +badge > 0 && (
            <View
              style={[
                styles.badgeBubble,
                this.props.tabStyles.badgeBubble,
                { backgroundColor: badgeColor || tabBadgeColor || activeTextColor },
              ]}
            >
              <Text style={[styles.badgeText, this.props.tabStyles.badgeText]}>{badge || 0}</Text>
            </View>
          )}
      </TouchableOpacity>
    );
  };

  render() {
    const {
      style,
      backgroundColor,
      tabBarStyle,
      tabMargin,
      scrollContainerStyle,
      tabs,
    } = this.props;
    return (
      <View
        style={[styles.tabs, { backgroundColor }, style, tabBarStyle]}
        onLayout={this.measureTabsContainer}
      >
        <ScrollView
          horizontal
          contentContainerStyle={[
            styles.scrollContainer,
            tabMargin && { paddingRight: tabMargin },
            scrollContainerStyle,
          ]}
          showsHorizontalScrollIndicator={false}
          onContentSizeChange={this.onScrollContentSizeChange}
          ref={node => (this.scrollView = node)}
          bounces={false}
          scrollEventThrottle={1}
        >
          {tabs.map(this.renderTab)}
          {this.state.renderUnderline && this.renderUnderline()}
        </ScrollView>
      </View>
    );
  }
}

export default TabBar;
<commit_msg>minor improvement<commit_after>/**
 * Created by Konstantin Yakushin.
 * react-native-underline-tabbar
 */
// @flow
import React, { Component } from 'react';
import { Text, TouchableOpacity, View, Animated, ScrollView } from 'react-native';
import MatrixMath from 'react-native/Libraries/Utilities/MatrixMath';

import styles from './Styles';

function transformOrigin(matrix, origin) {
  const { x, y, z } = origin;

  const translate = MatrixMath.createIdentityMatrix();
  MatrixMath.reuseTranslate3dCommand(translate, x, y, z);
  MatrixMath.multiplyInto(matrix, translate, matrix);

  const untranslate = MatrixMath.createIdentityMatrix();
  MatrixMath.reuseTranslate3dCommand(untranslate, -x, -y, -z);
  MatrixMath.multiplyInto(matrix, matrix, untranslate);
}

function createTranslateXScaleX(scaleXFactor, x) {
  // prettier-ignore
  return [
    scaleXFactor, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    x, 0, 0, 1,
  ];
}

type TabType = {
  label: string,
  badge: string,
  badgeColor?: string,
};

type Props = {
  goToPage: Function,
  activeTab: number,
  tabs: TabType[],
  underlineColor: string,
  backgroundColor: string,
  activeTextColor: string,
  inactiveTextColor: string,
  tabBadgeColor: string,
  scrollValue: Animated.Value,
  scrollContainerStyle: Object,
  tabStyles: Object,
  tabMargin: number,
  style: Object,
  activeTabTextStyle: Object,
  tabBarTextStyle: Object,
  tabBarStyle: Object,
};

type State = {
  renderUnderline: boolean,
  tabScrollValue: number,
};

type LayoutType = {
  x: number,
  y: number,
  width: number,
  height: number,
};

type TabStateType = {
  [string | number]: LayoutType,
};

class TabBar extends Component<Props, State> {
  static defaultProps = {
    tabBarTextStyle: {},
    tabStyles: {
      tab: {},
    },
    scrollContainerStyle: {},
    style: {},
  };
  tabState: TabStateType = {};
  tabContainerLayout: LayoutType = {
    width: 0,
    height: 0,
    x: 0,
    y: 0,
  };
  scrollContainerLayout: LayoutType = {
    width: 0,
    height: 0,
    x: 0,
    y: 0,
  };
  underlineRef: ?any = null;
  scrollView: ?any = null;
  _animateListenedId: ?string = null;
  offsetCollection: ?Object = null;
  widthCollection: ?Object = null;
  scrollOffsetsCollection: ?Object = null;
  state = {
    renderUnderline: false,
    tabScrollValue: 0,
  };

  componentDidMount() {
    this._animateListenedId = this.props.scrollValue.addListener((event: { value: number }) => {
      const { value } = event;
      const dx = (this.offsetCollection && this.offsetCollection._interpolation(value)) || 0;
      const scaleX = (this.widthCollection && this.widthCollection._interpolation(value)) || 0;
      this.applyTransformToUnderline(this.underlineRef, scaleX, dx);
      if (this.scrollOffsetsCollection) {
        const scrollOffset =
          this.scrollOffsetsCollection && this.scrollOffsetsCollection._interpolation(value);
        if (this.scrollView) {
          this.scrollView.scrollTo({ x: scrollOffset, animated: false });
        }
      }
    });
  }

  componentWillUnmount() {
    if (this._animateListenedId) {
      this.props.scrollValue.removeListener(this._animateListenedId);
    }
  }

  measureTabsContainer = (event: Object) => {
    this.tabContainerLayout = event.nativeEvent.layout;
    this.checkMeasures();
  };

  onScrollContentSizeChange = (width: number, height: number) => {
    this.scrollContainerLayout = { width, height, x: 0, y: 0 };
    this.checkMeasures();
  };

  setUnderlineRef = (ref: any) => {
    this.underlineRef = ref;
  };

  applyTransformToUnderline(ref: any, scaleXFactor: number, dx: number) {
    const matrix = createTranslateXScaleX(scaleXFactor, dx);
    transformOrigin(matrix, { x: -0.5, y: 0, z: 0 });
    ref.setNativeProps({
      style: {
        transform: [
          {
            matrix,
          },
        ],
      },
    });
  }

  onTabLayout(event: Object, page: number) {
    const { x, y, width, height } = event.nativeEvent.layout;
    this.tabState[page] = { x, y, width, height };
    if (this.props.tabs.length === Object.keys(this.tabState).length) {
      this.setState({ renderUnderline: true }, () => {
        this.applyTransformToUnderline(
          this.underlineRef,
          this.tabState[0].width,
          this.tabState[0].x,
        );
        this.checkMeasures();
      });
    }
  }

  checkMeasures = () => {
    if (
      this.state.renderUnderline &&
      this.tabContainerLayout.width !== 0 &&
      this.scrollContainerLayout.width !== 0
    ) {
      this.calculateInterpolations();
    }
  };

  calculateInterpolations = () => {
    const inputRange = Object.keys(this.tabState);
    const outputRangeLeft = [];
    const outputRangeWidth = [];
    const tabContainerWidth = this.tabContainerLayout.width;
    const scrollWidth = this.scrollContainerLayout.width;
    const marginValue = 20;
    for (let i = 0, len = inputRange.length; i < len; i += 1) {
      const key = inputRange[i];
      outputRangeLeft.push(this.tabState[key].x);
      outputRangeWidth.push(this.tabState[key].width);
    }
    // $FlowFixMe
    this.offsetCollection = this.props.scrollValue.interpolate({
      inputRange, // $FlowFixMe
      outputRange: outputRangeLeft, // $FlowFixMe
    });
    // $FlowFixMe
    this.widthCollection = this.props.scrollValue.interpolate({
      inputRange, // $FlowFixMe
      outputRange: outputRangeWidth, // $FlowFixMe
    });
    if (scrollWidth <= tabContainerWidth) {
      return;
    }
    const outputRangeScroll = [];
    for (let i = 0, len = inputRange.length; i < len; i += 1) {
      if (i === 0) {
        outputRangeScroll.push(0);
        continue; // eslint-disable-line
      }
      const isLast = i === len - 1;
      const offset = outputRangeLeft[i];
      const tabWidth = outputRangeWidth[i];
      const nextTabWidth = outputRangeWidth[i + 1] || 0;
      let scrollOffset = offset;

      if (offset + tabWidth + nextTabWidth + 20 + 20 >= scrollWidth) {
        if (isLast) {
          scrollOffset = offset - (tabContainerWidth - (tabWidth + marginValue));
        } else {
          scrollOffset =
            offset -
            (tabContainerWidth - (tabWidth + marginValue) + (nextTabWidth + 2 * marginValue)) / 2;
        }
      } else {
        scrollOffset =
          offset -
          (tabContainerWidth - (tabWidth + marginValue) + (nextTabWidth + 2 * marginValue)) / 2;
        scrollOffset = scrollOffset >= 0 ? scrollOffset : 0;
      }
      outputRangeScroll.push(scrollOffset);
    }
    // $FlowFixMe
    this.scrollOffsetsCollection = this.props.scrollValue.interpolate({
      inputRange: [-1, ...inputRange], // $FlowFixMe
      outputRange: [-40, ...outputRangeScroll], // $FlowFixMe
    });
  };

  renderUnderline() {
    const tabUnderlineStyle = {
      position: 'absolute',
      backgroundColor: this.props.underlineColor || 'navy',
      height: 2,
      width: 1,
      bottom: 0,
      padding: 0,
    };

    return <Animated.View ref={this.setUnderlineRef} style={[tabUnderlineStyle]} />;
  }

  renderTab = (tab: TabType, page: number) => {
    const { activeTab, tabBadgeColor, activeTabTextStyle } = this.props;
    const { label, badge, badgeColor } = tab;
    const isTabActive = activeTab === page;
    const activeTextColor = this.props.activeTextColor || 'navy';
    const inactiveTextColor = this.props.inactiveTextColor || 'black';
    const textStyle = this.props.tabBarTextStyle;
    return (
      <TouchableOpacity
        style={[
          styles.tab,
          this.props.tabMargin && { marginLeft: this.props.tabMargin },
          this.props.tabStyles.tab,
        ]}
        key={page}
        onPress={() => this.props.goToPage(page)}
        onLayout={event => this.onTabLayout(event, page)}
      >
        <Text
          style={[
            {
              color: isTabActive ? activeTextColor : inactiveTextColor,
            },
            isTabActive && activeTabTextStyle,
            textStyle,
          ]}
        >
          {label}
        </Text>
        {badge != null &&
          +badge > 0 && (
            <View
              style={[
                styles.badgeBubble,
                this.props.tabStyles.badgeBubble,
                { backgroundColor: badgeColor || tabBadgeColor || activeTextColor },
              ]}
            >
              <Text style={[styles.badgeText, this.props.tabStyles.badgeText]}>{badge}</Text>
            </View>
          )}
      </TouchableOpacity>
    );
  };

  render() {
    const {
      style,
      backgroundColor,
      tabBarStyle,
      tabMargin,
      scrollContainerStyle,
      tabs,
    } = this.props;
    return (
      <View
        style={[styles.tabs, { backgroundColor }, style, tabBarStyle]}
        onLayout={this.measureTabsContainer}
      >
        <ScrollView
          horizontal
          contentContainerStyle={[
            styles.scrollContainer,
            tabMargin && { paddingRight: tabMargin },
            scrollContainerStyle,
          ]}
          showsHorizontalScrollIndicator={false}
          onContentSizeChange={this.onScrollContentSizeChange}
          ref={node => (this.scrollView = node)}
          bounces={false}
          scrollEventThrottle={1}
        >
          {tabs.map(this.renderTab)}
          {this.state.renderUnderline && this.renderUnderline()}
        </ScrollView>
      </View>
    );
  }
}

export default TabBar;
<|endoftext|>


<commit_before>const { mergeWithRules } = require("webpack-merge");
const path = require("path");
const sveltePreprocess = require("svelte-preprocess");
const SveltePreRenderPlugin = require("./webpack/svelte-pre-render-plugin");

const common = require("./webpack.common.js");

module.exports = mergeWithRules({
  module: {
    rules: {
      test: "match",
      type: "replace",
      use: "replace",
    },
  },
})(common, {
  entry: {
    contribute: "./svelte/contribute/Contribute",
  },
  plugins: [
    new SveltePreRenderPlugin({
      "contribute.js": [
        "/contribute",
        "/contribute/forum",
        "/contribute/kb",
        "/contribute/social",
      ],
    }),
  ],
  mode: "production",
  module: {
    rules: [
      {
        test: /\.svelte$/,
        use: {
          loader: "svelte-loader",
          options: {
            emitCss: false,
            preprocess: sveltePreprocess(),
            compilerOptions: {
              generate: "ssr",
              hydratable: true,
            },
          },
        },
      },
      {
        test: /\.(svg|png|gif|woff2?)$/,
        type: "asset/source",
        use: {
          loader: path.resolve("./webpack/ssr-asset-loader"),
        },
      },
    ],
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist/pre-render"),
    library: {
      type: "commonjs",
    },
  },
  target: "node",
});
<commit_msg>pre-render l10n and play-store pages as well<commit_after>const { mergeWithRules } = require("webpack-merge");
const path = require("path");
const sveltePreprocess = require("svelte-preprocess");
const SveltePreRenderPlugin = require("./webpack/svelte-pre-render-plugin");

const common = require("./webpack.common.js");

module.exports = mergeWithRules({
  module: {
    rules: {
      test: "match",
      type: "replace",
      use: "replace",
    },
  },
})(common, {
  entry: {
    contribute: "./svelte/contribute/Contribute",
  },
  plugins: [
    new SveltePreRenderPlugin({
      "contribute.js": [
        "/contribute",
        "/contribute/forum",
        "/contribute/kb",
        "/contribute/social",
        "/contribute/l10n",
        "/contribute/play-store",
      ],
    }),
  ],
  mode: "production",
  module: {
    rules: [
      {
        test: /\.svelte$/,
        use: {
          loader: "svelte-loader",
          options: {
            emitCss: false,
            preprocess: sveltePreprocess(),
            compilerOptions: {
              generate: "ssr",
              hydratable: true,
            },
          },
        },
      },
      {
        test: /\.(svg|png|gif|woff2?)$/,
        type: "asset/source",
        use: {
          loader: path.resolve("./webpack/ssr-asset-loader"),
        },
      },
    ],
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist/pre-render"),
    library: {
      type: "commonjs",
    },
  },
  target: "node",
});
<|endoftext|>


<commit_before><commit_msg>Removed useless file<commit_after><|endoftext|>


<commit_before>var dgram = require('dgram');

var Artnet = function (config) {

    if (!(this instanceof Artnet)) return new Artnet(config);

    var that = this;

    config = config || {};

    var host =     config.host                    || '255.255.255.255';
    var port =     parseInt(config.port)          || 6454;
    var refresh =  parseInt(config.refresh)       || 4000;

    var socket = dgram.createSocket("udp4");

    if (config.iface) {
        socket.bind(port, config.iface);
    }

    // index of the following arrays is the universe
    var data =          [];     // the 512 dmx channels
    var interval =      [];     // the intervals for the 4sec refresh
    var sendThrottle =  [];     // the timeouts
    var sendDelayed =   [];     // boolean flag indicating if data should be sent after sendThrottle timeout
    var dataChanged =   [];     // the highest channel number that had a change. mind that channel counting starts at 1!

    var startRefresh = function (universe) {
        interval[universe] = setInterval(function () {
            that.send(universe, 512);
        }, refresh);
    };

    // see http://www.artisticlicence.com/WebSiteMaster/User%20Guides/art-net.pdf page 45
    var artdmxPackage = function (universe, length) {

        length = parseInt(length, 10) || 2;
        if (length % 2) length += 1;

        var hUni = (universe >> 8) & 0xff;
        var lUni = universe & 0xff;

        var hLen = (length >> 8) & 0xff;
        var lLen = (length & 0xff);

        var header =   [65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 0, 0, lUni, hUni, hLen, lLen];

        if (!data[universe]) data[universe] = Array.apply(null, new Array(512)).map(function () { return null; }, 0);
        return new Buffer(header.concat(data[universe].slice(0, (hLen * 256) + lLen)));

    };

    // if refresh is set to true all 512 channels will be sent, otherwise from channel 1 to the last changed channel
    this.send = function (universe, refresh, callback) {
        if (typeof refresh === 'function') {
            callback = refresh;
            refresh = false;
        }

        // DEBUG
        refresh = true;

        if (!interval[universe]) startRefresh(universe);

        if (sendThrottle[universe]) {
            sendDelayed[universe] = true;
            return;
        }

        clearTimeout(sendThrottle[universe]);
        sendThrottle[universe] = setTimeout(function () {
            sendThrottle[universe] = null;
            if (sendDelayed[universe]) {
                sendDelayed[universe] = false;
                that.send(universe, callback);
            }
        }, 25);

        var buf = artdmxPackage(universe, refresh ? 512 : dataChanged[universe]);
        dataChanged[universe] = 0;
        socket.send(buf, 0, buf.length, port, host, callback);
    };

    /* [ [ uint15 universe, ] uint9 channel, ] uint8 value [, function callback ] */
    /* [ [ uint15 universe, ] uint9 channel, ] array[uint8] values [, function callback ] */
    this.set = function () {

        var universe;
        var channel;
        var value;
        var callback;

        if (arguments.length === 4) {
            universe =      arguments[0];
            channel =       arguments[1];
            value =         arguments[2];
            callback =      arguments[3];
        } else if (arguments.length === 3) {
            if (typeof arguments[2] === 'function') {
                channel =   arguments[0];
                value =     arguments[1];
                callback =  arguments[2];
            } else {
                universe =  arguments[0];
                channel =   arguments[1];
                value =     arguments[2];
            }
        } else if (arguments.length === 2) {
            if (typeof arguments[1] === 'function') {
                channel =   1;
                value =     arguments[0];
                callback =  arguments[1];
            } else {
                channel =   arguments[0];
                value =     arguments[1];
            }
        } else if (arguments.length === 1) {
            channel =       1;
            value =         arguments[0];
        } else {
            return false;
        }

        universe = parseInt(universe, 10) || 0;

        //console.log('set universe=' + universe, 'channel=' + channel, 'value=' + value, 'typeof callback=' + typeof callback);

        if (!data[universe]) data[universe] = Array.apply(null, new Array(512)).map(function () { return null; }, 0);

        dataChanged[universe] = dataChanged[universe] || 0;

        var index;
        if (typeof value === 'object' && value.length) {
            for (var i = 0; i < value.length; i++) {
                index = channel + i - 1;
                if (typeof value[i] === 'number' && data[universe][index] !== value[i]) {
                    data[universe][index] = value[i];
                    if ((index + 1) > dataChanged[universe]) dataChanged[universe] = index + 1;
                }
            }
        } else {
            if (typeof value === 'number' && data[universe][channel - 1] !== value) {
                data[universe][channel - 1] = value;
                if (channel > dataChanged[universe]) dataChanged[universe] = channel;
            }
        }

        if (dataChanged[universe]) {
            that.send(universe, callback);
        } else {
            if (typeof callback === 'function') callback(null, null);
        }

        return true;
    };

    this.close = function () {
        for (var i = 0; i < interval.length; i++)
        clearInterval(interval[i]);
        socket.close();
    };

    this.setHost = function (h) {
        host = h;
    };

};

module.exports = Artnet;
<commit_msg>Added sendAll as config parameter<commit_after>var dgram = require('dgram');

var Artnet = function (config) {

    if (!(this instanceof Artnet)) return new Artnet(config);

    var that = this;

    config = config || {};

    var host =     config.host                    || '255.255.255.255';
    var port =     parseInt(config.port)          || 6454;
    var refresh =  parseInt(config.refresh)       || 4000;
    var sendAll =  config.sendAll                 || 0;

    var socket = dgram.createSocket("udp4");

    if (config.iface) {
        socket.bind(port, config.iface);
    }

    // index of the following arrays is the universe
    var data =          [];     // the 512 dmx channels
    var interval =      [];     // the intervals for the 4sec refresh
    var sendThrottle =  [];     // the timeouts
    var sendDelayed =   [];     // boolean flag indicating if data should be sent after sendThrottle timeout
    var dataChanged =   [];     // the highest channel number that had a change. mind that channel counting starts at 1!

    var startRefresh = function (universe) {
        interval[universe] = setInterval(function () {
            that.send(universe, 512);
        }, refresh);
    };

    // see http://www.artisticlicence.com/WebSiteMaster/User%20Guides/art-net.pdf page 45
    var artdmxPackage = function (universe, length) {

        length = parseInt(length, 10) || 2;
        if (length % 2) length += 1;

        var hUni = (universe >> 8) & 0xff;
        var lUni = universe & 0xff;

        var hLen = (length >> 8) & 0xff;
        var lLen = (length & 0xff);

        var header =   [65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 0, 0, lUni, hUni, hLen, lLen];

        if (!data[universe]) data[universe] = Array.apply(null, new Array(512)).map(function () { return null; }, 0);
        return new Buffer(header.concat(data[universe].slice(0, (hLen * 256) + lLen)));

    };

    // if refresh is set to true all 512 channels will be sent, otherwise from channel 1 to the last changed channel
    this.send = function (universe, refresh, callback) {
        if (typeof refresh === 'function') {
            callback = refresh;
            refresh = false;
        }

        if(sendAll) refresh = true;

        if (!interval[universe]) startRefresh(universe);

        if (sendThrottle[universe]) {
            sendDelayed[universe] = true;
            return;
        }

        clearTimeout(sendThrottle[universe]);
        sendThrottle[universe] = setTimeout(function () {
            sendThrottle[universe] = null;
            if (sendDelayed[universe]) {
                sendDelayed[universe] = false;
                that.send(universe, callback);
            }
        }, 25);

        var buf = artdmxPackage(universe, refresh ? 512 : dataChanged[universe]);
        dataChanged[universe] = 0;
        socket.send(buf, 0, buf.length, port, host, callback);
    };

    /* [ [ uint15 universe, ] uint9 channel, ] uint8 value [, function callback ] */
    /* [ [ uint15 universe, ] uint9 channel, ] array[uint8] values [, function callback ] */
    this.set = function () {

        var universe;
        var channel;
        var value;
        var callback;

        if (arguments.length === 4) {
            universe =      arguments[0];
            channel =       arguments[1];
            value =         arguments[2];
            callback =      arguments[3];
        } else if (arguments.length === 3) {
            if (typeof arguments[2] === 'function') {
                channel =   arguments[0];
                value =     arguments[1];
                callback =  arguments[2];
            } else {
                universe =  arguments[0];
                channel =   arguments[1];
                value =     arguments[2];
            }
        } else if (arguments.length === 2) {
            if (typeof arguments[1] === 'function') {
                channel =   1;
                value =     arguments[0];
                callback =  arguments[1];
            } else {
                channel =   arguments[0];
                value =     arguments[1];
            }
        } else if (arguments.length === 1) {
            channel =       1;
            value =         arguments[0];
        } else {
            return false;
        }

        universe = parseInt(universe, 10) || 0;

        //console.log('set universe=' + universe, 'channel=' + channel, 'value=' + value, 'typeof callback=' + typeof callback);

        if (!data[universe]) data[universe] = Array.apply(null, new Array(512)).map(function () { return null; }, 0);

        dataChanged[universe] = dataChanged[universe] || 0;

        var index;
        if (typeof value === 'object' && value.length) {
            for (var i = 0; i < value.length; i++) {
                index = channel + i - 1;
                if (typeof value[i] === 'number' && data[universe][index] !== value[i]) {
                    data[universe][index] = value[i];
                    if ((index + 1) > dataChanged[universe]) dataChanged[universe] = index + 1;
                }
            }
        } else {
            if (typeof value === 'number' && data[universe][channel - 1] !== value) {
                data[universe][channel - 1] = value;
                if (channel > dataChanged[universe]) dataChanged[universe] = channel;
            }
        }

        if (dataChanged[universe]) {
            that.send(universe, callback);
        } else {
            if (typeof callback === 'function') callback(null, null);
        }

        return true;
    };

    this.close = function () {
        for (var i = 0; i < interval.length; i++)
        clearInterval(interval[i]);
        socket.close();
    };

    this.setHost = function (h) {
        host = h;
    };

};

module.exports = Artnet;
<|endoftext|>


<commit_before>$(document).ready(function(){
	multipleComboSelect();
	hoverRowsColors();
	bindFancyBox();
	flashClick();
	toclone();
	bindRichEditor();
	checkMultiple();
	$('select').jDoubleSelect();
	filterCheckbox();
});

function flashClick() {
	$('#flashMessage a').click(function(e){
		e.stopPropagation();
		return true;
	});

	$('#flashMessage').click(function(){
		$(this).fadeOut();
	})
}

function hoverRowsColors() {
	$('tr.list').hover(function() {
		$(this).addClass('hover');
	},
	function() {
		$(this).removeClass('hover');
	});
}

function multipleComboSelect() {
	$('.combo-select').comboselect({ sort: 'none', addbtn: '»',  rembtn: '«' });
}

function bindFancyBox() {
	$('a.brw-image').fancybox({'titlePosition': 'inside'});
	$('a[target=modal]').fancybox({'titleShow': false});
}

function toclone() {
	$('.hide').css('display', 'none');
	$('.cloneLink').click(function(){
		parts = $(this).attr('id').split('_');
		var i = parts[1];
		$('#fieldset' + i).clone().css('display', 'none').removeClass('hide').appendTo('#cloneHoder' + i).fadeIn();
		bindRemove();
		return false;
	});
}

function bindRemove() {
	$('.cloneRemove').click(function(){
		$(this).parents('div.fieldsetUploads').fadeOut('fast', function() {
			$(this).remove();
		});
		return false;
	});
}

function bindRichEditor() {
	if (typeof jQuery.fn.tinymce == 'function') {
		bindTinyMCE();
	} else if (typeof FCKeditor == 'function') {
		bindFckEditor();
	}
}

function bindTinyMCE() {
	$('textarea.richEditor').tinymce({
		script_url : APP_BASE + 'js/tiny_mce/tiny_mce.js',
		theme: 'advanced',
		plugins: 'contextmenu,paste,table,inlinepopups',
		theme_advanced_buttons1 : "bold,italic,underline,strikethrough,link,unlink,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,blockquote,|,undo,redo,|,code,removeformat,forecolor,table",
		skin : "o2k7",
		skin_variant : "silver",
		theme_advanced_buttons2: '',
		theme_advanced_toolbar_location : "top",
		theme_advanced_toolbar_align : "left",
		theme_advanced_statusbar_location : "bottom",
		theme_advanced_resizing : true,
		paste_auto_cleanup_on_paste: true,
		content_css: APP_BASE + 'brownie/css/tinymce.css'
	});
}

function bindFckEditor(id) {
	$('textarea.richEditor').each(function(){
		id = $(this).attr('id');
		oFCKeditor = new FCKeditor(id);
		oFCKeditor.BasePath = APP_BASE + 'js/fckeditor/';
		oFCKeditor.Config['CustomConfigurationsPath'] = APP_BASE + 'brownie/js/fckconfig.js';
		oFCKeditor.ToolbarSet = "Brownie";
		oFCKeditor.ReplaceTextarea();
	})
}

function checkMultiple() {
	$('td.delete_multiple input[type=checkbox]').change(function(){
		if ($(this).is(':checked')) {
			$(this).parents('tr').addClass('checked');
		} else {
			$(this).parents('tr').removeClass('checked');
			$('#deleteCheckAll').attr('checked', false);
		}
	});

	$('#deleteCheckAll').change(function(){
		var mustBeChecked = $(this).is(':checked');
		$('td.delete_multiple input[type=checkbox]').each(function(){
			if (mustBeChecked) {
				$(this).attr('checked', true);
			} else {
				$(this).attr('checked', false);
			}
			$(this).change();
		});
	}).css('visibility', 'visible');

	$('form#deleteMultiple tr').click(function(e){
		if (e.target.type == "checkbox") {
			e.stopPropagation();
		} else {
			$checkbox = $(this).find(':checkbox');
			$checkbox.attr('checked', !$checkbox.attr('checked'));
			$checkbox.change();
		};
	});

	$('#deleteMultiple').submit(function(){
		var allowSubmit = false;
		$('td.delete_multiple input[type=checkbox]').each(function(){
			if ($(this).is(':checked')) {
				allowSubmit = true;
				return;
			}
		});
		if (!allowSubmit) {
			alert(brwMsg.no_checked_for_deletion);
		}
		return allowSubmit;
	});

	$('td.actions a').click(function(e){
		e.stopPropagation();
		return true;
	});
}

function filterCheckbox() {
	$('div.filter-checkbox div.checkbox').addClass('clearfix');
	$button = $('<input type="button" value="Elegir" class="filter-choose">');
	$div = $('div.filter-checkbox');
	$div.before($button).hide();
	$button.toggle(
		function(){
			$div.fadeIn('fast');
			$button.val(brwMsg.done);
		},
		function(){
			$div.fadeOut('fast');
			$button.val(brwMsg.choose);
		}
	);
}<commit_msg>translate multiple select filter button<commit_after>$(document).ready(function(){
	multipleComboSelect();
	hoverRowsColors();
	bindFancyBox();
	flashClick();
	toclone();
	bindRichEditor();
	checkMultiple();
	$('select').jDoubleSelect();
	filterCheckbox();
});

function flashClick() {
	$('#flashMessage a').click(function(e){
		e.stopPropagation();
		return true;
	});

	$('#flashMessage').click(function(){
		$(this).fadeOut();
	})
}

function hoverRowsColors() {
	$('tr.list').hover(function() {
		$(this).addClass('hover');
	},
	function() {
		$(this).removeClass('hover');
	});
}

function multipleComboSelect() {
	$('.combo-select').comboselect({ sort: 'none', addbtn: '»',  rembtn: '«' });
}

function bindFancyBox() {
	$('a.brw-image').fancybox({'titlePosition': 'inside'});
	$('a[target=modal]').fancybox({'titleShow': false});
}

function toclone() {
	$('.hide').css('display', 'none');
	$('.cloneLink').click(function(){
		parts = $(this).attr('id').split('_');
		var i = parts[1];
		$('#fieldset' + i).clone().css('display', 'none').removeClass('hide').appendTo('#cloneHoder' + i).fadeIn();
		bindRemove();
		return false;
	});
}

function bindRemove() {
	$('.cloneRemove').click(function(){
		$(this).parents('div.fieldsetUploads').fadeOut('fast', function() {
			$(this).remove();
		});
		return false;
	});
}

function bindRichEditor() {
	if (typeof jQuery.fn.tinymce == 'function') {
		bindTinyMCE();
	} else if (typeof FCKeditor == 'function') {
		bindFckEditor();
	}
}

function bindTinyMCE() {
	$('textarea.richEditor').tinymce({
		script_url : APP_BASE + 'js/tiny_mce/tiny_mce.js',
		theme: 'advanced',
		plugins: 'contextmenu,paste,table,inlinepopups',
		theme_advanced_buttons1 : "bold,italic,underline,strikethrough,link,unlink,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,blockquote,|,undo,redo,|,code,removeformat,forecolor,table",
		skin : "o2k7",
		skin_variant : "silver",
		theme_advanced_buttons2: '',
		theme_advanced_toolbar_location : "top",
		theme_advanced_toolbar_align : "left",
		theme_advanced_statusbar_location : "bottom",
		theme_advanced_resizing : true,
		paste_auto_cleanup_on_paste: true,
		content_css: APP_BASE + 'brownie/css/tinymce.css'
	});
}

function bindFckEditor(id) {
	$('textarea.richEditor').each(function(){
		id = $(this).attr('id');
		oFCKeditor = new FCKeditor(id);
		oFCKeditor.BasePath = APP_BASE + 'js/fckeditor/';
		oFCKeditor.Config['CustomConfigurationsPath'] = APP_BASE + 'brownie/js/fckconfig.js';
		oFCKeditor.ToolbarSet = "Brownie";
		oFCKeditor.ReplaceTextarea();
	})
}

function checkMultiple() {
	$('td.delete_multiple input[type=checkbox]').change(function(){
		if ($(this).is(':checked')) {
			$(this).parents('tr').addClass('checked');
		} else {
			$(this).parents('tr').removeClass('checked');
			$('#deleteCheckAll').attr('checked', false);
		}
	});

	$('#deleteCheckAll').change(function(){
		var mustBeChecked = $(this).is(':checked');
		$('td.delete_multiple input[type=checkbox]').each(function(){
			if (mustBeChecked) {
				$(this).attr('checked', true);
			} else {
				$(this).attr('checked', false);
			}
			$(this).change();
		});
	}).css('visibility', 'visible');

	$('form#deleteMultiple tr').click(function(e){
		if (e.target.type == "checkbox") {
			e.stopPropagation();
		} else {
			$checkbox = $(this).find(':checkbox');
			$checkbox.attr('checked', !$checkbox.attr('checked'));
			$checkbox.change();
		};
	});

	$('#deleteMultiple').submit(function(){
		var allowSubmit = false;
		$('td.delete_multiple input[type=checkbox]').each(function(){
			if ($(this).is(':checked')) {
				allowSubmit = true;
				return;
			}
		});
		if (!allowSubmit) {
			alert(brwMsg.no_checked_for_deletion);
		}
		return allowSubmit;
	});

	$('td.actions a').click(function(e){
		e.stopPropagation();
		return true;
	});
}

function filterCheckbox() {
	$('div.filter-checkbox div.checkbox').addClass('clearfix');
	$button = $('<input type="button" value="' + brwMsg.choose + '" class="filter-choose">');
	$div = $('div.filter-checkbox');
	$div.before($button).hide();
	$button.toggle(
		function(){
			$div.fadeIn('fast');
			$button.val(brwMsg.done);
		},
		function(){
			$div.fadeOut('fast');
			$button.val(brwMsg.choose);
		}
	);
}<|endoftext|>