<commit_before>import BiaxialLineChart from './Biaxial';
import CustomizedDotLineChart from './CustomizedDot';
import CustomizedLableLineChart from './CustomizedLabel';
import DashedLineChart from './DashedLineChart';
import LineChartConnectNulls from './LineChartConnectNulls';
import LineChartWithReferenceLines from './LineChartWithReferenceLines';
import LineChartWithXAxisPading from './LineChartWithXAxisPading'
import SimpleLineChart from './Simple';
import SynchronizedLineChart from './SynchronizedLineChart';
import TinyLineChart from './Tiny';
import VerticalLineChart from './Vertical';
import VerticalLineChartWithSpecifiedDomain from './VerticalLineChartWithSpecifiedDomain';
import HighlightAndZoomLineChart from './HighlightAndZoomLineChart';
import LineChartHasMultiSeries from './LineChartHasMultiSeries';

export default {
  SimpleLineChart,
  TinyLineChart,
  DashedLineChart,
  VerticalLineChart,
  BiaxialLineChart,
  VerticalLineChartWithSpecifiedDomain,
  LineChartConnectNulls,
  LineChartWithXAxisPading,
  LineChartWithReferenceLines,
  CustomizedDotLineChart,
  CustomizedLableLineChart,
  SynchronizedLineChart,
  HighlightAndZoomLineChart,
  LineChartHasMultiSeries
};<commit_msg>Fix typo<commit_after>import BiaxialLineChart from './Biaxial';
import CustomizedDotLineChart from './CustomizedDot';
import CustomizedLabelLineChart from './CustomizedLabel';
import DashedLineChart from './DashedLineChart';
import LineChartConnectNulls from './LineChartConnectNulls';
import LineChartWithReferenceLines from './LineChartWithReferenceLines';
import LineChartWithXAxisPading from './LineChartWithXAxisPading'
import SimpleLineChart from './Simple';
import SynchronizedLineChart from './SynchronizedLineChart';
import TinyLineChart from './Tiny';
import VerticalLineChart from './Vertical';
import VerticalLineChartWithSpecifiedDomain from './VerticalLineChartWithSpecifiedDomain';
import HighlightAndZoomLineChart from './HighlightAndZoomLineChart';
import LineChartHasMultiSeries from './LineChartHasMultiSeries';

export default {
  SimpleLineChart,
  TinyLineChart,
  DashedLineChart,
  VerticalLineChart,
  BiaxialLineChart,
  VerticalLineChartWithSpecifiedDomain,
  LineChartConnectNulls,
  LineChartWithXAxisPading,
  LineChartWithReferenceLines,
  CustomizedDotLineChart,
  CustomizedLabelLineChart,
  SynchronizedLineChart,
  HighlightAndZoomLineChart,
  LineChartHasMultiSeries
};
<|endoftext|>


<commit_before>// `window.ParsleyExtend`, like `ParsleyAbstract`, is inherited by `ParsleyField` and `ParsleyForm`
// That way, we could add new methods or redefine some for these both classes. In particular case
// We are adding async validation methods that returns promises, bind them properly to triggered
// Events like onkeyup when field is invalid or on form submit. These validation methods adds an
// Extra `remote` validator which could not be simply added like other `ParsleyExtra` validators
// Because returns promises instead of booleans.
window.ParsleyExtend = window.ParsleyExtend || {};
window.ParsleyExtend = $.extend(window.ParsleyExtend, {
  asyncSupport: true,

  asyncValidators: $.extend({
    default: {
      fn: function (xhr) {
        return 'resolved' === xhr.state();
      },
      url: false
    },
    reverse: {
      fn: function (xhr) {
        // If reverse option is set, a failing ajax request is considered successful
        return 'rejected' === xhr.state();
      },
      url: false
    }
  }, window.ParsleyExtend.asyncValidators),

  addAsyncValidator: function (name, fn, url) {
    this.asyncValidators[name.toLowerCase()] = {
      fn: fn,
      url: url || false
    };

    return this;
  },

  asyncValidate: function () {
    if ('ParsleyForm' === this.__class__)
      return this._asyncValidateForm.apply(this, arguments);

    return this._asyncValidateField.apply(this, arguments);
  },

  asyncIsValid: function () {
    if ('ParsleyField' === this.__class__)
      return this._asyncIsValidField.apply(this, arguments);

    return this._asyncIsValidForm.apply(this, arguments);
  },

  onSubmitValidate: function (event) {
    var that = this;

    // This is a Parsley generated submit event, do not validate, do not prevent, simply exit and keep normal behavior
    if (true === event.parsley)
      return;

    // Clone the event object
    this.submitEvent = $.extend(true, {}, event);

    // Prevent form submit and immediately stop its event propagation
    if (event instanceof $.Event) {
      event.stopImmediatePropagation();
      event.preventDefault();
    }

    return this._asyncValidateForm(undefined, event)
      .done(function () {
        // If user do not have prevented the event, re-submit form
        if (!that.submitEvent.isDefaultPrevented())
          that.$element.trigger($.extend($.Event('submit'), { parsley: true }));
      });
  },

  eventValidate: function (event) {
    // For keyup, keypress, keydown.. events that could be a little bit obstrusive
    // do not validate if val length < min threshold on first validation. Once field have been validated once and info
    // about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.
    if (new RegExp('key').test(event.type))
      if (!this._ui.validationInformationVisible  && this.getValue().length <= this.options.validationThreshold)
        return;

    this._ui.validatedOnce = true;
    this.asyncValidate();
  },

  // Returns Promise
  _asyncValidateForm: function (group, event) {
    var
      that = this,
      promises = [];

    this._refreshFields();

    $.emit('parsley:form:validate', this);

    for (var i = 0; i < this.fields.length; i++) {

      // do not validate a field if not the same as given validation group
      if (group && group !== this.fields[i].options.group)
        continue;

      promises.push(this.fields[i]._asyncValidateField());
    }

    return $.when.apply($, promises)
      .always(function () {
        $.emit('parsley:form:validated', that);
      });
  },

  _asyncIsValidForm: function (group, force) {
    var promises = [];
    this._refreshFields();

    for (var i = 0; i < this.fields.length; i++) {

      // do not validate a field if not the same as given validation group
      if (group && group !== this.fields[i].options.group)
        continue;

      promises.push(this.fields[i]._asyncIsValidField(force));
    }

    return $.when.apply($, promises);
  },

  _asyncValidateField: function (force) {
    var that = this;

    $.emit('parsley:field:validate', this);

    return this._asyncIsValidField(force)
      .done(function () {
        $.emit('parsley:field:success', that);
      })
      .fail(function () {
        $.emit('parsley:field:error', that);
      })
      .always(function () {
        $.emit('parsley:field:validated', that);
      });
  },

  _asyncIsValidField: function (force, value) {
    var
      deferred = $.Deferred(),
      remoteConstraintIndex;

    // If regular isValid (matching regular constraints) returns `false`, no need to go further
    // Directly reject promise, do not run remote validator and save server load
    if (false === this.isValid(force, value))
      deferred.rejectWith(this);

    // If regular constraints are valid, and there is a remote validator registered, run it
    else if ('undefined' !== typeof this.constraintsByName.remote)
      this._remote(deferred);

    // Otherwise all is good, resolve promise
    else
      deferred.resolveWith(this);

    // Return promise
    return deferred.promise();
  },

  _remote: function (deferred) {
    var
      that = this,
      data = {},
      ajaxOptions,
      csr,
      validator = this.options.remoteValidator || (true === this.options.remoteReverse ? 'reverse' : 'default');

    validator = validator.toLowerCase();

    if ('undefined' === typeof this.asyncValidators[validator])
      throw new Error('Calling an undefined async validator: `' + validator + '`');

    // Fill data with current value
    data[this.$element.attr('name') || this.$element.attr('id')] = this.getValue();

    // All `$.ajax(options)` could be overridden or extended directly from DOM in `data-parsley-remote-options`
    ajaxOptions = $.extend(true, {}, {
      url: this.asyncValidators[validator].url || this.options.remote,
      data: data,
      type: 'GET'
    }, this.options.remoteOptions || {});

    // Generate store key based on ajax options
    csr = $.param(ajaxOptions);

    // Initialise querry cache
    if ('undefined' === typeof this._remoteCache)
      this._remoteCache = {};

    // Try to retrieve stored xhr
    if (!this._remoteCache[csr]) {
      // Prevent multi burst xhr queries
      if (this._xhr && 'pending' === this._xhr.state())
        this._xhr.abort();

      // Make ajax call
      this._xhr =  $.ajax(ajaxOptions)

      // Store remote call result to avoid next calls with exact same parameters
      this._remoteCache[csr] = this._xhr;
    }

    this._remoteCache[csr]
      .done(function (data, textStatus, xhr) {
        that._handleRemoteResult(validator, xhr, deferred);
      })
      .fail(function (xhr, status, message) {
        // If we aborted the query, do not handle nothing for this value
        if ('abort' === status)
          return;

        that._handleRemoteResult(validator, xhr, deferred);
      });
  },

  _handleRemoteResult: function (validator, xhr, deferred) {
    // If true, simply resolve and exit
    if ('function' === typeof this.asyncValidators[validator].fn && this.asyncValidators[validator].fn(xhr)) {
      deferred.resolveWith(this);

      return;
    }

    // Else, create a proper remote validation Violation to trigger right UI
    this.validationResult = [
      new window.ParsleyValidator.Validator.Violation(
        this.constraintsByName.remote,
        this.getValue(),
        null
      )
    ];

    deferred.rejectWith(this);
  }
});

