<commit_before>//var dom = require('xmldom/dom');
var DOMParser = require('xmldom').DOMParser;

/**
 * A MultiStatus message.
 *
 * See RFC 4918, section 13.
 */
function MultiStatus() {
  this.stats = [];
}
module.exports = MultiStatus;

/**
 * Add a properties status (PROPFIND).
 */
MultiStatus.prototype.addProperties = function (href, properties) {
  this.stats.push({
    href: href,
    //status: this.statusFromCode(statusCode),
    props: properties
  });
}

/**
 * Add an href status (DELETE, etc.)
 */
MultiStatus.prototype.addStatus = function (href, status) {
  this.stats.push({href: href, status: status});
}

MultiStatus.prototype.toXML = function () {
  var D = 'DAV:';

  // This does not work according to spec.
  //var dom = require('xmldom/dom');
  //var domFactory = new dom.DOMImplementation();
  //var doc = domFactory.createDocument(D, 'D:multistatus', '<?xml version="1.0" ?>');
  //doc.documentElement.setAttribute('xml:D', D);

  // This is an annoying hack:
  var doc = new DOMParser().parseFromString(
    '<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:"/>'
  );

  var msEle = doc.documentElement;//.createElementNS(D, 'multistatus');

  for (var i = 0; i < this.stats.length; ++i) {
    var stat = this.stats[i];

    var resEle = doc.createElementNS(D, 'D:response');
    var hrefEle = doc.createElementNS(D, 'D:href');

    // <href>http://foo</href>
    hrefEle.appendChild(doc.createTextNode(stat.href));
    resEle.appendChild(hrefEle);
    msEle.appendChild(resEle);

    // Propstats (e.g. PROPFIND multistatus)
    if (stat.props && stat.props.length > 0) {
      this._serializeProps(resEle, stat.props)
    }
    // Status (e.g. DELETE, COPY, MOVE multistatus)
    else if (stat.status) {
      var statusEle = doc.createElementNS(D, 'D:status');
      var msg = this.statusFromCode(stat.status);
      statusEle.appendChild(doc.createTextNode(msg));
      resEle.appendChild(statusEle);
    }

  }

  return doc;
}

/**
 * INTERNAL: Serialize properties for PROPFIND.
 */
MultiStatus.prototype._serializeProps = function (parent, props) {
  var doc = parent.ownerDocument;

  var notFound = doc.createElementNS('DAV:', 'D:prop');
  var ok = doc.createElementNS('DAV:', 'D:prop');

  var codeGroups = {};
  for (var i = 0; i < props.length; ++i) {
    var property = props[i];

    if (!codeGroups[property.status]) {
      codeGroups[property.status] = doc.createElementNS('DAV:', 'D:prop');
    }

    property.toXML(codeGroups[property.status]);

    /*
    if (property.status == 200) {
      property.toXML(ok);
    }
    else {
      property.toXML(notFound);
    }
    */
  }

  for (var statEle in codeGroups) {
    this._serializePropstat(statEle, codeGroups[statEle], parent, doc);
  }

  //this._serializePropstat(200, ok, parent, doc)
  //this._serializePropstat(404, notFound, parent, doc)

}

/**
 * INTERNAL: Create propstat element.
 */
MultiStatus.prototype._serializePropstat = function (status, props, parent, doc) {
  if (props.hasChildNodes() == false) {
    return;
  }

  var statusMsg = this.statusFromCode(status);
  var propstat = doc.createElementNS('DAV:', 'D:propstat');
  var stat = doc.createElementNS('DAV:', 'D:status');

  stat.appendChild(doc.createTextNode(statusMsg));
  propstat.appendChild(props);
  propstat.appendChild(stat);
  parent.appendChild(propstat);

}

/**
 * Utility for converting an HTTP code to a status message.
 */
MultiStatus.prototype.statusFromCode = function (code) {
  var prefix = 'HTTP/1.1 ';
  switch (code) {
    case 200:
      return prefix + '200 OK';
    case 403:
      return prefix + '403 Forbidden';
    case 404:
      return prefix + '404 Not Found';
    case 423:
      return prefix + '423 Locked';
    case 424:
      return prefix + '424 Failed Dependency';
    default:
      return prefix + ' ' + code + ' Error';
  }

}
<commit_msg>Removed commented code.<commit_after>//var dom = require('xmldom/dom');
var DOMParser = require('xmldom').DOMParser;

/**
 * A MultiStatus message.
 *
 * See RFC 4918, section 13.
 */
function MultiStatus() {
  this.stats = [];
}
module.exports = MultiStatus;

/**
 * Add a properties status (PROPFIND).
 */
MultiStatus.prototype.addProperties = function (href, properties) {
  this.stats.push({
    href: href,
    //status: this.statusFromCode(statusCode),
    props: properties
  });
}

/**
 * Add an href status (DELETE, etc.)
 */
MultiStatus.prototype.addStatus = function (href, status) {
  this.stats.push({href: href, status: status});
}

MultiStatus.prototype.toXML = function () {
  var D = 'DAV:';

  // This does not work according to spec.
  //var dom = require('xmldom/dom');
  //var domFactory = new dom.DOMImplementation();
  //var doc = domFactory.createDocument(D, 'D:multistatus', '<?xml version="1.0" ?>');
  //doc.documentElement.setAttribute('xml:D', D);

  // This is an annoying hack:
  var doc = new DOMParser().parseFromString(
    '<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:"/>'
  );

  var msEle = doc.documentElement;//.createElementNS(D, 'multistatus');

  for (var i = 0; i < this.stats.length; ++i) {
    var stat = this.stats[i];

    var resEle = doc.createElementNS(D, 'D:response');
    var hrefEle = doc.createElementNS(D, 'D:href');

    // <href>http://foo</href>
    hrefEle.appendChild(doc.createTextNode(stat.href));
    resEle.appendChild(hrefEle);
    msEle.appendChild(resEle);

    // Propstats (e.g. PROPFIND multistatus)
    if (stat.props && stat.props.length > 0) {
      this._serializeProps(resEle, stat.props)
    }
    // Status (e.g. DELETE, COPY, MOVE multistatus)
    else if (stat.status) {
      var statusEle = doc.createElementNS(D, 'D:status');
      var msg = this.statusFromCode(stat.status);
      statusEle.appendChild(doc.createTextNode(msg));
      resEle.appendChild(statusEle);
    }

  }

  return doc;
}

/**
 * INTERNAL: Serialize properties for PROPFIND.
 */
MultiStatus.prototype._serializeProps = function (parent, props) {
  var doc = parent.ownerDocument;

  var codeGroups = {};
  for (var i = 0; i < props.length; ++i) {
    var property = props[i];

    if (!codeGroups[property.status]) {
      codeGroups[property.status] = doc.createElementNS('DAV:', 'D:prop');
    }

    property.toXML(codeGroups[property.status]);

  }

  for (var statEle in codeGroups) {
    this._serializePropstat(statEle, codeGroups[statEle], parent, doc);
  }
}

/**
 * INTERNAL: Create propstat element.
 */
MultiStatus.prototype._serializePropstat = function (status, props, parent, doc) {
  if (props.hasChildNodes() == false) {
    return;
  }

  var statusMsg = this.statusFromCode(status);
  var propstat = doc.createElementNS('DAV:', 'D:propstat');
  var stat = doc.createElementNS('DAV:', 'D:status');

  stat.appendChild(doc.createTextNode(statusMsg));
  propstat.appendChild(props);
  propstat.appendChild(stat);
  parent.appendChild(propstat);

}

/**
 * Utility for converting an HTTP code to a status message.
 */
MultiStatus.prototype.statusFromCode = function (code) {
  var prefix = 'HTTP/1.1 ';
  switch (code) {
    case 200:
      return prefix + '200 OK';
    case 403:
      return prefix + '403 Forbidden';
    case 404:
      return prefix + '404 Not Found';
    case 423:
      return prefix + '423 Locked';
    case 424:
      return prefix + '424 Failed Dependency';
    default:
      return prefix + ' ' + code + ' Error';
  }

}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

/**
 * @fileoverview This library provides functions for navigating to and dealing
 *     with views of the current gadget.
 */

var gadgets = gadgets || {};

/**
 * Implements the gadgets.views API spec. See
 * http://code.google.com/apis/gadgets/docs/reference/gadgets.views.html
 */
gadgets.views = function() {

  /**
   * Reference to the current view object.
   */
  var currentView = null;

  /**
   * Map of all supported views for this container.
   */
  var supportedViews = {};

  /**
   * Map of parameters passed to the current request.
   */
  var params = {};

  /**
   * Initializes views. Assumes that the current view is the "view"
   * url parameter (or default if "view" isn't supported), and that
   * all view parameters are in the form view-<name>
   * TODO: Use unified configuration when it becomes available.
   *
   */
  function init(config) {
    var supported = config["views"];

    for (var s in supported) if (supported.hasOwnProperty(s)) {
      var obj = supported[s];
      if (!obj) {
        continue;
      }
      supportedViews[s] = new gadgets.views.View(s, obj.isOnlyVisible);
      var aliases = obj.aliases || [];
      for (var i = 0, alias; alias = aliases[i]; ++i) {
        supportedViews[alias] = new gadgets.views.View(s, obj.isOnlyVisible);
      }
    }

    var urlParams = gadgets.util.getUrlParameters();
    // View parameters are passed as a single parameter.
    if (urlParams["view-params"]) {
      var tmpParams = gadgets.json.parse(
          decodeURIComponent(urlParams["view-params"]));
      if (tmpParams) {
        params = tmpParams;
        for (var p in params) if (params.hasOwnProperty(p)) {
          params[p] = gadgets.util.escapeString(params[p]);
        }
      }
    }
    currentView = supportedViews[urlParams.view] || supportedViews["default"];
  }

  gadgets.config.register("views", null, init);

  return {
    /**
     * Attempts to navigate to this gadget in a different view. If the container
     * supports parameters will pass the optional parameters along to the gadget
     * in the new view.
     *
     * @param {gadgets.views.View} view The view to navigate to
     * @param {Map.<String, String>} opt_params Parameters to pass to the
     *     gadget after it has been navigated to on the surface
     */
    requestNavigateTo : function(view, opt_params) {
      gadgets.rpc.call(
          null, "requestNavigateTo", null, view.getName(), opt_params);
    },

    /**
     * Returns the current view.
     *
     * @return {gadgets.views.View} The current view
     */
    getCurrentView : function() {
      return currentView;
    },

    /**
     * Returns a map of all the supported views. Keys each gadgets.view.View by
     * its name.
     *
     * @return {Map<gadgets.views.ViewType | String, gadgets.views.View>}
     *   All supported views, keyed by their name attribute.
     */
    getSupportedViews : function() {
      return supportedViews;
    },

    /**
     * Returns the parameters passed into this gadget for this view. Does not
     * include all url parameters, only the ones passed into
     * gadgets.views.requestNavigateTo
     *
     * @return {Map.<String, String>} The parameter map
     */
    getParams : function() {
      return params;
    }
  };
}();

gadgets.views.View = function(name, opt_isOnlyVisible) {
  this.name_ = name;
  this.isOnlyVisible_ = !!opt_isOnlyVisible;
};

/**
 * @return {String} The view name.
 */
gadgets.views.View.prototype.getName = function() {
  return this.name_;
};

/**
 * @return {Boolean} True if this is the only visible gadget on the page.
 */
gadgets.views.View.prototype.isOnlyVisibleGadget = function() {
  return this.isOnlyVisible_;
};

gadgets.views.ViewType = gadgets.util.makeEnum([
  "FULL_PAGE", "DASHBOARD", "POPUP"
]);
<commit_msg>Support v0.8 view names in gadgets.views.ViewType. (SHINDIG-347)<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

/**
 * @fileoverview This library provides functions for navigating to and dealing
 *     with views of the current gadget.
 */

var gadgets = gadgets || {};

/**
 * Implements the gadgets.views API spec. See
 * http://code.google.com/apis/gadgets/docs/reference/gadgets.views.html
 */
