<commit_before>'use strict';

var move = {

  somethingMoved: false,
  rows: null,
  right: function(tiles){

    this.rows =  _.groupBy(tiles, 'row');

    for ( var idx in this.rows ){

      var values = _.pluck(this.rows[idx], 'value');
      values = this.consolidate( _.filter(values, function(value){ return (value)}) );

      var i = 4;
      while(i>=0){
        this.rows[idx][i].value =  _(values).pop();
        i--;
      }

    }

    return this.reassemble(this.rows, tiles);

  },

  left: function(tiles){

    this.rows =  _.groupBy(tiles, 'row');

    for ( var idx in this.rows ){

      var values = _.pluck(this.rows[idx], 'value');
      values = this.consolidate( _.filter(values, function(value){ return (value)}).reverse() );

      var i = 0;
      while(i<5){
        this.rows[idx][i].value =  _(values).pop();
        i++;
      }

    }

    return this.reassemble(this.rows, tiles);

  },

  up: function(tiles){

    this.rows =  _.groupBy(tiles, 'column');

    for ( var idx in this.rows ) {

      var values = _.pluck(this.rows[idx], 'value');
      values = this.consolidate( _.filter(values, function (value) { return (value) }).reverse() );

      var i = 0;
      while (i < 5) {
        this.rows[idx][i].value = _(values).pop();
        i++;
      }
    }
    return this.reassemble(this.rows, tiles);
  },

  down: function(tiles){

    this.rows =  _.groupBy(tiles, 'column');

    for ( var idx in this.rows ){

      var values = _.pluck(this.rows[idx], 'value');
      values = this.consolidate( _.filter(values, function(value){ return (value)}) );

      var i = 4;
      while(i>=0){
        this.rows[idx][i].value =  _(values).pop();
        i--;
      }

    }

    return this.reassemble(this.rows, tiles);

  },

  reassemble: function(rows, tiles){

    var idx = 0;
    _.forEach(rows, function(row){
      _.forEach(row, function(cell){ tiles[idx] = cell; idx++; }, this);
    }, this);

    return tiles;
  },

  consolidate: function(values){

    if ( values.length < 2 ){
      return values;
    }
    for( var i in values ) {
      if ( values[i] == values[i*1+1] ){
        values[i*1+1] = values[i]*2;
        values[i] = '';
      }
    }
    return values;
  }

};

<commit_msg>Fixes the double combine bug<commit_after>'use strict';

var move = {

  somethingMoved: false,
  rows: null,
  right: function(tiles){

    this.rows =  _.groupBy(tiles, 'row');

    for ( var idx in this.rows ){

      var values = _.pluck(this.rows[idx], 'value');
      values = this.consolidate( _.filter(values, function(value){ return (value)}) );

      var i = 4;
      while(i>=0){
        this.rows[idx][i].value =  _(values).pop();
        i--;
      }

    }

    return this.reassemble(this.rows, tiles);

  },

  left: function(tiles){

    this.rows =  _.groupBy(tiles, 'row');

    for ( var idx in this.rows ){

      var values = _.pluck(this.rows[idx], 'value');
      values = this.consolidate( _.filter(values, function(value){ return (value)}).reverse() );

      var i = 0;
      while(i<5){
        this.rows[idx][i].value =  _(values).pop();
        i++;
      }

    }

    return this.reassemble(this.rows, tiles);

  },

  up: function(tiles){

    this.rows =  _.groupBy(tiles, 'column');

    for ( var idx in this.rows ) {

      var values = _.pluck(this.rows[idx], 'value');
      values = this.consolidate( _.filter(values, function (value) { return (value) }).reverse() );

      var i = 0;
      while (i < 5) {
        this.rows[idx][i].value = _(values).pop();
        i++;
      }
    }
    return this.reassemble(this.rows, tiles);
  },

  down: function(tiles){

    this.rows =  _.groupBy(tiles, 'column');

    for ( var idx in this.rows ){

      var values = _.pluck(this.rows[idx], 'value');
      values = this.consolidate( _.filter(values, function(value){ return (value)}) );

      var i = 4;
      while(i>=0){
        this.rows[idx][i].value =  _(values).pop();
        i--;
      }

    }

    return this.reassemble(this.rows, tiles);

  },

  reassemble: function(rows, tiles){

    var idx = 0;
    _.forEach(rows, function(row){
      _.forEach(row, function(cell){ tiles[idx] = cell; idx++; }, this);
    }, this);

    return tiles;
  },

  consolidate: function(values){

    if ( values.length < 2 ){
      return values;
    }

    var skip = null;

    for( var i in values ) {
      if ( i == skip ){
        skip = null;
        continue;
      }
      if ( values[i] == values[i*1+1] ){
        values[i*1+1] = values[i]*2;
        values[i] = '';
        skip = i*1+1;
      }

    }
    return values;
  }

};

<|endoftext|>


<commit_before>const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
    entry:  './src/index.js',
    output: {
        path: './build',
        filename: 'bundle.js'
    },
    module: {
        loaders: [
            {
                test:   /\.js/,
                loaders: ['babel-loader']
            },
            {
                test: /\.scss$/,
                loaders: ['style-loader', 'css-loader', 'sass-loader']
            }
        ]
    },
    plugins: [
        new webpack.optimize.UglifyJsPlugin(),
        new webpack.optimize.AggressiveMergingPlugin(),
        new CopyWebpackPlugin([
            { from: 'src/favicon.ico' }
        ])
    ]
};
<commit_msg>use production react in build<commit_after>const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
    entry:  './src/index.js',
    output: {
        path: './build',
        filename: 'bundle.js'
    },
    module: {
        loaders: [
            {
                test:   /\.js/,
                loaders: ['babel-loader']
            },
            {
                test: /\.scss$/,
                loaders: ['style-loader', 'css-loader', 'sass-loader']
            }
        ]
    },
    plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: JSON.stringify('production')
            }
        }),
        new webpack.optimize.UglifyJsPlugin(),
        new webpack.optimize.AggressiveMergingPlugin(),
        new CopyWebpackPlugin([
            { from: 'src/favicon.ico' }
        ])
    ]
};
<|endoftext|>


<commit_before>const AWS      = require('aws-sdk');
const Consumer = require('sqs-consumer');
const config   = require('./config');
const networks = require('./networks');
const logger   = require('bole')('social');

const sqs = Consumer.create({
	queueUrl: config('sqs').queueUrl,
	messageAttributeNames: ['Card'],
	handleMessage: handleMessage,
	sqs: new AWS.SQS({
		accessKeyId: config('sqs').accessKeyId,
		secretAccessKey: config('sqs').secretAccessKey,
		region: config('sqs').region,
		apiVersion: config('sqs').apiVersion
	}),
	batchSize: 1
});

sqs.on('error', (err) => {
	logger.error(err);
});

sqs.start();

function handleMessage(message, done) {
	logger.info('Received new message');

	let body = JSON.parse(message['Body']);
	let buffer = message.MessageAttributes.Card.BinaryValue;

	let date = new Date(body['date']);
	let time = ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);

	let magnitude = body['magnitude']['value'].toFixed(1);
	let uncertainty = body['magnitude']['uncertainty'];
	let type = body['magnitude']['type'];
	let city = body['city'];

	let text = `#terremoto alle ${time}\n\nEpicentro: ${city}\nMagnitudo: ${magnitude} ± ${uncertainty} (${type})`;

	let options = {
		origin: body['origin'],
		text: text,
		buffer: buffer,
		date: date
	};

	logger.info('Uploading to Twitter');

	networks.twitter.upload(options, (err) => {
		if (err) {
			logger.error(err);
			done(err);
			return;
		}

		logger.info('Done');
		logger.info('Uploading to Facebook');

		networks.facebook.upload(options, (err) => {
			if (err) {
				logger.error(err);
			}

			logger.info('Done');
			done();
		});
	});
}
<commit_msg>more logging<commit_after>const AWS      = require('aws-sdk');
const Consumer = require('sqs-consumer');
const config   = require('./config');
const networks = require('./networks');
const logger   = require('bole')('social');

const sqs = Consumer.create({
	queueUrl: config('sqs').queueUrl,
	messageAttributeNames: ['Card'],
	handleMessage: handleMessage,
	sqs: new AWS.SQS({
		accessKeyId: config('sqs').accessKeyId,
		secretAccessKey: config('sqs').secretAccessKey,
		region: config('sqs').region,
		apiVersion: config('sqs').apiVersion
	}),
	batchSize: 1
});

sqs.on('error', (err) => {
	logger.error(err);
});

sqs.start();

function handleMessage(message, done) {
	logger.info('Received new message');

	let body = JSON.parse(message['Body']);
	let buffer = message.MessageAttributes.Card.BinaryValue;

	logger.info('Event ', body);

	let date = new Date(body['date']);
	let time = ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);

	let magnitude = body['magnitude']['value'].toFixed(1);
	let uncertainty = body['magnitude']['uncertainty'];
	let type = body['magnitude']['type'];
	let city = body['city'];

	let text = `#terremoto alle ${time}\n\nEpicentro: ${city}\nMagnitudo: ${magnitude} ± ${uncertainty} (${type})`;

	let options = {
		origin: body['origin'],
		text: text,
		buffer: buffer,
		date: date
	};

	logger.info('Uploading to Twitter');

	networks.twitter.upload(options, (err) => {
		if (err) {
			logger.error(err);
			done(err);
			return;
		}

		logger.info('Done');
		logger.info('Uploading to Facebook');

		networks.facebook.upload(options, (err) => {
			if (err) {
				logger.error(err);
			}

			logger.info('Done');
			done();
		});
	});
}
<|endoftext|>


<commit_before>/* eslint-disable func-names */
'use strict';
const webpack = require('webpack');
const path = require('path');
const fs = require('fs');
const env = require('yargs').argv.mode;
const target = require('yargs').argv.target;
const UglifyPlugin = webpack.optimize.UglifyJsPlugin;
const CommonsChunkPlugin =  webpack.optimize.CommonsChunkPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
var BrowserSyncPlugin = require('browser-sync-webpack-plugin')
var nodeModulesDir = path.resolve(__dirname, '../node_modules');

const fileName = 'app';
const appName = 'conceptdictionary'

const plugins = [];
const nodeModules = {};

let outputFile;
let outputPath;

var configJson;
let appEntryPoint;
let localOwaFolder;

let devtool;

try{
	configJson = require('./config.json');
	appEntryPoint = configJson.APP_ENTRY_POINT;
	localOwaFolder = configJson.LOCAL_OWA_FOLDER;
} catch(err){
	appEntryPoint = "http://localhost:8080//openmrs//owa//conceptdictionary//index.html";
	localOwaFolder = `${__dirname}/dist/`;
}

/** Don't bundle dependencies for node module */
if (target === 'web') {
  outputFile = `${fileName}.bundle`;
} else if (target === 'node') {
  outputFile = fileName;

  fs.readdirSync('node_modules')
    .filter(x =>
      ['.bin'].indexOf(x) === -1
    )
    .forEach(mod => {
      nodeModules[mod] = `commonjs ${mod}`;
    });
}

/** Minify for production */
if (env === 'production') {
  plugins.push(new UglifyPlugin({
    output: {
      comments: false,
    },
    minimize: true,
    sourceMap: false,
    compress: {
        warnings: false
    }
  }));
  outputFile = `${outputFile}.min.js`;
  outputPath = `${__dirname}/dist/`;
  devtool = 'source-map';
} else if (env === 'dev') {
  outputFile = `${outputFile}.js`;
  outputPath = `${localOwaFolder}${appName}`;
  devtool = 'eval-source-map';
}