// Remote validator is just an always true sync validator with lowest (-1) priority possible
// It will be overloaded in `validateThroughValidator()` that will do the heavy async work
// This 'hack' is needed not to mess up too much with error messages and stuff in `ParsleyUI`
window.ParsleyConfig = window.ParsleyConfig || {};
window.ParsleyConfig.validators = window.ParsleyConfig.validators || {};
window.ParsleyConfig.validators.remote = {
  fn: function () {
    return true;
  },
  priority: -1
};
<commit_msg>Allow passing of extra options with addAsyncValidator function<commit_after>// `window.ParsleyExtend`, like `ParsleyAbstract`, is inherited by `ParsleyField` and `ParsleyForm`
// That way, we could add new methods or redefine some for these both classes. In particular case
// We are adding async validation methods that returns promises, bind them properly to triggered
// Events like onkeyup when field is invalid or on form submit. These validation methods adds an
// Extra `remote` validator which could not be simply added like other `ParsleyExtra` validators
// Because returns promises instead of booleans.
window.ParsleyExtend = window.ParsleyExtend || {};
window.ParsleyExtend = $.extend(window.ParsleyExtend, {
  asyncSupport: true,

  asyncValidators: $.extend({
    default: {
      fn: function (xhr) {
        return 'resolved' === xhr.state();
      },
      url: false
    },
    reverse: {
      fn: function (xhr) {
        // If reverse option is set, a failing ajax request is considered successful
        return 'rejected' === xhr.state();
      },
      url: false
    }
  }, window.ParsleyExtend.asyncValidators),

  addAsyncValidator: function (name, fn, url, options) {
    this.asyncValidators[name.toLowerCase()] = {
      fn: fn,
      url: url || false,
      options: options || {}
    };

    return this;
  },

  asyncValidate: function () {
    if ('ParsleyForm' === this.__class__)
      return this._asyncValidateForm.apply(this, arguments);

    return this._asyncValidateField.apply(this, arguments);
  },

  asyncIsValid: function () {
    if ('ParsleyField' === this.__class__)
      return this._asyncIsValidField.apply(this, arguments);

    return this._asyncIsValidForm.apply(this, arguments);
  },

  onSubmitValidate: function (event) {
    var that = this;

    // This is a Parsley generated submit event, do not validate, do not prevent, simply exit and keep normal behavior
    if (true === event.parsley)
      return;

    // Clone the event object
    this.submitEvent = $.extend(true, {}, event);

    // Prevent form submit and immediately stop its event propagation
    if (event instanceof $.Event) {
      event.stopImmediatePropagation();
      event.preventDefault();
    }

    return this._asyncValidateForm(undefined, event)
      .done(function () {
        // If user do not have prevented the event, re-submit form
        if (!that.submitEvent.isDefaultPrevented())
          that.$element.trigger($.extend($.Event('submit'), { parsley: true }));
      });
  },

  eventValidate: function (event) {
    // For keyup, keypress, keydown.. events that could be a little bit obstrusive
    // do not validate if val length < min threshold on first validation. Once field have been validated once and info
    // about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.
    if (new RegExp('key').test(event.type))
      if (!this._ui.validationInformationVisible  && this.getValue().length <= this.options.validationThreshold)
        return;

    this._ui.validatedOnce = true;
    this.asyncValidate();
  },

  // Returns Promise
  _asyncValidateForm: function (group, event) {
    var
      that = this,
      promises = [];

    this._refreshFields();

    $.emit('parsley:form:validate', this);

    for (var i = 0; i < this.fields.length; i++) {

      // do not validate a field if not the same as given validation group
      if (group && group !== this.fields[i].options.group)
        continue;

      promises.push(this.fields[i]._asyncValidateField());
    }

    return $.when.apply($, promises)
      .always(function () {
        $.emit('parsley:form:validated', that);
      });
  },

  _asyncIsValidForm: function (group, force) {
    var promises = [];
    this._refreshFields();

    for (var i = 0; i < this.fields.length; i++) {

      // do not validate a field if not the same as given validation group
      if (group && group !== this.fields[i].options.group)
        continue;

      promises.push(this.fields[i]._asyncIsValidField(force));
    }

    return $.when.apply($, promises);
  },

  _asyncValidateField: function (force) {
    var that = this;

    $.emit('parsley:field:validate', this);

    return this._asyncIsValidField(force)
      .done(function () {
        $.emit('parsley:field:success', that);
      })
      .fail(function () {
        $.emit('parsley:field:error', that);
      })
      .always(function () {
        $.emit('parsley:field:validated', that);
      });
  },

  _asyncIsValidField: function (force, value) {
    var
      deferred = $.Deferred(),
      remoteConstraintIndex;

    // If regular isValid (matching regular constraints) returns `false`, no need to go further
    // Directly reject promise, do not run remote validator and save server load
    if (false === this.isValid(force, value))
      deferred.rejectWith(this);

    // If regular constraints are valid, and there is a remote validator registered, run it
    else if ('undefined' !== typeof this.constraintsByName.remote)
      this._remote(deferred);

    // Otherwise all is good, resolve promise
    else
      deferred.resolveWith(this);

    // Return promise
    return deferred.promise();
  },

  _remote: function (deferred) {
    var
      that = this,
      data = {},
      ajaxOptions,
      csr,
      validator = this.options.remoteValidator || (true === this.options.remoteReverse ? 'reverse' : 'default');

    validator = validator.toLowerCase();

    if ('undefined' === typeof this.asyncValidators[validator])
      throw new Error('Calling an undefined async validator: `' + validator + '`');

    // Fill data with current value
    data[this.$element.attr('name') || this.$element.attr('id')] = this.getValue();

    // Merge options passed in from the function with the ones in the attribute
    this.options.remoteOptions = $.extend(true, this.options.remoteOptions || {} , this.asyncValidators[validator].options);

    // All `$.ajax(options)` could be overridden or extended directly from DOM in `data-parsley-remote-options`
    ajaxOptions = $.extend(true, {}, {
      url: this.asyncValidators[validator].url || this.options.remote,
      data: data,
      type: 'GET'
    }, this.options.remoteOptions || {});

    // Generate store key based on ajax options
    csr = $.param(ajaxOptions);

    // Initialise querry cache
    if ('undefined' === typeof this._remoteCache)
      this._remoteCache = {};

    // Try to retrieve stored xhr
    if (!this._remoteCache[csr]) {
      // Prevent multi burst xhr queries
      if (this._xhr && 'pending' === this._xhr.state())
        this._xhr.abort();

      // Make ajax call
      this._xhr =  $.ajax(ajaxOptions)

      // Store remote call result to avoid next calls with exact same parameters
      this._remoteCache[csr] = this._xhr;
    }

    this._remoteCache[csr]
      .done(function (data, textStatus, xhr) {
        that._handleRemoteResult(validator, xhr, deferred);
      })
      .fail(function (xhr, status, message) {
        // If we aborted the query, do not handle nothing for this value
        if ('abort' === status)
          return;

        that._handleRemoteResult(validator, xhr, deferred);
      });
  },

  _handleRemoteResult: function (validator, xhr, deferred) {
    // If true, simply resolve and exit
    if ('function' === typeof this.asyncValidators[validator].fn && this.asyncValidators[validator].fn(xhr)) {
      deferred.resolveWith(this);

      return;
    }

    // Else, create a proper remote validation Violation to trigger right UI
    this.validationResult = [
      new window.ParsleyValidator.Validator.Violation(
        this.constraintsByName.remote,
        this.getValue(),
        null
      )
    ];

    deferred.rejectWith(this);
  }
});

// Remote validator is just an always true sync validator with lowest (-1) priority possible
// It will be overloaded in `validateThroughValidator()` that will do the heavy async work
// This 'hack' is needed not to mess up too much with error messages and stuff in `ParsleyUI`
window.ParsleyConfig = window.ParsleyConfig || {};
window.ParsleyConfig.validators = window.ParsleyConfig.validators || {};
window.ParsleyConfig.validators.remote = {
  fn: function () {
    return true;
  },
  priority: -1
};
<|endoftext|>


<commit_before>var React = require('react');
var ReactNative = require('react-native');
var assign = require('object-assign');
var PropTypes = require('prop-types');
var createReactClass = require('create-react-class');

var { StyleSheet, View, TouchableWithoutFeedback } = ReactNative;

var PageControl = createReactClass({
    propTypes: {
        numberOfPages: PropTypes.number.isRequired,
        currentPage: PropTypes.number,
        hidesForSinglePage: PropTypes.bool,
        pageIndicatorTintColor: PropTypes.string,
        currentPageIndicatorTintColor: PropTypes.string,
        indicatorSize: PropTypes.object,
        indicatorStyle: View.propTypes.style,
        currentIndicatorStyle: View.propTypes.style,
        onPageIndicatorPress: PropTypes.func
    },

    getDefaultProps: function () {
        return {
            numberOfPages: 0,
            currentPage: 0,
            hidesForSinglePage: false,
            pageIndicatorTintColor: 'gray',
            currentPageIndicatorTintColor: 'white',
            indicatorSize: {width: 8, height: 8},
            indicatorStyle: {},
            currentIndicatorStyle: {},
            onPageIndicatorPress: function() {}
        };
    },

    onPageIndicatorPress: function(idx) {
        this.props.onPageIndicatorPress(idx);
    },

    render: function () {
        var { style, ...props } = this.props;

        var defaultStyle = {
            height: this.props.indicatorSize.height
        };

        var indicatorItemStyle = {
            width: this.props.indicatorSize.width,
            height: this.props.indicatorSize.height,
            borderRadius: this.props.indicatorSize.height / 2,
            marginLeft: 5,
            marginRight: 5
        };

        var indicatorStyle = {
          ...indicatorItemStyle,
          ...this.props.indicatorStyle,
          ...{
            backgroundColor: this.props.pageIndicatorTintColor
          }
        };

        var currentIndicatorStyle = {
          ...indicatorItemStyle,
          ...this.props.currentIndicatorStyle,
          ...{
            backgroundColor: this.props.currentPageIndicatorTintColor
          }
        };

        var pages = [];
        for (var i = 0; i < this.props.numberOfPages; i++) {
            pages.push(i);
        }

        return (
          this.props.hidesForSinglePage && pages.length <= 1 ? null : <View style={[styles.container, defaultStyle, style]}>
            {pages.map((el, i) => <TouchableWithoutFeedback key={i} onPress={this.onPageIndicatorPress.bind(this, i)}>
              <View style={i == this.props.currentPage ? currentIndicatorStyle: indicatorStyle} >
                  {this.props.indicator && this.props.indicator(i)}
                </View>
            </TouchableWithoutFeedback>
            )}
          </View>
        );
    }
});

var styles = StyleSheet.create({
    container: {
        backgroundColor: 'transparent',
        alignItems: 'center',
        justifyContent: 'center',
        flexDirection: 'row'
    }
});

module.exports = PageControl;
<commit_msg>Revert "user defined indicator"<commit_after>var React = require('react');
var ReactNative = require('react-native');
var assign = require('object-assign');
var PropTypes = require('prop-types');
var createReactClass = require('create-react-class');

var { StyleSheet, View, TouchableWithoutFeedback } = ReactNative;

var PageControl = createReactClass({
    propTypes: {
        numberOfPages: PropTypes.number.isRequired,
        currentPage: PropTypes.number,
        hidesForSinglePage: PropTypes.bool,
        pageIndicatorTintColor: PropTypes.string,
        currentPageIndicatorTintColor: PropTypes.string,
        indicatorSize: PropTypes.object,
        indicatorStyle: View.propTypes.style,
        currentIndicatorStyle: View.propTypes.style,
        onPageIndicatorPress: PropTypes.func
    },

    getDefaultProps: function () {
        return {
            numberOfPages: 0,
            currentPage: 0,
            hidesForSinglePage: false,
            pageIndicatorTintColor: 'gray',
            currentPageIndicatorTintColor: 'white',
            indicatorSize: {width: 8, height: 8},
            indicatorStyle: {},
            currentIndicatorStyle: {},
            onPageIndicatorPress: function() {}
        };
    },

    onPageIndicatorPress: function(idx) {
        this.props.onPageIndicatorPress(idx);
    },

    render: function () {
        var { style, ...props } = this.props;

        var defaultStyle = {
            height: this.props.indicatorSize.height
        };

        var indicatorItemStyle = {
            width: this.props.indicatorSize.width,
            height: this.props.indicatorSize.height,
            borderRadius: this.props.indicatorSize.height / 2,
            marginLeft: 5,
            marginRight: 5
        };

        var indicatorStyle = {
          ...indicatorItemStyle,
          ...this.props.indicatorStyle,
          ...{
            backgroundColor: this.props.pageIndicatorTintColor
          }
        };

        var currentIndicatorStyle = {
          ...indicatorItemStyle,
          ...this.props.currentIndicatorStyle,
          ...{
            backgroundColor: this.props.currentPageIndicatorTintColor
          }
        };

        var pages = [];
        for (var i = 0; i < this.props.numberOfPages; i++) {
            pages.push(i);
        }

        return (
          this.props.hidesForSinglePage && pages.length <= 1 ? null : <View style={[styles.container, defaultStyle, style]}>
            {pages.map((el, i) => <TouchableWithoutFeedback key={i} onPress={this.onPageIndicatorPress.bind(this, i)}>
              <View style={i == this.props.currentPage ? currentIndicatorStyle: indicatorStyle} />
            </TouchableWithoutFeedback>
            )}
          </View>
        );
    }
});

var styles = StyleSheet.create({
    container: {
        backgroundColor: 'transparent',
        alignItems: 'center',
        justifyContent: 'center',
        flexDirection: 'row'
    }
});

module.exports = PageControl;
<|endoftext|>


<commit_before>/**
 * Synchronize zooming and/or selections between a set of dygraphs.
 *
 * Usage:
 *
 *   var g1 = new Dygraph(...),
 *       g2 = new Dygraph(...),
 *       ...;
 *   var sync = Dygraph.synchronize(g1, g2, ...);
 *   // charts are now synchronized
 *   sync.detach();
 *   // charts are no longer synchronized
 *
 * You can set options using the last parameter, for example:
 *
 *   var sync = Dygraph.synchronize(g1, g2, g3, {
 *      selection: true,
 *      zoom: true
 *   });
 *
 * The default is to synchronize both of these.
 *
 * Instead of passing one Dygraph object as each parameter, you may also pass an
 * array of dygraphs:
 *
 *   var sync = Dygraph.synchronize([g1, g2, g3], {
 *      selection: false,
 *      zoom: true
 *   });
 *
 * You may also set `range: false` if you wish to only sync the x-axis.
 * The `range` option has no effect unless `zoom` is true (the default).
 */