gadgets.views = function() {

  /**
   * Reference to the current view object.
   */
  var currentView = null;

  /**
   * Map of all supported views for this container.
   */
  var supportedViews = {};

  /**
   * Map of parameters passed to the current request.
   */
  var params = {};

  /**
   * Initializes views. Assumes that the current view is the "view"
   * url parameter (or default if "view" isn't supported), and that
   * all view parameters are in the form view-<name>
   * TODO: Use unified configuration when it becomes available.
   *
   */
  function init(config) {
    var supported = config["views"];

    for (var s in supported) if (supported.hasOwnProperty(s)) {
      var obj = supported[s];
      if (!obj) {
        continue;
      }
      supportedViews[s] = new gadgets.views.View(s, obj.isOnlyVisible);
      var aliases = obj.aliases || [];
      for (var i = 0, alias; alias = aliases[i]; ++i) {
        supportedViews[alias] = new gadgets.views.View(s, obj.isOnlyVisible);
      }
    }

    var urlParams = gadgets.util.getUrlParameters();
    // View parameters are passed as a single parameter.
    if (urlParams["view-params"]) {
      var tmpParams = gadgets.json.parse(
          decodeURIComponent(urlParams["view-params"]));
      if (tmpParams) {
        params = tmpParams;
        for (var p in params) if (params.hasOwnProperty(p)) {
          params[p] = gadgets.util.escapeString(params[p]);
        }
      }
    }
    currentView = supportedViews[urlParams.view] || supportedViews["default"];
  }

  gadgets.config.register("views", null, init);

  return {
    /**
     * Attempts to navigate to this gadget in a different view. If the container
     * supports parameters will pass the optional parameters along to the gadget
     * in the new view.
     *
     * @param {gadgets.views.View} view The view to navigate to
     * @param {Map.<String, String>} opt_params Parameters to pass to the
     *     gadget after it has been navigated to on the surface
     */
    requestNavigateTo : function(view, opt_params) {
      gadgets.rpc.call(
          null, "requestNavigateTo", null, view.getName(), opt_params);
    },

    /**
     * Returns the current view.
     *
     * @return {gadgets.views.View} The current view
     */
    getCurrentView : function() {
      return currentView;
    },

    /**
     * Returns a map of all the supported views. Keys each gadgets.view.View by
     * its name.
     *
     * @return {Map<gadgets.views.ViewType | String, gadgets.views.View>}
     *   All supported views, keyed by their name attribute.
     */
    getSupportedViews : function() {
      return supportedViews;
    },

    /**
     * Returns the parameters passed into this gadget for this view. Does not
     * include all url parameters, only the ones passed into
     * gadgets.views.requestNavigateTo
     *
     * @return {Map.<String, String>} The parameter map
     */
    getParams : function() {
      return params;
    }
  };
}();

gadgets.views.View = function(name, opt_isOnlyVisible) {
  this.name_ = name;
  this.isOnlyVisible_ = !!opt_isOnlyVisible;
};

/**
 * @return {String} The view name.
 */
gadgets.views.View.prototype.getName = function() {
  return this.name_;
};

/**
 * @return {Boolean} True if this is the only visible gadget on the page.
 */
gadgets.views.View.prototype.isOnlyVisibleGadget = function() {
  return this.isOnlyVisible_;
};

gadgets.views.ViewType = gadgets.util.makeEnum([
  "CANVAS", "HOME", "PREVIEW", "PROFILE",
  // TODO Deprecate the following ViewTypes.
  "FULL_PAGE", "DASHBOARD", "POPUP"
]);
<|endoftext|>


<commit_before>import $ from 'jquery';
import d3 from 'd3';
import * from 'd3-scale-chromatic';

// Color related utility functions go in this object
export const bnbColors = [
  '#9e0142',
  '#d53e4f',
  '#f46d43',
  '#fdae61',
  '#fee08b',
   '#ffffbf',
  '#e6f598',
  '#abdda4',
  '#66c2a5',
  '#3288bd',
  '#5e4fa2',
  '#8e0152',
  '#c51b7d',
  '#de77ae',
  '#f1b6da',
  '#fde0ef',
  '#f7f7f7',
  '#e6f5d0',
  '#b8e186',
  '#7fbc41',
  '#4d9221',
  '#276419',
];

const spectrums = {
  blue_white_yellow: [
    '#00d1c1',
    'white',
    '#ffb400',
  ],
  fire: [
    'white',
    'yellow',
    'red',
    'black',
  ],
  white_black: [
    'white',
    'black',
  ],
  black_white: [
    'black',
    'white',
  ],
};

export const category21 = (function () {
  // Color factory
  const seen = {};
  return function (s) {
    if (!s) {
      return;
    }
    let stringifyS = String(s);
    // next line is for superset series that should have the same color
    stringifyS = stringifyS.replace('---', '');
    if (seen[stringifyS] === undefined) {
      seen[stringifyS] = Object.keys(seen).length;
    }
    /* eslint consistent-return: 0 */
    return bnbColors[seen[stringifyS] % bnbColors.length];
    /*return d3.interpolateSpectral[seen[stringifyS] % seen[stringifyS].length];*/
  };
}());

export const colorScalerFactory = function (colors, data, accessor) {
  // Returns a linear scaler our of an array of color
  if (!Array.isArray(colors)) {
    /* eslint no-param-reassign: 0 */
    colors = spectrums[colors];
  }
  let ext = [0, 1];
  if (data !== undefined) {
    ext = d3.extent(data, accessor);
  }
  const points = [];
  const chunkSize = (ext[1] - ext[0]) / colors.length;
  $.each(colors, function (i) {
    points.push(i * chunkSize);
  });
  return d3.scale.linear().domain(points).range(colors);
};
<commit_msg>Update colors.js<commit_after>import $ from 'jquery';
import d3 from 'd3';
//import * from 'd3-scale-chromatic';

// Color related utility functions go in this object
export const bnbColors = [
  '#9e0142',
  '#d53e4f',
  '#f46d43',
  '#fdae61',
  '#fee08b',
   '#ffffbf',
  '#e6f598',
  '#abdda4',
  '#66c2a5',
  '#3288bd',
  '#5e4fa2',
  '#8e0152',
  '#c51b7d',
  '#de77ae',
  '#f1b6da',
  '#fde0ef',
  '#f7f7f7',
  '#e6f5d0',
  '#b8e186',
  '#7fbc41',
  '#4d9221',
  '#276419',
];

const spectrums = {
  blue_white_yellow: [
    '#00d1c1',
    'white',
    '#ffb400',
  ],
  fire: [
    'white',
    'yellow',
    'red',
    'black',
  ],
  white_black: [
    'white',
    'black',
  ],
  black_white: [
    'black',
    'white',
  ],
};

export const category21 = (function () {
  // Color factory
  const seen = {};
  return function (s) {
    if (!s) {
      return;
    }
    let stringifyS = String(s);
    // next line is for superset series that should have the same color
    stringifyS = stringifyS.replace('---', '');
    if (seen[stringifyS] === undefined) {
      seen[stringifyS] = Object.keys(seen).length;
    }
    /* eslint consistent-return: 0 */
    return bnbColors[seen[stringifyS] % bnbColors.length];
    /*return d3.interpolateSpectral[seen[stringifyS] % seen[stringifyS].length];*/
  };
}());

export const colorScalerFactory = function (colors, data, accessor) {
  // Returns a linear scaler our of an array of color
  if (!Array.isArray(colors)) {
    /* eslint no-param-reassign: 0 */
    colors = spectrums[colors];
  }
  let ext = [0, 1];
  if (data !== undefined) {
    ext = d3.extent(data, accessor);
  }
  const points = [];
  const chunkSize = (ext[1] - ext[0]) / colors.length;
  $.each(colors, function (i) {
    points.push(i * chunkSize);
  });
  return d3.scale.linear().domain(points).range(colors);
};
<|endoftext|>


<commit_before>'use strict';
'require rpc';
'require uci';
'require form';
'require network';
'require firewall';
'require tools.widgets as widgets';

