<commit_before>var assert = require('assert');
var async = require('async');
var util = require('util');

var helper = require('../../test-helper.js');
var Client = require('../../../lib/client.js');
var types = require('../../../lib/types');
var utils = require('../../../lib/utils.js');
var policies = require('../../../lib/policies');

describe('Client', function () {
  this.timeout(120000);
  afterEach(helper.ccmHelper.remove);
  it('should handle parallel insert and select', function (done) {
    var client = newInstance({policies: { retry: new RetryMultipleTimes(2)}});
    //var client = newInstance();
    var keyspace = helper.getRandomName('ks');
    var table = keyspace + '.' + helper.getRandomName('tbl');
    var selectQuery = 'SELECT * FROM ' + table;
    var insertQuery = util.format('INSERT INTO %s (id, text_sample, timestamp_sample) VALUES (?, ?, ?)', table);
    var times = 2000;
    async.series([
      helper.ccmHelper.start(3),
      function createKs(next) {
        client.execute(helper.createKeyspaceCql(keyspace, 3), [], helper.waitSchema(client, next));
      },
      function createTable(next) {
        client.execute(helper.createTableCql(table), [], helper.waitSchema(client, next));
      },
      function testCase(next) {
        async.parallel([insert, select], next);
      }
    ], done);
    function insert(callback) {
      async.eachLimit(new Array(times), 500, function (i, next) {
        var options = {
          prepare: 1,
          consistency: types.consistencies.quorum};
        client.execute(insertQuery, [types.uuid(), 'text' + i, new Date()], options, next);
      }, callback);
    }
    function select(callback) {
      var resultCount = 0;
      async.eachLimit(new Array(times), 200, function (i, next) {
        var options = {
          prepare: 1,
          consistency: types.consistencies.one};
        client.execute(selectQuery, [], options, function (err, result) {
          assert.ifError(err);
          assert.ok(result.rows);
          resultCount += result.rows.length;
          next();
        });
      }, function (err) {
        assert.ifError(err);
        assert.ok(resultCount > times, 'it should have selected the rows inserted in parallel');
        callback();
      });
    }
  });
  it('should handle parallel insert and select with nodes failing', function (done) {
    var client = newInstance({policies: { retry: new RetryMultipleTimes(2)}});
    var keyspace = helper.getRandomName('ks');
    var table = keyspace + '.' + helper.getRandomName('tbl');
    var selectQuery = 'SELECT * FROM ' + table;
    var insertQuery = util.format('INSERT INTO %s (id, text_sample, timestamp_sample) VALUES (?, ?, ?)', table);
    var times = 2000;
    async.series([
      helper.ccmHelper.start(3),
      function createKs(next) {
        client.execute(helper.createKeyspaceCql(keyspace, 3), [], helper.waitSchema(client, next));
      },
      function createTable(next) {
        client.execute(helper.createTableCql(table), [], helper.waitSchema(client, next));
      },
      function testCase(next) {
        async.parallel([insert, select, killANode], next);
      }
    ], done);
    function insert(callback) {
      async.eachLimit(new Array(times), 500, function (i, next) {
        var options = {
          prepare: 1,
          consistency: types.consistencies.quorum};
        client.execute(insertQuery, [types.uuid(), 'text' + i, new Date()], options, next);
      }, callback);
    }
    function select(callback) {
      var resultCount = 0;
      async.eachLimit(new Array(times), 100, function (i, next) {
        var options = {
          prepare: 1,
          consistency: types.consistencies.one};
        client.execute(selectQuery, [], options, function (err, result) {
          assert.ifError(err);
          assert.ok(result.rows);
          resultCount += result.rows.length;
          next();
        });
      }, function (err) {
        assert.ifError(err);
        assert.ok(resultCount > times, 'it should have selected the rows inserted in parallel');
        callback();
      });
    }
    function killANode(callback) {
      setTimeout(function () {
        helper.ccmHelper.exec(['node2', 'stop'], callback);
      }, 500);
    }
  });
  it('should handle parallel insert and select of large blobs', function (done) {
    var client = newInstance({policies: { retry: new RetryMultipleTimes(2)}});
    var keyspace = helper.getRandomName('ks');
    var table = helper.getRandomName('tbl');
    var clientInsert = newInstance({keyspace: keyspace, policies: { retry: new RetryMultipleTimes(2)}});
    var clientSelect = newInstance({keyspace: keyspace, policies: { retry: new RetryMultipleTimes(2)}});
    var selectQuery = 'SELECT * FROM ' + table + ' LIMIT 10';
    var insertQuery = util.format('INSERT INTO %s (id, double_sample, blob_sample) VALUES (?, ?, ?)', table);
    var times = 500;
    var idArray = [];
    async.series([
      helper.ccmHelper.start(3),
      function createKs(next) {
        client.execute(helper.createKeyspaceCql(keyspace, 3), [], helper.waitSchema(client, next));
      },
      function createTable(next) {
        client.execute(helper.createTableCql(keyspace + '.' + table), [], helper.waitSchema(client, next));
      },
      function testCase(next) {
        async.parallel([insert, select], next);
      }
    ], done);
    function insert(callback) {
      var n = 0;
      async.eachLimit(new Array(times), 100, function (i, next) {
        i = ++n;
        var options = {
          prepare: 1,
          consistency: types.consistencies.quorum};
        var buf = new Buffer(i * 1024);
        buf.write(i + ' dummy values ' + (new Array(100)).join(i.toString()));
        clientInsert.execute(insertQuery, [types.uuid(), buf.length, buf], options, next);
      }, callback);
    }
    function select(callback) {
      var resultCount = 0;
      async.eachLimit(new Array(times*10), 2, function (i, next) {
        var options = {
          prepare: 1,
          consistency: types.consistencies.one,
          autoPage: true};
        clientSelect.execute(selectQuery, [], options, function (err, result) {
          assert.ifError(err);
          assert.ok(result);
          if (result.rows) {
            result.rows.forEach(function (row) {
              assert.strictEqual(row['blob_sample'].length, row['double_sample']);
              resultCount++;
            });
          }
          next();
        });
      }, function (err) {
        assert.ifError(err);
        assert.ok(resultCount > times, 'it should have selected the rows inserted in parallel: ' + resultCount);
        callback();
      });
    }
  });
});

/**
 * A retry policy for testing purposes only, retries for a number of times
 * @param {Number} times
 * @constructor
 */
function RetryMultipleTimes(times) {
  this.times = times;
}

util.inherits(RetryMultipleTimes, policies.retry.RetryPolicy);

RetryMultipleTimes.prototype.onReadTimeout = function (requestInfo, consistency, received, blockFor, isDataPresent) {
  if (requestInfo.nbRetry > this.times) {
    return this.rethrowResult();
  }
  return this.retryResult();
};

RetryMultipleTimes.prototype.onUnavailable = function (requestInfo, consistency, required, alive) {
  if (requestInfo.nbRetry > this.times) {
    return this.rethrowResult();
  }
  return this.retryResult();
};

RetryMultipleTimes.prototype.onWriteTimeout = function (requestInfo, consistency, received, blockFor, writeType) {
  if (requestInfo.nbRetry > this.times) {
    return this.rethrowResult();
  }
  return this.retryResult();
};

/**
 * @returns {Client}
 */
function newInstance(options) {
  return new Client(utils.extend({}, helper.baseOptions, options));
}
<commit_msg>Stress tests: reduce the amount of rows selected<commit_after>var assert = require('assert');
var async = require('async');
var util = require('util');

var helper = require('../../test-helper.js');
var Client = require('../../../lib/client.js');
var types = require('../../../lib/types');
var utils = require('../../../lib/utils.js');
var policies = require('../../../lib/policies');