(function() {
/* global Dygraph:false */
'use strict';

Dygraph.synchronize = function(/* dygraphs..., opts */) {
  if (arguments.length === 0) {
    throw 'Invalid invocation of Dygraph.synchronize(). Need >= 1 argument.';
  }

  var OPTIONS = ['selection', 'zoom', 'range'];
  var opts = {
    selection: true,
    zoom: true,
    range: true
  };
  var dygraphs = [];
  var prevCallbacks = [];

  var parseOpts = function(obj) {
    if (!(obj instanceof Object)) {
      throw 'Last argument must be either Dygraph or Object.';
    } else {
      for (var i = 0; i < OPTIONS.length; i++) {
        var optName = OPTIONS[i];
        if (obj.hasOwnProperty(optName)) opts[optName] = obj[optName];
      }
    }
  };

  if (arguments[0] instanceof Dygraph) {
    // Arguments are Dygraph objects.
    for (var i = 0; i < arguments.length; i++) {
      if (arguments[i] instanceof Dygraph) {
        dygraphs.push(arguments[i]);
      } else {
        break;
      }
    }
    if (i < arguments.length - 1) {
      throw 'Invalid invocation of Dygraph.synchronize(). ' +
            'All but the last argument must be Dygraph objects.';
    } else if (i == arguments.length - 1) {
      parseOpts(arguments[arguments.length - 1]);
    }
  } else if (arguments[0].length) {
    // Invoked w/ list of dygraphs, options
    for (var i = 0; i < arguments[0].length; i++) {
      dygraphs.push(arguments[0][i]);
    }
    if (arguments.length == 2) {
      parseOpts(arguments[1]);
    } else if (arguments.length > 2) {
      throw 'Invalid invocation of Dygraph.synchronize(). ' +
            'Expected two arguments: array and optional options argument.';
    }  // otherwise arguments.length == 1, which is fine.
  } else {
    throw 'Invalid invocation of Dygraph.synchronize(). ' +
          'First parameter must be either Dygraph or list of Dygraphs.';
  }

  if (dygraphs.length < 2) {
    throw 'Invalid invocation of Dygraph.synchronize(). ' +
          'Need two or more dygraphs to synchronize.';
  }

  var readycount = dygraphs.length;
  for (var i = 0; i < dygraphs.length; i++) {
    var g = dygraphs[i];
    g.ready( function() {
      if (--readycount == 0) {
        // store original callbacks
        var callBackTypes = ['drawCallback', 'highlightCallback', 'unhighlightCallback'];
        for (var j = 0; j < dygraphs.length; j++) {
          if (!prevCallbacks[j]) {
            prevCallbacks[j] = {};
          }
          for (var k = callBackTypes.length - 1; k >= 0; k--) {
            prevCallbacks[j][callBackTypes[k]] = dygraphs[j].getFunctionOption(callBackTypes[k]);
          }
        }

        // Listen for draw, highlight, unhighlight callbacks.
        if (opts.zoom) {
          attachZoomHandlers(dygraphs, opts, prevCallbacks);
        }

        if (opts.selection) {
          attachSelectionHandlers(dygraphs, prevCallbacks);
        }
      }
    });
  }

  return {
    detach: function() {
      for (var i = 0; i < dygraphs.length; i++) {
        var g = dygraphs[i];
        if (opts.zoom) {
          g.updateOptions({drawCallback: prevCallbacks[i].drawCallback});
        }
        if (opts.selection) {
          g.updateOptions({
            highlightCallback: prevCallbacks[i].highlightCallback,
            unhighlightCallback: prevCallbacks[i].unhighlightCallback
          });
        }
      }
      // release references & make subsequent calls throw.
      dygraphs = null;
      opts = null;
      prevCallbacks = null;
    }
  };
};

function attachZoomHandlers(gs, syncOpts, prevCallbacks) {
  var block = false;
  for (var i = 0; i < gs.length; i++) {
    var g = gs[i];
    g.updateOptions({
      drawCallback: function(me, initial) {
        if (block || initial) return;
        block = true;
        var opts = {
          dateWindow: me.xAxisRange()
        };
        if (syncOpts.range) opts.valueRange = me.yAxisRange();

        for (var j = 0; j < gs.length; j++) {
          if (gs[j] == me) {
            if (prevCallbacks[j] && prevCallbacks[j].drawCallback) {
              prevCallbacks[j].drawCallback.apply(this, arguments);
            }
            continue;
          }
          gs[j].updateOptions(opts);
        }
        block = false;
      }
    }, false /* no need to redraw */);
  }
}

function attachSelectionHandlers(gs, prevCallbacks) {
  var block = false;
  for (var i = 0; i < gs.length; i++) {
    var g = gs[i];

    g.updateOptions({
      highlightCallback: function(event, x, points, row, seriesName) {
        if (block) return;
        block = true;
        var me = this;
        for (var i = 0; i < gs.length; i++) {
          if (me == gs[i]) {
            if (prevCallbacks[i] && prevCallbacks[i].highlightCallback) {
              prevCallbacks[i].highlightCallback.apply(this, arguments);
            }
            continue;
          }
          var idx = gs[i].getRowForX(x);
          if (idx !== null) {
            gs[i].setSelection(idx, seriesName);
          }
        }
        block = false;
      },
      unhighlightCallback: function(event) {
        if (block) return;
        block = true;
        var me = this;
        for (var i = 0; i < gs.length; i++) {
          if (me == gs[i]) {
            if (prevCallbacks[i] && prevCallbacks[i].unhighlightCallback) {
              prevCallbacks[i].unhighlightCallback.apply(this, arguments);
            }
            continue;
          }
          gs[i].clearSelection();
        }
        block = false;
      }
    });
  }
}

})();
<commit_msg>Fix true/false redraw blocking bug in synchronizer<commit_after>/**
 * Synchronize zooming and/or selections between a set of dygraphs.
 *
 * Usage:
 *
 *   var g1 = new Dygraph(...),
 *       g2 = new Dygraph(...),
 *       ...;
 *   var sync = Dygraph.synchronize(g1, g2, ...);
 *   // charts are now synchronized
 *   sync.detach();
 *   // charts are no longer synchronized
 *
 * You can set options using the last parameter, for example:
 *
 *   var sync = Dygraph.synchronize(g1, g2, g3, {
 *      selection: true,
 *      zoom: true
 *   });
 *
 * The default is to synchronize both of these.
 *
 * Instead of passing one Dygraph object as each parameter, you may also pass an
 * array of dygraphs:
 *
 *   var sync = Dygraph.synchronize([g1, g2, g3], {
 *      selection: false,
 *      zoom: true
 *   });
 *
 * You may also set `range: false` if you wish to only sync the x-axis.
 * The `range` option has no effect unless `zoom` is true (the default).
 */
(function() {
/* global Dygraph:false */
'use strict';

Dygraph.synchronize = function(/* dygraphs..., opts */) {
  if (arguments.length === 0) {
    throw 'Invalid invocation of Dygraph.synchronize(). Need >= 1 argument.';
  }

  var OPTIONS = ['selection', 'zoom', 'range'];
  var opts = {
    selection: true,
    zoom: true,
    range: true
  };
  var dygraphs = [];
  var prevCallbacks = [];

  var parseOpts = function(obj) {
    if (!(obj instanceof Object)) {
      throw 'Last argument must be either Dygraph or Object.';
    } else {
      for (var i = 0; i < OPTIONS.length; i++) {
        var optName = OPTIONS[i];
        if (obj.hasOwnProperty(optName)) opts[optName] = obj[optName];
      }
    }
  };

  if (arguments[0] instanceof Dygraph) {
    // Arguments are Dygraph objects.
    for (var i = 0; i < arguments.length; i++) {
      if (arguments[i] instanceof Dygraph) {
        dygraphs.push(arguments[i]);
      } else {
        break;
      }
    }
    if (i < arguments.length - 1) {
      throw 'Invalid invocation of Dygraph.synchronize(). ' +
            'All but the last argument must be Dygraph objects.';
    } else if (i == arguments.length - 1) {
      parseOpts(arguments[arguments.length - 1]);
    }
  } else if (arguments[0].length) {
    // Invoked w/ list of dygraphs, options
    for (var i = 0; i < arguments[0].length; i++) {
      dygraphs.push(arguments[0][i]);
    }
    if (arguments.length == 2) {
      parseOpts(arguments[1]);
    } else if (arguments.length > 2) {
      throw 'Invalid invocation of Dygraph.synchronize(). ' +
            'Expected two arguments: array and optional options argument.';
    }  // otherwise arguments.length == 1, which is fine.
  } else {
    throw 'Invalid invocation of Dygraph.synchronize(). ' +
          'First parameter must be either Dygraph or list of Dygraphs.';
  }

  if (dygraphs.length < 2) {
    throw 'Invalid invocation of Dygraph.synchronize(). ' +
          'Need two or more dygraphs to synchronize.';
  }

  var readycount = dygraphs.length;
  for (var i = 0; i < dygraphs.length; i++) {
    var g = dygraphs[i];
    g.ready( function() {
      if (--readycount == 0) {
        // store original callbacks
        var callBackTypes = ['drawCallback', 'highlightCallback', 'unhighlightCallback'];
        for (var j = 0; j < dygraphs.length; j++) {
          if (!prevCallbacks[j]) {
            prevCallbacks[j] = {};
          }
          for (var k = callBackTypes.length - 1; k >= 0; k--) {
            prevCallbacks[j][callBackTypes[k]] = dygraphs[j].getFunctionOption(callBackTypes[k]);
          }
        }

        // Listen for draw, highlight, unhighlight callbacks.
        if (opts.zoom) {
          attachZoomHandlers(dygraphs, opts, prevCallbacks);
        }

        if (opts.selection) {
          attachSelectionHandlers(dygraphs, prevCallbacks);
        }
      }
    });
  }

  return {
    detach: function() {
      for (var i = 0; i < dygraphs.length; i++) {
        var g = dygraphs[i];
        if (opts.zoom) {
          g.updateOptions({drawCallback: prevCallbacks[i].drawCallback});
        }
        if (opts.selection) {
          g.updateOptions({
            highlightCallback: prevCallbacks[i].highlightCallback,
            unhighlightCallback: prevCallbacks[i].unhighlightCallback
          });
        }
      }
      // release references & make subsequent calls throw.
      dygraphs = null;
      opts = null;
      prevCallbacks = null;
    }
  };
};

function attachZoomHandlers(gs, syncOpts, prevCallbacks) {
  var block = false;
  for (var i = 0; i < gs.length; i++) {
    var g = gs[i];
    g.updateOptions({
      drawCallback: function(me, initial) {
        if (block || initial) return;
        block = true;
        var opts = {
          dateWindow: me.xAxisRange()
        };
        if (syncOpts.range) opts.valueRange = me.yAxisRange();

        for (var j = 0; j < gs.length; j++) {
          if (gs[j] == me) {
            if (prevCallbacks[j] && prevCallbacks[j].drawCallback) {
              prevCallbacks[j].drawCallback.apply(this, arguments);
            }
            continue;
          }
          gs[j].updateOptions(opts);
        }
        block = false;
      }
    }, true /* no need to redraw */);
  }
}

function attachSelectionHandlers(gs, prevCallbacks) {
  var block = false;
  for (var i = 0; i < gs.length; i++) {
    var g = gs[i];

    g.updateOptions({
      highlightCallback: function(event, x, points, row, seriesName) {
        if (block) return;
        block = true;
        var me = this;
        for (var i = 0; i < gs.length; i++) {
          if (me == gs[i]) {
            if (prevCallbacks[i] && prevCallbacks[i].highlightCallback) {
              prevCallbacks[i].highlightCallback.apply(this, arguments);
            }
            continue;
          }
          var idx = gs[i].getRowForX(x);
          if (idx !== null) {
            gs[i].setSelection(idx, seriesName);
          }
        }
        block = false;
      },
      unhighlightCallback: function(event) {
        if (block) return;
        block = true;
        var me = this;
        for (var i = 0; i < gs.length; i++) {
          if (me == gs[i]) {
            if (prevCallbacks[i] && prevCallbacks[i].unhighlightCallback) {
              prevCallbacks[i].unhighlightCallback.apply(this, arguments);
            }
            continue;
          }
          gs[i].clearSelection();
        }
        block = false;
      }
    }, true /* no need to redraw */);
  }
}

})();
<|endoftext|>