return L.view.extend({
	callConntrackHelpers: rpc.declare({
		object: 'luci',
		method: 'conntrack_helpers',
		expect: { helpers: [] }
	}),

	load: function() {
		return Promise.all([
			this.callConntrackHelpers(),
			firewall.getDefaults()
		]);
	},

	render: function(data) {
		var ctHelpers = data[0],
		    fwDefaults = data[1],
		    m, s, o, inp, out;

		m = new form.Map('firewall', _('Firewall - Zone Settings'),
			_('The firewall creates zones over your network interfaces to control network traffic flow.'));

		s = m.section(form.TypedSection, 'defaults', _('General Settings'));
		s.anonymous = true;
		s.addremove = false;

		o = s.option(form.Flag, 'syn_flood', _('Enable SYN-flood protection'));
		o = s.option(form.Flag, 'drop_invalid', _('Drop invalid packets'));

		var p = [
			s.option(form.ListValue, 'input', _('Input')),
			s.option(form.ListValue, 'output', _('Output')),
			s.option(form.ListValue, 'forward', _('Forward'))
		];

		for (var i = 0; i < p.length; i++) {
			p[i].value('REJECT', _('reject'));
			p[i].value('DROP', _('drop'));
			p[i].value('ACCEPT', _('accept'));
		}

		/* Netfilter flow offload support */

		if (L.hasSystemFeature('offloading')) {
			s = m.section(form.TypedSection, 'defaults', _('Routing/NAT Offloading'),
				_('Experimental feature. Not fully compatible with QoS/SQM.'));

			s.anonymous = true;
			s.addremove = false;

			o = s.option(form.Flag, 'flow_offloading',
				_('Software flow offloading'),
				_('Software based offloading for routing/NAT'));
			o.optional = true;

			o = s.option(form.Flag, 'flow_offloading_hw',
				_('Hardware flow offloading'),
				_('Requires hardware NAT support. Implemented at least for mt7621'));
			o.optional = true;
			o.depends('flow_offloading', '1');
		}

		s = m.section(form.GridSection, 'zone', _('Zones'));
		s.addremove = true;
		s.anonymous = true;
		s.sortable  = true;

		s.tab('general', _('General Settings'));
		s.tab('advanced', _('Advanced Settings'));
		s.tab('conntrack', _('Conntrack Settings'));
		s.tab('extra', _('Extra iptables arguments'));

		o = s.taboption('general', form.DummyValue, '_generalinfo');
		o.rawhtml = true;
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			var name = uci.get('firewall', section_id, 'name');

			return _('This section defines common properties of %q. The input and output options set the default policies for traffic entering and leaving this zone while the forward option describes the policy for forwarded traffic between different networks within the zone. Covered networks specifies which available networks are members of this zone.')
				.replace(/%s/g, name).replace(/%q/g, '"' + name + '"');
		};

		o = s.taboption('general', form.Value, 'name', _('Name'));
		o.placeholder = _('Unnamed zone');
		o.modalonly = true;
		o.datatype = 'and(uciname,maxlength(11))';
		o.write = function(section_id, formvalue) {
			var cfgvalue = this.cfgvalue(section_id);

			if (cfgvalue != formvalue)
				return firewall.renameZone(cfgvalue, formvalue);
		};

		o = s.option(widgets.ZoneForwards, '_info', _('Zone ⇒ Forwardings'));
		o.editable = true;
		o.modalonly = false;
		o.cfgvalue = function(section_id) {
			return uci.get('firewall', section_id, 'name');
		};

		var p = [
			s.taboption('general', form.ListValue, 'input', _('Input')),
			s.taboption('general', form.ListValue, 'output', _('Output')),
			s.taboption('general', form.ListValue, 'forward', _('Forward'))
		];

		for (var i = 0; i < p.length; i++) {
			p[i].value('REJECT', _('reject'));
			p[i].value('DROP', _('drop'));
			p[i].value('ACCEPT', _('accept'));
			p[i].editable = true;
		}

		p[0].default = fwDefaults.getInput();
		p[1].default = fwDefaults.getOutput();
		p[2].default = fwDefaults.getForward();

		o = s.taboption('general', form.Flag, 'masq', _('Masquerading'));
		o.editable = true;

		o = s.taboption('general', form.Flag, 'mtu_fix', _('MSS clamping'));
		o.modalonly = true;

		o = s.taboption('general', widgets.NetworkSelect, 'network', _('Covered networks'));
		o.modalonly = true;
		o.multiple = true;
		o.write = function(section_id, formvalue) {
			var name = uci.get('firewall', section_id, 'name'),
			    cfgvalue = this.cfgvalue(section_id);

			if (typeof(cfgvalue) == 'string' && Array.isArray(formvalue) && (cfgvalue == formvalue.join(' ')))
				return;

			var tasks = [ firewall.getZone(name) ];

			if (Array.isArray(formvalue))
				for (var i = 0; i < formvalue.length; i++) {
					var netname = formvalue[i];
					tasks.push(network.getNetwork(netname).then(function(net) {
						return net || network.addNetwork(netname, { 'proto': 'none' });
					}));
				}

			return Promise.all(tasks).then(function(zone_networks) {
				if (zone_networks[0])
					for (var i = 1; i < zone_networks.length; i++)
						zone_networks[0].addNetwork(zone_networks[i].getName());
			});
		};
		o.remove = function(section_id) {
			return uci.set('firewall', section_id, 'network', ' ');
		};

		o = s.taboption('advanced', form.DummyValue, '_advancedinfo');
		o.rawhtml = true;
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			var name = uci.get('firewall', section_id, 'name');

			return _('The options below control the forwarding policies between this zone (%s) and other zones. Destination zones cover forwarded traffic originating from %q. Source zones match forwarded traffic from other zones targeted at %q. The forwarding rule is unidirectional, e.g. a forward from lan to wan does not imply a permission to forward from wan to lan as well.')
				.format(name);
		};

		o = s.taboption('advanced', widgets.DeviceSelect, 'device', _('Covered devices'), _('Use this option to classify zone traffic by raw, non-uci managed network devices.'));
		o.modalonly = true;
		o.multiple = true;

		o = s.taboption('advanced', form.DynamicList, 'subnet', _('Covered subnets'), _('Use this option to classify zone traffic by source or destination subnet instead of networks or devices.'));
		o.datatype = 'neg(cidr)';
		o.modalonly = true;
		o.multiple = true;

		o = s.taboption('advanced', form.ListValue, 'family', _('Restrict to address family'));
		o.value('', _('IPv4 and IPv6'));
		o.value('ipv4', _('IPv4 only'));
		o.value('ipv6', _('IPv6 only'));
		o.modalonly = true;

		o = s.taboption('advanced', form.DynamicList, 'masq_src', _('Restrict Masquerading to given source subnets'));
		o.depends('family', '');
		o.depends('family', 'ipv4');
		o.datatype = 'list(neg(or(uciname,hostname,ipmask4)))';
		o.placeholder = '0.0.0.0/0';
		o.modalonly = true;

		o = s.taboption('advanced', form.DynamicList, 'masq_dest', _('Restrict Masquerading to given destination subnets'));
		o.depends('family', '');
		o.depends('family', 'ipv4');
		o.datatype = 'list(neg(or(uciname,hostname,ipmask4)))';
		o.placeholder = '0.0.0.0/0';
		o.modalonly = true;

		o = s.taboption('conntrack', form.Flag, 'conntrack', _('Force connection tracking'), _('Prevent the installation of NOTRACK rules which would bypass connection tracking.'));
		o.modalonly = true;

		o = s.taboption('conntrack', form.Flag, 'masq_allow_invalid', _('Allow "invalid" traffic'), _('Do not install extra rules to reject forwarded traffic with conntrack state invalid. This may be required for complex asymmetric route setups.'));
		o.modalonly = true;

		o = s.taboption('conntrack', form.Flag, 'auto_helper', _('Automatic helper assignment'), _('Automatically assign conntrack helpers based on traffic protocol and port'));
		o.default = o.enabled;
		o.modalonly = true;

		o = s.taboption('conntrack', form.MultiValue, 'helper', _('Conntrack helpers'), _('Explicitly choses allowed connection tracking helpers for zone traffic'));
		o.depends('auto_helper', '0');
		o.modalonly = true;
		for (var i = 0; i < ctHelpers.length; i++)
			o.value(ctHelpers[i].name, '%s (%s)%s'.format(ctHelpers[i].description, ctHelpers[i].name.toUpperCase(), ctHelpers[i].name.toUpperCase()));

		o = s.taboption('advanced', form.Flag, 'log', _('Enable logging on this zone'));
		o.modalonly = true;

		o = s.taboption('advanced', form.Value, 'log_limit', _('Limit log messages'));
		o.depends('log', '1');
		o.placeholder = '10/minute';
		o.modalonly = true;

		o = s.taboption('extra', form.DummyValue, '_extrainfo');
		o.rawhtml = true;
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			return _('Passing raw iptables arguments to source and destination traffic classification rules allows to match packets based on other criteria than interfaces or subnets. These options should be used with extreme care as invalid values could render the firewall ruleset broken, completely exposing all services.');
		};

		o = s.taboption('extra', form.Value, 'extra_src', _('Extra source arguments'), _('Additional raw iptables arguments to classify zone source traffic, e.g. -p tcp --sport 443 to only match inbound HTTPS traffic.'));
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			return uci.get('firewall', section_id, 'extra_src') || uci.get('firewall', section_id, 'extra');
		};
		o.write = function(section_id, value) {
			uci.unset('firewall', section_id, 'extra');
			uci.set('firewall', section_id, 'extra_src', value);
		};

		o = s.taboption('extra', form.Value, 'extra_dest', _('Extra destination arguments'), _('Additional raw iptables arguments to classify zone destination traffic, e.g. -p tcp --dport 443 to only match outbound HTTPS traffic.'));
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			return uci.get('firewall', section_id, 'extra_dest') || uci.get('firewall', section_id, 'extra_src') || uci.get('firewall', section_id, 'extra');
		};
		o.write = function(section_id, value) {
			uci.unset('firewall', section_id, 'extra');
			uci.set('firewall', section_id, 'extra_dest', value);
		};

		o = s.taboption('general', form.DummyValue, '_forwardinfo');
		o.rawhtml = true;
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			return _('The options below control the forwarding policies between this zone (%s) and other zones. Destination zones cover forwarded traffic originating from %q. Source zones match forwarded traffic from other zones targeted at %q. The forwarding rule is unidirectional, e.g. a forward from lan to wan does not imply a permission to forward from wan to lan as well.')
				.format(uci.get('firewall', section_id, 'name'));
		};

		out = o = s.taboption('general', widgets.ZoneSelect, 'out', _('Allow forward to destination zones:'));
		o.nocreate = true;
		o.multiple = true;
		o.modalonly = true;
		o.filter = function(section_id, value) {
			return (uci.get('firewall', section_id, 'name') != value);
		};
		o.cfgvalue = function(section_id) {
			var out = (this.option == 'out'),
			    zone = this.lookupZone(uci.get('firewall', section_id, 'name')),
			    fwds = zone.getForwardingsBy(out ? 'src' : 'dest'),
			    value = [];

			for (var i = 0; i < fwds.length; i++)
				value.push(out ? fwds[i].getDestination() : fwds[i].getSource());

			return value;
		};
		o.write = o.remove = function(section_id, formvalue) {
			var out = (this.option == 'out'),
			    zone = this.lookupZone(uci.get('firewall', section_id, 'name')),
			    fwds = zone.getForwardingsBy(out ? 'src' : 'dest');

			if (formvalue == null)
				formvalue = [];

			if (Array.isArray(formvalue)) {
				for (var i = 0; i < fwds.length; i++) {
					var cmp = out ? fwds[i].getDestination() : fwds[i].getSource();
					if (!formvalue.filter(function(d) { return d == cmp }).length)
						zone.deleteForwarding(fwds[i]);
				}

				for (var i = 0; i < formvalue.length; i++)
					if (out)
						zone.addForwardingTo(formvalue[i]);
					else
						zone.addForwardingFrom(formvalue[i]);
			}
		};

		inp = o = s.taboption('general', widgets.ZoneSelect, 'in', _('Allow forward from source zones:'));
		o.nocreate = true;
		o.multiple = true;
		o.modalonly = true;
		o.write = o.remove = out.write;
		o.filter = out.filter;
		o.cfgvalue = out.cfgvalue;

		return m.render();
	}
});
<commit_msg>luci-app-firewall: fix zone overview page after rpc procedure renaming<commit_after>'use strict';
'require rpc';
'require uci';
'require form';
'require network';
'require firewall';
'require tools.widgets as widgets';