describe('Client', function () {
  this.timeout(180000);
  afterEach(helper.ccmHelper.remove);
  it('should handle parallel insert and select', function (done) {
    var client = newInstance({policies: { retry: new RetryMultipleTimes(2)}, encoding: { copyBuffer: false}});
    //var client = newInstance();
    var keyspace = helper.getRandomName('ks');
    var table = keyspace + '.' + helper.getRandomName('tbl');
    var selectQuery = 'SELECT * FROM ' + table;
    var insertQuery = util.format('INSERT INTO %s (id, text_sample, timestamp_sample) VALUES (?, ?, ?)', table);
    var times = 2000;
    async.series([
      helper.ccmHelper.start(3),
      function createKs(next) {
        client.execute(helper.createKeyspaceCql(keyspace, 3), [], helper.waitSchema(client, next));
      },
      function createTable(next) {
        client.execute(helper.createTableCql(table), [], helper.waitSchema(client, next));
      },
      function testCase(next) {
        async.parallel([insert, select], next);
      }
    ], done);
    function insert(callback) {
      async.eachLimit(new Array(times), 500, function (i, next) {
        var options = {
          prepare: 1,
          consistency: types.consistencies.quorum};
        client.execute(insertQuery, [types.uuid(), 'text' + i, new Date()], options, next);
      }, callback);
    }
    function select(callback) {
      var resultCount = 0;
      async.eachLimit(new Array(Math.floor(times / 5)), 200, function (i, next) {
        var options = {
          prepare: 1,
          consistency: types.consistencies.one};
        client.execute(selectQuery, [], options, function (err, result) {
          assert.ifError(err);
          assert.ok(result.rows);
          resultCount += result.rows.length;
          next();
        });
      }, function (err) {
        assert.ifError(err);
        assert.ok(resultCount > times, 'it should have selected the rows inserted in parallel');
        callback();
      });
    }
  });
  it('should handle parallel insert and select with nodes failing', function (done) {
    var client = newInstance({policies: { retry: new RetryMultipleTimes(2)}});
    var keyspace = helper.getRandomName('ks');
    var table = keyspace + '.' + helper.getRandomName('tbl');
    var selectQuery = 'SELECT * FROM ' + table;
    var insertQuery = util.format('INSERT INTO %s (id, text_sample, timestamp_sample) VALUES (?, ?, ?)', table);
    var times = 2000;
    async.series([
      helper.ccmHelper.start(3),
      function createKs(next) {
        client.execute(helper.createKeyspaceCql(keyspace, 3), [], helper.waitSchema(client, next));
      },
      function createTable(next) {
        client.execute(helper.createTableCql(table), [], helper.waitSchema(client, next));
      },
      function testCase(next) {
        async.parallel([insert, select, killANode], next);
      }
    ], done);
    function insert(callback) {
      async.eachLimit(new Array(times), 500, function (i, next) {
        var options = {
          prepare: 1,
          consistency: types.consistencies.quorum};
        client.execute(insertQuery, [types.uuid(), 'text' + i, new Date()], options, next);
      }, callback);
    }
    function select(callback) {
      var resultCount = 0;
      async.eachLimit(new Array(Math.floor(times / 5)), 100, function (i, next) {
        var options = {
          prepare: 1,
          consistency: types.consistencies.one};
        client.execute(selectQuery, [], options, function (err, result) {
          assert.ifError(err);
          assert.ok(result.rows);
          resultCount += result.rows.length;
          next();
        });
      }, function (err) {
        assert.ifError(err);
        assert.ok(resultCount > times, 'it should have selected the rows inserted in parallel');
        callback();
      });
    }
    function killANode(callback) {
      setTimeout(function () {
        helper.ccmHelper.exec(['node2', 'stop'], callback);
      }, 500);
    }
  });
  it('should handle parallel insert and select of large blobs', function (done) {
    var client = newInstance({policies: { retry: new RetryMultipleTimes(2)}});
    var keyspace = helper.getRandomName('ks');
    var table = helper.getRandomName('tbl');
    var clientInsert = newInstance({keyspace: keyspace, policies: { retry: new RetryMultipleTimes(2)}});
    var clientSelect = newInstance({keyspace: keyspace, policies: { retry: new RetryMultipleTimes(2)}});
    var selectQuery = 'SELECT * FROM ' + table + ' LIMIT 10';
    var insertQuery = util.format('INSERT INTO %s (id, double_sample, blob_sample) VALUES (?, ?, ?)', table);
    var times = 500;
    async.series([
      helper.ccmHelper.start(3),
      function createKs(next) {
        client.execute(helper.createKeyspaceCql(keyspace, 3), [], helper.waitSchema(client, next));
      },
      function createTable(next) {
        client.execute(helper.createTableCql(keyspace + '.' + table), [], helper.waitSchema(client, next));
      },
      function testCase(next) {
        async.parallel([insert, select], next);
      }
    ], done);
    function insert(callback) {
      var n = 0;
      async.eachLimit(new Array(times), 100, function (i, next) {
        i = ++n;
        var options = {
          prepare: 1,
          consistency: types.consistencies.quorum};
        var buf = new Buffer(i * 1024);
        buf.write(i + ' dummy values ' + (new Array(100)).join(i.toString()));
        clientInsert.execute(insertQuery, [types.uuid(), buf.length, buf], options, next);
      }, callback);
    }
    function select(callback) {
      var resultCount = 0;
      async.eachLimit(new Array(times*10), 2, function (i, next) {
        var options = {
          prepare: 1,
          consistency: types.consistencies.one,
          autoPage: true};
        clientSelect.execute(selectQuery, [], options, function (err, result) {
          assert.ifError(err);
          assert.ok(result);
          if (result.rows) {
            result.rows.forEach(function (row) {
              assert.strictEqual(row['blob_sample'].length, row['double_sample']);
              resultCount++;
            });
          }
          next();
        });
      }, function (err) {
        assert.ifError(err);
        assert.ok(resultCount > times, 'it should have selected the rows inserted in parallel: ' + resultCount);
        callback();
      });
    }
  });
});

/**
 * A retry policy for testing purposes only, retries for a number of times
 * @param {Number} times
 * @constructor
 */
function RetryMultipleTimes(times) {
  this.times = times;
}

util.inherits(RetryMultipleTimes, policies.retry.RetryPolicy);

RetryMultipleTimes.prototype.onReadTimeout = function (requestInfo, consistency, received, blockFor, isDataPresent) {
  if (requestInfo.nbRetry > this.times) {
    return this.rethrowResult();
  }
  return this.retryResult();
};

RetryMultipleTimes.prototype.onUnavailable = function (requestInfo, consistency, required, alive) {
  if (requestInfo.nbRetry > this.times) {
    return this.rethrowResult();
  }
  return this.retryResult();
};

RetryMultipleTimes.prototype.onWriteTimeout = function (requestInfo, consistency, received, blockFor, writeType) {
  if (requestInfo.nbRetry > this.times) {
    return this.rethrowResult();
  }
  return this.retryResult();
};

/**
 * @returns {Client}
 */
function newInstance(options) {
  return new Client(utils.extend({}, helper.baseOptions, options));
}
<|endoftext|>


<commit_before>import React from 'react'
import { Motion, spring } from 'react-motion'
import { line } from 'd3-shape'
import { scaleLinear } from 'd3-scale'

const getX = d => Array.isArray(d) ? d[0] : d.x
const getY = d => Array.isArray(d) ? d[1] : d.y

const Stack = React.createClass({
  render () {
    const {
      children
    } = this.props

    return (
      <g>
        {children}
      </g>
    )
  }
})

const Line = React.createClass({
  getDefaultProps () {
    return {
      strokeWidth: '2',
      stroke: 'black',
      fill: 'transparent'
    }
  },
  render () {
    const {
      x1,
      y1,
      x2,
      y2,
      ...rest
    } = this.props
    return (
      <line
        x1={x1}
        y1={y1}
        x2={x2}
        y2={y2}
        {...rest}
      />
    )
  }
})

const Curve = React.createClass({
  getDefaultProps () {
    return {
      // Set up some default getters for our x and y values
      getX,
      getY,
      strokeWidth: '2',
      stroke: 'royalblue',
      fill: 'transparent'
    }
  },
  render () {
    const {
      data,
      getX,
      getY,
      scaleX,
      scaleY,
      ...rest
    } = this.props

    // For react-motion to interpolate correctly, it needs to interpolate
    // the x and y values independently for each point. So we create an
    // object that maps to the available points in the data array
    const pathKeyPrefix = 'path_'
    const pathXPrefix = pathKeyPrefix + 'x_'
    const pathYPrefix = pathKeyPrefix + 'y_'

    const pathSpringMap = {}
    data.forEach((d, i) => {
      // Interpolate each x and y with the default spring
      pathSpringMap[pathXPrefix + i] = spring(scaleX(getX(d)))
      pathSpringMap[pathYPrefix + i] = spring(scaleY(getY(d)))
    })

    return (
      <Motion
        style={{
          // anything being animated should have a key/value here
          ...pathSpringMap
        }}
      >
        {interpolated => {
          // Map back through the data, using the interpolated data point
          const interData = data.map((d, i) => [
            interpolated[pathXPrefix + i],
            interpolated[pathYPrefix + i]
          ])
          // Create the path using the interpolated data
          const path = line()(interData)
          return (
            <path
              {...rest}
              d={path}
            />
          )
        }}
      </Motion>
    )
  }
})

const Scale = ({
  data,
  axis,
  width,
  height
}) => {
  const getter = axis === 'y' ? getY : getX
  const vals = []

  data.forEach(series => {
    series.forEach(d => {
      vals.push(getter(d))
    })
  })

  const min = Math.min(...vals)
  const max = Math.max(...vals)

  return scaleLinear()
    .domain([min, max])
    .range([0, axis === 'y' ? height : width])
}

const Axis = React.createClass({
  render () {
    const {
      axis,
      scale
    } = this.props

    const range = scale.range()
    const x1 = range[0]
    const y1 = range[0]
    const x2 = axis === 'x' ? range[1] : range[0]
    const y2 = axis === 'x' ? range[0] : range[1]

    const ticks = scale.ticks()

    console.log(ticks)

    return (
      <g>
        <Line
          x1={x1}
          y1={y1}
          x2={x2}
          y2={y2}
        />
      </g>
    )
  }
})

export default React.createClass({
  render () {
    const {
      data,
      width,
      height
    } = this.props

    const scaleX = Scale({
      data,
      axis: 'x',
      width,
      height
    })

    const scaleY = Scale({
      data,
      axis: 'y',
      width,
      height
    })

    return (
      <svg
        width={width}
        height={height}
        viewBox={`0 0 ${width} ${height}`}
      >
        <Stack>
          {data.map((series, i) => (
            <Curve
              key={i}
              data={series}
              scaleX={scaleX}
              scaleY={scaleY}
            />
          ))}
        </Stack>
        <Axis
          axis='x'
          scale={scaleX}
        />
        <Axis
          axis='y'
          scale={scaleY}
        />
      </svg>
    )
  }
})
<commit_msg>Animated Lines<commit_after>import React from 'react'
import { Motion, spring } from 'react-motion'
import { line } from 'd3-shape'
import { scaleLinear } from 'd3-scale'

const getX = d => Array.isArray(d) ? d[0] : d.x
const getY = d => Array.isArray(d) ? d[1] : d.y

// Primitives

const Line = React.createClass({
  getDefaultProps () {
    return {
      strokeWidth: '2',
      stroke: 'black',
      fill: 'transparent'
    }
  },
  render () {
    const {
      x1,
      y1,
      x2,
      y2,
      ...rest
    } = this.props

    const animated = {
      x1: spring(x1),
      y1: spring(y1),
      x2: spring(x2),
      y2: spring(y2)
    }

    return (
      <Motion
        style={{
          // anything being animated should have a key/value here
          ...animated
        }}
      >
        {({
          x1,
          y1,
          x2,
          y2
        }) => (
          <line
            x1={x1}
            y1={y1}
            x2={x2}
            y2={y2}
            {...rest}
          />
        )}
      </Motion>
    )
  }
})

const Text = React.createClass({
  getDefaultProps () {
    return {
      fontFamily: 'Helvetica',
      fontSize: 10
    }
  },
  render () {
    const {
      x,
      y,
      ...rest
    } = this.props

    const animated = {
      x: spring(x),
      y: spring(y)
    }

    return (
      <Motion
        style={{
          // anything being animated should have a key/value here
          ...animated
        }}
      >
        {({
          x,
          y
        }) => (
          <text
            x={x}
            y={y}
            {...rest}
          />
        )}
      </Motion>
    )
  }
})

// const Circle = React.createClass({
//   getDefaultProps () {
//     return {
//       r: 3,
//       strokeWidth: '2',
//       stroke: 'red',
//       fill: 'transparent'
//     }
//   },
//   render () {
//     const {
//       x,
//       y,
//       r,
//       ...rest
//     } = this.props
//     return (
//       <circle
//         {...rest}
//         cx={x}
//         cy={y}
//         r={r}
//       />
//     )
//   }
// })