<commit_before>import Ember from 'ember';
import joint from 'npm:jointjs';

export default Ember.Controller.extend({
  actions: {
    printDiagram: function() {
      let _this = this;
      Ember.run.schedule('afterRender',	function() {
        _this.graph = new joint.dia.Graph();

        let paper = document.getElementById('paper');
        let minX = 16384;
        let minY = 16384;
        let maxX = 0;
        let maxY = 0;
        let sidebar = Ember.$('.ui.sidebar.main.menu');
        let sidebarWidth = sidebar.hasClass('visible') ? sidebar.width() : 0;

        if (minX > maxX) {
          maxX = paper && ('offsetWidth' in paper) ? paper.offsetWidth : 1024;
          maxX += sidebarWidth;
          maxY = 840;
        } else {
          maxX = minX + maxX + sidebarWidth;
          maxY = minY + maxY;
        }

        _this.paper = new joint.dia.Paper({
          el: paper,
          width: maxX,
          height: maxY,
          gridSize: 1,
          model: _this.graph,
        });

        var linkAggregation = new joint.shapes.flexberryUml.Aggregation({
          source: { x:100, y:30 },
          target: { x:300, y:30 },
        });

        var linkAssociation = new joint.shapes.flexberryUml.Association({
          source: { x:100, y:80 },
          target: { x:300, y:80 },
          labels: [{
            attrs: { text: { text:  '*' } } }, {
            attrs: { text: { text:  '0..1' } }
          }]
        });

        var linkComposition = new joint.shapes.flexberryUml.Composition({
          source: { x:100, y:120 },
          target: { x:300, y:120 },
        });

        var linkDependency = new joint.shapes.flexberryUml.Dependency({
          source: { x:100, y:170 },
          target: { x:300, y:170 },
        });

        var linkRealization = new joint.shapes.flexberryUml.Realization({
          source: { x:100, y:220 },
          target: { x:300, y:220 },
        });

        var linkGeneralization = new joint.shapes.flexberryUml.Generalization({
          source: { x:100, y:270 },
          target: { x:300, y:270 },
        });

        var linkQualified = new joint.shapes.flexberryUml.Qualified({
          source: { x:100, y:320 },
          target: { x:300, y:320 },
        });

        var linkQualifiedAggregation = new joint.shapes.flexberryUml.QualifiedAggregation({
          source: { x:100, y:370 },
          target: { x:300, y:370 },
        });

        var linkQualifiedComposition = new joint.shapes.flexberryUml.QualifiedComposition({
          source: { x:100, y:420 },
          target: { x:300, y:420 },
        });

        var linkNestedClassAssociation = new joint.shapes.flexberryUml.NestedClassAssociation({
          source: { x:100, y:470 },
          target: { x:300, y:470 },
        });

        var linkNoteConnector = new joint.shapes.flexberryUml.NoteConnector({
          source: { x:100, y:520 },
          target: { x:300, y:520 },
        });

        _this.graph.addCell([linkAggregation, linkAssociation, linkComposition, linkDependency,
          linkRealization, linkGeneralization, linkQualified, linkQualifiedAggregation,
          linkQualifiedComposition, linkNestedClassAssociation, linkNoteConnector]);

        let attributes = ['attr1', 'attr2'];
        let methods = ['method1'];

        let classWithoutStp = new joint.shapes.flexberryUml.Class({
          position: { x: 350, y: 30 },
          name: 'Class1',
          attributes: attributes,
          methods: methods,
        });

        let classCollapsed = new joint.shapes.flexberryUml.ClassCollapsed({
          position: { x: 450, y: 30 },
          size: { width: 100 },
          name: 'ClassCollapsed',
          attributes: attributes,
          methods: methods,
        });

        let classWithStp = new joint.shapes.flexberryUml.Class({
          position: { x: 350, y: 150 },
          name: 'Class2textextext',
          stereotype: 'enumeration',
          attributes: attributes,
          methods: methods,
        });

        let nAryAssociation = new joint.shapes.flexberryUml.NAryAssociation({
          position: { x: 550, y: 30 },
          size: { width: 150, height: 75 },
          name: 'n-ary Association'
        });

        let obj = new joint.shapes.flexberryUml.Object({
          position: { x: 350, y: 300 },
          name: 'Object',
          attributes: attributes,
          methods: methods,
        });

        var instance = new joint.shapes.flexberryUml.Instance({
          position: { x: 350, y: 400 },
          name: 'Instance'
        });

        var multiObject = new joint.shapes.flexberryUml.MultiObject({
          position: { x: 350, y: 500 },
          size: { width: 150, height: 40 },
          name: 'multiObject'
        });

        var activeObj = new joint.shapes.flexberryUml.ActiveObject({
          position: { x: 350, y: 600 },
          name: 'Active object'
        });

        let templateClass = new joint.shapes.flexberryUml.TemplateClass({
          position: { x: 550, y: 150 },
          name: 'Class2textextext',
          attributes: attributes,
          methods: methods,
          params: 'params'
        });

        let note = new joint.shapes.flexberryUml.Note({
          position: { x: 550, y: 300 },
          name: 'Comment'
        });

        let moreClasses = new joint.shapes.flexberryUml.MoreClasses({
          position: { x: 550, y: 400 },
        });

        let packagePr = new joint.shapes.flexberryUml.Package({
          position: { x: 550, y: 500 },
          name: 'Class2',
          attributes: attributes,
        });

        _this.graph.addCell([classWithoutStp, classCollapsed, classWithStp, nAryAssociation, obj, instance, multiObject, activeObj,
          templateClass, note, moreClasses, packagePr]);
      });
    }
  }
});
<commit_msg>Fix JSHint error<commit_after>import Ember from 'ember';
import joint from 'npm:jointjs';

export default Ember.Controller.extend({
  actions: {
    printDiagram: function() {
      let _this = this;
      Ember.run.schedule('afterRender',	function() {
        _this.graph = new joint.dia.Graph();

        let paper = document.getElementById('paper');
        let minX = 16384;
        let minY = 16384;
        let maxX = 0;
        let maxY = 0;
        let sidebar = Ember.$('.ui.sidebar.main.menu');
        let sidebarWidth = sidebar.hasClass('visible') ? sidebar.width() : 0;

        if (minX > maxX) {
          maxX = paper && ('offsetWidth' in paper) ? paper.offsetWidth : 1024;
          maxX += sidebarWidth;
          maxY = 840;
        } else {
          maxX = minX + maxX + sidebarWidth;
          maxY = minY + maxY;
        }

        _this.paper = new joint.dia.Paper({
          el: paper,
          width: maxX,
          height: maxY,
          gridSize: 1,
          model: _this.graph,
        });

        var linkAggregation = new joint.shapes.flexberryUml.Aggregation({
          source: { x:100, y:30 },
          target: { x:300, y:30 },
        });

        var linkAssociation = new joint.shapes.flexberryUml.Association({
          source: { x:100, y:80 },
          target: { x:300, y:80 },
          labels: [{
            attrs: { text: { text:  '*' } } }, {
            attrs: { text: { text:  '0..1' } }
          }]
        });

        var linkComposition = new joint.shapes.flexberryUml.Composition({
          source: { x:100, y:120 },
          target: { x:300, y:120 },
        });

        var linkDependency = new joint.shapes.flexberryUml.Dependency({
          source: { x:100, y:170 },
          target: { x:300, y:170 },
        });

        var linkRealization = new joint.shapes.flexberryUml.Realization({
          source: { x:100, y:220 },
          target: { x:300, y:220 },
        });

        var linkGeneralization = new joint.shapes.flexberryUml.Generalization({
          source: { x:100, y:270 },
          target: { x:300, y:270 },
        });

        var linkQualified = new joint.shapes.flexberryUml.Qualified({
          source: { x:100, y:320 },
          target: { x:300, y:320 },
        });

        var linkQualifiedAggregation = new joint.shapes.flexberryUml.QualifiedAggregation({
          source: { x:100, y:370 },
          target: { x:300, y:370 },
        });

        var linkQualifiedComposition = new joint.shapes.flexberryUml.QualifiedComposition({
          source: { x:100, y:420 },
          target: { x:300, y:420 },
        });

        var linkNestedClassAssociation = new joint.shapes.flexberryUml.NestedClassAssociation({
          source: { x:100, y:470 },
          target: { x:300, y:470 },
        });

        var linkNoteConnector = new joint.shapes.flexberryUml.NoteConnector({
          source: { x:100, y:520 },
          target: { x:300, y:520 },
        });

        _this.graph.addCell([linkAggregation, linkAssociation, linkComposition, linkDependency,
          linkRealization, linkGeneralization, linkQualified, linkQualifiedAggregation,
          linkQualifiedComposition, linkNestedClassAssociation, linkNoteConnector]);

        let attributes = ['attr1', 'attr2'];
        let methods = ['method1'];

        let classWithoutStp = new joint.shapes.flexberryUml.Class({
          position: { x: 350, y: 30 },
          name: 'Class1',
          attributes: attributes,
          methods: methods,
        });

        let classCollapsed = new joint.shapes.flexberryUml.ClassCollapsed({
          position: { x: 450, y: 30 },
          size: { width: 100 },
          name: 'ClassCollapsed',
          attributes: attributes,
          methods: methods,
        });

        let classWithStp = new joint.shapes.flexberryUml.Class({
          position: { x: 350, y: 150 },
          name: 'Class2textextext',
          stereotype: 'enumeration',
          attributes: attributes,
          methods: methods,
        });

        let nAryAssociation = new joint.shapes.flexberryUml.NAryAssociation({
          position: { x: 550, y: 30 },
          size: { width: 150, height: 75 },
          name: 'n-ary Association'
        });

        let obj = new joint.shapes.flexberryUml.Object({
          position: { x: 350, y: 300 },
          name: 'Object',
          attributes: attributes,
          methods: methods,
        });

        var instance = new joint.shapes.flexberryUml.Instance({
          position: { x: 350, y: 400 },
          name: 'Instance'
        });

        var multiObject = new joint.shapes.flexberryUml.MultiObject({
          position: { x: 350, y: 500 },
          size: { width: 150, height: 40 },
          name: 'multiObject'
        });

        var activeObj = new joint.shapes.flexberryUml.ActiveObject({
          position: { x: 350, y: 600 },
          name: 'Active object'
        });

        let templateClass = new joint.shapes.flexberryUml.TemplateClass({
          position: { x: 550, y: 150 },
          name: 'Class2textextext',
          attributes: attributes,
          methods: methods,
          params: 'params'
        });

        let note = new joint.shapes.flexberryUml.Note({
          position: { x: 550, y: 300 },
          name: 'Comment'
        });

        let moreClasses = new joint.shapes.flexberryUml.MoreClasses({
          position: { x: 550, y: 400 },
        });

        let packagePr = new joint.shapes.flexberryUml.Package({
          position: { x: 550, y: 500 },
          name: 'Class2',
          attributes: attributes,
        });

        _this.graph.addCell([classWithoutStp, classCollapsed, classWithStp, nAryAssociation, obj, instance, multiObject, activeObj,
          templateClass, note, moreClasses, packagePr]);
      });
    }
  }
});
<|endoftext|>