return L.view.extend({
	callConntrackHelpers: rpc.declare({
		object: 'luci',
		method: 'getConntrackHelpers',
		expect: { result: [] }
	}),

	load: function() {
		return Promise.all([
			this.callConntrackHelpers(),
			firewall.getDefaults()
		]);
	},

	render: function(data) {
		var ctHelpers = data[0],
		    fwDefaults = data[1],
		    m, s, o, inp, out;

		m = new form.Map('firewall', _('Firewall - Zone Settings'),
			_('The firewall creates zones over your network interfaces to control network traffic flow.'));

		s = m.section(form.TypedSection, 'defaults', _('General Settings'));
		s.anonymous = true;
		s.addremove = false;

		o = s.option(form.Flag, 'syn_flood', _('Enable SYN-flood protection'));
		o = s.option(form.Flag, 'drop_invalid', _('Drop invalid packets'));

		var p = [
			s.option(form.ListValue, 'input', _('Input')),
			s.option(form.ListValue, 'output', _('Output')),
			s.option(form.ListValue, 'forward', _('Forward'))
		];

		for (var i = 0; i < p.length; i++) {
			p[i].value('REJECT', _('reject'));
			p[i].value('DROP', _('drop'));
			p[i].value('ACCEPT', _('accept'));
		}

		/* Netfilter flow offload support */

		if (L.hasSystemFeature('offloading')) {
			s = m.section(form.TypedSection, 'defaults', _('Routing/NAT Offloading'),
				_('Experimental feature. Not fully compatible with QoS/SQM.'));

			s.anonymous = true;
			s.addremove = false;

			o = s.option(form.Flag, 'flow_offloading',
				_('Software flow offloading'),
				_('Software based offloading for routing/NAT'));
			o.optional = true;

			o = s.option(form.Flag, 'flow_offloading_hw',
				_('Hardware flow offloading'),
				_('Requires hardware NAT support. Implemented at least for mt7621'));
			o.optional = true;
			o.depends('flow_offloading', '1');
		}

		s = m.section(form.GridSection, 'zone', _('Zones'));
		s.addremove = true;
		s.anonymous = true;
		s.sortable  = true;

		s.tab('general', _('General Settings'));
		s.tab('advanced', _('Advanced Settings'));
		s.tab('conntrack', _('Conntrack Settings'));
		s.tab('extra', _('Extra iptables arguments'));

		o = s.taboption('general', form.DummyValue, '_generalinfo');
		o.rawhtml = true;
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			var name = uci.get('firewall', section_id, 'name');

			return _('This section defines common properties of %q. The input and output options set the default policies for traffic entering and leaving this zone while the forward option describes the policy for forwarded traffic between different networks within the zone. Covered networks specifies which available networks are members of this zone.')
				.replace(/%s/g, name).replace(/%q/g, '"' + name + '"');
		};

		o = s.taboption('general', form.Value, 'name', _('Name'));
		o.placeholder = _('Unnamed zone');
		o.modalonly = true;
		o.datatype = 'and(uciname,maxlength(11))';
		o.write = function(section_id, formvalue) {
			var cfgvalue = this.cfgvalue(section_id);

			if (cfgvalue != formvalue)
				return firewall.renameZone(cfgvalue, formvalue);
		};

		o = s.option(widgets.ZoneForwards, '_info', _('Zone ⇒ Forwardings'));
		o.editable = true;
		o.modalonly = false;
		o.cfgvalue = function(section_id) {
			return uci.get('firewall', section_id, 'name');
		};

		var p = [
			s.taboption('general', form.ListValue, 'input', _('Input')),
			s.taboption('general', form.ListValue, 'output', _('Output')),
			s.taboption('general', form.ListValue, 'forward', _('Forward'))
		];

		for (var i = 0; i < p.length; i++) {
			p[i].value('REJECT', _('reject'));
			p[i].value('DROP', _('drop'));
			p[i].value('ACCEPT', _('accept'));
			p[i].editable = true;
		}

		p[0].default = fwDefaults.getInput();
		p[1].default = fwDefaults.getOutput();
		p[2].default = fwDefaults.getForward();

		o = s.taboption('general', form.Flag, 'masq', _('Masquerading'));
		o.editable = true;

		o = s.taboption('general', form.Flag, 'mtu_fix', _('MSS clamping'));
		o.modalonly = true;

		o = s.taboption('general', widgets.NetworkSelect, 'network', _('Covered networks'));
		o.modalonly = true;
		o.multiple = true;
		o.write = function(section_id, formvalue) {
			var name = uci.get('firewall', section_id, 'name'),
			    cfgvalue = this.cfgvalue(section_id);

			if (typeof(cfgvalue) == 'string' && Array.isArray(formvalue) && (cfgvalue == formvalue.join(' ')))
				return;

			var tasks = [ firewall.getZone(name) ];

			if (Array.isArray(formvalue))
				for (var i = 0; i < formvalue.length; i++) {
					var netname = formvalue[i];
					tasks.push(network.getNetwork(netname).then(function(net) {
						return net || network.addNetwork(netname, { 'proto': 'none' });
					}));
				}

			return Promise.all(tasks).then(function(zone_networks) {
				if (zone_networks[0])
					for (var i = 1; i < zone_networks.length; i++)
						zone_networks[0].addNetwork(zone_networks[i].getName());
			});
		};
		o.remove = function(section_id) {
			return uci.set('firewall', section_id, 'network', ' ');
		};

		o = s.taboption('advanced', form.DummyValue, '_advancedinfo');
		o.rawhtml = true;
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			var name = uci.get('firewall', section_id, 'name');

			return _('The options below control the forwarding policies between this zone (%s) and other zones. Destination zones cover forwarded traffic originating from %q. Source zones match forwarded traffic from other zones targeted at %q. The forwarding rule is unidirectional, e.g. a forward from lan to wan does not imply a permission to forward from wan to lan as well.')
				.format(name);
		};

		o = s.taboption('advanced', widgets.DeviceSelect, 'device', _('Covered devices'), _('Use this option to classify zone traffic by raw, non-uci managed network devices.'));
		o.modalonly = true;
		o.multiple = true;

		o = s.taboption('advanced', form.DynamicList, 'subnet', _('Covered subnets'), _('Use this option to classify zone traffic by source or destination subnet instead of networks or devices.'));
		o.datatype = 'neg(cidr)';
		o.modalonly = true;
		o.multiple = true;

		o = s.taboption('advanced', form.ListValue, 'family', _('Restrict to address family'));
		o.value('', _('IPv4 and IPv6'));
		o.value('ipv4', _('IPv4 only'));
		o.value('ipv6', _('IPv6 only'));
		o.modalonly = true;

		o = s.taboption('advanced', form.DynamicList, 'masq_src', _('Restrict Masquerading to given source subnets'));
		o.depends('family', '');
		o.depends('family', 'ipv4');
		o.datatype = 'list(neg(or(uciname,hostname,ipmask4)))';
		o.placeholder = '0.0.0.0/0';
		o.modalonly = true;

		o = s.taboption('advanced', form.DynamicList, 'masq_dest', _('Restrict Masquerading to given destination subnets'));
		o.depends('family', '');
		o.depends('family', 'ipv4');
		o.datatype = 'list(neg(or(uciname,hostname,ipmask4)))';
		o.placeholder = '0.0.0.0/0';
		o.modalonly = true;

		o = s.taboption('conntrack', form.Flag, 'conntrack', _('Force connection tracking'), _('Prevent the installation of NOTRACK rules which would bypass connection tracking.'));
		o.modalonly = true;

		o = s.taboption('conntrack', form.Flag, 'masq_allow_invalid', _('Allow "invalid" traffic'), _('Do not install extra rules to reject forwarded traffic with conntrack state invalid. This may be required for complex asymmetric route setups.'));
		o.modalonly = true;

		o = s.taboption('conntrack', form.Flag, 'auto_helper', _('Automatic helper assignment'), _('Automatically assign conntrack helpers based on traffic protocol and port'));
		o.default = o.enabled;
		o.modalonly = true;

		o = s.taboption('conntrack', form.MultiValue, 'helper', _('Conntrack helpers'), _('Explicitly choses allowed connection tracking helpers for zone traffic'));
		o.depends('auto_helper', '0');
		o.modalonly = true;
		for (var i = 0; i < ctHelpers.length; i++)
			o.value(ctHelpers[i].name, '%s (%s)%s'.format(ctHelpers[i].description, ctHelpers[i].name.toUpperCase(), ctHelpers[i].name.toUpperCase()));

		o = s.taboption('advanced', form.Flag, 'log', _('Enable logging on this zone'));
		o.modalonly = true;

		o = s.taboption('advanced', form.Value, 'log_limit', _('Limit log messages'));
		o.depends('log', '1');
		o.placeholder = '10/minute';
		o.modalonly = true;

		o = s.taboption('extra', form.DummyValue, '_extrainfo');
		o.rawhtml = true;
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			return _('Passing raw iptables arguments to source and destination traffic classification rules allows to match packets based on other criteria than interfaces or subnets. These options should be used with extreme care as invalid values could render the firewall ruleset broken, completely exposing all services.');
		};

		o = s.taboption('extra', form.Value, 'extra_src', _('Extra source arguments'), _('Additional raw iptables arguments to classify zone source traffic, e.g. -p tcp --sport 443 to only match inbound HTTPS traffic.'));
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			return uci.get('firewall', section_id, 'extra_src') || uci.get('firewall', section_id, 'extra');
		};
		o.write = function(section_id, value) {
			uci.unset('firewall', section_id, 'extra');
			uci.set('firewall', section_id, 'extra_src', value);
		};

		o = s.taboption('extra', form.Value, 'extra_dest', _('Extra destination arguments'), _('Additional raw iptables arguments to classify zone destination traffic, e.g. -p tcp --dport 443 to only match outbound HTTPS traffic.'));
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			return uci.get('firewall', section_id, 'extra_dest') || uci.get('firewall', section_id, 'extra_src') || uci.get('firewall', section_id, 'extra');
		};
		o.write = function(section_id, value) {
			uci.unset('firewall', section_id, 'extra');
			uci.set('firewall', section_id, 'extra_dest', value);
		};

		o = s.taboption('general', form.DummyValue, '_forwardinfo');
		o.rawhtml = true;
		o.modalonly = true;
		o.cfgvalue = function(section_id) {
			return _('The options below control the forwarding policies between this zone (%s) and other zones. Destination zones cover forwarded traffic originating from %q. Source zones match forwarded traffic from other zones targeted at %q. The forwarding rule is unidirectional, e.g. a forward from lan to wan does not imply a permission to forward from wan to lan as well.')
				.format(uci.get('firewall', section_id, 'name'));
		};

		out = o = s.taboption('general', widgets.ZoneSelect, 'out', _('Allow forward to destination zones:'));
		o.nocreate = true;
		o.multiple = true;
		o.modalonly = true;
		o.filter = function(section_id, value) {
			return (uci.get('firewall', section_id, 'name') != value);
		};
		o.cfgvalue = function(section_id) {
			var out = (this.option == 'out'),
			    zone = this.lookupZone(uci.get('firewall', section_id, 'name')),
			    fwds = zone.getForwardingsBy(out ? 'src' : 'dest'),
			    value = [];

			for (var i = 0; i < fwds.length; i++)
				value.push(out ? fwds[i].getDestination() : fwds[i].getSource());

			return value;
		};
		o.write = o.remove = function(section_id, formvalue) {
			var out = (this.option == 'out'),
			    zone = this.lookupZone(uci.get('firewall', section_id, 'name')),
			    fwds = zone.getForwardingsBy(out ? 'src' : 'dest');

			if (formvalue == null)
				formvalue = [];

			if (Array.isArray(formvalue)) {
				for (var i = 0; i < fwds.length; i++) {
					var cmp = out ? fwds[i].getDestination() : fwds[i].getSource();
					if (!formvalue.filter(function(d) { return d == cmp }).length)
						zone.deleteForwarding(fwds[i]);
				}

				for (var i = 0; i < formvalue.length; i++)
					if (out)
						zone.addForwardingTo(formvalue[i]);
					else
						zone.addForwardingFrom(formvalue[i]);
			}
		};

		inp = o = s.taboption('general', widgets.ZoneSelect, 'in', _('Allow forward from source zones:'));
		o.nocreate = true;
		o.multiple = true;
		o.modalonly = true;
		o.write = o.remove = out.write;
		o.filter = out.filter;
		o.cfgvalue = out.cfgvalue;

		return m.render();
	}
});
<|endoftext|>


<commit_before>    $.extend($.fn, {
        bindKey: function (hotkey, handler) {
            hotkey = hotkey.toLowerCase();
            var needCtrl = /ctrl\+/.test(hotkey);
            var needAlt = /alt\+/.test(hotkey);
            var needShift = /shift\+/.test(hotkey);
            var key = hotkey.match(/(^|\+)([^\+]+)$/)[2];
            var charCode;
            switch (key) {
                case 'esc':
                    charCode = 27;
                    break;
                case 'enter':
                    charCode = 13;
                    break;
                case 'backspace':
                    charCode = 8;
                    break;
				case 'space':
					charCode=32;
					break;
				case 'left':
					charCode=37;
					break;
				case 'up':
					charCode=38;
					break;
				case 'right':
					charCode=39;
					break;
				case 'down':
					charCode=40;
					break;
				case 'plus':
					charCode=107;
					break;
				case 'minus':
					charCode=109;
					break;
				case '²':
					charCode=222;
					break;
				case ',':
				    charCode=188;
				    break;
                default:
                    charCode = key.charCodeAt(1) - 97 + 65;
                    break;
            }

            return this.bind('keydown', function (evt) {
                if (needCtrl != evt.ctrlKey) return;
                if (needAlt != evt.altKey) return;
                if (needShift != evt.shiftKey) return;

                var result = true;

                if (evt.keyCode == charCode) result = handler(evt);

                if (result === false) {
                    evt.stopPropagation();
                    evt.preventDefault();
                    evt.keyCode = 0;
                    evt.cancelBubble = true;
                    evt.returnValue = false;
                    if (window.event) try {
                        window.event.keyCode = 0;
                    } catch (e) { }
                    return false;
                }
            });
        }
    });
<commit_msg>Update hotkeys.js<commit_after>(function ($) {

    $.extend($.fn, {
        bindKey: function (hotkey, handler) {
            hotkey = hotkey.toLowerCase();
            var needCtrl = /ctrl\+/.test(hotkey);
            var needAlt = /alt\+/.test(hotkey);
            var needShift = /shift\+/.test(hotkey);
            var key = hotkey.match(/(^|\+)([^\+]+)$/)[2];
            var charCode;
            switch (key) {
                case 'esc':
                    charCode = 27;
                    break;
                case 'enter':
                    charCode = 13;
                    break;
                case 'backspace':
                    charCode = 8;
                    break;
				case 'space':
					charCode=32;
					break;
				case 'left':
					charCode=37;
					break;
				case 'up':
					charCode=38;
					break;
				case 'right':
					charCode=39;
					break;
				case 'down':
					charCode=40;
					break;
				case 'plus':
					charCode=107;
					break;
				case 'minus':
					charCode=109;
					break;
				case '²':
					charCode=222;
					break;
				case ',':
				    charCode=188;
				    break;
                default:
                    charCode = key.charCodeAt(0) - 97 + 65;
                    break;
            }

            return this.bind('keydown', function (evt) {
                if (needCtrl != evt.ctrlKey) return;
                if (needAlt != evt.altKey) return;
                if (needShift != evt.shiftKey) return;

                var result = true;

                if (evt.keyCode == charCode) result = handler(evt);

                if (result === false) {
                    evt.stopPropagation();
                    evt.preventDefault();
                    evt.keyCode = 0;
                    evt.cancelBubble = true;
                    evt.returnValue = false;
                    if (window.event) try {
                        window.event.keyCode = 0;
                    } catch (e) { }
                    return false;
                }
            });
        }
    });

})(jQuery);
<|endoftext|>