const Curve = React.createClass({
  getDefaultProps () {
    return {
      // Set up some default getters for our x and y values
      getX,
      getY,
      strokeWidth: '2',
      stroke: 'royalblue',
      fill: 'transparent'
    }
  },
  render () {
    const {
      data,
      getX,
      getY,
      scaleX,
      scaleY,
      ...rest
    } = this.props

    // For react-motion to interpolate correctly, it needs to interpolate
    // the x and y values independently for each point. So we create an
    // object that maps to the available points in the data array
    const pathKeyPrefix = 'path_'
    const pathXPrefix = pathKeyPrefix + 'x_'
    const pathYPrefix = pathKeyPrefix + 'y_'

    const pathSpringMap = {}
    data.forEach((d, i) => {
      // Interpolate each x and y with the default spring
      pathSpringMap[pathXPrefix + i] = spring(scaleX(getX(d)))
      pathSpringMap[pathYPrefix + i] = spring(scaleY(getY(d)))
    })

    return (
      <Motion
        style={{
          // anything being animated should have a key/value here
          ...pathSpringMap
        }}
      >
        {interpolated => {
          // Map back through the data, using the interpolated data point
          const interData = data.map((d, i) => [
            interpolated[pathXPrefix + i],
            interpolated[pathYPrefix + i]
          ])
          // Create the path using the interpolated data
          const path = line()(interData)
          return (
            <path
              {...rest}
              d={path}
            />
          )
        }}
      </Motion>
    )
  }
})

// Components

const Stack = React.createClass({
  render () {
    const {
      children
    } = this.props

    return (
      <g>
        {children}
      </g>
    )
  }
})

const Scale = ({
  data,
  axis,
  width,
  height
}) => {
  const getter = axis === 'y' ? getY : getX
  const vals = []

  data.forEach(series => {
    series.forEach(d => {
      vals.push(getter(d))
    })
  })

  const min = Math.min(...vals)
  const max = Math.max(...vals)

  return scaleLinear()
    .domain([min, max])
    .range([0, axis === 'y' ? height : width])
}

const Axis = React.createClass({
  render () {
    const {
      axis,
      scale,
      height,
      width
    } = this.props

    const range = scale.range()

    const x1 = 0
    const y1 = axis === 'x' ? height : 0

    const x2 = axis === 'x' ? width : 0
    const y2 = axis === 'x' ? height : range[1]

    const ticks = scale.ticks()

    return (
      <g>
        <Line
          x1={x1}
          y1={y1}
          x2={x2}
          y2={y2}
          stroke={axis === 'y' ? 'red' : 'green'}
        />
        <g>
          {ticks.map((d, i) => {
            const zero = 0
            const val = scale(d)
            const x = axis === 'y' ? zero : val
            const y = axis === 'y' ? val : height
            return (
              <Line
                key={i}
                x1={x}
                y1={y}
                x2={axis === 'y' ? x + 5 : x}
                y2={axis === 'y' ? y : y - 5}
                stroke={axis === 'y' ? 'red' : 'green'}
              />
            )
          })}
        </g>
        <g>
          {ticks.map((d, i) => {
            const zero = 0
            const val = scale(d)
            const x = axis === 'y' ? zero : val
            const y = axis === 'y' ? val : height
            return (
              <Text
                key={i}
                x={axis === 'y' ? x + 5 : x}
                y={axis === 'y' ? y : y - 5}
                stroke={axis === 'y' ? 'red' : 'green'}
              >
                {d}
              </Text>
            )
          })}
        </g>
      </g>
    )
  }
})

export default React.createClass({
  render () {
    const {
      data,
      width,
      height
    } = this.props

    const scaleX = Scale({
      data,
      axis: 'x',
      width,
      height
    })

    const scaleY = Scale({
      data,
      axis: 'y',
      width,
      height
    })

    return (
      <svg
        width={width}
        height={height}
        viewBox={`0 0 ${width} ${height}`}
      >
        <Stack>
          {data.map((series, i) => (
            <Curve
              key={i}
              data={series}
              scaleX={scaleX}
              scaleY={scaleY}
            />
          ))}
        </Stack>
        <Axis
          axis='x'
          scale={scaleX}
          height={height}
          width={width}
        />
        <Axis
          axis='y'
          scale={scaleY}
          height={height}
          width={width}
        />
      </svg>
    )
  }
})
<|endoftext|>


<commit_before>/*
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var wrench = require('wrench');
var fs = require('fs');
var executor = require('nscale-util').executor();
var sshCheck = require('nscale-util').sshcheck();
var ku = require('./kutils');

/**
 * sync code and assets
 */
module.exports = function(loadConfig) {

  /**
   * sync the container source code and assets
   */
  var synch = function(system, containerDef, out, cb) {
    loadConfig(system, function(err, options) {
      if (err) { return cb(err); }

      var uh = ku.parseGitUrl(containerDef.specific.repositoryUrl, options);
      var updateCmd;
      var checkoutCmd = 'git checkout ' + uh.branch;
      var path = system.repoPath + '/workspace';
      var doSync = true;

      if (options.hasOwnProperty('pullOnCompile')) {
        doSync = options.pullOnCompile;
      }
      console.log('do sync => ' + doSync);

      function execute() {
        executor.exec('live', updateCmd, path, out, function(err) {
          if (err) { return cb(err); }

          path = system.repoPath + '/workspace/' + uh.repo;
          executor.exec('live', checkoutCmd, path, out, function(err) {
            cb(err);
          });
        });
      }
      out.stdout('--> synchronizing ' + containerDef.id, 'info');

      if (fs.existsSync(path + '/' + uh.repo)) {
        updateCmd = 'git fetch';
        path += '/' + uh.repo;
        checkoutCmd += '; git pull origin ' + uh.branch;
      }
      else {
        updateCmd = 'git clone ' + uh.cloneUrl;
        doSync = true;
      }

      if (doSync) {
        wrench.mkdirSyncRecursive(path, 511);
        if (uh.type === 'git') {
          sshCheck.check(uh.host, uh.user, options.sshKeyPath, out, function(err) {
            if (err) { return cb(err); }
            execute();
          });
        }
        else {
          execute();
        }
      }
      else {
        out.stdout('--> sync aborted for ' + containerDef.id + ' pullOnCompile flag set to false', 'info');
        cb();
      }
    });
  };

  return {
    synch: synch
  };
};

<commit_msg>No console.log in synchrotron.<commit_after>/*
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var wrench = require('wrench');
var fs = require('fs');
var executor = require('nscale-util').executor();
var sshCheck = require('nscale-util').sshcheck();
var ku = require('./kutils');

/**
 * sync code and assets
 */
module.exports = function(loadConfig) {

  /**
   * sync the container source code and assets
   */
  var synch = function(system, containerDef, out, cb) {
    loadConfig(system, function(err, options) {
      if (err) { return cb(err); }

      var uh = ku.parseGitUrl(containerDef.specific.repositoryUrl, options);
      var updateCmd;
      var checkoutCmd = 'git checkout ' + uh.branch;
      var path = system.repoPath + '/workspace';
      var doSync = true;

      if (options.hasOwnProperty('pullOnCompile')) {
        doSync = options.pullOnCompile;
      }

      function execute() {
        executor.exec('live', updateCmd, path, out, function(err) {
          if (err) { return cb(err); }

          path = system.repoPath + '/workspace/' + uh.repo;
          executor.exec('live', checkoutCmd, path, out, function(err) {
            cb(err);
          });
        });
      }

      out.stdout('--> synchronizing ' + containerDef.id, 'info');

      if (fs.existsSync(path + '/' + uh.repo)) {
        updateCmd = 'git fetch';
        path += '/' + uh.repo;
        checkoutCmd += '; git pull origin ' + uh.branch;
      }
      else {
        updateCmd = 'git clone ' + uh.cloneUrl;
        doSync = true;
      }

      if (doSync) {
        wrench.mkdirSyncRecursive(path, 511);
        if (uh.type === 'git') {
          sshCheck.check(uh.host, uh.user, options.sshKeyPath, out, function(err) {
            if (err) { return cb(err); }
            execute();
          });
        }
        else {
          execute();
        }
      }
      else {
        out.stdout('--> sync aborted for ' + containerDef.id + ' pullOnCompile flag set to false', 'info');
        cb();
      }
    });
  };

  return {
    synch: synch
  };
};

<|endoftext|>