plugins.push(new BrowserSyncPlugin({
    host: 'localhost',
    port: 3000,
    proxy: {
    	target : appEntryPoint
    }
}));

plugins.push(new CommonsChunkPlugin("vendor", "vendor.bundle.js"));

plugins.push(new HtmlWebpackPlugin({
    template: './app/index.html',
    inject: 'body'
}));

var config = {
  entry: {
	  app : `${__dirname}/app/components/conceptDictionaryApp.module.js`,
	  vendor : [
		            'angular',
		            'angular-translate',
		            'angular-route',
		            'angular-translate-loader-static-files',
		            'openmrs-contrib-uicommons'
	            ]
  },
  devtool: devtool,
  target,
  output: {
    path: outputPath,
    filename: outputFile,
  },
  module: {
    loaders: [{
	    test: /\.jsx?$/,
	    loader: 'babel-loader',
	    exclude: /node_modules/,
	    query: {
	        presets: ['es2015'],
	        cacheDirectory : true
    }
    },{
	    test: /\.css$/,
	    loader: 'css'
	}, {
	    test: /\.(png|jpg|jpeg|gif|svg)$/,
	    loader: 'url'
	}, {
	    test: /\.html$/,
	    loader: 'raw'
	},{
	    test: /\.json$/,
	    loader: 'file?name=translation/[name].[ext]'
	},{
        test: /\.scss$/,
        loader: "style!css!sass?outputStyle=expanded&includePaths[]="
        		+ path.resolve(__dirname, "./node_modules/compass-mixins/lib")
      },
        {test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url'},
        {test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url'},
        {test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url'},
        {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url'},
        {test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'url'},],
  },
  resolve: {
    root: path.resolve('./src'),
    extensions: ['', '.js'],
  },
  plugins,
  externals: nodeModules,
};

module.exports = config;<commit_msg>RA 1106 unmangle and dedupe<commit_after>/* eslint-disable func-names */
'use strict';
const webpack = require('webpack');
const path = require('path');
const fs = require('fs');
const env = require('yargs').argv.mode;
const target = require('yargs').argv.target;

const UglifyPlugin = webpack.optimize.UglifyJsPlugin;
const CommonsChunkPlugin =  webpack.optimize.CommonsChunkPlugin
const DedupePlugin = webpack.optimize.DedupePlugin;

const HtmlWebpackPlugin = require('html-webpack-plugin');
var BrowserSyncPlugin = require('browser-sync-webpack-plugin')
var nodeModulesDir = path.resolve(__dirname, '../node_modules');

const fileName = 'app';
const appName = 'conceptdictionary'

const plugins = [];
const nodeModules = {};

let outputFile;
let outputPath;

var configJson;
let appEntryPoint;
let localOwaFolder;

let devtool;

try{
	configJson = require('./config.json');
	appEntryPoint = configJson.APP_ENTRY_POINT;
	localOwaFolder = configJson.LOCAL_OWA_FOLDER;
} catch(err){
	appEntryPoint = "http://localhost:8080//openmrs//owa//conceptdictionary//index.html";
	localOwaFolder = `${__dirname}/dist/`;
}

/** Don't bundle dependencies for node module */
if (target === 'web') {
  outputFile = `${fileName}.bundle`;
} else if (target === 'node') {
  outputFile = fileName;

  fs.readdirSync('node_modules')
    .filter(x =>
      ['.bin'].indexOf(x) === -1
    )
    .forEach(mod => {
      nodeModules[mod] = `commonjs ${mod}`;
    });
}

/** Minify for production */
if (env === 'production') {
  plugins.push(new UglifyPlugin({
    output: {
      comments: false,
    },
    mangle: false,
    minimize: true,
    sourceMap: false,
    compress: {
        warnings: false
    }
  }));
  plugins.push(new DedupePlugin());
  outputFile = `${outputFile}.min.js`;
  outputPath = `${__dirname}/dist/`;
  devtool = 'source-map';
} else if (env === 'dev') {
  outputFile = `${outputFile}.js`;
  outputPath = `${localOwaFolder}${appName}`;
  devtool = 'eval-source-map';
}

plugins.push(new BrowserSyncPlugin({
    host: 'localhost',
    port: 3000,
    proxy: {
    	target : appEntryPoint
    }
}));

plugins.push(new CommonsChunkPlugin("vendor", "vendor.bundle.js"));

plugins.push(new HtmlWebpackPlugin({
    template: './app/index.html',
    inject: 'body'
}));

var config = {
  entry: {
	  app : `${__dirname}/app/components/conceptDictionaryApp.module.js`,
	  vendor : [
		            'angular',
		            'angular-translate',
		            'angular-route',
		            'angular-translate-loader-static-files',
		            'openmrs-contrib-uicommons'
	            ]
  },
  devtool: devtool,
  target,
  output: {
    path: outputPath,
    filename: outputFile,
  },
  module: {
    loaders: [{
	    test: /\.jsx?$/,
	    loader: 'babel-loader',
	    exclude: /node_modules/,
	    query: {
	        presets: ['es2015'],
	        cacheDirectory : true
    }
    },{
	    test: /\.css$/,
	    loader: 'css'
	}, {
	    test: /\.(png|jpg|jpeg|gif|svg)$/,
	    loader: 'url'
	}, {
	    test: /\.html$/,
	    loader: 'raw'
	},{
	    test: /\.json$/,
	    loader: 'file?name=translation/[name].[ext]'
	},{
        test: /\.scss$/,
        loader: "style!css!sass?outputStyle=expanded&includePaths[]="
        		+ path.resolve(__dirname, "./node_modules/compass-mixins/lib")
      },
        {test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url'},
        {test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url'},
        {test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url'},
        {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url'},
        {test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'url'},],
  },
  resolve: {
    root: path.resolve('./src'),
    extensions: ['', '.js'],
  },
  plugins,
  externals: nodeModules,
};

module.exports = config;<|endoftext|>


<commit_before>//var http = require('http');
var websocket = require('websocket-stream');
var http = require('flowhttp');
var sockets = {};

// TODO parse http requests and websocket messages
// TODO enable per-message-compression (Sec-WebSocket-Extensions: permessage-deflate)

exports.request = function (instance, eventName, endHandler) {

    // get instance
    // get even name
    // get request type
    var request;
    switch (eventName[0]) {
      case '/':

        /*
        var opts = {
            method: 'GET',
            path: '/' + instance._name + ':' + eventName.substr(1)
            headers: {},
            host: window.location.host,
            port: window.location.port
            responseType: 'response type to set on the underlying xhr object'
        };
        */

        // pipe http to flow event stream
        request = http[endHandler ? 'post' : 'post']('/' + instance._name + ':' + eventName.substr(1));

        // collect all data for a classic request callback
        if (endHandler) {
            var body = '';
            var error;
            request.on('response', function (res) {
                if (res.statusCode !== 200) {
                    error = true;
                }
            })
            request.on('data', function (chunk) {
                body += chunk;
            })
            .on('error', function (err) {
                body = err;
            })
            .on('end', function () {
                if (error) {
                    error = body;
                    body = undefined;
                }
                endHandler(error, body);
            });
        }

        break;
      case '@':

        // TODO cache sockets and reconnect on flow event
        request = websocket('wss://' + window.location.host);
        break;

      default:
        // TODO error
        return;
    }

    return request;
}

exports.incoming = function (CoreInst) {

    return function (req, res) {

        // handle wesocket message
        if (req.upgradeReq) {
            wsMessage(CoreInst, req);
            return;
        }

        // handle http request
        httpRequest(CoreInst, req, res);
    }
};

function httpRequest (CoreInst, req, res) {

    // TODO get url data
    // does incoming messages emit errors?

    var instance = req.params.instance;
    var eventNme = req.params.event;

    if (!instance || !eventNme) {
        res.set({'content-type': 'text/plain'}).status(400);
        res.end(new Error('Instance or event name not found.'));
        return;
    }

    req.pipe(CoreInst.flow(res, {to: instance, emit: eventNme}));
    req.push(req.url);
}

function wsMessage (CoreInst, msg) {

    // TODO pipe message stream to flow stream
    // TODO parse binary frames
    // TODO create a binary protocol
    /*
      header:
      - instance name
      - event name
      - request id
      - code 0 (data), 1 (error), // 2 (end) ??, read
      body:
      - data
    */

    var instance = '';
    var eventNme = '';

    CoreInst.link(instance, eventNme, req);

    var data;
    try {
        data = JSON.parse(msg.data);
    } catch (err) {
        return msg.target.send(JSON.stringify(['send error']));
    }

    // link message to flow event
    //CoreInst.link(data.instance, data.event, msg.target);

    msg.target.send(JSON.stringify(['instance', 'event', {response: 'data'}]));
}

exports.reset = function () {

    // close all websockets
    for (var socket in sockets) {
        sockets[socket].close();
    }

    // remove socket refs
    sockets = {};
};

exports.start = function () {};

return;

var utils = require('./flow/utils');
var streams = {};
var sockets = {};

exports.setup = setupSocket;
exports.stream = setupStream;

/**
 * Setup a stream to write over a socket.
 *
 * @public
 * @param {object} The stream object.
 * @param {string} The destination URL.
 */
function setupStream (stream, url) {

    // append parsed url on stream
    if (!url || typeof url === 'string' && !(url = parseUrl(url, stream))) {
        engine.log('E', new Error('Invalid socket URL.'));
        return stream;
    }

    // create socket context
    if (!stream.context.socket) {

        // create stream id
        var context = {
            id: utils.uid(3),
            url: url
        };
        context.socket = getSocket(stream, context.id, context.url);
        context.session = context.socket.session;
        stream.context = context;
    }

    // send data to socket on data
    stream.data(send);
    stream.error(send, 1);

    // append custom end handler
    stream._end = end;

    // save stream in cache
    streams[stream.context.id] = stream;

    return stream;
}

/**
 * Get or create a new client Socket.
 *
 * @public
 * @param {string} The target host.
 */
function getSocket (stream, id, url) {

    var host = url.host || global.location.host;
    var socket = sockets[host];

    // get socket from cached connections
    if (socket && socket.readyState < 2) {
        sockets[host].streams[id] = stream;
        return sockets[host];
    }

    // create new websocket connection
    socket = sockets[host] = new WebSocket('ws://' + host + '/');
    socket._cacheKey = host;

    socket.streams[id] = stream;

    // setup and return socket
    return socket;
}

/**
 * Setup socket with handlers.
 *
 * @public
 * @param {object} The socket.
 */
function setupSocket (socket) {

    // stream refs
    socket.streams = {};
    socket._buffer = [];

    // session
    socket.session = socket.session || {};

    // setup socket handlers
    socket.onclose = closeHandler;
    socket.onerror = errorHandler;
    socket.onmessage = parseMessage;
    socket.onopen = openHandler;

    return socket;
}

/**
 * Parse a socket URL string.
 *
 * @public
 * @param {string} The destination URL.
 */
function parseUrl (url, stream) {

    url = url.split('/');
    if (url.length < 2) {
        url.unshift(stream._._name);
    }

    var urlObject = {};
    if (url.length < 3) {
        urlObject = {
            inst: url[0],
            emit: url[1]
        };
    } else {
        urlObject = {
            host: url[0],
            inst: url[1],
            emit: url[2]
        };
    }

    return urlObject;
}

/**
 * Create and send a websocket message.
 *
 * @private
 * @param {object} The error object.
 * @param {object} The data object.
 */
function send (stream, options, data, type) {

    // create message
    var context = stream.context;
    var message = [type || 0, context.url.inst, context.url.emit, context.id];

    // convert error objects to strings
    if (type === 1 && data.toString) {
        data = data.toString();
    }

    // add the data to the message
    if (typeof data !== 'undefined') {
        message[4] = data;
    }

    // encode message (string)
    try {
        message = JSON.stringify(message);
    } catch (err) {
        return engine.log('E', err);
    }

    // create a new socket
    if (!context.socket) {
        context.socket = getSocket(stream, context.id, context.url);
    }

    // buffer writes if socket is not ready yet
    if (context.socket.readyState !== 1) {
        return context.socket._buffer.push(message);
    }

    // send message over socket
    context.socket.send(message);
}

/**
 * Custom end handler.
 *
 * @private
 */
function end (data, fromMessage) {

    // send end signal
    if (!fromMessage) {
        send(this, {}, data, 2);
    }

    // remove stream from cache
    delete streams[this.context.id];

    // remove stream from socket
    delete this.context.socket.streams[this.id];
}

/**
 * Prase websocket messages.
 *
 * @public
 * @param {object} The message event object.
 */
function parseMessage (messageEvent) {

    var socket = messageEvent.target;
    var message = messageEvent.data;

    // parse message
    // protocoll: [type, instance, event, id, err, data]

    // TODO broadcast (grouped connections)
    /*
      - how to define/create groups?
      - get group by name
      - get group by session id
      - get group by regexp pattern?
      - get group by role?
      - check group access with session
      - public groups
    */

    try {
        message = JSON.parse(message);
    } catch (error) {
        return engine.log('E', error);
    }

    // extract data from parsed message
    var type = message[0];
    var instanceName = message[1];
    var event = message[2];
    var id = message[3];
    var data = type === 1 ? [message[4]] : [null, message[4]];

    // check mandatory message values
    if (!event || !instanceName || !id) {

        // send error back
        message[0] =  1;
        message[4] = 'Invalid message.';
        return socket.send(JSON.stringify(message));
    }

    // get the link object
    var stream = streams[id];

    // write data to stream on write message
    if (type < 2) {

        // create a new stream or use cached stream
        stream = stream || createStream(instanceName, event, id, socket);
        stream.write.apply(stream, data);

    // end stream on end message
    } else if (stream) {
        stream.end(data, true);
    }
}

function createStream (instanceName, event, id, socket) {

    var stream = engine.flow(['flow', {'emit': (instanceName || '@') + '/' + event}], true);
    stream.context = {
        id: id,
        socket: socket,
        url: {
            inst: instance._name || '@',
            emit: event
        }
    };

    // create stream and save it to cache
    sockets[id] = setupStream(stream, stream.context.url);

    return sockets[id];
}

/**
 * Write bufferd data when a socket is connected.
 *
 * @public
 * @param {object} The open event object.
 */
function openHandler (openEvent) {
    var socket = openEvent.target;

    // send buffered writes to socket
    if (socket._buffer.length) {
        for (var i = 0, l = socket._buffer.length; i < l; ++i) {
            socket.send(socket._buffer[i]);
        }

        // empty buffer
        socket._buffer = [];
    }
}

/**
 * Remove socket from cache and end streams.
 *
 * @public
 * @param {object} The close event object.
 */
function closeHandler (closeEvent) {
    var socket = closeEvent.target;

    for (var stream in socket.streams) {

        // end all streams on the server
        if (!engine.client) {
            socket.streams[stream].end();

        // remove socket ref on the stream
        } else {
            delete socket.streams[stream].context.socket;
        }
    }

    // remove socket from sockets cache
    if (sockets[socket._cacheKey] && sockets[socket._cacheKey].readyState > 0) {
      delete sockets[socket._cacheKey];
    }
}

/**
 * Write socket errors to streams.
 *
 * @public
 * @param {object} The error event object.
 */
function errorHandler (errorEvent) {
    var socket = errorEvent.target;
    for (var stream in socket.streams) {
        stream.write(errorEvent.data);
    }
}
<commit_msg>end GET request automatically and emit url as first data chunk<commit_after>//var http = require('http');
var websocket = require('websocket-stream');
var http = require('flowhttp');
var sockets = {};

// TODO parse http requests and websocket messages
// TODO enable per-message-compression (Sec-WebSocket-Extensions: permessage-deflate)

exports.request = function (instance, eventName, endHandler) {

    // get instance
    // get even name
    // get request type
    var request;
    switch (eventName[0]) {
      case '/':

        /*
        var opts = {
            method: 'GET',
            path: '/' + instance._name + ':' + eventName.substr(1)
            headers: {},
            host: window.location.host,
            port: window.location.port
            responseType: 'response type to set on the underlying xhr object'
        };
        */

        // pipe http to flow event stream
        request = http[endHandler ? 'get' : 'post']('/' + instance._name + ':' + eventName.substr(1));

        // collect all data for a classic request callback
        if (endHandler) {
            var body = '';
            var error;
            request.on('response', function (res) {
                if (res.statusCode !== 200) {
                    error = true;
                }
            })
            request.on('data', function (chunk) {
                body += chunk;
            })
            .on('error', function (err) {
                body = err;
            })
            .on('end', function () {
                if (error) {
                    error = body;
                    body = undefined;
                }
                endHandler(error, body);
            });
            request.end();
        }

        break;
      case '@':

        // TODO cache sockets and reconnect on flow event
        request = websocket('wss://' + window.location.host);
        break;

      default:
        // TODO error
        return;
    }

    return request;
}

exports.incoming = function (CoreInst) {

    return function (req, res) {

        // handle wesocket message
        if (req.upgradeReq) {
            wsMessage(CoreInst, req);
            return;
        }

        // handle http request
        httpRequest(CoreInst, req, res);
    }
};

function httpRequest (CoreInst, req, res) {

    // TODO get url data
    // does incoming messages emit errors?

    var instance = req.params.instance;
    var eventNme = req.params.event;

    if (!instance || !eventNme) {
        res.set({'content-type': 'text/plain'}).status(400);
        res.end(new Error('Instance or event name not found.'));
        return;
    }

    req.pipe(CoreInst.flow(res, {to: instance, emit: eventNme}));

    // push url as first data chunk
    if (req.method === 'GET') {
        req.push(req.url);
    }
}

function wsMessage (CoreInst, msg) {

    // TODO pipe message stream to flow stream
    // TODO parse binary frames
    // TODO create a binary protocol
    /*
      header:
      - instance name
      - event name
      - request id
      - code 0 (data), 1 (error), // 2 (end) ??, read
      body:
      - data
    */

    var instance = '';
    var eventNme = '';

    CoreInst.link(instance, eventNme, req);

    var data;
    try {
        data = JSON.parse(msg.data);
    } catch (err) {
        return msg.target.send(JSON.stringify(['send error']));
    }

    // link message to flow event
    //CoreInst.link(data.instance, data.event, msg.target);

    msg.target.send(JSON.stringify(['instance', 'event', {response: 'data'}]));
}

exports.reset = function () {

    // close all websockets
    for (var socket in sockets) {
        sockets[socket].close();
    }

    // remove socket refs
    sockets = {};
};

exports.start = function () {};

return;

var utils = require('./flow/utils');
var streams = {};
var sockets = {};

exports.setup = setupSocket;
exports.stream = setupStream;

/**
 * Setup a stream to write over a socket.
 *
 * @public
 * @param {object} The stream object.
 * @param {string} The destination URL.
 */
function setupStream (stream, url) {

    // append parsed url on stream
    if (!url || typeof url === 'string' && !(url = parseUrl(url, stream))) {
        engine.log('E', new Error('Invalid socket URL.'));
        return stream;
    }

    // create socket context
    if (!stream.context.socket) {

        // create stream id
        var context = {
            id: utils.uid(3),
            url: url
        };
        context.socket = getSocket(stream, context.id, context.url);
        context.session = context.socket.session;
        stream.context = context;
    }

    // send data to socket on data
    stream.data(send);
    stream.error(send, 1);

    // append custom end handler
    stream._end = end;

    // save stream in cache
    streams[stream.context.id] = stream;

    return stream;
}

/**
 * Get or create a new client Socket.
 *
 * @public
 * @param {string} The target host.
 */
function getSocket (stream, id, url) {

    var host = url.host || global.location.host;
    var socket = sockets[host];

    // get socket from cached connections
    if (socket && socket.readyState < 2) {
        sockets[host].streams[id] = stream;
        return sockets[host];
    }

    // create new websocket connection
    socket = sockets[host] = new WebSocket('ws://' + host + '/');
    socket._cacheKey = host;

    socket.streams[id] = stream;

    // setup and return socket
    return socket;
}

/**
 * Setup socket with handlers.
 *
 * @public
 * @param {object} The socket.
 */
function setupSocket (socket) {

    // stream refs
    socket.streams = {};
    socket._buffer = [];

    // session
    socket.session = socket.session || {};

    // setup socket handlers
    socket.onclose = closeHandler;
    socket.onerror = errorHandler;
    socket.onmessage = parseMessage;
    socket.onopen = openHandler;

    return socket;
}

/**
 * Parse a socket URL string.
 *
 * @public
 * @param {string} The destination URL.
 */
function parseUrl (url, stream) {

    url = url.split('/');
    if (url.length < 2) {
        url.unshift(stream._._name);
    }

    var urlObject = {};
    if (url.length < 3) {
        urlObject = {
            inst: url[0],
            emit: url[1]
        };
    } else {
        urlObject = {
            host: url[0],
            inst: url[1],
            emit: url[2]
        };
    }

    return urlObject;
}

/**
 * Create and send a websocket message.
 *
 * @private
 * @param {object} The error object.
 * @param {object} The data object.
 */
function send (stream, options, data, type) {

    // create message
    var context = stream.context;
    var message = [type || 0, context.url.inst, context.url.emit, context.id];

    // convert error objects to strings
    if (type === 1 && data.toString) {
        data = data.toString();
    }

    // add the data to the message
    if (typeof data !== 'undefined') {
        message[4] = data;
    }

    // encode message (string)
    try {
        message = JSON.stringify(message);
    } catch (err) {
        return engine.log('E', err);
    }

    // create a new socket
    if (!context.socket) {
        context.socket = getSocket(stream, context.id, context.url);
    }

    // buffer writes if socket is not ready yet
    if (context.socket.readyState !== 1) {
        return context.socket._buffer.push(message);
    }

    // send message over socket
    context.socket.send(message);
}

/**
 * Custom end handler.
 *
 * @private
 */
function end (data, fromMessage) {

    // send end signal
    if (!fromMessage) {
        send(this, {}, data, 2);
    }

    // remove stream from cache
    delete streams[this.context.id];

    // remove stream from socket
    delete this.context.socket.streams[this.id];
}

/**
 * Prase websocket messages.
 *
 * @public
 * @param {object} The message event object.
 */
function parseMessage (messageEvent) {

    var socket = messageEvent.target;
    var message = messageEvent.data;

    // parse message
    // protocoll: [type, instance, event, id, err, data]

    // TODO broadcast (grouped connections)
    /*
      - how to define/create groups?
      - get group by name
      - get group by session id
      - get group by regexp pattern?
      - get group by role?
      - check group access with session
      - public groups
    */

    try {
        message = JSON.parse(message);
    } catch (error) {
        return engine.log('E', error);
    }

    // extract data from parsed message
    var type = message[0];
    var instanceName = message[1];
    var event = message[2];
    var id = message[3];
    var data = type === 1 ? [message[4]] : [null, message[4]];

    // check mandatory message values
    if (!event || !instanceName || !id) {

        // send error back
        message[0] =  1;
        message[4] = 'Invalid message.';
        return socket.send(JSON.stringify(message));
    }

    // get the link object
    var stream = streams[id];

    // write data to stream on write message
    if (type < 2) {

        // create a new stream or use cached stream
        stream = stream || createStream(instanceName, event, id, socket);
        stream.write.apply(stream, data);

    // end stream on end message
    } else if (stream) {
        stream.end(data, true);
    }
}

function createStream (instanceName, event, id, socket) {

    var stream = engine.flow(['flow', {'emit': (instanceName || '@') + '/' + event}], true);
    stream.context = {
        id: id,
        socket: socket,
        url: {
            inst: instance._name || '@',
            emit: event
        }
    };

    // create stream and save it to cache
    sockets[id] = setupStream(stream, stream.context.url);

    return sockets[id];
}

/**
 * Write bufferd data when a socket is connected.
 *
 * @public
 * @param {object} The open event object.
 */
function openHandler (openEvent) {
    var socket = openEvent.target;

    // send buffered writes to socket
    if (socket._buffer.length) {
        for (var i = 0, l = socket._buffer.length; i < l; ++i) {
            socket.send(socket._buffer[i]);
        }

        // empty buffer
        socket._buffer = [];
    }
}

/**
 * Remove socket from cache and end streams.
 *
 * @public
 * @param {object} The close event object.
 */
function closeHandler (closeEvent) {
    var socket = closeEvent.target;

    for (var stream in socket.streams) {

        // end all streams on the server
        if (!engine.client) {
            socket.streams[stream].end();

        // remove socket ref on the stream
        } else {
            delete socket.streams[stream].context.socket;
        }
    }

    // remove socket from sockets cache
    if (sockets[socket._cacheKey] && sockets[socket._cacheKey].readyState > 0) {
      delete sockets[socket._cacheKey];
    }
}

/**
 * Write socket errors to streams.
 *
 * @public
 * @param {object} The error event object.
 */
function errorHandler (errorEvent) {
    var socket = errorEvent.target;
    for (var stream in socket.streams) {
        stream.write(errorEvent.data);
    }
}
<|endoftext|>


<commit_before>/**
 * clipboard.js
 */
"use strict";
{
  /* api */
  const {i18n, runtime} = browser;

  /* constants */
  const COPY_ALL_TABS = "copyAllTabsURL";
  const COPY_LINK = "copyLinkURL";
  const COPY_PAGE = "copyPageURL";
  const COPY_TAB = "copyTabURL";
  const EXEC_COPY = "executeCopy";
  const EXEC_COPY_POPUP = "executeCopyPopup";
  const EXEC_COPY_TABS = "executeCopyAllTabs";
  const EXEC_COPY_TABS_POPUP = "executeCopyAllTabsPopup";
  const TYPE_FROM = 8;
  const TYPE_TO = -1;
  const USER_INPUT = "userInput";
  const USER_INPUT_DEFAULT = "Edit content text of the link";

  const ASCIIDOC = "AsciiDoc";
  const ASCIIDOC_TMPL = "link:%url%[%content%]";
  const BBCODE_TEXT = "BBCodeText";
  const BBCODE_TEXT_TMPL = "[url=%url%]%content%[/url]";
  const BBCODE_URL = "BBCodeURL";
  const BBCODE_URL_TMPL = "[url]%content%[/url]";
  const HTML = "HTML";
  const HTML_TMPL = "%content%";
  const MARKDOWN = "Markdown";
  const MARKDOWN_TMPL = "[%content%](%url% \"%title%\")";
  const TEXT = "Text";
  const TEXT_TMPL = "%content% %url%";
  const TEXTILE = "Textile";
  const TEXTILE_TMPL = "\"%content%\":%url%";

  /* variables */
  const vars = {
    mimeType: "text/plain",
  };

  /**
   * log error
   * @param {!Object} e - Error
   * @returns {boolean} - false
   */
  const logError = e => {
    console.error(e);
    return false;
  };

  /**
   * get type
   * @param {*} o - object to check
   * @returns {string} - type of object
   */
  const getType = o =>
    Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);

  /**
   * is string
   * @param {*} o - object to check
   * @returns {boolean} - result
   */
  const isString = o => typeof o === "string" || o instanceof String;

  /**
   * strip matching char
   * @param {string} str - string
   * @param {RegExp} re - RegExp
   * @returns {?string} - string
   */
  const stripChar = (str, re) =>
    isString(str) && re && re.global && str.replace(re, "") || null;

  /**
   * escape matching char
   * @param {string} str - string
   * @param {RegExp} re - RegExp
   * @returns {?string} - string
   */
  const escapeChar = (str, re) =>
    isString(str) && re && re.global &&
    str.replace(re, (m, c) => `\\${c}`) || null;

  /**
   * convert HTML specific character to character reference
   * @param {string} str - string
   * @returns {?string} - string
   */
  const convertHtmlChar = str =>
    isString(str) &&
    str.replace(/&(?!(?:(?:(?:[gl]|quo)t|amp)|[\dA-Za-z]+|#(?:\d+|x[\dA-Fa-f]+));)/g, "&")
      .replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """) ||
    null;

  /**
   * convert paren to numeric character reference
   * @param {string} str - string
   * @returns {?string} - string
   */
  const convertParen = str =>
    isString(str) &&
    str.replace(/(\()|(\))/g, (m, a, b) => a && "(" || b && ")") ||
    null;

  /**
   * encode URL component part
   * @param {string} part - component part
   * @returns {string} - encoded component part
   */
  const encodeUrlPart = part =>
    isString(part) &&
    part.replace(/([\s<>[\]'^`{|}])/g, (m, c) => encodeURIComponent(c))
      .replace(/(')/g, (m, c) => escape(c)) || "";

  /**
   * encode special char
   * @param {string} str - URL string
   * @returns {?string} - encoded URL
   */
  const encodeSpecialChar = str => {
    let encodedUrl;
    if (isString(str)) {
      const url = new URL(str);
      if (url) {
        const {
          hash: frag, origin, pathname: path, protocol, search: query,
        } = url;
        const base = protocol === "file:" && `${protocol}//` || origin;
        encodedUrl = new URL(
          `${encodeUrlPart(path)}${encodeUrlPart(query)}${encodeUrlPart(frag)}`,
          base
        );
      }
    }
    return encodedUrl && encodedUrl.href || null;
  };

  /**
   * close window
   * @returns {void}
   */
  const closeWindow = () => {
    window.close();
  };

  /**
   * copy to clipboard
   * @param {string} text - text to copy
   * @returns {void}
   */
  const copyToClipboard = async (text = "") => {
    if (!isString(text)) {
      throw new TypeError(`Expected String but got ${getType(text)}.`);
    }
    text = text.trim() || "";
    if (text) {
      /**
       * set clipboard data
       * @param {!Object} evt - Event
       * @returns {void}
       */
      const setClipboardData = evt => {
        let {mimeType: type} = vars;
        if (!isString(type) || !/^text\/(?:plain|html)$/.test(type)) {
          type = "text/plain";
        }
        document.removeEventListener("copy", setClipboardData, true);
        evt.stopImmediatePropagation();
        evt.preventDefault();
        evt.clipboardData.setData(type, text);
      };

      document.addEventListener("copy", setClipboardData, true);
      document.execCommand("copy");
    }
  };

  /**
   * edit content
   * @param {string} content - content to edit
   * @returns {?string} - edited content
   */
  const editContent = async (content = "") => {
    if (!isString(content)) {
      throw new TypeError(`Expected String but got ${getType(content)}.`);
    }
    const msg = await i18n.getMessage(USER_INPUT) || USER_INPUT_DEFAULT;
    content = window.prompt(msg, content.trim());
    return content;
  };

  /**
   * create link text
   * @param {Object} data - copy data
   * @returns {?string} - link text
   */
  const createLinkText = async (data = {}) => {
    const {content: contentText, menuItemId, mimeType, promptContent} = data;
    let {title, url} = data;
    let content = promptContent ?
      await editContent(contentText || "") || "" :
      contentText || "";
    let template, text;
    switch (menuItemId) {
      case `${COPY_ALL_TABS}${ASCIIDOC}`:
      case `${COPY_LINK}${ASCIIDOC}`:
      case `${COPY_PAGE}${ASCIIDOC}`:
      case `${COPY_TAB}${ASCIIDOC}`:
        content = escapeChar(content, /\[[\]]/g) || "";
        url = encodeSpecialChar(url);
        template = ASCIIDOC_TMPL;
        vars.mimeType = "text/plain";
        break;
      case `${COPY_ALL_TABS}${BBCODE_TEXT}`:
      case `${COPY_LINK}${BBCODE_TEXT}`:
      case `${COPY_PAGE}${BBCODE_TEXT}`:
      case `${COPY_TAB}${BBCODE_TEXT}`:
        content = stripChar(content, /\[(?:url(?:=.*)?|\/url)\]/ig) || "";
        template = BBCODE_TEXT_TMPL;
        vars.mimeType = "text/plain";
        break;
      case `${COPY_ALL_TABS}${BBCODE_URL}`:
      case `${COPY_LINK}${BBCODE_URL}`:
      case `${COPY_PAGE}${BBCODE_URL}`:
      case `${COPY_TAB}${BBCODE_URL}`:
        content = stripChar(content, /\[(?:url(?:=.*)?|\/url)\]/ig) || "";
        template = BBCODE_URL_TMPL;
        vars.mimeType = "text/plain";
        break;
      case `${COPY_ALL_TABS}${HTML}`:
      case `${COPY_LINK}${HTML}`:
      case `${COPY_PAGE}${HTML}`:
      case `${COPY_TAB}${HTML}`:
        content = convertHtmlChar(content) || "";
        title = convertHtmlChar(title) || "";
        template = HTML_TMPL;
        vars.mimeType = mimeType;
        break;
      case `${COPY_ALL_TABS}${MARKDOWN}`:
      case `${COPY_LINK}${MARKDOWN}`:
      case `${COPY_PAGE}${MARKDOWN}`:
      case `${COPY_TAB}${MARKDOWN}`:
        content = escapeChar(convertHtmlChar(content), /([[\]])/g) || "";
        title = escapeChar(convertHtmlChar(title), /(")/g) || "";
        template = MARKDOWN_TMPL;
        vars.mimeType = "text/plain";
        break;
      case `${COPY_ALL_TABS}${TEXT}`:
      case `${COPY_LINK}${TEXT}`:
      case `${COPY_PAGE}${TEXT}`:
      case `${COPY_TAB}${TEXT}`:
        template = TEXT_TMPL;
        vars.mimeType = "text/plain";
        break;
      case `${COPY_ALL_TABS}${TEXTILE}`:
      case `${COPY_LINK}${TEXTILE}`:
      case `${COPY_PAGE}${TEXTILE}`:
      case `${COPY_TAB}${TEXTILE}`:
        content = convertHtmlChar(convertParen(content)) || "";
        template = TEXTILE_TMPL;
        vars.mimeType = "text/plain";
        break;
      default:
    }
    if (template) {
      text = template.replace(/%content%/g, content.trim())
        .replace(/%title%/g, title && title.trim() || "")
        .replace(/%url%/g, url.trim());
    }
    return text || null;
  };

  /**
   * extract copy data
   * @param {Object} data - copy data
   * @returns {?string} - link text
   */
  const extractCopyData = async (data = {}) => {
    const {allTabs} = data;
    let text;
    if (Array.isArray(allTabs)) {
      const func = [];
      for (const tabData of allTabs) {
        func.push(createLinkText(tabData));
      }
      text = await Promise.all(func).then(arr => arr.filter(i => i).join("\n"));
    } else {
      text = await createLinkText(data);
    }
    return text || null;
  };

  /**
   * handle message
   * @param {*} msg - message
   * @returns {Promise.<Array>} - results of each handler
   */
  const handleMsg = async (msg = {}) => {
    const items = msg && Object.keys(msg);
    const func = [];
    if (items && items.length) {
      for (const item of items) {
        const obj = msg[item];
        switch (item) {
          case EXEC_COPY:
          case EXEC_COPY_TABS:
            func.push(extractCopyData(obj).then(copyToClipboard));
            break;
          case EXEC_COPY_POPUP:
          case EXEC_COPY_TABS_POPUP:
            func.push(
              extractCopyData(obj).then(copyToClipboard).then(closeWindow)
            );
            break;
          default:
        }
      }
    }
    return Promise.all(func);
  };

  /* listener */
  runtime.onMessage.addListener(msg => handleMsg(msg).catch(logError));
}
<commit_msg>Generalize function<commit_after>/**
 * clipboard.js
 */
"use strict";
{
  /* api */
  const {i18n, runtime} = browser;

  /* constants */
  const COPY_ALL_TABS = "copyAllTabsURL";
  const COPY_LINK = "copyLinkURL";
  const COPY_PAGE = "copyPageURL";
  const COPY_TAB = "copyTabURL";
  const EXEC_COPY = "executeCopy";
  const EXEC_COPY_POPUP = "executeCopyPopup";
  const EXEC_COPY_TABS = "executeCopyAllTabs";
  const EXEC_COPY_TABS_POPUP = "executeCopyAllTabsPopup";
  const TYPE_FROM = 8;
  const TYPE_TO = -1;
  const USER_INPUT = "userInput";
  const USER_INPUT_DEFAULT = "Edit content text of the link";

  const ASCIIDOC = "AsciiDoc";
  const ASCIIDOC_TMPL = "link:%url%[%content%]";
  const BBCODE_TEXT = "BBCodeText";
  const BBCODE_TEXT_TMPL = "[url=%url%]%content%[/url]";
  const BBCODE_URL = "BBCodeURL";
  const BBCODE_URL_TMPL = "[url]%content%[/url]";
  const HTML = "HTML";
  const HTML_TMPL = "%content%";
  const MARKDOWN = "Markdown";
  const MARKDOWN_TMPL = "[%content%](%url% \"%title%\")";
  const TEXT = "Text";
  const TEXT_TMPL = "%content% %url%";
  const TEXTILE = "Textile";
  const TEXTILE_TMPL = "\"%content%\":%url%";

  /* variables */
  const vars = {
    mimeType: "text/plain",
  };

  /**
   * log error
   * @param {!Object} e - Error
   * @returns {boolean} - false
   */
  const logError = e => {
    console.error(e);
    return false;
  };

  /**
   * get type
   * @param {*} o - object to check
   * @returns {string} - type of object
   */
  const getType = o =>
    Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);

  /**
   * is string
   * @param {*} o - object to check
   * @returns {boolean} - result
   */
  const isString = o => typeof o === "string" || o instanceof String;

  /**
   * strip matching char
   * @param {string} str - string
   * @param {RegExp} re - RegExp
   * @returns {?string} - string
   */
  const stripChar = (str, re) =>
    isString(str) && re && re.global && str.replace(re, "") || null;

  /**
   * escape matching char
   * @param {string} str - string
   * @param {RegExp} re - RegExp
   * @returns {?string} - string
   */
  const escapeChar = (str, re) =>
    isString(str) && re && re.global &&
    str.replace(re, (m, c) => `\\${c}`) || null;

  /**
   * convert matching character to numeric character reference
   * @param {string} str - string
   * @param {RegExp} re - RegExp
   * @returns {?string} - string
   */
  const convertNumCharRef = (str, re) =>
    isString(str) && re && re.global &&
    str.replace(re, (m, c) => `&#${c.charCodeAt(0)};`) || null;

  /**
   * convert HTML specific character to character reference
   * @param {string} str - string
   * @returns {?string} - string
   */
  const convertHtmlChar = str =>
    isString(str) &&
    str.replace(/&(?!(?:(?:(?:[gl]|quo)t|amp)|[\dA-Za-z]+|#(?:\d+|x[\dA-Fa-f]+));)/g, "&")
      .replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """) ||
    null;

  /**
   * encode URL component part
   * @param {string} part - component part
   * @returns {string} - encoded component part
   */
  const encodeUrlPart = part =>
    isString(part) &&
    part.replace(/([\s<>[\]'^`{|}])/g, (m, c) => encodeURIComponent(c))
      .replace(/(')/g, (m, c) => escape(c)) || "";

  /**
   * encode special char
   * @param {string} str - URL string
   * @returns {?string} - encoded URL
   */
  const encodeSpecialChar = str => {
    let encodedUrl;
    if (isString(str)) {
      const url = new URL(str);
      if (url) {
        const {
          hash: frag, origin, pathname: path, protocol, search: query,
        } = url;
        const base = protocol === "file:" && `${protocol}//` || origin;
        encodedUrl = new URL(
          `${encodeUrlPart(path)}${encodeUrlPart(query)}${encodeUrlPart(frag)}`,
          base
        );
      }
    }
    return encodedUrl && encodedUrl.href || null;
  };

  /**
   * close window
   * @returns {void}
   */
  const closeWindow = () => {
    window.close();
  };

  /**
   * copy to clipboard
   * @param {string} text - text to copy
   * @returns {void}
   */
  const copyToClipboard = async (text = "") => {
    if (!isString(text)) {
      throw new TypeError(`Expected String but got ${getType(text)}.`);
    }
    text = text.trim() || "";
    if (text) {
      /**
       * set clipboard data
       * @param {!Object} evt - Event
       * @returns {void}
       */
      const setClipboardData = evt => {
        let {mimeType: type} = vars;
        if (!isString(type) || !/^text\/(?:plain|html)$/.test(type)) {
          type = "text/plain";
        }
        document.removeEventListener("copy", setClipboardData, true);
        evt.stopImmediatePropagation();
        evt.preventDefault();
        evt.clipboardData.setData(type, text);
      };

      document.addEventListener("copy", setClipboardData, true);
      document.execCommand("copy");
    }
  };

  /**
   * edit content
   * @param {string} content - content to edit
   * @returns {?string} - edited content
   */
  const editContent = async (content = "") => {
    if (!isString(content)) {
      throw new TypeError(`Expected String but got ${getType(content)}.`);
    }
    const msg = await i18n.getMessage(USER_INPUT) || USER_INPUT_DEFAULT;
    content = window.prompt(msg, content.trim());
    return content;
  };

  /**
   * create link text
   * @param {Object} data - copy data
   * @returns {?string} - link text
   */
  const createLinkText = async (data = {}) => {
    const {content: contentText, menuItemId, mimeType, promptContent} = data;
    let {title, url} = data;
    let content = promptContent ?
      await editContent(contentText || "") || "" :
      contentText || "";
    let template, text;
    switch (menuItemId) {
      case `${COPY_ALL_TABS}${ASCIIDOC}`:
      case `${COPY_LINK}${ASCIIDOC}`:
      case `${COPY_PAGE}${ASCIIDOC}`:
      case `${COPY_TAB}${ASCIIDOC}`:
        content = escapeChar(content, /\[[\]]/g) || "";
        url = encodeSpecialChar(url);
        template = ASCIIDOC_TMPL;
        vars.mimeType = "text/plain";
        break;
      case `${COPY_ALL_TABS}${BBCODE_TEXT}`:
      case `${COPY_LINK}${BBCODE_TEXT}`:
      case `${COPY_PAGE}${BBCODE_TEXT}`:
      case `${COPY_TAB}${BBCODE_TEXT}`:
        content = stripChar(content, /\[(?:url(?:=.*)?|\/url)\]/ig) || "";
        template = BBCODE_TEXT_TMPL;
        vars.mimeType = "text/plain";
        break;
      case `${COPY_ALL_TABS}${BBCODE_URL}`:
      case `${COPY_LINK}${BBCODE_URL}`:
      case `${COPY_PAGE}${BBCODE_URL}`:
      case `${COPY_TAB}${BBCODE_URL}`:
        content = stripChar(content, /\[(?:url(?:=.*)?|\/url)\]/ig) || "";
        template = BBCODE_URL_TMPL;
        vars.mimeType = "text/plain";
        break;
      case `${COPY_ALL_TABS}${HTML}`:
      case `${COPY_LINK}${HTML}`:
      case `${COPY_PAGE}${HTML}`:
      case `${COPY_TAB}${HTML}`:
        content = convertHtmlChar(content) || "";
        title = convertHtmlChar(title) || "";
        template = HTML_TMPL;
        vars.mimeType = mimeType;
        break;
      case `${COPY_ALL_TABS}${MARKDOWN}`:
      case `${COPY_LINK}${MARKDOWN}`:
      case `${COPY_PAGE}${MARKDOWN}`:
      case `${COPY_TAB}${MARKDOWN}`:
        content = escapeChar(convertHtmlChar(content), /([[\]])/g) || "";
        title = escapeChar(convertHtmlChar(title), /(")/g) || "";
        template = MARKDOWN_TMPL;
        vars.mimeType = "text/plain";
        break;
      case `${COPY_ALL_TABS}${TEXT}`:
      case `${COPY_LINK}${TEXT}`:
      case `${COPY_PAGE}${TEXT}`:
      case `${COPY_TAB}${TEXT}`:
        template = TEXT_TMPL;
        vars.mimeType = "text/plain";
        break;
      case `${COPY_ALL_TABS}${TEXTILE}`:
      case `${COPY_LINK}${TEXTILE}`:
      case `${COPY_PAGE}${TEXTILE}`:
      case `${COPY_TAB}${TEXTILE}`:
        content = convertHtmlChar(convertNumCharRef(content, /([()])/g)) || "";
        template = TEXTILE_TMPL;
        vars.mimeType = "text/plain";
        break;
      default:
    }
    if (template) {
      text = template.replace(/%content%/g, content.trim())
        .replace(/%title%/g, title && title.trim() || "")
        .replace(/%url%/g, url.trim());
    }
    return text || null;
  };

  /**
   * extract copy data
   * @param {Object} data - copy data
   * @returns {?string} - link text
   */
  const extractCopyData = async (data = {}) => {
    const {allTabs} = data;
    let text;
    if (Array.isArray(allTabs)) {
      const func = [];
      for (const tabData of allTabs) {
        func.push(createLinkText(tabData));
      }
      text = await Promise.all(func).then(arr => arr.filter(i => i).join("\n"));
    } else {
      text = await createLinkText(data);
    }
    return text || null;
  };

  /**
   * handle message
   * @param {*} msg - message
   * @returns {Promise.<Array>} - results of each handler
   */
  const handleMsg = async (msg = {}) => {
    const items = msg && Object.keys(msg);
    const func = [];
    if (items && items.length) {
      for (const item of items) {
        const obj = msg[item];
        switch (item) {
          case EXEC_COPY:
          case EXEC_COPY_TABS:
            func.push(extractCopyData(obj).then(copyToClipboard));
            break;
          case EXEC_COPY_POPUP:
          case EXEC_COPY_TABS_POPUP:
            func.push(
              extractCopyData(obj).then(copyToClipboard).then(closeWindow)
            );
            break;
          default:
        }
      }
    }
    return Promise.all(func);
  };

  /* listener */
  runtime.onMessage.addListener(msg => handleMsg(msg).catch(logError));
}
<|endoftext|>


<commit_before>var Encore = require('@symfony/webpack-encore');

Encore
// directory where all compiled assets will be stored
    .setOutputPath('html/build/')

    // what's the public path to this directory (relative to your project's document root dir)
    .setPublicPath('/build')

    // empty the outputPath dir before each build
    .cleanupOutputBeforeBuild()

    // will output as build/admin.js and similar
    .addEntry('admin', './html/js/src/admin.js')
    .addEntry('public', './html/js/src/public.js')

    // allow sass/scss files to be processed
    .enableSassLoader()
    .enablePostCssLoader()
    // allow .vue files to be processed
    .enableVueLoader()

    .enableSourceMaps(true)

    // create hashed filenames (e.g. public.abc123.css)
    .enableVersioning()
;

// export the final configuration
let config = Encore.getWebpackConfig();

config.resolve.alias['vue$'] = 'vue/dist/vue.common.js';

if (Encore.isProduction()) {
    config.devtool = 'source-map';
}

module.exports = config;<commit_msg>disabling resolving url()'s in SASS<commit_after>var Encore = require('@symfony/webpack-encore');

Encore
// directory where all compiled assets will be stored
    .setOutputPath('html/build/')

    // what's the public path to this directory (relative to your project's document root dir)
    .setPublicPath('/build')

    // empty the outputPath dir before each build
    .cleanupOutputBeforeBuild()

    // will output as build/admin.js and similar
    .addEntry('admin', './html/js/src/admin.js')
    .addEntry('public', './html/js/src/public.js')

    // allow sass/scss files to be processed
    .enableSassLoader(function(sassOptions) {}, {
        // see: http://symfony.com/doc/current/frontend/encore/bootstrap.html#importing-bootstrap-sass
        resolve_url_loader: false
    })
    .enablePostCssLoader()
    // allow .vue files to be processed
    .enableVueLoader()

    .enableSourceMaps(true)

    // create hashed filenames (e.g. public.abc123.css)
    .enableVersioning()
;

// export the final configuration
let config = Encore.getWebpackConfig();

config.resolve.alias['vue$'] = 'vue/dist/vue.common.js';

if (Encore.isProduction()) {
    config.devtool = 'source-map';
}

module.exports = config;
<|endoftext|>


<commit_before>import Eventable from './eventable.js';
import {
  getElementsFromOption
} from '../util/util.js';
import Content from '../slide/content.js';

/** @typedef {import("../photoswipe.js").default} PhotoSwipe */
/** @typedef {import("../photoswipe.js").PhotoSwipeOptions} PhotoSwipeOptions */
/** @typedef {import("../slide/slide.js").SlideData} SlideData */

/**
 * PhotoSwipe base class that can retrieve data about every slide.
 * Shared by PhotoSwipe Core and PhotoSwipe Lightbox
 */
class PhotoSwipeBase extends Eventable {
  /**
   * Get total number of slides
   *
   * @returns {number}
   */
  getNumItems() {
    let numItems;
    const { dataSource } = this.options;
    if (!dataSource) {
      numItems = 0;
    } else if ('length' in dataSource) {
      // may be an array or just object with length property
      numItems = dataSource.length;
    } else if ('gallery' in dataSource) {
      // query DOM elements
      if (!dataSource.items) {
        dataSource.items = this._getGalleryDOMElements(dataSource.gallery);
      }

      if (dataSource.items) {
        numItems = dataSource.items.length;
      }
    }

    // legacy event, before filters were introduced
    const event = this.dispatch('numItems', {
      dataSource,
      numItems
    });
    return this.applyFilters('numItems', event.numItems, dataSource);
  }

  /**
   * @param {SlideData} slideData
   * @param {number} index
   */
  createContentFromData(slideData, index) {
    // @ts-expect-error
    return new Content(slideData, this, index);
  }

  /**
   * Get item data by index.
   *
   * "item data" should contain normalized information that PhotoSwipe needs to generate a slide.
   * For example, it may contain properties like
   * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.
   *
   * @param {number} index
   */
  getItemData(index) {
    const { dataSource } = this.options;
    let dataSourceItem;
    if (Array.isArray(dataSource)) {
      // Datasource is an array of elements
      dataSourceItem = dataSource[index];
    } else if (dataSource && dataSource.gallery) {
      // dataSource has gallery property,
      // thus it was created by Lightbox, based on
      // gallery and children options

      // query DOM elements
      if (!dataSource.items) {
        dataSource.items = this._getGalleryDOMElements(dataSource.gallery);
      }

      dataSourceItem = dataSource.items[index];
    }

    let itemData = dataSourceItem;

    if (itemData instanceof Element) {
      itemData = this._domElementToItemData(itemData);
    }

    // Dispatching the itemData event,
    // it's a legacy verion before filters were introduced
    const event = this.dispatch('itemData', {
      itemData: itemData || {},
      index
    });

    return this.applyFilters('itemData', event.itemData, index);
  }

  /**
   * Get array of gallery DOM elements,
   * based on childSelector and gallery element.
   *
   * @param {HTMLElement} galleryElement
   */
  _getGalleryDOMElements(galleryElement) {
    if (this.options.children || this.options.childSelector) {
      return getElementsFromOption(
        this.options.children,
        this.options.childSelector,
        galleryElement
      ) || [];
    }

    return [galleryElement];
  }

  /**
   * Converts DOM element to item data object.
   *
   * @param {HTMLElement} element DOM element
   */
  // eslint-disable-next-line class-methods-use-this
  _domElementToItemData(element) {
    /** @type {SlideData} */
    const itemData = {
      element
    };

    // eslint-disable-next-line max-len
    const linkEl = /** @type {HTMLAnchorElement} */ (element.tagName === 'A' ? element : element.querySelector('a'));

    if (linkEl) {
      // src comes from data-pswp-src attribute,
      // if it's empty link href is used
      itemData.src = linkEl.dataset.pswpSrc || linkEl.href;

      if (linkEl.dataset.pswpSrcset) {
        itemData.srcset = linkEl.dataset.pswpSrcset;
      }

      itemData.width = parseInt(linkEl.dataset.pswpWidth, 10);
      itemData.height = parseInt(linkEl.dataset.pswpHeight, 10);

      // support legacy w & h properties
      itemData.w = itemData.width;
      itemData.h = itemData.height;

      if (linkEl.dataset.pswpType) {
        itemData.type = linkEl.dataset.pswpType;
      }

      const thumbnailEl = element.querySelector('img');

      if (thumbnailEl) {
        // msrc is URL to placeholder image that's displayed before large image is loaded
        // by default it's displayed only for the first slide
        itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;
        itemData.alt = thumbnailEl.getAttribute('alt');
      }

      if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {
        itemData.thumbCropped = true;
      }
    }

    return this.applyFilters('domItemData', itemData, element, linkEl);
  }
}

export default PhotoSwipeBase;
<commit_msg>Expose method to lazy-load content by data<commit_after>import Eventable from './eventable.js';
import {
  getElementsFromOption
} from '../util/util.js';
import Content from '../slide/content.js';
import { lazyLoadData } from '../slide/loader.js';

/** @typedef {import("../photoswipe.js").default} PhotoSwipe */
/** @typedef {import("../photoswipe.js").PhotoSwipeOptions} PhotoSwipeOptions */
/** @typedef {import("../slide/slide.js").SlideData} SlideData */

/**
 * PhotoSwipe base class that can retrieve data about every slide.
 * Shared by PhotoSwipe Core and PhotoSwipe Lightbox
 */
class PhotoSwipeBase extends Eventable {
  /**
   * Get total number of slides
   *
   * @returns {number}
   */
  getNumItems() {
    let numItems;
    const { dataSource } = this.options;
    if (!dataSource) {
      numItems = 0;
    } else if ('length' in dataSource) {
      // may be an array or just object with length property
      numItems = dataSource.length;
    } else if ('gallery' in dataSource) {
      // query DOM elements
      if (!dataSource.items) {
        dataSource.items = this._getGalleryDOMElements(dataSource.gallery);
      }

      if (dataSource.items) {
        numItems = dataSource.items.length;
      }
    }

    // legacy event, before filters were introduced
    const event = this.dispatch('numItems', {
      dataSource,
      numItems
    });
    return this.applyFilters('numItems', event.numItems, dataSource);
  }

  /**
   * @param {SlideData} slideData
   * @param {number} index
   */
  createContentFromData(slideData, index) {
    // @ts-expect-error
    return new Content(slideData, this, index);
  }

  /**
   * Get item data by index.
   *
   * "item data" should contain normalized information that PhotoSwipe needs to generate a slide.
   * For example, it may contain properties like
   * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.
   *
   * @param {number} index
   */
  getItemData(index) {
    const { dataSource } = this.options;
    let dataSourceItem;
    if (Array.isArray(dataSource)) {
      // Datasource is an array of elements
      dataSourceItem = dataSource[index];
    } else if (dataSource && dataSource.gallery) {
      // dataSource has gallery property,
      // thus it was created by Lightbox, based on
      // gallery and children options

      // query DOM elements
      if (!dataSource.items) {
        dataSource.items = this._getGalleryDOMElements(dataSource.gallery);
      }

      dataSourceItem = dataSource.items[index];
    }

    let itemData = dataSourceItem;

    if (itemData instanceof Element) {
      itemData = this._domElementToItemData(itemData);
    }

    // Dispatching the itemData event,
    // it's a legacy verion before filters were introduced
    const event = this.dispatch('itemData', {
      itemData: itemData || {},
      index
    });

    return this.applyFilters('itemData', event.itemData, index);
  }

  /**
   * Get array of gallery DOM elements,
   * based on childSelector and gallery element.
   *
   * @param {HTMLElement} galleryElement
   */
  _getGalleryDOMElements(galleryElement) {
    if (this.options.children || this.options.childSelector) {
      return getElementsFromOption(
        this.options.children,
        this.options.childSelector,
        galleryElement
      ) || [];
    }

    return [galleryElement];
  }

  /**
   * Converts DOM element to item data object.
   *
   * @param {HTMLElement} element DOM element
   */
  // eslint-disable-next-line class-methods-use-this
  _domElementToItemData(element) {
    /** @type {SlideData} */
    const itemData = {
      element
    };

    // eslint-disable-next-line max-len
    const linkEl = /** @type {HTMLAnchorElement} */ (element.tagName === 'A' ? element : element.querySelector('a'));

    if (linkEl) {
      // src comes from data-pswp-src attribute,
      // if it's empty link href is used
      itemData.src = linkEl.dataset.pswpSrc || linkEl.href;

      if (linkEl.dataset.pswpSrcset) {
        itemData.srcset = linkEl.dataset.pswpSrcset;
      }

      itemData.width = parseInt(linkEl.dataset.pswpWidth, 10);
      itemData.height = parseInt(linkEl.dataset.pswpHeight, 10);

      // support legacy w & h properties
      itemData.w = itemData.width;
      itemData.h = itemData.height;

      if (linkEl.dataset.pswpType) {
        itemData.type = linkEl.dataset.pswpType;
      }

      const thumbnailEl = element.querySelector('img');

      if (thumbnailEl) {
        // msrc is URL to placeholder image that's displayed before large image is loaded
        // by default it's displayed only for the first slide
        itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;
        itemData.alt = thumbnailEl.getAttribute('alt');
      }

      if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {
        itemData.thumbCropped = true;
      }
    }

    return this.applyFilters('domItemData', itemData, element, linkEl);
  }

  /**
   * Lazy-load by slide data
   *
   * @param {SlideData} itemData Data about the slide
   * @param {number} index
   * @returns Image that is being decoded or false.
   */
  lazyLoadData(itemData, index) {
    return lazyLoadData(itemData, this, index);
  }
}

export default PhotoSwipeBase;
<|endoftext|>


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

(function (exports, io) {

  /**
   * Expose constructor.
   */

  exports.Socket = Socket;

  /**
   * Create a new `Socket.IO client` which can establish a persisent
   * connection with a Socket.IO enabled server.
   *
   * @api public
   */

  function Socket (options) {
    this.options = {
        port: 80
      , secure: false
      , document: document
      , resource: 'socket.io'
      , transports: io.transports
      , 'connect timeout': 10000
      , 'try multiple transports': true
      , 'reconnect': true
      , 'reconnection delay': 500
      , 'reopen delay': 3000
      , 'max reconnection attempts': 10
      , 'sync disconnect on unload': true
      , 'auto connect': true
    };

    io.util.merge(this.options, options);

    this.connected = false;
    this.open = false;
    this.connecting = false;
    this.reconnecting = false;
    this.namespaces = {};
    this.buffer = [];
    this.doBuffer = false;

    if (this.options['sync disconnect on unload'] &&
        (!this.isXDomain() || io.util.ua.hasCORS)) {
      var self = this;

      io.util.on(window, 'beforeunload', function () {
        self.disconnectSync();
      }, false);
    }

    if (this.options['auto connect']) {
      this.connect();
    }
};

  /**
   * Apply EventEmitter mixin.
   */

  io.util.mixin(Socket, io.EventEmitter);

  /**
   * Returns a namespace listener/emitter for this socket
   *
   * @api public
   */

  Socket.prototype.of = function (name) {
    if (!this.namespaces[name]) {
      this.namespaces[name] = new io.SocketNamespace(this, name);

      if (name !== '') {
        this.namespaces[name].packet({ type: 'connect' });
      }
    }

    return this.namespaces[name];
  };

  /**
   * Emits the given event to the Socket and all namespaces
   *
   * @api private
   */

  Socket.prototype.publish = function () {
    this.emit.apply(this, arguments);

    var nsp;

    for (var i in this.namespaces) {
      if (this.namespaces.hasOwnProperty(i)) {
        nsp = this.of(i);
        nsp.$emit.apply(nsp, arguments);
      }
    }
  };

  /**
   * Performs the handshake
   *
   * @api private
   */

  function empty () { };

  Socket.prototype.handshake = function (fn) {
    var self = this
      , options = this.options;

    function complete (data) {
      if (data instanceof Error) {
        self.onError(data.message);
      } else {
        fn.apply(null, data.split(':'));
      }
    };

    var url = [
          'http' + (options.secure ? 's' : '') + ':/'
        , options.host + ':' + options.port
        , this.options.resource
        , io.protocol
        , '?t=' + + new Date
      ].join('/');

    if (this.isXDomain()) {
      var insertAt = document.getElementsByTagName('script')[0]
        , script = document.createElement('SCRIPT');

      script.src = url + '&jsonp=' + io.j.length;
      insertAt.parentNode.insertBefore(script, insertAt);

      io.j.push(function (data) {
        complete(data);
        script.parentNode.removeChild(script);
      });
    } else {
      var xhr = io.util.request();

      xhr.open('GET', url);
      xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
          xhr.onreadystatechange = empty;

          if (xhr.status == 200) {
            complete(xhr.responseText);
          } else {
            !self.reconnecting && self.onError(xhr.responseText);
          }
        }
      };
      xhr.send(null);
    }
  };

  /**
   * Find an available transport based on the options supplied in the constructor.
   *
   * @api private
   */

  Socket.prototype.getTransport = function (override) {
    var transports = override || this.transports, match;

    for (var i = 0, transport; transport = transports[i]; i++) {
      if (io.Transport[transport]
        && io.Transport[transport].check(this)
        && (!this.isXDomain() || io.Transport[transport].xdomainCheck())) {
        return new io.Transport[transport](this, this.sessionid);
      }
    }

    return null;
  };

  /**
   * Connects to the server.
   *
   * @param {Function} [fn] Callback.
   * @returns {io.Socket}
   * @api public
   */

  Socket.prototype.connect = function (fn) {
    console.log('connect called')
    if (this.connecting) {
      return this;
    }

    var self = this;

    this.handshake(function (sid, heartbeat, close, transports) {
      self.sessionid = sid;
      self.closeTimeout = close * 1000;
      self.heartbeatTimeout = heartbeat * 1000;
      self.transports = io.util.intersect(
          transports.split(',')
        , self.options.transports
      );

      function connect (transports){
        self.transport = self.getTransport(transports);
        if (!self.transport) return self.publish('connect_failed');

        self.connecting = true;
        self.publish('connecting', self.transport.name);
        self.transport.open();

        if (self.options['connect timeout']) {
          self.connectTimeoutTimer = setTimeout(function () {
            if (!self.connected) {
              self.connecting = false;

              if (self.options['try multiple transports']) {
                if (!self.remainingTransports) {
                  self.remainingTransports = self.transports.slice(0);
                }

                var remaining = self.remainingTransports;

                while (remaining.length > 0 && remaining.splice(0,1)[0] !=
                  self.transport.name) {}

                if (remaining.length){
                  connect(remaining);
                } else {
                  self.publish('connect_failed');
                }
              }
            }
          }, self.options['connect timeout']);
        }
      }

      connect();
      if (fn && typeof fn == 'function') {
        self.once('connect', fn);
      }
    });

    return this;
  };

  /**
   * Sends a message.
   *
   * @param {Object} data packet.
   * @returns {io.Socket}
   * @api public
   */

  Socket.prototype.packet = function (data) {
    if (this.connected && !this.doBuffer) {
      this.transport.packet(data);
    } else {
      this.buffer.push(data);
    }

    return this;
  };

  /**
   * Sets buffer state
   *
   * @api private
   */

  Socket.prototype.setBuffer = function (v) {
    this.doBuffer = v;

    if (!v && this.connected && this.buffer.length) {
      this.transport.payload(this.buffer);
      this.buffer = [];
    }
  };

  /**
   * Disconnect the established connect.
   *
   * @returns {io.Socket}
   * @api public
   */

  Socket.prototype.disconnect = function () {
    if (this.connected) {
      if (this.open) {
        this.of('').packet({ type: 'disconnect' });
      }

      // handle disconnection immediately
      this.onDisconnect('booted');
    }

    return this;
  };

  /**
   * Disconnects the socket with a sync XHR.
   *
   * @api private
   */

  Socket.prototype.disconnectSync = function () {
    // ensure disconnection
    var xhr = io.util.request()
      , uri = this.resource + '/' + io.protocol + '/' + this.sessionid;

    xhr.open('GET', uri, true);

    // handle disconnection immediately
    this.onDisconnect('booted');
  };

  /**
   * Check if we need to use cross domain enabled transports. Cross domain would
   * be a different port or different domain name.
   *
   * @returns {Boolean}
   * @api private
   */

  Socket.prototype.isXDomain = function () {
    var locPort = window.location.port || 80;
    return this.options.host !== document.domain || this.options.port != locPort;
  };

  /**
   * Called upon handshake.
   *
   * @api private
   */

  Socket.prototype.onConnect = function () {
    this.connected = true;
    this.connecting = false;
    if (!this.doBuffer) {
      // make sure to flush the buffer
      this.setBuffer(false);
    }
    this.emit('connect');
  };

  /**
   * Called when the transport opens
   *
   * @api private
   */

  Socket.prototype.onOpen = function () {
    this.open = true;
  };

  /**
   * Called when the transport closes.
   *
   * @api private
   */

  Socket.prototype.onClose = function () {
    this.open = false;
  };

  /**
   * Called when the transport first opens a connection
   *
   * @param text
   */

  Socket.prototype.onPacket = function (packet) {
    this.of(packet.endpoint).onPacket(packet);
  };

  /**
   * Handles an error.
   *
   * @api private
   */

  Socket.prototype.onError = function (err) {
    if (err && err.advice) {
      if (err.advice === 'reconnect') {
        this.disconnect();
        this.reconnect();
      }
    }

    this.publish('error', err && err.reason ? err.reason : err);
  };

  /**
   * Called when the transport disconnects.
   *
   * @api private
   */

  Socket.prototype.onDisconnect = function (reason) {
    var wasConnected = this.connected;

    this.connected = false;
    this.connecting = false;
    this.open = false;

    if (wasConnected) {
      this.transport.close();
      this.transport.clearTimeouts();
      this.publish('disconnect', reason);

      if ('booted' != reason && this.options.reconnect && !this.reconnecting) {
        this.reconnect();
      }
    }
  };

  /**
   * Called upon reconnection.
   *
   * @api private
   */

  Socket.prototype.reconnect = function () {
    this.reconnecting = true;
    this.reconnectionAttempts = 0;
    this.reconnectionDelay = this.options['reconnection delay'];

    var self = this
      , maxAttempts = this.options['max reconnection attempts']
      , tryMultiple = this.options['try multiple transports']

    function reset () {
      if (self.connected) {
        self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
      }

      self.removeListener('connect_failed', maybeReconnect);
      self.removeListener('connect', maybeReconnect);

      self.reconnecting = false;

      delete self.reconnectionAttempts;
      delete self.reconnectionDelay;
      delete self.reconnectionTimer;
      delete self.redoTransports;

      self.options['try multiple transports'] = tryMultiple;
    };

    function maybeReconnect () {
      if (!self.reconnecting) {
        return;
      }

      if (self.connected) {
        return reset();
      };

      if (self.connecting && self.reconnecting) {
        return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
      }

      if (self.reconnectionAttempts++ >= maxAttempts) {
        if (!self.redoTransports) {
          self.on('connect_failed', maybeReconnect);
          self.options['try multiple transports'] = true;
          self.transport = self.getTransport();
          self.redoTransports = true;
          self.connect();
        } else {
          self.publish('reconnect_failed');
          reset();
        }
      } else {
        self.reconnectionDelay *= 2; // exponential back off
        self.connect();
        self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
        self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
      }
    };

    this.options['try multiple transports'] = false;
    this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);

    this.on('connect', maybeReconnect);
  };

})(
    'undefined' != typeof io ? io : module.exports
  , 'undefined' != typeof io ? io : module.parent.exports
);
<commit_msg>Removed console.log statement<commit_after>
/**
 * socket.io
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

(function (exports, io) {

  /**
   * Expose constructor.
   */

  exports.Socket = Socket;

  /**
   * Create a new `Socket.IO client` which can establish a persisent
   * connection with a Socket.IO enabled server.
   *
   * @api public
   */

  function Socket (options) {
    this.options = {
        port: 80
      , secure: false
      , document: document
      , resource: 'socket.io'
      , transports: io.transports
      , 'connect timeout': 10000
      , 'try multiple transports': true
      , 'reconnect': true
      , 'reconnection delay': 500
      , 'reopen delay': 3000
      , 'max reconnection attempts': 10
      , 'sync disconnect on unload': true
      , 'auto connect': true
    };

    io.util.merge(this.options, options);

    this.connected = false;
    this.open = false;
    this.connecting = false;
    this.reconnecting = false;
    this.namespaces = {};
    this.buffer = [];
    this.doBuffer = false;

    if (this.options['sync disconnect on unload'] &&
        (!this.isXDomain() || io.util.ua.hasCORS)) {
      var self = this;

      io.util.on(window, 'beforeunload', function () {
        self.disconnectSync();
      }, false);
    }

    if (this.options['auto connect']) {
      this.connect();
    }
};

  /**
   * Apply EventEmitter mixin.
   */

  io.util.mixin(Socket, io.EventEmitter);

  /**
   * Returns a namespace listener/emitter for this socket
   *
   * @api public
   */

  Socket.prototype.of = function (name) {
    if (!this.namespaces[name]) {
      this.namespaces[name] = new io.SocketNamespace(this, name);

      if (name !== '') {
        this.namespaces[name].packet({ type: 'connect' });
      }
    }

    return this.namespaces[name];
  };

  /**
   * Emits the given event to the Socket and all namespaces
   *
   * @api private
   */

  Socket.prototype.publish = function () {
    this.emit.apply(this, arguments);

    var nsp;

    for (var i in this.namespaces) {
      if (this.namespaces.hasOwnProperty(i)) {
        nsp = this.of(i);
        nsp.$emit.apply(nsp, arguments);
      }
    }
  };

  /**
   * Performs the handshake
   *
   * @api private
   */

  function empty () { };

  Socket.prototype.handshake = function (fn) {
    var self = this
      , options = this.options;

    function complete (data) {
      if (data instanceof Error) {
        self.onError(data.message);
      } else {
        fn.apply(null, data.split(':'));
      }
    };

    var url = [
          'http' + (options.secure ? 's' : '') + ':/'
        , options.host + ':' + options.port
        , this.options.resource
        , io.protocol
        , '?t=' + + new Date
      ].join('/');

    if (this.isXDomain()) {
      var insertAt = document.getElementsByTagName('script')[0]
        , script = document.createElement('SCRIPT');

      script.src = url + '&jsonp=' + io.j.length;
      insertAt.parentNode.insertBefore(script, insertAt);

      io.j.push(function (data) {
        complete(data);
        script.parentNode.removeChild(script);
      });
    } else {
      var xhr = io.util.request();

      xhr.open('GET', url);
      xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
          xhr.onreadystatechange = empty;

          if (xhr.status == 200) {
            complete(xhr.responseText);
          } else {
            !self.reconnecting && self.onError(xhr.responseText);
          }
        }
      };
      xhr.send(null);
    }
  };

  /**
   * Find an available transport based on the options supplied in the constructor.
   *
   * @api private
   */

  Socket.prototype.getTransport = function (override) {
    var transports = override || this.transports, match;

    for (var i = 0, transport; transport = transports[i]; i++) {
      if (io.Transport[transport]
        && io.Transport[transport].check(this)
        && (!this.isXDomain() || io.Transport[transport].xdomainCheck())) {
        return new io.Transport[transport](this, this.sessionid);
      }
    }

    return null;
  };

  /**
   * Connects to the server.
   *
   * @param {Function} [fn] Callback.
   * @returns {io.Socket}
   * @api public
   */

  Socket.prototype.connect = function (fn) {
    if (this.connecting) {
      return this;
    }

    var self = this;

    this.handshake(function (sid, heartbeat, close, transports) {
      self.sessionid = sid;
      self.closeTimeout = close * 1000;
      self.heartbeatTimeout = heartbeat * 1000;
      self.transports = io.util.intersect(
          transports.split(',')
        , self.options.transports
      );

      function connect (transports){
        self.transport = self.getTransport(transports);
        if (!self.transport) return self.publish('connect_failed');

        self.connecting = true;
        self.publish('connecting', self.transport.name);
        self.transport.open();

        if (self.options['connect timeout']) {
          self.connectTimeoutTimer = setTimeout(function () {
            if (!self.connected) {
              self.connecting = false;

              if (self.options['try multiple transports']) {
                if (!self.remainingTransports) {
                  self.remainingTransports = self.transports.slice(0);
                }

                var remaining = self.remainingTransports;

                while (remaining.length > 0 && remaining.splice(0,1)[0] !=
                  self.transport.name) {}

                if (remaining.length){
                  connect(remaining);
                } else {
                  self.publish('connect_failed');
                }
              }
            }
          }, self.options['connect timeout']);
        }
      }

      connect();
      if (fn && typeof fn == 'function') {
        self.once('connect', fn);
      }
    });

    return this;
  };

  /**
   * Sends a message.
   *
   * @param {Object} data packet.
   * @returns {io.Socket}
   * @api public
   */

  Socket.prototype.packet = function (data) {
    if (this.connected && !this.doBuffer) {
      this.transport.packet(data);
    } else {
      this.buffer.push(data);
    }

    return this;
  };

  /**
   * Sets buffer state
   *
   * @api private
   */

  Socket.prototype.setBuffer = function (v) {
    this.doBuffer = v;

    if (!v && this.connected && this.buffer.length) {
      this.transport.payload(this.buffer);
      this.buffer = [];
    }
  };

  /**
   * Disconnect the established connect.
   *
   * @returns {io.Socket}
   * @api public
   */

  Socket.prototype.disconnect = function () {
    if (this.connected) {
      if (this.open) {
        this.of('').packet({ type: 'disconnect' });
      }

      // handle disconnection immediately
      this.onDisconnect('booted');
    }

    return this;
  };

  /**
   * Disconnects the socket with a sync XHR.
   *
   * @api private
   */

  Socket.prototype.disconnectSync = function () {
    // ensure disconnection
    var xhr = io.util.request()
      , uri = this.resource + '/' + io.protocol + '/' + this.sessionid;

    xhr.open('GET', uri, true);

    // handle disconnection immediately
    this.onDisconnect('booted');
  };

  /**
   * Check if we need to use cross domain enabled transports. Cross domain would
   * be a different port or different domain name.
   *
   * @returns {Boolean}
   * @api private
   */

  Socket.prototype.isXDomain = function () {
    var locPort = window.location.port || 80;
    return this.options.host !== document.domain || this.options.port != locPort;
  };

  /**
   * Called upon handshake.
   *
   * @api private
   */

  Socket.prototype.onConnect = function () {
    this.connected = true;
    this.connecting = false;
    if (!this.doBuffer) {
      // make sure to flush the buffer
      this.setBuffer(false);
    }
    this.emit('connect');
  };

  /**
   * Called when the transport opens
   *
   * @api private
   */

  Socket.prototype.onOpen = function () {
    this.open = true;
  };

  /**
   * Called when the transport closes.
   *
   * @api private
   */

  Socket.prototype.onClose = function () {
    this.open = false;
  };

  /**
   * Called when the transport first opens a connection
   *
   * @param text
   */

  Socket.prototype.onPacket = function (packet) {
    this.of(packet.endpoint).onPacket(packet);
  };

  /**
   * Handles an error.
   *
   * @api private
   */

  Socket.prototype.onError = function (err) {
    if (err && err.advice) {
      if (err.advice === 'reconnect') {
        this.disconnect();
        this.reconnect();
      }
    }

    this.publish('error', err && err.reason ? err.reason : err);
  };

  /**
   * Called when the transport disconnects.
   *
   * @api private
   */

  Socket.prototype.onDisconnect = function (reason) {
    var wasConnected = this.connected;

    this.connected = false;
    this.connecting = false;
    this.open = false;

    if (wasConnected) {
      this.transport.close();
      this.transport.clearTimeouts();
      this.publish('disconnect', reason);

      if ('booted' != reason && this.options.reconnect && !this.reconnecting) {
        this.reconnect();
      }
    }
  };

  /**
   * Called upon reconnection.
   *
   * @api private
   */

  Socket.prototype.reconnect = function () {
    this.reconnecting = true;
    this.reconnectionAttempts = 0;
    this.reconnectionDelay = this.options['reconnection delay'];

    var self = this
      , maxAttempts = this.options['max reconnection attempts']
      , tryMultiple = this.options['try multiple transports']

    function reset () {
      if (self.connected) {
        self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
      }

      self.removeListener('connect_failed', maybeReconnect);
      self.removeListener('connect', maybeReconnect);

      self.reconnecting = false;

      delete self.reconnectionAttempts;
      delete self.reconnectionDelay;
      delete self.reconnectionTimer;
      delete self.redoTransports;

      self.options['try multiple transports'] = tryMultiple;
    };

    function maybeReconnect () {
      if (!self.reconnecting) {
        return;
      }

      if (self.connected) {
        return reset();
      };

      if (self.connecting && self.reconnecting) {
        return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
      }

      if (self.reconnectionAttempts++ >= maxAttempts) {
        if (!self.redoTransports) {
          self.on('connect_failed', maybeReconnect);
          self.options['try multiple transports'] = true;
          self.transport = self.getTransport();
          self.redoTransports = true;
          self.connect();
        } else {
          self.publish('reconnect_failed');
          reset();
        }
      } else {
        self.reconnectionDelay *= 2; // exponential back off
        self.connect();
        self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
        self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
      }
    };

    this.options['try multiple transports'] = false;
    this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);

    this.on('connect', maybeReconnect);
  };

})(
    'undefined' != typeof io ? io : module.exports
  , 'undefined' != typeof io ? io : module.parent.exports
);
<|endoftext|>


<commit_before>const CopyWebpackPlugin = require('copy-webpack-plugin')
const GitRevisionPlugin = require('git-revision-webpack-plugin')
const path = require('path')
const validate = require('webpack-validator').validateRoot
const webpack = require('webpack')

const isProd = (process.env.NODE_ENV === 'production')
const version = require('./package.json').version + '+' + new GitRevisionPlugin().version()

function getPlugins() {
  const plugins = [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development')
      }
    }),
    new CopyWebpackPlugin([
      {from: 'builtins', to: 'builtins'},
      {from: 'examples', to: 'examples'}
    ])
  ]
  if (isProd) {
    plugins.push(new webpack.optimize.UglifyJsPlugin({
      compress: {warnings: false}
      // TODO: Mangling reduces bundle size by 20%, but breaks things.
      // Need to figure out the right set of exceptions.
      // mangle: {props: true}
    }))
    plugins.push(new webpack.optimize.DedupePlugin())
    plugins.push(new webpack.optimize.AggressiveMergingPlugin())
  }
  return plugins
}

module.exports = validate({
  devtool: isProd ? 'source-map' : 'eval-source-map',
  entry: {
    other: './other.js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loaders: ['babel']
      }
    ]
  },
  output: {
    filename: `./otherjs/${version}/[name].min.js`,
    libraryTarget: 'commonjs2',
    path: path.resolve(__dirname, 'dist'),
    sourceMapFilename: `./otherjs/${version}/[name].js.map`
  },
  plugins: getPlugins()
})
<commit_msg>Enable CORS on the development server.<commit_after>const CopyWebpackPlugin = require('copy-webpack-plugin')
const GitRevisionPlugin = require('git-revision-webpack-plugin')
const path = require('path')
const validate = require('webpack-validator').validateRoot
const webpack = require('webpack')

const isProd = (process.env.NODE_ENV === 'production')
const version = require('./package.json').version + '+' + new GitRevisionPlugin().version()

function getPlugins() {
  const plugins = [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development')
      }
    }),
    new CopyWebpackPlugin([
      {from: 'builtins', to: 'builtins'},
      {from: 'examples', to: 'examples'}
    ])
  ]
  if (isProd) {
    plugins.push(new webpack.optimize.UglifyJsPlugin({
      compress: {warnings: false}
      // TODO: Mangling reduces bundle size by 20%, but breaks things.
      // Need to figure out the right set of exceptions.
      // mangle: {props: true}
    }))
    plugins.push(new webpack.optimize.DedupePlugin())
    plugins.push(new webpack.optimize.AggressiveMergingPlugin())
  }
  return plugins
}

module.exports = validate({
  devServer: {
    headers: {
      'Access-Control-Allow-Origin': '*'
    }
  },
  devtool: isProd ? 'source-map' : 'eval-source-map',
  entry: {
    other: './other.js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loaders: ['babel']
      }
    ]
  },
  output: {
    filename: `./otherjs/${version}/[name].min.js`,
    libraryTarget: 'commonjs2',
    path: path.resolve(__dirname, 'dist'),
    sourceMapFilename: `./otherjs/${version}/[name].js.map`
  },
  plugins: getPlugins()
})
<|endoftext|>