<commit_before>define(["Tone/core/Tone", "Tone/core/Emitter", "Tone/type/Type"], function(Tone){

	"use strict";

	/**
	 *  AudioBuffer.copyToChannel polyfill
	 *  @private
	 */
	if (window.AudioBuffer && !AudioBuffer.prototype.copyToChannel){
		AudioBuffer.prototype.copyToChannel = function(dest, chanNum, start){
			var channel = this.getChannelData(chanNum);
			start = start || 0;
			for (var i = start; i < channel.length; i++){
				channel[i-start] = dest[i];
			}
		};
	}

	/**
	 *  @class  Buffer loading and storage. Tone.Buffer is used internally by all
	 *          classes that make requests for audio files such as Tone.Player,
	 *          Tone.Sampler and Tone.Convolver.
	 *

	 *          Aside from load callbacks from individual buffers, Tone.Buffer
	 *  		provides static methods which keep track of the loading progress
	 *  		of all of the buffers. These methods are Tone.Buffer.on("load" / "progress" / "error")
	 *
	 *  @constructor
	 *  @extends {Tone}
	 *  @param {AudioBuffer|string} url The url to load, or the audio buffer to set.
	 *  @param {Function=} onload A callback which is invoked after the buffer is loaded.
	 *                            It's recommended to use Tone.Buffer.onload instead
	 *                            since it will give you a callback when ALL buffers are loaded.
	 *  @param {Function=} onerror The callback to invoke if there is an error
	 *  @example
	 * var buffer = new Tone.Buffer("path/to/sound.mp3", function(){
	 * 	//the buffer is now available.
	 * 	var buff = buffer.get();
	 * });
	 */
	Tone.Buffer = function(){

		var options = this.optionsObject(arguments, ["url", "onload", "onerror"], Tone.Buffer.defaults);

		/**
		 *  stores the loaded AudioBuffer
		 *  @type {AudioBuffer}
		 *  @private
		 */
		this._buffer = null;

		/**
		 *  indicates if the buffer should be reversed or not
		 *  @type {Boolean}
		 *  @private
		 */
		this._reversed = options.reverse;

		/**
		 *  The XHR
		 *  @type  {XMLHttpRequest}
		 *  @private
		 */
		this._xhr = null;

		if (options.url instanceof AudioBuffer || options.url instanceof Tone.Buffer){
			this.set(options.url);
			// invoke the onload callback
			if (options.onload){
				options.onload(this);
			}
		} else if (this.isString(options.url)){
			this.load(options.url, options.onload, options.onerror);
		}
	};

	Tone.extend(Tone.Buffer);

	/**
	 *  the default parameters
	 *  @type {Object}
	 */
	Tone.Buffer.defaults = {
		"url" : undefined,
		"reverse" : false
	};

	/**
	 *  Pass in an AudioBuffer or Tone.Buffer to set the value
	 *  of this buffer.
	 *  @param {AudioBuffer|Tone.Buffer} buffer the buffer
	 *  @returns {Tone.Buffer} this
	 */
	Tone.Buffer.prototype.set = function(buffer){
		if (buffer instanceof Tone.Buffer){
			this._buffer = buffer.get();
		} else {
			this._buffer = buffer;
		}
		return this;
	};

	/**
	 *  @return {AudioBuffer} The audio buffer stored in the object.
	 */
	Tone.Buffer.prototype.get = function(){
		return this._buffer;
	};

	/**
	 *  Makes an xhr reqest for the selected url then decodes
	 *  the file as an audio buffer. Invokes
	 *  the callback once the audio buffer loads.
	 *  @param {String} url The url of the buffer to load.
	 *                      filetype support depends on the
	 *                      browser.
	 *  @returns {Promise} returns a Promise which resolves with the Tone.Buffer
	 */
	Tone.Buffer.prototype.load = function(url, onload, onerror){

		var promise = new Promise(function(load, error){

			this._xhr = Tone.Buffer.load(url,

				//success
				function(buff){
					this._xhr = null;
					this.set(buff);
					load(this);
					if (onload){
						onload(this);
					}
				}.bind(this),

				//error
				function(err){
					this._xhr = null;
					error(err);
					if (onerror){
						onerror(err);
					}
				}.bind(this));

		}.bind(this));

		return promise;
	};

	/**
	 *  dispose and disconnect
	 *  @returns {Tone.Buffer} this
	 */
	Tone.Buffer.prototype.dispose = function(){
		Tone.Emitter.prototype.dispose.call(this);
		this._buffer = null;
		if (this._xhr){
			Tone.Buffer._currentDownloads--;
			this._xhr.abort();
			this._xhr = null;
		}
		return this;
	};

	/**
	 * If the buffer is loaded or not
	 * @memberOf Tone.Buffer#
	 * @type {Boolean}
	 * @name loaded
	 * @readOnly
	 */
	Object.defineProperty(Tone.Buffer.prototype, "loaded", {
		get : function(){
			return this.length > 0;
		},
	});

	/**
	 * The duration of the buffer.
	 * @memberOf Tone.Buffer#
	 * @type {Number}
	 * @name duration
	 * @readOnly
	 */
	Object.defineProperty(Tone.Buffer.prototype, "duration", {
		get : function(){
			if (this._buffer){
				return this._buffer.duration;
			} else {
				return 0;
			}
		},
	});

	/**
	 * The length of the buffer in samples
	 * @memberOf Tone.Buffer#
	 * @type {Number}
	 * @name length
	 * @readOnly
	 */
	Object.defineProperty(Tone.Buffer.prototype, "length", {
		get : function(){
			if (this._buffer){
				return this._buffer.length;
			} else {
				return 0;
			}
		},
	});

	/**
	 * The number of discrete audio channels. Returns 0 if no buffer
	 * is loaded.
	 * @memberOf Tone.Buffer#
	 * @type {Number}
	 * @name numberOfChannels
	 * @readOnly
	 */
	Object.defineProperty(Tone.Buffer.prototype, "numberOfChannels", {
		get : function(){
			if (this._buffer){
				return this._buffer.numberOfChannels;
			} else {
				return 0;
			}
		},
	});

	/**
	 *  Set the audio buffer from the array
	 *  @param {Float32Array} array The array to fill the audio buffer
	 *  @param {Number} [channels=1] The number of channels contained in the array.
	 *                               If the channel is more than 1, the input array
	 *                               is expected to be a multidimensional array
	 *                               with dimensions equal to the number of channels.
	 *  @return {Tone.Buffer} this
	 */
	Tone.Buffer.prototype.fromArray = function(array){
		var isMultidimensional = array[0].length > 0;
		var channels = isMultidimensional ? array.length : 1;
		var len = isMultidimensional ? array[0].length : array.length;
		var buffer = this.context.createBuffer(channels, len, this.context.sampleRate);
		if (!isMultidimensional && channels === 1){
			array = [array];
		}
		for (var c = 0; c < channels; c++){
			buffer.copyToChannel(array[c], c);
		}
		this._buffer = buffer;
		return this;
	};

	/**
	 * 	Sums muliple channels into 1 channel
	 *  @param {Number=} channel Optionally only copy a single channel from the array.
	 *  @return {Array}
	 */
	Tone.Buffer.prototype.toMono = function(chanNum){
		if (this.isNumber(chanNum)){
			this.fromArray(this.toArray(chanNum));
		} else {
			var outputArray = new Float32Array(this.length);
			var numChannels = this.numberOfChannels;
			for (var channel = 0; channel < numChannels; channel++){
				var channelArray = this.toArray(channel);
				for (var i = 0; i < channelArray.length; i++){
					outputArray[i] += channelArray[i];
				}
			}
			//divide by the number of channels
			outputArray = outputArray.map(function(sample){
				return sample / numChannels;
			});
			this.fromArray(outputArray);
		}
		return this;
	};

	/**
	 * 	Get the buffer as an array. Single channel buffers will return a 1-dimensional
	 * 	Float32Array, and multichannel buffers will return multidimensional arrays.
	 *  @param {Number=} channel Optionally only copy a single channel from the array.
	 *  @return {Array}
	 */
	Tone.Buffer.prototype.toArray = function(channel){
		if (this.isNumber(channel)){
			return this._buffer.getChannelData(channel);
		} else {
			var ret = [];
			for (var c = 0; c < this.numberOfChannels; c++){
				ret[c] = new Float32Array(this.length);
				if (this.isFunction(this._buffer.copyFromChannel)){
					this._buffer.copyFromChannel(ret[c], c);
				} else {
					var channelData = this._buffer.getChannelData(c);
					var retArray = ret[c];
					for (var i = 0; i < channelData.length; i++){
						retArray[i] = channelData[i];
					}
				}
			}
			if (ret.length === 1){
				return ret[0];
			} else {
				return ret;
			}
		}
	};

	/**
	 *  Cut a subsection of the array and return a buffer of the
	 *  subsection. Does not modify the original buffer
	 *  @param {Time} start The time to start the slice
	 *  @param {Time=} end The end time to slice. If none is given
	 *                     will default to the end of the buffer
	 *  @return {Tone.Buffer} this
	 */
	Tone.Buffer.prototype.slice = function(start, end){
		end = this.defaultArg(end, this.duration);
		var startSamples = Math.floor(this.context.sampleRate * this.toSeconds(start));
		var endSamples = Math.floor(this.context.sampleRate * this.toSeconds(end));
		var replacement = [];
		for (var i = 0; i < this.numberOfChannels; i++){
			replacement[i] = this.toArray(i).slice(startSamples, endSamples);
		}
		var retBuffer = new Tone.Buffer().fromArray(replacement);
		return retBuffer;
	};

	/**
	 *  Reverse the buffer.
	 *  @private
	 *  @return {Tone.Buffer} this
	 */
	Tone.Buffer.prototype._reverse = function(){
		if (this.loaded){
			for (var i = 0; i < this._buffer.numberOfChannels; i++){
				Array.prototype.reverse.call(this._buffer.getChannelData(i));
			}
		}
		return this;
	};

	/**
	 * Reverse the buffer.
	 * @memberOf Tone.Buffer#
	 * @type {Boolean}
	 * @name reverse
	 */
	Object.defineProperty(Tone.Buffer.prototype, "reverse", {
		get : function(){
			return this._reversed;
		},
		set : function(rev){
			if (this._reversed !== rev){
				this._reversed = rev;
				this._reverse();
			}
		},
	});

	///////////////////////////////////////////////////////////////////////////
	// STATIC METHODS
	///////////////////////////////////////////////////////////////////////////

	//statically inherits Emitter methods
	Tone.Emitter.mixin(Tone.Buffer);

	/**
	 *  the static queue for all of the xhr requests
	 *  @type {Array}
	 *  @private
	 */
	Tone.Buffer._downloadQueue = [];

	/**
	 *  the total number of downloads
	 *  @type {Number}
	 *  @private
	 */
	Tone.Buffer._currentDownloads = 0;

	/**
	 *  A path which is prefixed before every url.
	 *  @type  {String}
	 *  @static
	 */
	Tone.Buffer.baseUrl = "";

	/**
	 *  Loads a url using XMLHttpRequest.
	 *  @param {String} url
	 *  @param {Function} onload
	 *  @param {Function} onerror
	 *  @param {Function} onprogress
	 *  @return {XMLHttpRequest}
	 */
	Tone.Buffer.load = function(url, onload, onerror){
		//default
		onload = onload || Tone.noOp;

		function onError(e){
			if (onerror){
				onerror(e);
				Tone.Buffer.emit("error", e);
			} else {
				throw new Error(e);
			}
		}

		function onProgress(){
			//calculate the progress
			var totalProgress = 0;
			for (var i = 0; i < Tone.Buffer._downloadQueue.length; i++){
				totalProgress += Tone.Buffer._downloadQueue[i].progress;
			}
			Tone.Buffer.emit("progress", totalProgress / Tone.Buffer._downloadQueue.length);
		}

		var request = new XMLHttpRequest();
		request.open("GET", Tone.Buffer.baseUrl + url, true);
		request.responseType = "arraybuffer";
		//start out as 0
		request.progress = 0;

		Tone.Buffer._currentDownloads++;
		Tone.Buffer._downloadQueue.push(request);

		request.addEventListener("load", function(){
			if (request.status === 200){
				Tone.context.decodeAudioData(request.response, function(buff) {

					request.progress = 1;
					onProgress();
					onload(buff);

					Tone.Buffer._currentDownloads--;
					if (Tone.Buffer._currentDownloads === 0){
						// clear the downloads
						Tone.Buffer._downloadQueue = [];
						//emit the event at the end
						Tone.Buffer.emit("load");
					}

				}, function(){
					onError("Tone.Buffer: could not decode audio data: "+url);
				});
			} else {
				onError("Tone.Buffer: could not locate file: "+url);
			}
		});
		request.addEventListener("error", onError);

		request.addEventListener("progress", function(event){
			if (event.lengthComputable){
				//only go to 95%, the last 5% is when the audio is decoded
				request.progress = (event.loaded / event.total) * 0.95;
				onProgress();
			}
		});

		request.send();

		return request;
	};

	/**
	 *  Stop all of the downloads in progress
	 *  @return {Tone.Buffer}
	 *  @static
	 */
	Tone.Buffer.cancelDownloads = function(){
		Tone.Buffer._downloadQueue.forEach(function(request){
			request.abort();
		});
		Tone.Buffer._currentDownloads = 0;
		return Tone.Buffer;
	};

	/**
	 *  Checks a url's extension to see if the current browser can play that file type.
	 *  @param {String} url The url/extension to test
	 *  @return {Boolean} If the file extension can be played
	 *  @static
	 *  @example
	 * Tone.Buffer.supportsType("wav"); //returns true
	 * Tone.Buffer.supportsType("path/to/file.wav"); //returns true
	 */
	Tone.Buffer.supportsType = function(url){
		var extension = url.split(".");
		extension = extension[extension.length - 1];
		var response = document.createElement("audio").canPlayType("audio/"+extension);
		return response !== "";
	};

	/**
	 *  Returns a Promise which resolves when all of the buffers have loaded
	 */
	Tone.loaded = function(){
		var onload, onerror;
		return new Promise(function(success, fail){
			onload = function(){
				success();
			};
			onerror = function(){
				fail();
			};
			//add the event listeners
			Tone.Buffer.on("load", onload);
			Tone.Buffer.on("error", onerror);
		}).then(function(){
			//remove the events when it's resolved
			Tone.Buffer.off("load", onload);
			Tone.Buffer.off("error", onerror);
		}).catch(function(){
			//remove the events when it's resolved
			Tone.Buffer.off("load", onload);
			Tone.Buffer.off("error", onerror);
		});
	};

	return Tone.Buffer;
});<commit_msg>also polyfilling copyFromChannel<commit_after>define(["Tone/core/Tone", "Tone/core/Emitter", "Tone/type/Type"], function(Tone){

	"use strict";

	/**
	 *  AudioBuffer.copyToChannel polyfill
	 *  @private
	 */
	if (window.AudioBuffer && !AudioBuffer.prototype.copyToChannel){
		AudioBuffer.prototype.copyToChannel = function(dest, chanNum, start){
			var channel = this.getChannelData(chanNum);
			start = start || 0;
			for (var i = 0; i < channel.length; i++){
				channel[i+start] = dest[i];
			}
		};
		AudioBuffer.prototype.copyFromChannel = function(dest, chanNum, start){
			var channel = this.getChannelData(chanNum);
			start = start || 0;
			for (var i = 0; i < channel.length; i++){
				dest[i] = channel[i+start];
			}
		};
	}

	/**
	 *  @class  Buffer loading and storage. Tone.Buffer is used internally by all
	 *          classes that make requests for audio files such as Tone.Player,
	 *          Tone.Sampler and Tone.Convolver.
	 *

	 *          Aside from load callbacks from individual buffers, Tone.Buffer
	 *  		provides static methods which keep track of the loading progress
	 *  		of all of the buffers. These methods are Tone.Buffer.on("load" / "progress" / "error")
	 *
	 *  @constructor
	 *  @extends {Tone}
	 *  @param {AudioBuffer|string} url The url to load, or the audio buffer to set.
	 *  @param {Function=} onload A callback which is invoked after the buffer is loaded.
	 *                            It's recommended to use Tone.Buffer.onload instead
	 *                            since it will give you a callback when ALL buffers are loaded.
	 *  @param {Function=} onerror The callback to invoke if there is an error
	 *  @example
	 * var buffer = new Tone.Buffer("path/to/sound.mp3", function(){
	 * 	//the buffer is now available.
	 * 	var buff = buffer.get();
	 * });
	 */
	Tone.Buffer = function(){

		var options = this.optionsObject(arguments, ["url", "onload", "onerror"], Tone.Buffer.defaults);

		/**
		 *  stores the loaded AudioBuffer
		 *  @type {AudioBuffer}
		 *  @private
		 */
		this._buffer = null;

		/**
		 *  indicates if the buffer should be reversed or not
		 *  @type {Boolean}
		 *  @private
		 */
		this._reversed = options.reverse;

		/**
		 *  The XHR
		 *  @type  {XMLHttpRequest}
		 *  @private
		 */
		this._xhr = null;

		if (options.url instanceof AudioBuffer || options.url instanceof Tone.Buffer){
			this.set(options.url);
			// invoke the onload callback
			if (options.onload){
				options.onload(this);
			}
		} else if (this.isString(options.url)){
			this.load(options.url, options.onload, options.onerror);
		}
	};

	Tone.extend(Tone.Buffer);

	/**
	 *  the default parameters
	 *  @type {Object}
	 */
	Tone.Buffer.defaults = {
		"url" : undefined,
		"reverse" : false
	};

	/**
	 *  Pass in an AudioBuffer or Tone.Buffer to set the value
	 *  of this buffer.
	 *  @param {AudioBuffer|Tone.Buffer} buffer the buffer
	 *  @returns {Tone.Buffer} this
	 */
	Tone.Buffer.prototype.set = function(buffer){
		if (buffer instanceof Tone.Buffer){
			this._buffer = buffer.get();
		} else {
			this._buffer = buffer;
		}
		return this;
	};

	/**
	 *  @return {AudioBuffer} The audio buffer stored in the object.
	 */
	Tone.Buffer.prototype.get = function(){
		return this._buffer;
	};

	/**
	 *  Makes an xhr reqest for the selected url then decodes
	 *  the file as an audio buffer. Invokes
	 *  the callback once the audio buffer loads.
	 *  @param {String} url The url of the buffer to load.
	 *                      filetype support depends on the
	 *                      browser.
	 *  @returns {Promise} returns a Promise which resolves with the Tone.Buffer
	 */
	Tone.Buffer.prototype.load = function(url, onload, onerror){

		var promise = new Promise(function(load, error){

			this._xhr = Tone.Buffer.load(url,

				//success
				function(buff){
					this._xhr = null;
					this.set(buff);
					load(this);
					if (onload){
						onload(this);
					}
				}.bind(this),

				//error
				function(err){
					this._xhr = null;
					error(err);
					if (onerror){
						onerror(err);
					}
				}.bind(this));

		}.bind(this));

		return promise;
	};

	/**
	 *  dispose and disconnect
	 *  @returns {Tone.Buffer} this
	 */
	Tone.Buffer.prototype.dispose = function(){
		Tone.Emitter.prototype.dispose.call(this);
		this._buffer = null;
		if (this._xhr){
			Tone.Buffer._currentDownloads--;
			this._xhr.abort();
			this._xhr = null;
		}
		return this;
	};

	/**
	 * If the buffer is loaded or not
	 * @memberOf Tone.Buffer#
	 * @type {Boolean}
	 * @name loaded
	 * @readOnly
	 */
	Object.defineProperty(Tone.Buffer.prototype, "loaded", {
		get : function(){
			return this.length > 0;
		},
	});

	/**
	 * The duration of the buffer.
	 * @memberOf Tone.Buffer#
	 * @type {Number}
	 * @name duration
	 * @readOnly
	 */
	Object.defineProperty(Tone.Buffer.prototype, "duration", {
		get : function(){
			if (this._buffer){
				return this._buffer.duration;
			} else {
				return 0;
			}
		},
	});

	/**
	 * The length of the buffer in samples
	 * @memberOf Tone.Buffer#
	 * @type {Number}
	 * @name length
	 * @readOnly
	 */
	Object.defineProperty(Tone.Buffer.prototype, "length", {
		get : function(){
			if (this._buffer){
				return this._buffer.length;
			} else {
				return 0;
			}
		},
	});

	/**
	 * The number of discrete audio channels. Returns 0 if no buffer
	 * is loaded.
	 * @memberOf Tone.Buffer#
	 * @type {Number}
	 * @name numberOfChannels
	 * @readOnly
	 */
	Object.defineProperty(Tone.Buffer.prototype, "numberOfChannels", {
		get : function(){
			if (this._buffer){
				return this._buffer.numberOfChannels;
			} else {
				return 0;
			}
		},
	});

	/**
	 *  Set the audio buffer from the array
	 *  @param {Float32Array} array The array to fill the audio buffer
	 *  @param {Number} [channels=1] The number of channels contained in the array.
	 *                               If the channel is more than 1, the input array
	 *                               is expected to be a multidimensional array
	 *                               with dimensions equal to the number of channels.
	 *  @return {Tone.Buffer} this
	 */
	Tone.Buffer.prototype.fromArray = function(array){
		var isMultidimensional = array[0].length > 0;
		var channels = isMultidimensional ? array.length : 1;
		var len = isMultidimensional ? array[0].length : array.length;
		var buffer = this.context.createBuffer(channels, len, this.context.sampleRate);
		if (!isMultidimensional && channels === 1){
			array = [array];
		}
		for (var c = 0; c < channels; c++){
			buffer.copyToChannel(array[c], c);
		}
		this._buffer = buffer;
		return this;
	};

	/**
	 * 	Sums muliple channels into 1 channel
	 *  @param {Number=} channel Optionally only copy a single channel from the array.
	 *  @return {Array}
	 */
	Tone.Buffer.prototype.toMono = function(chanNum){
		if (this.isNumber(chanNum)){
			this.fromArray(this.toArray(chanNum));
		} else {
			var outputArray = new Float32Array(this.length);
			var numChannels = this.numberOfChannels;
			for (var channel = 0; channel < numChannels; channel++){
				var channelArray = this.toArray(channel);
				for (var i = 0; i < channelArray.length; i++){
					outputArray[i] += channelArray[i];
				}
			}
			//divide by the number of channels
			outputArray = outputArray.map(function(sample){
				return sample / numChannels;
			});
			this.fromArray(outputArray);
		}
		return this;
	};

	/**
	 * 	Get the buffer as an array. Single channel buffers will return a 1-dimensional
	 * 	Float32Array, and multichannel buffers will return multidimensional arrays.
	 *  @param {Number=} channel Optionally only copy a single channel from the array.
	 *  @return {Array}
	 */
	Tone.Buffer.prototype.toArray = function(channel){
		if (this.isNumber(channel)){
			return this._buffer.getChannelData(channel);
		} else if (this.numberOfChannels === 1){
			return this.toArray(0);
		} else {
			var ret = [];
			for (var c = 0; c < this.numberOfChannels; c++){
				ret[c] = this._buffer.getChannelData(c);
			}
			return ret;
		}
	};

	/**
	 *  Cut a subsection of the array and return a buffer of the
	 *  subsection. Does not modify the original buffer
	 *  @param {Time} start The time to start the slice
	 *  @param {Time=} end The end time to slice. If none is given
	 *                     will default to the end of the buffer
	 *  @return {Tone.Buffer} this
	 */
	Tone.Buffer.prototype.slice = function(start, end){
		end = this.defaultArg(end, this.duration);
		var startSamples = Math.floor(this.context.sampleRate * this.toSeconds(start));
		var endSamples = Math.floor(this.context.sampleRate * this.toSeconds(end));
		var replacement = [];
		for (var i = 0; i < this.numberOfChannels; i++){
			replacement[i] = this.toArray(i).slice(startSamples, endSamples);
		}
		var retBuffer = new Tone.Buffer().fromArray(replacement);
		return retBuffer;
	};

	/**
	 *  Reverse the buffer.
	 *  @private
	 *  @return {Tone.Buffer} this
	 */
	Tone.Buffer.prototype._reverse = function(){
		if (this.loaded){
			for (var i = 0; i < this._buffer.numberOfChannels; i++){
				Array.prototype.reverse.call(this._buffer.getChannelData(i));
			}
		}
		return this;
	};

	/**
	 * Reverse the buffer.
	 * @memberOf Tone.Buffer#
	 * @type {Boolean}
	 * @name reverse
	 */
	Object.defineProperty(Tone.Buffer.prototype, "reverse", {
		get : function(){
			return this._reversed;
		},
		set : function(rev){
			if (this._reversed !== rev){
				this._reversed = rev;
				this._reverse();
			}
		},
	});

	///////////////////////////////////////////////////////////////////////////
	// STATIC METHODS
	///////////////////////////////////////////////////////////////////////////

	//statically inherits Emitter methods
	Tone.Emitter.mixin(Tone.Buffer);

	/**
	 *  the static queue for all of the xhr requests
	 *  @type {Array}
	 *  @private
	 */
	Tone.Buffer._downloadQueue = [];

	/**
	 *  the total number of downloads
	 *  @type {Number}
	 *  @private
	 */
	Tone.Buffer._currentDownloads = 0;

	/**
	 *  A path which is prefixed before every url.
	 *  @type  {String}
	 *  @static
	 */
	Tone.Buffer.baseUrl = "";

	/**
	 *  Loads a url using XMLHttpRequest.
	 *  @param {String} url
	 *  @param {Function} onload
	 *  @param {Function} onerror
	 *  @param {Function} onprogress
	 *  @return {XMLHttpRequest}
	 */
	Tone.Buffer.load = function(url, onload, onerror){
		//default
		onload = onload || Tone.noOp;

		function onError(e){
			if (onerror){
				onerror(e);
				Tone.Buffer.emit("error", e);
			} else {
				throw new Error(e);
			}
		}

		function onProgress(){
			//calculate the progress
			var totalProgress = 0;
			for (var i = 0; i < Tone.Buffer._downloadQueue.length; i++){
				totalProgress += Tone.Buffer._downloadQueue[i].progress;
			}
			Tone.Buffer.emit("progress", totalProgress / Tone.Buffer._downloadQueue.length);
		}

		var request = new XMLHttpRequest();
		request.open("GET", Tone.Buffer.baseUrl + url, true);
		request.responseType = "arraybuffer";
		//start out as 0
		request.progress = 0;

		Tone.Buffer._currentDownloads++;
		Tone.Buffer._downloadQueue.push(request);

		request.addEventListener("load", function(){
			if (request.status === 200){
				Tone.context.decodeAudioData(request.response, function(buff) {

					request.progress = 1;
					onProgress();
					onload(buff);

					Tone.Buffer._currentDownloads--;
					if (Tone.Buffer._currentDownloads === 0){
						// clear the downloads
						Tone.Buffer._downloadQueue = [];
						//emit the event at the end
						Tone.Buffer.emit("load");
					}

				}, function(){
					onError("Tone.Buffer: could not decode audio data: "+url);
				});
			} else {
				onError("Tone.Buffer: could not locate file: "+url);
			}
		});
		request.addEventListener("error", onError);

		request.addEventListener("progress", function(event){
			if (event.lengthComputable){
				//only go to 95%, the last 5% is when the audio is decoded
				request.progress = (event.loaded / event.total) * 0.95;
				onProgress();
			}
		});

		request.send();

		return request;
	};

	/**
	 *  Stop all of the downloads in progress
	 *  @return {Tone.Buffer}
	 *  @static
	 */
	Tone.Buffer.cancelDownloads = function(){
		Tone.Buffer._downloadQueue.forEach(function(request){
			request.abort();
		});
		Tone.Buffer._currentDownloads = 0;
		return Tone.Buffer;
	};

	/**
	 *  Checks a url's extension to see if the current browser can play that file type.
	 *  @param {String} url The url/extension to test
	 *  @return {Boolean} If the file extension can be played
	 *  @static
	 *  @example
	 * Tone.Buffer.supportsType("wav"); //returns true
	 * Tone.Buffer.supportsType("path/to/file.wav"); //returns true
	 */
	Tone.Buffer.supportsType = function(url){
		var extension = url.split(".");
		extension = extension[extension.length - 1];
		var response = document.createElement("audio").canPlayType("audio/"+extension);
		return response !== "";
	};

	/**
	 *  Returns a Promise which resolves when all of the buffers have loaded
	 */
	Tone.loaded = function(){
		var onload, onerror;
		return new Promise(function(success, fail){
			onload = function(){
				success();
			};
			onerror = function(){
				fail();
			};
			//add the event listeners
			Tone.Buffer.on("load", onload);
			Tone.Buffer.on("error", onerror);
		}).then(function(){
			//remove the events when it's resolved
			Tone.Buffer.off("load", onload);
			Tone.Buffer.off("error", onerror);
		}).catch(function(){
			//remove the events when it's resolved
			Tone.Buffer.off("load", onload);
			Tone.Buffer.off("error", onerror);
		});
	};

	return Tone.Buffer;
});<|endoftext|>