<commit_before>//      CLMS-model
//      Copyright 2015 Rappsilber Laboratory, Edinburgh University
//
//      authors: Colin Combe, Martin Graham
//
//      SearchResultsModel.js

    var CLMS = CLMS || {};
    CLMS.model = CLMS.model || {};
    CLMS.uniprotAccRegex = /[OPQ][0-9][A-Z0-9]{3}[0-9]|[A-NR-Z][0-9]([A-Z][A-Z0-9]{2}[0-9]){1,2}/;

    CLMS.model.SearchResultsModel = Backbone.Model.extend ({
        //http://stackoverflow.com/questions/19835163/backbone-model-collection-property-not-empty-on-new-model-creation
        defaults :  function() {
            return {
                participants: new Map (), //map
                //peptides: new Map (), //map
                matches: [],
                crossLinks: new Map(), //map
                scoreExtent: null,
                searches: new Map(),
                decoysPresent: false,
            };
        },

        initialize: function (options) {

            var defaultOptions = {};

            this.options = _.extend(defaultOptions, options);

            var self = this;
            this.set("sid", this.options.sid);

            //search meta data
            var searches = new Map();
            for(var propertyName in this.options.searches) {
                var search = this.options.searches[propertyName];
                searches.set(propertyName, search);
            }
            this.set("searches", searches);

			//enzyme specificity
            var postAaSet = new Set();
            var aaConstrainedCTermSet = new Set();
            var aaConstrainedNTermSet = new Set();
            var searchArray = Array.from(searches.values());
            var searchCount = searchArray.length;
            for (var s = 0; s < searchCount; s++) {
                var search = searchArray[s];
                var enzymes = search.enzymes;
                var enzymeCount = enzymes.length;
                for (var e = 0; e < enzymeCount ; e++) {
                    var enzymeDescription = enzymes[e].description;
                    var postAARegex = /DIGESTED:(.*?);/g;
                    var postAAMatch = postAARegex.exec(enzymeDescription);
                    getResiduesFromEnzymeDescription (postAAMatch, postAaSet);

                    var cTermRegex = /CTERMDIGEST:(.*?);/g;
                    var ctMatch = cTermRegex.exec(enzymeDescription);
                    getResiduesFromEnzymeDescription (ctMatch, aaConstrainedCTermSet);

					var nTermRegex = /NTERMDIGEST:(.*?);/g;
					var ntMatch = nTermRegex.exec(enzymeDescription);
                    getResiduesFromEnzymeDescription (ntMatch, aaConstrainedNTermSet);
                }
            }

            function getResiduesFromEnzymeDescription (regexMatch, residueSet) {
				if (regexMatch && regexMatch.length > 1) {
					var resArray = regexMatch[1].split(',');
					var resCount = resArray.length;
                    for (var r = 0; r < resCount; r++){
						residueSet.add(resArray[r]);
					}
				}
			}

			var enzymeSpecificity = [];
			addEnzymeSpecificityResidues(postAaSet, "Post AA constrained");
			addEnzymeSpecificityResidues(aaConstrainedCTermSet, "AA constrained c-term");
			addEnzymeSpecificityResidues(aaConstrainedNTermSet, "AA constrained n-term");
			this.set("enzymeSpecificity", enzymeSpecificity);

            function addEnzymeSpecificityResidues (residueSet, type) {
				var resArray = Array.from(residueSet.values());
				var resCount = resArray.length;
				for (var r = 0; r < resCount; r++) {
					enzymeSpecificity.push(
						{aa: resArray[r] , type: type}
					);
				}
			}

			//crosslink specificity
			var linkableResSet = new Set();
            for (var s = 0; s < searchCount; s++) {
                var search = searchArray[s];
                var crosslinkers = search.crosslinkers;
                var crosslinkerCount = crosslinkers.length;
                for (var cl = 0; cl < crosslinkerCount ; cl++) {
                    var crosslinkerDescription = crosslinkers[cl].description;
                    var linkedAARegex = /LINKEDAMINOACIDS:(.*?);/g;
                    var result = null;
                    while ((result = linkedAARegex.exec(crosslinkerDescription)) !== null) {
						var resArray = result[1].split(',');
						var resCount = resArray.length;
						for (var r = 0; r < resCount; r++){
							var resRegex = /([A-Z])(.*)?/
							var resMatch = resRegex.exec(resArray[r]);
							if (resMatch) {
								linkableResSet.add(resMatch[1]);
							}
						}
					}
                }
            }

			this.set("crosslinkerSpecificity", Array.from(linkableResSet));

            //saved config should end up including filter settings not just xiNET layout
            this.set("xiNETLayout", options.xiNETLayout);
            //spectrum sources
            var spectrumSources = new Map();
            var specSource;
            for (var propertyName in this.options.spectrumSources) {
                specSource = this.options.spectrumSources[propertyName];
                spectrumSources.set(+specSource.id, specSource.name);
            }
            this.set("spectrumSources", spectrumSources);

            // we will be removing modification info from sequences
            var notUpperCase = /[^A-Z]/g;

            var participants = new Map();
            var proteins = this.options.proteins;
            var participant;
            for (var propertyName in proteins) {
                notUpperCase.lastIndex = 0;
                participant = proteins[propertyName];
                participant.sequence = participant.seq_mods.replace(notUpperCase, '');
                participant.size = participant.sequence.length;
                participant.crossLinks = [];
                participant.hidden = false;//?
                participants.set(participant.id, participant);
            }
            this.set("participants", participants);

            //peptides
            var peptides = new Map();
            var peptide;
            for (var propertyName in this.options.peptides) {
                notUpperCase.lastIndex = 0;
                peptide = this.options.peptides[propertyName];
                peptide.sequence = peptide.seq_mods.replace(notUpperCase, '');
                peptides.set(peptide.id, peptide);
            }
            //this.set("peptides", peptides);

            var crossLinks = this.get("crossLinks");

            var rawMatches = this.options.rawMatches;
            if (rawMatches) {
                var matches = this.get("matches");
                var minScore = Number.MIN_VALUE;
                var maxScore = Number.MAX_VALUE;

                var l = rawMatches.length, match;
                for (var i = 0; i < l; i++) {
                    //TODO: this will need updated for ternary or higher order crosslinks
                    if ((i < (l - 1)) && rawMatches[i].id == rawMatches[i+1].id){
                        match = new CLMS.model.SpectrumMatch (this, participants, crossLinks, peptides, [rawMatches[i], rawMatches[i+1]]);
                        i++;
                    }
                    else {
                        match = new CLMS.model.SpectrumMatch (this, participants, crossLinks, peptides, [rawMatches[i]]);
                    }

                    matches.push(match);//set(match.id, match);

                    if (match.score > maxScore) {
                        maxScore = match.score;
                    }
                    else if (match.score < minScore) {
                        minScore = this.score;
                    }
                }
            }

            this.set("scoreExtent", [minScore, maxScore]);

            var participantCount = participants.size;

            if (participantCount < 101) {
				            var participantArray = Array.from(participants.values());
                var invariantCount = participantCount;
                for (var p = 0; p < invariantCount; p++ ){
                    uniProtTxt(participantArray[p]);
                }
            }
            else {
                CLMSUI.vent.trigger("uniprotDataParsed", self);
            }

            function uniProtTxt (p){
                CLMS.uniprotAccRegex.lastIndex = 0;
                if (!p.is_decoy && CLMS.uniprotAccRegex.test(p.accession)) {
                    var url = "https://www.ebi.ac.uk/proteins/api/features/" + p.accession + ".json";

                    d3.json(url, function (json) {
                        processUniProtTxt(p, json);
                    });
                } else { //not protein, no accession or isDecoy
                    participantCount--;
                    if (participantCount === 0) {
                        CLMSUI.vent.trigger("uniprotDataParsed", self);
                    }
                }
            }

            function processUniProtTxt(p, json){
                p.uniprot = json;
                participantCount--;
                if (participantCount === 0) {
                    CLMSUI.vent.trigger("uniprotDataParsed", self);
                }
            }

        },

        getDigestibleResiduesAsFeatures(participant){
            var digestibleResiduesAsFeatures = [];

            var sequence = participant.sequence;
            var seqLength = sequence.length;
            var specificity = this.get("enzymeSpecificity");

            var specifCount = specificity.length;
            for (var i = 0; i < specifCount; i++){
				var spec = specificity[i];
				for (var s = 0; s < seqLength; s++) {
					if (sequence[s] == spec.aa) {
						digestibleResiduesAsFeatures.push(
							{
								begin: s + 1,
								end: s + 1,
								name: spec.type,
								protID: participant.id,
								id: participant.id+" "+spec.type+(s+1),
								category: "Digestible residue",
								type: spec.type
							}
                        );
					}
				}
			}
			//console.log("sp:", specificity, "df:", digestibleResiduesAsFeatures);
            return digestibleResiduesAsFeatures;
        },

        getCrosslinkableResiduesAsFeatures(participant){
            var crosslinkableResiduesAsFeatures = [];

            var sequence = participant.sequence;
            var seqLength = sequence.length;
            var specificity = this.get("crosslinkerSpecificity");

            var specifCount = specificity.length;
            for (var i = 0; i < specifCount; i++){
				var spec = specificity[i];
				for (var s = 0; s < seqLength; s++) {
					if (sequence[s] == spec) {
						crosslinkableResiduesAsFeatures.push(
							{
								begin: s + 1,
								end: s + 1,
								name: "Crosslinkable residue",
								protID: participant.id,
								id: participant.id+" Crosslinkable residue"+(s+1),
								category: "Crosslinkable residue",
								type: spec.type
							}
                        );
					}
				}
			}
			//console.log("sp:", specificity, "clf:", crosslinkableResiduesAsFeatures);
            return crosslinkableResiduesAsFeatures;
        }
    });