<commit_before>var AbstractCamera = require('./AbstractCamera');
var Vec2 = require('pex-math/Vec2');
var Vec3 = require('pex-math/Vec3');
var Vec4 = require('pex-math/Vec4');
var Mat4 = require('pex-math/Mat4');

var DEFAULT_FOV          = 60.0;
var DEFAULT_NEAR         = 0.01;
var DEFAULT_FAR          = 10.0;
var DEFAULT_ASPECT_RATIO = 4 / 3;

var TEMP_VEC2   = Vec2.create();
var TEMP_VEC3_0 = Vec3.create();
var TEMO_VEC3_1 = Vec3.create();
var TEMP_VEC3_2 = Vec3.create();
var TEMP_VEC4   = Vec4.create();
var TEMP_MAT4   = Mat4.create();

function PerspCamera(fov, aspectRatio, near, far){
    AbstractCamera.call(this);

    this._aspectRatio = aspectRatio;

    this.setPerspective(
        fov         === undefined ? DEFAULT_FOV : fov,
        aspectRatio === undefined ? DEFAULT_ASPECT_RATIO : aspectRatio,
        near        === undefined ? DEFAULT_NEAR : near,
        far         === undefined ? DEFAULT_FAR : far
    );

    this.updateViewMatrix();
}

PerspCamera.prototype = Object.create(AbstractCamera.prototype);
PerspCamera.prototype.constructor = PerspCamera;

PerspCamera.prototype.setFov = function(fov){
    this._fov = fov;
    this._matrixProjectionDirty = true;
};

PerspCamera.prototype.getFov = function(){
    return this._fov;
};

PerspCamera.prototype.setAspectRatio = function(aspectRatio){
    this._aspectRatio = aspectRatio;
    this._matrixProjectionDirty = true;
};

PerspCamera.prototype.setDistance = function(distance){
    Vec3.sub(this._position, this._target);
    Vec3.normalize(this._position);
    Vec3.scale(this._position, distance);
    this._matrixViewDirty = true;
};

PerspCamera.prototype.setPerspective = function(fov, aspectRatio, near, far){
    this._fov         = fov;
    this._aspectRatio = aspectRatio;
    this._near        = near;
    this._far         = far;
    this._matrixProjectionDirty = true;
    this.updateProjectionMatrix();
};

PerspCamera.prototype.updateProjectionMatrix = function(){
    if(!this._matrixProjectionDirty){
        return;
    }
    Mat4.perspective(this._matrixProjection, this._fov, this._aspectRatio, this._near, this._far);
    this._matrixProjectionDirty = false;
};

PerspCamera.prototype.getViewRay = function(point, width, height, out){
    out = out === undefined ? Vec2.create() : out;

    var width_2  = width * 0.5;
    var height_2 = height * 0.5;

    point = Vec2.set2(TEMP_VEC2, (point[0] - width_2) / width_2, -(point[1] - height_2) / height_2);

    var hnear = 2 * Math.tan(this._fov / 180 * Math.PI * 0.5) * this._near;
    var wnear = hnear * this._aspectRatio;

    point[0] *= hnear * 0.5;
    point[1] *= wnear * 0.5;

    var origin    = Vec3.toZero(TEMP_VEC3_0);
    var target    = Vec3.set3(TEMO_VEC3_1, point[0], point[1], -this._near);
    var direction = Vec3.normalize(Vec3.sub(Vec3.set(TEMP_VEC3_2, target), origin));

    out[0] = origin;
    out[1] = direction;

    return out;
};

PerspCamera.prototype.setFrustumOffset = function(x, y, width, height, widthTotal, heightTotal){
    widthTotal  = widthTotal === undefined ? width : widthTotal;
    heightTotal = heightTotal === undefined ? height : heightTotal;

    var near = this._near;
    var far  = this._far;

    var aspectRatio = widthTotal / heightTotal;

    var top     = Math.tan(this._fov * Math.PI / 180 * 0.5) * near;
    var bottom  = -top;
    var left    = aspectRatio * bottom;
    var right   = aspectRatio * top;
    var width_  = Math.abs(right - left);
    var height_ = Math.abs(top - bottom);
    var widthNormalized  = width_ / widthTotal;
    var heightNormalized = height_ / heightTotal;

    var l = left + x * widthNormalized;
    var r = left + (x + width) * widthNormalized;
    var b = top - (y + height) * heightNormalized;
    var t = top - y * heightNormalized;

    Mat4.frustum(this._matrixProjection, l, r, b, t, near, far);
};

module.exports = PerspCamera;<commit_msg>PerspCamera removed matrix update in constructor, made updateProjectionMatrix private<commit_after>var AbstractCamera = require('./AbstractCamera');
var Vec2 = require('pex-math/Vec2');
var Vec3 = require('pex-math/Vec3');
var Vec4 = require('pex-math/Vec4');
var Mat4 = require('pex-math/Mat4');

var DEFAULT_FOV          = 60.0;
var DEFAULT_NEAR         = 0.01;
var DEFAULT_FAR          = 10.0;
var DEFAULT_ASPECT_RATIO = 4 / 3;

var TEMP_VEC2   = Vec2.create();
var TEMP_VEC3_0 = Vec3.create();
var TEMO_VEC3_1 = Vec3.create();
var TEMP_VEC3_2 = Vec3.create();
var TEMP_VEC4   = Vec4.create();
var TEMP_MAT4   = Mat4.create();

function PerspCamera(fov, aspectRatio, near, far){
    AbstractCamera.call(this);

    this._aspectRatio = aspectRatio;

    this.setPerspective(
        fov         === undefined ? DEFAULT_FOV : fov,
        aspectRatio === undefined ? DEFAULT_ASPECT_RATIO : aspectRatio,
        near        === undefined ? DEFAULT_NEAR : near,
        far         === undefined ? DEFAULT_FAR : far
    );
}

PerspCamera.prototype = Object.create(AbstractCamera.prototype);
PerspCamera.prototype.constructor = PerspCamera;

PerspCamera.prototype.setFov = function(fov){
    this._fov = fov;
    this._matrixProjectionDirty = true;
};

PerspCamera.prototype.getFov = function(){
    return this._fov;
};

PerspCamera.prototype.setAspectRatio = function(aspectRatio){
    this._aspectRatio = aspectRatio;
    this._matrixProjectionDirty = true;
};

PerspCamera.prototype.setDistance = function(distance){
    Vec3.sub(this._position, this._target);
    Vec3.normalize(this._position);
    Vec3.scale(this._position, distance);
    this._matrixViewDirty = true;
};

PerspCamera.prototype.setPerspective = function(fov, aspectRatio, near, far){
    this._fov         = fov;
    this._aspectRatio = aspectRatio;
    this._near        = near;
    this._far         = far;
    this._matrixProjectionDirty = true;
};

PerspCamera.prototype._updateProjectionMatrix = function(){
    if(!this._matrixProjectionDirty){
        return;
    }
    Mat4.perspective(this._matrixProjection, this._fov, this._aspectRatio, this._near, this._far);
    this._matrixProjectionDirty = false;
};

PerspCamera.prototype.getViewRay = function(point, width, height, out){
    out = out === undefined ? Vec2.create() : out;

    var width_2  = width * 0.5;
    var height_2 = height * 0.5;

    point = Vec2.set2(TEMP_VEC2, (point[0] - width_2) / width_2, -(point[1] - height_2) / height_2);

    var hnear = 2 * Math.tan(this._fov / 180 * Math.PI * 0.5) * this._near;
    var wnear = hnear * this._aspectRatio;

    point[0] *= hnear * 0.5;
    point[1] *= wnear * 0.5;

    var origin    = Vec3.toZero(TEMP_VEC3_0);
    var target    = Vec3.set3(TEMO_VEC3_1, point[0], point[1], -this._near);
    var direction = Vec3.normalize(Vec3.sub(Vec3.set(TEMP_VEC3_2, target), origin));

    out[0] = origin;
    out[1] = direction;

    return out;
};

PerspCamera.prototype.setFrustumOffset = function(x, y, width, height, widthTotal, heightTotal){
    widthTotal  = widthTotal === undefined ? width : widthTotal;
    heightTotal = heightTotal === undefined ? height : heightTotal;

    var near = this._near;
    var far  = this._far;

    var aspectRatio = widthTotal / heightTotal;

    var top     = Math.tan(this._fov * Math.PI / 180 * 0.5) * near;
    var bottom  = -top;
    var left    = aspectRatio * bottom;
    var right   = aspectRatio * top;
    var width_  = Math.abs(right - left);
    var height_ = Math.abs(top - bottom);
    var widthNormalized  = width_ / widthTotal;
    var heightNormalized = height_ / heightTotal;

    var l = left + x * widthNormalized;
    var r = left + (x + width) * widthNormalized;
    var b = top - (y + height) * heightNormalized;
    var t = top - y * heightNormalized;

    Mat4.frustum(this._matrixProjection, l, r, b, t, near, far);
};

module.exports = PerspCamera;<|endoftext|>


<commit_before>'use strict';
/*jshint asi:true */

var test = require('tap').test
  , validate = require('../validate-requires')
  , path = require('path')
  , pathToModule = path.join(__dirname, './some-module.js')

test('\ngiven ./deps/uno.js ./deps/dos.js ./deps/tres.js', function (t) {
  t.test('\n# when a module requires ./deps/uno', function (t) {
    var src = '' + function foo() {
      require('./deps/uno');
    }
    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 0, 'finds no error')
      t.end()
    })
  })

  t.test('\n# when a module requires ./Deps/uno.js ./deps/dos.js ', function (t) {
    var src = '' + function foo() {
      require('./Deps/uno.js');
      require('./deps/dos.js');
    }

    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 1, 'finds one error')
      t.similar(errors[0].message, /doesn't exactly match .*directory path/, 'warns that directory paths do not exactly match')
      t.end()
    })
  })

  t.test('\n# when a module requires ./deps/uNo.js ./deps/dos.js ', function (t) {
    var src = '' + function foo() {
      require('./deps/uNo.js');
      require('./deps/dos.js');
    }

    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 1, 'finds one error')
      t.similar(errors[0].message, /uNo.+doesn't exactly match .*file path/, 'warns that file paths do not exactly match')
      t.similar(errors[0].message, /.+uno.+/, 'includes file that was inexactly matched in the message')
      t.end()
    })
  })

  t.test('\n# when a module requires ./deps/dos.js ./deps/cuatro.js', function (t) {
    var src = '' + function foo() {
      require('./deps/dos.js');
      require('./deps/cuatro.js');
    }

    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 1, 'finds one error')
      t.similar(errors[0].message, /Cannot find module/, 'warns that module does not exist')
      t.end()
    })
  })

  t.test('\n# when a module requires ./deps/Uno.js ./deps/dos.js ./deps/cuatro.js', function (t) {
    var src = '' + function foo() {
      require('./deps/Uno.js');
      require('./deps/dos.js');
      require('./deps/cuatro.js');
    }

    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 2, 'finds two errors')
      t.end()
    })
  })

  t.test('\n# when a module requires ./deps/Uno ./deps/dos ./deps/cuatro', function (t) {
    var src = '' + function foo() {
      require('./deps/Uno');
      require('./deps/dos');
      require('./deps/cuatro');
    }

    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 2, 'finds two errors')
      t.end()
    })
  })
})

test('\nglobal modules', function (t) {

  t.test('\n# when a module requires fs Path and uTils', function (t) {
    var src = '' + function foo() {
      require('fs');
      require('Path');
      require('uTils');
    }

    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 2, 'finds two errors')
      t.end()
    })
  })

  t.test('\n# when a module requires fs and uTils', function (t) {
    var src = '' + function foo() {
      require('fs');
      require('uTils');
    }

    validate(pathToModule, src, function (errors) {
      t.similar(errors[0].message, /Cannot find module/, 'warns that module does not exist')
      t.equals(errors.length, 1, 'finds one error')
      t.end()
    })
  })
})