<commit_before>var irc = require("irc");
var repl = require("repl");
var fs = require("fs");
var clc = require("cli-color");
var util = require("util");

var config = JSON.parse(fs.readFileSync("config.json"));
var defcfg = {
	autoRejoin: false,
	channels: [],
	messageSplit: 300,
};
config.__proto__ = defcfg;

var bot = new irc.Client(config.server, config.nick, config);
bot.out = {};
bot.out.file = fs.createWriteStream("./data/simbot.log", {flags: 'a'});

bot.conn.setTimeout(180 * 1000);
bot.out.time = function() {
	return new Date().toISOString();
};

bot.out.wrapper = function(type, color, module, message) {
	console.log(clc.blackBright(bot.out.time()) + " " + color("[" + type + ":") + color.bold(module) + color("] ") + message);
	bot.out.file.write(bot.out.time() + " [" + type + ":" + module + "] " + message + "\n", 'utf8');
};

bot.out.log = function(module, message) {
	bot.out.wrapper("LOG", clc.cyan, module, message);
};

bot.out.doing = function(module, message) {
	bot.out.wrapper("DOING", clc.cyanBright, module, message);
};

bot.out.ok = function(module, message) {
	bot.out.wrapper("OK", clc.greenBright, module, message);
};

bot.out.debug = function(module, message) {
	bot.out.wrapper("DEBUG", clc.magentaBright, module, message);
};