<commit_msg>fix for isoform uniprot data<commit_after>//      CLMS-model
//      Copyright 2015 Rappsilber Laboratory, Edinburgh University
//
//      authors: Colin Combe, Martin Graham
//
//      SearchResultsModel.js

    var CLMS = CLMS || {};
    CLMS.model = CLMS.model || {};
    CLMS.uniprotAccRegex = /[OPQ][0-9][A-Z0-9]{3}[0-9]|[A-NR-Z][0-9]([A-Z][A-Z0-9]{2}[0-9]){1,2}/;

    CLMS.model.SearchResultsModel = Backbone.Model.extend ({
        //http://stackoverflow.com/questions/19835163/backbone-model-collection-property-not-empty-on-new-model-creation
        defaults :  function() {
            return {
                participants: new Map (), //map
                //peptides: new Map (), //map
                matches: [],
                crossLinks: new Map(), //map
                scoreExtent: null,
                searches: new Map(),
                decoysPresent: false,
            };
        },

        initialize: function (options) {

            var defaultOptions = {};

            this.options = _.extend(defaultOptions, options);

            var self = this;
            this.set("sid", this.options.sid);

            //search meta data
            var searches = new Map();
            for(var propertyName in this.options.searches) {
                var search = this.options.searches[propertyName];
                searches.set(propertyName, search);
            }
            this.set("searches", searches);

			//enzyme specificity
            var postAaSet = new Set();
            var aaConstrainedCTermSet = new Set();
            var aaConstrainedNTermSet = new Set();
            var searchArray = Array.from(searches.values());
            var searchCount = searchArray.length;
            for (var s = 0; s < searchCount; s++) {
                var search = searchArray[s];
                var enzymes = search.enzymes;
                var enzymeCount = enzymes.length;
                for (var e = 0; e < enzymeCount ; e++) {
                    var enzymeDescription = enzymes[e].description;
                    var postAARegex = /DIGESTED:(.*?);/g;
                    var postAAMatch = postAARegex.exec(enzymeDescription);
                    getResiduesFromEnzymeDescription (postAAMatch, postAaSet);

                    var cTermRegex = /CTERMDIGEST:(.*?);/g;
                    var ctMatch = cTermRegex.exec(enzymeDescription);
                    getResiduesFromEnzymeDescription (ctMatch, aaConstrainedCTermSet);

					var nTermRegex = /NTERMDIGEST:(.*?);/g;
					var ntMatch = nTermRegex.exec(enzymeDescription);
                    getResiduesFromEnzymeDescription (ntMatch, aaConstrainedNTermSet);
                }
            }

            function getResiduesFromEnzymeDescription (regexMatch, residueSet) {
				if (regexMatch && regexMatch.length > 1) {
					var resArray = regexMatch[1].split(',');
					var resCount = resArray.length;
                    for (var r = 0; r < resCount; r++){
						residueSet.add(resArray[r]);
					}
				}
			}

			var enzymeSpecificity = [];
			addEnzymeSpecificityResidues(postAaSet, "Post AA constrained");
			addEnzymeSpecificityResidues(aaConstrainedCTermSet, "AA constrained c-term");
			addEnzymeSpecificityResidues(aaConstrainedNTermSet, "AA constrained n-term");
			this.set("enzymeSpecificity", enzymeSpecificity);

            function addEnzymeSpecificityResidues (residueSet, type) {
				var resArray = Array.from(residueSet.values());
				var resCount = resArray.length;
				for (var r = 0; r < resCount; r++) {
					enzymeSpecificity.push(
						{aa: resArray[r] , type: type}
					);
				}
			}

			//crosslink specificity
			var linkableResSet = new Set();
            for (var s = 0; s < searchCount; s++) {
                var search = searchArray[s];
                var crosslinkers = search.crosslinkers;
                var crosslinkerCount = crosslinkers.length;
                for (var cl = 0; cl < crosslinkerCount ; cl++) {
                    var crosslinkerDescription = crosslinkers[cl].description;
                    var linkedAARegex = /LINKEDAMINOACIDS:(.*?);/g;
                    var result = null;
                    while ((result = linkedAARegex.exec(crosslinkerDescription)) !== null) {
						var resArray = result[1].split(',');
						var resCount = resArray.length;
						for (var r = 0; r < resCount; r++){
							var resRegex = /([A-Z])(.*)?/
							var resMatch = resRegex.exec(resArray[r]);
							if (resMatch) {
								linkableResSet.add(resMatch[1]);
							}
						}
					}
                }
            }

			this.set("crosslinkerSpecificity", Array.from(linkableResSet));

            //saved config should end up including filter settings not just xiNET layout
            this.set("xiNETLayout", options.xiNETLayout);
            //spectrum sources
            var spectrumSources = new Map();
            var specSource;
            for (var propertyName in this.options.spectrumSources) {
                specSource = this.options.spectrumSources[propertyName];
                spectrumSources.set(+specSource.id, specSource.name);
            }
            this.set("spectrumSources", spectrumSources);

            // we will be removing modification info from sequences
            var notUpperCase = /[^A-Z]/g;

            var participants = new Map();
            var proteins = this.options.proteins;
            var participant;
            for (var propertyName in proteins) {
                notUpperCase.lastIndex = 0;
                participant = proteins[propertyName];
                participant.sequence = participant.seq_mods.replace(notUpperCase, '');
                participant.size = participant.sequence.length;
                participant.crossLinks = [];
                participant.hidden = false;//?
                participants.set(participant.id, participant);
            }
            this.set("participants", participants);

            //peptides
            var peptides = new Map();
            var peptide;
            for (var propertyName in this.options.peptides) {
                notUpperCase.lastIndex = 0;
                peptide = this.options.peptides[propertyName];
                peptide.sequence = peptide.seq_mods.replace(notUpperCase, '');
                peptides.set(peptide.id, peptide);
            }
            //this.set("peptides", peptides);

            var crossLinks = this.get("crossLinks");

            var rawMatches = this.options.rawMatches;
            if (rawMatches) {
                var matches = this.get("matches");
                var minScore = Number.MIN_VALUE;
                var maxScore = Number.MAX_VALUE;

                var l = rawMatches.length, match;
                for (var i = 0; i < l; i++) {
                    //TODO: this will need updated for ternary or higher order crosslinks
                    if ((i < (l - 1)) && rawMatches[i].id == rawMatches[i+1].id){
                        match = new CLMS.model.SpectrumMatch (this, participants, crossLinks, peptides, [rawMatches[i], rawMatches[i+1]]);
                        i++;
                    }
                    else {
                        match = new CLMS.model.SpectrumMatch (this, participants, crossLinks, peptides, [rawMatches[i]]);
                    }

                    matches.push(match);//set(match.id, match);

                    if (match.score > maxScore) {
                        maxScore = match.score;
                    }
                    else if (match.score < minScore) {
                        minScore = this.score;
                    }
                }
            }

            this.set("scoreExtent", [minScore, maxScore]);

            var participantCount = participants.size;

            if (participantCount < 101) {
				            var participantArray = Array.from(participants.values());
                var invariantCount = participantCount;
                for (var p = 0; p < invariantCount; p++ ){
                    uniProtTxt(participantArray[p]);
                }
            }
            else {
                CLMSUI.vent.trigger("uniprotDataParsed", self);
            }

            function uniProtTxt (p){
                CLMS.uniprotAccRegex.lastIndex = 0;
                var regexMatch = CLMS.uniprotAccRegex.exec(p.accession);
		if (!p.is_decoy && regexMatch) {
		    var url = "https://www.ebi.ac.uk/proteins/api/features/" + match[0] + ".json";
                    d3.json(url, function (json) {
                        processUniProtTxt(p, json);
                    });
                } else { //not protein, no accession or isDecoy
                    participantCount--;
                    if (participantCount === 0) {
                        CLMSUI.vent.trigger("uniprotDataParsed", self);
                    }
                }
            }

            function processUniProtTxt(p, json){
                p.uniprot = json;
                participantCount--;
                if (participantCount === 0) {
                    CLMSUI.vent.trigger("uniprotDataParsed", self);
                }
            }

        },

        getDigestibleResiduesAsFeatures(participant){
            var digestibleResiduesAsFeatures = [];

            var sequence = participant.sequence;
            var seqLength = sequence.length;
            var specificity = this.get("enzymeSpecificity");

            var specifCount = specificity.length;
            for (var i = 0; i < specifCount; i++){
				var spec = specificity[i];
				for (var s = 0; s < seqLength; s++) {
					if (sequence[s] == spec.aa) {
						digestibleResiduesAsFeatures.push(
							{
								begin: s + 1,
								end: s + 1,
								name: spec.type,
								protID: participant.id,
								id: participant.id+" "+spec.type+(s+1),
								category: "Digestible residue",
								type: spec.type
							}
                        );
					}
				}
			}
			//console.log("sp:", specificity, "df:", digestibleResiduesAsFeatures);
            return digestibleResiduesAsFeatures;
        },

        getCrosslinkableResiduesAsFeatures(participant){
            var crosslinkableResiduesAsFeatures = [];

            var sequence = participant.sequence;
            var seqLength = sequence.length;
            var specificity = this.get("crosslinkerSpecificity");

            var specifCount = specificity.length;
            for (var i = 0; i < specifCount; i++){
				var spec = specificity[i];
				for (var s = 0; s < seqLength; s++) {
					if (sequence[s] == spec) {
						crosslinkableResiduesAsFeatures.push(
							{
								begin: s + 1,
								end: s + 1,
								name: "Crosslinkable residue",
								protID: participant.id,
								id: participant.id+" Crosslinkable residue"+(s+1),
								category: "Crosslinkable residue",
								type: spec.type
							}
                        );
					}
				}
			}
			//console.log("sp:", specificity, "clf:", crosslinkableResiduesAsFeatures);
            return crosslinkableResiduesAsFeatures;
        }
    });
<|endoftext|>


<commit_before>setup_switch = function(li, file) {
    $(li).click(function() {
	$(".pure-menu-selected").removeClass("pure-menu-selected");
	$(li).addClass("pure-menu-selected");
	$.ajax({
	    url: "/translate/"+file,
	    success: function(data) {
		replace_it(data);
	    },
	    data: load_lang()
	});
    });
}

replace_it = function(data) {
    var ndiv = document.createElement('div');
    ndiv.innerHTML = '
'+data+'
';
    Rainbow.color(ndiv, function() {
	var p = document.getElementById('thacode').parentNode;
	p.parentNode.replaceChild(ndiv, p);
    });
}

a = [["]", "#_ARSCR"],
     ["[", "#_ARSCL"],
     ["(", "#_PARL"],
     [")", "#_PARR"],
     ["=", "#_EQOP"]]

load_lang = function() {
    obj = {rules:[]};
    a.forEach(function(v, i) {
	obj.rules.push([v[0], encodeURIComponent($(v[1]).val() || $(v[1]).attr('placeholder'))]);
    });
    obj.l_name = encodeURIComponent($("#l_name").val() || $("#l_name").attr('placeholder'));
    return JSON.stringify(obj);
}

$(document).ready(function() {
    setup_switch("#switch_hello", "hello_world.py");
    setup_switch("#switch_for", "for_loop.py");
    a.forEach(function(v, i) {
	$(v[1]).change(function() {
	    $.ajax({
		url: "/translate",
		success: function(data) {
		    replace_it(data);
		},
		data: load_lang()
	    });
	});
    });
    $("#i_download").click(function() {
	$(location).attr('href', '/interpreter?' + load_lang());
    });
    $.ajax({
	url: "/translate",
	success: function(data) {
	    replace_it(data);
	},
	data: load_lang()
    });
    $("#code_reload").click(
	function() {
	    $.ajax({
		url: "/translate",
		success: function(data) {
		    replace_it(data);
		},
		data: load_lang()
	    });
	}
    );
});
<commit_msg>Always use the most recent file selected<commit_after>selected_file = "hello_world.py"

setup_switch = function(li, file) {
    $(li).click(function() {
	$(".pure-menu-selected").removeClass("pure-menu-selected");
	$(li).addClass("pure-menu-selected");
	selected_file = file;
	$.ajax({
	    url: "/translate/"+file,
	    success: function(data) {
		replace_it(data);
	    },
	    data: load_lang()
	});
    });
}

replace_it = function(data) {
    var ndiv = document.createElement('div');
    ndiv.innerHTML = '
'+data+'
';
    Rainbow.color(ndiv, function() {
	var p = document.getElementById('thacode').parentNode;
	p.parentNode.replaceChild(ndiv, p);
    });
}

a = [["]", "#_ARSCR"],
     ["[", "#_ARSCL"],
     ["(", "#_PARL"],
     [")", "#_PARR"],
     ["=", "#_EQOP"]]

load_lang = function() {
    obj = {rules:[]};
    a.forEach(function(v, i) {
	obj.rules.push([v[0], encodeURIComponent($(v[1]).val() || $(v[1]).attr('placeholder'))]);
    });
    obj.l_name = encodeURIComponent($("#l_name").val() || $("#l_name").attr('placeholder'));
    return JSON.stringify(obj);
}