<commit_msg>adapting tests to different platforms<commit_after>'use strict';
/*jshint asi:true */

var test = require('tap').test
  , validate = require('../validate-requires')
  , path = require('path')
  , pathToModule = path.join(__dirname, './some-module.js')

  // on linux platforms files are case sensitive, so resolve will fail properly and our custom errors will not appear
  , isMac = require('os').platform() === 'darwin'

test('\ngiven ./deps/uno.js ./deps/dos.js ./deps/tres.js', function (t) {
  t.test('\n# when a module requires ./deps/uno', function (t) {
    var src = '' + function foo() {
      require('./deps/uno');
    }
    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 0, 'finds no error')
      t.end()
    })
  })

  t.test('\n# when a module requires ./Deps/uno.js ./deps/dos.js ', function (t) {
    var src = '' + function foo() {
      require('./Deps/uno.js');
      require('./deps/dos.js');
    }

    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 1, 'finds one error')
      if (isMac) {
        t.similar(errors[0].message, /doesn't exactly match .*directory path/, 'warns that directory paths do not exactly match')
      }
      t.end()
    })
  })

  t.test('\n# when a module requires ./deps/uNo.js ./deps/dos.js ', function (t) {
    var src = '' + function foo() {
      require('./deps/uNo.js');
      require('./deps/dos.js');
    }

    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 1, 'finds one error')
      if (isMac) {
        t.similar(errors[0].message, /uNo.+doesn't exactly match .*file path/, 'warns that file paths do not exactly match')
        t.similar(errors[0].message, /.+uno.+/, 'includes file that was inexactly matched in the message')
      }
      t.end()
    })
  })

  t.test('\n# when a module requires ./deps/dos.js ./deps/cuatro.js', function (t) {
    var src = '' + function foo() {
      require('./deps/dos.js');
      require('./deps/cuatro.js');
    }

    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 1, 'finds one error')
      t.similar(errors[0].message, /Cannot find module/, 'warns that module does not exist')
      t.end()
    })
  })

  t.test('\n# when a module requires ./deps/Uno.js ./deps/dos.js ./deps/cuatro.js', function (t) {
    var src = '' + function foo() {
      require('./deps/Uno.js');
      require('./deps/dos.js');
      require('./deps/cuatro.js');
    }

    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 2, 'finds two errors')
      t.end()
    })
  })

  t.test('\n# when a module requires ./deps/Uno ./deps/dos ./deps/cuatro', function (t) {
    var src = '' + function foo() {
      require('./deps/Uno');
      require('./deps/dos');
      require('./deps/cuatro');
    }

    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 2, 'finds two errors')
      t.end()
    })
  })
})

test('\nglobal modules', function (t) {

  t.test('\n# when a module requires fs Path and uTils', function (t) {
    var src = '' + function foo() {
      require('fs');
      require('Path');
      require('uTils');
    }

    validate(pathToModule, src, function (errors) {
      t.equals(errors.length, 2, 'finds two errors')
      t.end()
    })
  })

  t.test('\n# when a module requires fs and uTils', function (t) {
    var src = '' + function foo() {
      require('fs');
      require('uTils');
    }

    validate(pathToModule, src, function (errors) {
      t.similar(errors[0].message, /Cannot find module/, 'warns that module does not exist')
      t.equals(errors.length, 1, 'finds one error')
      t.end()
    })
  })
})

<|endoftext|>


<commit_before>/*!
 * wef.cssParser tests
 * Copyright (c) 2011 Pablo Escalada
 * MIT Licensed
 */
module("cssParser");
test("namespace", function() {
    notEqual(wef.cssParser , undefined, "is wef.cssParser namespace defined?");
    equal(typeof wef.cssParser, "function", "is wef.cssParser a function?");
});

test("constructor", function() {
    equal(typeof wef.cssParser(), "object", "empty constructor returns an object");
});

test("public properties", function() {
    equal(typeof wef.cssParser().version, "string", "wef.cssParser().version");
});

test("pubic methods", function() {
    var text = 'body { height: 100%; display: "a.b.c"  /2em "....."  /1em "d.e.f" "....."  /1em "g.h.i"  /2em 5em 1em  *  1em 10em}';
    notEqual(wef.cssParser().parse(text), null, "parse(string) ok");
});

test("parse exceptions", function() {
    raises(function() {
        wef.cssParser().parse("asd");
    }, "invalid css data throws an exception");
    raises(function() {
        wef.cssParser().parse(444);
    }, "parse(number) throws an exception");
    raises(function() {
        wef.cssParser().parse()
    }, "parse(undefined) throws an exception");
    raises(function() {
        wef.cssParser().parse(null)
    }, "parse(null) throws an exception");
    raises(function() {
        wef.cssParser().parse("")
    }, "empty data throws an exception");
    notEqual(wef.cssParser().parse("body{}"), null, "empty cssRule ok");
    notEqual(wef.cssParser().parse("body{234}"), null, "invalid cssRule declaration ok");
    notEqual(wef.cssParser().parse("body{} h1{display:none}"), null, "empty cssRule ok");
});<commit_msg>Add more parse test<commit_after>/*!
 * wef.cssParser tests
 * Copyright (c) 2011 Pablo Escalada
 * MIT Licensed
 */
module("cssParser");
test("namespace", function() {
    notEqual(wef.cssParser , undefined, "is wef.cssParser namespace defined?");
    equal(typeof wef.cssParser, "function", "is wef.cssParser a function?");
});

test("constructor", function() {
    equal(typeof wef.cssParser(), "object", "empty constructor returns an object");
});

test("public properties", function() {
    equal(typeof wef.cssParser().version, "string", "wef.cssParser().version");
});

test("pubic methods", function() {
    var text = 'body { height: 100%; display: "a.b.c"  /2em "....."  /1em "d.e.f" "....."  /1em "g.h.i"  /2em 5em 1em  *  1em 10em}';
    notEqual(wef.cssParser().parse(text), null, "parse(string) ok");
});

test("parse exceptions", function() {
    raises(function() {
        wef.cssParser().parse("asd");
    }, "invalid css data throws an exception");
    raises(function() {
        wef.cssParser().parse(444);
    }, "parse(number) throws an exception");
    raises(function() {
        wef.cssParser().parse()
    }, "parse(undefined) throws an exception");
    raises(function() {
        wef.cssParser().parse(null)
    }, "parse(null) throws an exception");
    raises(function() {
        wef.cssParser().parse("")
    }, "empty data throws an exception");

    notEqual(wef.cssParser().parse("body{}"), null, "empty cssRule ok");
    notEqual(wef.cssParser().parse("body{234}"), null, "invalid cssRule declaration ok");
    notEqual(wef.cssParser().parse("body{} h1{display:none}"), null, "empty cssRule ok");

    notEqual(wef.cssParser().whenError(function() {}).parse("asd"), null, "error callback catches exception");
    notEqual(wef.cssParser().whenError(function() {}).parse("asd").parse("body{}"), null, "error callback allows chaining");
});<|endoftext|>