bot.out.warn = function(module, message) {
	bot.out.wrapper("WARN", clc.yellowBright, module, message);
};

bot.out.error = function(module, message) {
	bot.out.wrapper("ERROR", clc.redBright, module, message);
};

bot.out.ok("bot", "bot started");

bot.conn.on("timeout", function() {
	bot.conn.destroy();
	//bot.connect();
});

bot.on("error", function(message) {
	bot.out.error("irc", util.inspect(message, {colors: true}));
});

bot.on("registered", function(message) {
	bot.send("UMODE2", "+B");
	bot.out.ok("irc", "registered on server");
});

bot.plugins = require("./plugins");

fs.readFile("autoload.json", function(err, data) {
	bot.out.doing("bot", "autoloading plugins...");
	var autoload = JSON.parse(data).autoload;
	for (var i = 0; i < autoload.length; i++) {
		bot.plugins.load(autoload[i]);
	}
});

if (config.saveinterval) {
	bot.saver = setInterval(function() {
		bot.out.doing("bot", "autosaving plugins...");
		for (var name in bot.plugins) {
			if (bot.plugins[name].name) {
				bot.plugins.save(name);
			}
		}
	}, config.saveinterval * 60 * 1000);
}

process.on("SIGINT", function() {
	bot.out.doing("bot", "unloading plugins...");
	for (var name in bot.plugins) {
		if (bot.plugins[name].name) {
			bot.plugins.unload(name);
		}
	}
	bot.out.ok("bot", "bot stopped");
	process.exit(0);
});

process.on("uncaughtException", function(e) {
	bot.out.error("bot", "uncaught exception: " + e.stack);
});

repl.start({
	useGlobal: true
}).context.bot = bot;

<commit_msg>Cleaner output in REPL<commit_after>var irc = require("irc");
var repl = require("repl");
var fs = require("fs");
var clc = require("cli-color");
var util = require("util");

var config = JSON.parse(fs.readFileSync("config.json"));
var defcfg = {
	autoRejoin: false,
	channels: [],
	messageSplit: 300,
};
config.__proto__ = defcfg;

var bot = new irc.Client(config.server, config.nick, config);
bot.out = {};
bot.out.file = fs.createWriteStream("./data/simbot.log", {flags: 'a'});

bot.conn.setTimeout(180 * 1000);
bot.out.time = function() {
	return new Date().toISOString();
};

bot.out.wrapper = function(type, color, module, message) {
	console.log(clc.blackBright(bot.out.time()) + " " + color("[" + type + ":") + color.bold(module) + color("] ") + message);
	bot.out.file.write(bot.out.time() + " [" + type + ":" + module + "] " + message + "\n", 'utf8');
};

bot.out.log = function(module, message) {
	bot.out.wrapper("LOG", clc.cyan, module, message);
};

bot.out.doing = function(module, message) {
	bot.out.wrapper("DOING", clc.cyanBright, module, message);
};

bot.out.ok = function(module, message) {
	bot.out.wrapper("OK", clc.greenBright, module, message);
};

bot.out.debug = function(module, message) {
	bot.out.wrapper("DEBUG", clc.magentaBright, module, message);
};

bot.out.warn = function(module, message) {
	bot.out.wrapper("WARN", clc.yellowBright, module, message);
};

bot.out.error = function(module, message) {
	bot.out.wrapper("ERROR", clc.redBright, module, message);
};

bot.out.ok("bot", "bot started");

bot.conn.on("timeout", function() {
	bot.conn.destroy();
	//bot.connect();
});

bot.on("error", function(message) {
	bot.out.error("irc", util.inspect(message, {colors: true}));
});

bot.on("registered", function(message) {
	bot.send("UMODE2", "+B");
	bot.out.ok("irc", "registered on server");
});

bot.plugins = require("./plugins");

fs.readFile("autoload.json", function(err, data) {
	bot.out.doing("bot", "autoloading plugins...");
	var autoload = JSON.parse(data).autoload;
	for (var i = 0; i < autoload.length; i++) {
		bot.plugins.load(autoload[i]);
	}
});

if (config.saveinterval) {
	bot.saver = setInterval(function() {
		bot.out.doing("bot", "autosaving plugins...");
		for (var name in bot.plugins) {
			if (bot.plugins[name].name) {
				bot.plugins.save(name);
			}
		}
	}, config.saveinterval * 60 * 1000);
}

process.on("SIGINT", function() {
	bot.out.doing("bot", "unloading plugins...");
	for (var name in bot.plugins) {
		if (bot.plugins[name].name) {
			bot.plugins.unload(name);
		}
	}
	bot.out.ok("bot", "bot stopped");
	process.exit(0);
});

process.on("uncaughtException", function(e) {
	bot.out.error("bot", "uncaught exception: " + e.stack);
});

repl.start({
	useGlobal: true,
	ignoreUndefined: true
}).context.bot = bot;

<|endoftext|>


<commit_before>import { delay } from 'redux-saga';
import { spawn, fork, join, call } from 'redux-saga/effects';

function func() {
  console.log(1.5);
}

function* generator(i) {
  yield call(delay, 1000);
  console.log(yield `-- ${i}`);
  yield call(childGenerator, i);
}

function* childGenerator(i) {
  yield call(delay, 2000);
  console.log(yield `---- ${i}`);
}

export default function* api() {
  console.log(yield 'call(func) -> {');
  yield call(func);
  console.log(yield '} <- call(func)');

  console.log(yield 'fork(generator) -> {');
  yield fork(generator, 'fork(generator)');
  console.log(yield '} <- fork(generator)');

  console.log('fork(generator) and join(task) -> {');
  let task = yield fork(generator, 'fork(generator) and join(task)');
  yield join(task);
  console.log(yield '} <- fork(generator) and join(task)');

  console.log('spawn(generator) -> {');
  yield spawn(generator, 'spawn(generator)');
  yield join(task);
  console.log(yield '} <- spawn(generator)');

  console.log('spawn(generator) and join(task) -> {');
  task = yield spawn(generator, 'spawn(generator) and join(task)');
  yield join(task);
  console.log(yield '} <- spawn(generator) and join(task)');
}
<commit_msg>redux-saga: add a code of cancel<commit_after>import { delay } from 'redux-saga';
import { spawn, fork, join, call, cancel } from 'redux-saga/effects';

function func() {
  console.log(1.5);
}

function* generator(i) {
  yield call(delay, 1000);
  console.log(yield `-- ${i}`);
  yield call(childGenerator, i);
}