$(document).ready(function() {
    setup_switch("#switch_hello", "hello_world.py");
    setup_switch("#switch_for", "for_loop.py");
    a.forEach(function(v, i) {
	$(v[1]).change(function() {
	    $.ajax({
		url: "/translate/"+selected_file,
		success: function(data) {
		    replace_it(data);
		},
		data: load_lang()
	    });
	});
    });
    $("#i_download").click(function() {
	$(location).attr('href', '/interpreter?' + load_lang());
    });
    $.ajax({
	url: "/translate/"+selected_file,
	success: function(data) {
	    replace_it(data);
	},
	data: load_lang()
    });
    $("#code_reload").click(
	function() {
	    $.ajax({
		url: "/translate/"+selected_file,
		success: function(data) {
		    replace_it(data);
		},
		data: load_lang()
	    });
	}
    );
});
<|endoftext|>


<commit_before>var redmineIssueHistoryPlugin = {
	arrayUnique: function(a) {
		return a.reduce(function(p, c) {
			if (p.indexOf(c) < 0) p.push(c);
			return p;
		}, []);
	},

	updateFilter: function() {
		var match = $("#issue_search_history_text").val().toLowerCase();
		var user = $("#issue_search_history_user option:selected").text();
		var attr = $("#issue_search_history_attribute option:selected").text();
		var showNotes = $("#issue_search_history_show_comments").prop("checked");
		var showDetails = $("#issue_search_history_show_details").prop("checked");

		if (match == "" && user == "" && attr == "" && showNotes && showDetails) {
			$("#issue_search_history_magnifier").addClass("issue_search_history_not_applied");
		} else {
			$("#issue_search_history_magnifier").removeClass("issue_search_history_not_applied");
		}

		if (showNotes) {
			$(".journal .wiki").fadeIn();
		} else {
			$(".journal .wiki").fadeOut();
		}

		if (showDetails) {
			$(".journal .details").fadeIn();
		} else {
			$(".journal .details").fadeOut();
		}

		$(".journal").each(
			function(i, e){
				var el = $(e);
				var forceHide = false;
				var hasDetails = el.hasClass('has-details');
				var hasNotes = el.hasClass('has-notes');
				if (showDetails) {
					if (showNotes) {
						forceHide = false;
					} else {
						forceHide = ! hasDetails;
					}
				} else {
					if (showNotes) {
						forceHide = ! hasNotes;
					} else {
						forceHide = true;
					}
				}
				var notText = match != "" && el.text().toLowerCase().indexOf(match) <= -1;
				var notUser = user != "" && el.find("h4:first .user").text() != user;
				var notAttr = attr != "" && el.find(".details strong").text() != attr;
				if (notText || notUser || notAttr || forceHide)
					el.fadeOut();
				else
					el.fadeIn();
			}
		)
	},

	addMagnifier: function() {
		$("div#history h3:first").append(
				""
		);
		$("#issue_search_history_magnifier")
		.click(
			function(){
				var dialog = $("#issue_search_history");
				if (dialog.dialog("isOpen")) {
					dialog.dialog("close");
				} else {
					dialog.dialog("open");
				}
			}
		);
	},

	collectUsers: function() {
		var activeUsers = $(".journal .user").map(
			function(i, e){
				return e.textContent;
			}
		);
		return $(this.arrayUnique(activeUsers.toArray())).sort().toArray();
	},

	collectAttributes: function() {
		var usedAttributes = $(".journal .details strong").map(
			function(i, e){
				return e.textContent;
			}
		);
		return $(this.arrayUnique(usedAttributes.toArray())).sort().toArray();
	},

	clearFilter: function() {
		$("#issue_search_history_user").val("");
		$("#issue_search_history_attribute").val("");
		$("#issue_search_history_text").val("");
		$("#issue_search_history_show_comments").prop("checked", true);
		$("#issue_search_history_show_details").prop("checked", true);
		window.redmineIssueHistoryPlugin.updateFilter();
	},

	process: function() {
		try {
			var usersOptions =
				this.collectUsers()
				.reduce(
					function(p, c) {
						return p + "<option>" + c + "</option>"
					},
					"<option></option>"
				);
			var attrsOptions =
				this.collectAttributes()
				.reduce(
					function(p, c){
						return p + "<option>" + c + "</option>"
					},
					"<option></option>"
				);

			var filterForm =
				"
" +
					"<form>" +
						"Find in comment" +
							"<input type='text' id='issue_search_history_text'/>" +
						"" +
						"User" +
							"<select id='issue_search_history_user'>" +
								usersOptions +
							"</select>" +
						"" +
						"Modified attribute" +
							"<select id='issue_search_history_attribute'>" +
								attrsOptions +
							"</select>" +
						"" +
						"" +
							"<input id='issue_search_history_show_details' type='checkbox' checked/>" +
							"Display changed attributes" +
						"" +
						"" +
							"<input id='issue_search_history_show_comments' type='checkbox' checked/>" +
							"Display comment" +
						"" +
						"
" +
							"<button onclick='redmineIssueHistoryPlugin.clearFilter();return false;'>Clear</button>" +
							"<button onclick='$(\"#issue_search_history\").dialog(\"close\");return false'>Close</button>" +
						"
" +
					"</form>" +
				"
";
			$("div#history h3:first").after(filterForm);
			$("#issue_search_history")
			.dialog({
				autoOpen: false,
				closeOnEscape: true,
				position: {
					my: "left bottom",
					at: "right bottom",
					of: "#issue_search_history_magnifier"
				},
				draggable: false,
				resizable: false,
				width: 223,
			});
			$("#issue_search_history").parent().find(".ui-dialog-titlebar").remove();

			this.addMagnifier();

			$("#issue_search_history_user").change(this.updateFilter);
			$("#issue_search_history_attribute").change(this.updateFilter);
			$("#issue_search_history_text").change(this.updateFilter);
			$("#issue_search_history_text").keyup(this.updateFilter);
			$("#issue_search_history_show_comments").change(this.updateFilter);
			$("#issue_search_history_show_details").change(this.updateFilter);
		} catch (e) {
			console.log(e);
		}
	}
}

redmineIssueHistoryPlugin.process();

window.redmineIssueHistoryPlugin = redmineIssueHistoryPlugin;
<commit_msg>The plugin adds its form on every h3 tags in comments. Which is problematic when textile is used in these comments. Now it only add its forms on the first H3 tag<commit_after>var redmineIssueHistoryPlugin = {
	arrayUnique: function(a) {
		return a.reduce(function(p, c) {
			if (p.indexOf(c) < 0) p.push(c);
			return p;
		}, []);
	},

	updateFilter: function() {
		var match = $("#issue_search_history_text").val().toLowerCase();
		var user = $("#issue_search_history_user option:selected").text();
		var attr = $("#issue_search_history_attribute option:selected").text();
		var showNotes = $("#issue_search_history_show_comments").prop("checked");
		var showDetails = $("#issue_search_history_show_details").prop("checked");

		if (match == "" && user == "" && attr == "" && showNotes && showDetails) {
			$("#issue_search_history_magnifier").addClass("issue_search_history_not_applied");
		} else {
			$("#issue_search_history_magnifier").removeClass("issue_search_history_not_applied");
		}

		if (showNotes) {
			$(".journal .wiki").fadeIn();
		} else {
			$(".journal .wiki").fadeOut();
		}

		if (showDetails) {
			$(".journal .details").fadeIn();
		} else {
			$(".journal .details").fadeOut();
		}

		$(".journal").each(
			function(i, e){
				var el = $(e);
				var forceHide = false;
				var hasDetails = el.hasClass('has-details');
				var hasNotes = el.hasClass('has-notes');
				if (showDetails) {
					if (showNotes) {
						forceHide = false;
					} else {
						forceHide = ! hasDetails;
					}
				} else {
					if (showNotes) {
						forceHide = ! hasNotes;
					} else {
						forceHide = true;
					}
				}
				var notText = match != "" && el.text().toLowerCase().indexOf(match) <= -1;
				var notUser = user != "" && el.find("h4:first .user").text() != user;
				var notAttr = attr != "" && el.find(".details strong").text() != attr;
				if (notText || notUser || notAttr || forceHide)
					el.fadeOut();
				else
					el.fadeIn();
			}
		)
	},

	addMagnifier: function() {
		$("div#history h3:first").append(
				""
		);
		$("#issue_search_history_magnifier")
		.click(
			function(){
				var dialog = $("#issue_search_history");
				if (dialog.dialog("isOpen")) {
					dialog.dialog("close");
				} else {
					dialog.dialog("open");
				}
			}
		);
	},

	collectUsers: function() {
		var activeUsers = $(".journal .user").map(
			function(i, e){
				return e.textContent;
			}
		);
		return $(this.arrayUnique(activeUsers.toArray())).sort().toArray();
	},

	collectAttributes: function() {
		var usedAttributes = $(".journal .details strong").map(
			function(i, e){
				return e.textContent;
			}
		);
		return $(this.arrayUnique(usedAttributes.toArray())).sort().toArray();
	},

	clearFilter: function() {
		$("#issue_search_history_user").val("");
		$("#issue_search_history_attribute").val("");
		$("#issue_search_history_text").val("");
		$("#issue_search_history_show_comments").prop("checked", true);
		$("#issue_search_history_show_details").prop("checked", true);
		window.redmineIssueHistoryPlugin.updateFilter();
	},

	process: function() {
		try {
			var usersOptions =
				this.collectUsers()
				.reduce(
					function(p, c) {
						return p + "<option>" + c + "</option>"
					},
					"<option></option>"
				);
			var attrsOptions =
				this.collectAttributes()
				.reduce(
					function(p, c){
						return p + "<option>" + c + "</option>"
					},
					"<option></option>"
				);

			var filterForm =
				"
" +
					"<form>" +
						"Find in comment" +
							"<input type='text' id='issue_search_history_text'/>" +
						"" +
						"User" +
							"<select id='issue_search_history_user'>" +
								usersOptions +
							"</select>" +
						"" +
						"Modified attribute" +
							"<select id='issue_search_history_attribute'>" +
								attrsOptions +
							"</select>" +
						"" +
						"" +
							"<input id='issue_search_history_show_details' type='checkbox' checked/>" +
							"Display changed attributes" +
						"" +
						"" +
							"<input id='issue_search_history_show_comments' type='checkbox' checked/>" +
							"Display comment" +
						"" +
						"
" +
							"<button onclick='redmineIssueHistoryPlugin.clearFilter();return false;'>Clear</button>" +
							"<button onclick='$(\"#issue_search_history\").dialog(\"close\");return false'>Close</button>" +
						"
" +
					"</form>" +
				"
";
			$("div#history h3:first").after(filterForm);
			$("#issue_search_history")
			.dialog({
				autoOpen: false,
				closeOnEscape: true,
				position: {
					my: "left bottom",
					at: "right bottom",
					of: "#issue_search_history_magnifier"
				},
				draggable: false,
				resizable: false,
				width: 223,
			});
			$("#issue_search_history").parent().find(".ui-dialog-titlebar").remove();

			this.addMagnifier();

			$("#issue_search_history_user").change(this.updateFilter);
			$("#issue_search_history_attribute").change(this.updateFilter);
			$("#issue_search_history_text").change(this.updateFilter);
			$("#issue_search_history_text").keyup(this.updateFilter);
			$("#issue_search_history_show_comments").change(this.updateFilter);
			$("#issue_search_history_show_details").change(this.updateFilter);
		} catch (e) {
			console.log(e);
		}
	}
}