<commit_before>/*    Copyright 2021 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename);

const Sensor = require('./Sensor.js').Sensor;

const _ = require('lodash');

const validator = require('validator');

const IntelTool = require('../net2/IntelTool');
const intelTool = new IntelTool();

const rclient = require('../util/redis_manager.js').getRedisClient();

const flowUtil = require('../net2/FlowUtil');

const sys = require('sys'),
      Buffer = require('buffer').Buffer,
      dgram = require('dgram');

// slices a single byte into bits
// assuming only single bytes
const sliceBits = function(b, off, len) {
    var s = 7 - (off + len - 1);

    b = b >>> s;
    return b & ~(0xff << len);
};

const qnameToDomain = (qname) => {
  var domain= '';
  for(var i=0;i<qname.length;i++) {
    if (qname[i] == 0) {
      //last char chop trailing .
      domain = domain.substring(0, domain.length - 1);
      break;
    }

    var tmpBuf = qname.slice(i+1, i+qname[i]+1);
    domain += tmpBuf.toString('binary', 0, tmpBuf.length);
    domain += '.';

    i = i + qname[i];
  }

  return domain;
}

const expireTime = 48 * 3600; // expire in two days, by default
const allowKey = "fastdns:allow_list";
const blockKey = "fastdns:block_list";
const defaultListenPort = 9963;

class DNSProxyPlugin extends Sensor {
  async run() {
    this.hookFeature("dns_proxy");
  }

  async globalOn() {
    this.launchServer();
  }

  async globalOff() {
    if(this.server) {
      this.server.close();
      this.server = null;
    }
  }

  launchServer() {
    this.server = dgram.createSocket('udp4');

    this.server.on('message', async (msg, info) => {
      const qname = this.parseRequest(msg);
      if(qname) {
        await this.processRequest(qname);
      }
      // never need to reply back to client as this is not a true dns server
    });

    this.server.on('close', () => {
      log.info("DNS proxy server is closed.");
    });

    let port = this.config.listenPort || defaultListenPort;
    if(!_.isNumber(port)) {
      log.warn("Invalid port", port, ", reverting back to default port.");
      port = defaultListenPort;
    }

    this.server.bind(port, '127.0.0.1');
    log.info("DNS proxy server is now running at port:", port);
  }

  parseRequest(req) {
    //see rfc1035 for more details
    //http://tools.ietf.org/html/rfc1035#section-4.1.1
    if(req.length < 16) {
      return null;
    }
    return req.slice(12, req.length - 4);
  }

  async checkCache(domain) { // only return if there is exact-match intel in redis
    return intelTool.getDomainIntel(domain);
  }

  async processRequest(qname) {
    const domain = qnameToDomain(qname);
    log.info("dns request is", domain);
    const begin = new Date() / 1;
    const cache = await this.checkCache(domain);
    if(cache) {
      log.info("domain info is already cached locally:", cache);
      return; // do need to do anything
    }
    const result = await intelTool.checkIntelFromCloud(undefined, domain); // parameter ip is undefined since it's a dns request only
    await this.updateCache(domain, result);
    const end = new Date() / 1;
    log.info("dns intel result is", result, "took", Math.floor(end - begin), "ms");
  }

  async updateCache(domain, result) {
    if(_.isEmpty(result)) { // empty intel, means the domain is good
      const domains = flowUtil.getSubDomains(domain);
      if(!domains) {
        log.warn("Invalid Domain", domain, "skipped.");
        return;
      }

      // since result is empty, it means all sub domains of this domain are good
      const placeholder = {c: 'x', a: '1'};
      for(const dn of domains) {
        await intelTool.addDomainIntel(dn, placeholder, expireTime);
      }

      // only the exact dn is added to the allow and block list
      // generic domains can't be added, because another sub domain may be malicous
      // example:
      //   domain1.blogspot.com may be good
      //   and domain2.blogspot.com may be malicous
      // when domain1 is checked to be good, we should NOT add blogspot.com to allow_list
      await rclient.saddAsync(allowKey, domain);
      await rclient.sremAsync(blockKey, domain);

    } else {
      for(const item of result) {
        const dn = item.originIP; // originIP is the domain
        const isDomain = validator.isFQDN(dn);
        if(!isDomain) {
          continue;
        }

        for(const k in item) { // to suppress redis error
          const v = item[k];
          if(_.isBoolean(v) || _.isNumber(v) || _.isString(v)) {
            continue;
          }
          item[k] = JSON.stringify(v);
        }

        await intelTool.addDomainIntel(dn, item, item.e || expireTime);
        if(item.c === 'intel') { // need to decide the criteria better
          item.a = '0';
          await rclient.saddAsync(blockKey, dn);
          // either allow or block, the same domain can't stay in both set at the same time
          await rclient.sremAsync(allowKey, dn);
        } else {
          item.a = '1';
          await rclient.saddAsync(allowKey, dn);
          await rclient.sremAsync(blockKey, dn);
        }
      }
    }
  }
}

module.exports = DNSProxyPlugin;
<commit_msg>cosmetics<commit_after>/*    Copyright 2021 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

const log = require('../net2/logger.js')(__filename);

const Sensor = require('./Sensor.js').Sensor;

const _ = require('lodash');

const validator = require('validator');

const IntelTool = require('../net2/IntelTool');
const intelTool = new IntelTool();

const rclient = require('../util/redis_manager.js').getRedisClient();

const flowUtil = require('../net2/FlowUtil');

const sys = require('sys'),
      Buffer = require('buffer').Buffer,
      dgram = require('dgram');

// slices a single byte into bits
// assuming only single bytes
const sliceBits = function(b, off, len) {
    const s = 7 - (off + len - 1);

    b = b >>> s;
    return b & ~(0xff << len);
};

const qnameToDomain = (qname) => {
  let domain= '';
  for(let i=0;i<qname.length;i++) {
    if (qname[i] == 0) {
      //last char chop trailing .
      domain = domain.substring(0, domain.length - 1);
      break;
    }

    const tmpBuf = qname.slice(i+1, i+qname[i]+1);
    domain += tmpBuf.toString('binary', 0, tmpBuf.length);
    domain += '.';

    i = i + qname[i];
  }

  return domain;
};

const expireTime = 48 * 3600; // expire in two days, by default
const allowKey = "fastdns:allow_list";
const blockKey = "fastdns:block_list";
const defaultListenPort = 9963;

class DNSProxyPlugin extends Sensor {
  async run() {
    this.hookFeature("dns_proxy");
  }

  async globalOn() {
    this.launchServer();
  }

  async globalOff() {
    if(this.server) {
      this.server.close();
      this.server = null;
    }
  }

  launchServer() {
    this.server = dgram.createSocket('udp4');

    this.server.on('message', async (msg, info) => {
      const qname = this.parseRequest(msg);
      if(qname) {
        await this.processRequest(qname);
      }
      // never need to reply back to client as this is not a true dns server
    });

    this.server.on('close', () => {
      log.info("DNS proxy server is closed.");
    });

    let port = this.config.listenPort || defaultListenPort;
    if(!_.isNumber(port)) {
      log.warn("Invalid port", port, ", reverting back to default port.");
      port = defaultListenPort;
    }

    this.server.bind(port, '127.0.0.1');
    log.info("DNS proxy server is now running at port:", port);
  }

  parseRequest(req) {
    //see rfc1035 for more details
    //http://tools.ietf.org/html/rfc1035#section-4.1.1
    if(req.length < 16) {
      return null;
    }
    return req.slice(12, req.length - 4);
  }

  async checkCache(domain) { // only return if there is exact-match intel in redis
    return intelTool.getDomainIntel(domain);
  }

  async processRequest(qname) {
    const domain = qnameToDomain(qname);
    log.info("dns request is", domain);
    const begin = new Date() / 1;
    const cache = await this.checkCache(domain);
    if(cache) {
      log.info("domain info is already cached locally:", cache);
      return; // do need to do anything
    }
    const result = await intelTool.checkIntelFromCloud(undefined, domain); // parameter ip is undefined since it's a dns request only
    await this.updateCache(domain, result);
    const end = new Date() / 1;
    log.info("dns intel result is", result, "took", Math.floor(end - begin), "ms");
  }

  async updateCache(domain, result) {
    if(_.isEmpty(result)) { // empty intel, means the domain is good
      const domains = flowUtil.getSubDomains(domain);
      if(!domains) {
        log.warn("Invalid Domain", domain, "skipped.");
        return;
      }

      // since result is empty, it means all sub domains of this domain are good
      const placeholder = {c: 'x', a: '1'};
      for(const dn of domains) {
        await intelTool.addDomainIntel(dn, placeholder, expireTime);
      }

      // only the exact dn is added to the allow and block list
      // generic domains can't be added, because another sub domain may be malicous
      // example:
      //   domain1.blogspot.com may be good
      //   and domain2.blogspot.com may be malicous
      // when domain1 is checked to be good, we should NOT add blogspot.com to allow_list
      await rclient.saddAsync(allowKey, domain);
      await rclient.sremAsync(blockKey, domain);

    } else {
      for(const item of result) {
        const dn = item.originIP; // originIP is the domain
        const isDomain = validator.isFQDN(dn);
        if(!isDomain) {
          continue;
        }

        for(const k in item) { // to suppress redis error
          const v = item[k];
          if(_.isBoolean(v) || _.isNumber(v) || _.isString(v)) {
            continue;
          }
          item[k] = JSON.stringify(v);
        }

        await intelTool.addDomainIntel(dn, item, item.e || expireTime);
        if(item.c === 'intel') { // need to decide the criteria better
          item.a = '0';
          await rclient.saddAsync(blockKey, dn);
          // either allow or block, the same domain can't stay in both set at the same time
          await rclient.sremAsync(allowKey, dn);
        } else {
          item.a = '1';
          await rclient.saddAsync(allowKey, dn);
          await rclient.sremAsync(blockKey, dn);
        }
      }
    }
  }
}

module.exports = DNSProxyPlugin;
<|endoftext|>


<commit_before>var should = require('chai').should();
var expect = require('chai').expect;
require('fake-dom');
describe('yaws.socketConnect', function() {
  window = {};
  window.location={
    href: "https://127.0.0.1/example",
    protocol: "http",
    path: "/ex",
    domainname: "localhost"
  };
  require('../src/yawsSocketConnect.js');
  it('yaws should be an object', function() {
    window.yaws.should.be.a('object');
  });
  it('yaws.socketConnect should be a function', function() {
    window.yaws.socketConnect.should.be.a('function');
  });
  it('yaws.socketConnect() should throw an error on missing argument', function() {
    expect(window.yaws.socketConnect).to.throw("The first parameter 'onMessage' is required to be a function accepting a single parameter of type Blob.");
  });
  it('yaws.socketConnect() should throw an error on missing Websocket', function() {
    expect(function(){window.yaws.socketConnect(function(blob){},{},'/')}).to.throw("No Websocket Implementation found");
  });
  //basic socket
  window.Websocket = function(url){
    this.url=url;
    return this;
  };
  Websocket = window.Websocket;
  it('yaws.socketConnect() should be an object', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a('object');
  });
  it('yaws.socketConnect() should be a Websocket', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.instanceof(Websocket);
  });
  //check all getURL-options
  it('yaws.socketConnect().url should be wss://127.0.0.1/example', function() {
    window.location={
      href: window.location.href
    };
    expect(window.yaws.socketConnect(function(blob){},{})).to.have.property('url','wss://127.0.0.1/example');
  });
  window.location={
      href: window.location.href,
      protocol: "http",
      path: "/ex",
      domainname: "localhost"
    };
  it('yaws.socketConnect().url should be ws://localhost/ex', function() {
    expect(window.yaws.socketConnect(function(blob){},{})).to.have.property('url','ws://localhost/ex');
  });
  it('yaws.socketConnect().url should be ws://localhost/socket/ex', function() {
    expect(window.yaws.socketConnect(function(blob){},{},'{protocol}://{domain}/socket{path}')).to.have.property('url','ws://localhost/socket/ex');
  });
  //reconnecting socket
  window.ReconnectingWebSocket = window.Websocket;
  ReconnectingWebSocket = window.ReconnectingWebSocket;
  it('yaws.socketConnect() should be an object', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a('object');
  });
  it('yaws.socketConnect() should be a ReconnectingWebSocket', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.instanceof(ReconnectingWebSocket);
  });
  //robust socket
  window.RobustWebSocket = window.Websocket;
  RobustWebSocket = window.RobustWebSocket;
  it('yaws.socketConnect() should be an object', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a('object');
  });
  it('yaws.socketConnect() should be a RobustWebSocket', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.instanceof(RobustWebSocket);
  });
});
<commit_msg>Update yawsSocketConnect.js<commit_after>var should = require('chai').should();
var expect = require('chai').expect;
require('fake-dom');
describe('yaws.socketConnect', function() {
  window = {};
  window.location={
    href: "https://127.0.0.1/example"
  };
  require('../src/yawsSocketConnect.js');
  it('yaws should be an object', function() {
    window.yaws.should.be.a('object');
  });
  it('yaws.socketConnect should be a function', function() {
    window.yaws.socketConnect.should.be.a('function');
  });
  it('yaws.socketConnect() should throw an error on missing argument', function() {
    expect(window.yaws.socketConnect).to.throw("The first parameter 'onMessage' is required to be a function accepting a single parameter of type Blob.");
  });
  it('yaws.socketConnect() should throw an error on missing Websocket', function() {
    expect(function(){window.yaws.socketConnect(function(blob){},{},'/')}).to.throw("No Websocket Implementation found");
  });
  //basic socket
  window.Websocket = function(url){
    this.url=url;
    return this;
  };
  Websocket = window.Websocket;
  it('yaws.socketConnect() should be an object', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a('object');
  });
  it('yaws.socketConnect() should be a Websocket', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.instanceof(Websocket);
  });
  //check all getURL-options
  it('yaws.socketConnect().url should be wss://127.0.0.1/example', function() {
    expect(window.yaws.socketConnect(function(blob){},{})).to.have.property('url','wss://127.0.0.1/example');
  });
  window.location={
      href: window.location.href,
      protocol: "http",
      path: "/ex",
      domainname: "localhost"
    };
  it('yaws.socketConnect().url should be ws://localhost/ex', function() {
    expect(window.yaws.socketConnect(function(blob){},{})).to.have.property('url','ws://localhost/ex');
  });
  it('yaws.socketConnect().url should be ws://localhost/socket/ex', function() {
    expect(window.yaws.socketConnect(function(blob){},{},'{protocol}://{domain}/socket{path}')).to.have.property('url','ws://localhost/socket/ex');
  });
  //reconnecting socket
  window.ReconnectingWebSocket = window.Websocket;
  ReconnectingWebSocket = window.ReconnectingWebSocket;
  it('yaws.socketConnect() should be an object', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a('object');
  });
  it('yaws.socketConnect() should be a ReconnectingWebSocket', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.instanceof(ReconnectingWebSocket);
  });
  //robust socket
  window.RobustWebSocket = window.Websocket;
  RobustWebSocket = window.RobustWebSocket;
  it('yaws.socketConnect() should be an object', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a('object');
  });
  it('yaws.socketConnect() should be a RobustWebSocket', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.instanceof(RobustWebSocket);
  });
});
<|endoftext|>


<commit_before>var should = require('chai').should();
var expect = require('chai').expect;
require('fake-dom');
describe('yaws.socketConnect', function() {
  window={location:{href:"https://127.0.0.1/example"}};
  require('../src/yawsSocketConnect.js');
  it('yaws should be an object', function() {
    window.yaws.should.be.a('object');
  });
  it('yaws.socketConnect should be a function', function() {
    window.yaws.socketConnect.should.be.a('function');
  });
  it('yaws.socketConnect() should throw an error on missing argument', function() {
    expect(window.yaws.socketConnect).to.throw("The first parameter 'onMessage' is required to be a function accepting a single parameter of type Blob.");
  });
  it('yaws.socketConnect() should throw an error on missing Websocket', function() {
    expect(function(){window.yaws.socketConnect(function(blob){},{},'/')}).to.throw("No Websocket Implementation found");
  });
  //basic socket
  window.Websocket = function(){};
  Websocket = window.Websocket;
  it('yaws.socketConnect() should be an object', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a('object');
  });
  it('yaws.socketConnect() should be a Websocket', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a(Websocket);
  });
  //reconnecting socket
  window.ReconnectingWebSocket = function(){};
  ReconnectingWebSocket = window.ReconnectingWebSocket;
  it('yaws.socketConnect() should be an object', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a('object');
  });
  it('yaws.socketConnect() should be a ReconnectingWebSocket', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a(ReconnectingWebSocket);
  });
  //robust socket
  window.RobustWebSocket = function(){};
  RobustWebSocket = window.RobustWebSocket;
  it('yaws.socketConnect() should be an object', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a('object');
  });
  it('yaws.socketConnect() should be a RobustWebSocket', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a(RobustWebSocket);
  });
});
<commit_msg>Update yawsSocketConnect.js<commit_after>var should = require('chai').should();
var expect = require('chai').expect;
require('fake-dom');
describe('yaws.socketConnect', function() {
  window={location:{href:"https://127.0.0.1/example"}};
  require('../src/yawsSocketConnect.js');
  it('yaws should be an object', function() {
    window.yaws.should.be.a('object');
  });
  it('yaws.socketConnect should be a function', function() {
    window.yaws.socketConnect.should.be.a('function');
  });
  it('yaws.socketConnect() should throw an error on missing argument', function() {
    expect(window.yaws.socketConnect).to.throw("The first parameter 'onMessage' is required to be a function accepting a single parameter of type Blob.");
  });
  it('yaws.socketConnect() should throw an error on missing Websocket', function() {
    expect(function(){window.yaws.socketConnect(function(blob){},{},'/')}).to.throw("No Websocket Implementation found");
  });
  //basic socket
  window.Websocket = function(){};
  Websocket = window.Websocket;
  it('yaws.socketConnect() should be an object', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a('object');
  });
  it('yaws.socketConnect() should be a Websocket', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.instanceof(Websocket);
  });
  //reconnecting socket
  window.ReconnectingWebSocket = function(){};
  ReconnectingWebSocket = window.ReconnectingWebSocket;
  it('yaws.socketConnect() should be an object', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a('object');
  });
  it('yaws.socketConnect() should be a ReconnectingWebSocket', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.instanceof(ReconnectingWebSocket);
  });
  //robust socket
  window.RobustWebSocket = function(){};
  RobustWebSocket = window.RobustWebSocket;
  it('yaws.socketConnect() should be an object', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.a('object');
  });
  it('yaws.socketConnect() should be a RobustWebSocket', function() {
    window.yaws.socketConnect(function(blob){},{},'/').should.be.instanceof(RobustWebSocket);
  });
});
<|endoftext|>


<commit_before>/*jslint mocha: true */
/*global inject*/
/*global assert*/