function* childGenerator(i) {
  yield call(delay, 2000);
  console.log(yield `---- ${i}`);
}

export default function* api() {
  console.log(yield 'call(func) -> {');
  yield call(func);
  console.log(yield '} <- call(func)');

  console.log(yield 'fork(generator) -> {');
  yield fork(generator, 'fork(generator)');
  console.log(yield '} <- fork(generator)');

  console.log('fork(generator) and join(task) -> {');
  let task = yield fork(generator, 'fork(generator) and join(task)');
  yield join(task);
  console.log(yield '} <- fork(generator) and join(task)');

  console.log('spawn(generator) -> {');
  yield spawn(generator, 'spawn(generator)');
  yield join(task);
  console.log(yield '} <- spawn(generator)');

  console.log('spawn(generator) and join(task) -> {');
  task = yield spawn(generator, 'spawn(generator) and join(task)');
  yield join(task);
  console.log(yield '} <- spawn(generator) and join(task)');

  console.log('fork(generator) and cancel(task) -> {');
  task = yield fork(generator, 'fork(generator) and cancel(task)');
  yield call(delay, 500)
  yield cancel(task);
  console.log(yield '} <- fork(generator) and cancel(task)');

}
<|endoftext|>


<commit_before>var assert = require('assert');
var fs = require('fs');
var path = require('path');
var request = require('request');

var baseUrl = 'http://latex.aslushnikov.com';
if (process.argv[process.argv.length - 1] === '--local')
    baseUrl = 'http://localhost:2700';

describe(baseUrl, function() {
    this.timeout(60000);
    this.slow(20000);
    describe('/compile', function() {
        describe('git', function() {
            it('https://github.com/aslushnikov/diplom-latex&target=diplom.tex', async function() {
                var url = baseUrl +  '/compile?git=git%3A%2F%2Fgithub.com%2Faslushnikov%2Fdiplom-latex.git&target=diplom.tex';
                var request = createGetRequest(url);
                await expectPdf(request);
            });
        });
        describe('xelatex command', function() {
            it('https://github.com/posquit0/Awesome-CV&target=examples/resume.tex&command=xelatex', async function() {
                var url = baseUrl +  '/compile?git=https%3A%2F%2Fgithub.com%2Fposquit0%2FAwesome-CV&target=examples%2Fresume.tex&command=xelatex';
                var request = createGetRequest(url);
                await expectPdf(request);
            });
        });
        describe('text', function() {
            it('goodText', async function() {
                var goodText = [
                    '\\documentclass{article}',
                    '\\begin{document}',
                    'Correct document.',
                    '\\end{document}'
                ].join('\n');
                var url = baseUrl + '/compile?text=' + encodeURIComponent(goodText);
                var request = createGetRequest(url);
                await expectPdf(request);
            });

            it('badText', async function() {
                var badText = [
                    '\\documentclass{article}',
                    '\\begin{document}',
                    'Does not compile!'
                ].join('\n');
                var url = baseUrl + '/compile?text=' + encodeURIComponent(badText);
                var request = createGetRequest(url);
                await expectError(request);
            });
        });
        describe('url', function() {
            it('goodURL', async function() {
                var goodURL = 'https://raw.githubusercontent.com/aslushnikov/latex-online/master/sample/sample.tex';
                var url = baseUrl + '/compile?url=' + encodeURIComponent(goodURL);
                var request = createGetRequest(url);
                await expectPdf(request);
            });
            it('badURL', async function() {
                var badURL = 'https://raw.githubusercontent.com/aslushnikov/latex-online/master/sample/bad.tex';
                var url = baseUrl + '/compile?url=' + encodeURIComponent(badURL);
                var request = createGetRequest(url);
                await expectError(request);
            });
        });
    });

    describe('/data', function() {
        it('cli-good', async function() {
            var filePath = path.join(__dirname, 'resources', 'good.tar.gz');
            var target = 'short.tex';
            var request = createUploadRequest(filePath, target);
            await expectPdf(request);
        });
        it('cli-bad', async function() {
            var filePath = path.join(__dirname, 'resources', 'bad.tar.gz');
            var target = 'short.tex';
            var request = createUploadRequest(filePath, target);
            await expectError(request);
        });
        it('cli-cache-busting', async function() {
            var filePath = path.join(__dirname, 'resources', 'good.tar.gz');
            var target = 'nonexistent.tex';
            var request = createUploadRequest(filePath, target);
            await expectError(request);
            target = 'short.tex';
            request = createUploadRequest(filePath, target);
            await expectPdf(request);
        });
    });

});
/**
 * @param {!Request} request
 */
async function expectPdf(request) {
    var response = await request
    assert.ok(response);
    assert.equal(response.statusCode, 200);
    assert.equal(response.headers['content-type'], 'application/pdf');
}

/**
 * @param {string} testName
 * @param {!Request} request
 */
async function expectError( request) {
    var response = await request;
    assert.ok(response);
    assert.equal(response.statusCode, 400);
    assert.equal(response.headers['content-type'], 'text/plain; charset=UTF-8');
}

/**
 * @param {string} url
 * @return {!Promise}
 */
function createGetRequest(url) {
    var options = {
        method: 'get',
        url: url,
        headers: {
            // Pretend to be bot: Avoid analytics-related redirects.
            'User-Agent': 'wget latex-oneline test sanity-test.js'
        }
    };
    return doRequest(options);
}

/**
 * @param {string} filePath
 * @param {string} target
 * @return {!Promise}
 */
function createUploadRequest(filePath, target) {
    var options = {
        method: 'post',
        url: baseUrl + '/data?target=' + encodeURIComponent(target),
        formData: {
            file: fs.createReadStream(filePath)
        }
    };
    return doRequest(options);
}

/**
 * @param {!Object} options
 * @return {!Promise}
 */
function doRequest(options) {
    var fulfill, reject;
    var promise = new Promise((x, y) => {fulfill = x; reject = y});
    request(options).on('response', function(response) {
        fulfill(response);
    }).on('error', function(error) {
        reject(error);
    });
    return promise;
}

<commit_msg>support LATEXHOST env for running tests<commit_after>var assert = require('assert');
var fs = require('fs');
var path = require('path');
var request = require('request');

var baseUrl = 'http://localhost:2700';
if (process.env.LATEXHOST)
    baseUrl = process.env.LATEXHOST;

describe(baseUrl, function() {
    this.timeout(60000);
    this.slow(20000);
    describe('/compile', function() {
        describe('git', function() {
            it('https://github.com/aslushnikov/diplom-latex&target=diplom.tex', async function() {
                var url = baseUrl +  '/compile?git=git%3A%2F%2Fgithub.com%2Faslushnikov%2Fdiplom-latex.git&target=diplom.tex';
                var request = createGetRequest(url);
                await expectPdf(request);
            });
        });
        describe('xelatex command', function() {
            it('https://github.com/posquit0/Awesome-CV&target=examples/resume.tex&command=xelatex', async function() {
                var url = baseUrl +  '/compile?git=https%3A%2F%2Fgithub.com%2Fposquit0%2FAwesome-CV&target=examples%2Fresume.tex&command=xelatex';
                var request = createGetRequest(url);
                await expectPdf(request);
            });
        });
        describe('text', function() {
            it('goodText', async function() {
                var goodText = [
                    '\\documentclass{article}',
                    '\\begin{document}',
                    'Correct document.',
                    '\\end{document}'
                ].join('\n');
                var url = baseUrl + '/compile?text=' + encodeURIComponent(goodText);
                var request = createGetRequest(url);
                await expectPdf(request);
            });

            it('badText', async function() {
                var badText = [
                    '\\documentclass{article}',
                    '\\begin{document}',
                    'Does not compile!'
                ].join('\n');
                var url = baseUrl + '/compile?text=' + encodeURIComponent(badText);
                var request = createGetRequest(url);
                await expectError(request);
            });
        });
        describe('url', function() {
            it('goodURL', async function() {
                var goodURL = 'https://raw.githubusercontent.com/aslushnikov/latex-online/master/sample/sample.tex';
                var url = baseUrl + '/compile?url=' + encodeURIComponent(goodURL);
                var request = createGetRequest(url);
                await expectPdf(request);
            });
            it('badURL', async function() {
                var badURL = 'https://raw.githubusercontent.com/aslushnikov/latex-online/master/sample/bad.tex';
                var url = baseUrl + '/compile?url=' + encodeURIComponent(badURL);
                var request = createGetRequest(url);
                await expectError(request);
            });
        });
    });

    describe('/data', function() {
        it('cli-good', async function() {
            var filePath = path.join(__dirname, 'resources', 'good.tar.gz');
            var target = 'short.tex';
            var request = createUploadRequest(filePath, target);
            await expectPdf(request);
        });
        it('cli-bad', async function() {
            var filePath = path.join(__dirname, 'resources', 'bad.tar.gz');
            var target = 'short.tex';
            var request = createUploadRequest(filePath, target);
            await expectError(request);
        });
        it('cli-cache-busting', async function() {
            var filePath = path.join(__dirname, 'resources', 'good.tar.gz');
            var target = 'nonexistent.tex';
            var request = createUploadRequest(filePath, target);
            await expectError(request);
            target = 'short.tex';
            request = createUploadRequest(filePath, target);
            await expectPdf(request);
        });
    });

});
/**
 * @param {!Request} request
 */
async function expectPdf(request) {
    var response = await request
    assert.ok(response);
    assert.equal(response.statusCode, 200);
    assert.equal(response.headers['content-type'], 'application/pdf');
}

/**
 * @param {string} testName
 * @param {!Request} request
 */
async function expectError( request) {
    var response = await request;
    assert.ok(response);
    assert.equal(response.statusCode, 400);
    assert.equal(response.headers['content-type'], 'text/plain; charset=UTF-8');
}

/**
 * @param {string} url
 * @return {!Promise}
 */
function createGetRequest(url) {
    var options = {
        method: 'get',
        url: url,
        headers: {
            // Pretend to be bot: Avoid analytics-related redirects.
            'User-Agent': 'wget latex-oneline test sanity-test.js'
        }
    };
    return doRequest(options);
}

/**
 * @param {string} filePath
 * @param {string} target
 * @return {!Promise}
 */
function createUploadRequest(filePath, target) {
    var options = {
        method: 'post',
        url: baseUrl + '/data?target=' + encodeURIComponent(target),
        formData: {
            file: fs.createReadStream(filePath)
        }
    };
    return doRequest(options);
}

/**
 * @param {!Object} options
 * @return {!Promise}
 */
function doRequest(options) {
    var fulfill, reject;
    var promise = new Promise((x, y) => {fulfill = x; reject = y});
    request(options).on('response', function(response) {
        fulfill(response);
    }).on('error', function(error) {
        reject(error);
    });
    return promise;
}

<|endoftext|>


<commit_before>/**
 * invoke logic
 */

function invokeLogic(options){
  return (ctx, next) => {
    return next();
  }
}

module.exports = invokeLogic;<commit_msg>Add logic middleware<commit_after>const assert = require('assert');
const helper = require('think-helper');
/**
 * invoke logic
 */

function invokeLogic(options){
  return (ctx, next) => {
    if(think.isMultiModule){
      assert(ctx.module, 'module can not be blank in multi module');
    }
    assert(ctx.controller, 'controller can not be blank');
    assert(ctx.action, 'action can not be blank');

    const logics = think.data.logic;
    if(think.isMultiModule){
      logics = logics[ctx.module];
    }
    //logics empty
    if(helper.isEmpty(logics)){
      return next();
    }
    let logic = logics[ctx.controller];
    // logic not exist
    if(helper.isEmpty(logic)){
      return next();
    }
    const instance = new logic(ctx);
    let promise = Promise.resolve();
    if(instance.__before){
      promise = Promise.resolve(instance.__before());
    }
    // if return false, it will be prevent next process
    return promise.then(data => {
      if(data === false) return false;
      let method = `${ctx.action}Action`;
      if(!instance[method]){
        method = '__call';
      }
      if(instance[method]){
        return Promise.resolve(instance[method]())
      }
    }).then(data => {
      if(data === false) return false;
      if(instance.__after){
        return Promise.resolve(instance.__after());
      }
    }).then(data => {
      if(data !== false){
        return next();
      }
    });
  }
}

module.exports = invokeLogic;<|endoftext|>