redmineIssueHistoryPlugin.process();

window.redmineIssueHistoryPlugin = redmineIssueHistoryPlugin;<|endoftext|>


<commit_before><commit_msg>product routes<commit_after><|endoftext|>


<commit_before>/**
 *  class Wire
 **/

"use strict";

////////////////////////////////////////////////////////////////////////////////

// Helpers for cross-browser compatibility

var $$ = {};

$$.noop = function () {};

$$.isString = function (obj) {
  return Object.prototype.toString.call(obj) === '[object String]';
};

$$.isArray  = Array.isArray || function (obj) {
  return Object.prototype.toString.call(obj) === '[object Array]';
};

$$.isFunction = function (obj) {
  return Object.prototype.toString.call(obj) === '[object Function]';
};

////////////////////////////////////////////////////////////////////////////////

// Structure to hold handler data
function WireHandler(channel, options, func) {
  this.channel  = channel;
  this.func     = func;
  this.name     = func.name || "<anonymous>";
  this.sync     = 1 === func.length;
  this.once     = Boolean(options.once);
  this.ensure   = Boolean(options.ensure);
  this.priority = Number(options.priority || 0);
  this.ncalled  = 0;
  this.pattern  = new RegExp("^" + channel.replace(/\*+/g, function (m) {
                    // '*' - anything but "dot"
                    // '**' -
                    return '*' === m ? '[^.]+?' : '.+?';
                  }) + "$");
}

////////////////////////////////////////////////////////////////////////////////

function Wire() {
  this.__handlers__       = [];
  this.__sortedCache__    = [];
  this.__knownChannels__  = {};
  this.__skips__          = {};
}

Wire.prototype.getHandlers = function (channel) {
  var skip_set = this.__skips__[channel] || {},
      result = [],
      i, handler;

  if (!this.__sortedCache__[channel]) {

    for (i in this.__handlers__) {
      handler = this.__handlers__[i];
      if (handler.pattern.test(channel) && !skip_set[handler.name]) {
        result.push(handler);
      }
    }

    result = result.sort(function (a, b) {
      if (a.priority === b.priority) {
        return 0;
      }
      return (a.priority < b.priority) ? -1 : 1;
    });

    this.__sortedCache__[channel] = result;
  }

  return this.__sortedCache__[channel];
};

// Internal helper that runs handlers for a single channel
function emitSingle(self, channel, params, callback) {
  var stash;

  if (!self.has(channel)) {
    callback("Unknown channel");
    return;
  }

  // get array of associated handlers
  stash = self.getHandlers(channel).slice();

  // helps to prevent from double-firing callback
  // when developer forgot to interrupt:
  //
  //    function doSomething(params, next) {
  //      try {
  //        // ...
  //      } catch (err) {
  //        next(err);
  //      }
  //
  //      next();
  //    }
  function done(err) {
    var _callback = callback;

    stash    = [];
    callback = $$.noop;

    _callback(err);
  }

  // iterates through handlers of stash
  function walk(err) {
    var wh, fn;

    if (err || !stash.length) {
      done(err);
      return;
    }

    while (stash.length) {
      wh = stash.shift();
      fn = wh.func;

      wh.ncalled += 1;

      if (wh.once) {
        self.off(wh.channel, fn);
      }

      if (!wh.sync) {
        fn(params, walk);
        return;
      }

      err = fn(params);

      if (err) {
        done(err);
        return;
      }
    }
  }

  // start stash walker
  walk();
}

/**
 *  Wire#emit(channels, params[, callback]) -> Void
 *  - channels (String|Array):
 *  - params (Mixed):
 *  - callback (Function):
 *
 *  Sends message with `params` into the `channel`. Once all sync and ascync
 *  handlers finished, optional `callback(err)` (if specified) fired.
 **/
Wire.prototype.emit = function (channels, params, callback) {
  var self = this;

  callback = callback || $$.noop;
  channels = $$.isArray(channels) ? channels.slice() : [channels];

  function walk(err) {
    var chan;

    if (err || !channels.length) {
      callback(err);
      return;
    }

    chan = channels.shift();
    emitSingle(self, chan, params, walk);
  }

  walk();
};

/**
 *  Wire#on(channel[, options], handler) -> Void
 *  - channel (String):
 *  - options (Object):
 *  - handler (Function):
 *
 *  Registers `handler` to be executed upon messages in the `channel`. Handler
 *  can be either sync function:
 *
 *      wire.on('foobar', function (params) {
 *        // do stuff here
 *      });
 *
 *  Or it might be an async function with `callback(err)` second argument:
 *
 *      wire.on('foobar', function (params, callback) {
 *        // do stuff here
 *        callback(null);
 *      });
 *
 *
 *  ##### Options
 *
 *  - `priority` (Number, Default: 0)
 *  - `exclude` (String|RegExp, Default: Null)
 *    Glob or RegExp patther to exclude channels from being listened.
 *  - `ensure` (Boolean, Default: false)
 *    If `true`, will run handler even if one of previous fired error.
 **/
Wire.prototype.on = function (channel, options, handler) {
  if (!handler) {
    handler = options;
    options = null;
  }

  options = options || {};

  if (!$$.isFunction(handler)) {
    throw "Not a function";
  }

  if (handler.length < 1 && 2 < handler.length) {
    throw "Function must accept exactly 1 (sync) or 2 (async) arguments";
  }

  if (!channel) {
    throw "Channel is required. Use `**` if you want 'any channel'.";
  }

  var wh = new WireHandler(channel, options, handler);

  // Count main channel handler (no wildcards, zero-priority)
  if ((wh.priority === 0) && (-1 === wh.channel.indexOf('*'))) {
    this.__knownChannels__[channel] = (this.__knownChannels__[channel] || 0) + 1;
  }

  this.__handlers__.push(wh);

  // TODO: Move to separate method
  this.__sortedCache__ = [];
};

/**
 *  Wire#once(channel[, options], handler) -> Void
 *  - channel (String):
 *  - options (Object):
 *  - handler (Function):
 *
 *  Same as [[Wire#on]] but runs handler one time only.
 **/
Wire.prototype.once = function (channel, options, handler) {
  if (!handler) {
    handler = options;
    options = {};
  }

  options = options || {};
  options.once = true;

  this.on(channel, options, handler);
};

/**
 *  Wire#before(channel[, options], handler) -> Void
 *  - channel (String):
 *  - options (Object):
 *  - handler (Function):
 *
 *  Same as [[Wire#on]] but with "fixed" priority of `-10`
 **/
Wire.prototype.before = function (channel, options, handler) {
  if (!handler) {
    handler = options;
    options = {};
  }

  options = options || {};
  options.priority = options.priority || -10;

  if (0 <= options.priority) {
    throw "before() requires priority lower than 0";
  }

  return this.on(channel, options, handler);
};

/**
 *  Wire#after(channel[, options], handler) -> Void
 *  - channel (String):
 *  - options (Object):
 *  - handler (Function):
 *
 *  Same as [[Wire#on]] but with default priority of `10`
 **/
Wire.prototype.after = function (channel, options, handler) {
  if (!handler) {
    handler = options;
    options = {};
  }

  options = options || {};
  options.priority = options.priority || 10;

  if (0 >= options.priority) {
    throw "after() requires priority greater than 0";
  }

  return this.on(channel, options, handler);
};

/**
 *  Wire#off(channel[, handler]) -> Void
 *  - channel (String):
 *  - handler (Function):
 *
 *  Removes `handler` of a channel, or removes ALL handlers of a channel if
 *  `handler` is not given.
 **/
Wire.prototype.off = function (channel, handler) {
  var i, wh;

  for (i in this.__handlers__) {
    wh = this.__handlers__[i];

    if (channel !== wh.channel) {
      continue;
    }

    if (handler && (handler !== wh.func)) {
      continue;
    }

    // Unkount back zero-priority handler
    if ((wh.priority === 0) && (this.__knownChannels__[channel])) {
      this.__knownChannels__[channel]--;
    }
    // Just replace with dummy call, to keep cache lists intact
    wh.sync = true;
    wh.func = $$.noop;
  }
};

/**
 *  Wire#skip(channel, skipList) -> Void
 *  - channel (String):
 *  - skipList (Array):
 *
 *  Exclude calling list of named handlers for given chennel:
 *
 *      wire.skip('server:static', [
 *        session_start,
 *        cookies_start
 *      ]);
 *
 **/
Wire.prototype.skip = function (channel, skipList) {
  var i;

  if (-1 !== channel.indexOf('*')) {
    throw "No wildcards allowed in Wire.skip()";
  }

  if ($$.isString(skipList)) {
    skipList = [skipList];
  }
  if (!$$.isArray(skipList)) {
    throw "skipList must be String or Array of Strings";
  }

  this.__skips__[channel] = this.__skips__[channel] || {};

  for (i in skipList) {
    this.__skips__[channel][skipList[i]] = true;
  }

  // TODO: Move to separate method
  this.__sortedCache__ = [];
};

/**
 *  Wire#has(channel) -> Boolean
 *  - channel (String):
 *
 *  Returns if `channel` has at least one subscriber
 *  with zero priority (main handler)
 **/