beforeEach(module('myApp'));

describe('Clients controller', function()
{
	var ctrl, mockBackend, location;

	beforeEach(inject(function($controller, $httpBackend, $location)
	{
		mockBackend = $httpBackend;
		ctrl = $controller('ClientsController');
        location = $location;
		mockBackend.expectGET('/api/v1/Clients/pages/1/').respond(200,
		{
            data:
            [
			    {
				    'Title': 'Dr.',
				    'Firstname': 'Edison',
				    'Surname': 'Bartell',
			    },
                {
                    'Title': 'Miss.',
                    'Firstname': 'Luther',
                    'Surname': 'Dickens'
                }
            ],
            links:
            [
                {'rel':'First'},
                {'rel':'Previous'},
                {'rel':'Next', 'pageNumber' : 2},
                {'rel':'Last', 'pageNumber' : 4},
            ]
		});
	}));

	it('populates page 1', function()
	{
		assert.ok(ctrl);

		// Initially, before the server responds, the model should be empty
        assert.equal(ctrl.clients, undefined);
        assert.equal(ctrl.links, undefined);
        assert.equal(ctrl.filter, '');

		// Simulate a server response
		mockBackend.flush();

        // Now check the model has been populated as expected for page 1
        assert.deepEqual(ctrl.clients,
        [
			{
				'Title': 'Dr.',
				'Firstname': 'Edison',
				'Surname': 'Bartell',
			},
            {
                'Title': 'Miss.',
                'Firstname': 'Luther',
                'Surname': 'Dickens'
            }
        ]);

        assert.deepEqual(ctrl.links,
        [
            {'rel':'First'},
            {'rel':'Previous'},
            {'rel':'Next', 'pageNumber' : 2},
            {'rel':'Last', 'pageNumber' : 4},
        ]);

	});

    it('can filter', function()
    {
		mockBackend.flush();
        ctrl.filter = 'Edison';
        ctrl.filterChanged();

		mockBackend.expectGET('/api/v1/Clients/pages/1/Edison').respond(200,
		{
            data:
            [
			    {
				    'Title': 'Dr.',
				    'Firstname': 'Edison',
				    'Surname': 'Bartell',
			    }
            ],
            links:
            [
                {'rel':'First'},
                {'rel':'Previous'},
                {'rel':'Next'},
                {'rel':'Last'},
            ]
        });

		// Simulate a server response
		mockBackend.flush();

        // Now check the model has been populated as expected for page 1
        assert.deepEqual(ctrl.clients,
        [
			{
				'Title': 'Dr.',
				'Firstname': 'Edison',
				'Surname': 'Bartell',
			}
        ]);

        assert.deepEqual(ctrl.links,
        [
            {'rel':'First'},
            {'rel':'Previous'},
            {'rel':'Next'},
            {'rel':'Last'},
        ]);
    });

    it('can go to a client', function()
    {
        assert.equal(location.path(), '');

		mockBackend.flush();
        ctrl.gotoClient(2);

        assert.equal(location.path(), '/client/2');
    });

    it('create a new client', function()
    {
        assert.equal(location.path(), '');

		mockBackend.flush();
        ctrl.createNew();

        assert.equal(location.path(), '/client/');
    });

	afterEach(function()
	{
		mockBackend.verifyNoOutstandingExpectation();
		mockBackend.verifyNoOutstandingRequest();
	});
});

<commit_msg>Tests for client controller.<commit_after>/*jslint mocha: true */
/*global inject*/
/*global assert*/

beforeEach(module('myApp'));

describe('Clients controller', function()
{
	var ctrl, mockBackend, location;

	beforeEach(inject(function($controller, $httpBackend, $location)
	{
		mockBackend = $httpBackend;
		ctrl = $controller('ClientsController');
        location = $location;
		mockBackend.expectGET('/api/v1/Clients/pages/1/').respond(200,
		{
            data:
            [
			    {
				    'Title': 'Dr.',
				    'Firstname': 'Edison',
				    'Surname': 'Bartell',
			    },
                {
                    'Title': 'Miss.',
                    'Firstname': 'Luther',
                    'Surname': 'Dickens'
                }
            ],
            links:
            [
                {'rel':'First'},
                {'rel':'Previous'},
                {'rel':'Next', 'pageNumber' : 2},
                {'rel':'Last', 'pageNumber' : 4},
            ]
		});
	}));

	it('populates page 1', function()
	{
		assert.ok(ctrl);

		// Initially, before the server responds, the model should be empty
        assert.equal(ctrl.clients, undefined);
        assert.equal(ctrl.links, undefined);
        assert.equal(ctrl.filter, '');

		// Simulate a server response
		mockBackend.flush();

        // Now check the model has been populated as expected for page 1
        assert.deepEqual(ctrl.clients,
        [
			{
				'Title': 'Dr.',
				'Firstname': 'Edison',
				'Surname': 'Bartell',
			},
            {
                'Title': 'Miss.',
                'Firstname': 'Luther',
                'Surname': 'Dickens'
            }
        ]);

        assert.deepEqual(ctrl.links,
        [
            {'rel':'First'},
            {'rel':'Previous'},
            {'rel':'Next', 'pageNumber' : 2},
            {'rel':'Last', 'pageNumber' : 4},
        ]);

	});

    it('can filter', function()
    {
		mockBackend.flush();
        ctrl.filter = 'Edison';
        ctrl.filterChanged();

		mockBackend.expectGET('/api/v1/Clients/pages/1/Edison').respond(200,
		{
            data:
            [
			    {
				    'Title': 'Dr.',
				    'Firstname': 'Edison',
				    'Surname': 'Bartell',
			    }
            ],
            links:
            [
                {'rel':'First'},
                {'rel':'Previous'},
                {'rel':'Next'},
                {'rel':'Last'},
            ]
        });

		// Simulate a server response
		mockBackend.flush();

        // Now check the model has been populated as expected for page 1
        assert.deepEqual(ctrl.clients,
        [
			{
				'Title': 'Dr.',
				'Firstname': 'Edison',
				'Surname': 'Bartell',
			}
        ]);

        assert.deepEqual(ctrl.links,
        [
            {'rel':'First'},
            {'rel':'Previous'},
            {'rel':'Next'},
            {'rel':'Last'},
        ]);
    });

    it('can go to a client', function()
    {
        assert.equal(location.path(), '');

		mockBackend.flush();
        ctrl.gotoClient(2);

        assert.equal(location.path(), '/client/2');
    });

    it('can create a new client', function()
    {
        assert.equal(location.path(), '');

		mockBackend.flush();
        ctrl.createNew();

        assert.equal(location.path(), '/client/');
    });

	afterEach(function()
	{
		mockBackend.verifyNoOutstandingExpectation();
		mockBackend.verifyNoOutstandingRequest();
	});
});

describe('Client controller - existing client', function()
{
	var ctrl, mockBackend, location;

	beforeEach(inject(function($controller, $httpBackend, $location, $routeParams)
	{
		mockBackend = $httpBackend;
        location = $location;
		$routeParams.clientId = 1;
		$routeParams.filter = '';
		ctrl = $controller('ClientController');

		mockBackend.expectGET('/api/v1/Clients/1').respond(200,
		{
			'data':
			{
				'Title': 'Dr.',
				'Firstname': 'Edison',
				'Surname': 'Bartell'
			}
		});
	}));

	it('populates', function()
	{
	    assert.equal(ctrl.client, undefined);

		mockBackend.flush();

		assert.deepEqual(ctrl.client,
		{
			'Title': 'Dr.',
			'Firstname': 'Edison',
			'Surname': 'Bartell',
		});
	});

	it('OKs (applies and closes)', function()
	{
		mockBackend.flush();

		ctrl.client =
		{
			'Title': 'Mr.',
			'Firstname': 'Eddy',
			'Surname': 'Barnes',
		};

		ctrl.apply(true);

		mockBackend.expectPUT('/api/v1/Clients/1',
		{
			'Title': 'Mr.',
			'Firstname': 'Eddy',
			'Surname': 'Barnes',
		}).respond(200);

		mockBackend.flush();

		assert.equal(location.path(), '/1/');
	});

	it('deletes', function()
	{
		mockBackend.flush();
		ctrl.delete();

		mockBackend.expectDELETE('/api/v1/Clients/1').respond(200);

		mockBackend.flush();

		assert.equal(location.path(), '/1/');
	})

	afterEach(function()
	{
		mockBackend.verifyNoOutstandingExpectation();
		mockBackend.verifyNoOutstandingRequest();
	});

});

describe('Client controller - new client', function()
{
	var ctrl, mockBackend, location;

	beforeEach(inject(function($controller, $httpBackend, $location, $routeParams)
	{
		mockBackend = $httpBackend;
        location = $location;
		$routeParams.filter = '';
		ctrl = $controller('ClientController');
	}));

	it('populates (blank)', function()
	{
		assert.deepEqual(ctrl.client,
		{
			'Title': '',
			'Firstname': '',
			'Initial': '',
			'Surname': '',
			'AddressLine1': '',
			'AddressLine2': '',
			'Town': '',
			'Postcode': '',
			'HomeNumber': '',
			'MobileNumber': '',
			'EmailAddress': '',
			'Notes': '',
			'IsActive': true
		});
	});

	it('OKs (applies and closes)', function()
	{
		ctrl.client =
		{
			'Title': 'Mr.',
			'Firstname': 'Eddy',
			'Surname': 'Barnes',
		};

		ctrl.apply(true);

		mockBackend.expectPOST('/api/v1/Clients/',
		{
			'Title': 'Mr.',
			'Firstname': 'Eddy',
			'Surname': 'Barnes',
		}).respond(200, {id: 66});

		mockBackend.flush();

		assert.equal(location.path(), '/1/');
	});

	it('deletes/discards', function()
	{
		ctrl.delete();

		assert.equal(location.path(), '/1/');
	})

	afterEach(function()
	{
		mockBackend.verifyNoOutstandingExpectation();
		mockBackend.verifyNoOutstandingRequest();
	});

});
<|endoftext|>