Wire.prototype.has = function (channel) {
  return Boolean(this.__knownChannels__[channel]);
};

/**
 *  Wire#stat() -> Object
 *
 *  Returns full statictics about all channels. Only channels without wildcards
 *  are displayed. Each channel has following structures:
 *
 *  ```
 *  {
 *    name: channnelName,
 *    listeners: Array[handlerStat]
 *  }
 *  ```
 **/
Wire.prototype.stat = function () {
  var _channel, result = [];

  for(_channel in this.__knownChannels__) {
    result.push({ name : _channel, listeners: this.getHandlers(_channel) });
  }

  return result;
};

////////////////////////////////////////////////////////////////////////////////

module.exports = Wire;
<commit_msg>Make wire platform independent<commit_after>/**
 *  class Wire
 **/

(function () {
  "use strict";

  //////////////////////////////////////////////////////////////////////////////

  function noop() {}

  //
  // Helpers for cross-browser compatibility
  //

  var isString = function isString(obj) {
    return Object.prototype.toString.call(obj) === '[object String]';
  };

  var isArray = Array.isArray || function isArray(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
  };

  var isFunction = function isFunction(obj) {
    return Object.prototype.toString.call(obj) === '[object Function]';
  };

  //////////////////////////////////////////////////////////////////////////////

  // Structure to hold handler data
  function WireHandler(channel, options, func) {
    this.channel  = channel;
    this.func     = func;
    this.name     = func.name || "<anonymous>";
    this.sync     = 1 === func.length;
    this.once     = Boolean(options.once);
    this.ensure   = Boolean(options.ensure);
    this.priority = Number(options.priority || 0);
    this.ncalled  = 0;
    this.pattern  = new RegExp("^" + channel.replace(/\*+/g, function (m) {
                      // '*' - anything but "dot"
                      // '**' -
                      return '*' === m ? '[^.]+?' : '.+?';
                    }) + "$");
  }

  //////////////////////////////////////////////////////////////////////////////

  function Wire() {
    this.__handlers__       = [];
    this.__sortedCache__    = [];
    this.__knownChannels__  = {};
    this.__skips__          = {};
  }

  Wire.prototype.getHandlers = function (channel) {
    var skip_set = this.__skips__[channel] || {},
        result = [],
        i, handler;

    if (!this.__sortedCache__[channel]) {

      for (i in this.__handlers__) {
        handler = this.__handlers__[i];
        if (handler.pattern.test(channel) && !skip_set[handler.name]) {
          result.push(handler);
        }
      }

      result = result.sort(function (a, b) {
        if (a.priority === b.priority) {
          return 0;
        }
        return (a.priority < b.priority) ? -1 : 1;
      });

      this.__sortedCache__[channel] = result;
    }

    return this.__sortedCache__[channel];
  };

  // Internal helper that runs handlers for a single channel
  function emitSingle(self, channel, params, callback) {
    var stash;

    if (!self.has(channel)) {
      callback("Unknown channel");
      return;
    }

    // get array of associated handlers
    stash = self.getHandlers(channel).slice();

    // helps to prevent from double-firing callback
    // when developer forgot to interrupt:
    //
    //    function doSomething(params, next) {
    //      try {
    //        // ...
    //      } catch (err) {
    //        next(err);
    //      }
    //
    //      next();
    //    }
    function done(err) {
      var _callback = callback;

      stash    = [];
      callback = noop;

      _callback(err);
    }

    // iterates through handlers of stash
    function walk(err) {
      var wh, fn;

      if (err || !stash.length) {
        done(err);
        return;
      }

      while (stash.length) {
        wh = stash.shift();
        fn = wh.func;

        wh.ncalled += 1;

        if (wh.once) {
          self.off(wh.channel, fn);
        }

        if (!wh.sync) {
          fn(params, walk);
          return;
        }

        err = fn(params);

        if (err) {
          done(err);
          return;
        }
      }
    }

    // start stash walker
    walk();
  }

  /**
   *  Wire#emit(channels, params[, callback]) -> Void
   *  - channels (String|Array):
   *  - params (Mixed):
   *  - callback (Function):
   *
   *  Sends message with `params` into the `channel`. Once all sync and ascync
   *  handlers finished, optional `callback(err)` (if specified) fired.
   **/
  Wire.prototype.emit = function (channels, params, callback) {
    var self = this;

    callback = callback || noop;
    channels = isArray(channels) ? channels.slice() : [channels];

    function walk(err) {
      var chan;

      if (err || !channels.length) {
        callback(err);
        return;
      }

      chan = channels.shift();
      emitSingle(self, chan, params, walk);
    }

    walk();
  };

  /**
   *  Wire#on(channel[, options], handler) -> Void
   *  - channel (String):
   *  - options (Object):
   *  - handler (Function):
   *
   *  Registers `handler` to be executed upon messages in the `channel`. Handler
   *  can be either sync function:
   *
   *      wire.on('foobar', function (params) {
   *        // do stuff here
   *      });
   *
   *  Or it might be an async function with `callback(err)` second argument:
   *
   *      wire.on('foobar', function (params, callback) {
   *        // do stuff here
   *        callback(null);
   *      });
   *
   *
   *  ##### Options
   *
   *  - `priority` (Number, Default: 0)
   *  - `exclude` (String|RegExp, Default: Null)
   *    Glob or RegExp patther to exclude channels from being listened.
   *  - `ensure` (Boolean, Default: false)
   *    If `true`, will run handler even if one of previous fired error.
   **/
  Wire.prototype.on = function (channel, options, handler) {
    if (!handler) {
      handler = options;
      options = null;
    }

    options = options || {};

    if (!isFunction(handler)) {
      throw "Not a function";
    }

    if (handler.length < 1 && 2 < handler.length) {
      throw "Function must accept exactly 1 (sync) or 2 (async) arguments";
    }

    if (!channel) {
      throw "Channel is required. Use `**` if you want 'any channel'.";
    }

    var wh = new WireHandler(channel, options, handler);

    // Count main channel handler (no wildcards, zero-priority)
    if ((wh.priority === 0) && (-1 === wh.channel.indexOf('*'))) {
      this.__knownChannels__[channel] = (this.__knownChannels__[channel] || 0) + 1;
    }

    this.__handlers__.push(wh);

    // TODO: Move to separate method
    this.__sortedCache__ = [];
  };

  /**
   *  Wire#once(channel[, options], handler) -> Void
   *  - channel (String):
   *  - options (Object):
   *  - handler (Function):
   *
   *  Same as [[Wire#on]] but runs handler one time only.
   **/
  Wire.prototype.once = function (channel, options, handler) {
    if (!handler) {
      handler = options;
      options = {};
    }

    options = options || {};
    options.once = true;

    this.on(channel, options, handler);
  };

  /**
   *  Wire#before(channel[, options], handler) -> Void
   *  - channel (String):
   *  - options (Object):
   *  - handler (Function):
   *
   *  Same as [[Wire#on]] but with "fixed" priority of `-10`
   **/
  Wire.prototype.before = function (channel, options, handler) {
    if (!handler) {
      handler = options;
      options = {};
    }

    options = options || {};
    options.priority = options.priority || -10;

    if (0 <= options.priority) {
      throw "before() requires priority lower than 0";
    }

    return this.on(channel, options, handler);
  };

  /**
   *  Wire#after(channel[, options], handler) -> Void
   *  - channel (String):
   *  - options (Object):
   *  - handler (Function):
   *
   *  Same as [[Wire#on]] but with default priority of `10`
   **/
  Wire.prototype.after = function (channel, options, handler) {
    if (!handler) {
      handler = options;
      options = {};
    }

    options = options || {};
    options.priority = options.priority || 10;

    if (0 >= options.priority) {
      throw "after() requires priority greater than 0";
    }

    return this.on(channel, options, handler);
  };

  /**
   *  Wire#off(channel[, handler]) -> Void
   *  - channel (String):
   *  - handler (Function):
   *
   *  Removes `handler` of a channel, or removes ALL handlers of a channel if
   *  `handler` is not given.
   **/
  Wire.prototype.off = function (channel, handler) {
    var i, wh;

    for (i in this.__handlers__) {
      wh = this.__handlers__[i];

      if (channel !== wh.channel) {
        continue;
      }

      if (handler && (handler !== wh.func)) {
        continue;
      }

      // Unkount back zero-priority handler
      if ((wh.priority === 0) && (this.__knownChannels__[channel])) {
        this.__knownChannels__[channel]--;
      }
      // Just replace with dummy call, to keep cache lists intact
      wh.sync = true;
      wh.func = noop;
    }
  };

  /**
   *  Wire#skip(channel, skipList) -> Void
   *  - channel (String):
   *  - skipList (Array):
   *
   *  Exclude calling list of named handlers for given chennel:
   *
   *      wire.skip('server:static', [
   *        session_start,
   *        cookies_start
   *      ]);
   *
   **/
  Wire.prototype.skip = function (channel, skipList) {
    var i;

    if (-1 !== channel.indexOf('*')) {
      throw "No wildcards allowed in Wire.skip()";
    }

    if (isString(skipList)) {
      skipList = [skipList];
    }
    if (!isArray(skipList)) {
      throw "skipList must be String or Array of Strings";
    }

    this.__skips__[channel] = this.__skips__[channel] || {};

    for (i in skipList) {
      this.__skips__[channel][skipList[i]] = true;
    }

    // TODO: Move to separate method
    this.__sortedCache__ = [];
  };

  /**
   *  Wire#has(channel) -> Boolean
   *  - channel (String):
   *
   *  Returns if `channel` has at least one subscriber
   *  with zero priority (main handler)
   **/
  Wire.prototype.has = function (channel) {
    return Boolean(this.__knownChannels__[channel]);
  };

  /**
   *  Wire#stat() -> Object
   *
   *  Returns full statictics about all channels. Only channels without wildcards
   *  are displayed. Each channel has following structures:
   *
   *  ```
   *  {
   *    name: channnelName,
   *    listeners: Array[handlerStat]
   *  }
   *  ```
   **/
  Wire.prototype.stat = function () {
    var _channel, result = [];

    for(_channel in this.__knownChannels__) {
      result.push({ name : _channel, listeners: this.getHandlers(_channel) });
    }

    return result;
  };

  //////////////////////////////////////////////////////////////////////////////

  // Node.JS
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = Wire;
  // Browser
  } else {
    this.Wire = Wire;
  }
}());
<|endoftext|>