define(["jupyter-js-widgets"], function(__WEBPACK_EXTERNAL_MODULE_2__) { return /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;
/******/
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			exports: {},
/******/ 			id: moduleId,
/******/ 			loaded: false
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

	// Entry point for the notebook bundle containing custom model definitions.
	//
	// Setup notebook base URL
	//
	// Some static assets may be required by the custom widget javascript. The base
	// url for the notebook is not known at build time and is therefore computed
	// dynamically.
	__webpack_require__.p = document.querySelector('body').getAttribute('data-base-url') + 'nbextensions/clustergrammer_gl/';
	
	// Export widget models and views, and the npm package version number.
	module.exports = __webpack_require__(1);
	module.exports['version'] = __webpack_require__(18).version;


/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {

	var widgets = __webpack_require__(2);
	var _ = __webpack_require__(3);
	var d3 = __webpack_require__(4)
	var cgm_fun = __webpack_require__(5);
	var cgm_fun2 = __webpack_require__(6);
	var ini_hzome = __webpack_require__(11);
	var Enrichrgram = __webpack_require__(12);
	var url = __webpack_require__(13);
	
	// version 0.1.1
	console.log('**************************')
	console.log('clustergrammer_gl!!!!!!!!!!!!!!!!!!!!!!')
	console.log('**************************')
	
	__webpack_require__(14);
	
	// Custom Model. Custom widgets models must at least provide default values
	// for model attributes, including `_model_name`, `_view_name`, `_model_module`
	// and `_view_module` when different from the base class.
	//
	// When serialiazing entire widget state for embedding, only values different from the
	// defaults will be specified.
	var hello_model = widgets.DOMWidgetModel.extend({
	  defaults: _.extend({}, widgets.DOMWidgetModel.prototype.defaults, {
	    _view_name : 'hello_view',
	    _model_name : 'hello_model',
	    _view_module : 'clustergrammer_gl',
	    _model_module : 'clustergrammer_gl',
	    viz_title : 'default value',
	    network: ''
	  })
	});
	
	
	// Custom View. Renders the widget model.
	var hello_view = widgets.DOMWidgetView.extend({
	
	  render: render_function,
	
	  value_changed: function() {
	
	    // this.el.textContent = this.model.get('viz_title');
	    // var inst_network_string = this.model.get('network');
	    // inst_network = JSON.parse(inst_network_string);
	    // d3.select(this.el)
	    //   .classed('.widget_viz',true);
	
	  }
	});
	
	function render_function() {
	
	  // generate unique id for each visualization
	  var viz_number = String(Math.round(Math.random()*10000));
	  var container_name = 'cgm_notebook_' + String(viz_number) ;
	  if (d3.select('#'+container_name).empty() === false){
	    var backup_number = String(Math.round(Math.random()*10000));
	    container_name = container_name + backup_number;
	  }
	
	  // widget-subarea appears to be limited to a width of ~960px in nbviewer
	  d3.select(this.el)
	      .append('div')
	      .classed('clustergrammer_gl', true)
	      .attr('id', container_name)
	      .style('width', '975px')
	      .style('height', '800px');
	
	  var inst_network_string = this.model.get('network');
	
	  inst_network = JSON.parse(inst_network_string);
	
	  var about_string = "<a href='http://clustergrammer.readthedocs.io/clustergrammer_gl.html' target='_blank' ><img src='http://amp.pharm.mssm.edu/clustergrammer/static/img/clustergrammer_logo.png' style='width:130px; margin-left:-5px' alt='clustergrammer'></a>";
	
	  var hzome = ini_hzome();
	
	  // cgm_model needs to be global
	  cgm_model = this;
	
	  var container_id = '#'+container_name;
	
	  var inst_container = document.getElementById(container_name)
	
	  console.log('container_name', container_name)
	  console.log('inst_container', inst_container)
	
	  // define arguments object
	  var args = {
	      // root: container_id,
	      'container_name': container_name,
	      // 'container': inst_container,
	      'network': inst_network,
	      'about':about_string,
	      'row_tip_callback':hzome.gene_info,
	      'matrix_update_callback':matrix_update_callback,
	      'cat_update_callback': cat_update_callback,
	      'sidebar_width':135,
	  };
	
	  setTimeout(make_viz, 10, args);
	
	}
	
	function make_viz(args){
	
	  /*
	  selecting the container here, but not earlier, works. not sure why
	  */
	
	  var inst_container_2 = document.getElementById(args.container_name)
	
	  console.log('inst_container_2', inst_container_2)
	
	  args.container = inst_container_2;
	  // debugger
	
	  // cgm = cgm_fun(args);
	  cgm = cgm_fun2(args);
	
	  // check_setup_enrichr(cgm);
	
	  // console.log('DO NOT UPDATE MATRIX STRING WHEN MAKING VIZ -- clustergrammer_gl')
	
	}
	
	// hack to prevent matrix update string from running in nbviewer
	var inst_url = window.location.href;
	var in_nbviewer = false;
	if (inst_url.indexOf('nbviewer.jupyter.org') > 0){
	  in_nbviewer = true;
	}
	
	// Enrichrgram specific functions
	///////////////////////////////////////////////////////////////
	
	function matrix_update_callback(){
	
	  console.log('matrix_update_callback')
	
	  if (in_nbviewer === false){
	    // wait to update matrix string until updating has finished
	    setTimeout(update_matrix_string, 1500);
	  }
	
	  if (genes_were_found[this.root]){
	    enr_obj[this.root].clear_enrichr_results();
	  }
	
	}
	
	function cat_update_callback(){
	  if (in_nbviewer === false){
	    setTimeout(update_matrix_string, 1500);
	  }
	}
	
	function update_matrix_string(){
	  console.log('*** update matrix string')
	  // update model with matrix string
	  var inst_mat_string = cgm.export_matrix_string();
	  cgm_model.model.set("mat_string", inst_mat_string);
	  cgm_model.touch();
	}
	
	
	var genes_were_found = {};
	enr_obj = {};
	
	
	
	function run_ini_enrichr(inst_cgm){
	
	  var inst_root = inst_cgm.params.root;
	
	  var has_enrichrgram = _.has(inst_cgm.params.network_data, 'enrichrgram');
	
	  var make_enrichrgram = false;
	  if (has_enrichrgram){
	    make_enrichrgram = inst_cgm.params.network_data.enrichrgram;
	  }
	
	  if (genes_were_found[inst_root] || make_enrichrgram){
	
	    if (d3.select(inst_root + ' .enrichr_logo').empty()){
	
	      // set up Enrichr category import
	      enr_obj[inst_root] = Enrichrgram(inst_cgm);
	      enr_obj[inst_root].enrichr_icon();
	
	      // set up Enrichr export in dendro modal
	      //////////////////////////////////////////
	
	      // only display for rows
	      var enrichr_section = d3.selectAll(inst_root + ' .dendro_info')
	        .select('.modal-body')
	        .append('div')
	        .classed('enrichr_export_section', true)
	        .style('margin-top', '10px')
	        // .style('display','none');
	
	      enrichr_section
	        .append('text')
	        .text('Send genes to ');
	
	      enrichr_section
	        .append('a')
	        .html('Enrichr')
	        .on('click', function(){
	
	          var group_string = d3.select(inst_root + ' .dendro_text input').attr('value');
	
	          // replace all instances of commas with new line
	          var gene_list = group_string.replace(/, /g, '\n');
	
	          ///////////////
	          // clean list
	          ///////////////
	          var enrichr_info = {list: gene_list, description: 'Clustergrammer gene-cluster list' , popup: true};
	
	          // defined globally - will improve
	          send_to_Enrichr(enrichr_info);
	
	        });
	
	    }
	
	  }
	
	}
	
	function check_gene_request(inst_cgm, gene_symbol, run_ini_enrichr){
	
	  if (gene_symbol.indexOf(' ') > 0){
	    gene_symbol = gene_symbol.split(' ')[0];
	  } else if (gene_symbol.indexOf('_') > 0){
	    gene_symbol = gene_symbol.split('_')[0];
	  }
	
	
	  var base_url = 'https://amp.pharm.mssm.edu/Harmonizome/api/1.0/gene/';
	  var url = base_url + gene_symbol;
	
	  if (genes_were_found[inst_cgm.params.root] === false){
	
	    // make sure value is non-numeric
	    if (isNaN(gene_symbol)){
	
	      $.get(url, function(data) {
	
	        data = JSON.parse(data);
	
	        if (data.name != undefined){
	          genes_were_found[inst_cgm.params.root] = true;
	        }
	
	        run_ini_enrichr(inst_cgm, gene_symbol);
	
	      });
	
	    }
	  }
	
	}
	
	function send_to_Enrichr(options) { // http://amp.pharm.mssm.edu/Enrichr/#help
	    var defaultOptions = {
	    description: "",
	    popup: false
	  };
	
	  if (typeof options.description == 'undefined')
	    options.description = defaultOptions.description;
	  if (typeof options.popup == 'undefined')
	    options.popup = defaultOptions.popup;
	  if (typeof options.list == 'undefined')
	    alert('No genes defined.');
	
	  var form = document.createElement('form');
	  form.setAttribute('method', 'post');
	  form.setAttribute('action', 'https://amp.pharm.mssm.edu/Enrichr/enrich');
	  if (options.popup)
	    form.setAttribute('target', '_blank');
	  form.setAttribute('enctype', 'multipart/form-data');
	
	  var listField = document.createElement('input');
	  listField.setAttribute('type', 'hidden');
	  listField.setAttribute('name', 'list');
	  listField.setAttribute('value', options.list);
	  form.appendChild(listField);
	
	  var descField = document.createElement('input');
	  descField.setAttribute('type', 'hidden');
	  descField.setAttribute('name', 'description');
	  descField.setAttribute('value', options.description);
	  form.appendChild(descField);
	
	  document.body.appendChild(form);
	  form.submit();
	  document.body.removeChild(form);
	}
	
	function abort_request(inst_request){
	  console.log('ABORTING REQUEST');
	  inst_request.abort();
	}
	
	module.exports = {
	  hello_model : hello_model,
	  hello_view : hello_view
	};


/***/ }),
/* 2 */
/***/ (function(module, exports) {

	module.exports = __WEBPACK_EXTERNAL_MODULE_2__;

/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {

	var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;//     Underscore.js 1.8.3
	//     http://underscorejs.org
	//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
	//     Underscore may be freely distributed under the MIT license.
	
	(function() {
	
	  // Baseline setup
	  // --------------
	
	  // Establish the root object, `window` in the browser, or `exports` on the server.
	  var root = this;
	
	  // Save the previous value of the `_` variable.
	  var previousUnderscore = root._;
	
	  // Save bytes in the minified (but not gzipped) version:
	  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
	
	  // Create quick reference variables for speed access to core prototypes.
	  var
	    push             = ArrayProto.push,
	    slice            = ArrayProto.slice,
	    toString         = ObjProto.toString,
	    hasOwnProperty   = ObjProto.hasOwnProperty;
	
	  // All **ECMAScript 5** native function implementations that we hope to use
	  // are declared here.
	  var
	    nativeIsArray      = Array.isArray,
	    nativeKeys         = Object.keys,
	    nativeBind         = FuncProto.bind,
	    nativeCreate       = Object.create;
	
	  // Naked function reference for surrogate-prototype-swapping.
	  var Ctor = function(){};
	
	  // Create a safe reference to the Underscore object for use below.
	  var _ = function(obj) {
	    if (obj instanceof _) return obj;
	    if (!(this instanceof _)) return new _(obj);
	    this._wrapped = obj;
	  };
	
	  // Export the Underscore object for **Node.js**, with
	  // backwards-compatibility for the old `require()` API. If we're in
	  // the browser, add `_` as a global object.
	  if (true) {
	    if (typeof module !== 'undefined' && module.exports) {
	      exports = module.exports = _;
	    }
	    exports._ = _;
	  } else {
	    root._ = _;
	  }
	
	  // Current version.
	  _.VERSION = '1.8.3';
	
	  // Internal function that returns an efficient (for current engines) version
	  // of the passed-in callback, to be repeatedly applied in other Underscore
	  // functions.
	  var optimizeCb = function(func, context, argCount) {
	    if (context === void 0) return func;
	    switch (argCount == null ? 3 : argCount) {
	      case 1: return function(value) {
	        return func.call(context, value);
	      };
	      case 2: return function(value, other) {
	        return func.call(context, value, other);
	      };
	      case 3: return function(value, index, collection) {
	        return func.call(context, value, index, collection);
	      };
	      case 4: return function(accumulator, value, index, collection) {
	        return func.call(context, accumulator, value, index, collection);
	      };
	    }
	    return function() {
	      return func.apply(context, arguments);
	    };
	  };
	
	  // A mostly-internal function to generate callbacks that can be applied
	  // to each element in a collection, returning the desired result — either
	  // identity, an arbitrary callback, a property matcher, or a property accessor.
	  var cb = function(value, context, argCount) {
	    if (value == null) return _.identity;
	    if (_.isFunction(value)) return optimizeCb(value, context, argCount);
	    if (_.isObject(value)) return _.matcher(value);
	    return _.property(value);
	  };
	  _.iteratee = function(value, context) {
	    return cb(value, context, Infinity);
	  };
	
	  // An internal function for creating assigner functions.
	  var createAssigner = function(keysFunc, undefinedOnly) {
	    return function(obj) {
	      var length = arguments.length;
	      if (length < 2 || obj == null) return obj;
	      for (var index = 1; index < length; index++) {
	        var source = arguments[index],
	            keys = keysFunc(source),
	            l = keys.length;
	        for (var i = 0; i < l; i++) {
	          var key = keys[i];
	          if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
	        }
	      }
	      return obj;
	    };
	  };
	
	  // An internal function for creating a new object that inherits from another.
	  var baseCreate = function(prototype) {
	    if (!_.isObject(prototype)) return {};
	    if (nativeCreate) return nativeCreate(prototype);
	    Ctor.prototype = prototype;
	    var result = new Ctor;
	    Ctor.prototype = null;
	    return result;
	  };
	
	  var property = function(key) {
	    return function(obj) {
	      return obj == null ? void 0 : obj[key];
	    };
	  };
	
	  // Helper for collection methods to determine whether a collection
	  // should be iterated as an array or as an object
	  // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
	  // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
	  var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
	  var getLength = property('length');
	  var isArrayLike = function(collection) {
	    var length = getLength(collection);
	    return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
	  };
	
	  // Collection Functions
	  // --------------------
	
	  // The cornerstone, an `each` implementation, aka `forEach`.
	  // Handles raw objects in addition to array-likes. Treats all
	  // sparse array-likes as if they were dense.
	  _.each = _.forEach = function(obj, iteratee, context) {
	    iteratee = optimizeCb(iteratee, context);
	    var i, length;
	    if (isArrayLike(obj)) {
	      for (i = 0, length = obj.length; i < length; i++) {
	        iteratee(obj[i], i, obj);
	      }
	    } else {
	      var keys = _.keys(obj);
	      for (i = 0, length = keys.length; i < length; i++) {
	        iteratee(obj[keys[i]], keys[i], obj);
	      }
	    }
	    return obj;
	  };
	
	  // Return the results of applying the iteratee to each element.
	  _.map = _.collect = function(obj, iteratee, context) {
	    iteratee = cb(iteratee, context);
	    var keys = !isArrayLike(obj) && _.keys(obj),
	        length = (keys || obj).length,
	        results = Array(length);
	    for (var index = 0; index < length; index++) {
	      var currentKey = keys ? keys[index] : index;
	      results[index] = iteratee(obj[currentKey], currentKey, obj);
	    }
	    return results;
	  };
	
	  // Create a reducing function iterating left or right.
	  function createReduce(dir) {
	    // Optimized iterator function as using arguments.length
	    // in the main function will deoptimize the, see #1991.
	    function iterator(obj, iteratee, memo, keys, index, length) {
	      for (; index >= 0 && index < length; index += dir) {
	        var currentKey = keys ? keys[index] : index;
	        memo = iteratee(memo, obj[currentKey], currentKey, obj);
	      }
	      return memo;
	    }
	
	    return function(obj, iteratee, memo, context) {
	      iteratee = optimizeCb(iteratee, context, 4);
	      var keys = !isArrayLike(obj) && _.keys(obj),
	          length = (keys || obj).length,
	          index = dir > 0 ? 0 : length - 1;
	      // Determine the initial value if none is provided.
	      if (arguments.length < 3) {
	        memo = obj[keys ? keys[index] : index];
	        index += dir;
	      }
	      return iterator(obj, iteratee, memo, keys, index, length);
	    };
	  }
	
	  // **Reduce** builds up a single result from a list of values, aka `inject`,
	  // or `foldl`.
	  _.reduce = _.foldl = _.inject = createReduce(1);
	
	  // The right-associative version of reduce, also known as `foldr`.
	  _.reduceRight = _.foldr = createReduce(-1);
	
	  // Return the first value which passes a truth test. Aliased as `detect`.
	  _.find = _.detect = function(obj, predicate, context) {
	    var key;
	    if (isArrayLike(obj)) {
	      key = _.findIndex(obj, predicate, context);
	    } else {
	      key = _.findKey(obj, predicate, context);
	    }
	    if (key !== void 0 && key !== -1) return obj[key];
	  };
	
	  // Return all the elements that pass a truth test.
	  // Aliased as `select`.
	  _.filter = _.select = function(obj, predicate, context) {
	    var results = [];
	    predicate = cb(predicate, context);
	    _.each(obj, function(value, index, list) {
	      if (predicate(value, index, list)) results.push(value);
	    });
	    return results;
	  };
	
	  // Return all the elements for which a truth test fails.
	  _.reject = function(obj, predicate, context) {
	    return _.filter(obj, _.negate(cb(predicate)), context);
	  };
	
	  // Determine whether all of the elements match a truth test.
	  // Aliased as `all`.
	  _.every = _.all = function(obj, predicate, context) {
	    predicate = cb(predicate, context);
	    var keys = !isArrayLike(obj) && _.keys(obj),
	        length = (keys || obj).length;
	    for (var index = 0; index < length; index++) {
	      var currentKey = keys ? keys[index] : index;
	      if (!predicate(obj[currentKey], currentKey, obj)) return false;
	    }
	    return true;
	  };
	
	  // Determine if at least one element in the object matches a truth test.
	  // Aliased as `any`.
	  _.some = _.any = function(obj, predicate, context) {
	    predicate = cb(predicate, context);
	    var keys = !isArrayLike(obj) && _.keys(obj),
	        length = (keys || obj).length;
	    for (var index = 0; index < length; index++) {
	      var currentKey = keys ? keys[index] : index;
	      if (predicate(obj[currentKey], currentKey, obj)) return true;
	    }
	    return false;
	  };
	
	  // Determine if the array or object contains a given item (using `===`).
	  // Aliased as `includes` and `include`.
	  _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
	    if (!isArrayLike(obj)) obj = _.values(obj);
	    if (typeof fromIndex != 'number' || guard) fromIndex = 0;
	    return _.indexOf(obj, item, fromIndex) >= 0;
	  };
	
	  // Invoke a method (with arguments) on every item in a collection.
	  _.invoke = function(obj, method) {
	    var args = slice.call(arguments, 2);
	    var isFunc = _.isFunction(method);
	    return _.map(obj, function(value) {
	      var func = isFunc ? method : value[method];
	      return func == null ? func : func.apply(value, args);
	    });
	  };
	
	  // Convenience version of a common use case of `map`: fetching a property.
	  _.pluck = function(obj, key) {
	    return _.map(obj, _.property(key));
	  };
	
	  // Convenience version of a common use case of `filter`: selecting only objects
	  // containing specific `key:value` pairs.
	  _.where = function(obj, attrs) {
	    return _.filter(obj, _.matcher(attrs));
	  };
	
	  // Convenience version of a common use case of `find`: getting the first object
	  // containing specific `key:value` pairs.
	  _.findWhere = function(obj, attrs) {
	    return _.find(obj, _.matcher(attrs));
	  };
	
	  // Return the maximum element (or element-based computation).
	  _.max = function(obj, iteratee, context) {
	    var result = -Infinity, lastComputed = -Infinity,
	        value, computed;
	    if (iteratee == null && obj != null) {
	      obj = isArrayLike(obj) ? obj : _.values(obj);
	      for (var i = 0, length = obj.length; i < length; i++) {
	        value = obj[i];
	        if (value > result) {
	          result = value;
	        }
	      }
	    } else {
	      iteratee = cb(iteratee, context);
	      _.each(obj, function(value, index, list) {
	        computed = iteratee(value, index, list);
	        if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
	          result = value;
	          lastComputed = computed;
	        }
	      });
	    }
	    return result;
	  };
	
	  // Return the minimum element (or element-based computation).
	  _.min = function(obj, iteratee, context) {
	    var result = Infinity, lastComputed = Infinity,
	        value, computed;
	    if (iteratee == null && obj != null) {
	      obj = isArrayLike(obj) ? obj : _.values(obj);
	      for (var i = 0, length = obj.length; i < length; i++) {
	        value = obj[i];
	        if (value < result) {
	          result = value;
	        }
	      }
	    } else {
	      iteratee = cb(iteratee, context);
	      _.each(obj, function(value, index, list) {
	        computed = iteratee(value, index, list);
	        if (computed < lastComputed || computed === Infinity && result === Infinity) {
	          result = value;
	          lastComputed = computed;
	        }
	      });
	    }
	    return result;
	  };
	
	  // Shuffle a collection, using the modern version of the
	  // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
	  _.shuffle = function(obj) {
	    var set = isArrayLike(obj) ? obj : _.values(obj);
	    var length = set.length;
	    var shuffled = Array(length);
	    for (var index = 0, rand; index < length; index++) {
	      rand = _.random(0, index);
	      if (rand !== index) shuffled[index] = shuffled[rand];
	      shuffled[rand] = set[index];
	    }
	    return shuffled;
	  };
	
	  // Sample **n** random values from a collection.
	  // If **n** is not specified, returns a single random element.
	  // The internal `guard` argument allows it to work with `map`.
	  _.sample = function(obj, n, guard) {
	    if (n == null || guard) {
	      if (!isArrayLike(obj)) obj = _.values(obj);
	      return obj[_.random(obj.length - 1)];
	    }
	    return _.shuffle(obj).slice(0, Math.max(0, n));
	  };
	
	  // Sort the object's values by a criterion produced by an iteratee.
	  _.sortBy = function(obj, iteratee, context) {
	    iteratee = cb(iteratee, context);
	    return _.pluck(_.map(obj, function(value, index, list) {
	      return {
	        value: value,
	        index: index,
	        criteria: iteratee(value, index, list)
	      };
	    }).sort(function(left, right) {
	      var a = left.criteria;
	      var b = right.criteria;
	      if (a !== b) {
	        if (a > b || a === void 0) return 1;
	        if (a < b || b === void 0) return -1;
	      }
	      return left.index - right.index;
	    }), 'value');
	  };
	
	  // An internal function used for aggregate "group by" operations.
	  var group = function(behavior) {
	    return function(obj, iteratee, context) {
	      var result = {};
	      iteratee = cb(iteratee, context);
	      _.each(obj, function(value, index) {
	        var key = iteratee(value, index, obj);
	        behavior(result, value, key);
	      });
	      return result;
	    };
	  };
	
	  // Groups the object's values by a criterion. Pass either a string attribute
	  // to group by, or a function that returns the criterion.
	  _.groupBy = group(function(result, value, key) {
	    if (_.has(result, key)) result[key].push(value); else result[key] = [value];
	  });
	
	  // Indexes the object's values by a criterion, similar to `groupBy`, but for
	  // when you know that your index values will be unique.
	  _.indexBy = group(function(result, value, key) {
	    result[key] = value;
	  });
	
	  // Counts instances of an object that group by a certain criterion. Pass
	  // either a string attribute to count by, or a function that returns the
	  // criterion.
	  _.countBy = group(function(result, value, key) {
	    if (_.has(result, key)) result[key]++; else result[key] = 1;
	  });
	
	  // Safely create a real, live array from anything iterable.
	  _.toArray = function(obj) {
	    if (!obj) return [];
	    if (_.isArray(obj)) return slice.call(obj);
	    if (isArrayLike(obj)) return _.map(obj, _.identity);
	    return _.values(obj);
	  };
	
	  // Return the number of elements in an object.
	  _.size = function(obj) {
	    if (obj == null) return 0;
	    return isArrayLike(obj) ? obj.length : _.keys(obj).length;
	  };
	
	  // Split a collection into two arrays: one whose elements all satisfy the given
	  // predicate, and one whose elements all do not satisfy the predicate.
	  _.partition = function(obj, predicate, context) {
	    predicate = cb(predicate, context);
	    var pass = [], fail = [];
	    _.each(obj, function(value, key, obj) {
	      (predicate(value, key, obj) ? pass : fail).push(value);
	    });
	    return [pass, fail];
	  };
	
	  // Array Functions
	  // ---------------
	
	  // Get the first element of an array. Passing **n** will return the first N
	  // values in the array. Aliased as `head` and `take`. The **guard** check
	  // allows it to work with `_.map`.
	  _.first = _.head = _.take = function(array, n, guard) {
	    if (array == null) return void 0;
	    if (n == null || guard) return array[0];
	    return _.initial(array, array.length - n);
	  };
	
	  // Returns everything but the last entry of the array. Especially useful on
	  // the arguments object. Passing **n** will return all the values in
	  // the array, excluding the last N.
	  _.initial = function(array, n, guard) {
	    return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
	  };
	
	  // Get the last element of an array. Passing **n** will return the last N
	  // values in the array.
	  _.last = function(array, n, guard) {
	    if (array == null) return void 0;
	    if (n == null || guard) return array[array.length - 1];
	    return _.rest(array, Math.max(0, array.length - n));
	  };
	
	  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
	  // Especially useful on the arguments object. Passing an **n** will return
	  // the rest N values in the array.
	  _.rest = _.tail = _.drop = function(array, n, guard) {
	    return slice.call(array, n == null || guard ? 1 : n);
	  };
	
	  // Trim out all falsy values from an array.
	  _.compact = function(array) {
	    return _.filter(array, _.identity);
	  };
	
	  // Internal implementation of a recursive `flatten` function.
	  var flatten = function(input, shallow, strict, startIndex) {
	    var output = [], idx = 0;
	    for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
	      var value = input[i];
	      if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
	        //flatten current level of array or arguments object
	        if (!shallow) value = flatten(value, shallow, strict);
	        var j = 0, len = value.length;
	        output.length += len;
	        while (j < len) {
	          output[idx++] = value[j++];
	        }
	      } else if (!strict) {
	        output[idx++] = value;
	      }
	    }
	    return output;
	  };
	
	  // Flatten out an array, either recursively (by default), or just one level.
	  _.flatten = function(array, shallow) {
	    return flatten(array, shallow, false);
	  };
	
	  // Return a version of the array that does not contain the specified value(s).
	  _.without = function(array) {
	    return _.difference(array, slice.call(arguments, 1));
	  };
	
	  // Produce a duplicate-free version of the array. If the array has already
	  // been sorted, you have the option of using a faster algorithm.
	  // Aliased as `unique`.
	  _.uniq = _.unique = function(array, isSorted, iteratee, context) {
	    if (!_.isBoolean(isSorted)) {
	      context = iteratee;
	      iteratee = isSorted;
	      isSorted = false;
	    }
	    if (iteratee != null) iteratee = cb(iteratee, context);
	    var result = [];
	    var seen = [];
	    for (var i = 0, length = getLength(array); i < length; i++) {
	      var value = array[i],
	          computed = iteratee ? iteratee(value, i, array) : value;
	      if (isSorted) {
	        if (!i || seen !== computed) result.push(value);
	        seen = computed;
	      } else if (iteratee) {
	        if (!_.contains(seen, computed)) {
	          seen.push(computed);
	          result.push(value);
	        }
	      } else if (!_.contains(result, value)) {
	        result.push(value);
	      }
	    }
	    return result;
	  };
	
	  // Produce an array that contains the union: each distinct element from all of
	  // the passed-in arrays.
	  _.union = function() {
	    return _.uniq(flatten(arguments, true, true));
	  };
	
	  // Produce an array that contains every item shared between all the
	  // passed-in arrays.
	  _.intersection = function(array) {
	    var result = [];
	    var argsLength = arguments.length;
	    for (var i = 0, length = getLength(array); i < length; i++) {
	      var item = array[i];
	      if (_.contains(result, item)) continue;
	      for (var j = 1; j < argsLength; j++) {
	        if (!_.contains(arguments[j], item)) break;
	      }
	      if (j === argsLength) result.push(item);
	    }
	    return result;
	  };
	
	  // Take the difference between one array and a number of other arrays.
	  // Only the elements present in just the first array will remain.
	  _.difference = function(array) {
	    var rest = flatten(arguments, true, true, 1);
	    return _.filter(array, function(value){
	      return !_.contains(rest, value);
	    });
	  };
	
	  // Zip together multiple lists into a single array -- elements that share
	  // an index go together.
	  _.zip = function() {
	    return _.unzip(arguments);
	  };
	
	  // Complement of _.zip. Unzip accepts an array of arrays and groups
	  // each array's elements on shared indices
	  _.unzip = function(array) {
	    var length = array && _.max(array, getLength).length || 0;
	    var result = Array(length);
	
	    for (var index = 0; index < length; index++) {
	      result[index] = _.pluck(array, index);
	    }
	    return result;
	  };
	
	  // Converts lists into objects. Pass either a single array of `[key, value]`
	  // pairs, or two parallel arrays of the same length -- one of keys, and one of
	  // the corresponding values.
	  _.object = function(list, values) {
	    var result = {};
	    for (var i = 0, length = getLength(list); i < length; i++) {
	      if (values) {
	        result[list[i]] = values[i];
	      } else {
	        result[list[i][0]] = list[i][1];
	      }
	    }
	    return result;
	  };
	
	  // Generator function to create the findIndex and findLastIndex functions
	  function createPredicateIndexFinder(dir) {
	    return function(array, predicate, context) {
	      predicate = cb(predicate, context);
	      var length = getLength(array);
	      var index = dir > 0 ? 0 : length - 1;
	      for (; index >= 0 && index < length; index += dir) {
	        if (predicate(array[index], index, array)) return index;
	      }
	      return -1;
	    };
	  }
	
	  // Returns the first index on an array-like that passes a predicate test
	  _.findIndex = createPredicateIndexFinder(1);
	  _.findLastIndex = createPredicateIndexFinder(-1);
	
	  // Use a comparator function to figure out the smallest index at which
	  // an object should be inserted so as to maintain order. Uses binary search.
	  _.sortedIndex = function(array, obj, iteratee, context) {
	    iteratee = cb(iteratee, context, 1);
	    var value = iteratee(obj);
	    var low = 0, high = getLength(array);
	    while (low < high) {
	      var mid = Math.floor((low + high) / 2);
	      if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
	    }
	    return low;
	  };
	
	  // Generator function to create the indexOf and lastIndexOf functions
	  function createIndexFinder(dir, predicateFind, sortedIndex) {
	    return function(array, item, idx) {
	      var i = 0, length = getLength(array);
	      if (typeof idx == 'number') {
	        if (dir > 0) {
	            i = idx >= 0 ? idx : Math.max(idx + length, i);
	        } else {
	            length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
	        }
	      } else if (sortedIndex && idx && length) {
	        idx = sortedIndex(array, item);
	        return array[idx] === item ? idx : -1;
	      }
	      if (item !== item) {
	        idx = predicateFind(slice.call(array, i, length), _.isNaN);
	        return idx >= 0 ? idx + i : -1;
	      }
	      for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
	        if (array[idx] === item) return idx;
	      }
	      return -1;
	    };
	  }
	
	  // Return the position of the first occurrence of an item in an array,
	  // or -1 if the item is not included in the array.
	  // If the array is large and already in sort order, pass `true`
	  // for **isSorted** to use binary search.
	  _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
	  _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
	
	  // Generate an integer Array containing an arithmetic progression. A port of
	  // the native Python `range()` function. See
	  // [the Python documentation](http://docs.python.org/library/functions.html#range).
	  _.range = function(start, stop, step) {
	    if (stop == null) {
	      stop = start || 0;
	      start = 0;
	    }
	    step = step || 1;
	
	    var length = Math.max(Math.ceil((stop - start) / step), 0);
	    var range = Array(length);
	
	    for (var idx = 0; idx < length; idx++, start += step) {
	      range[idx] = start;
	    }
	
	    return range;
	  };
	
	  // Function (ahem) Functions
	  // ------------------
	
	  // Determines whether to execute a function as a constructor
	  // or a normal function with the provided arguments
	  var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
	    if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
	    var self = baseCreate(sourceFunc.prototype);
	    var result = sourceFunc.apply(self, args);
	    if (_.isObject(result)) return result;
	    return self;
	  };
	
	  // Create a function bound to a given object (assigning `this`, and arguments,
	  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
	  // available.
	  _.bind = function(func, context) {
	    if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
	    if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
	    var args = slice.call(arguments, 2);
	    var bound = function() {
	      return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
	    };
	    return bound;
	  };
	
	  // Partially apply a function by creating a version that has had some of its
	  // arguments pre-filled, without changing its dynamic `this` context. _ acts
	  // as a placeholder, allowing any combination of arguments to be pre-filled.
	  _.partial = function(func) {
	    var boundArgs = slice.call(arguments, 1);
	    var bound = function() {
	      var position = 0, length = boundArgs.length;
	      var args = Array(length);
	      for (var i = 0; i < length; i++) {
	        args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
	      }
	      while (position < arguments.length) args.push(arguments[position++]);
	      return executeBound(func, bound, this, this, args);
	    };
	    return bound;
	  };
	
	  // Bind a number of an object's methods to that object. Remaining arguments
	  // are the method names to be bound. Useful for ensuring that all callbacks
	  // defined on an object belong to it.
	  _.bindAll = function(obj) {
	    var i, length = arguments.length, key;
	    if (length <= 1) throw new Error('bindAll must be passed function names');
	    for (i = 1; i < length; i++) {
	      key = arguments[i];
	      obj[key] = _.bind(obj[key], obj);
	    }
	    return obj;
	  };
	
	  // Memoize an expensive function by storing its results.
	  _.memoize = function(func, hasher) {
	    var memoize = function(key) {
	      var cache = memoize.cache;
	      var address = '' + (hasher ? hasher.apply(this, arguments) : key);
	      if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
	      return cache[address];
	    };
	    memoize.cache = {};
	    return memoize;
	  };
	
	  // Delays a function for the given number of milliseconds, and then calls
	  // it with the arguments supplied.
	  _.delay = function(func, wait) {
	    var args = slice.call(arguments, 2);
	    return setTimeout(function(){
	      return func.apply(null, args);
	    }, wait);
	  };
	
	  // Defers a function, scheduling it to run after the current call stack has
	  // cleared.
	  _.defer = _.partial(_.delay, _, 1);
	
	  // Returns a function, that, when invoked, will only be triggered at most once
	  // during a given window of time. Normally, the throttled function will run
	  // as much as it can, without ever going more than once per `wait` duration;
	  // but if you'd like to disable the execution on the leading edge, pass
	  // `{leading: false}`. To disable execution on the trailing edge, ditto.
	  _.throttle = function(func, wait, options) {
	    var context, args, result;
	    var timeout = null;
	    var previous = 0;
	    if (!options) options = {};
	    var later = function() {
	      previous = options.leading === false ? 0 : _.now();
	      timeout = null;
	      result = func.apply(context, args);
	      if (!timeout) context = args = null;
	    };
	    return function() {
	      var now = _.now();
	      if (!previous && options.leading === false) previous = now;
	      var remaining = wait - (now - previous);
	      context = this;
	      args = arguments;
	      if (remaining <= 0 || remaining > wait) {
	        if (timeout) {
	          clearTimeout(timeout);
	          timeout = null;
	        }
	        previous = now;
	        result = func.apply(context, args);
	        if (!timeout) context = args = null;
	      } else if (!timeout && options.trailing !== false) {
	        timeout = setTimeout(later, remaining);
	      }
	      return result;
	    };
	  };
	
	  // Returns a function, that, as long as it continues to be invoked, will not
	  // be triggered. The function will be called after it stops being called for
	  // N milliseconds. If `immediate` is passed, trigger the function on the
	  // leading edge, instead of the trailing.
	  _.debounce = function(func, wait, immediate) {
	    var timeout, args, context, timestamp, result;
	
	    var later = function() {
	      var last = _.now() - timestamp;
	
	      if (last < wait && last >= 0) {
	        timeout = setTimeout(later, wait - last);
	      } else {
	        timeout = null;
	        if (!immediate) {
	          result = func.apply(context, args);
	          if (!timeout) context = args = null;
	        }
	      }
	    };
	
	    return function() {
	      context = this;
	      args = arguments;
	      timestamp = _.now();
	      var callNow = immediate && !timeout;
	      if (!timeout) timeout = setTimeout(later, wait);
	      if (callNow) {
	        result = func.apply(context, args);
	        context = args = null;
	      }
	
	      return result;
	    };
	  };
	
	  // Returns the first function passed as an argument to the second,
	  // allowing you to adjust arguments, run code before and after, and
	  // conditionally execute the original function.
	  _.wrap = function(func, wrapper) {
	    return _.partial(wrapper, func);
	  };
	
	  // Returns a negated version of the passed-in predicate.
	  _.negate = function(predicate) {
	    return function() {
	      return !predicate.apply(this, arguments);
	    };
	  };
	
	  // Returns a function that is the composition of a list of functions, each
	  // consuming the return value of the function that follows.
	  _.compose = function() {
	    var args = arguments;
	    var start = args.length - 1;
	    return function() {
	      var i = start;
	      var result = args[start].apply(this, arguments);
	      while (i--) result = args[i].call(this, result);
	      return result;
	    };
	  };
	
	  // Returns a function that will only be executed on and after the Nth call.
	  _.after = function(times, func) {
	    return function() {
	      if (--times < 1) {
	        return func.apply(this, arguments);
	      }
	    };
	  };
	
	  // Returns a function that will only be executed up to (but not including) the Nth call.
	  _.before = function(times, func) {
	    var memo;
	    return function() {
	      if (--times > 0) {
	        memo = func.apply(this, arguments);
	      }
	      if (times <= 1) func = null;
	      return memo;
	    };
	  };
	
	  // Returns a function that will be executed at most one time, no matter how
	  // often you call it. Useful for lazy initialization.
	  _.once = _.partial(_.before, 2);
	
	  // Object Functions
	  // ----------------
	
	  // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
	  var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
	  var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
	                      'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
	
	  function collectNonEnumProps(obj, keys) {
	    var nonEnumIdx = nonEnumerableProps.length;
	    var constructor = obj.constructor;
	    var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;
	
	    // Constructor is a special case.
	    var prop = 'constructor';
	    if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
	
	    while (nonEnumIdx--) {
	      prop = nonEnumerableProps[nonEnumIdx];
	      if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
	        keys.push(prop);
	      }
	    }
	  }
	
	  // Retrieve the names of an object's own properties.
	  // Delegates to **ECMAScript 5**'s native `Object.keys`
	  _.keys = function(obj) {
	    if (!_.isObject(obj)) return [];
	    if (nativeKeys) return nativeKeys(obj);
	    var keys = [];
	    for (var key in obj) if (_.has(obj, key)) keys.push(key);
	    // Ahem, IE < 9.
	    if (hasEnumBug) collectNonEnumProps(obj, keys);
	    return keys;
	  };
	
	  // Retrieve all the property names of an object.
	  _.allKeys = function(obj) {
	    if (!_.isObject(obj)) return [];
	    var keys = [];
	    for (var key in obj) keys.push(key);
	    // Ahem, IE < 9.
	    if (hasEnumBug) collectNonEnumProps(obj, keys);
	    return keys;
	  };
	
	  // Retrieve the values of an object's properties.
	  _.values = function(obj) {
	    var keys = _.keys(obj);
	    var length = keys.length;
	    var values = Array(length);
	    for (var i = 0; i < length; i++) {
	      values[i] = obj[keys[i]];
	    }
	    return values;
	  };
	
	  // Returns the results of applying the iteratee to each element of the object
	  // In contrast to _.map it returns an object
	  _.mapObject = function(obj, iteratee, context) {
	    iteratee = cb(iteratee, context);
	    var keys =  _.keys(obj),
	          length = keys.length,
	          results = {},
	          currentKey;
	      for (var index = 0; index < length; index++) {
	        currentKey = keys[index];
	        results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
	      }
	      return results;
	  };
	
	  // Convert an object into a list of `[key, value]` pairs.
	  _.pairs = function(obj) {
	    var keys = _.keys(obj);
	    var length = keys.length;
	    var pairs = Array(length);
	    for (var i = 0; i < length; i++) {
	      pairs[i] = [keys[i], obj[keys[i]]];
	    }
	    return pairs;
	  };
	
	  // Invert the keys and values of an object. The values must be serializable.
	  _.invert = function(obj) {
	    var result = {};
	    var keys = _.keys(obj);
	    for (var i = 0, length = keys.length; i < length; i++) {
	      result[obj[keys[i]]] = keys[i];
	    }
	    return result;
	  };
	
	  // Return a sorted list of the function names available on the object.
	  // Aliased as `methods`
	  _.functions = _.methods = function(obj) {
	    var names = [];
	    for (var key in obj) {
	      if (_.isFunction(obj[key])) names.push(key);
	    }
	    return names.sort();
	  };
	
	  // Extend a given object with all the properties in passed-in object(s).
	  _.extend = createAssigner(_.allKeys);
	
	  // Assigns a given object with all the own properties in the passed-in object(s)
	  // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
	  _.extendOwn = _.assign = createAssigner(_.keys);
	
	  // Returns the first key on an object that passes a predicate test
	  _.findKey = function(obj, predicate, context) {
	    predicate = cb(predicate, context);
	    var keys = _.keys(obj), key;
	    for (var i = 0, length = keys.length; i < length; i++) {
	      key = keys[i];
	      if (predicate(obj[key], key, obj)) return key;
	    }
	  };
	
	  // Return a copy of the object only containing the whitelisted properties.
	  _.pick = function(object, oiteratee, context) {
	    var result = {}, obj = object, iteratee, keys;
	    if (obj == null) return result;
	    if (_.isFunction(oiteratee)) {
	      keys = _.allKeys(obj);
	      iteratee = optimizeCb(oiteratee, context);
	    } else {
	      keys = flatten(arguments, false, false, 1);
	      iteratee = function(value, key, obj) { return key in obj; };
	      obj = Object(obj);
	    }
	    for (var i = 0, length = keys.length; i < length; i++) {
	      var key = keys[i];
	      var value = obj[key];
	      if (iteratee(value, key, obj)) result[key] = value;
	    }
	    return result;
	  };
	
	   // Return a copy of the object without the blacklisted properties.
	  _.omit = function(obj, iteratee, context) {
	    if (_.isFunction(iteratee)) {
	      iteratee = _.negate(iteratee);
	    } else {
	      var keys = _.map(flatten(arguments, false, false, 1), String);
	      iteratee = function(value, key) {
	        return !_.contains(keys, key);
	      };
	    }
	    return _.pick(obj, iteratee, context);
	  };
	
	  // Fill in a given object with default properties.
	  _.defaults = createAssigner(_.allKeys, true);
	
	  // Creates an object that inherits from the given prototype object.
	  // If additional properties are provided then they will be added to the
	  // created object.
	  _.create = function(prototype, props) {
	    var result = baseCreate(prototype);
	    if (props) _.extendOwn(result, props);
	    return result;
	  };
	
	  // Create a (shallow-cloned) duplicate of an object.
	  _.clone = function(obj) {
	    if (!_.isObject(obj)) return obj;
	    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
	  };
	
	  // Invokes interceptor with the obj, and then returns obj.
	  // The primary purpose of this method is to "tap into" a method chain, in
	  // order to perform operations on intermediate results within the chain.
	  _.tap = function(obj, interceptor) {
	    interceptor(obj);
	    return obj;
	  };
	
	  // Returns whether an object has a given set of `key:value` pairs.
	  _.isMatch = function(object, attrs) {
	    var keys = _.keys(attrs), length = keys.length;
	    if (object == null) return !length;
	    var obj = Object(object);
	    for (var i = 0; i < length; i++) {
	      var key = keys[i];
	      if (attrs[key] !== obj[key] || !(key in obj)) return false;
	    }
	    return true;
	  };
	
	
	  // Internal recursive comparison function for `isEqual`.
	  var eq = function(a, b, aStack, bStack) {
	    // Identical objects are equal. `0 === -0`, but they aren't identical.
	    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
	    if (a === b) return a !== 0 || 1 / a === 1 / b;
	    // A strict comparison is necessary because `null == undefined`.
	    if (a == null || b == null) return a === b;
	    // Unwrap any wrapped objects.
	    if (a instanceof _) a = a._wrapped;
	    if (b instanceof _) b = b._wrapped;
	    // Compare `[[Class]]` names.
	    var className = toString.call(a);
	    if (className !== toString.call(b)) return false;
	    switch (className) {
	      // Strings, numbers, regular expressions, dates, and booleans are compared by value.
	      case '[object RegExp]':
	      // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
	      case '[object String]':
	        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
	        // equivalent to `new String("5")`.
	        return '' + a === '' + b;
	      case '[object Number]':
	        // `NaN`s are equivalent, but non-reflexive.
	        // Object(NaN) is equivalent to NaN
	        if (+a !== +a) return +b !== +b;
	        // An `egal` comparison is performed for other numeric values.
	        return +a === 0 ? 1 / +a === 1 / b : +a === +b;
	      case '[object Date]':
	      case '[object Boolean]':
	        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
	        // millisecond representations. Note that invalid dates with millisecond representations
	        // of `NaN` are not equivalent.
	        return +a === +b;
	    }
	
	    var areArrays = className === '[object Array]';
	    if (!areArrays) {
	      if (typeof a != 'object' || typeof b != 'object') return false;
	
	      // Objects with different constructors are not equivalent, but `Object`s or `Array`s
	      // from different frames are.
	      var aCtor = a.constructor, bCtor = b.constructor;
	      if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
	                               _.isFunction(bCtor) && bCtor instanceof bCtor)
	                          && ('constructor' in a && 'constructor' in b)) {
	        return false;
	      }
	    }
	    // Assume equality for cyclic structures. The algorithm for detecting cyclic
	    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
	
	    // Initializing stack of traversed objects.
	    // It's done here since we only need them for objects and arrays comparison.
	    aStack = aStack || [];
	    bStack = bStack || [];
	    var length = aStack.length;
	    while (length--) {
	      // Linear search. Performance is inversely proportional to the number of
	      // unique nested structures.
	      if (aStack[length] === a) return bStack[length] === b;
	    }
	
	    // Add the first object to the stack of traversed objects.
	    aStack.push(a);
	    bStack.push(b);
	
	    // Recursively compare objects and arrays.
	    if (areArrays) {
	      // Compare array lengths to determine if a deep comparison is necessary.
	      length = a.length;
	      if (length !== b.length) return false;
	      // Deep compare the contents, ignoring non-numeric properties.
	      while (length--) {
	        if (!eq(a[length], b[length], aStack, bStack)) return false;
	      }
	    } else {
	      // Deep compare objects.
	      var keys = _.keys(a), key;
	      length = keys.length;
	      // Ensure that both objects contain the same number of properties before comparing deep equality.
	      if (_.keys(b).length !== length) return false;
	      while (length--) {
	        // Deep compare each member
	        key = keys[length];
	        if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
	      }
	    }
	    // Remove the first object from the stack of traversed objects.
	    aStack.pop();
	    bStack.pop();
	    return true;
	  };
	
	  // Perform a deep comparison to check if two objects are equal.
	  _.isEqual = function(a, b) {
	    return eq(a, b);
	  };
	
	  // Is a given array, string, or object empty?
	  // An "empty" object has no enumerable own-properties.
	  _.isEmpty = function(obj) {
	    if (obj == null) return true;
	    if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
	    return _.keys(obj).length === 0;
	  };
	
	  // Is a given value a DOM element?
	  _.isElement = function(obj) {
	    return !!(obj && obj.nodeType === 1);
	  };
	
	  // Is a given value an array?
	  // Delegates to ECMA5's native Array.isArray
	  _.isArray = nativeIsArray || function(obj) {
	    return toString.call(obj) === '[object Array]';
	  };
	
	  // Is a given variable an object?
	  _.isObject = function(obj) {
	    var type = typeof obj;
	    return type === 'function' || type === 'object' && !!obj;
	  };
	
	  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
	  _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
	    _['is' + name] = function(obj) {
	      return toString.call(obj) === '[object ' + name + ']';
	    };
	  });
	
	  // Define a fallback version of the method in browsers (ahem, IE < 9), where
	  // there isn't any inspectable "Arguments" type.
	  if (!_.isArguments(arguments)) {
	    _.isArguments = function(obj) {
	      return _.has(obj, 'callee');
	    };
	  }
	
	  // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
	  // IE 11 (#1621), and in Safari 8 (#1929).
	  if (typeof /./ != 'function' && typeof Int8Array != 'object') {
	    _.isFunction = function(obj) {
	      return typeof obj == 'function' || false;
	    };
	  }
	
	  // Is a given object a finite number?
	  _.isFinite = function(obj) {
	    return isFinite(obj) && !isNaN(parseFloat(obj));
	  };
	
	  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
	  _.isNaN = function(obj) {
	    return _.isNumber(obj) && obj !== +obj;
	  };
	
	  // Is a given value a boolean?
	  _.isBoolean = function(obj) {
	    return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
	  };
	
	  // Is a given value equal to null?
	  _.isNull = function(obj) {
	    return obj === null;
	  };
	
	  // Is a given variable undefined?
	  _.isUndefined = function(obj) {
	    return obj === void 0;
	  };
	
	  // Shortcut function for checking if an object has a given property directly
	  // on itself (in other words, not on a prototype).
	  _.has = function(obj, key) {
	    return obj != null && hasOwnProperty.call(obj, key);
	  };
	
	  // Utility Functions
	  // -----------------
	
	  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
	  // previous owner. Returns a reference to the Underscore object.
	  _.noConflict = function() {
	    root._ = previousUnderscore;
	    return this;
	  };
	
	  // Keep the identity function around for default iteratees.
	  _.identity = function(value) {
	    return value;
	  };
	
	  // Predicate-generating functions. Often useful outside of Underscore.
	  _.constant = function(value) {
	    return function() {
	      return value;
	    };
	  };
	
	  _.noop = function(){};
	
	  _.property = property;
	
	  // Generates a function for a given object that returns a given property.
	  _.propertyOf = function(obj) {
	    return obj == null ? function(){} : function(key) {
	      return obj[key];
	    };
	  };
	
	  // Returns a predicate for checking whether an object has a given set of
	  // `key:value` pairs.
	  _.matcher = _.matches = function(attrs) {
	    attrs = _.extendOwn({}, attrs);
	    return function(obj) {
	      return _.isMatch(obj, attrs);
	    };
	  };
	
	  // Run a function **n** times.
	  _.times = function(n, iteratee, context) {
	    var accum = Array(Math.max(0, n));
	    iteratee = optimizeCb(iteratee, context, 1);
	    for (var i = 0; i < n; i++) accum[i] = iteratee(i);
	    return accum;
	  };
	
	  // Return a random integer between min and max (inclusive).
	  _.random = function(min, max) {
	    if (max == null) {
	      max = min;
	      min = 0;
	    }
	    return min + Math.floor(Math.random() * (max - min + 1));
	  };
	
	  // A (possibly faster) way to get the current timestamp as an integer.
	  _.now = Date.now || function() {
	    return new Date().getTime();
	  };
	
	   // List of HTML entities for escaping.
	  var escapeMap = {
	    '&': '&amp;',
	    '<': '&lt;',
	    '>': '&gt;',
	    '"': '&quot;',
	    "'": '&#x27;',
	    '`': '&#x60;'
	  };
	  var unescapeMap = _.invert(escapeMap);
	
	  // Functions for escaping and unescaping strings to/from HTML interpolation.
	  var createEscaper = function(map) {
	    var escaper = function(match) {
	      return map[match];
	    };
	    // Regexes for identifying a key that needs to be escaped
	    var source = '(?:' + _.keys(map).join('|') + ')';
	    var testRegexp = RegExp(source);
	    var replaceRegexp = RegExp(source, 'g');
	    return function(string) {
	      string = string == null ? '' : '' + string;
	      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
	    };
	  };
	  _.escape = createEscaper(escapeMap);
	  _.unescape = createEscaper(unescapeMap);
	
	  // If the value of the named `property` is a function then invoke it with the
	  // `object` as context; otherwise, return it.
	  _.result = function(object, property, fallback) {
	    var value = object == null ? void 0 : object[property];
	    if (value === void 0) {
	      value = fallback;
	    }
	    return _.isFunction(value) ? value.call(object) : value;
	  };
	
	  // Generate a unique integer id (unique within the entire client session).
	  // Useful for temporary DOM ids.
	  var idCounter = 0;
	  _.uniqueId = function(prefix) {
	    var id = ++idCounter + '';
	    return prefix ? prefix + id : id;
	  };
	
	  // By default, Underscore uses ERB-style template delimiters, change the
	  // following template settings to use alternative delimiters.
	  _.templateSettings = {
	    evaluate    : /<%([\s\S]+?)%>/g,
	    interpolate : /<%=([\s\S]+?)%>/g,
	    escape      : /<%-([\s\S]+?)%>/g
	  };
	
	  // When customizing `templateSettings`, if you don't want to define an
	  // interpolation, evaluation or escaping regex, we need one that is
	  // guaranteed not to match.
	  var noMatch = /(.)^/;
	
	  // Certain characters need to be escaped so that they can be put into a
	  // string literal.
	  var escapes = {
	    "'":      "'",
	    '\\':     '\\',
	    '\r':     'r',
	    '\n':     'n',
	    '\u2028': 'u2028',
	    '\u2029': 'u2029'
	  };
	
	  var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
	
	  var escapeChar = function(match) {
	    return '\\' + escapes[match];
	  };
	
	  // JavaScript micro-templating, similar to John Resig's implementation.
	  // Underscore templating handles arbitrary delimiters, preserves whitespace,
	  // and correctly escapes quotes within interpolated code.
	  // NB: `oldSettings` only exists for backwards compatibility.
	  _.template = function(text, settings, oldSettings) {
	    if (!settings && oldSettings) settings = oldSettings;
	    settings = _.defaults({}, settings, _.templateSettings);
	
	    // Combine delimiters into one regular expression via alternation.
	    var matcher = RegExp([
	      (settings.escape || noMatch).source,
	      (settings.interpolate || noMatch).source,
	      (settings.evaluate || noMatch).source
	    ].join('|') + '|$', 'g');
	
	    // Compile the template source, escaping string literals appropriately.
	    var index = 0;
	    var source = "__p+='";
	    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
	      source += text.slice(index, offset).replace(escaper, escapeChar);
	      index = offset + match.length;
	
	      if (escape) {
	        source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
	      } else if (interpolate) {
	        source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
	      } else if (evaluate) {
	        source += "';\n" + evaluate + "\n__p+='";
	      }
	
	      // Adobe VMs need the match returned to produce the correct offest.
	      return match;
	    });
	    source += "';\n";
	
	    // If a variable is not specified, place data values in local scope.
	    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
	
	    source = "var __t,__p='',__j=Array.prototype.join," +
	      "print=function(){__p+=__j.call(arguments,'');};\n" +
	      source + 'return __p;\n';
	
	    try {
	      var render = new Function(settings.variable || 'obj', '_', source);
	    } catch (e) {
	      e.source = source;
	      throw e;
	    }
	
	    var template = function(data) {
	      return render.call(this, data, _);
	    };
	
	    // Provide the compiled source as a convenience for precompilation.
	    var argument = settings.variable || 'obj';
	    template.source = 'function(' + argument + '){\n' + source + '}';
	
	    return template;
	  };
	
	  // Add a "chain" function. Start chaining a wrapped Underscore object.
	  _.chain = function(obj) {
	    var instance = _(obj);
	    instance._chain = true;
	    return instance;
	  };
	
	  // OOP
	  // ---------------
	  // If Underscore is called as a function, it returns a wrapped object that
	  // can be used OO-style. This wrapper holds altered versions of all the
	  // underscore functions. Wrapped objects may be chained.
	
	  // Helper function to continue chaining intermediate results.
	  var result = function(instance, obj) {
	    return instance._chain ? _(obj).chain() : obj;
	  };
	
	  // Add your own custom functions to the Underscore object.
	  _.mixin = function(obj) {
	    _.each(_.functions(obj), function(name) {
	      var func = _[name] = obj[name];
	      _.prototype[name] = function() {
	        var args = [this._wrapped];
	        push.apply(args, arguments);
	        return result(this, func.apply(_, args));
	      };
	    });
	  };
	
	  // Add all of the Underscore functions to the wrapper object.
	  _.mixin(_);
	
	  // Add all mutator Array functions to the wrapper.
	  _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
	    var method = ArrayProto[name];
	    _.prototype[name] = function() {
	      var obj = this._wrapped;
	      method.apply(obj, arguments);
	      if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
	      return result(this, obj);
	    };
	  });
	
	  // Add all accessor Array functions to the wrapper.
	  _.each(['concat', 'join', 'slice'], function(name) {
	    var method = ArrayProto[name];
	    _.prototype[name] = function() {
	      return result(this, method.apply(this._wrapped, arguments));
	    };
	  });
	
	  // Extracts the result from a wrapped and chained object.
	  _.prototype.value = function() {
	    return this._wrapped;
	  };
	
	  // Provide unwrapping proxy for some methods used in engine operations
	  // such as arithmetic and JSON stringification.
	  _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
	
	  _.prototype.toString = function() {
	    return '' + this._wrapped;
	  };
	
	  // AMD registration happens at the end for compatibility with AMD loaders
	  // that may not enforce next-turn semantics on modules. Even though general
	  // practice for AMD registration is to be anonymous, underscore registers
	  // as a named module because, like jQuery, it is a base library that is
	  // popular enough to be bundled in a third party lib, but not be part of
	  // an AMD load request. Those cases could generate an error when an
	  // anonymous define() is called outside of a loader request.
	  if (true) {
	    !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function() {
	      return _;
	    }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
	  }
	}.call(this));


/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {

	var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;!function() {
	  var d3 = {
	    version: "3.5.17"
	  };
	  var d3_arraySlice = [].slice, d3_array = function(list) {
	    return d3_arraySlice.call(list);
	  };
	  var d3_document = this.document;
	  function d3_documentElement(node) {
	    return node && (node.ownerDocument || node.document || node).documentElement;
	  }
	  function d3_window(node) {
	    return node && (node.ownerDocument && node.ownerDocument.defaultView || node.document && node || node.defaultView);
	  }
	  if (d3_document) {
	    try {
	      d3_array(d3_document.documentElement.childNodes)[0].nodeType;
	    } catch (e) {
	      d3_array = function(list) {
	        var i = list.length, array = new Array(i);
	        while (i--) array[i] = list[i];
	        return array;
	      };
	    }
	  }
	  if (!Date.now) Date.now = function() {
	    return +new Date();
	  };
	  if (d3_document) {
	    try {
	      d3_document.createElement("DIV").style.setProperty("opacity", 0, "");
	    } catch (error) {
	      var d3_element_prototype = this.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = this.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty;
	      d3_element_prototype.setAttribute = function(name, value) {
	        d3_element_setAttribute.call(this, name, value + "");
	      };
	      d3_element_prototype.setAttributeNS = function(space, local, value) {
	        d3_element_setAttributeNS.call(this, space, local, value + "");
	      };
	      d3_style_prototype.setProperty = function(name, value, priority) {
	        d3_style_setProperty.call(this, name, value + "", priority);
	      };
	    }
	  }
	  d3.ascending = d3_ascending;
	  function d3_ascending(a, b) {
	    return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
	  }
	  d3.descending = function(a, b) {
	    return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
	  };
	  d3.min = function(array, f) {
	    var i = -1, n = array.length, a, b;
	    if (arguments.length === 1) {
	      while (++i < n) if ((b = array[i]) != null && b >= b) {
	        a = b;
	        break;
	      }
	      while (++i < n) if ((b = array[i]) != null && a > b) a = b;
	    } else {
	      while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {
	        a = b;
	        break;
	      }
	      while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
	    }
	    return a;
	  };
	  d3.max = function(array, f) {
	    var i = -1, n = array.length, a, b;
	    if (arguments.length === 1) {
	      while (++i < n) if ((b = array[i]) != null && b >= b) {
	        a = b;
	        break;
	      }
	      while (++i < n) if ((b = array[i]) != null && b > a) a = b;
	    } else {
	      while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {
	        a = b;
	        break;
	      }
	      while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
	    }
	    return a;
	  };
	  d3.extent = function(array, f) {
	    var i = -1, n = array.length, a, b, c;
	    if (arguments.length === 1) {
	      while (++i < n) if ((b = array[i]) != null && b >= b) {
	        a = c = b;
	        break;
	      }
	      while (++i < n) if ((b = array[i]) != null) {
	        if (a > b) a = b;
	        if (c < b) c = b;
	      }
	    } else {
	      while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {
	        a = c = b;
	        break;
	      }
	      while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
	        if (a > b) a = b;
	        if (c < b) c = b;
	      }
	    }
	    return [ a, c ];
	  };
	  function d3_number(x) {
	    return x === null ? NaN : +x;
	  }
	  function d3_numeric(x) {
	    return !isNaN(x);
	  }
	  d3.sum = function(array, f) {
	    var s = 0, n = array.length, a, i = -1;
	    if (arguments.length === 1) {
	      while (++i < n) if (d3_numeric(a = +array[i])) s += a;
	    } else {
	      while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a;
	    }
	    return s;
	  };
	  d3.mean = function(array, f) {
	    var s = 0, n = array.length, a, i = -1, j = n;
	    if (arguments.length === 1) {
	      while (++i < n) if (d3_numeric(a = d3_number(array[i]))) s += a; else --j;
	    } else {
	      while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) s += a; else --j;
	    }
	    if (j) return s / j;
	  };
	  d3.quantile = function(values, p) {
	    var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h;
	    return e ? v + e * (values[h] - v) : v;
	  };
	  d3.median = function(array, f) {
	    var numbers = [], n = array.length, a, i = -1;
	    if (arguments.length === 1) {
	      while (++i < n) if (d3_numeric(a = d3_number(array[i]))) numbers.push(a);
	    } else {
	      while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) numbers.push(a);
	    }
	    if (numbers.length) return d3.quantile(numbers.sort(d3_ascending), .5);
	  };
	  d3.variance = function(array, f) {
	    var n = array.length, m = 0, a, d, s = 0, i = -1, j = 0;
	    if (arguments.length === 1) {
	      while (++i < n) {
	        if (d3_numeric(a = d3_number(array[i]))) {
	          d = a - m;
	          m += d / ++j;
	          s += d * (a - m);
	        }
	      }
	    } else {
	      while (++i < n) {
	        if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) {
	          d = a - m;
	          m += d / ++j;
	          s += d * (a - m);
	        }
	      }
	    }
	    if (j > 1) return s / (j - 1);
	  };
	  d3.deviation = function() {
	    var v = d3.variance.apply(this, arguments);
	    return v ? Math.sqrt(v) : v;
	  };
	  function d3_bisector(compare) {
	    return {
	      left: function(a, x, lo, hi) {
	        if (arguments.length < 3) lo = 0;
	        if (arguments.length < 4) hi = a.length;
	        while (lo < hi) {
	          var mid = lo + hi >>> 1;
	          if (compare(a[mid], x) < 0) lo = mid + 1; else hi = mid;
	        }
	        return lo;
	      },
	      right: function(a, x, lo, hi) {
	        if (arguments.length < 3) lo = 0;
	        if (arguments.length < 4) hi = a.length;
	        while (lo < hi) {
	          var mid = lo + hi >>> 1;
	          if (compare(a[mid], x) > 0) hi = mid; else lo = mid + 1;
	        }
	        return lo;
	      }
	    };
	  }
	  var d3_bisect = d3_bisector(d3_ascending);
	  d3.bisectLeft = d3_bisect.left;
	  d3.bisect = d3.bisectRight = d3_bisect.right;
	  d3.bisector = function(f) {
	    return d3_bisector(f.length === 1 ? function(d, x) {
	      return d3_ascending(f(d), x);
	    } : f);
	  };
	  d3.shuffle = function(array, i0, i1) {
	    if ((m = arguments.length) < 3) {
	      i1 = array.length;
	      if (m < 2) i0 = 0;
	    }
	    var m = i1 - i0, t, i;
	    while (m) {
	      i = Math.random() * m-- | 0;
	      t = array[m + i0], array[m + i0] = array[i + i0], array[i + i0] = t;
	    }
	    return array;
	  };
	  d3.permute = function(array, indexes) {
	    var i = indexes.length, permutes = new Array(i);
	    while (i--) permutes[i] = array[indexes[i]];
	    return permutes;
	  };
	  d3.pairs = function(array) {
	    var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n);
	    while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ];
	    return pairs;
	  };
	  d3.transpose = function(matrix) {
	    if (!(n = matrix.length)) return [];
	    for (var i = -1, m = d3.min(matrix, d3_transposeLength), transpose = new Array(m); ++i < m; ) {
	      for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n; ) {
	        row[j] = matrix[j][i];
	      }
	    }
	    return transpose;
	  };
	  function d3_transposeLength(d) {
	    return d.length;
	  }
	  d3.zip = function() {
	    return d3.transpose(arguments);
	  };
	  d3.keys = function(map) {
	    var keys = [];
	    for (var key in map) keys.push(key);
	    return keys;
	  };
	  d3.values = function(map) {
	    var values = [];
	    for (var key in map) values.push(map[key]);
	    return values;
	  };
	  d3.entries = function(map) {
	    var entries = [];
	    for (var key in map) entries.push({
	      key: key,
	      value: map[key]
	    });
	    return entries;
	  };
	  d3.merge = function(arrays) {
	    var n = arrays.length, m, i = -1, j = 0, merged, array;
	    while (++i < n) j += arrays[i].length;
	    merged = new Array(j);
	    while (--n >= 0) {
	      array = arrays[n];
	      m = array.length;
	      while (--m >= 0) {
	        merged[--j] = array[m];
	      }
	    }
	    return merged;
	  };
	  var abs = Math.abs;
	  d3.range = function(start, stop, step) {
	    if (arguments.length < 3) {
	      step = 1;
	      if (arguments.length < 2) {
	        stop = start;
	        start = 0;
	      }
	    }
	    if ((stop - start) / step === Infinity) throw new Error("infinite range");
	    var range = [], k = d3_range_integerScale(abs(step)), i = -1, j;
	    start *= k, stop *= k, step *= k;
	    if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k);
	    return range;
	  };
	  function d3_range_integerScale(x) {
	    var k = 1;
	    while (x * k % 1) k *= 10;
	    return k;
	  }
	  function d3_class(ctor, properties) {
	    for (var key in properties) {
	      Object.defineProperty(ctor.prototype, key, {
	        value: properties[key],
	        enumerable: false
	      });
	    }
	  }
	  d3.map = function(object, f) {
	    var map = new d3_Map();
	    if (object instanceof d3_Map) {
	      object.forEach(function(key, value) {
	        map.set(key, value);
	      });
	    } else if (Array.isArray(object)) {
	      var i = -1, n = object.length, o;
	      if (arguments.length === 1) while (++i < n) map.set(i, object[i]); else while (++i < n) map.set(f.call(object, o = object[i], i), o);
	    } else {
	      for (var key in object) map.set(key, object[key]);
	    }
	    return map;
	  };
	  function d3_Map() {
	    this._ = Object.create(null);
	  }
	  var d3_map_proto = "__proto__", d3_map_zero = "\x00";
	  d3_class(d3_Map, {
	    has: d3_map_has,
	    get: function(key) {
	      return this._[d3_map_escape(key)];
	    },
	    set: function(key, value) {
	      return this._[d3_map_escape(key)] = value;
	    },
	    remove: d3_map_remove,
	    keys: d3_map_keys,
	    values: function() {
	      var values = [];
	      for (var key in this._) values.push(this._[key]);
	      return values;
	    },
	    entries: function() {
	      var entries = [];
	      for (var key in this._) entries.push({
	        key: d3_map_unescape(key),
	        value: this._[key]
	      });
	      return entries;
	    },
	    size: d3_map_size,
	    empty: d3_map_empty,
	    forEach: function(f) {
	      for (var key in this._) f.call(this, d3_map_unescape(key), this._[key]);
	    }
	  });
	  function d3_map_escape(key) {
	    return (key += "") === d3_map_proto || key[0] === d3_map_zero ? d3_map_zero + key : key;
	  }
	  function d3_map_unescape(key) {
	    return (key += "")[0] === d3_map_zero ? key.slice(1) : key;
	  }
	  function d3_map_has(key) {
	    return d3_map_escape(key) in this._;
	  }
	  function d3_map_remove(key) {
	    return (key = d3_map_escape(key)) in this._ && delete this._[key];
	  }
	  function d3_map_keys() {
	    var keys = [];
	    for (var key in this._) keys.push(d3_map_unescape(key));
	    return keys;
	  }
	  function d3_map_size() {
	    var size = 0;
	    for (var key in this._) ++size;
	    return size;
	  }
	  function d3_map_empty() {
	    for (var key in this._) return false;
	    return true;
	  }
	  d3.nest = function() {
	    var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
	    function map(mapType, array, depth) {
	      if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array;
	      var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values;
	      while (++i < n) {
	        if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
	          values.push(object);
	        } else {
	          valuesByKey.set(keyValue, [ object ]);
	        }
	      }
	      if (mapType) {
	        object = mapType();
	        setter = function(keyValue, values) {
	          object.set(keyValue, map(mapType, values, depth));
	        };
	      } else {
	        object = {};
	        setter = function(keyValue, values) {
	          object[keyValue] = map(mapType, values, depth);
	        };
	      }
	      valuesByKey.forEach(setter);
	      return object;
	    }
	    function entries(map, depth) {
	      if (depth >= keys.length) return map;
	      var array = [], sortKey = sortKeys[depth++];
	      map.forEach(function(key, keyMap) {
	        array.push({
	          key: key,
	          values: entries(keyMap, depth)
	        });
	      });
	      return sortKey ? array.sort(function(a, b) {
	        return sortKey(a.key, b.key);
	      }) : array;
	    }
	    nest.map = function(array, mapType) {
	      return map(mapType, array, 0);
	    };
	    nest.entries = function(array) {
	      return entries(map(d3.map, array, 0), 0);
	    };
	    nest.key = function(d) {
	      keys.push(d);
	      return nest;
	    };
	    nest.sortKeys = function(order) {
	      sortKeys[keys.length - 1] = order;
	      return nest;
	    };
	    nest.sortValues = function(order) {
	      sortValues = order;
	      return nest;
	    };
	    nest.rollup = function(f) {
	      rollup = f;
	      return nest;
	    };
	    return nest;
	  };
	  d3.set = function(array) {
	    var set = new d3_Set();
	    if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]);
	    return set;
	  };
	  function d3_Set() {
	    this._ = Object.create(null);
	  }
	  d3_class(d3_Set, {
	    has: d3_map_has,
	    add: function(key) {
	      this._[d3_map_escape(key += "")] = true;
	      return key;
	    },
	    remove: d3_map_remove,
	    values: d3_map_keys,
	    size: d3_map_size,
	    empty: d3_map_empty,
	    forEach: function(f) {
	      for (var key in this._) f.call(this, d3_map_unescape(key));
	    }
	  });
	  d3.behavior = {};
	  function d3_identity(d) {
	    return d;
	  }
	  d3.rebind = function(target, source) {
	    var i = 1, n = arguments.length, method;
	    while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
	    return target;
	  };
	  function d3_rebind(target, source, method) {
	    return function() {
	      var value = method.apply(source, arguments);
	      return value === source ? target : value;
	    };
	  }
	  function d3_vendorSymbol(object, name) {
	    if (name in object) return name;
	    name = name.charAt(0).toUpperCase() + name.slice(1);
	    for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) {
	      var prefixName = d3_vendorPrefixes[i] + name;
	      if (prefixName in object) return prefixName;
	    }
	  }
	  var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ];
	  function d3_noop() {}
	  d3.dispatch = function() {
	    var dispatch = new d3_dispatch(), i = -1, n = arguments.length;
	    while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
	    return dispatch;
	  };
	  function d3_dispatch() {}
	  d3_dispatch.prototype.on = function(type, listener) {
	    var i = type.indexOf("."), name = "";
	    if (i >= 0) {
	      name = type.slice(i + 1);
	      type = type.slice(0, i);
	    }
	    if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener);
	    if (arguments.length === 2) {
	      if (listener == null) for (type in this) {
	        if (this.hasOwnProperty(type)) this[type].on(name, null);
	      }
	      return this;
	    }
	  };
	  function d3_dispatch_event(dispatch) {
	    var listeners = [], listenerByName = new d3_Map();
	    function event() {
	      var z = listeners, i = -1, n = z.length, l;
	      while (++i < n) if (l = z[i].on) l.apply(this, arguments);
	      return dispatch;
	    }
	    event.on = function(name, listener) {
	      var l = listenerByName.get(name), i;
	      if (arguments.length < 2) return l && l.on;
	      if (l) {
	        l.on = null;
	        listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
	        listenerByName.remove(name);
	      }
	      if (listener) listeners.push(listenerByName.set(name, {
	        on: listener
	      }));
	      return dispatch;
	    };
	    return event;
	  }
	  d3.event = null;
	  function d3_eventPreventDefault() {
	    d3.event.preventDefault();
	  }
	  function d3_eventSource() {
	    var e = d3.event, s;
	    while (s = e.sourceEvent) e = s;
	    return e;
	  }
	  function d3_eventDispatch(target) {
	    var dispatch = new d3_dispatch(), i = 0, n = arguments.length;
	    while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
	    dispatch.of = function(thiz, argumentz) {
	      return function(e1) {
	        try {
	          var e0 = e1.sourceEvent = d3.event;
	          e1.target = target;
	          d3.event = e1;
	          dispatch[e1.type].apply(thiz, argumentz);
	        } finally {
	          d3.event = e0;
	        }
	      };
	    };
	    return dispatch;
	  }
	  d3.requote = function(s) {
	    return s.replace(d3_requote_re, "\\$&");
	  };
	  var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
	  var d3_subclass = {}.__proto__ ? function(object, prototype) {
	    object.__proto__ = prototype;
	  } : function(object, prototype) {
	    for (var property in prototype) object[property] = prototype[property];
	  };
	  function d3_selection(groups) {
	    d3_subclass(groups, d3_selectionPrototype);
	    return groups;
	  }
	  var d3_select = function(s, n) {
	    return n.querySelector(s);
	  }, d3_selectAll = function(s, n) {
	    return n.querySelectorAll(s);
	  }, d3_selectMatches = function(n, s) {
	    var d3_selectMatcher = n.matches || n[d3_vendorSymbol(n, "matchesSelector")];
	    d3_selectMatches = function(n, s) {
	      return d3_selectMatcher.call(n, s);
	    };
	    return d3_selectMatches(n, s);
	  };
	  if (typeof Sizzle === "function") {
	    d3_select = function(s, n) {
	      return Sizzle(s, n)[0] || null;
	    };
	    d3_selectAll = Sizzle;
	    d3_selectMatches = Sizzle.matchesSelector;
	  }
	  d3.selection = function() {
	    return d3.select(d3_document.documentElement);
	  };
	  var d3_selectionPrototype = d3.selection.prototype = [];
	  d3_selectionPrototype.select = function(selector) {
	    var subgroups = [], subgroup, subnode, group, node;
	    selector = d3_selection_selector(selector);
	    for (var j = -1, m = this.length; ++j < m; ) {
	      subgroups.push(subgroup = []);
	      subgroup.parentNode = (group = this[j]).parentNode;
	      for (var i = -1, n = group.length; ++i < n; ) {
	        if (node = group[i]) {
	          subgroup.push(subnode = selector.call(node, node.__data__, i, j));
	          if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
	        } else {
	          subgroup.push(null);
	        }
	      }
	    }
	    return d3_selection(subgroups);
	  };
	  function d3_selection_selector(selector) {
	    return typeof selector === "function" ? selector : function() {
	      return d3_select(selector, this);
	    };
	  }
	  d3_selectionPrototype.selectAll = function(selector) {
	    var subgroups = [], subgroup, node;
	    selector = d3_selection_selectorAll(selector);
	    for (var j = -1, m = this.length; ++j < m; ) {
	      for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
	        if (node = group[i]) {
	          subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j)));
	          subgroup.parentNode = node;
	        }
	      }
	    }
	    return d3_selection(subgroups);
	  };
	  function d3_selection_selectorAll(selector) {
	    return typeof selector === "function" ? selector : function() {
	      return d3_selectAll(selector, this);
	    };
	  }
	  var d3_nsXhtml = "http://www.w3.org/1999/xhtml";
	  var d3_nsPrefix = {
	    svg: "http://www.w3.org/2000/svg",
	    xhtml: d3_nsXhtml,
	    xlink: "http://www.w3.org/1999/xlink",
	    xml: "http://www.w3.org/XML/1998/namespace",
	    xmlns: "http://www.w3.org/2000/xmlns/"
	  };
	  d3.ns = {
	    prefix: d3_nsPrefix,
	    qualify: function(name) {
	      var i = name.indexOf(":"), prefix = name;
	      if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
	      return d3_nsPrefix.hasOwnProperty(prefix) ? {
	        space: d3_nsPrefix[prefix],
	        local: name
	      } : name;
	    }
	  };
	  d3_selectionPrototype.attr = function(name, value) {
	    if (arguments.length < 2) {
	      if (typeof name === "string") {
	        var node = this.node();
	        name = d3.ns.qualify(name);
	        return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name);
	      }
	      for (value in name) this.each(d3_selection_attr(value, name[value]));
	      return this;
	    }
	    return this.each(d3_selection_attr(name, value));
	  };
	  function d3_selection_attr(name, value) {
	    name = d3.ns.qualify(name);
	    function attrNull() {
	      this.removeAttribute(name);
	    }
	    function attrNullNS() {
	      this.removeAttributeNS(name.space, name.local);
	    }
	    function attrConstant() {
	      this.setAttribute(name, value);
	    }
	    function attrConstantNS() {
	      this.setAttributeNS(name.space, name.local, value);
	    }
	    function attrFunction() {
	      var x = value.apply(this, arguments);
	      if (x == null) this.removeAttribute(name); else this.setAttribute(name, x);
	    }
	    function attrFunctionNS() {
	      var x = value.apply(this, arguments);
	      if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x);
	    }
	    return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant;
	  }
	  function d3_collapse(s) {
	    return s.trim().replace(/\s+/g, " ");
	  }
	  d3_selectionPrototype.classed = function(name, value) {
	    if (arguments.length < 2) {
	      if (typeof name === "string") {
	        var node = this.node(), n = (name = d3_selection_classes(name)).length, i = -1;
	        if (value = node.classList) {
	          while (++i < n) if (!value.contains(name[i])) return false;
	        } else {
	          value = node.getAttribute("class");
	          while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
	        }
	        return true;
	      }
	      for (value in name) this.each(d3_selection_classed(value, name[value]));
	      return this;
	    }
	    return this.each(d3_selection_classed(name, value));
	  };
	  function d3_selection_classedRe(name) {
	    return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
	  }
	  function d3_selection_classes(name) {
	    return (name + "").trim().split(/^|\s+/);
	  }
	  function d3_selection_classed(name, value) {
	    name = d3_selection_classes(name).map(d3_selection_classedName);
	    var n = name.length;
	    function classedConstant() {
	      var i = -1;
	      while (++i < n) name[i](this, value);
	    }
	    function classedFunction() {
	      var i = -1, x = value.apply(this, arguments);
	      while (++i < n) name[i](this, x);
	    }
	    return typeof value === "function" ? classedFunction : classedConstant;
	  }
	  function d3_selection_classedName(name) {
	    var re = d3_selection_classedRe(name);
	    return function(node, value) {
	      if (c = node.classList) return value ? c.add(name) : c.remove(name);
	      var c = node.getAttribute("class") || "";
	      if (value) {
	        re.lastIndex = 0;
	        if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name));
	      } else {
	        node.setAttribute("class", d3_collapse(c.replace(re, " ")));
	      }
	    };
	  }
	  d3_selectionPrototype.style = function(name, value, priority) {
	    var n = arguments.length;
	    if (n < 3) {
	      if (typeof name !== "string") {
	        if (n < 2) value = "";
	        for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
	        return this;
	      }
	      if (n < 2) {
	        var node = this.node();
	        return d3_window(node).getComputedStyle(node, null).getPropertyValue(name);
	      }
	      priority = "";
	    }
	    return this.each(d3_selection_style(name, value, priority));
	  };
	  function d3_selection_style(name, value, priority) {
	    function styleNull() {
	      this.style.removeProperty(name);
	    }
	    function styleConstant() {
	      this.style.setProperty(name, value, priority);
	    }
	    function styleFunction() {
	      var x = value.apply(this, arguments);
	      if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority);
	    }
	    return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant;
	  }
	  d3_selectionPrototype.property = function(name, value) {
	    if (arguments.length < 2) {
	      if (typeof name === "string") return this.node()[name];
	      for (value in name) this.each(d3_selection_property(value, name[value]));
	      return this;
	    }
	    return this.each(d3_selection_property(name, value));
	  };
	  function d3_selection_property(name, value) {
	    function propertyNull() {
	      delete this[name];
	    }
	    function propertyConstant() {
	      this[name] = value;
	    }
	    function propertyFunction() {
	      var x = value.apply(this, arguments);
	      if (x == null) delete this[name]; else this[name] = x;
	    }
	    return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant;
	  }
	  d3_selectionPrototype.text = function(value) {
	    return arguments.length ? this.each(typeof value === "function" ? function() {
	      var v = value.apply(this, arguments);
	      this.textContent = v == null ? "" : v;
	    } : value == null ? function() {
	      this.textContent = "";
	    } : function() {
	      this.textContent = value;
	    }) : this.node().textContent;
	  };
	  d3_selectionPrototype.html = function(value) {
	    return arguments.length ? this.each(typeof value === "function" ? function() {
	      var v = value.apply(this, arguments);
	      this.innerHTML = v == null ? "" : v;
	    } : value == null ? function() {
	      this.innerHTML = "";
	    } : function() {
	      this.innerHTML = value;
	    }) : this.node().innerHTML;
	  };
	  d3_selectionPrototype.append = function(name) {
	    name = d3_selection_creator(name);
	    return this.select(function() {
	      return this.appendChild(name.apply(this, arguments));
	    });
	  };
	  function d3_selection_creator(name) {
	    function create() {
	      var document = this.ownerDocument, namespace = this.namespaceURI;
	      return namespace === d3_nsXhtml && document.documentElement.namespaceURI === d3_nsXhtml ? document.createElement(name) : document.createElementNS(namespace, name);
	    }
	    function createNS() {
	      return this.ownerDocument.createElementNS(name.space, name.local);
	    }
	    return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? createNS : create;
	  }
	  d3_selectionPrototype.insert = function(name, before) {
	    name = d3_selection_creator(name);
	    before = d3_selection_selector(before);
	    return this.select(function() {
	      return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null);
	    });
	  };
	  d3_selectionPrototype.remove = function() {
	    return this.each(d3_selectionRemove);
	  };
	  function d3_selectionRemove() {
	    var parent = this.parentNode;
	    if (parent) parent.removeChild(this);
	  }
	  d3_selectionPrototype.data = function(value, key) {
	    var i = -1, n = this.length, group, node;
	    if (!arguments.length) {
	      value = new Array(n = (group = this[0]).length);
	      while (++i < n) {
	        if (node = group[i]) {
	          value[i] = node.__data__;
	        }
	      }
	      return value;
	    }
	    function bind(group, groupData) {
	      var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData;
	      if (key) {
	        var nodeByKeyValue = new d3_Map(), keyValues = new Array(n), keyValue;
	        for (i = -1; ++i < n; ) {
	          if (node = group[i]) {
	            if (nodeByKeyValue.has(keyValue = key.call(node, node.__data__, i))) {
	              exitNodes[i] = node;
	            } else {
	              nodeByKeyValue.set(keyValue, node);
	            }
	            keyValues[i] = keyValue;
	          }
	        }
	        for (i = -1; ++i < m; ) {
	          if (!(node = nodeByKeyValue.get(keyValue = key.call(groupData, nodeData = groupData[i], i)))) {
	            enterNodes[i] = d3_selection_dataNode(nodeData);
	          } else if (node !== true) {
	            updateNodes[i] = node;
	            node.__data__ = nodeData;
	          }
	          nodeByKeyValue.set(keyValue, true);
	        }
	        for (i = -1; ++i < n; ) {
	          if (i in keyValues && nodeByKeyValue.get(keyValues[i]) !== true) {
	            exitNodes[i] = group[i];
	          }
	        }
	      } else {
	        for (i = -1; ++i < n0; ) {
	          node = group[i];
	          nodeData = groupData[i];
	          if (node) {
	            node.__data__ = nodeData;
	            updateNodes[i] = node;
	          } else {
	            enterNodes[i] = d3_selection_dataNode(nodeData);
	          }
	        }
	        for (;i < m; ++i) {
	          enterNodes[i] = d3_selection_dataNode(groupData[i]);
	        }
	        for (;i < n; ++i) {
	          exitNodes[i] = group[i];
	        }
	      }
	      enterNodes.update = updateNodes;
	      enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode;
	      enter.push(enterNodes);
	      update.push(updateNodes);
	      exit.push(exitNodes);
	    }
	    var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]);
	    if (typeof value === "function") {
	      while (++i < n) {
	        bind(group = this[i], value.call(group, group.parentNode.__data__, i));
	      }
	    } else {
	      while (++i < n) {
	        bind(group = this[i], value);
	      }
	    }
	    update.enter = function() {
	      return enter;
	    };
	    update.exit = function() {
	      return exit;
	    };
	    return update;
	  };
	  function d3_selection_dataNode(data) {
	    return {
	      __data__: data
	    };
	  }
	  d3_selectionPrototype.datum = function(value) {
	    return arguments.length ? this.property("__data__", value) : this.property("__data__");
	  };
	  d3_selectionPrototype.filter = function(filter) {
	    var subgroups = [], subgroup, group, node;
	    if (typeof filter !== "function") filter = d3_selection_filter(filter);
	    for (var j = 0, m = this.length; j < m; j++) {
	      subgroups.push(subgroup = []);
	      subgroup.parentNode = (group = this[j]).parentNode;
	      for (var i = 0, n = group.length; i < n; i++) {
	        if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
	          subgroup.push(node);
	        }
	      }
	    }
	    return d3_selection(subgroups);
	  };
	  function d3_selection_filter(selector) {
	    return function() {
	      return d3_selectMatches(this, selector);
	    };
	  }
	  d3_selectionPrototype.order = function() {
	    for (var j = -1, m = this.length; ++j < m; ) {
	      for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {
	        if (node = group[i]) {
	          if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
	          next = node;
	        }
	      }
	    }
	    return this;
	  };
	  d3_selectionPrototype.sort = function(comparator) {
	    comparator = d3_selection_sortComparator.apply(this, arguments);
	    for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator);
	    return this.order();
	  };
	  function d3_selection_sortComparator(comparator) {
	    if (!arguments.length) comparator = d3_ascending;
	    return function(a, b) {
	      return a && b ? comparator(a.__data__, b.__data__) : !a - !b;
	    };
	  }
	  d3_selectionPrototype.each = function(callback) {
	    return d3_selection_each(this, function(node, i, j) {
	      callback.call(node, node.__data__, i, j);
	    });
	  };
	  function d3_selection_each(groups, callback) {
	    for (var j = 0, m = groups.length; j < m; j++) {
	      for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
	        if (node = group[i]) callback(node, i, j);
	      }
	    }
	    return groups;
	  }
	  d3_selectionPrototype.call = function(callback) {
	    var args = d3_array(arguments);
	    callback.apply(args[0] = this, args);
	    return this;
	  };
	  d3_selectionPrototype.empty = function() {
	    return !this.node();
	  };
	  d3_selectionPrototype.node = function() {
	    for (var j = 0, m = this.length; j < m; j++) {
	      for (var group = this[j], i = 0, n = group.length; i < n; i++) {
	        var node = group[i];
	        if (node) return node;
	      }
	    }
	    return null;
	  };
	  d3_selectionPrototype.size = function() {
	    var n = 0;
	    d3_selection_each(this, function() {
	      ++n;
	    });
	    return n;
	  };
	  function d3_selection_enter(selection) {
	    d3_subclass(selection, d3_selection_enterPrototype);
	    return selection;
	  }
	  var d3_selection_enterPrototype = [];
	  d3.selection.enter = d3_selection_enter;
	  d3.selection.enter.prototype = d3_selection_enterPrototype;
	  d3_selection_enterPrototype.append = d3_selectionPrototype.append;
	  d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
	  d3_selection_enterPrototype.node = d3_selectionPrototype.node;
	  d3_selection_enterPrototype.call = d3_selectionPrototype.call;
	  d3_selection_enterPrototype.size = d3_selectionPrototype.size;
	  d3_selection_enterPrototype.select = function(selector) {
	    var subgroups = [], subgroup, subnode, upgroup, group, node;
	    for (var j = -1, m = this.length; ++j < m; ) {
	      upgroup = (group = this[j]).update;
	      subgroups.push(subgroup = []);
	      subgroup.parentNode = group.parentNode;
	      for (var i = -1, n = group.length; ++i < n; ) {
	        if (node = group[i]) {
	          subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j));
	          subnode.__data__ = node.__data__;
	        } else {
	          subgroup.push(null);
	        }
	      }
	    }
	    return d3_selection(subgroups);
	  };
	  d3_selection_enterPrototype.insert = function(name, before) {
	    if (arguments.length < 2) before = d3_selection_enterInsertBefore(this);
	    return d3_selectionPrototype.insert.call(this, name, before);
	  };
	  function d3_selection_enterInsertBefore(enter) {
	    var i0, j0;
	    return function(d, i, j) {
	      var group = enter[j].update, n = group.length, node;
	      if (j != j0) j0 = j, i0 = 0;
	      if (i >= i0) i0 = i + 1;
	      while (!(node = group[i0]) && ++i0 < n) ;
	      return node;
	    };
	  }
	  d3.select = function(node) {
	    var group;
	    if (typeof node === "string") {
	      group = [ d3_select(node, d3_document) ];
	      group.parentNode = d3_document.documentElement;
	    } else {
	      group = [ node ];
	      group.parentNode = d3_documentElement(node);
	    }
	    return d3_selection([ group ]);
	  };
	  d3.selectAll = function(nodes) {
	    var group;
	    if (typeof nodes === "string") {
	      group = d3_array(d3_selectAll(nodes, d3_document));
	      group.parentNode = d3_document.documentElement;
	    } else {
	      group = d3_array(nodes);
	      group.parentNode = null;
	    }
	    return d3_selection([ group ]);
	  };
	  d3_selectionPrototype.on = function(type, listener, capture) {
	    var n = arguments.length;
	    if (n < 3) {
	      if (typeof type !== "string") {
	        if (n < 2) listener = false;
	        for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
	        return this;
	      }
	      if (n < 2) return (n = this.node()["__on" + type]) && n._;
	      capture = false;
	    }
	    return this.each(d3_selection_on(type, listener, capture));
	  };
	  function d3_selection_on(type, listener, capture) {
	    var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener;
	    if (i > 0) type = type.slice(0, i);
	    var filter = d3_selection_onFilters.get(type);
	    if (filter) type = filter, wrap = d3_selection_onFilter;
	    function onRemove() {
	      var l = this[name];
	      if (l) {
	        this.removeEventListener(type, l, l.$);
	        delete this[name];
	      }
	    }
	    function onAdd() {
	      var l = wrap(listener, d3_array(arguments));
	      onRemove.call(this);
	      this.addEventListener(type, this[name] = l, l.$ = capture);
	      l._ = listener;
	    }
	    function removeAll() {
	      var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match;
	      for (var name in this) {
	        if (match = name.match(re)) {
	          var l = this[name];
	          this.removeEventListener(match[1], l, l.$);
	          delete this[name];
	        }
	      }
	    }
	    return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll;
	  }
	  var d3_selection_onFilters = d3.map({
	    mouseenter: "mouseover",
	    mouseleave: "mouseout"
	  });
	  if (d3_document) {
	    d3_selection_onFilters.forEach(function(k) {
	      if ("on" + k in d3_document) d3_selection_onFilters.remove(k);
	    });
	  }
	  function d3_selection_onListener(listener, argumentz) {
	    return function(e) {
	      var o = d3.event;
	      d3.event = e;
	      argumentz[0] = this.__data__;
	      try {
	        listener.apply(this, argumentz);
	      } finally {
	        d3.event = o;
	      }
	    };
	  }
	  function d3_selection_onFilter(listener, argumentz) {
	    var l = d3_selection_onListener(listener, argumentz);
	    return function(e) {
	      var target = this, related = e.relatedTarget;
	      if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) {
	        l.call(target, e);
	      }
	    };
	  }
	  var d3_event_dragSelect, d3_event_dragId = 0;
	  function d3_event_dragSuppress(node) {
	    var name = ".dragsuppress-" + ++d3_event_dragId, click = "click" + name, w = d3.select(d3_window(node)).on("touchmove" + name, d3_eventPreventDefault).on("dragstart" + name, d3_eventPreventDefault).on("selectstart" + name, d3_eventPreventDefault);
	    if (d3_event_dragSelect == null) {
	      d3_event_dragSelect = "onselectstart" in node ? false : d3_vendorSymbol(node.style, "userSelect");
	    }
	    if (d3_event_dragSelect) {
	      var style = d3_documentElement(node).style, select = style[d3_event_dragSelect];
	      style[d3_event_dragSelect] = "none";
	    }
	    return function(suppressClick) {
	      w.on(name, null);
	      if (d3_event_dragSelect) style[d3_event_dragSelect] = select;
	      if (suppressClick) {
	        var off = function() {
	          w.on(click, null);
	        };
	        w.on(click, function() {
	          d3_eventPreventDefault();
	          off();
	        }, true);
	        setTimeout(off, 0);
	      }
	    };
	  }
	  d3.mouse = function(container) {
	    return d3_mousePoint(container, d3_eventSource());
	  };
	  var d3_mouse_bug44083 = this.navigator && /WebKit/.test(this.navigator.userAgent) ? -1 : 0;
	  function d3_mousePoint(container, e) {
	    if (e.changedTouches) e = e.changedTouches[0];
	    var svg = container.ownerSVGElement || container;
	    if (svg.createSVGPoint) {
	      var point = svg.createSVGPoint();
	      if (d3_mouse_bug44083 < 0) {
	        var window = d3_window(container);
	        if (window.scrollX || window.scrollY) {
	          svg = d3.select("body").append("svg").style({
	            position: "absolute",
	            top: 0,
	            left: 0,
	            margin: 0,
	            padding: 0,
	            border: "none"
	          }, "important");
	          var ctm = svg[0][0].getScreenCTM();
	          d3_mouse_bug44083 = !(ctm.f || ctm.e);
	          svg.remove();
	        }
	      }
	      if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY; else point.x = e.clientX, 
	      point.y = e.clientY;
	      point = point.matrixTransform(container.getScreenCTM().inverse());
	      return [ point.x, point.y ];
	    }
	    var rect = container.getBoundingClientRect();
	    return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ];
	  }
	  d3.touch = function(container, touches, identifier) {
	    if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches;
	    if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) {
	      if ((touch = touches[i]).identifier === identifier) {
	        return d3_mousePoint(container, touch);
	      }
	    }
	  };
	  d3.behavior.drag = function() {
	    var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, d3_window, "mousemove", "mouseup"), touchstart = dragstart(d3_behavior_dragTouchId, d3.touch, d3_identity, "touchmove", "touchend");
	    function drag() {
	      this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart);
	    }
	    function dragstart(id, position, subject, move, end) {
	      return function() {
	        var that = this, target = d3.event.target.correspondingElement || d3.event.target, parent = that.parentNode, dispatch = event.of(that, arguments), dragged = 0, dragId = id(), dragName = ".drag" + (dragId == null ? "" : "-" + dragId), dragOffset, dragSubject = d3.select(subject(target)).on(move + dragName, moved).on(end + dragName, ended), dragRestore = d3_event_dragSuppress(target), position0 = position(parent, dragId);
	        if (origin) {
	          dragOffset = origin.apply(that, arguments);
	          dragOffset = [ dragOffset.x - position0[0], dragOffset.y - position0[1] ];
	        } else {
	          dragOffset = [ 0, 0 ];
	        }
	        dispatch({
	          type: "dragstart"
	        });
	        function moved() {
	          var position1 = position(parent, dragId), dx, dy;
	          if (!position1) return;
	          dx = position1[0] - position0[0];
	          dy = position1[1] - position0[1];
	          dragged |= dx | dy;
	          position0 = position1;
	          dispatch({
	            type: "drag",
	            x: position1[0] + dragOffset[0],
	            y: position1[1] + dragOffset[1],
	            dx: dx,
	            dy: dy
	          });
	        }
	        function ended() {
	          if (!position(parent, dragId)) return;
	          dragSubject.on(move + dragName, null).on(end + dragName, null);
	          dragRestore(dragged);
	          dispatch({
	            type: "dragend"
	          });
	        }
	      };
	    }
	    drag.origin = function(x) {
	      if (!arguments.length) return origin;
	      origin = x;
	      return drag;
	    };
	    return d3.rebind(drag, event, "on");
	  };
	  function d3_behavior_dragTouchId() {
	    return d3.event.changedTouches[0].identifier;
	  }
	  d3.touches = function(container, touches) {
	    if (arguments.length < 2) touches = d3_eventSource().touches;
	    return touches ? d3_array(touches).map(function(touch) {
	      var point = d3_mousePoint(container, touch);
	      point.identifier = touch.identifier;
	      return point;
	    }) : [];
	  };
	  var ε = 1e-6, ε2 = ε * ε, π = Math.PI, τ = 2 * π, τε = τ - ε, halfπ = π / 2, d3_radians = π / 180, d3_degrees = 180 / π;
	  function d3_sgn(x) {
	    return x > 0 ? 1 : x < 0 ? -1 : 0;
	  }
	  function d3_cross2d(a, b, c) {
	    return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
	  }
	  function d3_acos(x) {
	    return x > 1 ? 0 : x < -1 ? π : Math.acos(x);
	  }
	  function d3_asin(x) {
	    return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x);
	  }
	  function d3_sinh(x) {
	    return ((x = Math.exp(x)) - 1 / x) / 2;
	  }
	  function d3_cosh(x) {
	    return ((x = Math.exp(x)) + 1 / x) / 2;
	  }
	  function d3_tanh(x) {
	    return ((x = Math.exp(2 * x)) - 1) / (x + 1);
	  }
	  function d3_haversin(x) {
	    return (x = Math.sin(x / 2)) * x;
	  }
	  var ρ = Math.SQRT2, ρ2 = 2, ρ4 = 4;
	  d3.interpolateZoom = function(p0, p1) {
	    var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2], dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, i, S;
	    if (d2 < ε2) {
	      S = Math.log(w1 / w0) / ρ;
	      i = function(t) {
	        return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * t * S) ];
	      };
	    } else {
	      var d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
	      S = (r1 - r0) / ρ;
	      i = function(t) {
	        var s = t * S, coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0));
	        return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(ρ * s + r0) ];
	      };
	    }
	    i.duration = S * 1e3;
	    return i;
	  };
	  d3.behavior.zoom = function() {
	    var view = {
	      x: 0,
	      y: 0,
	      k: 1
	    }, translate0, center0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity, duration = 250, zooming = 0, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", mousewheelTimer, touchstart = "touchstart.zoom", touchtime, event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"), x0, x1, y0, y1;
	    if (!d3_behavior_zoomWheel) {
	      d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() {
	        return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1);
	      }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() {
	        return d3.event.wheelDelta;
	      }, "mousewheel") : (d3_behavior_zoomDelta = function() {
	        return -d3.event.detail;
	      }, "MozMousePixelScroll");
	    }
	    function zoom(g) {
	      g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted);
	    }
	    zoom.event = function(g) {
	      g.each(function() {
	        var dispatch = event.of(this, arguments), view1 = view;
	        if (d3_transitionInheritId) {
	          d3.select(this).transition().each("start.zoom", function() {
	            view = this.__chart__ || {
	              x: 0,
	              y: 0,
	              k: 1
	            };
	            zoomstarted(dispatch);
	          }).tween("zoom:zoom", function() {
	            var dx = size[0], dy = size[1], cx = center0 ? center0[0] : dx / 2, cy = center0 ? center0[1] : dy / 2, i = d3.interpolateZoom([ (cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k ], [ (cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k ]);
	            return function(t) {
	              var l = i(t), k = dx / l[2];
	              this.__chart__ = view = {
	                x: cx - l[0] * k,
	                y: cy - l[1] * k,
	                k: k
	              };
	              zoomed(dispatch);
	            };
	          }).each("interrupt.zoom", function() {
	            zoomended(dispatch);
	          }).each("end.zoom", function() {
	            zoomended(dispatch);
	          });
	        } else {
	          this.__chart__ = view;
	          zoomstarted(dispatch);
	          zoomed(dispatch);
	          zoomended(dispatch);
	        }
	      });
	    };
	    zoom.translate = function(_) {
	      if (!arguments.length) return [ view.x, view.y ];
	      view = {
	        x: +_[0],
	        y: +_[1],
	        k: view.k
	      };
	      rescale();
	      return zoom;
	    };
	    zoom.scale = function(_) {
	      if (!arguments.length) return view.k;
	      view = {
	        x: view.x,
	        y: view.y,
	        k: null
	      };
	      scaleTo(+_);
	      rescale();
	      return zoom;
	    };
	    zoom.scaleExtent = function(_) {
	      if (!arguments.length) return scaleExtent;
	      scaleExtent = _ == null ? d3_behavior_zoomInfinity : [ +_[0], +_[1] ];
	      return zoom;
	    };
	    zoom.center = function(_) {
	      if (!arguments.length) return center;
	      center = _ && [ +_[0], +_[1] ];
	      return zoom;
	    };
	    zoom.size = function(_) {
	      if (!arguments.length) return size;
	      size = _ && [ +_[0], +_[1] ];
	      return zoom;
	    };
	    zoom.duration = function(_) {
	      if (!arguments.length) return duration;
	      duration = +_;
	      return zoom;
	    };
	    zoom.x = function(z) {
	      if (!arguments.length) return x1;
	      x1 = z;
	      x0 = z.copy();
	      view = {
	        x: 0,
	        y: 0,
	        k: 1
	      };
	      return zoom;
	    };
	    zoom.y = function(z) {
	      if (!arguments.length) return y1;
	      y1 = z;
	      y0 = z.copy();
	      view = {
	        x: 0,
	        y: 0,
	        k: 1
	      };
	      return zoom;
	    };
	    function location(p) {
	      return [ (p[0] - view.x) / view.k, (p[1] - view.y) / view.k ];
	    }
	    function point(l) {
	      return [ l[0] * view.k + view.x, l[1] * view.k + view.y ];
	    }
	    function scaleTo(s) {
	      view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
	    }
	    function translateTo(p, l) {
	      l = point(l);
	      view.x += p[0] - l[0];
	      view.y += p[1] - l[1];
	    }
	    function zoomTo(that, p, l, k) {
	      that.__chart__ = {
	        x: view.x,
	        y: view.y,
	        k: view.k
	      };
	      scaleTo(Math.pow(2, k));
	      translateTo(center0 = p, l);
	      that = d3.select(that);
	      if (duration > 0) that = that.transition().duration(duration);
	      that.call(zoom.event);
	    }
	    function rescale() {
	      if (x1) x1.domain(x0.range().map(function(x) {
	        return (x - view.x) / view.k;
	      }).map(x0.invert));
	      if (y1) y1.domain(y0.range().map(function(y) {
	        return (y - view.y) / view.k;
	      }).map(y0.invert));
	    }
	    function zoomstarted(dispatch) {
	      if (!zooming++) dispatch({
	        type: "zoomstart"
	      });
	    }
	    function zoomed(dispatch) {
	      rescale();
	      dispatch({
	        type: "zoom",
	        scale: view.k,
	        translate: [ view.x, view.y ]
	      });
	    }
	    function zoomended(dispatch) {
	      if (!--zooming) dispatch({
	        type: "zoomend"
	      }), center0 = null;
	    }
	    function mousedowned() {
	      var that = this, dispatch = event.of(that, arguments), dragged = 0, subject = d3.select(d3_window(that)).on(mousemove, moved).on(mouseup, ended), location0 = location(d3.mouse(that)), dragRestore = d3_event_dragSuppress(that);
	      d3_selection_interrupt.call(that);
	      zoomstarted(dispatch);
	      function moved() {
	        dragged = 1;
	        translateTo(d3.mouse(that), location0);
	        zoomed(dispatch);
	      }
	      function ended() {
	        subject.on(mousemove, null).on(mouseup, null);
	        dragRestore(dragged);
	        zoomended(dispatch);
	      }
	    }
	    function touchstarted() {
	      var that = this, dispatch = event.of(that, arguments), locations0 = {}, distance0 = 0, scale0, zoomName = ".zoom-" + d3.event.changedTouches[0].identifier, touchmove = "touchmove" + zoomName, touchend = "touchend" + zoomName, targets = [], subject = d3.select(that), dragRestore = d3_event_dragSuppress(that);
	      started();
	      zoomstarted(dispatch);
	      subject.on(mousedown, null).on(touchstart, started);
	      function relocate() {
	        var touches = d3.touches(that);
	        scale0 = view.k;
	        touches.forEach(function(t) {
	          if (t.identifier in locations0) locations0[t.identifier] = location(t);
	        });
	        return touches;
	      }
	      function started() {
	        var target = d3.event.target;
	        d3.select(target).on(touchmove, moved).on(touchend, ended);
	        targets.push(target);
	        var changed = d3.event.changedTouches;
	        for (var i = 0, n = changed.length; i < n; ++i) {
	          locations0[changed[i].identifier] = null;
	        }
	        var touches = relocate(), now = Date.now();
	        if (touches.length === 1) {
	          if (now - touchtime < 500) {
	            var p = touches[0];
	            zoomTo(that, p, locations0[p.identifier], Math.floor(Math.log(view.k) / Math.LN2) + 1);
	            d3_eventPreventDefault();
	          }
	          touchtime = now;
	        } else if (touches.length > 1) {
	          var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1];
	          distance0 = dx * dx + dy * dy;
	        }
	      }
	      function moved() {
	        var touches = d3.touches(that), p0, l0, p1, l1;
	        d3_selection_interrupt.call(that);
	        for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
	          p1 = touches[i];
	          if (l1 = locations0[p1.identifier]) {
	            if (l0) break;
	            p0 = p1, l0 = l1;
	          }
	        }
	        if (l1) {
	          var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1, scale1 = distance0 && Math.sqrt(distance1 / distance0);
	          p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];
	          l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];
	          scaleTo(scale1 * scale0);
	        }
	        touchtime = null;
	        translateTo(p0, l0);
	        zoomed(dispatch);
	      }
	      function ended() {
	        if (d3.event.touches.length) {
	          var changed = d3.event.changedTouches;
	          for (var i = 0, n = changed.length; i < n; ++i) {
	            delete locations0[changed[i].identifier];
	          }
	          for (var identifier in locations0) {
	            return void relocate();
	          }
	        }
	        d3.selectAll(targets).on(zoomName, null);
	        subject.on(mousedown, mousedowned).on(touchstart, touchstarted);
	        dragRestore();
	        zoomended(dispatch);
	      }
	    }
	    function mousewheeled() {
	      var dispatch = event.of(this, arguments);
	      if (mousewheelTimer) clearTimeout(mousewheelTimer); else d3_selection_interrupt.call(this), 
	      translate0 = location(center0 = center || d3.mouse(this)), zoomstarted(dispatch);
	      mousewheelTimer = setTimeout(function() {
	        mousewheelTimer = null;
	        zoomended(dispatch);
	      }, 50);
	      d3_eventPreventDefault();
	      scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k);
	      translateTo(center0, translate0);
	      zoomed(dispatch);
	    }
	    function dblclicked() {
	      var p = d3.mouse(this), k = Math.log(view.k) / Math.LN2;
	      zoomTo(this, p, location(p), d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1);
	    }
	    return d3.rebind(zoom, event, "on");
	  };
	  var d3_behavior_zoomInfinity = [ 0, Infinity ], d3_behavior_zoomDelta, d3_behavior_zoomWheel;
	  d3.color = d3_color;
	  function d3_color() {}
	  d3_color.prototype.toString = function() {
	    return this.rgb() + "";
	  };
	  d3.hsl = d3_hsl;
	  function d3_hsl(h, s, l) {
	    return this instanceof d3_hsl ? void (this.h = +h, this.s = +s, this.l = +l) : arguments.length < 2 ? h instanceof d3_hsl ? new d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : new d3_hsl(h, s, l);
	  }
	  var d3_hslPrototype = d3_hsl.prototype = new d3_color();
	  d3_hslPrototype.brighter = function(k) {
	    k = Math.pow(.7, arguments.length ? k : 1);
	    return new d3_hsl(this.h, this.s, this.l / k);
	  };
	  d3_hslPrototype.darker = function(k) {
	    k = Math.pow(.7, arguments.length ? k : 1);
	    return new d3_hsl(this.h, this.s, k * this.l);
	  };
	  d3_hslPrototype.rgb = function() {
	    return d3_hsl_rgb(this.h, this.s, this.l);
	  };
	  function d3_hsl_rgb(h, s, l) {
	    var m1, m2;
	    h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h;
	    s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s;
	    l = l < 0 ? 0 : l > 1 ? 1 : l;
	    m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
	    m1 = 2 * l - m2;
	    function v(h) {
	      if (h > 360) h -= 360; else if (h < 0) h += 360;
	      if (h < 60) return m1 + (m2 - m1) * h / 60;
	      if (h < 180) return m2;
	      if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
	      return m1;
	    }
	    function vv(h) {
	      return Math.round(v(h) * 255);
	    }
	    return new d3_rgb(vv(h + 120), vv(h), vv(h - 120));
	  }
	  d3.hcl = d3_hcl;
	  function d3_hcl(h, c, l) {
	    return this instanceof d3_hcl ? void (this.h = +h, this.c = +c, this.l = +l) : arguments.length < 2 ? h instanceof d3_hcl ? new d3_hcl(h.h, h.c, h.l) : h instanceof d3_lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : new d3_hcl(h, c, l);
	  }
	  var d3_hclPrototype = d3_hcl.prototype = new d3_color();
	  d3_hclPrototype.brighter = function(k) {
	    return new d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));
	  };
	  d3_hclPrototype.darker = function(k) {
	    return new d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)));
	  };
	  d3_hclPrototype.rgb = function() {
	    return d3_hcl_lab(this.h, this.c, this.l).rgb();
	  };
	  function d3_hcl_lab(h, c, l) {
	    if (isNaN(h)) h = 0;
	    if (isNaN(c)) c = 0;
	    return new d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
	  }
	  d3.lab = d3_lab;
	  function d3_lab(l, a, b) {
	    return this instanceof d3_lab ? void (this.l = +l, this.a = +a, this.b = +b) : arguments.length < 2 ? l instanceof d3_lab ? new d3_lab(l.l, l.a, l.b) : l instanceof d3_hcl ? d3_hcl_lab(l.h, l.c, l.l) : d3_rgb_lab((l = d3_rgb(l)).r, l.g, l.b) : new d3_lab(l, a, b);
	  }
	  var d3_lab_K = 18;
	  var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883;
	  var d3_labPrototype = d3_lab.prototype = new d3_color();
	  d3_labPrototype.brighter = function(k) {
	    return new d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
	  };
	  d3_labPrototype.darker = function(k) {
	    return new d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
	  };
	  d3_labPrototype.rgb = function() {
	    return d3_lab_rgb(this.l, this.a, this.b);
	  };
	  function d3_lab_rgb(l, a, b) {
	    var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
	    x = d3_lab_xyz(x) * d3_lab_X;
	    y = d3_lab_xyz(y) * d3_lab_Y;
	    z = d3_lab_xyz(z) * d3_lab_Z;
	    return new d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z));
	  }
	  function d3_lab_hcl(l, a, b) {
	    return l > 0 ? new d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : new d3_hcl(NaN, NaN, l);
	  }
	  function d3_lab_xyz(x) {
	    return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
	  }
	  function d3_xyz_lab(x) {
	    return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
	  }
	  function d3_xyz_rgb(r) {
	    return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055));
	  }
	  d3.rgb = d3_rgb;
	  function d3_rgb(r, g, b) {
	    return this instanceof d3_rgb ? void (this.r = ~~r, this.g = ~~g, this.b = ~~b) : arguments.length < 2 ? r instanceof d3_rgb ? new d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : new d3_rgb(r, g, b);
	  }
	  function d3_rgbNumber(value) {
	    return new d3_rgb(value >> 16, value >> 8 & 255, value & 255);
	  }
	  function d3_rgbString(value) {
	    return d3_rgbNumber(value) + "";
	  }
	  var d3_rgbPrototype = d3_rgb.prototype = new d3_color();
	  d3_rgbPrototype.brighter = function(k) {
	    k = Math.pow(.7, arguments.length ? k : 1);
	    var r = this.r, g = this.g, b = this.b, i = 30;
	    if (!r && !g && !b) return new d3_rgb(i, i, i);
	    if (r && r < i) r = i;
	    if (g && g < i) g = i;
	    if (b && b < i) b = i;
	    return new d3_rgb(Math.min(255, r / k), Math.min(255, g / k), Math.min(255, b / k));
	  };
	  d3_rgbPrototype.darker = function(k) {
	    k = Math.pow(.7, arguments.length ? k : 1);
	    return new d3_rgb(k * this.r, k * this.g, k * this.b);
	  };
	  d3_rgbPrototype.hsl = function() {
	    return d3_rgb_hsl(this.r, this.g, this.b);
	  };
	  d3_rgbPrototype.toString = function() {
	    return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
	  };
	  function d3_rgb_hex(v) {
	    return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16);
	  }
	  function d3_rgb_parse(format, rgb, hsl) {
	    var r = 0, g = 0, b = 0, m1, m2, color;
	    m1 = /([a-z]+)\((.*)\)/.exec(format = format.toLowerCase());
	    if (m1) {
	      m2 = m1[2].split(",");
	      switch (m1[1]) {
	       case "hsl":
	        {
	          return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100);
	        }
	
	       case "rgb":
	        {
	          return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2]));
	        }
	      }
	    }
	    if (color = d3_rgb_names.get(format)) {
	      return rgb(color.r, color.g, color.b);
	    }
	    if (format != null && format.charAt(0) === "#" && !isNaN(color = parseInt(format.slice(1), 16))) {
	      if (format.length === 4) {
	        r = (color & 3840) >> 4;
	        r = r >> 4 | r;
	        g = color & 240;
	        g = g >> 4 | g;
	        b = color & 15;
	        b = b << 4 | b;
	      } else if (format.length === 7) {
	        r = (color & 16711680) >> 16;
	        g = (color & 65280) >> 8;
	        b = color & 255;
	      }
	    }
	    return rgb(r, g, b);
	  }
	  function d3_rgb_hsl(r, g, b) {
	    var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2;
	    if (d) {
	      s = l < .5 ? d / (max + min) : d / (2 - max - min);
	      if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4;
	      h *= 60;
	    } else {
	      h = NaN;
	      s = l > 0 && l < 1 ? 0 : h;
	    }
	    return new d3_hsl(h, s, l);
	  }
	  function d3_rgb_lab(r, g, b) {
	    r = d3_rgb_xyz(r);
	    g = d3_rgb_xyz(g);
	    b = d3_rgb_xyz(b);
	    var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z);
	    return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
	  }
	  function d3_rgb_xyz(r) {
	    return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4);
	  }
	  function d3_rgb_parseNumber(c) {
	    var f = parseFloat(c);
	    return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
	  }
	  var d3_rgb_names = d3.map({
	    aliceblue: 15792383,
	    antiquewhite: 16444375,
	    aqua: 65535,
	    aquamarine: 8388564,
	    azure: 15794175,
	    beige: 16119260,
	    bisque: 16770244,
	    black: 0,
	    blanchedalmond: 16772045,
	    blue: 255,
	    blueviolet: 9055202,
	    brown: 10824234,
	    burlywood: 14596231,
	    cadetblue: 6266528,
	    chartreuse: 8388352,
	    chocolate: 13789470,
	    coral: 16744272,
	    cornflowerblue: 6591981,
	    cornsilk: 16775388,
	    crimson: 14423100,
	    cyan: 65535,
	    darkblue: 139,
	    darkcyan: 35723,
	    darkgoldenrod: 12092939,
	    darkgray: 11119017,
	    darkgreen: 25600,
	    darkgrey: 11119017,
	    darkkhaki: 12433259,
	    darkmagenta: 9109643,
	    darkolivegreen: 5597999,
	    darkorange: 16747520,
	    darkorchid: 10040012,
	    darkred: 9109504,
	    darksalmon: 15308410,
	    darkseagreen: 9419919,
	    darkslateblue: 4734347,
	    darkslategray: 3100495,
	    darkslategrey: 3100495,
	    darkturquoise: 52945,
	    darkviolet: 9699539,
	    deeppink: 16716947,
	    deepskyblue: 49151,
	    dimgray: 6908265,
	    dimgrey: 6908265,
	    dodgerblue: 2003199,
	    firebrick: 11674146,
	    floralwhite: 16775920,
	    forestgreen: 2263842,
	    fuchsia: 16711935,
	    gainsboro: 14474460,
	    ghostwhite: 16316671,
	    gold: 16766720,
	    goldenrod: 14329120,
	    gray: 8421504,
	    green: 32768,
	    greenyellow: 11403055,
	    grey: 8421504,
	    honeydew: 15794160,
	    hotpink: 16738740,
	    indianred: 13458524,
	    indigo: 4915330,
	    ivory: 16777200,
	    khaki: 15787660,
	    lavender: 15132410,
	    lavenderblush: 16773365,
	    lawngreen: 8190976,
	    lemonchiffon: 16775885,
	    lightblue: 11393254,
	    lightcoral: 15761536,
	    lightcyan: 14745599,
	    lightgoldenrodyellow: 16448210,
	    lightgray: 13882323,
	    lightgreen: 9498256,
	    lightgrey: 13882323,
	    lightpink: 16758465,
	    lightsalmon: 16752762,
	    lightseagreen: 2142890,
	    lightskyblue: 8900346,
	    lightslategray: 7833753,
	    lightslategrey: 7833753,
	    lightsteelblue: 11584734,
	    lightyellow: 16777184,
	    lime: 65280,
	    limegreen: 3329330,
	    linen: 16445670,
	    magenta: 16711935,
	    maroon: 8388608,
	    mediumaquamarine: 6737322,
	    mediumblue: 205,
	    mediumorchid: 12211667,
	    mediumpurple: 9662683,
	    mediumseagreen: 3978097,
	    mediumslateblue: 8087790,
	    mediumspringgreen: 64154,
	    mediumturquoise: 4772300,
	    mediumvioletred: 13047173,
	    midnightblue: 1644912,
	    mintcream: 16121850,
	    mistyrose: 16770273,
	    moccasin: 16770229,
	    navajowhite: 16768685,
	    navy: 128,
	    oldlace: 16643558,
	    olive: 8421376,
	    olivedrab: 7048739,
	    orange: 16753920,
	    orangered: 16729344,
	    orchid: 14315734,
	    palegoldenrod: 15657130,
	    palegreen: 10025880,
	    paleturquoise: 11529966,
	    palevioletred: 14381203,
	    papayawhip: 16773077,
	    peachpuff: 16767673,
	    peru: 13468991,
	    pink: 16761035,
	    plum: 14524637,
	    powderblue: 11591910,
	    purple: 8388736,
	    rebeccapurple: 6697881,
	    red: 16711680,
	    rosybrown: 12357519,
	    royalblue: 4286945,
	    saddlebrown: 9127187,
	    salmon: 16416882,
	    sandybrown: 16032864,
	    seagreen: 3050327,
	    seashell: 16774638,
	    sienna: 10506797,
	    silver: 12632256,
	    skyblue: 8900331,
	    slateblue: 6970061,
	    slategray: 7372944,
	    slategrey: 7372944,
	    snow: 16775930,
	    springgreen: 65407,
	    steelblue: 4620980,
	    tan: 13808780,
	    teal: 32896,
	    thistle: 14204888,
	    tomato: 16737095,
	    turquoise: 4251856,
	    violet: 15631086,
	    wheat: 16113331,
	    white: 16777215,
	    whitesmoke: 16119285,
	    yellow: 16776960,
	    yellowgreen: 10145074
	  });
	  d3_rgb_names.forEach(function(key, value) {
	    d3_rgb_names.set(key, d3_rgbNumber(value));
	  });
	  function d3_functor(v) {
	    return typeof v === "function" ? v : function() {
	      return v;
	    };
	  }
	  d3.functor = d3_functor;
	  d3.xhr = d3_xhrType(d3_identity);
	  function d3_xhrType(response) {
	    return function(url, mimeType, callback) {
	      if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, 
	      mimeType = null;
	      return d3_xhr(url, mimeType, response, callback);
	    };
	  }
	  function d3_xhr(url, mimeType, response, callback) {
	    var xhr = {}, dispatch = d3.dispatch("beforesend", "progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null;
	    if (this.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest();
	    "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() {
	      request.readyState > 3 && respond();
	    };
	    function respond() {
	      var status = request.status, result;
	      if (!status && d3_xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) {
	        try {
	          result = response.call(xhr, request);
	        } catch (e) {
	          dispatch.error.call(xhr, e);
	          return;
	        }
	        dispatch.load.call(xhr, result);
	      } else {
	        dispatch.error.call(xhr, request);
	      }
	    }
	    request.onprogress = function(event) {
	      var o = d3.event;
	      d3.event = event;
	      try {
	        dispatch.progress.call(xhr, request);
	      } finally {
	        d3.event = o;
	      }
	    };
	    xhr.header = function(name, value) {
	      name = (name + "").toLowerCase();
	      if (arguments.length < 2) return headers[name];
	      if (value == null) delete headers[name]; else headers[name] = value + "";
	      return xhr;
	    };
	    xhr.mimeType = function(value) {
	      if (!arguments.length) return mimeType;
	      mimeType = value == null ? null : value + "";
	      return xhr;
	    };
	    xhr.responseType = function(value) {
	      if (!arguments.length) return responseType;
	      responseType = value;
	      return xhr;
	    };
	    xhr.response = function(value) {
	      response = value;
	      return xhr;
	    };
	    [ "get", "post" ].forEach(function(method) {
	      xhr[method] = function() {
	        return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments)));
	      };
	    });
	    xhr.send = function(method, data, callback) {
	      if (arguments.length === 2 && typeof data === "function") callback = data, data = null;
	      request.open(method, url, true);
	      if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*";
	      if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]);
	      if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType);
	      if (responseType != null) request.responseType = responseType;
	      if (callback != null) xhr.on("error", callback).on("load", function(request) {
	        callback(null, request);
	      });
	      dispatch.beforesend.call(xhr, request);
	      request.send(data == null ? null : data);
	      return xhr;
	    };
	    xhr.abort = function() {
	      request.abort();
	      return xhr;
	    };
	    d3.rebind(xhr, dispatch, "on");
	    return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));
	  }
	  function d3_xhr_fixCallback(callback) {
	    return callback.length === 1 ? function(error, request) {
	      callback(error == null ? request : null);
	    } : callback;
	  }
	  function d3_xhrHasResponse(request) {
	    var type = request.responseType;
	    return type && type !== "text" ? request.response : request.responseText;
	  }
	  d3.dsv = function(delimiter, mimeType) {
	    var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0);
	    function dsv(url, row, callback) {
	      if (arguments.length < 3) callback = row, row = null;
	      var xhr = d3_xhr(url, mimeType, row == null ? response : typedResponse(row), callback);
	      xhr.row = function(_) {
	        return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row;
	      };
	      return xhr;
	    }
	    function response(request) {
	      return dsv.parse(request.responseText);
	    }
	    function typedResponse(f) {
	      return function(request) {
	        return dsv.parse(request.responseText, f);
	      };
	    }
	    dsv.parse = function(text, f) {
	      var o;
	      return dsv.parseRows(text, function(row, i) {
	        if (o) return o(row, i - 1);
	        var a = new Function("d", "return {" + row.map(function(name, i) {
	          return JSON.stringify(name) + ": d[" + i + "]";
	        }).join(",") + "}");
	        o = f ? function(row, i) {
	          return f(a(row), i);
	        } : a;
	      });
	    };
	    dsv.parseRows = function(text, f) {
	      var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol;
	      function token() {
	        if (I >= N) return EOF;
	        if (eol) return eol = false, EOL;
	        var j = I;
	        if (text.charCodeAt(j) === 34) {
	          var i = j;
	          while (i++ < N) {
	            if (text.charCodeAt(i) === 34) {
	              if (text.charCodeAt(i + 1) !== 34) break;
	              ++i;
	            }
	          }
	          I = i + 2;
	          var c = text.charCodeAt(i + 1);
	          if (c === 13) {
	            eol = true;
	            if (text.charCodeAt(i + 2) === 10) ++I;
	          } else if (c === 10) {
	            eol = true;
	          }
	          return text.slice(j + 1, i).replace(/""/g, '"');
	        }
	        while (I < N) {
	          var c = text.charCodeAt(I++), k = 1;
	          if (c === 10) eol = true; else if (c === 13) {
	            eol = true;
	            if (text.charCodeAt(I) === 10) ++I, ++k;
	          } else if (c !== delimiterCode) continue;
	          return text.slice(j, I - k);
	        }
	        return text.slice(j);
	      }
	      while ((t = token()) !== EOF) {
	        var a = [];
	        while (t !== EOL && t !== EOF) {
	          a.push(t);
	          t = token();
	        }
	        if (f && (a = f(a, n++)) == null) continue;
	        rows.push(a);
	      }
	      return rows;
	    };
	    dsv.format = function(rows) {
	      if (Array.isArray(rows[0])) return dsv.formatRows(rows);
	      var fieldSet = new d3_Set(), fields = [];
	      rows.forEach(function(row) {
	        for (var field in row) {
	          if (!fieldSet.has(field)) {
	            fields.push(fieldSet.add(field));
	          }
	        }
	      });
	      return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) {
	        return fields.map(function(field) {
	          return formatValue(row[field]);
	        }).join(delimiter);
	      })).join("\n");
	    };
	    dsv.formatRows = function(rows) {
	      return rows.map(formatRow).join("\n");
	    };
	    function formatRow(row) {
	      return row.map(formatValue).join(delimiter);
	    }
	    function formatValue(text) {
	      return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text;
	    }
	    return dsv;
	  };
	  d3.csv = d3.dsv(",", "text/csv");
	  d3.tsv = d3.dsv("	", "text/tab-separated-values");
	  var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_frame = this[d3_vendorSymbol(this, "requestAnimationFrame")] || function(callback) {
	    setTimeout(callback, 17);
	  };
	  d3.timer = function() {
	    d3_timer.apply(this, arguments);
	  };
	  function d3_timer(callback, delay, then) {
	    var n = arguments.length;
	    if (n < 2) delay = 0;
	    if (n < 3) then = Date.now();
	    var time = then + delay, timer = {
	      c: callback,
	      t: time,
	      n: null
	    };
	    if (d3_timer_queueTail) d3_timer_queueTail.n = timer; else d3_timer_queueHead = timer;
	    d3_timer_queueTail = timer;
	    if (!d3_timer_interval) {
	      d3_timer_timeout = clearTimeout(d3_timer_timeout);
	      d3_timer_interval = 1;
	      d3_timer_frame(d3_timer_step);
	    }
	    return timer;
	  }
	  function d3_timer_step() {
	    var now = d3_timer_mark(), delay = d3_timer_sweep() - now;
	    if (delay > 24) {
	      if (isFinite(delay)) {
	        clearTimeout(d3_timer_timeout);
	        d3_timer_timeout = setTimeout(d3_timer_step, delay);
	      }
	      d3_timer_interval = 0;
	    } else {
	      d3_timer_interval = 1;
	      d3_timer_frame(d3_timer_step);
	    }
	  }
	  d3.timer.flush = function() {
	    d3_timer_mark();
	    d3_timer_sweep();
	  };
	  function d3_timer_mark() {
	    var now = Date.now(), timer = d3_timer_queueHead;
	    while (timer) {
	      if (now >= timer.t && timer.c(now - timer.t)) timer.c = null;
	      timer = timer.n;
	    }
	    return now;
	  }
	  function d3_timer_sweep() {
	    var t0, t1 = d3_timer_queueHead, time = Infinity;
	    while (t1) {
	      if (t1.c) {
	        if (t1.t < time) time = t1.t;
	        t1 = (t0 = t1).n;
	      } else {
	        t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n;
	      }
	    }
	    d3_timer_queueTail = t0;
	    return time;
	  }
	  function d3_format_precision(x, p) {
	    return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1);
	  }
	  d3.round = function(x, n) {
	    return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);
	  };
	  var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix);
	  d3.formatPrefix = function(value, precision) {
	    var i = 0;
	    if (value = +value) {
	      if (value < 0) value *= -1;
	      if (precision) value = d3.round(value, d3_format_precision(value, precision));
	      i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
	      i = Math.max(-24, Math.min(24, Math.floor((i - 1) / 3) * 3));
	    }
	    return d3_formatPrefixes[8 + i / 3];
	  };
	  function d3_formatPrefix(d, i) {
	    var k = Math.pow(10, abs(8 - i) * 3);
	    return {
	      scale: i > 8 ? function(d) {
	        return d / k;
	      } : function(d) {
	        return d * k;
	      },
	      symbol: d
	    };
	  }
	  function d3_locale_numberFormat(locale) {
	    var locale_decimal = locale.decimal, locale_thousands = locale.thousands, locale_grouping = locale.grouping, locale_currency = locale.currency, formatGroup = locale_grouping && locale_thousands ? function(value, width) {
	      var i = value.length, t = [], j = 0, g = locale_grouping[0], length = 0;
	      while (i > 0 && g > 0) {
	        if (length + g + 1 > width) g = Math.max(1, width - length);
	        t.push(value.substring(i -= g, i + g));
	        if ((length += g + 1) > width) break;
	        g = locale_grouping[j = (j + 1) % locale_grouping.length];
	      }
	      return t.reverse().join(locale_thousands);
	    } : d3_identity;
	    return function(specifier) {
	      var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "-", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, prefix = "", suffix = "", integer = false, exponent = true;
	      if (precision) precision = +precision.substring(1);
	      if (zfill || fill === "0" && align === "=") {
	        zfill = fill = "0";
	        align = "=";
	      }
	      switch (type) {
	       case "n":
	        comma = true;
	        type = "g";
	        break;
	
	       case "%":
	        scale = 100;
	        suffix = "%";
	        type = "f";
	        break;
	
	       case "p":
	        scale = 100;
	        suffix = "%";
	        type = "r";
	        break;
	
	       case "b":
	       case "o":
	       case "x":
	       case "X":
	        if (symbol === "#") prefix = "0" + type.toLowerCase();
	
	       case "c":
	        exponent = false;
	
	       case "d":
	        integer = true;
	        precision = 0;
	        break;
	
	       case "s":
	        scale = -1;
	        type = "r";
	        break;
	      }
	      if (symbol === "$") prefix = locale_currency[0], suffix = locale_currency[1];
	      if (type == "r" && !precision) type = "g";
	      if (precision != null) {
	        if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision));
	      }
	      type = d3_format_types.get(type) || d3_format_typeDefault;
	      var zcomma = zfill && comma;
	      return function(value) {
	        var fullSuffix = suffix;
	        if (integer && value % 1) return "";
	        var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign === "-" ? "" : sign;
	        if (scale < 0) {
	          var unit = d3.formatPrefix(value, precision);
	          value = unit.scale(value);
	          fullSuffix = unit.symbol + suffix;
	        } else {
	          value *= scale;
	        }
	        value = type(value, precision);
	        var i = value.lastIndexOf("."), before, after;
	        if (i < 0) {
	          var j = exponent ? value.lastIndexOf("e") : -1;
	          if (j < 0) before = value, after = ""; else before = value.substring(0, j), after = value.substring(j);
	        } else {
	          before = value.substring(0, i);
	          after = locale_decimal + value.substring(i + 1);
	        }
	        if (!zfill && comma) before = formatGroup(before, Infinity);
	        var length = prefix.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : "";
	        if (zcomma) before = formatGroup(padding + before, padding.length ? width - after.length : Infinity);
	        negative += prefix;
	        value = before + after;
	        return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + fullSuffix;
	      };
	    };
	  }
	  var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;
	  var d3_format_types = d3.map({
	    b: function(x) {
	      return x.toString(2);
	    },
	    c: function(x) {
	      return String.fromCharCode(x);
	    },
	    o: function(x) {
	      return x.toString(8);
	    },
	    x: function(x) {
	      return x.toString(16);
	    },
	    X: function(x) {
	      return x.toString(16).toUpperCase();
	    },
	    g: function(x, p) {
	      return x.toPrecision(p);
	    },
	    e: function(x, p) {
	      return x.toExponential(p);
	    },
	    f: function(x, p) {
	      return x.toFixed(p);
	    },
	    r: function(x, p) {
	      return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p))));
	    }
	  });
	  function d3_format_typeDefault(x) {
	    return x + "";
	  }
	  var d3_time = d3.time = {}, d3_date = Date;
	  function d3_date_utc() {
	    this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]);
	  }
	  d3_date_utc.prototype = {
	    getDate: function() {
	      return this._.getUTCDate();
	    },
	    getDay: function() {
	      return this._.getUTCDay();
	    },
	    getFullYear: function() {
	      return this._.getUTCFullYear();
	    },
	    getHours: function() {
	      return this._.getUTCHours();
	    },
	    getMilliseconds: function() {
	      return this._.getUTCMilliseconds();
	    },
	    getMinutes: function() {
	      return this._.getUTCMinutes();
	    },
	    getMonth: function() {
	      return this._.getUTCMonth();
	    },
	    getSeconds: function() {
	      return this._.getUTCSeconds();
	    },
	    getTime: function() {
	      return this._.getTime();
	    },
	    getTimezoneOffset: function() {
	      return 0;
	    },
	    valueOf: function() {
	      return this._.valueOf();
	    },
	    setDate: function() {
	      d3_time_prototype.setUTCDate.apply(this._, arguments);
	    },
	    setDay: function() {
	      d3_time_prototype.setUTCDay.apply(this._, arguments);
	    },
	    setFullYear: function() {
	      d3_time_prototype.setUTCFullYear.apply(this._, arguments);
	    },
	    setHours: function() {
	      d3_time_prototype.setUTCHours.apply(this._, arguments);
	    },
	    setMilliseconds: function() {
	      d3_time_prototype.setUTCMilliseconds.apply(this._, arguments);
	    },
	    setMinutes: function() {
	      d3_time_prototype.setUTCMinutes.apply(this._, arguments);
	    },
	    setMonth: function() {
	      d3_time_prototype.setUTCMonth.apply(this._, arguments);
	    },
	    setSeconds: function() {
	      d3_time_prototype.setUTCSeconds.apply(this._, arguments);
	    },
	    setTime: function() {
	      d3_time_prototype.setTime.apply(this._, arguments);
	    }
	  };
	  var d3_time_prototype = Date.prototype;
	  function d3_time_interval(local, step, number) {
	    function round(date) {
	      var d0 = local(date), d1 = offset(d0, 1);
	      return date - d0 < d1 - date ? d0 : d1;
	    }
	    function ceil(date) {
	      step(date = local(new d3_date(date - 1)), 1);
	      return date;
	    }
	    function offset(date, k) {
	      step(date = new d3_date(+date), k);
	      return date;
	    }
	    function range(t0, t1, dt) {
	      var time = ceil(t0), times = [];
	      if (dt > 1) {
	        while (time < t1) {
	          if (!(number(time) % dt)) times.push(new Date(+time));
	          step(time, 1);
	        }
	      } else {
	        while (time < t1) times.push(new Date(+time)), step(time, 1);
	      }
	      return times;
	    }
	    function range_utc(t0, t1, dt) {
	      try {
	        d3_date = d3_date_utc;
	        var utc = new d3_date_utc();
	        utc._ = t0;
	        return range(utc, t1, dt);
	      } finally {
	        d3_date = Date;
	      }
	    }
	    local.floor = local;
	    local.round = round;
	    local.ceil = ceil;
	    local.offset = offset;
	    local.range = range;
	    var utc = local.utc = d3_time_interval_utc(local);
	    utc.floor = utc;
	    utc.round = d3_time_interval_utc(round);
	    utc.ceil = d3_time_interval_utc(ceil);
	    utc.offset = d3_time_interval_utc(offset);
	    utc.range = range_utc;
	    return local;
	  }
	  function d3_time_interval_utc(method) {
	    return function(date, k) {
	      try {
	        d3_date = d3_date_utc;
	        var utc = new d3_date_utc();
	        utc._ = date;
	        return method(utc, k)._;
	      } finally {
	        d3_date = Date;
	      }
	    };
	  }
	  d3_time.year = d3_time_interval(function(date) {
	    date = d3_time.day(date);
	    date.setMonth(0, 1);
	    return date;
	  }, function(date, offset) {
	    date.setFullYear(date.getFullYear() + offset);
	  }, function(date) {
	    return date.getFullYear();
	  });
	  d3_time.years = d3_time.year.range;
	  d3_time.years.utc = d3_time.year.utc.range;
	  d3_time.day = d3_time_interval(function(date) {
	    var day = new d3_date(2e3, 0);
	    day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
	    return day;
	  }, function(date, offset) {
	    date.setDate(date.getDate() + offset);
	  }, function(date) {
	    return date.getDate() - 1;
	  });
	  d3_time.days = d3_time.day.range;
	  d3_time.days.utc = d3_time.day.utc.range;
	  d3_time.dayOfYear = function(date) {
	    var year = d3_time.year(date);
	    return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5);
	  };
	  [ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ].forEach(function(day, i) {
	    i = 7 - i;
	    var interval = d3_time[day] = d3_time_interval(function(date) {
	      (date = d3_time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7);
	      return date;
	    }, function(date, offset) {
	      date.setDate(date.getDate() + Math.floor(offset) * 7);
	    }, function(date) {
	      var day = d3_time.year(date).getDay();
	      return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i);
	    });
	    d3_time[day + "s"] = interval.range;
	    d3_time[day + "s"].utc = interval.utc.range;
	    d3_time[day + "OfYear"] = function(date) {
	      var day = d3_time.year(date).getDay();
	      return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7);
	    };
	  });
	  d3_time.week = d3_time.sunday;
	  d3_time.weeks = d3_time.sunday.range;
	  d3_time.weeks.utc = d3_time.sunday.utc.range;
	  d3_time.weekOfYear = d3_time.sundayOfYear;
	  function d3_locale_timeFormat(locale) {
	    var locale_dateTime = locale.dateTime, locale_date = locale.date, locale_time = locale.time, locale_periods = locale.periods, locale_days = locale.days, locale_shortDays = locale.shortDays, locale_months = locale.months, locale_shortMonths = locale.shortMonths;
	    function d3_time_format(template) {
	      var n = template.length;
	      function format(date) {
	        var string = [], i = -1, j = 0, c, p, f;
	        while (++i < n) {
	          if (template.charCodeAt(i) === 37) {
	            string.push(template.slice(j, i));
	            if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i);
	            if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p);
	            string.push(c);
	            j = i + 1;
	          }
	        }
	        string.push(template.slice(j, i));
	        return string.join("");
	      }
	      format.parse = function(string) {
	        var d = {
	          y: 1900,
	          m: 0,
	          d: 1,
	          H: 0,
	          M: 0,
	          S: 0,
	          L: 0,
	          Z: null
	        }, i = d3_time_parse(d, template, string, 0);
	        if (i != string.length) return null;
	        if ("p" in d) d.H = d.H % 12 + d.p * 12;
	        var localZ = d.Z != null && d3_date !== d3_date_utc, date = new (localZ ? d3_date_utc : d3_date)();
	        if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("W" in d || "U" in d) {
	          if (!("w" in d)) d.w = "W" in d ? 1 : 0;
	          date.setFullYear(d.y, 0, 1);
	          date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7);
	        } else date.setFullYear(d.y, d.m, d.d);
	        date.setHours(d.H + (d.Z / 100 | 0), d.M + d.Z % 100, d.S, d.L);
	        return localZ ? date._ : date;
	      };
	      format.toString = function() {
	        return template;
	      };
	      return format;
	    }
	    function d3_time_parse(date, template, string, j) {
	      var c, p, t, i = 0, n = template.length, m = string.length;
	      while (i < n) {
	        if (j >= m) return -1;
	        c = template.charCodeAt(i++);
	        if (c === 37) {
	          t = template.charAt(i++);
	          p = d3_time_parsers[t in d3_time_formatPads ? template.charAt(i++) : t];
	          if (!p || (j = p(date, string, j)) < 0) return -1;
	        } else if (c != string.charCodeAt(j++)) {
	          return -1;
	        }
	      }
	      return j;
	    }
	    d3_time_format.utc = function(template) {
	      var local = d3_time_format(template);
	      function format(date) {
	        try {
	          d3_date = d3_date_utc;
	          var utc = new d3_date();
	          utc._ = date;
	          return local(utc);
	        } finally {
	          d3_date = Date;
	        }
	      }
	      format.parse = function(string) {
	        try {
	          d3_date = d3_date_utc;
	          var date = local.parse(string);
	          return date && date._;
	        } finally {
	          d3_date = Date;
	        }
	      };
	      format.toString = local.toString;
	      return format;
	    };
	    d3_time_format.multi = d3_time_format.utc.multi = d3_time_formatMulti;
	    var d3_time_periodLookup = d3.map(), d3_time_dayRe = d3_time_formatRe(locale_days), d3_time_dayLookup = d3_time_formatLookup(locale_days), d3_time_dayAbbrevRe = d3_time_formatRe(locale_shortDays), d3_time_dayAbbrevLookup = d3_time_formatLookup(locale_shortDays), d3_time_monthRe = d3_time_formatRe(locale_months), d3_time_monthLookup = d3_time_formatLookup(locale_months), d3_time_monthAbbrevRe = d3_time_formatRe(locale_shortMonths), d3_time_monthAbbrevLookup = d3_time_formatLookup(locale_shortMonths);
	    locale_periods.forEach(function(p, i) {
	      d3_time_periodLookup.set(p.toLowerCase(), i);
	    });
	    var d3_time_formats = {
	      a: function(d) {
	        return locale_shortDays[d.getDay()];
	      },
	      A: function(d) {
	        return locale_days[d.getDay()];
	      },
	      b: function(d) {
	        return locale_shortMonths[d.getMonth()];
	      },
	      B: function(d) {
	        return locale_months[d.getMonth()];
	      },
	      c: d3_time_format(locale_dateTime),
	      d: function(d, p) {
	        return d3_time_formatPad(d.getDate(), p, 2);
	      },
	      e: function(d, p) {
	        return d3_time_formatPad(d.getDate(), p, 2);
	      },
	      H: function(d, p) {
	        return d3_time_formatPad(d.getHours(), p, 2);
	      },
	      I: function(d, p) {
	        return d3_time_formatPad(d.getHours() % 12 || 12, p, 2);
	      },
	      j: function(d, p) {
	        return d3_time_formatPad(1 + d3_time.dayOfYear(d), p, 3);
	      },
	      L: function(d, p) {
	        return d3_time_formatPad(d.getMilliseconds(), p, 3);
	      },
	      m: function(d, p) {
	        return d3_time_formatPad(d.getMonth() + 1, p, 2);
	      },
	      M: function(d, p) {
	        return d3_time_formatPad(d.getMinutes(), p, 2);
	      },
	      p: function(d) {
	        return locale_periods[+(d.getHours() >= 12)];
	      },
	      S: function(d, p) {
	        return d3_time_formatPad(d.getSeconds(), p, 2);
	      },
	      U: function(d, p) {
	        return d3_time_formatPad(d3_time.sundayOfYear(d), p, 2);
	      },
	      w: function(d) {
	        return d.getDay();
	      },
	      W: function(d, p) {
	        return d3_time_formatPad(d3_time.mondayOfYear(d), p, 2);
	      },
	      x: d3_time_format(locale_date),
	      X: d3_time_format(locale_time),
	      y: function(d, p) {
	        return d3_time_formatPad(d.getFullYear() % 100, p, 2);
	      },
	      Y: function(d, p) {
	        return d3_time_formatPad(d.getFullYear() % 1e4, p, 4);
	      },
	      Z: d3_time_zone,
	      "%": function() {
	        return "%";
	      }
	    };
	    var d3_time_parsers = {
	      a: d3_time_parseWeekdayAbbrev,
	      A: d3_time_parseWeekday,
	      b: d3_time_parseMonthAbbrev,
	      B: d3_time_parseMonth,
	      c: d3_time_parseLocaleFull,
	      d: d3_time_parseDay,
	      e: d3_time_parseDay,
	      H: d3_time_parseHour24,
	      I: d3_time_parseHour24,
	      j: d3_time_parseDayOfYear,
	      L: d3_time_parseMilliseconds,
	      m: d3_time_parseMonthNumber,
	      M: d3_time_parseMinutes,
	      p: d3_time_parseAmPm,
	      S: d3_time_parseSeconds,
	      U: d3_time_parseWeekNumberSunday,
	      w: d3_time_parseWeekdayNumber,
	      W: d3_time_parseWeekNumberMonday,
	      x: d3_time_parseLocaleDate,
	      X: d3_time_parseLocaleTime,
	      y: d3_time_parseYear,
	      Y: d3_time_parseFullYear,
	      Z: d3_time_parseZone,
	      "%": d3_time_parseLiteralPercent
	    };
	    function d3_time_parseWeekdayAbbrev(date, string, i) {
	      d3_time_dayAbbrevRe.lastIndex = 0;
	      var n = d3_time_dayAbbrevRe.exec(string.slice(i));
	      return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
	    }
	    function d3_time_parseWeekday(date, string, i) {
	      d3_time_dayRe.lastIndex = 0;
	      var n = d3_time_dayRe.exec(string.slice(i));
	      return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
	    }
	    function d3_time_parseMonthAbbrev(date, string, i) {
	      d3_time_monthAbbrevRe.lastIndex = 0;
	      var n = d3_time_monthAbbrevRe.exec(string.slice(i));
	      return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
	    }
	    function d3_time_parseMonth(date, string, i) {
	      d3_time_monthRe.lastIndex = 0;
	      var n = d3_time_monthRe.exec(string.slice(i));
	      return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
	    }
	    function d3_time_parseLocaleFull(date, string, i) {
	      return d3_time_parse(date, d3_time_formats.c.toString(), string, i);
	    }
	    function d3_time_parseLocaleDate(date, string, i) {
	      return d3_time_parse(date, d3_time_formats.x.toString(), string, i);
	    }
	    function d3_time_parseLocaleTime(date, string, i) {
	      return d3_time_parse(date, d3_time_formats.X.toString(), string, i);
	    }
	    function d3_time_parseAmPm(date, string, i) {
	      var n = d3_time_periodLookup.get(string.slice(i, i += 2).toLowerCase());
	      return n == null ? -1 : (date.p = n, i);
	    }
	    return d3_time_format;
	  }
	  var d3_time_formatPads = {
	    "-": "",
	    _: " ",
	    "0": "0"
	  }, d3_time_numberRe = /^\s*\d+/, d3_time_percentRe = /^%/;
	  function d3_time_formatPad(value, fill, width) {
	    var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length;
	    return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
	  }
	  function d3_time_formatRe(names) {
	    return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i");
	  }
	  function d3_time_formatLookup(names) {
	    var map = new d3_Map(), i = -1, n = names.length;
	    while (++i < n) map.set(names[i].toLowerCase(), i);
	    return map;
	  }
	  function d3_time_parseWeekdayNumber(date, string, i) {
	    d3_time_numberRe.lastIndex = 0;
	    var n = d3_time_numberRe.exec(string.slice(i, i + 1));
	    return n ? (date.w = +n[0], i + n[0].length) : -1;
	  }
	  function d3_time_parseWeekNumberSunday(date, string, i) {
	    d3_time_numberRe.lastIndex = 0;
	    var n = d3_time_numberRe.exec(string.slice(i));
	    return n ? (date.U = +n[0], i + n[0].length) : -1;
	  }
	  function d3_time_parseWeekNumberMonday(date, string, i) {
	    d3_time_numberRe.lastIndex = 0;
	    var n = d3_time_numberRe.exec(string.slice(i));
	    return n ? (date.W = +n[0], i + n[0].length) : -1;
	  }
	  function d3_time_parseFullYear(date, string, i) {
	    d3_time_numberRe.lastIndex = 0;
	    var n = d3_time_numberRe.exec(string.slice(i, i + 4));
	    return n ? (date.y = +n[0], i + n[0].length) : -1;
	  }
	  function d3_time_parseYear(date, string, i) {
	    d3_time_numberRe.lastIndex = 0;
	    var n = d3_time_numberRe.exec(string.slice(i, i + 2));
	    return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1;
	  }
	  function d3_time_parseZone(date, string, i) {
	    return /^[+-]\d{4}$/.test(string = string.slice(i, i + 5)) ? (date.Z = -string, 
	    i + 5) : -1;
	  }
	  function d3_time_expandYear(d) {
	    return d + (d > 68 ? 1900 : 2e3);
	  }
	  function d3_time_parseMonthNumber(date, string, i) {
	    d3_time_numberRe.lastIndex = 0;
	    var n = d3_time_numberRe.exec(string.slice(i, i + 2));
	    return n ? (date.m = n[0] - 1, i + n[0].length) : -1;
	  }
	  function d3_time_parseDay(date, string, i) {
	    d3_time_numberRe.lastIndex = 0;
	    var n = d3_time_numberRe.exec(string.slice(i, i + 2));
	    return n ? (date.d = +n[0], i + n[0].length) : -1;
	  }
	  function d3_time_parseDayOfYear(date, string, i) {
	    d3_time_numberRe.lastIndex = 0;
	    var n = d3_time_numberRe.exec(string.slice(i, i + 3));
	    return n ? (date.j = +n[0], i + n[0].length) : -1;
	  }
	  function d3_time_parseHour24(date, string, i) {
	    d3_time_numberRe.lastIndex = 0;
	    var n = d3_time_numberRe.exec(string.slice(i, i + 2));
	    return n ? (date.H = +n[0], i + n[0].length) : -1;
	  }
	  function d3_time_parseMinutes(date, string, i) {
	    d3_time_numberRe.lastIndex = 0;
	    var n = d3_time_numberRe.exec(string.slice(i, i + 2));
	    return n ? (date.M = +n[0], i + n[0].length) : -1;
	  }
	  function d3_time_parseSeconds(date, string, i) {
	    d3_time_numberRe.lastIndex = 0;
	    var n = d3_time_numberRe.exec(string.slice(i, i + 2));
	    return n ? (date.S = +n[0], i + n[0].length) : -1;
	  }
	  function d3_time_parseMilliseconds(date, string, i) {
	    d3_time_numberRe.lastIndex = 0;
	    var n = d3_time_numberRe.exec(string.slice(i, i + 3));
	    return n ? (date.L = +n[0], i + n[0].length) : -1;
	  }
	  function d3_time_zone(d) {
	    var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = abs(z) / 60 | 0, zm = abs(z) % 60;
	    return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2);
	  }
	  function d3_time_parseLiteralPercent(date, string, i) {
	    d3_time_percentRe.lastIndex = 0;
	    var n = d3_time_percentRe.exec(string.slice(i, i + 1));
	    return n ? i + n[0].length : -1;
	  }
	  function d3_time_formatMulti(formats) {
	    var n = formats.length, i = -1;
	    while (++i < n) formats[i][0] = this(formats[i][0]);
	    return function(date) {
	      var i = 0, f = formats[i];
	      while (!f[1](date)) f = formats[++i];
	      return f[0](date);
	    };
	  }
	  d3.locale = function(locale) {
	    return {
	      numberFormat: d3_locale_numberFormat(locale),
	      timeFormat: d3_locale_timeFormat(locale)
	    };
	  };
	  var d3_locale_enUS = d3.locale({
	    decimal: ".",
	    thousands: ",",
	    grouping: [ 3 ],
	    currency: [ "$", "" ],
	    dateTime: "%a %b %e %X %Y",
	    date: "%m/%d/%Y",
	    time: "%H:%M:%S",
	    periods: [ "AM", "PM" ],
	    days: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ],
	    shortDays: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ],
	    months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ],
	    shortMonths: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]
	  });
	  d3.format = d3_locale_enUS.numberFormat;
	  d3.geo = {};
	  function d3_adder() {}
	  d3_adder.prototype = {
	    s: 0,
	    t: 0,
	    add: function(y) {
	      d3_adderSum(y, this.t, d3_adderTemp);
	      d3_adderSum(d3_adderTemp.s, this.s, this);
	      if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t;
	    },
	    reset: function() {
	      this.s = this.t = 0;
	    },
	    valueOf: function() {
	      return this.s;
	    }
	  };
	  var d3_adderTemp = new d3_adder();
	  function d3_adderSum(a, b, o) {
	    var x = o.s = a + b, bv = x - a, av = x - bv;
	    o.t = a - av + (b - bv);
	  }
	  d3.geo.stream = function(object, listener) {
	    if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) {
	      d3_geo_streamObjectType[object.type](object, listener);
	    } else {
	      d3_geo_streamGeometry(object, listener);
	    }
	  };
	  function d3_geo_streamGeometry(geometry, listener) {
	    if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {
	      d3_geo_streamGeometryType[geometry.type](geometry, listener);
	    }
	  }
	  var d3_geo_streamObjectType = {
	    Feature: function(feature, listener) {
	      d3_geo_streamGeometry(feature.geometry, listener);
	    },
	    FeatureCollection: function(object, listener) {
	      var features = object.features, i = -1, n = features.length;
	      while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);
	    }
	  };
	  var d3_geo_streamGeometryType = {
	    Sphere: function(object, listener) {
	      listener.sphere();
	    },
	    Point: function(object, listener) {
	      object = object.coordinates;
	      listener.point(object[0], object[1], object[2]);
	    },
	    MultiPoint: function(object, listener) {
	      var coordinates = object.coordinates, i = -1, n = coordinates.length;
	      while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]);
	    },
	    LineString: function(object, listener) {
	      d3_geo_streamLine(object.coordinates, listener, 0);
	    },
	    MultiLineString: function(object, listener) {
	      var coordinates = object.coordinates, i = -1, n = coordinates.length;
	      while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);
	    },
	    Polygon: function(object, listener) {
	      d3_geo_streamPolygon(object.coordinates, listener);
	    },
	    MultiPolygon: function(object, listener) {
	      var coordinates = object.coordinates, i = -1, n = coordinates.length;
	      while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);
	    },
	    GeometryCollection: function(object, listener) {
	      var geometries = object.geometries, i = -1, n = geometries.length;
	      while (++i < n) d3_geo_streamGeometry(geometries[i], listener);
	    }
	  };
	  function d3_geo_streamLine(coordinates, listener, closed) {
	    var i = -1, n = coordinates.length - closed, coordinate;
	    listener.lineStart();
	    while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]);
	    listener.lineEnd();
	  }
	  function d3_geo_streamPolygon(coordinates, listener) {
	    var i = -1, n = coordinates.length;
	    listener.polygonStart();
	    while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);
	    listener.polygonEnd();
	  }
	  d3.geo.area = function(object) {
	    d3_geo_areaSum = 0;
	    d3.geo.stream(object, d3_geo_area);
	    return d3_geo_areaSum;
	  };
	  var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder();
	  var d3_geo_area = {
	    sphere: function() {
	      d3_geo_areaSum += 4 * π;
	    },
	    point: d3_noop,
	    lineStart: d3_noop,
	    lineEnd: d3_noop,
	    polygonStart: function() {
	      d3_geo_areaRingSum.reset();
	      d3_geo_area.lineStart = d3_geo_areaRingStart;
	    },
	    polygonEnd: function() {
	      var area = 2 * d3_geo_areaRingSum;
	      d3_geo_areaSum += area < 0 ? 4 * π + area : area;
	      d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
	    }
	  };
	  function d3_geo_areaRingStart() {
	    var λ00, φ00, λ0, cosφ0, sinφ0;
	    d3_geo_area.point = function(λ, φ) {
	      d3_geo_area.point = nextPoint;
	      λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), 
	      sinφ0 = Math.sin(φ);
	    };
	    function nextPoint(λ, φ) {
	      λ *= d3_radians;
	      φ = φ * d3_radians / 2 + π / 4;
	      var dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(adλ), v = k * sdλ * Math.sin(adλ);
	      d3_geo_areaRingSum.add(Math.atan2(v, u));
	      λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ;
	    }
	    d3_geo_area.lineEnd = function() {
	      nextPoint(λ00, φ00);
	    };
	  }
	  function d3_geo_cartesian(spherical) {
	    var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ);
	    return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ];
	  }
	  function d3_geo_cartesianDot(a, b) {
	    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
	  }
	  function d3_geo_cartesianCross(a, b) {
	    return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ];
	  }
	  function d3_geo_cartesianAdd(a, b) {
	    a[0] += b[0];
	    a[1] += b[1];
	    a[2] += b[2];
	  }
	  function d3_geo_cartesianScale(vector, k) {
	    return [ vector[0] * k, vector[1] * k, vector[2] * k ];
	  }
	  function d3_geo_cartesianNormalize(d) {
	    var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
	    d[0] /= l;
	    d[1] /= l;
	    d[2] /= l;
	  }
	  function d3_geo_spherical(cartesian) {
	    return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ];
	  }
	  function d3_geo_sphericalEqual(a, b) {
	    return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε;
	  }
	  d3.geo.bounds = function() {
	    var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range;
	    var bound = {
	      point: point,
	      lineStart: lineStart,
	      lineEnd: lineEnd,
	      polygonStart: function() {
	        bound.point = ringPoint;
	        bound.lineStart = ringStart;
	        bound.lineEnd = ringEnd;
	        dλSum = 0;
	        d3_geo_area.polygonStart();
	      },
	      polygonEnd: function() {
	        d3_geo_area.polygonEnd();
	        bound.point = point;
	        bound.lineStart = lineStart;
	        bound.lineEnd = lineEnd;
	        if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90;
	        range[0] = λ0, range[1] = λ1;
	      }
	    };
	    function point(λ, φ) {
	      ranges.push(range = [ λ0 = λ, λ1 = λ ]);
	      if (φ < φ0) φ0 = φ;
	      if (φ > φ1) φ1 = φ;
	    }
	    function linePoint(λ, φ) {
	      var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]);
	      if (p0) {
	        var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal);
	        d3_geo_cartesianNormalize(inflection);
	        inflection = d3_geo_spherical(inflection);
	        var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = abs(dλ) > 180;
	        if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
	          var φi = inflection[1] * d3_degrees;
	          if (φi > φ1) φ1 = φi;
	        } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
	          var φi = -inflection[1] * d3_degrees;
	          if (φi < φ0) φ0 = φi;
	        } else {
	          if (φ < φ0) φ0 = φ;
	          if (φ > φ1) φ1 = φ;
	        }
	        if (antimeridian) {
	          if (λ < λ_) {
	            if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
	          } else {
	            if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
	          }
	        } else {
	          if (λ1 >= λ0) {
	            if (λ < λ0) λ0 = λ;
	            if (λ > λ1) λ1 = λ;
	          } else {
	            if (λ > λ_) {
	              if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
	            } else {
	              if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
	            }
	          }
	        }
	      } else {
	        point(λ, φ);
	      }
	      p0 = p, λ_ = λ;
	    }
	    function lineStart() {
	      bound.point = linePoint;
	    }
	    function lineEnd() {
	      range[0] = λ0, range[1] = λ1;
	      bound.point = point;
	      p0 = null;
	    }
	    function ringPoint(λ, φ) {
	      if (p0) {
	        var dλ = λ - λ_;
	        dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ;
	      } else λ__ = λ, φ__ = φ;
	      d3_geo_area.point(λ, φ);
	      linePoint(λ, φ);
	    }
	    function ringStart() {
	      d3_geo_area.lineStart();
	    }
	    function ringEnd() {
	      ringPoint(λ__, φ__);
	      d3_geo_area.lineEnd();
	      if (abs(dλSum) > ε) λ0 = -(λ1 = 180);
	      range[0] = λ0, range[1] = λ1;
	      p0 = null;
	    }
	    function angle(λ0, λ1) {
	      return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1;
	    }
	    function compareRanges(a, b) {
	      return a[0] - b[0];
	    }
	    function withinRange(x, range) {
	      return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
	    }
	    return function(feature) {
	      φ1 = λ1 = -(λ0 = φ0 = Infinity);
	      ranges = [];
	      d3.geo.stream(feature, bound);
	      var n = ranges.length;
	      if (n) {
	        ranges.sort(compareRanges);
	        for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) {
	          b = ranges[i];
	          if (withinRange(b[0], a) || withinRange(b[1], a)) {
	            if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
	            if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
	          } else {
	            merged.push(a = b);
	          }
	        }
	        var best = -Infinity, dλ;
	        for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) {
	          b = merged[i];
	          if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1];
	        }
	      }
	      ranges = range = null;
	      return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ];
	    };
	  }();
	  d3.geo.centroid = function(object) {
	    d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
	    d3.geo.stream(object, d3_geo_centroid);
	    var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z;
	    if (m < ε2) {
	      x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1;
	      if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0;
	      m = x * x + y * y + z * z;
	      if (m < ε2) return [ NaN, NaN ];
	    }
	    return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ];
	  };
	  var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2;
	  var d3_geo_centroid = {
	    sphere: d3_noop,
	    point: d3_geo_centroidPoint,
	    lineStart: d3_geo_centroidLineStart,
	    lineEnd: d3_geo_centroidLineEnd,
	    polygonStart: function() {
	      d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
	    },
	    polygonEnd: function() {
	      d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
	    }
	  };
	  function d3_geo_centroidPoint(λ, φ) {
	    λ *= d3_radians;
	    var cosφ = Math.cos(φ *= d3_radians);
	    d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ));
	  }
	  function d3_geo_centroidPointXYZ(x, y, z) {
	    ++d3_geo_centroidW0;
	    d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0;
	    d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0;
	    d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0;
	  }
	  function d3_geo_centroidLineStart() {
	    var x0, y0, z0;
	    d3_geo_centroid.point = function(λ, φ) {
	      λ *= d3_radians;
	      var cosφ = Math.cos(φ *= d3_radians);
	      x0 = cosφ * Math.cos(λ);
	      y0 = cosφ * Math.sin(λ);
	      z0 = Math.sin(φ);
	      d3_geo_centroid.point = nextPoint;
	      d3_geo_centroidPointXYZ(x0, y0, z0);
	    };
	    function nextPoint(λ, φ) {
	      λ *= d3_radians;
	      var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
	      d3_geo_centroidW1 += w;
	      d3_geo_centroidX1 += w * (x0 + (x0 = x));
	      d3_geo_centroidY1 += w * (y0 + (y0 = y));
	      d3_geo_centroidZ1 += w * (z0 + (z0 = z));
	      d3_geo_centroidPointXYZ(x0, y0, z0);
	    }
	  }
	  function d3_geo_centroidLineEnd() {
	    d3_geo_centroid.point = d3_geo_centroidPoint;
	  }
	  function d3_geo_centroidRingStart() {
	    var λ00, φ00, x0, y0, z0;
	    d3_geo_centroid.point = function(λ, φ) {
	      λ00 = λ, φ00 = φ;
	      d3_geo_centroid.point = nextPoint;
	      λ *= d3_radians;
	      var cosφ = Math.cos(φ *= d3_radians);
	      x0 = cosφ * Math.cos(λ);
	      y0 = cosφ * Math.sin(λ);
	      z0 = Math.sin(φ);
	      d3_geo_centroidPointXYZ(x0, y0, z0);
	    };
	    d3_geo_centroid.lineEnd = function() {
	      nextPoint(λ00, φ00);
	      d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
	      d3_geo_centroid.point = d3_geo_centroidPoint;
	    };
	    function nextPoint(λ, φ) {
	      λ *= d3_radians;
	      var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u);
	      d3_geo_centroidX2 += v * cx;
	      d3_geo_centroidY2 += v * cy;
	      d3_geo_centroidZ2 += v * cz;
	      d3_geo_centroidW1 += w;
	      d3_geo_centroidX1 += w * (x0 + (x0 = x));
	      d3_geo_centroidY1 += w * (y0 + (y0 = y));
	      d3_geo_centroidZ1 += w * (z0 + (z0 = z));
	      d3_geo_centroidPointXYZ(x0, y0, z0);
	    }
	  }
	  function d3_geo_compose(a, b) {
	    function compose(x, y) {
	      return x = a(x, y), b(x[0], x[1]);
	    }
	    if (a.invert && b.invert) compose.invert = function(x, y) {
	      return x = b.invert(x, y), x && a.invert(x[0], x[1]);
	    };
	    return compose;
	  }
	  function d3_true() {
	    return true;
	  }
	  function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) {
	    var subject = [], clip = [];
	    segments.forEach(function(segment) {
	      if ((n = segment.length - 1) <= 0) return;
	      var n, p0 = segment[0], p1 = segment[n];
	      if (d3_geo_sphericalEqual(p0, p1)) {
	        listener.lineStart();
	        for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]);
	        listener.lineEnd();
	        return;
	      }
	      var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true), b = new d3_geo_clipPolygonIntersection(p0, null, a, false);
	      a.o = b;
	      subject.push(a);
	      clip.push(b);
	      a = new d3_geo_clipPolygonIntersection(p1, segment, null, false);
	      b = new d3_geo_clipPolygonIntersection(p1, null, a, true);
	      a.o = b;
	      subject.push(a);
	      clip.push(b);
	    });
	    clip.sort(compare);
	    d3_geo_clipPolygonLinkCircular(subject);
	    d3_geo_clipPolygonLinkCircular(clip);
	    if (!subject.length) return;
	    for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) {
	      clip[i].e = entry = !entry;
	    }
	    var start = subject[0], points, point;
	    while (1) {
	      var current = start, isSubject = true;
	      while (current.v) if ((current = current.n) === start) return;
	      points = current.z;
	      listener.lineStart();
	      do {
	        current.v = current.o.v = true;
	        if (current.e) {
	          if (isSubject) {
	            for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]);
	          } else {
	            interpolate(current.x, current.n.x, 1, listener);
	          }
	          current = current.n;
	        } else {
	          if (isSubject) {
	            points = current.p.z;
	            for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]);
	          } else {
	            interpolate(current.x, current.p.x, -1, listener);
	          }
	          current = current.p;
	        }
	        current = current.o;
	        points = current.z;
	        isSubject = !isSubject;
	      } while (!current.v);
	      listener.lineEnd();
	    }
	  }
	  function d3_geo_clipPolygonLinkCircular(array) {
	    if (!(n = array.length)) return;
	    var n, i = 0, a = array[0], b;
	    while (++i < n) {
	      a.n = b = array[i];
	      b.p = a;
	      a = b;
	    }
	    a.n = b = array[0];
	    b.p = a;
	  }
	  function d3_geo_clipPolygonIntersection(point, points, other, entry) {
	    this.x = point;
	    this.z = points;
	    this.o = other;
	    this.e = entry;
	    this.v = false;
	    this.n = this.p = null;
	  }
	  function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
	    return function(rotate, listener) {
	      var line = clipLine(listener), rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]);
	      var clip = {
	        point: point,
	        lineStart: lineStart,
	        lineEnd: lineEnd,
	        polygonStart: function() {
	          clip.point = pointRing;
	          clip.lineStart = ringStart;
	          clip.lineEnd = ringEnd;
	          segments = [];
	          polygon = [];
	        },
	        polygonEnd: function() {
	          clip.point = point;
	          clip.lineStart = lineStart;
	          clip.lineEnd = lineEnd;
	          segments = d3.merge(segments);
	          var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon);
	          if (segments.length) {
	            if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
	            d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener);
	          } else if (clipStartInside) {
	            if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
	            listener.lineStart();
	            interpolate(null, null, 1, listener);
	            listener.lineEnd();
	          }
	          if (polygonStarted) listener.polygonEnd(), polygonStarted = false;
	          segments = polygon = null;
	        },
	        sphere: function() {
	          listener.polygonStart();
	          listener.lineStart();
	          interpolate(null, null, 1, listener);
	          listener.lineEnd();
	          listener.polygonEnd();
	        }
	      };
	      function point(λ, φ) {
	        var point = rotate(λ, φ);
	        if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ);
	      }
	      function pointLine(λ, φ) {
	        var point = rotate(λ, φ);
	        line.point(point[0], point[1]);
	      }
	      function lineStart() {
	        clip.point = pointLine;
	        line.lineStart();
	      }
	      function lineEnd() {
	        clip.point = point;
	        line.lineEnd();
	      }
	      var segments;
	      var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygonStarted = false, polygon, ring;
	      function pointRing(λ, φ) {
	        ring.push([ λ, φ ]);
	        var point = rotate(λ, φ);
	        ringListener.point(point[0], point[1]);
	      }
	      function ringStart() {
	        ringListener.lineStart();
	        ring = [];
	      }
	      function ringEnd() {
	        pointRing(ring[0][0], ring[0][1]);
	        ringListener.lineEnd();
	        var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length;
	        ring.pop();
	        polygon.push(ring);
	        ring = null;
	        if (!n) return;
	        if (clean & 1) {
	          segment = ringSegments[0];
	          var n = segment.length - 1, i = -1, point;
	          if (n > 0) {
	            if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
	            listener.lineStart();
	            while (++i < n) listener.point((point = segment[i])[0], point[1]);
	            listener.lineEnd();
	          }
	          return;
	        }
	        if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
	        segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));
	      }
	      return clip;
	    };
	  }
	  function d3_geo_clipSegmentLength1(segment) {
	    return segment.length > 1;
	  }
	  function d3_geo_clipBufferListener() {
	    var lines = [], line;
	    return {
	      lineStart: function() {
	        lines.push(line = []);
	      },
	      point: function(λ, φ) {
	        line.push([ λ, φ ]);
	      },
	      lineEnd: d3_noop,
	      buffer: function() {
	        var buffer = lines;
	        lines = [];
	        line = null;
	        return buffer;
	      },
	      rejoin: function() {
	        if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
	      }
	    };
	  }
	  function d3_geo_clipSort(a, b) {
	    return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]);
	  }
	  var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, [ -π, -π / 2 ]);
	  function d3_geo_clipAntimeridianLine(listener) {
	    var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean;
	    return {
	      lineStart: function() {
	        listener.lineStart();
	        clean = 1;
	      },
	      point: function(λ1, φ1) {
	        var sλ1 = λ1 > 0 ? π : -π, dλ = abs(λ1 - λ0);
	        if (abs(dλ - π) < ε) {
	          listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ);
	          listener.point(sλ0, φ0);
	          listener.lineEnd();
	          listener.lineStart();
	          listener.point(sλ1, φ0);
	          listener.point(λ1, φ0);
	          clean = 0;
	        } else if (sλ0 !== sλ1 && dλ >= π) {
	          if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
	          if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
	          φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);
	          listener.point(sλ0, φ0);
	          listener.lineEnd();
	          listener.lineStart();
	          listener.point(sλ1, φ0);
	          clean = 0;
	        }
	        listener.point(λ0 = λ1, φ0 = φ1);
	        sλ0 = sλ1;
	      },
	      lineEnd: function() {
	        listener.lineEnd();
	        λ0 = φ0 = NaN;
	      },
	      clean: function() {
	        return 2 - clean;
	      }
	    };
	  }
	  function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {
	    var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1);
	    return abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2;
	  }
	  function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
	    var φ;
	    if (from == null) {
	      φ = direction * halfπ;
	      listener.point(-π, φ);
	      listener.point(0, φ);
	      listener.point(π, φ);
	      listener.point(π, 0);
	      listener.point(π, -φ);
	      listener.point(0, -φ);
	      listener.point(-π, -φ);
	      listener.point(-π, 0);
	      listener.point(-π, φ);
	    } else if (abs(from[0] - to[0]) > ε) {
	      var s = from[0] < to[0] ? π : -π;
	      φ = direction * s / 2;
	      listener.point(-s, φ);
	      listener.point(0, φ);
	      listener.point(s, φ);
	    } else {
	      listener.point(to[0], to[1]);
	    }
	  }
	  function d3_geo_pointInPolygon(point, polygon) {
	    var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, winding = 0;
	    d3_geo_areaRingSum.reset();
	    for (var i = 0, n = polygon.length; i < n; ++i) {
	      var ring = polygon[i], m = ring.length;
	      if (!m) continue;
	      var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1;
	      while (true) {
	        if (j === m) j = 0;
	        point = ring[j];
	        var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, antimeridian = adλ > π, k = sinφ0 * sinφ;
	        d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ)));
	        polarAngle += antimeridian ? dλ + sdλ * τ : dλ;
	        if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) {
	          var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point));
	          d3_geo_cartesianNormalize(arc);
	          var intersection = d3_geo_cartesianCross(meridianNormal, arc);
	          d3_geo_cartesianNormalize(intersection);
	          var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]);
	          if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) {
	            winding += antimeridian ^ dλ >= 0 ? 1 : -1;
	          }
	        }
	        if (!j++) break;
	        λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point;
	      }
	    }
	    return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < -ε) ^ winding & 1;
	  }
	  function d3_geo_clipCircle(radius) {
	    var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians);
	    return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [ 0, -radius ] : [ -π, radius - π ]);
	    function visible(λ, φ) {
	      return Math.cos(λ) * Math.cos(φ) > cr;
	    }
	    function clipLine(listener) {
	      var point0, c0, v0, v00, clean;
	      return {
	        lineStart: function() {
	          v00 = v0 = false;
	          clean = 1;
	        },
	        point: function(λ, φ) {
	          var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0;
	          if (!point0 && (v00 = v0 = v)) listener.lineStart();
	          if (v !== v0) {
	            point2 = intersect(point0, point1);
	            if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) {
	              point1[0] += ε;
	              point1[1] += ε;
	              v = visible(point1[0], point1[1]);
	            }
	          }
	          if (v !== v0) {
	            clean = 0;
	            if (v) {
	              listener.lineStart();
	              point2 = intersect(point1, point0);
	              listener.point(point2[0], point2[1]);
	            } else {
	              point2 = intersect(point0, point1);
	              listener.point(point2[0], point2[1]);
	              listener.lineEnd();
	            }
	            point0 = point2;
	          } else if (notHemisphere && point0 && smallRadius ^ v) {
	            var t;
	            if (!(c & c0) && (t = intersect(point1, point0, true))) {
	              clean = 0;
	              if (smallRadius) {
	                listener.lineStart();
	                listener.point(t[0][0], t[0][1]);
	                listener.point(t[1][0], t[1][1]);
	                listener.lineEnd();
	              } else {
	                listener.point(t[1][0], t[1][1]);
	                listener.lineEnd();
	                listener.lineStart();
	                listener.point(t[0][0], t[0][1]);
	              }
	            }
	          }
	          if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) {
	            listener.point(point1[0], point1[1]);
	          }
	          point0 = point1, v0 = v, c0 = c;
	        },
	        lineEnd: function() {
	          if (v0) listener.lineEnd();
	          point0 = null;
	        },
	        clean: function() {
	          return clean | (v00 && v0) << 1;
	        }
	      };
	    }
	    function intersect(a, b, two) {
	      var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b);
	      var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2;
	      if (!determinant) return !two && a;
	      var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2);
	      d3_geo_cartesianAdd(A, B);
	      var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1);
	      if (t2 < 0) return;
	      var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu);
	      d3_geo_cartesianAdd(q, A);
	      q = d3_geo_spherical(q);
	      if (!two) return q;
	      var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z;
	      if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z;
	      var δλ = λ1 - λ0, polar = abs(δλ - π) < ε, meridian = polar || δλ < ε;
	      if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z;
	      if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) {
	        var q1 = d3_geo_cartesianScale(u, (-w + t) / uu);
	        d3_geo_cartesianAdd(q1, A);
	        return [ q, d3_geo_spherical(q1) ];
	      }
	    }
	    function code(λ, φ) {
	      var r = smallRadius ? radius : π - radius, code = 0;
	      if (λ < -r) code |= 1; else if (λ > r) code |= 2;
	      if (φ < -r) code |= 4; else if (φ > r) code |= 8;
	      return code;
	    }
	  }
	  function d3_geom_clipLine(x0, y0, x1, y1) {
	    return function(line) {
	      var a = line.a, b = line.b, ax = a.x, ay = a.y, bx = b.x, by = b.y, t0 = 0, t1 = 1, dx = bx - ax, dy = by - ay, r;
	      r = x0 - ax;
	      if (!dx && r > 0) return;
	      r /= dx;
	      if (dx < 0) {
	        if (r < t0) return;
	        if (r < t1) t1 = r;
	      } else if (dx > 0) {
	        if (r > t1) return;
	        if (r > t0) t0 = r;
	      }
	      r = x1 - ax;
	      if (!dx && r < 0) return;
	      r /= dx;
	      if (dx < 0) {
	        if (r > t1) return;
	        if (r > t0) t0 = r;
	      } else if (dx > 0) {
	        if (r < t0) return;
	        if (r < t1) t1 = r;
	      }
	      r = y0 - ay;
	      if (!dy && r > 0) return;
	      r /= dy;
	      if (dy < 0) {
	        if (r < t0) return;
	        if (r < t1) t1 = r;
	      } else if (dy > 0) {
	        if (r > t1) return;
	        if (r > t0) t0 = r;
	      }
	      r = y1 - ay;
	      if (!dy && r < 0) return;
	      r /= dy;
	      if (dy < 0) {
	        if (r > t1) return;
	        if (r > t0) t0 = r;
	      } else if (dy > 0) {
	        if (r < t0) return;
	        if (r < t1) t1 = r;
	      }
	      if (t0 > 0) line.a = {
	        x: ax + t0 * dx,
	        y: ay + t0 * dy
	      };
	      if (t1 < 1) line.b = {
	        x: ax + t1 * dx,
	        y: ay + t1 * dy
	      };
	      return line;
	    };
	  }
	  var d3_geo_clipExtentMAX = 1e9;
	  d3.geo.clipExtent = function() {
	    var x0, y0, x1, y1, stream, clip, clipExtent = {
	      stream: function(output) {
	        if (stream) stream.valid = false;
	        stream = clip(output);
	        stream.valid = true;
	        return stream;
	      },
	      extent: function(_) {
	        if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
	        clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]);
	        if (stream) stream.valid = false, stream = null;
	        return clipExtent;
	      }
	    };
	    return clipExtent.extent([ [ 0, 0 ], [ 960, 500 ] ]);
	  };
	  function d3_geo_clipExtent(x0, y0, x1, y1) {
	    return function(listener) {
	      var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), clipLine = d3_geom_clipLine(x0, y0, x1, y1), segments, polygon, ring;
	      var clip = {
	        point: point,
	        lineStart: lineStart,
	        lineEnd: lineEnd,
	        polygonStart: function() {
	          listener = bufferListener;
	          segments = [];
	          polygon = [];
	          clean = true;
	        },
	        polygonEnd: function() {
	          listener = listener_;
	          segments = d3.merge(segments);
	          var clipStartInside = insidePolygon([ x0, y1 ]), inside = clean && clipStartInside, visible = segments.length;
	          if (inside || visible) {
	            listener.polygonStart();
	            if (inside) {
	              listener.lineStart();
	              interpolate(null, null, 1, listener);
	              listener.lineEnd();
	            }
	            if (visible) {
	              d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener);
	            }
	            listener.polygonEnd();
	          }
	          segments = polygon = ring = null;
	        }
	      };
	      function insidePolygon(p) {
	        var wn = 0, n = polygon.length, y = p[1];
	        for (var i = 0; i < n; ++i) {
	          for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) {
	            b = v[j];
	            if (a[1] <= y) {
	              if (b[1] > y && d3_cross2d(a, b, p) > 0) ++wn;
	            } else {
	              if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn;
	            }
	            a = b;
	          }
	        }
	        return wn !== 0;
	      }
	      function interpolate(from, to, direction, listener) {
	        var a = 0, a1 = 0;
	        if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) {
	          do {
	            listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
	          } while ((a = (a + direction + 4) % 4) !== a1);
	        } else {
	          listener.point(to[0], to[1]);
	        }
	      }
	      function pointVisible(x, y) {
	        return x0 <= x && x <= x1 && y0 <= y && y <= y1;
	      }
	      function point(x, y) {
	        if (pointVisible(x, y)) listener.point(x, y);
	      }
	      var x__, y__, v__, x_, y_, v_, first, clean;
	      function lineStart() {
	        clip.point = linePoint;
	        if (polygon) polygon.push(ring = []);
	        first = true;
	        v_ = false;
	        x_ = y_ = NaN;
	      }
	      function lineEnd() {
	        if (segments) {
	          linePoint(x__, y__);
	          if (v__ && v_) bufferListener.rejoin();
	          segments.push(bufferListener.buffer());
	        }
	        clip.point = point;
	        if (v_) listener.lineEnd();
	      }
	      function linePoint(x, y) {
	        x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
	        y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
	        var v = pointVisible(x, y);
	        if (polygon) ring.push([ x, y ]);
	        if (first) {
	          x__ = x, y__ = y, v__ = v;
	          first = false;
	          if (v) {
	            listener.lineStart();
	            listener.point(x, y);
	          }
	        } else {
	          if (v && v_) listener.point(x, y); else {
	            var l = {
	              a: {
	                x: x_,
	                y: y_
	              },
	              b: {
	                x: x,
	                y: y
	              }
	            };
	            if (clipLine(l)) {
	              if (!v_) {
	                listener.lineStart();
	                listener.point(l.a.x, l.a.y);
	              }
	              listener.point(l.b.x, l.b.y);
	              if (!v) listener.lineEnd();
	              clean = false;
	            } else if (v) {
	              listener.lineStart();
	              listener.point(x, y);
	              clean = false;
	            }
	          }
	        }
	        x_ = x, y_ = y, v_ = v;
	      }
	      return clip;
	    };
	    function corner(p, direction) {
	      return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2;
	    }
	    function compare(a, b) {
	      return comparePoints(a.x, b.x);
	    }
	    function comparePoints(a, b) {
	      var ca = corner(a, 1), cb = corner(b, 1);
	      return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0];
	    }
	  }
	  function d3_geo_conic(projectAt) {
	    var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1);
	    p.parallels = function(_) {
	      if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ];
	      return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180);
	    };
	    return p;
	  }
	  function d3_geo_conicEqualArea(φ0, φ1) {
	    var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n;
	    function forward(λ, φ) {
	      var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n;
	      return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ];
	    }
	    forward.invert = function(x, y) {
	      var ρ0_y = ρ0 - y;
	      return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ];
	    };
	    return forward;
	  }
	  (d3.geo.conicEqualArea = function() {
	    return d3_geo_conic(d3_geo_conicEqualArea);
	  }).raw = d3_geo_conicEqualArea;
	  d3.geo.albers = function() {
	    return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070);
	  };
	  d3.geo.albersUsa = function() {
	    var lower48 = d3.geo.albers();
	    var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]);
	    var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]);
	    var point, pointStream = {
	      point: function(x, y) {
	        point = [ x, y ];
	      }
	    }, lower48Point, alaskaPoint, hawaiiPoint;
	    function albersUsa(coordinates) {
	      var x = coordinates[0], y = coordinates[1];
	      point = null;
	      (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y);
	      return point;
	    }
	    albersUsa.invert = function(coordinates) {
	      var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k;
	      return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates);
	    };
	    albersUsa.stream = function(stream) {
	      var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream);
	      return {
	        point: function(x, y) {
	          lower48Stream.point(x, y);
	          alaskaStream.point(x, y);
	          hawaiiStream.point(x, y);
	        },
	        sphere: function() {
	          lower48Stream.sphere();
	          alaskaStream.sphere();
	          hawaiiStream.sphere();
	        },
	        lineStart: function() {
	          lower48Stream.lineStart();
	          alaskaStream.lineStart();
	          hawaiiStream.lineStart();
	        },
	        lineEnd: function() {
	          lower48Stream.lineEnd();
	          alaskaStream.lineEnd();
	          hawaiiStream.lineEnd();
	        },
	        polygonStart: function() {
	          lower48Stream.polygonStart();
	          alaskaStream.polygonStart();
	          hawaiiStream.polygonStart();
	        },
	        polygonEnd: function() {
	          lower48Stream.polygonEnd();
	          alaskaStream.polygonEnd();
	          hawaiiStream.polygonEnd();
	        }
	      };
	    };
	    albersUsa.precision = function(_) {
	      if (!arguments.length) return lower48.precision();
	      lower48.precision(_);
	      alaska.precision(_);
	      hawaii.precision(_);
	      return albersUsa;
	    };
	    albersUsa.scale = function(_) {
	      if (!arguments.length) return lower48.scale();
	      lower48.scale(_);
	      alaska.scale(_ * .35);
	      hawaii.scale(_);
	      return albersUsa.translate(lower48.translate());
	    };
	    albersUsa.translate = function(_) {
	      if (!arguments.length) return lower48.translate();
	      var k = lower48.scale(), x = +_[0], y = +_[1];
	      lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point;
	      alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point;
	      hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point;
	      return albersUsa;
	    };
	    return albersUsa.scale(1070);
	  };
	  var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {
	    point: d3_noop,
	    lineStart: d3_noop,
	    lineEnd: d3_noop,
	    polygonStart: function() {
	      d3_geo_pathAreaPolygon = 0;
	      d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;
	    },
	    polygonEnd: function() {
	      d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop;
	      d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2);
	    }
	  };
	  function d3_geo_pathAreaRingStart() {
	    var x00, y00, x0, y0;
	    d3_geo_pathArea.point = function(x, y) {
	      d3_geo_pathArea.point = nextPoint;
	      x00 = x0 = x, y00 = y0 = y;
	    };
	    function nextPoint(x, y) {
	      d3_geo_pathAreaPolygon += y0 * x - x0 * y;
	      x0 = x, y0 = y;
	    }
	    d3_geo_pathArea.lineEnd = function() {
	      nextPoint(x00, y00);
	    };
	  }
	  var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1;
	  var d3_geo_pathBounds = {
	    point: d3_geo_pathBoundsPoint,
	    lineStart: d3_noop,
	    lineEnd: d3_noop,
	    polygonStart: d3_noop,
	    polygonEnd: d3_noop
	  };
	  function d3_geo_pathBoundsPoint(x, y) {
	    if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x;
	    if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x;
	    if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y;
	    if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y;
	  }
	  function d3_geo_pathBuffer() {
	    var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = [];
	    var stream = {
	      point: point,
	      lineStart: function() {
	        stream.point = pointLineStart;
	      },
	      lineEnd: lineEnd,
	      polygonStart: function() {
	        stream.lineEnd = lineEndPolygon;
	      },
	      polygonEnd: function() {
	        stream.lineEnd = lineEnd;
	        stream.point = point;
	      },
	      pointRadius: function(_) {
	        pointCircle = d3_geo_pathBufferCircle(_);
	        return stream;
	      },
	      result: function() {
	        if (buffer.length) {
	          var result = buffer.join("");
	          buffer = [];
	          return result;
	        }
	      }
	    };
	    function point(x, y) {
	      buffer.push("M", x, ",", y, pointCircle);
	    }
	    function pointLineStart(x, y) {
	      buffer.push("M", x, ",", y);
	      stream.point = pointLine;
	    }
	    function pointLine(x, y) {
	      buffer.push("L", x, ",", y);
	    }
	    function lineEnd() {
	      stream.point = point;
	    }
	    function lineEndPolygon() {
	      buffer.push("Z");
	    }
	    return stream;
	  }
	  function d3_geo_pathBufferCircle(radius) {
	    return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z";
	  }
	  var d3_geo_pathCentroid = {
	    point: d3_geo_pathCentroidPoint,
	    lineStart: d3_geo_pathCentroidLineStart,
	    lineEnd: d3_geo_pathCentroidLineEnd,
	    polygonStart: function() {
	      d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;
	    },
	    polygonEnd: function() {
	      d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
	      d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;
	      d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;
	    }
	  };
	  function d3_geo_pathCentroidPoint(x, y) {
	    d3_geo_centroidX0 += x;
	    d3_geo_centroidY0 += y;
	    ++d3_geo_centroidZ0;
	  }
	  function d3_geo_pathCentroidLineStart() {
	    var x0, y0;
	    d3_geo_pathCentroid.point = function(x, y) {
	      d3_geo_pathCentroid.point = nextPoint;
	      d3_geo_pathCentroidPoint(x0 = x, y0 = y);
	    };
	    function nextPoint(x, y) {
	      var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
	      d3_geo_centroidX1 += z * (x0 + x) / 2;
	      d3_geo_centroidY1 += z * (y0 + y) / 2;
	      d3_geo_centroidZ1 += z;
	      d3_geo_pathCentroidPoint(x0 = x, y0 = y);
	    }
	  }
	  function d3_geo_pathCentroidLineEnd() {
	    d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
	  }
	  function d3_geo_pathCentroidRingStart() {
	    var x00, y00, x0, y0;
	    d3_geo_pathCentroid.point = function(x, y) {
	      d3_geo_pathCentroid.point = nextPoint;
	      d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y);
	    };
	    function nextPoint(x, y) {
	      var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
	      d3_geo_centroidX1 += z * (x0 + x) / 2;
	      d3_geo_centroidY1 += z * (y0 + y) / 2;
	      d3_geo_centroidZ1 += z;
	      z = y0 * x - x0 * y;
	      d3_geo_centroidX2 += z * (x0 + x);
	      d3_geo_centroidY2 += z * (y0 + y);
	      d3_geo_centroidZ2 += z * 3;
	      d3_geo_pathCentroidPoint(x0 = x, y0 = y);
	    }
	    d3_geo_pathCentroid.lineEnd = function() {
	      nextPoint(x00, y00);
	    };
	  }
	  function d3_geo_pathContext(context) {
	    var pointRadius = 4.5;
	    var stream = {
	      point: point,
	      lineStart: function() {
	        stream.point = pointLineStart;
	      },
	      lineEnd: lineEnd,
	      polygonStart: function() {
	        stream.lineEnd = lineEndPolygon;
	      },
	      polygonEnd: function() {
	        stream.lineEnd = lineEnd;
	        stream.point = point;
	      },
	      pointRadius: function(_) {
	        pointRadius = _;
	        return stream;
	      },
	      result: d3_noop
	    };
	    function point(x, y) {
	      context.moveTo(x + pointRadius, y);
	      context.arc(x, y, pointRadius, 0, τ);
	    }
	    function pointLineStart(x, y) {
	      context.moveTo(x, y);
	      stream.point = pointLine;
	    }
	    function pointLine(x, y) {
	      context.lineTo(x, y);
	    }
	    function lineEnd() {
	      stream.point = point;
	    }
	    function lineEndPolygon() {
	      context.closePath();
	    }
	    return stream;
	  }
	  function d3_geo_resample(project) {
	    var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16;
	    function resample(stream) {
	      return (maxDepth ? resampleRecursive : resampleNone)(stream);
	    }
	    function resampleNone(stream) {
	      return d3_geo_transformPoint(stream, function(x, y) {
	        x = project(x, y);
	        stream.point(x[0], x[1]);
	      });
	    }
	    function resampleRecursive(stream) {
	      var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0;
	      var resample = {
	        point: point,
	        lineStart: lineStart,
	        lineEnd: lineEnd,
	        polygonStart: function() {
	          stream.polygonStart();
	          resample.lineStart = ringStart;
	        },
	        polygonEnd: function() {
	          stream.polygonEnd();
	          resample.lineStart = lineStart;
	        }
	      };
	      function point(x, y) {
	        x = project(x, y);
	        stream.point(x[0], x[1]);
	      }
	      function lineStart() {
	        x0 = NaN;
	        resample.point = linePoint;
	        stream.lineStart();
	      }
	      function linePoint(λ, φ) {
	        var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ);
	        resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
	        stream.point(x0, y0);
	      }
	      function lineEnd() {
	        resample.point = point;
	        stream.lineEnd();
	      }
	      function ringStart() {
	        lineStart();
	        resample.point = ringPoint;
	        resample.lineEnd = ringEnd;
	      }
	      function ringPoint(λ, φ) {
	        linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
	        resample.point = linePoint;
	      }
	      function ringEnd() {
	        resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream);
	        resample.lineEnd = lineEnd;
	        lineEnd();
	      }
	      return resample;
	    }
	    function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) {
	      var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy;
	      if (d2 > 4 * δ2 && depth--) {
	        var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = abs(abs(c) - 1) < ε || abs(λ0 - λ1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2;
	        if (dz * dz / d2 > δ2 || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
	          resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream);
	          stream.point(x2, y2);
	          resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream);
	        }
	      }
	    }
	    resample.precision = function(_) {
	      if (!arguments.length) return Math.sqrt(δ2);
	      maxDepth = (δ2 = _ * _) > 0 && 16;
	      return resample;
	    };
	    return resample;
	  }
	  d3.geo.path = function() {
	    var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream;
	    function path(object) {
	      if (object) {
	        if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
	        if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream);
	        d3.geo.stream(object, cacheStream);
	      }
	      return contextStream.result();
	    }
	    path.area = function(object) {
	      d3_geo_pathAreaSum = 0;
	      d3.geo.stream(object, projectStream(d3_geo_pathArea));
	      return d3_geo_pathAreaSum;
	    };
	    path.centroid = function(object) {
	      d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
	      d3.geo.stream(object, projectStream(d3_geo_pathCentroid));
	      return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ];
	    };
	    path.bounds = function(object) {
	      d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity);
	      d3.geo.stream(object, projectStream(d3_geo_pathBounds));
	      return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ];
	    };
	    path.projection = function(_) {
	      if (!arguments.length) return projection;
	      projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity;
	      return reset();
	    };
	    path.context = function(_) {
	      if (!arguments.length) return context;
	      contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_);
	      if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
	      return reset();
	    };
	    path.pointRadius = function(_) {
	      if (!arguments.length) return pointRadius;
	      pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
	      return path;
	    };
	    function reset() {
	      cacheStream = null;
	      return path;
	    }
	    return path.projection(d3.geo.albersUsa()).context(null);
	  };
	  function d3_geo_pathProjectStream(project) {
	    var resample = d3_geo_resample(function(x, y) {
	      return project([ x * d3_degrees, y * d3_degrees ]);
	    });
	    return function(stream) {
	      return d3_geo_projectionRadians(resample(stream));
	    };
	  }
	  d3.geo.transform = function(methods) {
	    return {
	      stream: function(stream) {
	        var transform = new d3_geo_transform(stream);
	        for (var k in methods) transform[k] = methods[k];
	        return transform;
	      }
	    };
	  };
	  function d3_geo_transform(stream) {
	    this.stream = stream;
	  }
	  d3_geo_transform.prototype = {
	    point: function(x, y) {
	      this.stream.point(x, y);
	    },
	    sphere: function() {
	      this.stream.sphere();
	    },
	    lineStart: function() {
	      this.stream.lineStart();
	    },
	    lineEnd: function() {
	      this.stream.lineEnd();
	    },
	    polygonStart: function() {
	      this.stream.polygonStart();
	    },
	    polygonEnd: function() {
	      this.stream.polygonEnd();
	    }
	  };
	  function d3_geo_transformPoint(stream, point) {
	    return {
	      point: point,
	      sphere: function() {
	        stream.sphere();
	      },
	      lineStart: function() {
	        stream.lineStart();
	      },
	      lineEnd: function() {
	        stream.lineEnd();
	      },
	      polygonStart: function() {
	        stream.polygonStart();
	      },
	      polygonEnd: function() {
	        stream.polygonEnd();
	      }
	    };
	  }
	  d3.geo.projection = d3_geo_projection;
	  d3.geo.projectionMutator = d3_geo_projectionMutator;
	  function d3_geo_projection(project) {
	    return d3_geo_projectionMutator(function() {
	      return project;
	    })();
	  }
	  function d3_geo_projectionMutator(projectAt) {
	    var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) {
	      x = project(x, y);
	      return [ x[0] * k + δx, δy - x[1] * k ];
	    }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream;
	    function projection(point) {
	      point = projectRotate(point[0] * d3_radians, point[1] * d3_radians);
	      return [ point[0] * k + δx, δy - point[1] * k ];
	    }
	    function invert(point) {
	      point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k);
	      return point && [ point[0] * d3_degrees, point[1] * d3_degrees ];
	    }
	    projection.stream = function(output) {
	      if (stream) stream.valid = false;
	      stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output))));
	      stream.valid = true;
	      return stream;
	    };
	    projection.clipAngle = function(_) {
	      if (!arguments.length) return clipAngle;
	      preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians);
	      return invalidate();
	    };
	    projection.clipExtent = function(_) {
	      if (!arguments.length) return clipExtent;
	      clipExtent = _;
	      postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;
	      return invalidate();
	    };
	    projection.scale = function(_) {
	      if (!arguments.length) return k;
	      k = +_;
	      return reset();
	    };
	    projection.translate = function(_) {
	      if (!arguments.length) return [ x, y ];
	      x = +_[0];
	      y = +_[1];
	      return reset();
	    };
	    projection.center = function(_) {
	      if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ];
	      λ = _[0] % 360 * d3_radians;
	      φ = _[1] % 360 * d3_radians;
	      return reset();
	    };
	    projection.rotate = function(_) {
	      if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ];
	      δλ = _[0] % 360 * d3_radians;
	      δφ = _[1] % 360 * d3_radians;
	      δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0;
	      return reset();
	    };
	    d3.rebind(projection, projectResample, "precision");
	    function reset() {
	      projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project);
	      var center = project(λ, φ);
	      δx = x - center[0] * k;
	      δy = y + center[1] * k;
	      return invalidate();
	    }
	    function invalidate() {
	      if (stream) stream.valid = false, stream = null;
	      return projection;
	    }
	    return function() {
	      project = projectAt.apply(this, arguments);
	      projection.invert = project.invert && invert;
	      return reset();
	    };
	  }
	  function d3_geo_projectionRadians(stream) {
	    return d3_geo_transformPoint(stream, function(x, y) {
	      stream.point(x * d3_radians, y * d3_radians);
	    });
	  }
	  function d3_geo_equirectangular(λ, φ) {
	    return [ λ, φ ];
	  }
	  (d3.geo.equirectangular = function() {
	    return d3_geo_projection(d3_geo_equirectangular);
	  }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
	  d3.geo.rotation = function(rotate) {
	    rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0);
	    function forward(coordinates) {
	      coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
	      return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
	    }
	    forward.invert = function(coordinates) {
	      coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
	      return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
	    };
	    return forward;
	  };
	  function d3_geo_identityRotation(λ, φ) {
	    return [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ];
	  }
	  d3_geo_identityRotation.invert = d3_geo_equirectangular;
	  function d3_geo_rotation(δλ, δφ, δγ) {
	    return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_identityRotation;
	  }
	  function d3_geo_forwardRotationλ(δλ) {
	    return function(λ, φ) {
	      return λ += δλ, [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ];
	    };
	  }
	  function d3_geo_rotationλ(δλ) {
	    var rotation = d3_geo_forwardRotationλ(δλ);
	    rotation.invert = d3_geo_forwardRotationλ(-δλ);
	    return rotation;
	  }
	  function d3_geo_rotationφγ(δφ, δγ) {
	    var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ);
	    function rotation(λ, φ) {
	      var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ;
	      return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ];
	    }
	    rotation.invert = function(λ, φ) {
	      var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ;
	      return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ];
	    };
	    return rotation;
	  }
	  d3.geo.circle = function() {
	    var origin = [ 0, 0 ], angle, precision = 6, interpolate;
	    function circle() {
	      var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = [];
	      interpolate(null, null, 1, {
	        point: function(x, y) {
	          ring.push(x = rotate(x, y));
	          x[0] *= d3_degrees, x[1] *= d3_degrees;
	        }
	      });
	      return {
	        type: "Polygon",
	        coordinates: [ ring ]
	      };
	    }
	    circle.origin = function(x) {
	      if (!arguments.length) return origin;
	      origin = x;
	      return circle;
	    };
	    circle.angle = function(x) {
	      if (!arguments.length) return angle;
	      interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians);
	      return circle;
	    };
	    circle.precision = function(_) {
	      if (!arguments.length) return precision;
	      interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians);
	      return circle;
	    };
	    return circle.angle(90);
	  };
	  function d3_geo_circleInterpolate(radius, precision) {
	    var cr = Math.cos(radius), sr = Math.sin(radius);
	    return function(from, to, direction, listener) {
	      var step = direction * precision;
	      if (from != null) {
	        from = d3_geo_circleAngle(cr, from);
	        to = d3_geo_circleAngle(cr, to);
	        if (direction > 0 ? from < to : from > to) from += direction * τ;
	      } else {
	        from = radius + direction * τ;
	        to = radius - .5 * step;
	      }
	      for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) {
	        listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]);
	      }
	    };
	  }
	  function d3_geo_circleAngle(cr, point) {
	    var a = d3_geo_cartesian(point);
	    a[0] -= cr;
	    d3_geo_cartesianNormalize(a);
	    var angle = d3_acos(-a[1]);
	    return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
	  }
	  d3.geo.distance = function(a, b) {
	    var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t;
	    return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ);
	  };
	  d3.geo.graticule = function() {
	    var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5;
	    function graticule() {
	      return {
	        type: "MultiLineString",
	        coordinates: lines()
	      };
	    }
	    function lines() {
	      return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) {
	        return abs(x % DX) > ε;
	      }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) {
	        return abs(y % DY) > ε;
	      }).map(y));
	    }
	    graticule.lines = function() {
	      return lines().map(function(coordinates) {
	        return {
	          type: "LineString",
	          coordinates: coordinates
	        };
	      });
	    };
	    graticule.outline = function() {
	      return {
	        type: "Polygon",
	        coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ]
	      };
	    };
	    graticule.extent = function(_) {
	      if (!arguments.length) return graticule.minorExtent();
	      return graticule.majorExtent(_).minorExtent(_);
	    };
	    graticule.majorExtent = function(_) {
	      if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ];
	      X0 = +_[0][0], X1 = +_[1][0];
	      Y0 = +_[0][1], Y1 = +_[1][1];
	      if (X0 > X1) _ = X0, X0 = X1, X1 = _;
	      if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
	      return graticule.precision(precision);
	    };
	    graticule.minorExtent = function(_) {
	      if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
	      x0 = +_[0][0], x1 = +_[1][0];
	      y0 = +_[0][1], y1 = +_[1][1];
	      if (x0 > x1) _ = x0, x0 = x1, x1 = _;
	      if (y0 > y1) _ = y0, y0 = y1, y1 = _;
	      return graticule.precision(precision);
	    };
	    graticule.step = function(_) {
	      if (!arguments.length) return graticule.minorStep();
	      return graticule.majorStep(_).minorStep(_);
	    };
	    graticule.majorStep = function(_) {
	      if (!arguments.length) return [ DX, DY ];
	      DX = +_[0], DY = +_[1];
	      return graticule;
	    };
	    graticule.minorStep = function(_) {
	      if (!arguments.length) return [ dx, dy ];
	      dx = +_[0], dy = +_[1];
	      return graticule;
	    };
	    graticule.precision = function(_) {
	      if (!arguments.length) return precision;
	      precision = +_;
	      x = d3_geo_graticuleX(y0, y1, 90);
	      y = d3_geo_graticuleY(x0, x1, precision);
	      X = d3_geo_graticuleX(Y0, Y1, 90);
	      Y = d3_geo_graticuleY(X0, X1, precision);
	      return graticule;
	    };
	    return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]);
	  };
	  function d3_geo_graticuleX(y0, y1, dy) {
	    var y = d3.range(y0, y1 - ε, dy).concat(y1);
	    return function(x) {
	      return y.map(function(y) {
	        return [ x, y ];
	      });
	    };
	  }
	  function d3_geo_graticuleY(x0, x1, dx) {
	    var x = d3.range(x0, x1 - ε, dx).concat(x1);
	    return function(y) {
	      return x.map(function(x) {
	        return [ x, y ];
	      });
	    };
	  }
	  function d3_source(d) {
	    return d.source;
	  }
	  function d3_target(d) {
	    return d.target;
	  }
	  d3.geo.greatArc = function() {
	    var source = d3_source, source_, target = d3_target, target_;
	    function greatArc() {
	      return {
	        type: "LineString",
	        coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ]
	      };
	    }
	    greatArc.distance = function() {
	      return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments));
	    };
	    greatArc.source = function(_) {
	      if (!arguments.length) return source;
	      source = _, source_ = typeof _ === "function" ? null : _;
	      return greatArc;
	    };
	    greatArc.target = function(_) {
	      if (!arguments.length) return target;
	      target = _, target_ = typeof _ === "function" ? null : _;
	      return greatArc;
	    };
	    greatArc.precision = function() {
	      return arguments.length ? greatArc : 0;
	    };
	    return greatArc;
	  };
	  d3.geo.interpolate = function(source, target) {
	    return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians);
	  };
	  function d3_geo_interpolate(x0, y0, x1, y1) {
	    var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d);
	    var interpolate = d ? function(t) {
	      var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1;
	      return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ];
	    } : function() {
	      return [ x0 * d3_degrees, y0 * d3_degrees ];
	    };
	    interpolate.distance = d;
	    return interpolate;
	  }
	  d3.geo.length = function(object) {
	    d3_geo_lengthSum = 0;
	    d3.geo.stream(object, d3_geo_length);
	    return d3_geo_lengthSum;
	  };
	  var d3_geo_lengthSum;
	  var d3_geo_length = {
	    sphere: d3_noop,
	    point: d3_noop,
	    lineStart: d3_geo_lengthLineStart,
	    lineEnd: d3_noop,
	    polygonStart: d3_noop,
	    polygonEnd: d3_noop
	  };
	  function d3_geo_lengthLineStart() {
	    var λ0, sinφ0, cosφ0;
	    d3_geo_length.point = function(λ, φ) {
	      λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ);
	      d3_geo_length.point = nextPoint;
	    };
	    d3_geo_length.lineEnd = function() {
	      d3_geo_length.point = d3_geo_length.lineEnd = d3_noop;
	    };
	    function nextPoint(λ, φ) {
	      var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t);
	      d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ);
	      λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ;
	    }
	  }
	  function d3_geo_azimuthal(scale, angle) {
	    function azimuthal(λ, φ) {
	      var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ);
	      return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ];
	    }
	    azimuthal.invert = function(x, y) {
	      var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c);
	      return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ];
	    };
	    return azimuthal;
	  }
	  var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) {
	    return Math.sqrt(2 / (1 + cosλcosφ));
	  }, function(ρ) {
	    return 2 * Math.asin(ρ / 2);
	  });
	  (d3.geo.azimuthalEqualArea = function() {
	    return d3_geo_projection(d3_geo_azimuthalEqualArea);
	  }).raw = d3_geo_azimuthalEqualArea;
	  var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) {
	    var c = Math.acos(cosλcosφ);
	    return c && c / Math.sin(c);
	  }, d3_identity);
	  (d3.geo.azimuthalEquidistant = function() {
	    return d3_geo_projection(d3_geo_azimuthalEquidistant);
	  }).raw = d3_geo_azimuthalEquidistant;
	  function d3_geo_conicConformal(φ0, φ1) {
	    var cosφ0 = Math.cos(φ0), t = function(φ) {
	      return Math.tan(π / 4 + φ / 2);
	    }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n;
	    if (!n) return d3_geo_mercator;
	    function forward(λ, φ) {
	      if (F > 0) {
	        if (φ < -halfπ + ε) φ = -halfπ + ε;
	      } else {
	        if (φ > halfπ - ε) φ = halfπ - ε;
	      }
	      var ρ = F / Math.pow(t(φ), n);
	      return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ];
	    }
	    forward.invert = function(x, y) {
	      var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y);
	      return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - halfπ ];
	    };
	    return forward;
	  }
	  (d3.geo.conicConformal = function() {
	    return d3_geo_conic(d3_geo_conicConformal);
	  }).raw = d3_geo_conicConformal;
	  function d3_geo_conicEquidistant(φ0, φ1) {
	    var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0;
	    if (abs(n) < ε) return d3_geo_equirectangular;
	    function forward(λ, φ) {
	      var ρ = G - φ;
	      return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ];
	    }
	    forward.invert = function(x, y) {
	      var ρ0_y = G - y;
	      return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ];
	    };
	    return forward;
	  }
	  (d3.geo.conicEquidistant = function() {
	    return d3_geo_conic(d3_geo_conicEquidistant);
	  }).raw = d3_geo_conicEquidistant;
	  var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) {
	    return 1 / cosλcosφ;
	  }, Math.atan);
	  (d3.geo.gnomonic = function() {
	    return d3_geo_projection(d3_geo_gnomonic);
	  }).raw = d3_geo_gnomonic;
	  function d3_geo_mercator(λ, φ) {
	    return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ];
	  }
	  d3_geo_mercator.invert = function(x, y) {
	    return [ x, 2 * Math.atan(Math.exp(y)) - halfπ ];
	  };
	  function d3_geo_mercatorProjection(project) {
	    var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto;
	    m.scale = function() {
	      var v = scale.apply(m, arguments);
	      return v === m ? clipAuto ? m.clipExtent(null) : m : v;
	    };
	    m.translate = function() {
	      var v = translate.apply(m, arguments);
	      return v === m ? clipAuto ? m.clipExtent(null) : m : v;
	    };
	    m.clipExtent = function(_) {
	      var v = clipExtent.apply(m, arguments);
	      if (v === m) {
	        if (clipAuto = _ == null) {
	          var k = π * scale(), t = translate();
	          clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]);
	        }
	      } else if (clipAuto) {
	        v = null;
	      }
	      return v;
	    };
	    return m.clipExtent(null);
	  }
	  (d3.geo.mercator = function() {
	    return d3_geo_mercatorProjection(d3_geo_mercator);
	  }).raw = d3_geo_mercator;
	  var d3_geo_orthographic = d3_geo_azimuthal(function() {
	    return 1;
	  }, Math.asin);
	  (d3.geo.orthographic = function() {
	    return d3_geo_projection(d3_geo_orthographic);
	  }).raw = d3_geo_orthographic;
	  var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) {
	    return 1 / (1 + cosλcosφ);
	  }, function(ρ) {
	    return 2 * Math.atan(ρ);
	  });
	  (d3.geo.stereographic = function() {
	    return d3_geo_projection(d3_geo_stereographic);
	  }).raw = d3_geo_stereographic;
	  function d3_geo_transverseMercator(λ, φ) {
	    return [ Math.log(Math.tan(π / 4 + φ / 2)), -λ ];
	  }
	  d3_geo_transverseMercator.invert = function(x, y) {
	    return [ -y, 2 * Math.atan(Math.exp(x)) - halfπ ];
	  };
	  (d3.geo.transverseMercator = function() {
	    var projection = d3_geo_mercatorProjection(d3_geo_transverseMercator), center = projection.center, rotate = projection.rotate;
	    projection.center = function(_) {
	      return _ ? center([ -_[1], _[0] ]) : (_ = center(), [ _[1], -_[0] ]);
	    };
	    projection.rotate = function(_) {
	      return _ ? rotate([ _[0], _[1], _.length > 2 ? _[2] + 90 : 90 ]) : (_ = rotate(), 
	      [ _[0], _[1], _[2] - 90 ]);
	    };
	    return rotate([ 0, 0, 90 ]);
	  }).raw = d3_geo_transverseMercator;
	  d3.geom = {};
	  function d3_geom_pointX(d) {
	    return d[0];
	  }
	  function d3_geom_pointY(d) {
	    return d[1];
	  }
	  d3.geom.hull = function(vertices) {
	    var x = d3_geom_pointX, y = d3_geom_pointY;
	    if (arguments.length) return hull(vertices);
	    function hull(data) {
	      if (data.length < 3) return [];
	      var fx = d3_functor(x), fy = d3_functor(y), i, n = data.length, points = [], flippedPoints = [];
	      for (i = 0; i < n; i++) {
	        points.push([ +fx.call(this, data[i], i), +fy.call(this, data[i], i), i ]);
	      }
	      points.sort(d3_geom_hullOrder);
	      for (i = 0; i < n; i++) flippedPoints.push([ points[i][0], -points[i][1] ]);
	      var upper = d3_geom_hullUpper(points), lower = d3_geom_hullUpper(flippedPoints);
	      var skipLeft = lower[0] === upper[0], skipRight = lower[lower.length - 1] === upper[upper.length - 1], polygon = [];
	      for (i = upper.length - 1; i >= 0; --i) polygon.push(data[points[upper[i]][2]]);
	      for (i = +skipLeft; i < lower.length - skipRight; ++i) polygon.push(data[points[lower[i]][2]]);
	      return polygon;
	    }
	    hull.x = function(_) {
	      return arguments.length ? (x = _, hull) : x;
	    };
	    hull.y = function(_) {
	      return arguments.length ? (y = _, hull) : y;
	    };
	    return hull;
	  };
	  function d3_geom_hullUpper(points) {
	    var n = points.length, hull = [ 0, 1 ], hs = 2;
	    for (var i = 2; i < n; i++) {
	      while (hs > 1 && d3_cross2d(points[hull[hs - 2]], points[hull[hs - 1]], points[i]) <= 0) --hs;
	      hull[hs++] = i;
	    }
	    return hull.slice(0, hs);
	  }
	  function d3_geom_hullOrder(a, b) {
	    return a[0] - b[0] || a[1] - b[1];
	  }
	  d3.geom.polygon = function(coordinates) {
	    d3_subclass(coordinates, d3_geom_polygonPrototype);
	    return coordinates;
	  };
	  var d3_geom_polygonPrototype = d3.geom.polygon.prototype = [];
	  d3_geom_polygonPrototype.area = function() {
	    var i = -1, n = this.length, a, b = this[n - 1], area = 0;
	    while (++i < n) {
	      a = b;
	      b = this[i];
	      area += a[1] * b[0] - a[0] * b[1];
	    }
	    return area * .5;
	  };
	  d3_geom_polygonPrototype.centroid = function(k) {
	    var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c;
	    if (!arguments.length) k = -1 / (6 * this.area());
	    while (++i < n) {
	      a = b;
	      b = this[i];
	      c = a[0] * b[1] - b[0] * a[1];
	      x += (a[0] + b[0]) * c;
	      y += (a[1] + b[1]) * c;
	    }
	    return [ x * k, y * k ];
	  };
	  d3_geom_polygonPrototype.clip = function(subject) {
	    var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d;
	    while (++i < n) {
	      input = subject.slice();
	      subject.length = 0;
	      b = this[i];
	      c = input[(m = input.length - closed) - 1];
	      j = -1;
	      while (++j < m) {
	        d = input[j];
	        if (d3_geom_polygonInside(d, a, b)) {
	          if (!d3_geom_polygonInside(c, a, b)) {
	            subject.push(d3_geom_polygonIntersect(c, d, a, b));
	          }
	          subject.push(d);
	        } else if (d3_geom_polygonInside(c, a, b)) {
	          subject.push(d3_geom_polygonIntersect(c, d, a, b));
	        }
	        c = d;
	      }
	      if (closed) subject.push(subject[0]);
	      a = b;
	    }
	    return subject;
	  };
	  function d3_geom_polygonInside(p, a, b) {
	    return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
	  }
	  function d3_geom_polygonIntersect(c, d, a, b) {
	    var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21);
	    return [ x1 + ua * x21, y1 + ua * y21 ];
	  }
	  function d3_geom_polygonClosed(coordinates) {
	    var a = coordinates[0], b = coordinates[coordinates.length - 1];
	    return !(a[0] - b[0] || a[1] - b[1]);
	  }
	  var d3_geom_voronoiEdges, d3_geom_voronoiCells, d3_geom_voronoiBeaches, d3_geom_voronoiBeachPool = [], d3_geom_voronoiFirstCircle, d3_geom_voronoiCircles, d3_geom_voronoiCirclePool = [];
	  function d3_geom_voronoiBeach() {
	    d3_geom_voronoiRedBlackNode(this);
	    this.edge = this.site = this.circle = null;
	  }
	  function d3_geom_voronoiCreateBeach(site) {
	    var beach = d3_geom_voronoiBeachPool.pop() || new d3_geom_voronoiBeach();
	    beach.site = site;
	    return beach;
	  }
	  function d3_geom_voronoiDetachBeach(beach) {
	    d3_geom_voronoiDetachCircle(beach);
	    d3_geom_voronoiBeaches.remove(beach);
	    d3_geom_voronoiBeachPool.push(beach);
	    d3_geom_voronoiRedBlackNode(beach);
	  }
	  function d3_geom_voronoiRemoveBeach(beach) {
	    var circle = beach.circle, x = circle.x, y = circle.cy, vertex = {
	      x: x,
	      y: y
	    }, previous = beach.P, next = beach.N, disappearing = [ beach ];
	    d3_geom_voronoiDetachBeach(beach);
	    var lArc = previous;
	    while (lArc.circle && abs(x - lArc.circle.x) < ε && abs(y - lArc.circle.cy) < ε) {
	      previous = lArc.P;
	      disappearing.unshift(lArc);
	      d3_geom_voronoiDetachBeach(lArc);
	      lArc = previous;
	    }
	    disappearing.unshift(lArc);
	    d3_geom_voronoiDetachCircle(lArc);
	    var rArc = next;
	    while (rArc.circle && abs(x - rArc.circle.x) < ε && abs(y - rArc.circle.cy) < ε) {
	      next = rArc.N;
	      disappearing.push(rArc);
	      d3_geom_voronoiDetachBeach(rArc);
	      rArc = next;
	    }
	    disappearing.push(rArc);
	    d3_geom_voronoiDetachCircle(rArc);
	    var nArcs = disappearing.length, iArc;
	    for (iArc = 1; iArc < nArcs; ++iArc) {
	      rArc = disappearing[iArc];
	      lArc = disappearing[iArc - 1];
	      d3_geom_voronoiSetEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
	    }
	    lArc = disappearing[0];
	    rArc = disappearing[nArcs - 1];
	    rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, rArc.site, null, vertex);
	    d3_geom_voronoiAttachCircle(lArc);
	    d3_geom_voronoiAttachCircle(rArc);
	  }
	  function d3_geom_voronoiAddBeach(site) {
	    var x = site.x, directrix = site.y, lArc, rArc, dxl, dxr, node = d3_geom_voronoiBeaches._;
	    while (node) {
	      dxl = d3_geom_voronoiLeftBreakPoint(node, directrix) - x;
	      if (dxl > ε) node = node.L; else {
	        dxr = x - d3_geom_voronoiRightBreakPoint(node, directrix);
	        if (dxr > ε) {
	          if (!node.R) {
	            lArc = node;
	            break;
	          }
	          node = node.R;
	        } else {
	          if (dxl > -ε) {
	            lArc = node.P;
	            rArc = node;
	          } else if (dxr > -ε) {
	            lArc = node;
	            rArc = node.N;
	          } else {
	            lArc = rArc = node;
	          }
	          break;
	        }
	      }
	    }
	    var newArc = d3_geom_voronoiCreateBeach(site);
	    d3_geom_voronoiBeaches.insert(lArc, newArc);
	    if (!lArc && !rArc) return;
	    if (lArc === rArc) {
	      d3_geom_voronoiDetachCircle(lArc);
	      rArc = d3_geom_voronoiCreateBeach(lArc.site);
	      d3_geom_voronoiBeaches.insert(newArc, rArc);
	      newArc.edge = rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);
	      d3_geom_voronoiAttachCircle(lArc);
	      d3_geom_voronoiAttachCircle(rArc);
	      return;
	    }
	    if (!rArc) {
	      newArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);
	      return;
	    }
	    d3_geom_voronoiDetachCircle(lArc);
	    d3_geom_voronoiDetachCircle(rArc);
	    var lSite = lArc.site, ax = lSite.x, ay = lSite.y, bx = site.x - ax, by = site.y - ay, rSite = rArc.site, cx = rSite.x - ax, cy = rSite.y - ay, d = 2 * (bx * cy - by * cx), hb = bx * bx + by * by, hc = cx * cx + cy * cy, vertex = {
	      x: (cy * hb - by * hc) / d + ax,
	      y: (bx * hc - cx * hb) / d + ay
	    };
	    d3_geom_voronoiSetEdgeEnd(rArc.edge, lSite, rSite, vertex);
	    newArc.edge = d3_geom_voronoiCreateEdge(lSite, site, null, vertex);
	    rArc.edge = d3_geom_voronoiCreateEdge(site, rSite, null, vertex);
	    d3_geom_voronoiAttachCircle(lArc);
	    d3_geom_voronoiAttachCircle(rArc);
	  }
	  function d3_geom_voronoiLeftBreakPoint(arc, directrix) {
	    var site = arc.site, rfocx = site.x, rfocy = site.y, pby2 = rfocy - directrix;
	    if (!pby2) return rfocx;
	    var lArc = arc.P;
	    if (!lArc) return -Infinity;
	    site = lArc.site;
	    var lfocx = site.x, lfocy = site.y, plby2 = lfocy - directrix;
	    if (!plby2) return lfocx;
	    var hl = lfocx - rfocx, aby2 = 1 / pby2 - 1 / plby2, b = hl / plby2;
	    if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
	    return (rfocx + lfocx) / 2;
	  }
	  function d3_geom_voronoiRightBreakPoint(arc, directrix) {
	    var rArc = arc.N;
	    if (rArc) return d3_geom_voronoiLeftBreakPoint(rArc, directrix);
	    var site = arc.site;
	    return site.y === directrix ? site.x : Infinity;
	  }
	  function d3_geom_voronoiCell(site) {
	    this.site = site;
	    this.edges = [];
	  }
	  d3_geom_voronoiCell.prototype.prepare = function() {
	    var halfEdges = this.edges, iHalfEdge = halfEdges.length, edge;
	    while (iHalfEdge--) {
	      edge = halfEdges[iHalfEdge].edge;
	      if (!edge.b || !edge.a) halfEdges.splice(iHalfEdge, 1);
	    }
	    halfEdges.sort(d3_geom_voronoiHalfEdgeOrder);
	    return halfEdges.length;
	  };
	  function d3_geom_voronoiCloseCells(extent) {
	    var x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], x2, y2, x3, y3, cells = d3_geom_voronoiCells, iCell = cells.length, cell, iHalfEdge, halfEdges, nHalfEdges, start, end;
	    while (iCell--) {
	      cell = cells[iCell];
	      if (!cell || !cell.prepare()) continue;
	      halfEdges = cell.edges;
	      nHalfEdges = halfEdges.length;
	      iHalfEdge = 0;
	      while (iHalfEdge < nHalfEdges) {
	        end = halfEdges[iHalfEdge].end(), x3 = end.x, y3 = end.y;
	        start = halfEdges[++iHalfEdge % nHalfEdges].start(), x2 = start.x, y2 = start.y;
	        if (abs(x3 - x2) > ε || abs(y3 - y2) > ε) {
	          halfEdges.splice(iHalfEdge, 0, new d3_geom_voronoiHalfEdge(d3_geom_voronoiCreateBorderEdge(cell.site, end, abs(x3 - x0) < ε && y1 - y3 > ε ? {
	            x: x0,
	            y: abs(x2 - x0) < ε ? y2 : y1
	          } : abs(y3 - y1) < ε && x1 - x3 > ε ? {
	            x: abs(y2 - y1) < ε ? x2 : x1,
	            y: y1
	          } : abs(x3 - x1) < ε && y3 - y0 > ε ? {
	            x: x1,
	            y: abs(x2 - x1) < ε ? y2 : y0
	          } : abs(y3 - y0) < ε && x3 - x0 > ε ? {
	            x: abs(y2 - y0) < ε ? x2 : x0,
	            y: y0
	          } : null), cell.site, null));
	          ++nHalfEdges;
	        }
	      }
	    }
	  }
	  function d3_geom_voronoiHalfEdgeOrder(a, b) {
	    return b.angle - a.angle;
	  }
	  function d3_geom_voronoiCircle() {
	    d3_geom_voronoiRedBlackNode(this);
	    this.x = this.y = this.arc = this.site = this.cy = null;
	  }
	  function d3_geom_voronoiAttachCircle(arc) {
	    var lArc = arc.P, rArc = arc.N;
	    if (!lArc || !rArc) return;
	    var lSite = lArc.site, cSite = arc.site, rSite = rArc.site;
	    if (lSite === rSite) return;
	    var bx = cSite.x, by = cSite.y, ax = lSite.x - bx, ay = lSite.y - by, cx = rSite.x - bx, cy = rSite.y - by;
	    var d = 2 * (ax * cy - ay * cx);
	    if (d >= -ε2) return;
	    var ha = ax * ax + ay * ay, hc = cx * cx + cy * cy, x = (cy * ha - ay * hc) / d, y = (ax * hc - cx * ha) / d, cy = y + by;
	    var circle = d3_geom_voronoiCirclePool.pop() || new d3_geom_voronoiCircle();
	    circle.arc = arc;
	    circle.site = cSite;
	    circle.x = x + bx;
	    circle.y = cy + Math.sqrt(x * x + y * y);
	    circle.cy = cy;
	    arc.circle = circle;
	    var before = null, node = d3_geom_voronoiCircles._;
	    while (node) {
	      if (circle.y < node.y || circle.y === node.y && circle.x <= node.x) {
	        if (node.L) node = node.L; else {
	          before = node.P;
	          break;
	        }
	      } else {
	        if (node.R) node = node.R; else {
	          before = node;
	          break;
	        }
	      }
	    }
	    d3_geom_voronoiCircles.insert(before, circle);
	    if (!before) d3_geom_voronoiFirstCircle = circle;
	  }
	  function d3_geom_voronoiDetachCircle(arc) {
	    var circle = arc.circle;
	    if (circle) {
	      if (!circle.P) d3_geom_voronoiFirstCircle = circle.N;
	      d3_geom_voronoiCircles.remove(circle);
	      d3_geom_voronoiCirclePool.push(circle);
	      d3_geom_voronoiRedBlackNode(circle);
	      arc.circle = null;
	    }
	  }
	  function d3_geom_voronoiClipEdges(extent) {
	    var edges = d3_geom_voronoiEdges, clip = d3_geom_clipLine(extent[0][0], extent[0][1], extent[1][0], extent[1][1]), i = edges.length, e;
	    while (i--) {
	      e = edges[i];
	      if (!d3_geom_voronoiConnectEdge(e, extent) || !clip(e) || abs(e.a.x - e.b.x) < ε && abs(e.a.y - e.b.y) < ε) {
	        e.a = e.b = null;
	        edges.splice(i, 1);
	      }
	    }
	  }
	  function d3_geom_voronoiConnectEdge(edge, extent) {
	    var vb = edge.b;
	    if (vb) return true;
	    var va = edge.a, x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], lSite = edge.l, rSite = edge.r, lx = lSite.x, ly = lSite.y, rx = rSite.x, ry = rSite.y, fx = (lx + rx) / 2, fy = (ly + ry) / 2, fm, fb;
	    if (ry === ly) {
	      if (fx < x0 || fx >= x1) return;
	      if (lx > rx) {
	        if (!va) va = {
	          x: fx,
	          y: y0
	        }; else if (va.y >= y1) return;
	        vb = {
	          x: fx,
	          y: y1
	        };
	      } else {
	        if (!va) va = {
	          x: fx,
	          y: y1
	        }; else if (va.y < y0) return;
	        vb = {
	          x: fx,
	          y: y0
	        };
	      }
	    } else {
	      fm = (lx - rx) / (ry - ly);
	      fb = fy - fm * fx;
	      if (fm < -1 || fm > 1) {
	        if (lx > rx) {
	          if (!va) va = {
	            x: (y0 - fb) / fm,
	            y: y0
	          }; else if (va.y >= y1) return;
	          vb = {
	            x: (y1 - fb) / fm,
	            y: y1
	          };
	        } else {
	          if (!va) va = {
	            x: (y1 - fb) / fm,
	            y: y1
	          }; else if (va.y < y0) return;
	          vb = {
	            x: (y0 - fb) / fm,
	            y: y0
	          };
	        }
	      } else {
	        if (ly < ry) {
	          if (!va) va = {
	            x: x0,
	            y: fm * x0 + fb
	          }; else if (va.x >= x1) return;
	          vb = {
	            x: x1,
	            y: fm * x1 + fb
	          };
	        } else {
	          if (!va) va = {
	            x: x1,
	            y: fm * x1 + fb
	          }; else if (va.x < x0) return;
	          vb = {
	            x: x0,
	            y: fm * x0 + fb
	          };
	        }
	      }
	    }
	    edge.a = va;
	    edge.b = vb;
	    return true;
	  }
	  function d3_geom_voronoiEdge(lSite, rSite) {
	    this.l = lSite;
	    this.r = rSite;
	    this.a = this.b = null;
	  }
	  function d3_geom_voronoiCreateEdge(lSite, rSite, va, vb) {
	    var edge = new d3_geom_voronoiEdge(lSite, rSite);
	    d3_geom_voronoiEdges.push(edge);
	    if (va) d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, va);
	    if (vb) d3_geom_voronoiSetEdgeEnd(edge, rSite, lSite, vb);
	    d3_geom_voronoiCells[lSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, lSite, rSite));
	    d3_geom_voronoiCells[rSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, rSite, lSite));
	    return edge;
	  }
	  function d3_geom_voronoiCreateBorderEdge(lSite, va, vb) {
	    var edge = new d3_geom_voronoiEdge(lSite, null);
	    edge.a = va;
	    edge.b = vb;
	    d3_geom_voronoiEdges.push(edge);
	    return edge;
	  }
	  function d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, vertex) {
	    if (!edge.a && !edge.b) {
	      edge.a = vertex;
	      edge.l = lSite;
	      edge.r = rSite;
	    } else if (edge.l === rSite) {
	      edge.b = vertex;
	    } else {
	      edge.a = vertex;
	    }
	  }
	  function d3_geom_voronoiHalfEdge(edge, lSite, rSite) {
	    var va = edge.a, vb = edge.b;
	    this.edge = edge;
	    this.site = lSite;
	    this.angle = rSite ? Math.atan2(rSite.y - lSite.y, rSite.x - lSite.x) : edge.l === lSite ? Math.atan2(vb.x - va.x, va.y - vb.y) : Math.atan2(va.x - vb.x, vb.y - va.y);
	  }
	  d3_geom_voronoiHalfEdge.prototype = {
	    start: function() {
	      return this.edge.l === this.site ? this.edge.a : this.edge.b;
	    },
	    end: function() {
	      return this.edge.l === this.site ? this.edge.b : this.edge.a;
	    }
	  };
	  function d3_geom_voronoiRedBlackTree() {
	    this._ = null;
	  }
	  function d3_geom_voronoiRedBlackNode(node) {
	    node.U = node.C = node.L = node.R = node.P = node.N = null;
	  }
	  d3_geom_voronoiRedBlackTree.prototype = {
	    insert: function(after, node) {
	      var parent, grandpa, uncle;
	      if (after) {
	        node.P = after;
	        node.N = after.N;
	        if (after.N) after.N.P = node;
	        after.N = node;
	        if (after.R) {
	          after = after.R;
	          while (after.L) after = after.L;
	          after.L = node;
	        } else {
	          after.R = node;
	        }
	        parent = after;
	      } else if (this._) {
	        after = d3_geom_voronoiRedBlackFirst(this._);
	        node.P = null;
	        node.N = after;
	        after.P = after.L = node;
	        parent = after;
	      } else {
	        node.P = node.N = null;
	        this._ = node;
	        parent = null;
	      }
	      node.L = node.R = null;
	      node.U = parent;
	      node.C = true;
	      after = node;
	      while (parent && parent.C) {
	        grandpa = parent.U;
	        if (parent === grandpa.L) {
	          uncle = grandpa.R;
	          if (uncle && uncle.C) {
	            parent.C = uncle.C = false;
	            grandpa.C = true;
	            after = grandpa;
	          } else {
	            if (after === parent.R) {
	              d3_geom_voronoiRedBlackRotateLeft(this, parent);
	              after = parent;
	              parent = after.U;
	            }
	            parent.C = false;
	            grandpa.C = true;
	            d3_geom_voronoiRedBlackRotateRight(this, grandpa);
	          }
	        } else {
	          uncle = grandpa.L;
	          if (uncle && uncle.C) {
	            parent.C = uncle.C = false;
	            grandpa.C = true;
	            after = grandpa;
	          } else {
	            if (after === parent.L) {
	              d3_geom_voronoiRedBlackRotateRight(this, parent);
	              after = parent;
	              parent = after.U;
	            }
	            parent.C = false;
	            grandpa.C = true;
	            d3_geom_voronoiRedBlackRotateLeft(this, grandpa);
	          }
	        }
	        parent = after.U;
	      }
	      this._.C = false;
	    },
	    remove: function(node) {
	      if (node.N) node.N.P = node.P;
	      if (node.P) node.P.N = node.N;
	      node.N = node.P = null;
	      var parent = node.U, sibling, left = node.L, right = node.R, next, red;
	      if (!left) next = right; else if (!right) next = left; else next = d3_geom_voronoiRedBlackFirst(right);
	      if (parent) {
	        if (parent.L === node) parent.L = next; else parent.R = next;
	      } else {
	        this._ = next;
	      }
	      if (left && right) {
	        red = next.C;
	        next.C = node.C;
	        next.L = left;
	        left.U = next;
	        if (next !== right) {
	          parent = next.U;
	          next.U = node.U;
	          node = next.R;
	          parent.L = node;
	          next.R = right;
	          right.U = next;
	        } else {
	          next.U = parent;
	          parent = next;
	          node = next.R;
	        }
	      } else {
	        red = node.C;
	        node = next;
	      }
	      if (node) node.U = parent;
	      if (red) return;
	      if (node && node.C) {
	        node.C = false;
	        return;
	      }
	      do {
	        if (node === this._) break;
	        if (node === parent.L) {
	          sibling = parent.R;
	          if (sibling.C) {
	            sibling.C = false;
	            parent.C = true;
	            d3_geom_voronoiRedBlackRotateLeft(this, parent);
	            sibling = parent.R;
	          }
	          if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {
	            if (!sibling.R || !sibling.R.C) {
	              sibling.L.C = false;
	              sibling.C = true;
	              d3_geom_voronoiRedBlackRotateRight(this, sibling);
	              sibling = parent.R;
	            }
	            sibling.C = parent.C;
	            parent.C = sibling.R.C = false;
	            d3_geom_voronoiRedBlackRotateLeft(this, parent);
	            node = this._;
	            break;
	          }
	        } else {
	          sibling = parent.L;
	          if (sibling.C) {
	            sibling.C = false;
	            parent.C = true;
	            d3_geom_voronoiRedBlackRotateRight(this, parent);
	            sibling = parent.L;
	          }
	          if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {
	            if (!sibling.L || !sibling.L.C) {
	              sibling.R.C = false;
	              sibling.C = true;
	              d3_geom_voronoiRedBlackRotateLeft(this, sibling);
	              sibling = parent.L;
	            }
	            sibling.C = parent.C;
	            parent.C = sibling.L.C = false;
	            d3_geom_voronoiRedBlackRotateRight(this, parent);
	            node = this._;
	            break;
	          }
	        }
	        sibling.C = true;
	        node = parent;
	        parent = parent.U;
	      } while (!node.C);
	      if (node) node.C = false;
	    }
	  };
	  function d3_geom_voronoiRedBlackRotateLeft(tree, node) {
	    var p = node, q = node.R, parent = p.U;
	    if (parent) {
	      if (parent.L === p) parent.L = q; else parent.R = q;
	    } else {
	      tree._ = q;
	    }
	    q.U = parent;
	    p.U = q;
	    p.R = q.L;
	    if (p.R) p.R.U = p;
	    q.L = p;
	  }
	  function d3_geom_voronoiRedBlackRotateRight(tree, node) {
	    var p = node, q = node.L, parent = p.U;
	    if (parent) {
	      if (parent.L === p) parent.L = q; else parent.R = q;
	    } else {
	      tree._ = q;
	    }
	    q.U = parent;
	    p.U = q;
	    p.L = q.R;
	    if (p.L) p.L.U = p;
	    q.R = p;
	  }
	  function d3_geom_voronoiRedBlackFirst(node) {
	    while (node.L) node = node.L;
	    return node;
	  }
	  function d3_geom_voronoi(sites, bbox) {
	    var site = sites.sort(d3_geom_voronoiVertexOrder).pop(), x0, y0, circle;
	    d3_geom_voronoiEdges = [];
	    d3_geom_voronoiCells = new Array(sites.length);
	    d3_geom_voronoiBeaches = new d3_geom_voronoiRedBlackTree();
	    d3_geom_voronoiCircles = new d3_geom_voronoiRedBlackTree();
	    while (true) {
	      circle = d3_geom_voronoiFirstCircle;
	      if (site && (!circle || site.y < circle.y || site.y === circle.y && site.x < circle.x)) {
	        if (site.x !== x0 || site.y !== y0) {
	          d3_geom_voronoiCells[site.i] = new d3_geom_voronoiCell(site);
	          d3_geom_voronoiAddBeach(site);
	          x0 = site.x, y0 = site.y;
	        }
	        site = sites.pop();
	      } else if (circle) {
	        d3_geom_voronoiRemoveBeach(circle.arc);
	      } else {
	        break;
	      }
	    }
	    if (bbox) d3_geom_voronoiClipEdges(bbox), d3_geom_voronoiCloseCells(bbox);
	    var diagram = {
	      cells: d3_geom_voronoiCells,
	      edges: d3_geom_voronoiEdges
	    };
	    d3_geom_voronoiBeaches = d3_geom_voronoiCircles = d3_geom_voronoiEdges = d3_geom_voronoiCells = null;
	    return diagram;
	  }
	  function d3_geom_voronoiVertexOrder(a, b) {
	    return b.y - a.y || b.x - a.x;
	  }
	  d3.geom.voronoi = function(points) {
	    var x = d3_geom_pointX, y = d3_geom_pointY, fx = x, fy = y, clipExtent = d3_geom_voronoiClipExtent;
	    if (points) return voronoi(points);
	    function voronoi(data) {
	      var polygons = new Array(data.length), x0 = clipExtent[0][0], y0 = clipExtent[0][1], x1 = clipExtent[1][0], y1 = clipExtent[1][1];
	      d3_geom_voronoi(sites(data), clipExtent).cells.forEach(function(cell, i) {
	        var edges = cell.edges, site = cell.site, polygon = polygons[i] = edges.length ? edges.map(function(e) {
	          var s = e.start();
	          return [ s.x, s.y ];
	        }) : site.x >= x0 && site.x <= x1 && site.y >= y0 && site.y <= y1 ? [ [ x0, y1 ], [ x1, y1 ], [ x1, y0 ], [ x0, y0 ] ] : [];
	        polygon.point = data[i];
	      });
	      return polygons;
	    }
	    function sites(data) {
	      return data.map(function(d, i) {
	        return {
	          x: Math.round(fx(d, i) / ε) * ε,
	          y: Math.round(fy(d, i) / ε) * ε,
	          i: i
	        };
	      });
	    }
	    voronoi.links = function(data) {
	      return d3_geom_voronoi(sites(data)).edges.filter(function(edge) {
	        return edge.l && edge.r;
	      }).map(function(edge) {
	        return {
	          source: data[edge.l.i],
	          target: data[edge.r.i]
	        };
	      });
	    };
	    voronoi.triangles = function(data) {
	      var triangles = [];
	      d3_geom_voronoi(sites(data)).cells.forEach(function(cell, i) {
	        var site = cell.site, edges = cell.edges.sort(d3_geom_voronoiHalfEdgeOrder), j = -1, m = edges.length, e0, s0, e1 = edges[m - 1].edge, s1 = e1.l === site ? e1.r : e1.l;
	        while (++j < m) {
	          e0 = e1;
	          s0 = s1;
	          e1 = edges[j].edge;
	          s1 = e1.l === site ? e1.r : e1.l;
	          if (i < s0.i && i < s1.i && d3_geom_voronoiTriangleArea(site, s0, s1) < 0) {
	            triangles.push([ data[i], data[s0.i], data[s1.i] ]);
	          }
	        }
	      });
	      return triangles;
	    };
	    voronoi.x = function(_) {
	      return arguments.length ? (fx = d3_functor(x = _), voronoi) : x;
	    };
	    voronoi.y = function(_) {
	      return arguments.length ? (fy = d3_functor(y = _), voronoi) : y;
	    };
	    voronoi.clipExtent = function(_) {
	      if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent;
	      clipExtent = _ == null ? d3_geom_voronoiClipExtent : _;
	      return voronoi;
	    };
	    voronoi.size = function(_) {
	      if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent && clipExtent[1];
	      return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]);
	    };
	    return voronoi;
	  };
	  var d3_geom_voronoiClipExtent = [ [ -1e6, -1e6 ], [ 1e6, 1e6 ] ];
	  function d3_geom_voronoiTriangleArea(a, b, c) {
	    return (a.x - c.x) * (b.y - a.y) - (a.x - b.x) * (c.y - a.y);
	  }
	  d3.geom.delaunay = function(vertices) {
	    return d3.geom.voronoi().triangles(vertices);
	  };
	  d3.geom.quadtree = function(points, x1, y1, x2, y2) {
	    var x = d3_geom_pointX, y = d3_geom_pointY, compat;
	    if (compat = arguments.length) {
	      x = d3_geom_quadtreeCompatX;
	      y = d3_geom_quadtreeCompatY;
	      if (compat === 3) {
	        y2 = y1;
	        x2 = x1;
	        y1 = x1 = 0;
	      }
	      return quadtree(points);
	    }
	    function quadtree(data) {
	      var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_;
	      if (x1 != null) {
	        x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2;
	      } else {
	        x2_ = y2_ = -(x1_ = y1_ = Infinity);
	        xs = [], ys = [];
	        n = data.length;
	        if (compat) for (i = 0; i < n; ++i) {
	          d = data[i];
	          if (d.x < x1_) x1_ = d.x;
	          if (d.y < y1_) y1_ = d.y;
	          if (d.x > x2_) x2_ = d.x;
	          if (d.y > y2_) y2_ = d.y;
	          xs.push(d.x);
	          ys.push(d.y);
	        } else for (i = 0; i < n; ++i) {
	          var x_ = +fx(d = data[i], i), y_ = +fy(d, i);
	          if (x_ < x1_) x1_ = x_;
	          if (y_ < y1_) y1_ = y_;
	          if (x_ > x2_) x2_ = x_;
	          if (y_ > y2_) y2_ = y_;
	          xs.push(x_);
	          ys.push(y_);
	        }
	      }
	      var dx = x2_ - x1_, dy = y2_ - y1_;
	      if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy;
	      function insert(n, d, x, y, x1, y1, x2, y2) {
	        if (isNaN(x) || isNaN(y)) return;
	        if (n.leaf) {
	          var nx = n.x, ny = n.y;
	          if (nx != null) {
	            if (abs(nx - x) + abs(ny - y) < .01) {
	              insertChild(n, d, x, y, x1, y1, x2, y2);
	            } else {
	              var nPoint = n.point;
	              n.x = n.y = n.point = null;
	              insertChild(n, nPoint, nx, ny, x1, y1, x2, y2);
	              insertChild(n, d, x, y, x1, y1, x2, y2);
	            }
	          } else {
	            n.x = x, n.y = y, n.point = d;
	          }
	        } else {
	          insertChild(n, d, x, y, x1, y1, x2, y2);
	        }
	      }
	      function insertChild(n, d, x, y, x1, y1, x2, y2) {
	        var xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym, i = below << 1 | right;
	        n.leaf = false;
	        n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
	        if (right) x1 = xm; else x2 = xm;
	        if (below) y1 = ym; else y2 = ym;
	        insert(n, d, x, y, x1, y1, x2, y2);
	      }
	      var root = d3_geom_quadtreeNode();
	      root.add = function(d) {
	        insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_);
	      };
	      root.visit = function(f) {
	        d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_);
	      };
	      root.find = function(point) {
	        return d3_geom_quadtreeFind(root, point[0], point[1], x1_, y1_, x2_, y2_);
	      };
	      i = -1;
	      if (x1 == null) {
	        while (++i < n) {
	          insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_);
	        }
	        --i;
	      } else data.forEach(root.add);
	      xs = ys = data = d = null;
	      return root;
	    }
	    quadtree.x = function(_) {
	      return arguments.length ? (x = _, quadtree) : x;
	    };
	    quadtree.y = function(_) {
	      return arguments.length ? (y = _, quadtree) : y;
	    };
	    quadtree.extent = function(_) {
	      if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ];
	      if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], 
	      y2 = +_[1][1];
	      return quadtree;
	    };
	    quadtree.size = function(_) {
	      if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ];
	      if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1];
	      return quadtree;
	    };
	    return quadtree;
	  };
	  function d3_geom_quadtreeCompatX(d) {
	    return d.x;
	  }
	  function d3_geom_quadtreeCompatY(d) {
	    return d.y;
	  }
	  function d3_geom_quadtreeNode() {
	    return {
	      leaf: true,
	      nodes: [],
	      point: null,
	      x: null,
	      y: null
	    };
	  }
	  function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
	    if (!f(node, x1, y1, x2, y2)) {
	      var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes;
	      if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
	      if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
	      if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
	      if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
	    }
	  }
	  function d3_geom_quadtreeFind(root, x, y, x0, y0, x3, y3) {
	    var minDistance2 = Infinity, closestPoint;
	    (function find(node, x1, y1, x2, y2) {
	      if (x1 > x3 || y1 > y3 || x2 < x0 || y2 < y0) return;
	      if (point = node.point) {
	        var point, dx = x - node.x, dy = y - node.y, distance2 = dx * dx + dy * dy;
	        if (distance2 < minDistance2) {
	          var distance = Math.sqrt(minDistance2 = distance2);
	          x0 = x - distance, y0 = y - distance;
	          x3 = x + distance, y3 = y + distance;
	          closestPoint = point;
	        }
	      }
	      var children = node.nodes, xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym;
	      for (var i = below << 1 | right, j = i + 4; i < j; ++i) {
	        if (node = children[i & 3]) switch (i & 3) {
	         case 0:
	          find(node, x1, y1, xm, ym);
	          break;
	
	         case 1:
	          find(node, xm, y1, x2, ym);
	          break;
	
	         case 2:
	          find(node, x1, ym, xm, y2);
	          break;
	
	         case 3:
	          find(node, xm, ym, x2, y2);
	          break;
	        }
	      }
	    })(root, x0, y0, x3, y3);
	    return closestPoint;
	  }
	  d3.interpolateRgb = d3_interpolateRgb;
	  function d3_interpolateRgb(a, b) {
	    a = d3.rgb(a);
	    b = d3.rgb(b);
	    var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab;
	    return function(t) {
	      return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t));
	    };
	  }
	  d3.interpolateObject = d3_interpolateObject;
	  function d3_interpolateObject(a, b) {
	    var i = {}, c = {}, k;
	    for (k in a) {
	      if (k in b) {
	        i[k] = d3_interpolate(a[k], b[k]);
	      } else {
	        c[k] = a[k];
	      }
	    }
	    for (k in b) {
	      if (!(k in a)) {
	        c[k] = b[k];
	      }
	    }
	    return function(t) {
	      for (k in i) c[k] = i[k](t);
	      return c;
	    };
	  }
	  d3.interpolateNumber = d3_interpolateNumber;
	  function d3_interpolateNumber(a, b) {
	    a = +a, b = +b;
	    return function(t) {
	      return a * (1 - t) + b * t;
	    };
	  }
	  d3.interpolateString = d3_interpolateString;
	  function d3_interpolateString(a, b) {
	    var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, am, bm, bs, i = -1, s = [], q = [];
	    a = a + "", b = b + "";
	    while ((am = d3_interpolate_numberA.exec(a)) && (bm = d3_interpolate_numberB.exec(b))) {
	      if ((bs = bm.index) > bi) {
	        bs = b.slice(bi, bs);
	        if (s[i]) s[i] += bs; else s[++i] = bs;
	      }
	      if ((am = am[0]) === (bm = bm[0])) {
	        if (s[i]) s[i] += bm; else s[++i] = bm;
	      } else {
	        s[++i] = null;
	        q.push({
	          i: i,
	          x: d3_interpolateNumber(am, bm)
	        });
	      }
	      bi = d3_interpolate_numberB.lastIndex;
	    }
	    if (bi < b.length) {
	      bs = b.slice(bi);
	      if (s[i]) s[i] += bs; else s[++i] = bs;
	    }
	    return s.length < 2 ? q[0] ? (b = q[0].x, function(t) {
	      return b(t) + "";
	    }) : function() {
	      return b;
	    } : (b = q.length, function(t) {
	      for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
	      return s.join("");
	    });
	  }
	  var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g, d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g");
	  d3.interpolate = d3_interpolate;
	  function d3_interpolate(a, b) {
	    var i = d3.interpolators.length, f;
	    while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;
	    return f;
	  }
	  d3.interpolators = [ function(a, b) {
	    var t = typeof b;
	    return (t === "string" ? d3_rgb_names.has(b.toLowerCase()) || /^(#|rgb\(|hsl\()/i.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_color ? d3_interpolateRgb : Array.isArray(b) ? d3_interpolateArray : t === "object" && isNaN(b) ? d3_interpolateObject : d3_interpolateNumber)(a, b);
	  } ];
	  d3.interpolateArray = d3_interpolateArray;
	  function d3_interpolateArray(a, b) {
	    var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i;
	    for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i]));
	    for (;i < na; ++i) c[i] = a[i];
	    for (;i < nb; ++i) c[i] = b[i];
	    return function(t) {
	      for (i = 0; i < n0; ++i) c[i] = x[i](t);
	      return c;
	    };
	  }
	  var d3_ease_default = function() {
	    return d3_identity;
	  };
	  var d3_ease = d3.map({
	    linear: d3_ease_default,
	    poly: d3_ease_poly,
	    quad: function() {
	      return d3_ease_quad;
	    },
	    cubic: function() {
	      return d3_ease_cubic;
	    },
	    sin: function() {
	      return d3_ease_sin;
	    },
	    exp: function() {
	      return d3_ease_exp;
	    },
	    circle: function() {
	      return d3_ease_circle;
	    },
	    elastic: d3_ease_elastic,
	    back: d3_ease_back,
	    bounce: function() {
	      return d3_ease_bounce;
	    }
	  });
	  var d3_ease_mode = d3.map({
	    "in": d3_identity,
	    out: d3_ease_reverse,
	    "in-out": d3_ease_reflect,
	    "out-in": function(f) {
	      return d3_ease_reflect(d3_ease_reverse(f));
	    }
	  });
	  d3.ease = function(name) {
	    var i = name.indexOf("-"), t = i >= 0 ? name.slice(0, i) : name, m = i >= 0 ? name.slice(i + 1) : "in";
	    t = d3_ease.get(t) || d3_ease_default;
	    m = d3_ease_mode.get(m) || d3_identity;
	    return d3_ease_clamp(m(t.apply(null, d3_arraySlice.call(arguments, 1))));
	  };
	  function d3_ease_clamp(f) {
	    return function(t) {
	      return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
	    };
	  }
	  function d3_ease_reverse(f) {
	    return function(t) {
	      return 1 - f(1 - t);
	    };
	  }
	  function d3_ease_reflect(f) {
	    return function(t) {
	      return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t));
	    };
	  }
	  function d3_ease_quad(t) {
	    return t * t;
	  }
	  function d3_ease_cubic(t) {
	    return t * t * t;
	  }
	  function d3_ease_cubicInOut(t) {
	    if (t <= 0) return 0;
	    if (t >= 1) return 1;
	    var t2 = t * t, t3 = t2 * t;
	    return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
	  }
	  function d3_ease_poly(e) {
	    return function(t) {
	      return Math.pow(t, e);
	    };
	  }
	  function d3_ease_sin(t) {
	    return 1 - Math.cos(t * halfπ);
	  }
	  function d3_ease_exp(t) {
	    return Math.pow(2, 10 * (t - 1));
	  }
	  function d3_ease_circle(t) {
	    return 1 - Math.sqrt(1 - t * t);
	  }
	  function d3_ease_elastic(a, p) {
	    var s;
	    if (arguments.length < 2) p = .45;
	    if (arguments.length) s = p / τ * Math.asin(1 / a); else a = 1, s = p / 4;
	    return function(t) {
	      return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * τ / p);
	    };
	  }
	  function d3_ease_back(s) {
	    if (!s) s = 1.70158;
	    return function(t) {
	      return t * t * ((s + 1) * t - s);
	    };
	  }
	  function d3_ease_bounce(t) {
	    return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
	  }
	  d3.interpolateHcl = d3_interpolateHcl;
	  function d3_interpolateHcl(a, b) {
	    a = d3.hcl(a);
	    b = d3.hcl(b);
	    var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al;
	    if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac;
	    if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
	    return function(t) {
	      return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + "";
	    };
	  }
	  d3.interpolateHsl = d3_interpolateHsl;
	  function d3_interpolateHsl(a, b) {
	    a = d3.hsl(a);
	    b = d3.hsl(b);
	    var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al;
	    if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as;
	    if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
	    return function(t) {
	      return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + "";
	    };
	  }
	  d3.interpolateLab = d3_interpolateLab;
	  function d3_interpolateLab(a, b) {
	    a = d3.lab(a);
	    b = d3.lab(b);
	    var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab;
	    return function(t) {
	      return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + "";
	    };
	  }
	  d3.interpolateRound = d3_interpolateRound;
	  function d3_interpolateRound(a, b) {
	    b -= a;
	    return function(t) {
	      return Math.round(a + b * t);
	    };
	  }
	  d3.transform = function(string) {
	    var g = d3_document.createElementNS(d3.ns.prefix.svg, "g");
	    return (d3.transform = function(string) {
	      if (string != null) {
	        g.setAttribute("transform", string);
	        var t = g.transform.baseVal.consolidate();
	      }
	      return new d3_transform(t ? t.matrix : d3_transformIdentity);
	    })(string);
	  };
	  function d3_transform(m) {
	    var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;
	    if (r0[0] * r1[1] < r1[0] * r0[1]) {
	      r0[0] *= -1;
	      r0[1] *= -1;
	      kx *= -1;
	      kz *= -1;
	    }
	    this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees;
	    this.translate = [ m.e, m.f ];
	    this.scale = [ kx, ky ];
	    this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0;
	  }
	  d3_transform.prototype.toString = function() {
	    return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")";
	  };
	  function d3_transformDot(a, b) {
	    return a[0] * b[0] + a[1] * b[1];
	  }
	  function d3_transformNormalize(a) {
	    var k = Math.sqrt(d3_transformDot(a, a));
	    if (k) {
	      a[0] /= k;
	      a[1] /= k;
	    }
	    return k;
	  }
	  function d3_transformCombine(a, b, k) {
	    a[0] += k * b[0];
	    a[1] += k * b[1];
	    return a;
	  }
	  var d3_transformIdentity = {
	    a: 1,
	    b: 0,
	    c: 0,
	    d: 1,
	    e: 0,
	    f: 0
	  };
	  d3.interpolateTransform = d3_interpolateTransform;
	  function d3_interpolateTransformPop(s) {
	    return s.length ? s.pop() + "," : "";
	  }
	  function d3_interpolateTranslate(ta, tb, s, q) {
	    if (ta[0] !== tb[0] || ta[1] !== tb[1]) {
	      var i = s.push("translate(", null, ",", null, ")");
	      q.push({
	        i: i - 4,
	        x: d3_interpolateNumber(ta[0], tb[0])
	      }, {
	        i: i - 2,
	        x: d3_interpolateNumber(ta[1], tb[1])
	      });
	    } else if (tb[0] || tb[1]) {
	      s.push("translate(" + tb + ")");
	    }
	  }
	  function d3_interpolateRotate(ra, rb, s, q) {
	    if (ra !== rb) {
	      if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360;
	      q.push({
	        i: s.push(d3_interpolateTransformPop(s) + "rotate(", null, ")") - 2,
	        x: d3_interpolateNumber(ra, rb)
	      });
	    } else if (rb) {
	      s.push(d3_interpolateTransformPop(s) + "rotate(" + rb + ")");
	    }
	  }
	  function d3_interpolateSkew(wa, wb, s, q) {
	    if (wa !== wb) {
	      q.push({
	        i: s.push(d3_interpolateTransformPop(s) + "skewX(", null, ")") - 2,
	        x: d3_interpolateNumber(wa, wb)
	      });
	    } else if (wb) {
	      s.push(d3_interpolateTransformPop(s) + "skewX(" + wb + ")");
	    }
	  }
	  function d3_interpolateScale(ka, kb, s, q) {
	    if (ka[0] !== kb[0] || ka[1] !== kb[1]) {
	      var i = s.push(d3_interpolateTransformPop(s) + "scale(", null, ",", null, ")");
	      q.push({
	        i: i - 4,
	        x: d3_interpolateNumber(ka[0], kb[0])
	      }, {
	        i: i - 2,
	        x: d3_interpolateNumber(ka[1], kb[1])
	      });
	    } else if (kb[0] !== 1 || kb[1] !== 1) {
	      s.push(d3_interpolateTransformPop(s) + "scale(" + kb + ")");
	    }
	  }
	  function d3_interpolateTransform(a, b) {
	    var s = [], q = [];
	    a = d3.transform(a), b = d3.transform(b);
	    d3_interpolateTranslate(a.translate, b.translate, s, q);
	    d3_interpolateRotate(a.rotate, b.rotate, s, q);
	    d3_interpolateSkew(a.skew, b.skew, s, q);
	    d3_interpolateScale(a.scale, b.scale, s, q);
	    a = b = null;
	    return function(t) {
	      var i = -1, n = q.length, o;
	      while (++i < n) s[(o = q[i]).i] = o.x(t);
	      return s.join("");
	    };
	  }
	  function d3_uninterpolateNumber(a, b) {
	    b = (b -= a = +a) || 1 / b;
	    return function(x) {
	      return (x - a) / b;
	    };
	  }
	  function d3_uninterpolateClamp(a, b) {
	    b = (b -= a = +a) || 1 / b;
	    return function(x) {
	      return Math.max(0, Math.min(1, (x - a) / b));
	    };
	  }
	  d3.layout = {};
	  d3.layout.bundle = function() {
	    return function(links) {
	      var paths = [], i = -1, n = links.length;
	      while (++i < n) paths.push(d3_layout_bundlePath(links[i]));
	      return paths;
	    };
	  };
	  function d3_layout_bundlePath(link) {
	    var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ];
	    while (start !== lca) {
	      start = start.parent;
	      points.push(start);
	    }
	    var k = points.length;
	    while (end !== lca) {
	      points.splice(k, 0, end);
	      end = end.parent;
	    }
	    return points;
	  }
	  function d3_layout_bundleAncestors(node) {
	    var ancestors = [], parent = node.parent;
	    while (parent != null) {
	      ancestors.push(node);
	      node = parent;
	      parent = parent.parent;
	    }
	    ancestors.push(node);
	    return ancestors;
	  }
	  function d3_layout_bundleLeastCommonAncestor(a, b) {
	    if (a === b) return a;
	    var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null;
	    while (aNode === bNode) {
	      sharedNode = aNode;
	      aNode = aNodes.pop();
	      bNode = bNodes.pop();
	    }
	    return sharedNode;
	  }
	  d3.layout.chord = function() {
	    var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords;
	    function relayout() {
	      var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j;
	      chords = [];
	      groups = [];
	      k = 0, i = -1;
	      while (++i < n) {
	        x = 0, j = -1;
	        while (++j < n) {
	          x += matrix[i][j];
	        }
	        groupSums.push(x);
	        subgroupIndex.push(d3.range(n));
	        k += x;
	      }
	      if (sortGroups) {
	        groupIndex.sort(function(a, b) {
	          return sortGroups(groupSums[a], groupSums[b]);
	        });
	      }
	      if (sortSubgroups) {
	        subgroupIndex.forEach(function(d, i) {
	          d.sort(function(a, b) {
	            return sortSubgroups(matrix[i][a], matrix[i][b]);
	          });
	        });
	      }
	      k = (τ - padding * n) / k;
	      x = 0, i = -1;
	      while (++i < n) {
	        x0 = x, j = -1;
	        while (++j < n) {
	          var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k;
	          subgroups[di + "-" + dj] = {
	            index: di,
	            subindex: dj,
	            startAngle: a0,
	            endAngle: a1,
	            value: v
	          };
	        }
	        groups[di] = {
	          index: di,
	          startAngle: x0,
	          endAngle: x,
	          value: groupSums[di]
	        };
	        x += padding;
	      }
	      i = -1;
	      while (++i < n) {
	        j = i - 1;
	        while (++j < n) {
	          var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i];
	          if (source.value || target.value) {
	            chords.push(source.value < target.value ? {
	              source: target,
	              target: source
	            } : {
	              source: source,
	              target: target
	            });
	          }
	        }
	      }
	      if (sortChords) resort();
	    }
	    function resort() {
	      chords.sort(function(a, b) {
	        return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2);
	      });
	    }
	    chord.matrix = function(x) {
	      if (!arguments.length) return matrix;
	      n = (matrix = x) && matrix.length;
	      chords = groups = null;
	      return chord;
	    };
	    chord.padding = function(x) {
	      if (!arguments.length) return padding;
	      padding = x;
	      chords = groups = null;
	      return chord;
	    };
	    chord.sortGroups = function(x) {
	      if (!arguments.length) return sortGroups;
	      sortGroups = x;
	      chords = groups = null;
	      return chord;
	    };
	    chord.sortSubgroups = function(x) {
	      if (!arguments.length) return sortSubgroups;
	      sortSubgroups = x;
	      chords = null;
	      return chord;
	    };
	    chord.sortChords = function(x) {
	      if (!arguments.length) return sortChords;
	      sortChords = x;
	      if (chords) resort();
	      return chord;
	    };
	    chord.chords = function() {
	      if (!chords) relayout();
	      return chords;
	    };
	    chord.groups = function() {
	      if (!groups) relayout();
	      return groups;
	    };
	    return chord;
	  };
	  d3.layout.force = function() {
	    var force = {}, event = d3.dispatch("start", "tick", "end"), timer, size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, chargeDistance2 = d3_layout_forceChargeDistance2, gravity = .1, theta2 = .64, nodes = [], links = [], distances, strengths, charges;
	    function repulse(node) {
	      return function(quad, x1, _, x2) {
	        if (quad.point !== node) {
	          var dx = quad.cx - node.x, dy = quad.cy - node.y, dw = x2 - x1, dn = dx * dx + dy * dy;
	          if (dw * dw / theta2 < dn) {
	            if (dn < chargeDistance2) {
	              var k = quad.charge / dn;
	              node.px -= dx * k;
	              node.py -= dy * k;
	            }
	            return true;
	          }
	          if (quad.point && dn && dn < chargeDistance2) {
	            var k = quad.pointCharge / dn;
	            node.px -= dx * k;
	            node.py -= dy * k;
	          }
	        }
	        return !quad.charge;
	      };
	    }
	    force.tick = function() {
	      if ((alpha *= .99) < .005) {
	        timer = null;
	        event.end({
	          type: "end",
	          alpha: alpha = 0
	        });
	        return true;
	      }
	      var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y;
	      for (i = 0; i < m; ++i) {
	        o = links[i];
	        s = o.source;
	        t = o.target;
	        x = t.x - s.x;
	        y = t.y - s.y;
	        if (l = x * x + y * y) {
	          l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
	          x *= l;
	          y *= l;
	          t.x -= x * (k = s.weight + t.weight ? s.weight / (s.weight + t.weight) : .5);
	          t.y -= y * k;
	          s.x += x * (k = 1 - k);
	          s.y += y * k;
	        }
	      }
	      if (k = alpha * gravity) {
	        x = size[0] / 2;
	        y = size[1] / 2;
	        i = -1;
	        if (k) while (++i < n) {
	          o = nodes[i];
	          o.x += (x - o.x) * k;
	          o.y += (y - o.y) * k;
	        }
	      }
	      if (charge) {
	        d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
	        i = -1;
	        while (++i < n) {
	          if (!(o = nodes[i]).fixed) {
	            q.visit(repulse(o));
	          }
	        }
	      }
	      i = -1;
	      while (++i < n) {
	        o = nodes[i];
	        if (o.fixed) {
	          o.x = o.px;
	          o.y = o.py;
	        } else {
	          o.x -= (o.px - (o.px = o.x)) * friction;
	          o.y -= (o.py - (o.py = o.y)) * friction;
	        }
	      }
	      event.tick({
	        type: "tick",
	        alpha: alpha
	      });
	    };
	    force.nodes = function(x) {
	      if (!arguments.length) return nodes;
	      nodes = x;
	      return force;
	    };
	    force.links = function(x) {
	      if (!arguments.length) return links;
	      links = x;
	      return force;
	    };
	    force.size = function(x) {
	      if (!arguments.length) return size;
	      size = x;
	      return force;
	    };
	    force.linkDistance = function(x) {
	      if (!arguments.length) return linkDistance;
	      linkDistance = typeof x === "function" ? x : +x;
	      return force;
	    };
	    force.distance = force.linkDistance;
	    force.linkStrength = function(x) {
	      if (!arguments.length) return linkStrength;
	      linkStrength = typeof x === "function" ? x : +x;
	      return force;
	    };
	    force.friction = function(x) {
	      if (!arguments.length) return friction;
	      friction = +x;
	      return force;
	    };
	    force.charge = function(x) {
	      if (!arguments.length) return charge;
	      charge = typeof x === "function" ? x : +x;
	      return force;
	    };
	    force.chargeDistance = function(x) {
	      if (!arguments.length) return Math.sqrt(chargeDistance2);
	      chargeDistance2 = x * x;
	      return force;
	    };
	    force.gravity = function(x) {
	      if (!arguments.length) return gravity;
	      gravity = +x;
	      return force;
	    };
	    force.theta = function(x) {
	      if (!arguments.length) return Math.sqrt(theta2);
	      theta2 = x * x;
	      return force;
	    };
	    force.alpha = function(x) {
	      if (!arguments.length) return alpha;
	      x = +x;
	      if (alpha) {
	        if (x > 0) {
	          alpha = x;
	        } else {
	          timer.c = null, timer.t = NaN, timer = null;
	          event.end({
	            type: "end",
	            alpha: alpha = 0
	          });
	        }
	      } else if (x > 0) {
	        event.start({
	          type: "start",
	          alpha: alpha = x
	        });
	        timer = d3_timer(force.tick);
	      }
	      return force;
	    };
	    force.start = function() {
	      var i, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o;
	      for (i = 0; i < n; ++i) {
	        (o = nodes[i]).index = i;
	        o.weight = 0;
	      }
	      for (i = 0; i < m; ++i) {
	        o = links[i];
	        if (typeof o.source == "number") o.source = nodes[o.source];
	        if (typeof o.target == "number") o.target = nodes[o.target];
	        ++o.source.weight;
	        ++o.target.weight;
	      }
	      for (i = 0; i < n; ++i) {
	        o = nodes[i];
	        if (isNaN(o.x)) o.x = position("x", w);
	        if (isNaN(o.y)) o.y = position("y", h);
	        if (isNaN(o.px)) o.px = o.x;
	        if (isNaN(o.py)) o.py = o.y;
	      }
	      distances = [];
	      if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance;
	      strengths = [];
	      if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength;
	      charges = [];
	      if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge;
	      function position(dimension, size) {
	        if (!neighbors) {
	          neighbors = new Array(n);
	          for (j = 0; j < n; ++j) {
	            neighbors[j] = [];
	          }
	          for (j = 0; j < m; ++j) {
	            var o = links[j];
	            neighbors[o.source.index].push(o.target);
	            neighbors[o.target.index].push(o.source);
	          }
	        }
	        var candidates = neighbors[i], j = -1, l = candidates.length, x;
	        while (++j < l) if (!isNaN(x = candidates[j][dimension])) return x;
	        return Math.random() * size;
	      }
	      return force.resume();
	    };
	    force.resume = function() {
	      return force.alpha(.1);
	    };
	    force.stop = function() {
	      return force.alpha(0);
	    };
	    force.drag = function() {
	      if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend);
	      if (!arguments.length) return drag;
	      this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag);
	    };
	    function dragmove(d) {
	      d.px = d3.event.x, d.py = d3.event.y;
	      force.resume();
	    }
	    return d3.rebind(force, event, "on");
	  };
	  function d3_layout_forceDragstart(d) {
	    d.fixed |= 2;
	  }
	  function d3_layout_forceDragend(d) {
	    d.fixed &= ~6;
	  }
	  function d3_layout_forceMouseover(d) {
	    d.fixed |= 4;
	    d.px = d.x, d.py = d.y;
	  }
	  function d3_layout_forceMouseout(d) {
	    d.fixed &= ~4;
	  }
	  function d3_layout_forceAccumulate(quad, alpha, charges) {
	    var cx = 0, cy = 0;
	    quad.charge = 0;
	    if (!quad.leaf) {
	      var nodes = quad.nodes, n = nodes.length, i = -1, c;
	      while (++i < n) {
	        c = nodes[i];
	        if (c == null) continue;
	        d3_layout_forceAccumulate(c, alpha, charges);
	        quad.charge += c.charge;
	        cx += c.charge * c.cx;
	        cy += c.charge * c.cy;
	      }
	    }
	    if (quad.point) {
	      if (!quad.leaf) {
	        quad.point.x += Math.random() - .5;
	        quad.point.y += Math.random() - .5;
	      }
	      var k = alpha * charges[quad.point.index];
	      quad.charge += quad.pointCharge = k;
	      cx += k * quad.point.x;
	      cy += k * quad.point.y;
	    }
	    quad.cx = cx / quad.charge;
	    quad.cy = cy / quad.charge;
	  }
	  var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1, d3_layout_forceChargeDistance2 = Infinity;
	  d3.layout.hierarchy = function() {
	    var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue;
	    function hierarchy(root) {
	      var stack = [ root ], nodes = [], node;
	      root.depth = 0;
	      while ((node = stack.pop()) != null) {
	        nodes.push(node);
	        if ((childs = children.call(hierarchy, node, node.depth)) && (n = childs.length)) {
	          var n, childs, child;
	          while (--n >= 0) {
	            stack.push(child = childs[n]);
	            child.parent = node;
	            child.depth = node.depth + 1;
	          }
	          if (value) node.value = 0;
	          node.children = childs;
	        } else {
	          if (value) node.value = +value.call(hierarchy, node, node.depth) || 0;
	          delete node.children;
	        }
	      }
	      d3_layout_hierarchyVisitAfter(root, function(node) {
	        var childs, parent;
	        if (sort && (childs = node.children)) childs.sort(sort);
	        if (value && (parent = node.parent)) parent.value += node.value;
	      });
	      return nodes;
	    }
	    hierarchy.sort = function(x) {
	      if (!arguments.length) return sort;
	      sort = x;
	      return hierarchy;
	    };
	    hierarchy.children = function(x) {
	      if (!arguments.length) return children;
	      children = x;
	      return hierarchy;
	    };
	    hierarchy.value = function(x) {
	      if (!arguments.length) return value;
	      value = x;
	      return hierarchy;
	    };
	    hierarchy.revalue = function(root) {
	      if (value) {
	        d3_layout_hierarchyVisitBefore(root, function(node) {
	          if (node.children) node.value = 0;
	        });
	        d3_layout_hierarchyVisitAfter(root, function(node) {
	          var parent;
	          if (!node.children) node.value = +value.call(hierarchy, node, node.depth) || 0;
	          if (parent = node.parent) parent.value += node.value;
	        });
	      }
	      return root;
	    };
	    return hierarchy;
	  };
	  function d3_layout_hierarchyRebind(object, hierarchy) {
	    d3.rebind(object, hierarchy, "sort", "children", "value");
	    object.nodes = object;
	    object.links = d3_layout_hierarchyLinks;
	    return object;
	  }
	  function d3_layout_hierarchyVisitBefore(node, callback) {
	    var nodes = [ node ];
	    while ((node = nodes.pop()) != null) {
	      callback(node);
	      if ((children = node.children) && (n = children.length)) {
	        var n, children;
	        while (--n >= 0) nodes.push(children[n]);
	      }
	    }
	  }
	  function d3_layout_hierarchyVisitAfter(node, callback) {
	    var nodes = [ node ], nodes2 = [];
	    while ((node = nodes.pop()) != null) {
	      nodes2.push(node);
	      if ((children = node.children) && (n = children.length)) {
	        var i = -1, n, children;
	        while (++i < n) nodes.push(children[i]);
	      }
	    }
	    while ((node = nodes2.pop()) != null) {
	      callback(node);
	    }
	  }
	  function d3_layout_hierarchyChildren(d) {
	    return d.children;
	  }
	  function d3_layout_hierarchyValue(d) {
	    return d.value;
	  }
	  function d3_layout_hierarchySort(a, b) {
	    return b.value - a.value;
	  }
	  function d3_layout_hierarchyLinks(nodes) {
	    return d3.merge(nodes.map(function(parent) {
	      return (parent.children || []).map(function(child) {
	        return {
	          source: parent,
	          target: child
	        };
	      });
	    }));
	  }
	  d3.layout.partition = function() {
	    var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ];
	    function position(node, x, dx, dy) {
	      var children = node.children;
	      node.x = x;
	      node.y = node.depth * dy;
	      node.dx = dx;
	      node.dy = dy;
	      if (children && (n = children.length)) {
	        var i = -1, n, c, d;
	        dx = node.value ? dx / node.value : 0;
	        while (++i < n) {
	          position(c = children[i], x, d = c.value * dx, dy);
	          x += d;
	        }
	      }
	    }
	    function depth(node) {
	      var children = node.children, d = 0;
	      if (children && (n = children.length)) {
	        var i = -1, n;
	        while (++i < n) d = Math.max(d, depth(children[i]));
	      }
	      return 1 + d;
	    }
	    function partition(d, i) {
	      var nodes = hierarchy.call(this, d, i);
	      position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
	      return nodes;
	    }
	    partition.size = function(x) {
	      if (!arguments.length) return size;
	      size = x;
	      return partition;
	    };
	    return d3_layout_hierarchyRebind(partition, hierarchy);
	  };
	  d3.layout.pie = function() {
	    var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = τ, padAngle = 0;
	    function pie(data) {
	      var n = data.length, values = data.map(function(d, i) {
	        return +value.call(pie, d, i);
	      }), a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle), da = (typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a, p = Math.min(Math.abs(da) / n, +(typeof padAngle === "function" ? padAngle.apply(this, arguments) : padAngle)), pa = p * (da < 0 ? -1 : 1), sum = d3.sum(values), k = sum ? (da - n * pa) / sum : 0, index = d3.range(n), arcs = [], v;
	      if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) {
	        return values[j] - values[i];
	      } : function(i, j) {
	        return sort(data[i], data[j]);
	      });
	      index.forEach(function(i) {
	        arcs[i] = {
	          data: data[i],
	          value: v = values[i],
	          startAngle: a,
	          endAngle: a += v * k + pa,
	          padAngle: p
	        };
	      });
	      return arcs;
	    }
	    pie.value = function(_) {
	      if (!arguments.length) return value;
	      value = _;
	      return pie;
	    };
	    pie.sort = function(_) {
	      if (!arguments.length) return sort;
	      sort = _;
	      return pie;
	    };
	    pie.startAngle = function(_) {
	      if (!arguments.length) return startAngle;
	      startAngle = _;
	      return pie;
	    };
	    pie.endAngle = function(_) {
	      if (!arguments.length) return endAngle;
	      endAngle = _;
	      return pie;
	    };
	    pie.padAngle = function(_) {
	      if (!arguments.length) return padAngle;
	      padAngle = _;
	      return pie;
	    };
	    return pie;
	  };
	  var d3_layout_pieSortByValue = {};
	  d3.layout.stack = function() {
	    var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY;
	    function stack(data, index) {
	      if (!(n = data.length)) return data;
	      var series = data.map(function(d, i) {
	        return values.call(stack, d, i);
	      });
	      var points = series.map(function(d) {
	        return d.map(function(v, i) {
	          return [ x.call(stack, v, i), y.call(stack, v, i) ];
	        });
	      });
	      var orders = order.call(stack, points, index);
	      series = d3.permute(series, orders);
	      points = d3.permute(points, orders);
	      var offsets = offset.call(stack, points, index);
	      var m = series[0].length, n, i, j, o;
	      for (j = 0; j < m; ++j) {
	        out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);
	        for (i = 1; i < n; ++i) {
	          out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);
	        }
	      }
	      return data;
	    }
	    stack.values = function(x) {
	      if (!arguments.length) return values;
	      values = x;
	      return stack;
	    };
	    stack.order = function(x) {
	      if (!arguments.length) return order;
	      order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault;
	      return stack;
	    };
	    stack.offset = function(x) {
	      if (!arguments.length) return offset;
	      offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero;
	      return stack;
	    };
	    stack.x = function(z) {
	      if (!arguments.length) return x;
	      x = z;
	      return stack;
	    };
	    stack.y = function(z) {
	      if (!arguments.length) return y;
	      y = z;
	      return stack;
	    };
	    stack.out = function(z) {
	      if (!arguments.length) return out;
	      out = z;
	      return stack;
	    };
	    return stack;
	  };
	  function d3_layout_stackX(d) {
	    return d.x;
	  }
	  function d3_layout_stackY(d) {
	    return d.y;
	  }
	  function d3_layout_stackOut(d, y0, y) {
	    d.y0 = y0;
	    d.y = y;
	  }
	  var d3_layout_stackOrders = d3.map({
	    "inside-out": function(data) {
	      var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) {
	        return max[a] - max[b];
	      }), top = 0, bottom = 0, tops = [], bottoms = [];
	      for (i = 0; i < n; ++i) {
	        j = index[i];
	        if (top < bottom) {
	          top += sums[j];
	          tops.push(j);
	        } else {
	          bottom += sums[j];
	          bottoms.push(j);
	        }
	      }
	      return bottoms.reverse().concat(tops);
	    },
	    reverse: function(data) {
	      return d3.range(data.length).reverse();
	    },
	    "default": d3_layout_stackOrderDefault
	  });
	  var d3_layout_stackOffsets = d3.map({
	    silhouette: function(data) {
	      var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = [];
	      for (j = 0; j < m; ++j) {
	        for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
	        if (o > max) max = o;
	        sums.push(o);
	      }
	      for (j = 0; j < m; ++j) {
	        y0[j] = (max - sums[j]) / 2;
	      }
	      return y0;
	    },
	    wiggle: function(data) {
	      var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = [];
	      y0[0] = o = o0 = 0;
	      for (j = 1; j < m; ++j) {
	        for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1];
	        for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) {
	          for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) {
	            s3 += (data[k][j][1] - data[k][j - 1][1]) / dx;
	          }
	          s2 += s3 * data[i][j][1];
	        }
	        y0[j] = o -= s1 ? s2 / s1 * dx : 0;
	        if (o < o0) o0 = o;
	      }
	      for (j = 0; j < m; ++j) y0[j] -= o0;
	      return y0;
	    },
	    expand: function(data) {
	      var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = [];
	      for (j = 0; j < m; ++j) {
	        for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
	        if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k;
	      }
	      for (j = 0; j < m; ++j) y0[j] = 0;
	      return y0;
	    },
	    zero: d3_layout_stackOffsetZero
	  });
	  function d3_layout_stackOrderDefault(data) {
	    return d3.range(data.length);
	  }
	  function d3_layout_stackOffsetZero(data) {
	    var j = -1, m = data[0].length, y0 = [];
	    while (++j < m) y0[j] = 0;
	    return y0;
	  }
	  function d3_layout_stackMaxIndex(array) {
	    var i = 1, j = 0, v = array[0][1], k, n = array.length;
	    for (;i < n; ++i) {
	      if ((k = array[i][1]) > v) {
	        j = i;
	        v = k;
	      }
	    }
	    return j;
	  }
	  function d3_layout_stackReduceSum(d) {
	    return d.reduce(d3_layout_stackSum, 0);
	  }
	  function d3_layout_stackSum(p, d) {
	    return p + d[1];
	  }
	  d3.layout.histogram = function() {
	    var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges;
	    function histogram(data, i) {
	      var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x;
	      while (++i < m) {
	        bin = bins[i] = [];
	        bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
	        bin.y = 0;
	      }
	      if (m > 0) {
	        i = -1;
	        while (++i < n) {
	          x = values[i];
	          if (x >= range[0] && x <= range[1]) {
	            bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
	            bin.y += k;
	            bin.push(data[i]);
	          }
	        }
	      }
	      return bins;
	    }
	    histogram.value = function(x) {
	      if (!arguments.length) return valuer;
	      valuer = x;
	      return histogram;
	    };
	    histogram.range = function(x) {
	      if (!arguments.length) return ranger;
	      ranger = d3_functor(x);
	      return histogram;
	    };
	    histogram.bins = function(x) {
	      if (!arguments.length) return binner;
	      binner = typeof x === "number" ? function(range) {
	        return d3_layout_histogramBinFixed(range, x);
	      } : d3_functor(x);
	      return histogram;
	    };
	    histogram.frequency = function(x) {
	      if (!arguments.length) return frequency;
	      frequency = !!x;
	      return histogram;
	    };
	    return histogram;
	  };
	  function d3_layout_histogramBinSturges(range, values) {
	    return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1));
	  }
	  function d3_layout_histogramBinFixed(range, n) {
	    var x = -1, b = +range[0], m = (range[1] - b) / n, f = [];
	    while (++x <= n) f[x] = m * x + b;
	    return f;
	  }
	  function d3_layout_histogramRange(values) {
	    return [ d3.min(values), d3.max(values) ];
	  }
	  d3.layout.pack = function() {
	    var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius;
	    function pack(d, i) {
	      var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() {
	        return radius;
	      };
	      root.x = root.y = 0;
	      d3_layout_hierarchyVisitAfter(root, function(d) {
	        d.r = +r(d.value);
	      });
	      d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings);
	      if (padding) {
	        var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2;
	        d3_layout_hierarchyVisitAfter(root, function(d) {
	          d.r += dr;
	        });
	        d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings);
	        d3_layout_hierarchyVisitAfter(root, function(d) {
	          d.r -= dr;
	        });
	      }
	      d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h));
	      return nodes;
	    }
	    pack.size = function(_) {
	      if (!arguments.length) return size;
	      size = _;
	      return pack;
	    };
	    pack.radius = function(_) {
	      if (!arguments.length) return radius;
	      radius = _ == null || typeof _ === "function" ? _ : +_;
	      return pack;
	    };
	    pack.padding = function(_) {
	      if (!arguments.length) return padding;
	      padding = +_;
	      return pack;
	    };
	    return d3_layout_hierarchyRebind(pack, hierarchy);
	  };
	  function d3_layout_packSort(a, b) {
	    return a.value - b.value;
	  }
	  function d3_layout_packInsert(a, b) {
	    var c = a._pack_next;
	    a._pack_next = b;
	    b._pack_prev = a;
	    b._pack_next = c;
	    c._pack_prev = b;
	  }
	  function d3_layout_packSplice(a, b) {
	    a._pack_next = b;
	    b._pack_prev = a;
	  }
	  function d3_layout_packIntersects(a, b) {
	    var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r;
	    return .999 * dr * dr > dx * dx + dy * dy;
	  }
	  function d3_layout_packSiblings(node) {
	    if (!(nodes = node.children) || !(n = nodes.length)) return;
	    var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n;
	    function bound(node) {
	      xMin = Math.min(node.x - node.r, xMin);
	      xMax = Math.max(node.x + node.r, xMax);
	      yMin = Math.min(node.y - node.r, yMin);
	      yMax = Math.max(node.y + node.r, yMax);
	    }
	    nodes.forEach(d3_layout_packLink);
	    a = nodes[0];
	    a.x = -a.r;
	    a.y = 0;
	    bound(a);
	    if (n > 1) {
	      b = nodes[1];
	      b.x = b.r;
	      b.y = 0;
	      bound(b);
	      if (n > 2) {
	        c = nodes[2];
	        d3_layout_packPlace(a, b, c);
	        bound(c);
	        d3_layout_packInsert(a, c);
	        a._pack_prev = c;
	        d3_layout_packInsert(c, b);
	        b = a._pack_next;
	        for (i = 3; i < n; i++) {
	          d3_layout_packPlace(a, b, c = nodes[i]);
	          var isect = 0, s1 = 1, s2 = 1;
	          for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {
	            if (d3_layout_packIntersects(j, c)) {
	              isect = 1;
	              break;
	            }
	          }
	          if (isect == 1) {
	            for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {
	              if (d3_layout_packIntersects(k, c)) {
	                break;
	              }
	            }
	          }
	          if (isect) {
	            if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b);
	            i--;
	          } else {
	            d3_layout_packInsert(a, c);
	            b = c;
	            bound(c);
	          }
	        }
	      }
	    }
	    var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0;
	    for (i = 0; i < n; i++) {
	      c = nodes[i];
	      c.x -= cx;
	      c.y -= cy;
	      cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y));
	    }
	    node.r = cr;
	    nodes.forEach(d3_layout_packUnlink);
	  }
	  function d3_layout_packLink(node) {
	    node._pack_next = node._pack_prev = node;
	  }
	  function d3_layout_packUnlink(node) {
	    delete node._pack_next;
	    delete node._pack_prev;
	  }
	  function d3_layout_packTransform(node, x, y, k) {
	    var children = node.children;
	    node.x = x += k * node.x;
	    node.y = y += k * node.y;
	    node.r *= k;
	    if (children) {
	      var i = -1, n = children.length;
	      while (++i < n) d3_layout_packTransform(children[i], x, y, k);
	    }
	  }
	  function d3_layout_packPlace(a, b, c) {
	    var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y;
	    if (db && (dx || dy)) {
	      var da = b.r + c.r, dc = dx * dx + dy * dy;
	      da *= da;
	      db *= db;
	      var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
	      c.x = a.x + x * dx + y * dy;
	      c.y = a.y + x * dy - y * dx;
	    } else {
	      c.x = a.x + db;
	      c.y = a.y;
	    }
	  }
	  d3.layout.tree = function() {
	    var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = null;
	    function tree(d, i) {
	      var nodes = hierarchy.call(this, d, i), root0 = nodes[0], root1 = wrapTree(root0);
	      d3_layout_hierarchyVisitAfter(root1, firstWalk), root1.parent.m = -root1.z;
	      d3_layout_hierarchyVisitBefore(root1, secondWalk);
	      if (nodeSize) d3_layout_hierarchyVisitBefore(root0, sizeNode); else {
	        var left = root0, right = root0, bottom = root0;
	        d3_layout_hierarchyVisitBefore(root0, function(node) {
	          if (node.x < left.x) left = node;
	          if (node.x > right.x) right = node;
	          if (node.depth > bottom.depth) bottom = node;
	        });
	        var tx = separation(left, right) / 2 - left.x, kx = size[0] / (right.x + separation(right, left) / 2 + tx), ky = size[1] / (bottom.depth || 1);
	        d3_layout_hierarchyVisitBefore(root0, function(node) {
	          node.x = (node.x + tx) * kx;
	          node.y = node.depth * ky;
	        });
	      }
	      return nodes;
	    }
	    function wrapTree(root0) {
	      var root1 = {
	        A: null,
	        children: [ root0 ]
	      }, queue = [ root1 ], node1;
	      while ((node1 = queue.pop()) != null) {
	        for (var children = node1.children, child, i = 0, n = children.length; i < n; ++i) {
	          queue.push((children[i] = child = {
	            _: children[i],
	            parent: node1,
	            children: (child = children[i].children) && child.slice() || [],
	            A: null,
	            a: null,
	            z: 0,
	            m: 0,
	            c: 0,
	            s: 0,
	            t: null,
	            i: i
	          }).a = child);
	        }
	      }
	      return root1.children[0];
	    }
	    function firstWalk(v) {
	      var children = v.children, siblings = v.parent.children, w = v.i ? siblings[v.i - 1] : null;
	      if (children.length) {
	        d3_layout_treeShift(v);
	        var midpoint = (children[0].z + children[children.length - 1].z) / 2;
	        if (w) {
	          v.z = w.z + separation(v._, w._);
	          v.m = v.z - midpoint;
	        } else {
	          v.z = midpoint;
	        }
	      } else if (w) {
	        v.z = w.z + separation(v._, w._);
	      }
	      v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
	    }
	    function secondWalk(v) {
	      v._.x = v.z + v.parent.m;
	      v.m += v.parent.m;
	    }
	    function apportion(v, w, ancestor) {
	      if (w) {
	        var vip = v, vop = v, vim = w, vom = vip.parent.children[0], sip = vip.m, sop = vop.m, sim = vim.m, som = vom.m, shift;
	        while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) {
	          vom = d3_layout_treeLeft(vom);
	          vop = d3_layout_treeRight(vop);
	          vop.a = v;
	          shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
	          if (shift > 0) {
	            d3_layout_treeMove(d3_layout_treeAncestor(vim, v, ancestor), v, shift);
	            sip += shift;
	            sop += shift;
	          }
	          sim += vim.m;
	          sip += vip.m;
	          som += vom.m;
	          sop += vop.m;
	        }
	        if (vim && !d3_layout_treeRight(vop)) {
	          vop.t = vim;
	          vop.m += sim - sop;
	        }
	        if (vip && !d3_layout_treeLeft(vom)) {
	          vom.t = vip;
	          vom.m += sip - som;
	          ancestor = v;
	        }
	      }
	      return ancestor;
	    }
	    function sizeNode(node) {
	      node.x *= size[0];
	      node.y = node.depth * size[1];
	    }
	    tree.separation = function(x) {
	      if (!arguments.length) return separation;
	      separation = x;
	      return tree;
	    };
	    tree.size = function(x) {
	      if (!arguments.length) return nodeSize ? null : size;
	      nodeSize = (size = x) == null ? sizeNode : null;
	      return tree;
	    };
	    tree.nodeSize = function(x) {
	      if (!arguments.length) return nodeSize ? size : null;
	      nodeSize = (size = x) == null ? null : sizeNode;
	      return tree;
	    };
	    return d3_layout_hierarchyRebind(tree, hierarchy);
	  };
	  function d3_layout_treeSeparation(a, b) {
	    return a.parent == b.parent ? 1 : 2;
	  }
	  function d3_layout_treeLeft(v) {
	    var children = v.children;
	    return children.length ? children[0] : v.t;
	  }
	  function d3_layout_treeRight(v) {
	    var children = v.children, n;
	    return (n = children.length) ? children[n - 1] : v.t;
	  }
	  function d3_layout_treeMove(wm, wp, shift) {
	    var change = shift / (wp.i - wm.i);
	    wp.c -= change;
	    wp.s += shift;
	    wm.c += change;
	    wp.z += shift;
	    wp.m += shift;
	  }
	  function d3_layout_treeShift(v) {
	    var shift = 0, change = 0, children = v.children, i = children.length, w;
	    while (--i >= 0) {
	      w = children[i];
	      w.z += shift;
	      w.m += shift;
	      shift += w.s + (change += w.c);
	    }
	  }
	  function d3_layout_treeAncestor(vim, v, ancestor) {
	    return vim.a.parent === v.parent ? vim.a : ancestor;
	  }
	  d3.layout.cluster = function() {
	    var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false;
	    function cluster(d, i) {
	      var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0;
	      d3_layout_hierarchyVisitAfter(root, function(node) {
	        var children = node.children;
	        if (children && children.length) {
	          node.x = d3_layout_clusterX(children);
	          node.y = d3_layout_clusterY(children);
	        } else {
	          node.x = previousNode ? x += separation(node, previousNode) : 0;
	          node.y = 0;
	          previousNode = node;
	        }
	      });
	      var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2;
	      d3_layout_hierarchyVisitAfter(root, nodeSize ? function(node) {
	        node.x = (node.x - root.x) * size[0];
	        node.y = (root.y - node.y) * size[1];
	      } : function(node) {
	        node.x = (node.x - x0) / (x1 - x0) * size[0];
	        node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1];
	      });
	      return nodes;
	    }
	    cluster.separation = function(x) {
	      if (!arguments.length) return separation;
	      separation = x;
	      return cluster;
	    };
	    cluster.size = function(x) {
	      if (!arguments.length) return nodeSize ? null : size;
	      nodeSize = (size = x) == null;
	      return cluster;
	    };
	    cluster.nodeSize = function(x) {
	      if (!arguments.length) return nodeSize ? size : null;
	      nodeSize = (size = x) != null;
	      return cluster;
	    };
	    return d3_layout_hierarchyRebind(cluster, hierarchy);
	  };
	  function d3_layout_clusterY(children) {
	    return 1 + d3.max(children, function(child) {
	      return child.y;
	    });
	  }
	  function d3_layout_clusterX(children) {
	    return children.reduce(function(x, child) {
	      return x + child.x;
	    }, 0) / children.length;
	  }
	  function d3_layout_clusterLeft(node) {
	    var children = node.children;
	    return children && children.length ? d3_layout_clusterLeft(children[0]) : node;
	  }
	  function d3_layout_clusterRight(node) {
	    var children = node.children, n;
	    return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node;
	  }
	  d3.layout.treemap = function() {
	    var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5));
	    function scale(children, k) {
	      var i = -1, n = children.length, child, area;
	      while (++i < n) {
	        area = (child = children[i]).value * (k < 0 ? 0 : k);
	        child.area = isNaN(area) || area <= 0 ? 0 : area;
	      }
	    }
	    function squarify(node) {
	      var children = node.children;
	      if (children && children.length) {
	        var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n;
	        scale(remaining, rect.dx * rect.dy / node.value);
	        row.area = 0;
	        while ((n = remaining.length) > 0) {
	          row.push(child = remaining[n - 1]);
	          row.area += child.area;
	          if (mode !== "squarify" || (score = worst(row, u)) <= best) {
	            remaining.pop();
	            best = score;
	          } else {
	            row.area -= row.pop().area;
	            position(row, u, rect, false);
	            u = Math.min(rect.dx, rect.dy);
	            row.length = row.area = 0;
	            best = Infinity;
	          }
	        }
	        if (row.length) {
	          position(row, u, rect, true);
	          row.length = row.area = 0;
	        }
	        children.forEach(squarify);
	      }
	    }
	    function stickify(node) {
	      var children = node.children;
	      if (children && children.length) {
	        var rect = pad(node), remaining = children.slice(), child, row = [];
	        scale(remaining, rect.dx * rect.dy / node.value);
	        row.area = 0;
	        while (child = remaining.pop()) {
	          row.push(child);
	          row.area += child.area;
	          if (child.z != null) {
	            position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
	            row.length = row.area = 0;
	          }
	        }
	        children.forEach(stickify);
	      }
	    }
	    function worst(row, u) {
	      var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length;
	      while (++i < n) {
	        if (!(r = row[i].area)) continue;
	        if (r < rmin) rmin = r;
	        if (r > rmax) rmax = r;
	      }
	      s *= s;
	      u *= u;
	      return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity;
	    }
	    function position(row, u, rect, flush) {
	      var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o;
	      if (u == rect.dx) {
	        if (flush || v > rect.dy) v = rect.dy;
	        while (++i < n) {
	          o = row[i];
	          o.x = x;
	          o.y = y;
	          o.dy = v;
	          x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0);
	        }
	        o.z = true;
	        o.dx += rect.x + rect.dx - x;
	        rect.y += v;
	        rect.dy -= v;
	      } else {
	        if (flush || v > rect.dx) v = rect.dx;
	        while (++i < n) {
	          o = row[i];
	          o.x = x;
	          o.y = y;
	          o.dx = v;
	          y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0);
	        }
	        o.z = false;
	        o.dy += rect.y + rect.dy - y;
	        rect.x += v;
	        rect.dx -= v;
	      }
	    }
	    function treemap(d) {
	      var nodes = stickies || hierarchy(d), root = nodes[0];
	      root.x = root.y = 0;
	      if (root.value) root.dx = size[0], root.dy = size[1]; else root.dx = root.dy = 0;
	      if (stickies) hierarchy.revalue(root);
	      scale([ root ], root.dx * root.dy / root.value);
	      (stickies ? stickify : squarify)(root);
	      if (sticky) stickies = nodes;
	      return nodes;
	    }
	    treemap.size = function(x) {
	      if (!arguments.length) return size;
	      size = x;
	      return treemap;
	    };
	    treemap.padding = function(x) {
	      if (!arguments.length) return padding;
	      function padFunction(node) {
	        var p = x.call(treemap, node, node.depth);
	        return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p);
	      }
	      function padConstant(node) {
	        return d3_layout_treemapPad(node, x);
	      }
	      var type;
	      pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], 
	      padConstant) : padConstant;
	      return treemap;
	    };
	    treemap.round = function(x) {
	      if (!arguments.length) return round != Number;
	      round = x ? Math.round : Number;
	      return treemap;
	    };
	    treemap.sticky = function(x) {
	      if (!arguments.length) return sticky;
	      sticky = x;
	      stickies = null;
	      return treemap;
	    };
	    treemap.ratio = function(x) {
	      if (!arguments.length) return ratio;
	      ratio = x;
	      return treemap;
	    };
	    treemap.mode = function(x) {
	      if (!arguments.length) return mode;
	      mode = x + "";
	      return treemap;
	    };
	    return d3_layout_hierarchyRebind(treemap, hierarchy);
	  };
	  function d3_layout_treemapPadNull(node) {
	    return {
	      x: node.x,
	      y: node.y,
	      dx: node.dx,
	      dy: node.dy
	    };
	  }
	  function d3_layout_treemapPad(node, padding) {
	    var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2];
	    if (dx < 0) {
	      x += dx / 2;
	      dx = 0;
	    }
	    if (dy < 0) {
	      y += dy / 2;
	      dy = 0;
	    }
	    return {
	      x: x,
	      y: y,
	      dx: dx,
	      dy: dy
	    };
	  }
	  d3.random = {
	    normal: function(µ, σ) {
	      var n = arguments.length;
	      if (n < 2) σ = 1;
	      if (n < 1) µ = 0;
	      return function() {
	        var x, y, r;
	        do {
	          x = Math.random() * 2 - 1;
	          y = Math.random() * 2 - 1;
	          r = x * x + y * y;
	        } while (!r || r > 1);
	        return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r);
	      };
	    },
	    logNormal: function() {
	      var random = d3.random.normal.apply(d3, arguments);
	      return function() {
	        return Math.exp(random());
	      };
	    },
	    bates: function(m) {
	      var random = d3.random.irwinHall(m);
	      return function() {
	        return random() / m;
	      };
	    },
	    irwinHall: function(m) {
	      return function() {
	        for (var s = 0, j = 0; j < m; j++) s += Math.random();
	        return s;
	      };
	    }
	  };
	  d3.scale = {};
	  function d3_scaleExtent(domain) {
	    var start = domain[0], stop = domain[domain.length - 1];
	    return start < stop ? [ start, stop ] : [ stop, start ];
	  }
	  function d3_scaleRange(scale) {
	    return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
	  }
	  function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
	    var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);
	    return function(x) {
	      return i(u(x));
	    };
	  }
	  function d3_scale_nice(domain, nice) {
	    var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx;
	    if (x1 < x0) {
	      dx = i0, i0 = i1, i1 = dx;
	      dx = x0, x0 = x1, x1 = dx;
	    }
	    domain[i0] = nice.floor(x0);
	    domain[i1] = nice.ceil(x1);
	    return domain;
	  }
	  function d3_scale_niceStep(step) {
	    return step ? {
	      floor: function(x) {
	        return Math.floor(x / step) * step;
	      },
	      ceil: function(x) {
	        return Math.ceil(x / step) * step;
	      }
	    } : d3_scale_niceIdentity;
	  }
	  var d3_scale_niceIdentity = {
	    floor: d3_identity,
	    ceil: d3_identity
	  };
	  function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
	    var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1;
	    if (domain[k] < domain[0]) {
	      domain = domain.slice().reverse();
	      range = range.slice().reverse();
	    }
	    while (++j <= k) {
	      u.push(uninterpolate(domain[j - 1], domain[j]));
	      i.push(interpolate(range[j - 1], range[j]));
	    }
	    return function(x) {
	      var j = d3.bisect(domain, x, 1, k) - 1;
	      return i[j](u[j](x));
	    };
	  }
	  d3.scale.linear = function() {
	    return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false);
	  };
	  function d3_scale_linear(domain, range, interpolate, clamp) {
	    var output, input;
	    function rescale() {
	      var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;
	      output = linear(domain, range, uninterpolate, interpolate);
	      input = linear(range, domain, uninterpolate, d3_interpolate);
	      return scale;
	    }
	    function scale(x) {
	      return output(x);
	    }
	    scale.invert = function(y) {
	      return input(y);
	    };
	    scale.domain = function(x) {
	      if (!arguments.length) return domain;
	      domain = x.map(Number);
	      return rescale();
	    };
	    scale.range = function(x) {
	      if (!arguments.length) return range;
	      range = x;
	      return rescale();
	    };
	    scale.rangeRound = function(x) {
	      return scale.range(x).interpolate(d3_interpolateRound);
	    };
	    scale.clamp = function(x) {
	      if (!arguments.length) return clamp;
	      clamp = x;
	      return rescale();
	    };
	    scale.interpolate = function(x) {
	      if (!arguments.length) return interpolate;
	      interpolate = x;
	      return rescale();
	    };
	    scale.ticks = function(m) {
	      return d3_scale_linearTicks(domain, m);
	    };
	    scale.tickFormat = function(m, format) {
	      return d3_scale_linearTickFormat(domain, m, format);
	    };
	    scale.nice = function(m) {
	      d3_scale_linearNice(domain, m);
	      return rescale();
	    };
	    scale.copy = function() {
	      return d3_scale_linear(domain, range, interpolate, clamp);
	    };
	    return rescale();
	  }
	  function d3_scale_linearRebind(scale, linear) {
	    return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
	  }
	  function d3_scale_linearNice(domain, m) {
	    d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2]));
	    d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2]));
	    return domain;
	  }
	  function d3_scale_linearTickRange(domain, m) {
	    if (m == null) m = 10;
	    var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step;
	    if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2;
	    extent[0] = Math.ceil(extent[0] / step) * step;
	    extent[1] = Math.floor(extent[1] / step) * step + step * .5;
	    extent[2] = step;
	    return extent;
	  }
	  function d3_scale_linearTicks(domain, m) {
	    return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
	  }
	  function d3_scale_linearTickFormat(domain, m, format) {
	    var range = d3_scale_linearTickRange(domain, m);
	    if (format) {
	      var match = d3_format_re.exec(format);
	      match.shift();
	      if (match[8] === "s") {
	        var prefix = d3.formatPrefix(Math.max(abs(range[0]), abs(range[1])));
	        if (!match[7]) match[7] = "." + d3_scale_linearPrecision(prefix.scale(range[2]));
	        match[8] = "f";
	        format = d3.format(match.join(""));
	        return function(d) {
	          return format(prefix.scale(d)) + prefix.symbol;
	        };
	      }
	      if (!match[7]) match[7] = "." + d3_scale_linearFormatPrecision(match[8], range);
	      format = match.join("");
	    } else {
	      format = ",." + d3_scale_linearPrecision(range[2]) + "f";
	    }
	    return d3.format(format);
	  }
	  var d3_scale_linearFormatSignificant = {
	    s: 1,
	    g: 1,
	    p: 1,
	    r: 1,
	    e: 1
	  };
	  function d3_scale_linearPrecision(value) {
	    return -Math.floor(Math.log(value) / Math.LN10 + .01);
	  }
	  function d3_scale_linearFormatPrecision(type, range) {
	    var p = d3_scale_linearPrecision(range[2]);
	    return type in d3_scale_linearFormatSignificant ? Math.abs(p - d3_scale_linearPrecision(Math.max(abs(range[0]), abs(range[1])))) + +(type !== "e") : p - (type === "%") * 2;
	  }
	  d3.scale.log = function() {
	    return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]);
	  };
	  function d3_scale_log(linear, base, positive, domain) {
	    function log(x) {
	      return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base);
	    }
	    function pow(x) {
	      return positive ? Math.pow(base, x) : -Math.pow(base, -x);
	    }
	    function scale(x) {
	      return linear(log(x));
	    }
	    scale.invert = function(x) {
	      return pow(linear.invert(x));
	    };
	    scale.domain = function(x) {
	      if (!arguments.length) return domain;
	      positive = x[0] >= 0;
	      linear.domain((domain = x.map(Number)).map(log));
	      return scale;
	    };
	    scale.base = function(_) {
	      if (!arguments.length) return base;
	      base = +_;
	      linear.domain(domain.map(log));
	      return scale;
	    };
	    scale.nice = function() {
	      var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative);
	      linear.domain(niced);
	      domain = niced.map(pow);
	      return scale;
	    };
	    scale.ticks = function() {
	      var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base;
	      if (isFinite(j - i)) {
	        if (positive) {
	          for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k);
	          ticks.push(pow(i));
	        } else {
	          ticks.push(pow(i));
	          for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k);
	        }
	        for (i = 0; ticks[i] < u; i++) {}
	        for (j = ticks.length; ticks[j - 1] > v; j--) {}
	        ticks = ticks.slice(i, j);
	      }
	      return ticks;
	    };
	    scale.tickFormat = function(n, format) {
	      if (!arguments.length) return d3_scale_logFormat;
	      if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format);
	      var k = Math.max(1, base * n / scale.ticks().length);
	      return function(d) {
	        var i = d / pow(Math.round(log(d)));
	        if (i * base < base - .5) i *= base;
	        return i <= k ? format(d) : "";
	      };
	    };
	    scale.copy = function() {
	      return d3_scale_log(linear.copy(), base, positive, domain);
	    };
	    return d3_scale_linearRebind(scale, linear);
	  }
	  var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = {
	    floor: function(x) {
	      return -Math.ceil(-x);
	    },
	    ceil: function(x) {
	      return -Math.floor(-x);
	    }
	  };
	  d3.scale.pow = function() {
	    return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]);
	  };
	  function d3_scale_pow(linear, exponent, domain) {
	    var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent);
	    function scale(x) {
	      return linear(powp(x));
	    }
	    scale.invert = function(x) {
	      return powb(linear.invert(x));
	    };
	    scale.domain = function(x) {
	      if (!arguments.length) return domain;
	      linear.domain((domain = x.map(Number)).map(powp));
	      return scale;
	    };
	    scale.ticks = function(m) {
	      return d3_scale_linearTicks(domain, m);
	    };
	    scale.tickFormat = function(m, format) {
	      return d3_scale_linearTickFormat(domain, m, format);
	    };
	    scale.nice = function(m) {
	      return scale.domain(d3_scale_linearNice(domain, m));
	    };
	    scale.exponent = function(x) {
	      if (!arguments.length) return exponent;
	      powp = d3_scale_powPow(exponent = x);
	      powb = d3_scale_powPow(1 / exponent);
	      linear.domain(domain.map(powp));
	      return scale;
	    };
	    scale.copy = function() {
	      return d3_scale_pow(linear.copy(), exponent, domain);
	    };
	    return d3_scale_linearRebind(scale, linear);
	  }
	  function d3_scale_powPow(e) {
	    return function(x) {
	      return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);
	    };
	  }
	  d3.scale.sqrt = function() {
	    return d3.scale.pow().exponent(.5);
	  };
	  d3.scale.ordinal = function() {
	    return d3_scale_ordinal([], {
	      t: "range",
	      a: [ [] ]
	    });
	  };
	  function d3_scale_ordinal(domain, ranger) {
	    var index, range, rangeBand;
	    function scale(x) {
	      return range[((index.get(x) || (ranger.t === "range" ? index.set(x, domain.push(x)) : NaN)) - 1) % range.length];
	    }
	    function steps(start, step) {
	      return d3.range(domain.length).map(function(i) {
	        return start + step * i;
	      });
	    }
	    scale.domain = function(x) {
	      if (!arguments.length) return domain;
	      domain = [];
	      index = new d3_Map();
	      var i = -1, n = x.length, xi;
	      while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi));
	      return scale[ranger.t].apply(scale, ranger.a);
	    };
	    scale.range = function(x) {
	      if (!arguments.length) return range;
	      range = x;
	      rangeBand = 0;
	      ranger = {
	        t: "range",
	        a: arguments
	      };
	      return scale;
	    };
	    scale.rangePoints = function(x, padding) {
	      if (arguments.length < 2) padding = 0;
	      var start = x[0], stop = x[1], step = domain.length < 2 ? (start = (start + stop) / 2, 
	      0) : (stop - start) / (domain.length - 1 + padding);
	      range = steps(start + step * padding / 2, step);
	      rangeBand = 0;
	      ranger = {
	        t: "rangePoints",
	        a: arguments
	      };
	      return scale;
	    };
	    scale.rangeRoundPoints = function(x, padding) {
	      if (arguments.length < 2) padding = 0;
	      var start = x[0], stop = x[1], step = domain.length < 2 ? (start = stop = Math.round((start + stop) / 2), 
	      0) : (stop - start) / (domain.length - 1 + padding) | 0;
	      range = steps(start + Math.round(step * padding / 2 + (stop - start - (domain.length - 1 + padding) * step) / 2), step);
	      rangeBand = 0;
	      ranger = {
	        t: "rangeRoundPoints",
	        a: arguments
	      };
	      return scale;
	    };
	    scale.rangeBands = function(x, padding, outerPadding) {
	      if (arguments.length < 2) padding = 0;
	      if (arguments.length < 3) outerPadding = padding;
	      var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding);
	      range = steps(start + step * outerPadding, step);
	      if (reverse) range.reverse();
	      rangeBand = step * (1 - padding);
	      ranger = {
	        t: "rangeBands",
	        a: arguments
	      };
	      return scale;
	    };
	    scale.rangeRoundBands = function(x, padding, outerPadding) {
	      if (arguments.length < 2) padding = 0;
	      if (arguments.length < 3) outerPadding = padding;
	      var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding));
	      range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 2), step);
	      if (reverse) range.reverse();
	      rangeBand = Math.round(step * (1 - padding));
	      ranger = {
	        t: "rangeRoundBands",
	        a: arguments
	      };
	      return scale;
	    };
	    scale.rangeBand = function() {
	      return rangeBand;
	    };
	    scale.rangeExtent = function() {
	      return d3_scaleExtent(ranger.a[0]);
	    };
	    scale.copy = function() {
	      return d3_scale_ordinal(domain, ranger);
	    };
	    return scale.domain(domain);
	  }
	  d3.scale.category10 = function() {
	    return d3.scale.ordinal().range(d3_category10);
	  };
	  d3.scale.category20 = function() {
	    return d3.scale.ordinal().range(d3_category20);
	  };
	  d3.scale.category20b = function() {
	    return d3.scale.ordinal().range(d3_category20b);
	  };
	  d3.scale.category20c = function() {
	    return d3.scale.ordinal().range(d3_category20c);
	  };
	  var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString);
	  var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString);
	  var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString);
	  var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString);
	  d3.scale.quantile = function() {
	    return d3_scale_quantile([], []);
	  };
	  function d3_scale_quantile(domain, range) {
	    var thresholds;
	    function rescale() {
	      var k = 0, q = range.length;
	      thresholds = [];
	      while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
	      return scale;
	    }
	    function scale(x) {
	      if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)];
	    }
	    scale.domain = function(x) {
	      if (!arguments.length) return domain;
	      domain = x.map(d3_number).filter(d3_numeric).sort(d3_ascending);
	      return rescale();
	    };
	    scale.range = function(x) {
	      if (!arguments.length) return range;
	      range = x;
	      return rescale();
	    };
	    scale.quantiles = function() {
	      return thresholds;
	    };
	    scale.invertExtent = function(y) {
	      y = range.indexOf(y);
	      return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ];
	    };
	    scale.copy = function() {
	      return d3_scale_quantile(domain, range);
	    };
	    return rescale();
	  }
	  d3.scale.quantize = function() {
	    return d3_scale_quantize(0, 1, [ 0, 1 ]);
	  };
	  function d3_scale_quantize(x0, x1, range) {
	    var kx, i;
	    function scale(x) {
	      return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
	    }
	    function rescale() {
	      kx = range.length / (x1 - x0);
	      i = range.length - 1;
	      return scale;
	    }
	    scale.domain = function(x) {
	      if (!arguments.length) return [ x0, x1 ];
	      x0 = +x[0];
	      x1 = +x[x.length - 1];
	      return rescale();
	    };
	    scale.range = function(x) {
	      if (!arguments.length) return range;
	      range = x;
	      return rescale();
	    };
	    scale.invertExtent = function(y) {
	      y = range.indexOf(y);
	      y = y < 0 ? NaN : y / kx + x0;
	      return [ y, y + 1 / kx ];
	    };
	    scale.copy = function() {
	      return d3_scale_quantize(x0, x1, range);
	    };
	    return rescale();
	  }
	  d3.scale.threshold = function() {
	    return d3_scale_threshold([ .5 ], [ 0, 1 ]);
	  };
	  function d3_scale_threshold(domain, range) {
	    function scale(x) {
	      if (x <= x) return range[d3.bisect(domain, x)];
	    }
	    scale.domain = function(_) {
	      if (!arguments.length) return domain;
	      domain = _;
	      return scale;
	    };
	    scale.range = function(_) {
	      if (!arguments.length) return range;
	      range = _;
	      return scale;
	    };
	    scale.invertExtent = function(y) {
	      y = range.indexOf(y);
	      return [ domain[y - 1], domain[y] ];
	    };
	    scale.copy = function() {
	      return d3_scale_threshold(domain, range);
	    };
	    return scale;
	  }
	  d3.scale.identity = function() {
	    return d3_scale_identity([ 0, 1 ]);
	  };
	  function d3_scale_identity(domain) {
	    function identity(x) {
	      return +x;
	    }
	    identity.invert = identity;
	    identity.domain = identity.range = function(x) {
	      if (!arguments.length) return domain;
	      domain = x.map(identity);
	      return identity;
	    };
	    identity.ticks = function(m) {
	      return d3_scale_linearTicks(domain, m);
	    };
	    identity.tickFormat = function(m, format) {
	      return d3_scale_linearTickFormat(domain, m, format);
	    };
	    identity.copy = function() {
	      return d3_scale_identity(domain);
	    };
	    return identity;
	  }
	  d3.svg = {};
	  function d3_zero() {
	    return 0;
	  }
	  d3.svg.arc = function() {
	    var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, cornerRadius = d3_zero, padRadius = d3_svg_arcAuto, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle, padAngle = d3_svg_arcPadAngle;
	    function arc() {
	      var r0 = Math.max(0, +innerRadius.apply(this, arguments)), r1 = Math.max(0, +outerRadius.apply(this, arguments)), a0 = startAngle.apply(this, arguments) - halfπ, a1 = endAngle.apply(this, arguments) - halfπ, da = Math.abs(a1 - a0), cw = a0 > a1 ? 0 : 1;
	      if (r1 < r0) rc = r1, r1 = r0, r0 = rc;
	      if (da >= τε) return circleSegment(r1, cw) + (r0 ? circleSegment(r0, 1 - cw) : "") + "Z";
	      var rc, cr, rp, ap, p0 = 0, p1 = 0, x0, y0, x1, y1, x2, y2, x3, y3, path = [];
	      if (ap = (+padAngle.apply(this, arguments) || 0) / 2) {
	        rp = padRadius === d3_svg_arcAuto ? Math.sqrt(r0 * r0 + r1 * r1) : +padRadius.apply(this, arguments);
	        if (!cw) p1 *= -1;
	        if (r1) p1 = d3_asin(rp / r1 * Math.sin(ap));
	        if (r0) p0 = d3_asin(rp / r0 * Math.sin(ap));
	      }
	      if (r1) {
	        x0 = r1 * Math.cos(a0 + p1);
	        y0 = r1 * Math.sin(a0 + p1);
	        x1 = r1 * Math.cos(a1 - p1);
	        y1 = r1 * Math.sin(a1 - p1);
	        var l1 = Math.abs(a1 - a0 - 2 * p1) <= π ? 0 : 1;
	        if (p1 && d3_svg_arcSweep(x0, y0, x1, y1) === cw ^ l1) {
	          var h1 = (a0 + a1) / 2;
	          x0 = r1 * Math.cos(h1);
	          y0 = r1 * Math.sin(h1);
	          x1 = y1 = null;
	        }
	      } else {
	        x0 = y0 = 0;
	      }
	      if (r0) {
	        x2 = r0 * Math.cos(a1 - p0);
	        y2 = r0 * Math.sin(a1 - p0);
	        x3 = r0 * Math.cos(a0 + p0);
	        y3 = r0 * Math.sin(a0 + p0);
	        var l0 = Math.abs(a0 - a1 + 2 * p0) <= π ? 0 : 1;
	        if (p0 && d3_svg_arcSweep(x2, y2, x3, y3) === 1 - cw ^ l0) {
	          var h0 = (a0 + a1) / 2;
	          x2 = r0 * Math.cos(h0);
	          y2 = r0 * Math.sin(h0);
	          x3 = y3 = null;
	        }
	      } else {
	        x2 = y2 = 0;
	      }
	      if (da > ε && (rc = Math.min(Math.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments))) > .001) {
	        cr = r0 < r1 ^ cw ? 0 : 1;
	        var rc1 = rc, rc0 = rc;
	        if (da < π) {
	          var oc = x3 == null ? [ x2, y2 ] : x1 == null ? [ x0, y0 ] : d3_geom_polygonIntersect([ x0, y0 ], [ x3, y3 ], [ x1, y1 ], [ x2, y2 ]), ax = x0 - oc[0], ay = y0 - oc[1], bx = x1 - oc[0], by = y1 - oc[1], kc = 1 / Math.sin(Math.acos((ax * bx + ay * by) / (Math.sqrt(ax * ax + ay * ay) * Math.sqrt(bx * bx + by * by))) / 2), lc = Math.sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
	          rc0 = Math.min(rc, (r0 - lc) / (kc - 1));
	          rc1 = Math.min(rc, (r1 - lc) / (kc + 1));
	        }
	        if (x1 != null) {
	          var t30 = d3_svg_arcCornerTangents(x3 == null ? [ x2, y2 ] : [ x3, y3 ], [ x0, y0 ], r1, rc1, cw), t12 = d3_svg_arcCornerTangents([ x1, y1 ], [ x2, y2 ], r1, rc1, cw);
	          if (rc === rc1) {
	            path.push("M", t30[0], "A", rc1, ",", rc1, " 0 0,", cr, " ", t30[1], "A", r1, ",", r1, " 0 ", 1 - cw ^ d3_svg_arcSweep(t30[1][0], t30[1][1], t12[1][0], t12[1][1]), ",", cw, " ", t12[1], "A", rc1, ",", rc1, " 0 0,", cr, " ", t12[0]);
	          } else {
	            path.push("M", t30[0], "A", rc1, ",", rc1, " 0 1,", cr, " ", t12[0]);
	          }
	        } else {
	          path.push("M", x0, ",", y0);
	        }
	        if (x3 != null) {
	          var t03 = d3_svg_arcCornerTangents([ x0, y0 ], [ x3, y3 ], r0, -rc0, cw), t21 = d3_svg_arcCornerTangents([ x2, y2 ], x1 == null ? [ x0, y0 ] : [ x1, y1 ], r0, -rc0, cw);
	          if (rc === rc0) {
	            path.push("L", t21[0], "A", rc0, ",", rc0, " 0 0,", cr, " ", t21[1], "A", r0, ",", r0, " 0 ", cw ^ d3_svg_arcSweep(t21[1][0], t21[1][1], t03[1][0], t03[1][1]), ",", 1 - cw, " ", t03[1], "A", rc0, ",", rc0, " 0 0,", cr, " ", t03[0]);
	          } else {
	            path.push("L", t21[0], "A", rc0, ",", rc0, " 0 0,", cr, " ", t03[0]);
	          }
	        } else {
	          path.push("L", x2, ",", y2);
	        }
	      } else {
	        path.push("M", x0, ",", y0);
	        if (x1 != null) path.push("A", r1, ",", r1, " 0 ", l1, ",", cw, " ", x1, ",", y1);
	        path.push("L", x2, ",", y2);
	        if (x3 != null) path.push("A", r0, ",", r0, " 0 ", l0, ",", 1 - cw, " ", x3, ",", y3);
	      }
	      path.push("Z");
	      return path.join("");
	    }
	    function circleSegment(r1, cw) {
	      return "M0," + r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + -r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + r1;
	    }
	    arc.innerRadius = function(v) {
	      if (!arguments.length) return innerRadius;
	      innerRadius = d3_functor(v);
	      return arc;
	    };
	    arc.outerRadius = function(v) {
	      if (!arguments.length) return outerRadius;
	      outerRadius = d3_functor(v);
	      return arc;
	    };
	    arc.cornerRadius = function(v) {
	      if (!arguments.length) return cornerRadius;
	      cornerRadius = d3_functor(v);
	      return arc;
	    };
	    arc.padRadius = function(v) {
	      if (!arguments.length) return padRadius;
	      padRadius = v == d3_svg_arcAuto ? d3_svg_arcAuto : d3_functor(v);
	      return arc;
	    };
	    arc.startAngle = function(v) {
	      if (!arguments.length) return startAngle;
	      startAngle = d3_functor(v);
	      return arc;
	    };
	    arc.endAngle = function(v) {
	      if (!arguments.length) return endAngle;
	      endAngle = d3_functor(v);
	      return arc;
	    };
	    arc.padAngle = function(v) {
	      if (!arguments.length) return padAngle;
	      padAngle = d3_functor(v);
	      return arc;
	    };
	    arc.centroid = function() {
	      var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2, a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - halfπ;
	      return [ Math.cos(a) * r, Math.sin(a) * r ];
	    };
	    return arc;
	  };
	  var d3_svg_arcAuto = "auto";
	  function d3_svg_arcInnerRadius(d) {
	    return d.innerRadius;
	  }
	  function d3_svg_arcOuterRadius(d) {
	    return d.outerRadius;
	  }
	  function d3_svg_arcStartAngle(d) {
	    return d.startAngle;
	  }
	  function d3_svg_arcEndAngle(d) {
	    return d.endAngle;
	  }
	  function d3_svg_arcPadAngle(d) {
	    return d && d.padAngle;
	  }
	  function d3_svg_arcSweep(x0, y0, x1, y1) {
	    return (x0 - x1) * y0 - (y0 - y1) * x0 > 0 ? 0 : 1;
	  }
	  function d3_svg_arcCornerTangents(p0, p1, r1, rc, cw) {
	    var x01 = p0[0] - p1[0], y01 = p0[1] - p1[1], lo = (cw ? rc : -rc) / Math.sqrt(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x1 = p0[0] + ox, y1 = p0[1] + oy, x2 = p1[0] + ox, y2 = p1[1] + oy, x3 = (x1 + x2) / 2, y3 = (y1 + y2) / 2, dx = x2 - x1, dy = y2 - y1, d2 = dx * dx + dy * dy, r = r1 - rc, D = x1 * y2 - x2 * y1, d = (dy < 0 ? -1 : 1) * Math.sqrt(Math.max(0, r * r * d2 - D * D)), cx0 = (D * dy - dx * d) / d2, cy0 = (-D * dx - dy * d) / d2, cx1 = (D * dy + dx * d) / d2, cy1 = (-D * dx + dy * d) / d2, dx0 = cx0 - x3, dy0 = cy0 - y3, dx1 = cx1 - x3, dy1 = cy1 - y3;
	    if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
	    return [ [ cx0 - ox, cy0 - oy ], [ cx0 * r1 / r, cy0 * r1 / r ] ];
	  }
	  function d3_svg_line(projection) {
	    var x = d3_geom_pointX, y = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7;
	    function line(data) {
	      var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y);
	      function segment() {
	        segments.push("M", interpolate(projection(points), tension));
	      }
	      while (++i < n) {
	        if (defined.call(this, d = data[i], i)) {
	          points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]);
	        } else if (points.length) {
	          segment();
	          points = [];
	        }
	      }
	      if (points.length) segment();
	      return segments.length ? segments.join("") : null;
	    }
	    line.x = function(_) {
	      if (!arguments.length) return x;
	      x = _;
	      return line;
	    };
	    line.y = function(_) {
	      if (!arguments.length) return y;
	      y = _;
	      return line;
	    };
	    line.defined = function(_) {
	      if (!arguments.length) return defined;
	      defined = _;
	      return line;
	    };
	    line.interpolate = function(_) {
	      if (!arguments.length) return interpolateKey;
	      if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
	      return line;
	    };
	    line.tension = function(_) {
	      if (!arguments.length) return tension;
	      tension = _;
	      return line;
	    };
	    return line;
	  }
	  d3.svg.line = function() {
	    return d3_svg_line(d3_identity);
	  };
	  var d3_svg_lineInterpolators = d3.map({
	    linear: d3_svg_lineLinear,
	    "linear-closed": d3_svg_lineLinearClosed,
	    step: d3_svg_lineStep,
	    "step-before": d3_svg_lineStepBefore,
	    "step-after": d3_svg_lineStepAfter,
	    basis: d3_svg_lineBasis,
	    "basis-open": d3_svg_lineBasisOpen,
	    "basis-closed": d3_svg_lineBasisClosed,
	    bundle: d3_svg_lineBundle,
	    cardinal: d3_svg_lineCardinal,
	    "cardinal-open": d3_svg_lineCardinalOpen,
	    "cardinal-closed": d3_svg_lineCardinalClosed,
	    monotone: d3_svg_lineMonotone
	  });
	  d3_svg_lineInterpolators.forEach(function(key, value) {
	    value.key = key;
	    value.closed = /-closed$/.test(key);
	  });
	  function d3_svg_lineLinear(points) {
	    return points.length > 1 ? points.join("L") : points + "Z";
	  }
	  function d3_svg_lineLinearClosed(points) {
	    return points.join("L") + "Z";
	  }
	  function d3_svg_lineStep(points) {
	    var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
	    while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]);
	    if (n > 1) path.push("H", p[0]);
	    return path.join("");
	  }
	  function d3_svg_lineStepBefore(points) {
	    var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
	    while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]);
	    return path.join("");
	  }
	  function d3_svg_lineStepAfter(points) {
	    var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
	    while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]);
	    return path.join("");
	  }
	  function d3_svg_lineCardinalOpen(points, tension) {
	    return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, -1), d3_svg_lineCardinalTangents(points, tension));
	  }
	  function d3_svg_lineCardinalClosed(points, tension) {
	    return points.length < 3 ? d3_svg_lineLinearClosed(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), 
	    points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension));
	  }
	  function d3_svg_lineCardinal(points, tension) {
	    return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension));
	  }
	  function d3_svg_lineHermite(points, tangents) {
	    if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) {
	      return d3_svg_lineLinear(points);
	    }
	    var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1;
	    if (quad) {
	      path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1];
	      p0 = points[1];
	      pi = 2;
	    }
	    if (tangents.length > 1) {
	      t = tangents[1];
	      p = points[pi];
	      pi++;
	      path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
	      for (var i = 2; i < tangents.length; i++, pi++) {
	        p = points[pi];
	        t = tangents[i];
	        path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
	      }
	    }
	    if (quad) {
	      var lp = points[pi];
	      path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1];
	    }
	    return path;
	  }
	  function d3_svg_lineCardinalTangents(points, tension) {
	    var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length;
	    while (++i < n) {
	      p0 = p1;
	      p1 = p2;
	      p2 = points[i];
	      tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]);
	    }
	    return tangents;
	  }
	  function d3_svg_lineBasis(points) {
	    if (points.length < 3) return d3_svg_lineLinear(points);
	    var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
	    points.push(points[n - 1]);
	    while (++i <= n) {
	      pi = points[i];
	      px.shift();
	      px.push(pi[0]);
	      py.shift();
	      py.push(pi[1]);
	      d3_svg_lineBasisBezier(path, px, py);
	    }
	    points.pop();
	    path.push("L", pi);
	    return path.join("");
	  }
	  function d3_svg_lineBasisOpen(points) {
	    if (points.length < 4) return d3_svg_lineLinear(points);
	    var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ];
	    while (++i < 3) {
	      pi = points[i];
	      px.push(pi[0]);
	      py.push(pi[1]);
	    }
	    path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py));
	    --i;
	    while (++i < n) {
	      pi = points[i];
	      px.shift();
	      px.push(pi[0]);
	      py.shift();
	      py.push(pi[1]);
	      d3_svg_lineBasisBezier(path, px, py);
	    }
	    return path.join("");
	  }
	  function d3_svg_lineBasisClosed(points) {
	    var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = [];
	    while (++i < 4) {
	      pi = points[i % n];
	      px.push(pi[0]);
	      py.push(pi[1]);
	    }
	    path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
	    --i;
	    while (++i < m) {
	      pi = points[i % n];
	      px.shift();
	      px.push(pi[0]);
	      py.shift();
	      py.push(pi[1]);
	      d3_svg_lineBasisBezier(path, px, py);
	    }
	    return path.join("");
	  }
	  function d3_svg_lineBundle(points, tension) {
	    var n = points.length - 1;
	    if (n) {
	      var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t;
	      while (++i <= n) {
	        p = points[i];
	        t = i / n;
	        p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx);
	        p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy);
	      }
	    }
	    return d3_svg_lineBasis(points);
	  }
	  function d3_svg_lineDot4(a, b) {
	    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
	  }
	  var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ];
	  function d3_svg_lineBasisBezier(path, x, y) {
	    path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y));
	  }
	  function d3_svg_lineSlope(p0, p1) {
	    return (p1[1] - p0[1]) / (p1[0] - p0[0]);
	  }
	  function d3_svg_lineFiniteDifferences(points) {
	    var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1);
	    while (++i < j) {
	      m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;
	    }
	    m[i] = d;
	    return m;
	  }
	  function d3_svg_lineMonotoneTangents(points) {
	    var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1;
	    while (++i < j) {
	      d = d3_svg_lineSlope(points[i], points[i + 1]);
	      if (abs(d) < ε) {
	        m[i] = m[i + 1] = 0;
	      } else {
	        a = m[i] / d;
	        b = m[i + 1] / d;
	        s = a * a + b * b;
	        if (s > 9) {
	          s = d * 3 / Math.sqrt(s);
	          m[i] = s * a;
	          m[i + 1] = s * b;
	        }
	      }
	    }
	    i = -1;
	    while (++i <= j) {
	      s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i]));
	      tangents.push([ s || 0, m[i] * s || 0 ]);
	    }
	    return tangents;
	  }
	  function d3_svg_lineMonotone(points) {
	    return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points));
	  }
	  d3.svg.line.radial = function() {
	    var line = d3_svg_line(d3_svg_lineRadial);
	    line.radius = line.x, delete line.x;
	    line.angle = line.y, delete line.y;
	    return line;
	  };
	  function d3_svg_lineRadial(points) {
	    var point, i = -1, n = points.length, r, a;
	    while (++i < n) {
	      point = points[i];
	      r = point[0];
	      a = point[1] - halfπ;
	      point[0] = r * Math.cos(a);
	      point[1] = r * Math.sin(a);
	    }
	    return points;
	  }
	  function d3_svg_area(projection) {
	    var x0 = d3_geom_pointX, x1 = d3_geom_pointX, y0 = 0, y1 = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7;
	    function area(data) {
	      var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() {
	        return x;
	      } : d3_functor(x1), fy1 = y0 === y1 ? function() {
	        return y;
	      } : d3_functor(y1), x, y;
	      function segment() {
	        segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z");
	      }
	      while (++i < n) {
	        if (defined.call(this, d = data[i], i)) {
	          points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]);
	          points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]);
	        } else if (points0.length) {
	          segment();
	          points0 = [];
	          points1 = [];
	        }
	      }
	      if (points0.length) segment();
	      return segments.length ? segments.join("") : null;
	    }
	    area.x = function(_) {
	      if (!arguments.length) return x1;
	      x0 = x1 = _;
	      return area;
	    };
	    area.x0 = function(_) {
	      if (!arguments.length) return x0;
	      x0 = _;
	      return area;
	    };
	    area.x1 = function(_) {
	      if (!arguments.length) return x1;
	      x1 = _;
	      return area;
	    };
	    area.y = function(_) {
	      if (!arguments.length) return y1;
	      y0 = y1 = _;
	      return area;
	    };
	    area.y0 = function(_) {
	      if (!arguments.length) return y0;
	      y0 = _;
	      return area;
	    };
	    area.y1 = function(_) {
	      if (!arguments.length) return y1;
	      y1 = _;
	      return area;
	    };
	    area.defined = function(_) {
	      if (!arguments.length) return defined;
	      defined = _;
	      return area;
	    };
	    area.interpolate = function(_) {
	      if (!arguments.length) return interpolateKey;
	      if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
	      interpolateReverse = interpolate.reverse || interpolate;
	      L = interpolate.closed ? "M" : "L";
	      return area;
	    };
	    area.tension = function(_) {
	      if (!arguments.length) return tension;
	      tension = _;
	      return area;
	    };
	    return area;
	  }
	  d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;
	  d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;
	  d3.svg.area = function() {
	    return d3_svg_area(d3_identity);
	  };
	  d3.svg.area.radial = function() {
	    var area = d3_svg_area(d3_svg_lineRadial);
	    area.radius = area.x, delete area.x;
	    area.innerRadius = area.x0, delete area.x0;
	    area.outerRadius = area.x1, delete area.x1;
	    area.angle = area.y, delete area.y;
	    area.startAngle = area.y0, delete area.y0;
	    area.endAngle = area.y1, delete area.y1;
	    return area;
	  };
	  d3.svg.chord = function() {
	    var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
	    function chord(d, i) {
	      var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i);
	      return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z";
	    }
	    function subgroup(self, f, d, i) {
	      var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) - halfπ, a1 = endAngle.call(self, subgroup, i) - halfπ;
	      return {
	        r: r,
	        a0: a0,
	        a1: a1,
	        p0: [ r * Math.cos(a0), r * Math.sin(a0) ],
	        p1: [ r * Math.cos(a1), r * Math.sin(a1) ]
	      };
	    }
	    function equals(a, b) {
	      return a.a0 == b.a0 && a.a1 == b.a1;
	    }
	    function arc(r, p, a) {
	      return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p;
	    }
	    function curve(r0, p0, r1, p1) {
	      return "Q 0,0 " + p1;
	    }
	    chord.radius = function(v) {
	      if (!arguments.length) return radius;
	      radius = d3_functor(v);
	      return chord;
	    };
	    chord.source = function(v) {
	      if (!arguments.length) return source;
	      source = d3_functor(v);
	      return chord;
	    };
	    chord.target = function(v) {
	      if (!arguments.length) return target;
	      target = d3_functor(v);
	      return chord;
	    };
	    chord.startAngle = function(v) {
	      if (!arguments.length) return startAngle;
	      startAngle = d3_functor(v);
	      return chord;
	    };
	    chord.endAngle = function(v) {
	      if (!arguments.length) return endAngle;
	      endAngle = d3_functor(v);
	      return chord;
	    };
	    return chord;
	  };
	  function d3_svg_chordRadius(d) {
	    return d.radius;
	  }
	  d3.svg.diagonal = function() {
	    var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection;
	    function diagonal(d, i) {
	      var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, {
	        x: p0.x,
	        y: m
	      }, {
	        x: p3.x,
	        y: m
	      }, p3 ];
	      p = p.map(projection);
	      return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
	    }
	    diagonal.source = function(x) {
	      if (!arguments.length) return source;
	      source = d3_functor(x);
	      return diagonal;
	    };
	    diagonal.target = function(x) {
	      if (!arguments.length) return target;
	      target = d3_functor(x);
	      return diagonal;
	    };
	    diagonal.projection = function(x) {
	      if (!arguments.length) return projection;
	      projection = x;
	      return diagonal;
	    };
	    return diagonal;
	  };
	  function d3_svg_diagonalProjection(d) {
	    return [ d.x, d.y ];
	  }
	  d3.svg.diagonal.radial = function() {
	    var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection;
	    diagonal.projection = function(x) {
	      return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection;
	    };
	    return diagonal;
	  };
	  function d3_svg_diagonalRadialProjection(projection) {
	    return function() {
	      var d = projection.apply(this, arguments), r = d[0], a = d[1] - halfπ;
	      return [ r * Math.cos(a), r * Math.sin(a) ];
	    };
	  }
	  d3.svg.symbol = function() {
	    var type = d3_svg_symbolType, size = d3_svg_symbolSize;
	    function symbol(d, i) {
	      return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i));
	    }
	    symbol.type = function(x) {
	      if (!arguments.length) return type;
	      type = d3_functor(x);
	      return symbol;
	    };
	    symbol.size = function(x) {
	      if (!arguments.length) return size;
	      size = d3_functor(x);
	      return symbol;
	    };
	    return symbol;
	  };
	  function d3_svg_symbolSize() {
	    return 64;
	  }
	  function d3_svg_symbolType() {
	    return "circle";
	  }
	  function d3_svg_symbolCircle(size) {
	    var r = Math.sqrt(size / π);
	    return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z";
	  }
	  var d3_svg_symbols = d3.map({
	    circle: d3_svg_symbolCircle,
	    cross: function(size) {
	      var r = Math.sqrt(size / 5) / 2;
	      return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z";
	    },
	    diamond: function(size) {
	      var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30;
	      return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z";
	    },
	    square: function(size) {
	      var r = Math.sqrt(size) / 2;
	      return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z";
	    },
	    "triangle-down": function(size) {
	      var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
	      return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z";
	    },
	    "triangle-up": function(size) {
	      var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
	      return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z";
	    }
	  });
	  d3.svg.symbolTypes = d3_svg_symbols.keys();
	  var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians);
	  d3_selectionPrototype.transition = function(name) {
	    var id = d3_transitionInheritId || ++d3_transitionId, ns = d3_transitionNamespace(name), subgroups = [], subgroup, node, transition = d3_transitionInherit || {
	      time: Date.now(),
	      ease: d3_ease_cubicInOut,
	      delay: 0,
	      duration: 250
	    };
	    for (var j = -1, m = this.length; ++j < m; ) {
	      subgroups.push(subgroup = []);
	      for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
	        if (node = group[i]) d3_transitionNode(node, i, ns, id, transition);
	        subgroup.push(node);
	      }
	    }
	    return d3_transition(subgroups, ns, id);
	  };
	  d3_selectionPrototype.interrupt = function(name) {
	    return this.each(name == null ? d3_selection_interrupt : d3_selection_interruptNS(d3_transitionNamespace(name)));
	  };
	  var d3_selection_interrupt = d3_selection_interruptNS(d3_transitionNamespace());
	  function d3_selection_interruptNS(ns) {
	    return function() {
	      var lock, activeId, active;
	      if ((lock = this[ns]) && (active = lock[activeId = lock.active])) {
	        active.timer.c = null;
	        active.timer.t = NaN;
	        if (--lock.count) delete lock[activeId]; else delete this[ns];
	        lock.active += .5;
	        active.event && active.event.interrupt.call(this, this.__data__, active.index);
	      }
	    };
	  }
	  function d3_transition(groups, ns, id) {
	    d3_subclass(groups, d3_transitionPrototype);
	    groups.namespace = ns;
	    groups.id = id;
	    return groups;
	  }
	  var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit;
	  d3_transitionPrototype.call = d3_selectionPrototype.call;
	  d3_transitionPrototype.empty = d3_selectionPrototype.empty;
	  d3_transitionPrototype.node = d3_selectionPrototype.node;
	  d3_transitionPrototype.size = d3_selectionPrototype.size;
	  d3.transition = function(selection, name) {
	    return selection && selection.transition ? d3_transitionInheritId ? selection.transition(name) : selection : d3.selection().transition(selection);
	  };
	  d3.transition.prototype = d3_transitionPrototype;
	  d3_transitionPrototype.select = function(selector) {
	    var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnode, node;
	    selector = d3_selection_selector(selector);
	    for (var j = -1, m = this.length; ++j < m; ) {
	      subgroups.push(subgroup = []);
	      for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
	        if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) {
	          if ("__data__" in node) subnode.__data__ = node.__data__;
	          d3_transitionNode(subnode, i, ns, id, node[ns][id]);
	          subgroup.push(subnode);
	        } else {
	          subgroup.push(null);
	        }
	      }
	    }
	    return d3_transition(subgroups, ns, id);
	  };
	  d3_transitionPrototype.selectAll = function(selector) {
	    var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnodes, node, subnode, transition;
	    selector = d3_selection_selectorAll(selector);
	    for (var j = -1, m = this.length; ++j < m; ) {
	      for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
	        if (node = group[i]) {
	          transition = node[ns][id];
	          subnodes = selector.call(node, node.__data__, i, j);
	          subgroups.push(subgroup = []);
	          for (var k = -1, o = subnodes.length; ++k < o; ) {
	            if (subnode = subnodes[k]) d3_transitionNode(subnode, k, ns, id, transition);
	            subgroup.push(subnode);
	          }
	        }
	      }
	    }
	    return d3_transition(subgroups, ns, id);
	  };
	  d3_transitionPrototype.filter = function(filter) {
	    var subgroups = [], subgroup, group, node;
	    if (typeof filter !== "function") filter = d3_selection_filter(filter);
	    for (var j = 0, m = this.length; j < m; j++) {
	      subgroups.push(subgroup = []);
	      for (var group = this[j], i = 0, n = group.length; i < n; i++) {
	        if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
	          subgroup.push(node);
	        }
	      }
	    }
	    return d3_transition(subgroups, this.namespace, this.id);
	  };
	  d3_transitionPrototype.tween = function(name, tween) {
	    var id = this.id, ns = this.namespace;
	    if (arguments.length < 2) return this.node()[ns][id].tween.get(name);
	    return d3_selection_each(this, tween == null ? function(node) {
	      node[ns][id].tween.remove(name);
	    } : function(node) {
	      node[ns][id].tween.set(name, tween);
	    });
	  };
	  function d3_transition_tween(groups, name, value, tween) {
	    var id = groups.id, ns = groups.namespace;
	    return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) {
	      node[ns][id].tween.set(name, tween(value.call(node, node.__data__, i, j)));
	    } : (value = tween(value), function(node) {
	      node[ns][id].tween.set(name, value);
	    }));
	  }
	  d3_transitionPrototype.attr = function(nameNS, value) {
	    if (arguments.length < 2) {
	      for (value in nameNS) this.attr(value, nameNS[value]);
	      return this;
	    }
	    var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS);
	    function attrNull() {
	      this.removeAttribute(name);
	    }
	    function attrNullNS() {
	      this.removeAttributeNS(name.space, name.local);
	    }
	    function attrTween(b) {
	      return b == null ? attrNull : (b += "", function() {
	        var a = this.getAttribute(name), i;
	        return a !== b && (i = interpolate(a, b), function(t) {
	          this.setAttribute(name, i(t));
	        });
	      });
	    }
	    function attrTweenNS(b) {
	      return b == null ? attrNullNS : (b += "", function() {
	        var a = this.getAttributeNS(name.space, name.local), i;
	        return a !== b && (i = interpolate(a, b), function(t) {
	          this.setAttributeNS(name.space, name.local, i(t));
	        });
	      });
	    }
	    return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween);
	  };
	  d3_transitionPrototype.attrTween = function(nameNS, tween) {
	    var name = d3.ns.qualify(nameNS);
	    function attrTween(d, i) {
	      var f = tween.call(this, d, i, this.getAttribute(name));
	      return f && function(t) {
	        this.setAttribute(name, f(t));
	      };
	    }
	    function attrTweenNS(d, i) {
	      var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
	      return f && function(t) {
	        this.setAttributeNS(name.space, name.local, f(t));
	      };
	    }
	    return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
	  };
	  d3_transitionPrototype.style = function(name, value, priority) {
	    var n = arguments.length;
	    if (n < 3) {
	      if (typeof name !== "string") {
	        if (n < 2) value = "";
	        for (priority in name) this.style(priority, name[priority], value);
	        return this;
	      }
	      priority = "";
	    }
	    function styleNull() {
	      this.style.removeProperty(name);
	    }
	    function styleString(b) {
	      return b == null ? styleNull : (b += "", function() {
	        var a = d3_window(this).getComputedStyle(this, null).getPropertyValue(name), i;
	        return a !== b && (i = d3_interpolate(a, b), function(t) {
	          this.style.setProperty(name, i(t), priority);
	        });
	      });
	    }
	    return d3_transition_tween(this, "style." + name, value, styleString);
	  };
	  d3_transitionPrototype.styleTween = function(name, tween, priority) {
	    if (arguments.length < 3) priority = "";
	    function styleTween(d, i) {
	      var f = tween.call(this, d, i, d3_window(this).getComputedStyle(this, null).getPropertyValue(name));
	      return f && function(t) {
	        this.style.setProperty(name, f(t), priority);
	      };
	    }
	    return this.tween("style." + name, styleTween);
	  };
	  d3_transitionPrototype.text = function(value) {
	    return d3_transition_tween(this, "text", value, d3_transition_text);
	  };
	  function d3_transition_text(b) {
	    if (b == null) b = "";
	    return function() {
	      this.textContent = b;
	    };
	  }
	  d3_transitionPrototype.remove = function() {
	    var ns = this.namespace;
	    return this.each("end.transition", function() {
	      var p;
	      if (this[ns].count < 2 && (p = this.parentNode)) p.removeChild(this);
	    });
	  };
	  d3_transitionPrototype.ease = function(value) {
	    var id = this.id, ns = this.namespace;
	    if (arguments.length < 1) return this.node()[ns][id].ease;
	    if (typeof value !== "function") value = d3.ease.apply(d3, arguments);
	    return d3_selection_each(this, function(node) {
	      node[ns][id].ease = value;
	    });
	  };
	  d3_transitionPrototype.delay = function(value) {
	    var id = this.id, ns = this.namespace;
	    if (arguments.length < 1) return this.node()[ns][id].delay;
	    return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
	      node[ns][id].delay = +value.call(node, node.__data__, i, j);
	    } : (value = +value, function(node) {
	      node[ns][id].delay = value;
	    }));
	  };
	  d3_transitionPrototype.duration = function(value) {
	    var id = this.id, ns = this.namespace;
	    if (arguments.length < 1) return this.node()[ns][id].duration;
	    return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
	      node[ns][id].duration = Math.max(1, value.call(node, node.__data__, i, j));
	    } : (value = Math.max(1, value), function(node) {
	      node[ns][id].duration = value;
	    }));
	  };
	  d3_transitionPrototype.each = function(type, listener) {
	    var id = this.id, ns = this.namespace;
	    if (arguments.length < 2) {
	      var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId;
	      try {
	        d3_transitionInheritId = id;
	        d3_selection_each(this, function(node, i, j) {
	          d3_transitionInherit = node[ns][id];
	          type.call(node, node.__data__, i, j);
	        });
	      } finally {
	        d3_transitionInherit = inherit;
	        d3_transitionInheritId = inheritId;
	      }
	    } else {
	      d3_selection_each(this, function(node) {
	        var transition = node[ns][id];
	        (transition.event || (transition.event = d3.dispatch("start", "end", "interrupt"))).on(type, listener);
	      });
	    }
	    return this;
	  };
	  d3_transitionPrototype.transition = function() {
	    var id0 = this.id, id1 = ++d3_transitionId, ns = this.namespace, subgroups = [], subgroup, group, node, transition;
	    for (var j = 0, m = this.length; j < m; j++) {
	      subgroups.push(subgroup = []);
	      for (var group = this[j], i = 0, n = group.length; i < n; i++) {
	        if (node = group[i]) {
	          transition = node[ns][id0];
	          d3_transitionNode(node, i, ns, id1, {
	            time: transition.time,
	            ease: transition.ease,
	            delay: transition.delay + transition.duration,
	            duration: transition.duration
	          });
	        }
	        subgroup.push(node);
	      }
	    }
	    return d3_transition(subgroups, ns, id1);
	  };
	  function d3_transitionNamespace(name) {
	    return name == null ? "__transition__" : "__transition_" + name + "__";
	  }
	  function d3_transitionNode(node, i, ns, id, inherit) {
	    var lock = node[ns] || (node[ns] = {
	      active: 0,
	      count: 0
	    }), transition = lock[id], time, timer, duration, ease, tweens;
	    function schedule(elapsed) {
	      var delay = transition.delay;
	      timer.t = delay + time;
	      if (delay <= elapsed) return start(elapsed - delay);
	      timer.c = start;
	    }
	    function start(elapsed) {
	      var activeId = lock.active, active = lock[activeId];
	      if (active) {
	        active.timer.c = null;
	        active.timer.t = NaN;
	        --lock.count;
	        delete lock[activeId];
	        active.event && active.event.interrupt.call(node, node.__data__, active.index);
	      }
	      for (var cancelId in lock) {
	        if (+cancelId < id) {
	          var cancel = lock[cancelId];
	          cancel.timer.c = null;
	          cancel.timer.t = NaN;
	          --lock.count;
	          delete lock[cancelId];
	        }
	      }
	      timer.c = tick;
	      d3_timer(function() {
	        if (timer.c && tick(elapsed || 1)) {
	          timer.c = null;
	          timer.t = NaN;
	        }
	        return 1;
	      }, 0, time);
	      lock.active = id;
	      transition.event && transition.event.start.call(node, node.__data__, i);
	      tweens = [];
	      transition.tween.forEach(function(key, value) {
	        if (value = value.call(node, node.__data__, i)) {
	          tweens.push(value);
	        }
	      });
	      ease = transition.ease;
	      duration = transition.duration;
	    }
	    function tick(elapsed) {
	      var t = elapsed / duration, e = ease(t), n = tweens.length;
	      while (n > 0) {
	        tweens[--n].call(node, e);
	      }
	      if (t >= 1) {
	        transition.event && transition.event.end.call(node, node.__data__, i);
	        if (--lock.count) delete lock[id]; else delete node[ns];
	        return 1;
	      }
	    }
	    if (!transition) {
	      time = inherit.time;
	      timer = d3_timer(schedule, 0, time);
	      transition = lock[id] = {
	        tween: new d3_Map(),
	        time: time,
	        timer: timer,
	        delay: inherit.delay,
	        duration: inherit.duration,
	        ease: inherit.ease,
	        index: i
	      };
	      inherit = null;
	      ++lock.count;
	    }
	  }
	  d3.svg.axis = function() {
	    var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, innerTickSize = 6, outerTickSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_;
	    function axis(g) {
	      g.each(function() {
	        var g = d3.select(this);
	        var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = scale.copy();
	        var ticks = tickValues == null ? scale1.ticks ? scale1.ticks.apply(scale1, tickArguments_) : scale1.domain() : tickValues, tickFormat = tickFormat_ == null ? scale1.tickFormat ? scale1.tickFormat.apply(scale1, tickArguments_) : d3_identity : tickFormat_, tick = g.selectAll(".tick").data(ticks, scale1), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", ε), tickExit = d3.transition(tick.exit()).style("opacity", ε).remove(), tickUpdate = d3.transition(tick.order()).style("opacity", 1), tickSpacing = Math.max(innerTickSize, 0) + tickPadding, tickTransform;
	        var range = d3_scaleRange(scale1), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), 
	        d3.transition(path));
	        tickEnter.append("line");
	        tickEnter.append("text");
	        var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"), sign = orient === "top" || orient === "left" ? -1 : 1, x1, x2, y1, y2;
	        if (orient === "bottom" || orient === "top") {
	          tickTransform = d3_svg_axisX, x1 = "x", y1 = "y", x2 = "x2", y2 = "y2";
	          text.attr("dy", sign < 0 ? "0em" : ".71em").style("text-anchor", "middle");
	          pathUpdate.attr("d", "M" + range[0] + "," + sign * outerTickSize + "V0H" + range[1] + "V" + sign * outerTickSize);
	        } else {
	          tickTransform = d3_svg_axisY, x1 = "y", y1 = "x", x2 = "y2", y2 = "x2";
	          text.attr("dy", ".32em").style("text-anchor", sign < 0 ? "end" : "start");
	          pathUpdate.attr("d", "M" + sign * outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + sign * outerTickSize);
	        }
	        lineEnter.attr(y2, sign * innerTickSize);
	        textEnter.attr(y1, sign * tickSpacing);
	        lineUpdate.attr(x2, 0).attr(y2, sign * innerTickSize);
	        textUpdate.attr(x1, 0).attr(y1, sign * tickSpacing);
	        if (scale1.rangeBand) {
	          var x = scale1, dx = x.rangeBand() / 2;
	          scale0 = scale1 = function(d) {
	            return x(d) + dx;
	          };
	        } else if (scale0.rangeBand) {
	          scale0 = scale1;
	        } else {
	          tickExit.call(tickTransform, scale1, scale0);
	        }
	        tickEnter.call(tickTransform, scale0, scale1);
	        tickUpdate.call(tickTransform, scale1, scale1);
	      });
	    }
	    axis.scale = function(x) {
	      if (!arguments.length) return scale;
	      scale = x;
	      return axis;
	    };
	    axis.orient = function(x) {
	      if (!arguments.length) return orient;
	      orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient;
	      return axis;
	    };
	    axis.ticks = function() {
	      if (!arguments.length) return tickArguments_;
	      tickArguments_ = d3_array(arguments);
	      return axis;
	    };
	    axis.tickValues = function(x) {
	      if (!arguments.length) return tickValues;
	      tickValues = x;
	      return axis;
	    };
	    axis.tickFormat = function(x) {
	      if (!arguments.length) return tickFormat_;
	      tickFormat_ = x;
	      return axis;
	    };
	    axis.tickSize = function(x) {
	      var n = arguments.length;
	      if (!n) return innerTickSize;
	      innerTickSize = +x;
	      outerTickSize = +arguments[n - 1];
	      return axis;
	    };
	    axis.innerTickSize = function(x) {
	      if (!arguments.length) return innerTickSize;
	      innerTickSize = +x;
	      return axis;
	    };
	    axis.outerTickSize = function(x) {
	      if (!arguments.length) return outerTickSize;
	      outerTickSize = +x;
	      return axis;
	    };
	    axis.tickPadding = function(x) {
	      if (!arguments.length) return tickPadding;
	      tickPadding = +x;
	      return axis;
	    };
	    axis.tickSubdivide = function() {
	      return arguments.length && axis;
	    };
	    return axis;
	  };
	  var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = {
	    top: 1,
	    right: 1,
	    bottom: 1,
	    left: 1
	  };
	  function d3_svg_axisX(selection, x0, x1) {
	    selection.attr("transform", function(d) {
	      var v0 = x0(d);
	      return "translate(" + (isFinite(v0) ? v0 : x1(d)) + ",0)";
	    });
	  }
	  function d3_svg_axisY(selection, y0, y1) {
	    selection.attr("transform", function(d) {
	      var v0 = y0(d);
	      return "translate(0," + (isFinite(v0) ? v0 : y1(d)) + ")";
	    });
	  }
	  d3.svg.brush = function() {
	    var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, xExtent = [ 0, 0 ], yExtent = [ 0, 0 ], xExtentDomain, yExtentDomain, xClamp = true, yClamp = true, resizes = d3_svg_brushResizes[0];
	    function brush(g) {
	      g.each(function() {
	        var g = d3.select(this).style("pointer-events", "all").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart);
	        var background = g.selectAll(".background").data([ 0 ]);
	        background.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair");
	        g.selectAll(".extent").data([ 0 ]).enter().append("rect").attr("class", "extent").style("cursor", "move");
	        var resize = g.selectAll(".resize").data(resizes, d3_identity);
	        resize.exit().remove();
	        resize.enter().append("g").attr("class", function(d) {
	          return "resize " + d;
	        }).style("cursor", function(d) {
	          return d3_svg_brushCursor[d];
	        }).append("rect").attr("x", function(d) {
	          return /[ew]$/.test(d) ? -3 : null;
	        }).attr("y", function(d) {
	          return /^[ns]/.test(d) ? -3 : null;
	        }).attr("width", 6).attr("height", 6).style("visibility", "hidden");
	        resize.style("display", brush.empty() ? "none" : null);
	        var gUpdate = d3.transition(g), backgroundUpdate = d3.transition(background), range;
	        if (x) {
	          range = d3_scaleRange(x);
	          backgroundUpdate.attr("x", range[0]).attr("width", range[1] - range[0]);
	          redrawX(gUpdate);
	        }
	        if (y) {
	          range = d3_scaleRange(y);
	          backgroundUpdate.attr("y", range[0]).attr("height", range[1] - range[0]);
	          redrawY(gUpdate);
	        }
	        redraw(gUpdate);
	      });
	    }
	    brush.event = function(g) {
	      g.each(function() {
	        var event_ = event.of(this, arguments), extent1 = {
	          x: xExtent,
	          y: yExtent,
	          i: xExtentDomain,
	          j: yExtentDomain
	        }, extent0 = this.__chart__ || extent1;
	        this.__chart__ = extent1;
	        if (d3_transitionInheritId) {
	          d3.select(this).transition().each("start.brush", function() {
	            xExtentDomain = extent0.i;
	            yExtentDomain = extent0.j;
	            xExtent = extent0.x;
	            yExtent = extent0.y;
	            event_({
	              type: "brushstart"
	            });
	          }).tween("brush:brush", function() {
	            var xi = d3_interpolateArray(xExtent, extent1.x), yi = d3_interpolateArray(yExtent, extent1.y);
	            xExtentDomain = yExtentDomain = null;
	            return function(t) {
	              xExtent = extent1.x = xi(t);
	              yExtent = extent1.y = yi(t);
	              event_({
	                type: "brush",
	                mode: "resize"
	              });
	            };
	          }).each("end.brush", function() {
	            xExtentDomain = extent1.i;
	            yExtentDomain = extent1.j;
	            event_({
	              type: "brush",
	              mode: "resize"
	            });
	            event_({
	              type: "brushend"
	            });
	          });
	        } else {
	          event_({
	            type: "brushstart"
	          });
	          event_({
	            type: "brush",
	            mode: "resize"
	          });
	          event_({
	            type: "brushend"
	          });
	        }
	      });
	    };
	    function redraw(g) {
	      g.selectAll(".resize").attr("transform", function(d) {
	        return "translate(" + xExtent[+/e$/.test(d)] + "," + yExtent[+/^s/.test(d)] + ")";
	      });
	    }
	    function redrawX(g) {
	      g.select(".extent").attr("x", xExtent[0]);
	      g.selectAll(".extent,.n>rect,.s>rect").attr("width", xExtent[1] - xExtent[0]);
	    }
	    function redrawY(g) {
	      g.select(".extent").attr("y", yExtent[0]);
	      g.selectAll(".extent,.e>rect,.w>rect").attr("height", yExtent[1] - yExtent[0]);
	    }
	    function brushstart() {
	      var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), dragRestore = d3_event_dragSuppress(target), center, origin = d3.mouse(target), offset;
	      var w = d3.select(d3_window(target)).on("keydown.brush", keydown).on("keyup.brush", keyup);
	      if (d3.event.changedTouches) {
	        w.on("touchmove.brush", brushmove).on("touchend.brush", brushend);
	      } else {
	        w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend);
	      }
	      g.interrupt().selectAll("*").interrupt();
	      if (dragging) {
	        origin[0] = xExtent[0] - origin[0];
	        origin[1] = yExtent[0] - origin[1];
	      } else if (resizing) {
	        var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);
	        offset = [ xExtent[1 - ex] - origin[0], yExtent[1 - ey] - origin[1] ];
	        origin[0] = xExtent[ex];
	        origin[1] = yExtent[ey];
	      } else if (d3.event.altKey) center = origin.slice();
	      g.style("pointer-events", "none").selectAll(".resize").style("display", null);
	      d3.select("body").style("cursor", eventTarget.style("cursor"));
	      event_({
	        type: "brushstart"
	      });
	      brushmove();
	      function keydown() {
	        if (d3.event.keyCode == 32) {
	          if (!dragging) {
	            center = null;
	            origin[0] -= xExtent[1];
	            origin[1] -= yExtent[1];
	            dragging = 2;
	          }
	          d3_eventPreventDefault();
	        }
	      }
	      function keyup() {
	        if (d3.event.keyCode == 32 && dragging == 2) {
	          origin[0] += xExtent[1];
	          origin[1] += yExtent[1];
	          dragging = 0;
	          d3_eventPreventDefault();
	        }
	      }
	      function brushmove() {
	        var point = d3.mouse(target), moved = false;
	        if (offset) {
	          point[0] += offset[0];
	          point[1] += offset[1];
	        }
	        if (!dragging) {
	          if (d3.event.altKey) {
	            if (!center) center = [ (xExtent[0] + xExtent[1]) / 2, (yExtent[0] + yExtent[1]) / 2 ];
	            origin[0] = xExtent[+(point[0] < center[0])];
	            origin[1] = yExtent[+(point[1] < center[1])];
	          } else center = null;
	        }
	        if (resizingX && move1(point, x, 0)) {
	          redrawX(g);
	          moved = true;
	        }
	        if (resizingY && move1(point, y, 1)) {
	          redrawY(g);
	          moved = true;
	        }
	        if (moved) {
	          redraw(g);
	          event_({
	            type: "brush",
	            mode: dragging ? "move" : "resize"
	          });
	        }
	      }
	      function move1(point, scale, i) {
	        var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], extent = i ? yExtent : xExtent, size = extent[1] - extent[0], min, max;
	        if (dragging) {
	          r0 -= position;
	          r1 -= size + position;
	        }
	        min = (i ? yClamp : xClamp) ? Math.max(r0, Math.min(r1, point[i])) : point[i];
	        if (dragging) {
	          max = (min += position) + size;
	        } else {
	          if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min));
	          if (position < min) {
	            max = min;
	            min = position;
	          } else {
	            max = position;
	          }
	        }
	        if (extent[0] != min || extent[1] != max) {
	          if (i) yExtentDomain = null; else xExtentDomain = null;
	          extent[0] = min;
	          extent[1] = max;
	          return true;
	        }
	      }
	      function brushend() {
	        brushmove();
	        g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null);
	        d3.select("body").style("cursor", null);
	        w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null);
	        dragRestore();
	        event_({
	          type: "brushend"
	        });
	      }
	    }
	    brush.x = function(z) {
	      if (!arguments.length) return x;
	      x = z;
	      resizes = d3_svg_brushResizes[!x << 1 | !y];
	      return brush;
	    };
	    brush.y = function(z) {
	      if (!arguments.length) return y;
	      y = z;
	      resizes = d3_svg_brushResizes[!x << 1 | !y];
	      return brush;
	    };
	    brush.clamp = function(z) {
	      if (!arguments.length) return x && y ? [ xClamp, yClamp ] : x ? xClamp : y ? yClamp : null;
	      if (x && y) xClamp = !!z[0], yClamp = !!z[1]; else if (x) xClamp = !!z; else if (y) yClamp = !!z;
	      return brush;
	    };
	    brush.extent = function(z) {
	      var x0, x1, y0, y1, t;
	      if (!arguments.length) {
	        if (x) {
	          if (xExtentDomain) {
	            x0 = xExtentDomain[0], x1 = xExtentDomain[1];
	          } else {
	            x0 = xExtent[0], x1 = xExtent[1];
	            if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);
	            if (x1 < x0) t = x0, x0 = x1, x1 = t;
	          }
	        }
	        if (y) {
	          if (yExtentDomain) {
	            y0 = yExtentDomain[0], y1 = yExtentDomain[1];
	          } else {
	            y0 = yExtent[0], y1 = yExtent[1];
	            if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1);
	            if (y1 < y0) t = y0, y0 = y1, y1 = t;
	          }
	        }
	        return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ];
	      }
	      if (x) {
	        x0 = z[0], x1 = z[1];
	        if (y) x0 = x0[0], x1 = x1[0];
	        xExtentDomain = [ x0, x1 ];
	        if (x.invert) x0 = x(x0), x1 = x(x1);
	        if (x1 < x0) t = x0, x0 = x1, x1 = t;
	        if (x0 != xExtent[0] || x1 != xExtent[1]) xExtent = [ x0, x1 ];
	      }
	      if (y) {
	        y0 = z[0], y1 = z[1];
	        if (x) y0 = y0[1], y1 = y1[1];
	        yExtentDomain = [ y0, y1 ];
	        if (y.invert) y0 = y(y0), y1 = y(y1);
	        if (y1 < y0) t = y0, y0 = y1, y1 = t;
	        if (y0 != yExtent[0] || y1 != yExtent[1]) yExtent = [ y0, y1 ];
	      }
	      return brush;
	    };
	    brush.clear = function() {
	      if (!brush.empty()) {
	        xExtent = [ 0, 0 ], yExtent = [ 0, 0 ];
	        xExtentDomain = yExtentDomain = null;
	      }
	      return brush;
	    };
	    brush.empty = function() {
	      return !!x && xExtent[0] == xExtent[1] || !!y && yExtent[0] == yExtent[1];
	    };
	    return d3.rebind(brush, event, "on");
	  };
	  var d3_svg_brushCursor = {
	    n: "ns-resize",
	    e: "ew-resize",
	    s: "ns-resize",
	    w: "ew-resize",
	    nw: "nwse-resize",
	    ne: "nesw-resize",
	    se: "nwse-resize",
	    sw: "nesw-resize"
	  };
	  var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ];
	  var d3_time_format = d3_time.format = d3_locale_enUS.timeFormat;
	  var d3_time_formatUtc = d3_time_format.utc;
	  var d3_time_formatIso = d3_time_formatUtc("%Y-%m-%dT%H:%M:%S.%LZ");
	  d3_time_format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso;
	  function d3_time_formatIsoNative(date) {
	    return date.toISOString();
	  }
	  d3_time_formatIsoNative.parse = function(string) {
	    var date = new Date(string);
	    return isNaN(date) ? null : date;
	  };
	  d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
	  d3_time.second = d3_time_interval(function(date) {
	    return new d3_date(Math.floor(date / 1e3) * 1e3);
	  }, function(date, offset) {
	    date.setTime(date.getTime() + Math.floor(offset) * 1e3);
	  }, function(date) {
	    return date.getSeconds();
	  });
	  d3_time.seconds = d3_time.second.range;
	  d3_time.seconds.utc = d3_time.second.utc.range;
	  d3_time.minute = d3_time_interval(function(date) {
	    return new d3_date(Math.floor(date / 6e4) * 6e4);
	  }, function(date, offset) {
	    date.setTime(date.getTime() + Math.floor(offset) * 6e4);
	  }, function(date) {
	    return date.getMinutes();
	  });
	  d3_time.minutes = d3_time.minute.range;
	  d3_time.minutes.utc = d3_time.minute.utc.range;
	  d3_time.hour = d3_time_interval(function(date) {
	    var timezone = date.getTimezoneOffset() / 60;
	    return new d3_date((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
	  }, function(date, offset) {
	    date.setTime(date.getTime() + Math.floor(offset) * 36e5);
	  }, function(date) {
	    return date.getHours();
	  });
	  d3_time.hours = d3_time.hour.range;
	  d3_time.hours.utc = d3_time.hour.utc.range;
	  d3_time.month = d3_time_interval(function(date) {
	    date = d3_time.day(date);
	    date.setDate(1);
	    return date;
	  }, function(date, offset) {
	    date.setMonth(date.getMonth() + offset);
	  }, function(date) {
	    return date.getMonth();
	  });
	  d3_time.months = d3_time.month.range;
	  d3_time.months.utc = d3_time.month.utc.range;
	  function d3_time_scale(linear, methods, format) {
	    function scale(x) {
	      return linear(x);
	    }
	    scale.invert = function(x) {
	      return d3_time_scaleDate(linear.invert(x));
	    };
	    scale.domain = function(x) {
	      if (!arguments.length) return linear.domain().map(d3_time_scaleDate);
	      linear.domain(x);
	      return scale;
	    };
	    function tickMethod(extent, count) {
	      var span = extent[1] - extent[0], target = span / count, i = d3.bisect(d3_time_scaleSteps, target);
	      return i == d3_time_scaleSteps.length ? [ methods.year, d3_scale_linearTickRange(extent.map(function(d) {
	        return d / 31536e6;
	      }), count)[2] ] : !i ? [ d3_time_scaleMilliseconds, d3_scale_linearTickRange(extent, count)[2] ] : methods[target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target ? i - 1 : i];
	    }
	    scale.nice = function(interval, skip) {
	      var domain = scale.domain(), extent = d3_scaleExtent(domain), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" && tickMethod(extent, interval);
	      if (method) interval = method[0], skip = method[1];
	      function skipped(date) {
	        return !isNaN(date) && !interval.range(date, d3_time_scaleDate(+date + 1), skip).length;
	      }
	      return scale.domain(d3_scale_nice(domain, skip > 1 ? {
	        floor: function(date) {
	          while (skipped(date = interval.floor(date))) date = d3_time_scaleDate(date - 1);
	          return date;
	        },
	        ceil: function(date) {
	          while (skipped(date = interval.ceil(date))) date = d3_time_scaleDate(+date + 1);
	          return date;
	        }
	      } : interval));
	    };
	    scale.ticks = function(interval, skip) {
	      var extent = d3_scaleExtent(scale.domain()), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" ? tickMethod(extent, interval) : !interval.range && [ {
	        range: interval
	      }, skip ];
	      if (method) interval = method[0], skip = method[1];
	      return interval.range(extent[0], d3_time_scaleDate(+extent[1] + 1), skip < 1 ? 1 : skip);
	    };
	    scale.tickFormat = function() {
	      return format;
	    };
	    scale.copy = function() {
	      return d3_time_scale(linear.copy(), methods, format);
	    };
	    return d3_scale_linearRebind(scale, linear);
	  }
	  function d3_time_scaleDate(t) {
	    return new Date(t);
	  }
	  var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ];
	  var d3_time_scaleLocalMethods = [ [ d3_time.second, 1 ], [ d3_time.second, 5 ], [ d3_time.second, 15 ], [ d3_time.second, 30 ], [ d3_time.minute, 1 ], [ d3_time.minute, 5 ], [ d3_time.minute, 15 ], [ d3_time.minute, 30 ], [ d3_time.hour, 1 ], [ d3_time.hour, 3 ], [ d3_time.hour, 6 ], [ d3_time.hour, 12 ], [ d3_time.day, 1 ], [ d3_time.day, 2 ], [ d3_time.week, 1 ], [ d3_time.month, 1 ], [ d3_time.month, 3 ], [ d3_time.year, 1 ] ];
	  var d3_time_scaleLocalFormat = d3_time_format.multi([ [ ".%L", function(d) {
	    return d.getMilliseconds();
	  } ], [ ":%S", function(d) {
	    return d.getSeconds();
	  } ], [ "%I:%M", function(d) {
	    return d.getMinutes();
	  } ], [ "%I %p", function(d) {
	    return d.getHours();
	  } ], [ "%a %d", function(d) {
	    return d.getDay() && d.getDate() != 1;
	  } ], [ "%b %d", function(d) {
	    return d.getDate() != 1;
	  } ], [ "%B", function(d) {
	    return d.getMonth();
	  } ], [ "%Y", d3_true ] ]);
	  var d3_time_scaleMilliseconds = {
	    range: function(start, stop, step) {
	      return d3.range(Math.ceil(start / step) * step, +stop, step).map(d3_time_scaleDate);
	    },
	    floor: d3_identity,
	    ceil: d3_identity
	  };
	  d3_time_scaleLocalMethods.year = d3_time.year;
	  d3_time.scale = function() {
	    return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
	  };
	  var d3_time_scaleUtcMethods = d3_time_scaleLocalMethods.map(function(m) {
	    return [ m[0].utc, m[1] ];
	  });
	  var d3_time_scaleUtcFormat = d3_time_formatUtc.multi([ [ ".%L", function(d) {
	    return d.getUTCMilliseconds();
	  } ], [ ":%S", function(d) {
	    return d.getUTCSeconds();
	  } ], [ "%I:%M", function(d) {
	    return d.getUTCMinutes();
	  } ], [ "%I %p", function(d) {
	    return d.getUTCHours();
	  } ], [ "%a %d", function(d) {
	    return d.getUTCDay() && d.getUTCDate() != 1;
	  } ], [ "%b %d", function(d) {
	    return d.getUTCDate() != 1;
	  } ], [ "%B", function(d) {
	    return d.getUTCMonth();
	  } ], [ "%Y", d3_true ] ]);
	  d3_time_scaleUtcMethods.year = d3_time.year.utc;
	  d3_time.scale.utc = function() {
	    return d3_time_scale(d3.scale.linear(), d3_time_scaleUtcMethods, d3_time_scaleUtcFormat);
	  };
	  d3.text = d3_xhrType(function(request) {
	    return request.responseText;
	  });
	  d3.json = function(url, callback) {
	    return d3_xhr(url, "application/json", d3_json, callback);
	  };
	  function d3_json(request) {
	    return JSON.parse(request.responseText);
	  }
	  d3.html = function(url, callback) {
	    return d3_xhr(url, "text/html", d3_html, callback);
	  };
	  function d3_html(request) {
	    var range = d3_document.createRange();
	    range.selectNode(d3_document.body);
	    return range.createContextualFragment(request.responseText);
	  }
	  d3.xml = d3_xhrType(function(request) {
	    return request.responseXML;
	  });
	  if (true) this.d3 = d3, !(__WEBPACK_AMD_DEFINE_FACTORY__ = (d3), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); else if (typeof module === "object" && module.exports) module.exports = d3; else this.d3 = d3;
	}();

/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {

	module.exports =
	/******/ (function(modules) { // webpackBootstrap
	/******/ 	// The module cache
	/******/ 	var installedModules = {};
	
	/******/ 	// The require function
	/******/ 	function __webpack_require__(moduleId) {
	
	/******/ 		// Check if module is in cache
	/******/ 		if(installedModules[moduleId])
	/******/ 			return installedModules[moduleId].exports;
	
	/******/ 		// Create a new module (and put it into the cache)
	/******/ 		var module = installedModules[moduleId] = {
	/******/ 			exports: {},
	/******/ 			id: moduleId,
	/******/ 			loaded: false
	/******/ 		};
	
	/******/ 		// Execute the module function
	/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
	
	/******/ 		// Flag the module as loaded
	/******/ 		module.loaded = true;
	
	/******/ 		// Return the exports of the module
	/******/ 		return module.exports;
	/******/ 	}
	
	
	/******/ 	// expose the modules object (__webpack_modules__)
	/******/ 	__webpack_require__.m = modules;
	
	/******/ 	// expose the module cache
	/******/ 	__webpack_require__.c = installedModules;
	
	/******/ 	// __webpack_public_path__
	/******/ 	__webpack_require__.p = "";
	
	/******/ 	// Load entry module and return exports
	/******/ 	return __webpack_require__(0);
	/******/ })
	/************************************************************************/
	/******/ ([
	/* 0 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_config = __webpack_require__(1);
		var make_params = __webpack_require__(9);
		var make_viz = __webpack_require__(89);
		var resize_viz = __webpack_require__(152);
		var play_demo = __webpack_require__(229);
		var ini_demo = __webpack_require__(247);
		var filter_viz_using_nodes = __webpack_require__(250);
		var filter_viz_using_names = __webpack_require__(251);
		var update_cats = __webpack_require__(252);
		var reset_cats = __webpack_require__(253);
		var two_translate_zoom = __webpack_require__(144);
		var update_view = __webpack_require__(202);
		var save_matrix = __webpack_require__(255);
		var brush_crop_matrix = __webpack_require__(259);
		var run_zoom = __webpack_require__(153);
		var d3_tip_custom = __webpack_require__(100);
		var all_reorder = __webpack_require__(143);
		var make_matrix_string = __webpack_require__(257);
	
		// moved d3.slider to src
		d3.slider = __webpack_require__(261);
	
		/* eslint-disable */
	
		var awesomplete = __webpack_require__(263);
		// getting css from src
		__webpack_require__(265);
		__webpack_require__(269);
	
		/* clustergrammer v1.19.5
		 * Nicolas Fernandez, Ma'ayan Lab, Icahn School of Medicine at Mount Sinai
		 * (c) 2017
		 */
		function Clustergrammer(args) {
	
		  /* Main program
		   * ----------------------------------------------------------------------- */
		  // consume and validate user input
		  // build giant config object
		  // visualize based on config object
		  // handle user events
	
		  // consume and validate user arguments, produce configuration object
		  var config = make_config(args);
	
		  var cgm = {};
	
		  // make visualization parameters using configuration object
		  cgm.params = make_params(config);
		  cgm.config = config;
	
		  // set up zoom
		  cgm.params.zoom_behavior = d3.behavior.zoom().scaleExtent([1, cgm.params.viz.square_zoom * cgm.params.viz.zoom_ratio.x]).on('zoom', function () {
		    run_zoom(cgm);
		  });
	
		  cgm.params.zoom_behavior.translate([cgm.params.viz.clust.margin.left, cgm.params.viz.clust.margin.top]);
	
		  if (cgm.params.use_sidebar) {
		    var make_sidebar = __webpack_require__(271);
		    make_sidebar(cgm);
		  }
	
		  // make visualization using parameters
		  make_viz(cgm);
	
		  function external_resize() {
	
		    d3.select(cgm.params.viz.viz_svg).style('opacity', 0.5);
	
		    var wait_time = 500;
		    if (this.params.viz.run_trans === true) {
		      wait_time = 2500;
		    }
	
		    setTimeout(resize_fun, wait_time, this);
		  }
	
		  function resize_fun(cgm) {
		    resize_viz(cgm);
		  }
	
		  function run_update_cats(cat_data) {
		    update_cats(this, cat_data);
		  }
	
		  function zoom_api(pan_dx, pan_dy, fin_zoom) {
		    two_translate_zoom(this, pan_dx, pan_dy, fin_zoom);
		  }
	
		  function expose_d3_tip_custom() {
		    // this allows external modules to have access to d3_tip
		    return d3_tip_custom;
		  }
	
		  function api_reorder(inst_rc, inst_order) {
		    if (inst_order === 'sum') {
		      inst_order = 'rank';
		    }
		    if (inst_order === 'var') {
		      inst_order = 'rankvar';
		    }
		    all_reorder(this, inst_order, inst_rc);
		  }
	
		  function export_matrix_string() {
		    return make_matrix_string(this.params);
		  }
	
		  function external_update_view(filter_type, inst_state) {
		    update_view(this, filter_type, inst_state);
		  }
	
		  // add more API endpoints
		  cgm.update_view = update_view;
		  cgm.resize_viz = external_resize;
		  cgm.play_demo = play_demo;
		  cgm.ini_demo = ini_demo;
		  cgm.filter_viz_using_nodes = filter_viz_using_nodes;
		  cgm.filter_viz_using_names = filter_viz_using_names;
		  cgm.update_cats = run_update_cats;
		  cgm.reset_cats = reset_cats;
		  cgm.zoom = zoom_api;
		  cgm.save_matrix = save_matrix;
		  cgm.brush_crop_matrix = brush_crop_matrix;
		  cgm.d3_tip_custom = expose_d3_tip_custom;
		  cgm.reorder = api_reorder;
		  cgm.export_matrix_string = export_matrix_string;
		  cgm.update_view = external_update_view;
	
		  return cgm;
		}
	
		module.exports = Clustergrammer;
	
	/***/ }),
	/* 1 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
		var transpose_network = __webpack_require__(3);
		var get_available_filters = __webpack_require__(4);
		var get_filter_default_state = __webpack_require__(5);
		var set_defaults = __webpack_require__(6);
		var check_sim_mat = __webpack_require__(7);
		var check_nodes_for_categories = __webpack_require__(8);
	
		module.exports = function make_config(args) {
	
		  var defaults = set_defaults();
	
		  // Mixin defaults with user-defined arguments.
		  var config = utils.extend(defaults, args);
	
		  config.network_data = args.network_data;
	
		  var super_string = ': ';
	
		  // replace undersores with space in row/col names
		  _.each(['row', 'col'], function (inst_rc) {
	
		    var inst_nodes = config.network_data[inst_rc + '_nodes'];
	
		    var has_cats = check_nodes_for_categories(inst_nodes);
	
		    inst_nodes.forEach(function (d, i) {
	
		      // add index to row_nodes and col_nodes
		      d[inst_rc + '_index'] = i;
	
		      if (has_cats) {
		        config.super_labels = true;
		        config.super[inst_rc] = d.name.split(super_string)[0];
		        d.name = d.name.split(super_string)[1];
		      }
	
		      d.name = String(d.name);
	
		      d.name = d.name.replace(/_/g, ' ');
		    });
		  });
	
		  config.network_data.row_nodes_names = utils.pluck(config.network_data.row_nodes, 'name');
		  config.network_data.col_nodes_names = utils.pluck(config.network_data.col_nodes, 'name');
	
		  config.sim_mat = check_sim_mat(config);
	
		  var filters = get_available_filters(config.network_data.views);
	
		  var default_states = {};
		  _.each(_.keys(filters.possible_filters), function (inst_filter) {
		    var tmp_state = get_filter_default_state(filters.filter_data, inst_filter);
	
		    default_states[inst_filter] = tmp_state;
		  });
	
		  // process view
		  if (_.has(config.network_data, 'views')) {
		    config.network_data.views.forEach(function (inst_view) {
	
		      _.each(_.keys(filters.possible_filters), function (inst_filter) {
		        if (!_.has(inst_view, inst_filter)) {
		          inst_view[inst_filter] = default_states[inst_filter];
		        }
		      });
	
		      var inst_nodes = inst_view.nodes;
	
		      // proc row/col nodes names in views
		      _.each(['row', 'col'], function (inst_rc) {
	
		        var has_cats = check_nodes_for_categories(inst_nodes[inst_rc + '_nodes']);
	
		        inst_nodes[inst_rc + '_nodes'].forEach(function (d, i) {
	
		          // add index to row_nodes and col_nodes
		          d[inst_rc + '_index'] = i;
	
		          if (has_cats) {
		            d.name = d.name.split(super_string)[1];
		          }
	
		          d.name = String(d.name);
		          d.name = d.name.replace(/_/g, ' ');
		        });
		      });
		    });
		  }
	
		  var col_nodes = config.network_data.col_nodes;
		  var row_nodes = config.network_data.row_nodes;
	
		  // console.log( config.network_data.links[0] )
		  // console.log( config.network_data.links[1] )
		  // console.log( config.network_data.links[2] )
	
		  // console.log(_.has(config.network_data,'mat'));
	
		  ///////////////////////////
		  // convert 'mat' to links
		  ///////////////////////////
	
		  if (_.has(config.network_data, 'mat')) {
	
		    var links = [];
		    var mat = config.network_data.mat;
		    var inst_link = {};
	
		    // console.log('found mat')
		    for (var i = 0; i < mat.length; i++) {
		      for (var j = 0; j < mat[0].length; j++) {
		        // console.log(mat[i][j])
	
		        inst_link = {};
		        inst_link.source = i;
		        inst_link.target = j;
		        inst_link.value = mat[i][j];
		        links.push(inst_link);
		      }
		    }
	
		    // save to network_data
		    config.network_data.links = links;
		  }
	
		  // add names and instantaneous positions to links
		  config.network_data.links.forEach(function (d) {
		    d.name = row_nodes[d.source].name + '_' + col_nodes[d.target].name;
		    d.row_name = row_nodes[d.source].name;
		    d.col_name = col_nodes[d.target].name;
		  });
	
		  // transpose network if necessary
		  if (config.transpose) {
		    config.network_data = transpose_network(config.network_data);
		    var tmp_col_label = args.col_label;
		    var tmp_row_label = args.row_label;
		    args.row_label = tmp_col_label;
		    args.col_label = tmp_row_label;
		  }
	
		  // super-row/col labels
		  if (!utils.is_undefined(args.row_label) && !utils.is_undefined(args.col_label)) {
		    config.super_labels = true;
		    config.super = {};
		    config.super.row = args.row_label;
		    config.super.col = args.col_label;
		  }
	
		  // initialize cluster ordering - both rows and columns
		  config.inst_order = {};
		  if (!utils.is_undefined(args.order) && utils.is_supported_order(args.order)) {
		    config.inst_order.row = args.order;
		    config.inst_order.col = args.order;
		  } else {
		    config.inst_order.row = 'clust';
		    config.inst_order.col = 'clust';
		  }
	
		  // set row or column order directly -- note that row/col are swapped
		  // !! need to swap row/col orderings
		  if (!utils.is_undefined(args.row_order) && utils.is_supported_order(args.row_order)) {
		    // !! row and col orderings are swapped, need to fix
		    config.inst_order.col = args.row_order;
		  }
	
		  if (!utils.is_undefined(args.col_order) && utils.is_supported_order(args.col_order)) {
		    // !! row and col orderings are swapped, need to fix
		    config.inst_order.row = args.col_order;
		  }
	
		  var row_has_group = utils.has(config.network_data.row_nodes[0], 'group');
		  var col_has_group = utils.has(config.network_data.col_nodes[0], 'group');
	
		  config.show_dendrogram = row_has_group || col_has_group;
	
		  if (utils.has(config.network_data.links[0], 'value_orig')) {
		    config.keep_orig = true;
		  } else {
		    config.keep_orig = false;
		  }
	
		  return config;
		};
	
	/***/ }),
	/* 2 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
	
		/* Utility functions
		 * ----------------------------------------------------------------------- */
		module.exports = {
		  normal_name: function normal_name(d) {
		    var inst_name = d.name.replace(/_/g, ' ').split('#')[0];
		    return inst_name;
		  },
		  is_supported_order: function is_supported_order(order) {
		    return order === 'ini' || order === 'clust' || order === 'rank_var' || order === 'rank' || order === 'class' || order == 'alpha';
		  },
	
		  /* Returns whether or not an object has a certain property.
		   */
		  has: function has(obj, key) {
		    return obj != null && hasOwnProperty.call(obj, key);
		  },
	
		  property: function property(key) {
		    return function (obj) {
		      return obj == null ? void 0 : obj[key];
		    };
		  },
	
		  // Convenience version of a common use case of `map`: fetching a property.
		  pluck: function pluck(arr, key) {
		    var self = this;
		    // Double check that we have lodash or underscore available
		    if (window._) {
		      // Underscore provides a _.pluck function. Use that.
		      if (typeof _.pluck === 'function') {
		        return _.pluck(arr, key);
		      } else if (typeof _.map === 'function') {
		        // Lodash does not have a pluck function.
		        // Use _.map with the property function defined above.
		        return _.map(arr, self.property(key));
		      }
		    } else if (arr.map && typeof arr.map === 'function') {
		      // If lodash or underscore not available, check to see if the native arr.map is available.
		      // If so, use it with the property function defined above.
		      return arr.map(self.property(key));
		    }
		  },
	
		  /* Returns true if the object is undefined.
		   */
		  is_undefined: function is_undefined(obj) {
		    return obj === void 0;
		  },
	
		  /* Mixes two objects in together, overwriting a target with a source.
		   */
		  extend: function extend(target, source) {
		    target = target || {};
		    for (var prop in source) {
		      if (_typeof(source[prop]) === 'object') {
		        target[prop] = this.extend(target[prop], source[prop]);
		      } else {
		        target[prop] = source[prop];
		      }
		    }
		    return target;
		  }
			};
	
	/***/ }),
	/* 3 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
		/* Transpose network.
		 */
		module.exports = function (net) {
		  var tnet = {},
		      inst_link,
		      i;
	
		  tnet.row_nodes = net.col_nodes;
		  tnet.col_nodes = net.row_nodes;
		  tnet.links = [];
	
		  for (i = 0; i < net.links.length; i++) {
		    inst_link = {};
		    inst_link.source = net.links[i].target;
		    inst_link.target = net.links[i].source;
		    inst_link.value = net.links[i].value;
	
		    // Optional highlight.
		    if (utils.has(net.links[i], 'highlight')) {
		      inst_link.highlight = net.links[i].highlight;
		    }
		    if (utils.has(net.links[i], 'value_up')) {
		      inst_link.value_up = net.links[i].value_up;
		    }
		    if (utils.has(net.links[i], 'value_dn')) {
		      inst_link.value_dn = net.links[i].value_dn;
		    }
		    if (utils.has(net.links[i], 'info')) {
		      inst_link.info = net.links[i].info;
		    }
		    tnet.links.push(inst_link);
		  }
	
		  return tnet;
		};
	
	/***/ }),
	/* 4 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function get_available_filters(views) {
	
		  var possible_filters = {};
		  var filter_data = {};
	
		  _.each(views, function (inst_view) {
		    var inst_keys = _.keys(inst_view);
	
		    _.each(inst_keys, function (inst_key) {
	
		      if (inst_key != 'nodes') {
	
		        if (!_.has(filter_data, inst_key)) {
		          filter_data[inst_key] = [];
		        }
	
		        filter_data[inst_key].push(inst_view[inst_key]);
	
		        filter_data[inst_key] = _.uniq(filter_data[inst_key]);
		      }
		    });
		  });
	
		  var tmp_filters = _.keys(filter_data);
	
		  _.each(tmp_filters, function (inst_filter) {
	
		    var options = filter_data[inst_filter];
		    var num_options = options.length;
	
		    var filter_type = 'categorical';
		    _.each(options, function (inst_option) {
		      if (typeof inst_option === 'number') {
		        filter_type = 'numerical';
		      }
		    });
	
		    if (num_options > 1) {
		      possible_filters[inst_filter] = filter_type;
		    }
		  });
	
		  var filters = {};
		  filters.possible_filters = possible_filters;
		  filters.filter_data = filter_data;
	
		  return filters;
			};
	
	/***/ }),
	/* 5 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function get_filter_default_state(filter_data, filter_type) {
	
		  var default_state = filter_data[filter_type].sort(function (a, b) {
		    return b - a;
		  })[0];
	
		  default_state = String(default_state);
	
		  return default_state;
		};
	
	/***/ }),
	/* 6 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function set_defaults() {
	
		  var defaults = {
		    // Label options
		    row_label_scale: 1,
		    col_label_scale: 1,
		    super_labels: false,
		    super: {},
		    show_label_tooltips: true,
		    show_tile_tooltips: true,
		    // matrix options
		    transpose: false,
		    tile_colors: ['#FF0000', '#1C86EE'],
		    bar_colors: ['#FF0000', '#1C86EE'],
		    // value-cat colors
		    // cat_value_colors: ['#2F4F4F', '#8A2BE2'],
		    cat_value_colors: ['#2F4F4F', '#9370DB'],
		    outline_colors: ['orange', 'black'],
		    highlight_color: '#FFFF00',
		    tile_title: false,
		    // Default domain is set to 0: the domain will be set automatically
		    input_domain: 0,
		    opacity_scale: 'linear',
		    do_zoom: true,
		    is_zoom: 0,
		    is_slider_drag: false,
		    is_cropping: false,
		    background_color: '#FFFFFF',
		    super_border_color: '#F5F5F5',
		    outer_margins: {
		      top: 0,
		      bottom: 0,
		      left: 0,
		      right: 0
		    },
		    ini_expand: false,
		    grey_border_width: 2,
		    tile_click_hlight: false,
		    super_label_scale: 1,
		    make_tile_tooltip: function make_tile_tooltip(d) {
		      return d.info;
		    },
		    // initialize view, e.g. initialize with row filtering
		    ini_view: null,
		    // record of requested views
		    requested_view: null,
		    use_sidebar: true,
		    title: null,
		    about: null,
		    sidebar_width: 160,
		    sidebar_icons: true,
		    row_search_placeholder: 'Row',
		    buffer_width: 10,
		    show_sim_mat: false,
		    cat_colors: null,
		    resize: true,
		    clamp_opacity: 0.85,
		    expand_button: true,
		    max_allow_fs: 20,
		    dendro_filter: { 'row': false, 'col': false },
		    cat_filter: { 'row': false, 'col': false },
		    crop_filter_nodes: { 'row': false, 'col': false },
		    row_tip_callback: null,
		    col_tip_callback: null,
		    tile_tip_callback: null,
		    matrix_update_callback: null,
		    cat_update_callback: null,
		    dendro_callback: null,
		    dendro_click_callback: null,
		    new_row_cats: null,
		    make_modals: true,
		    show_viz_border: false
		  };
	
		  return defaults;
		};
	
	/***/ }),
	/* 7 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function check_sim_mat(config) {
	
		  var sim_mat = false;
	
		  var num_rows = config.network_data.row_nodes_names.length;
		  var num_cols = config.network_data.col_nodes_names.length;
	
		  if (num_rows == num_cols) {
	
		    // the sort here was causing errors 
		    var rows = config.network_data.row_nodes_names;
		    var cols = config.network_data.col_nodes_names;
		    sim_mat = true;
	
		    _.each(rows, function (inst_row) {
		      var inst_index = rows.indexOf(inst_row);
		      if (inst_row !== cols[inst_index]) {
		        sim_mat = false;
		      }
		    });
		  }
	
		  if (sim_mat) {
		    config.expand_button = false;
		  }
	
		  return sim_mat;
		};
	
	/***/ }),
	/* 8 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function check_nodes_for_categories(nodes) {
	
		  var super_string = ': ';
		  var has_cat = true;
	
		  _.each(nodes, function (inst_node) {
		    var inst_name = String(inst_node.name);
		    if (inst_name.indexOf(super_string) < 0) {
		      has_cat = false;
		    }
		  });
	
		  return has_cat;
			};
	
	/***/ }),
	/* 9 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_network_using_view = __webpack_require__(10);
		var ini_sidebar_params = __webpack_require__(64);
		var make_requested_view = __webpack_require__(65);
		var get_available_filters = __webpack_require__(4);
		var calc_viz_params = __webpack_require__(66);
		var ini_zoom_info = __webpack_require__(88);
	
		/*
		Params: calculates the size of all the visualization elements in the
		clustergram.
		 */
	
		module.exports = function make_params(input_config) {
	
		  var config = $.extend(true, {}, input_config);
		  var params = config;
	
		  // keep a copy of inst_view
		  params.inst_nodes = {};
		  params.inst_nodes.row_nodes = params.network_data.row_nodes;
		  params.inst_nodes.col_nodes = params.network_data.col_nodes;
	
		  // when pre-loading the visualization using a view
		  if (params.ini_view !== null) {
	
		    var requested_view = params.ini_view;
	
		    var filters = get_available_filters(params.network_data.views);
	
		    params.viz = {};
		    params.viz.possible_filters = filters.possible_filters;
		    params.viz.filter_data = filters.filter_data;
	
		    requested_view = make_requested_view(params, requested_view);
		    params.network_data = make_network_using_view(config, params, requested_view);
	
		    // save ini_view as requested_view
		    params.requested_view = requested_view;
		  }
	
		  params = calc_viz_params(params);
	
		  if (params.use_sidebar) {
		    params.sidebar = ini_sidebar_params(params);
		  }
	
		  params.zoom_info = ini_zoom_info();
	
		  return params;
		};
	
	/***/ }),
	/* 10 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var filter_network_using_new_nodes = __webpack_require__(11);
		var get_subset_views = __webpack_require__(63);
	
		module.exports = function make_network_using_view(config, params, requested_view) {
	
		  var orig_views = config.network_data.views;
	
		  var is_enr = false;
		  if (_.has(orig_views[0], 'enr_score_type')) {
		    is_enr = true;
		  }
	
		  var sub_views = get_subset_views(params, orig_views, requested_view);
	
		  //////////////////////////////
		  // Enrichr specific rules
		  //////////////////////////////
		  if (is_enr && sub_views.length == 0) {
		    requested_view = { 'N_row_sum': 'all', 'N_col_sum': '10' };
		    sub_views = get_subset_views(params, orig_views, requested_view);
		  }
	
		  var inst_view = sub_views[0];
	
		  var new_network_data;
	
		  // get new_network_data or default back to old_network_data
		  if (typeof inst_view !== 'undefined') {
		    var new_nodes = inst_view.nodes;
		    new_network_data = filter_network_using_new_nodes(config, new_nodes);
		  } else {
		    new_network_data = config.network_data;
		  }
	
		  return new_network_data;
		};
	
	/***/ }),
	/* 11 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
		var core = __webpack_require__(12);
		var math = core.create();
		math.import(__webpack_require__(25));
		math.import(__webpack_require__(62));
	
		module.exports = function filter_network_using_new_nodes(config, new_nodes) {
	
		  var links = config.network_data.links;
	
		  // // make new mat from links
		  // var new_mat = config.network_data.mat;
	
		  // get new names of rows and cols
		  var row_names = utils.pluck(new_nodes.row_nodes, 'name');
		  var col_names = utils.pluck(new_nodes.col_nodes, 'name');
	
		  var new_mat = math.matrix(math.zeros([new_nodes.row_nodes.length, new_nodes.col_nodes.length]));
		  new_mat = new_mat.toArray();
	
		  var new_links = _.filter(links, function (inst_link) {
	
		    var inst_row = inst_link.name.split('_')[0];
		    var inst_col = inst_link.name.split('_')[1];
	
		    var row_index = _.indexOf(row_names, inst_row);
		    var col_index = _.indexOf(col_names, inst_col);
	
		    // only keep links that have not been filtered out
		    if (row_index > -1 & col_index > -1) {
	
		      // redefine source and target
		      inst_link.source = row_index;
		      inst_link.target = col_index;
	
		      new_mat[row_index][col_index] = inst_link.value;
	
		      return inst_link;
		    }
		  });
	
		  // set up new_network_data
		  var new_network_data = {};
	
		  // rows
		  new_network_data.row_nodes = new_nodes.row_nodes;
		  new_network_data.row_nodes_names = row_names;
	
		  // cols
		  new_network_data.col_nodes = new_nodes.col_nodes;
		  new_network_data.col_nodes_names = col_names;
	
		  // save all links
		  new_network_data.links = new_links;
		  new_network_data.all_links = links;
	
		  // mat
		  new_network_data.mat = new_mat;
	
		  // add back all views
		  new_network_data.views = config.network_data.views;
	
		  // add cat_colors if necessary
		  if (_.has(config.network_data, 'cat_colors')) {
		    new_network_data.cat_colors = config.network_data.cat_colors;
		  }
	
		  return new_network_data;
		};
	
	/***/ }),
	/* 12 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
			module.exports = __webpack_require__(13);
	
	/***/ }),
	/* 13 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var isFactory = __webpack_require__(14).isFactory;
		var typedFactory = __webpack_require__(16);
		var emitter = __webpack_require__(20);
	
		var importFactory = __webpack_require__(22);
		var configFactory = __webpack_require__(24);
	
		/**
		 * Math.js core. Creates a new, empty math.js instance
		 * @param {Object} [options] Available options:
		 *                            {number} epsilon
		 *                              Minimum relative difference between two
		 *                              compared values, used by all comparison functions.
		 *                            {string} matrix
		 *                              A string 'Matrix' (default) or 'Array'.
		 *                            {string} number
		 *                              A string 'number' (default), 'BigNumber', or 'Fraction'
		 *                            {number} precision
		 *                              The number of significant digits for BigNumbers.
		 *                              Not applicable for Numbers.
		 *                            {boolean} predictable
		 *                              Predictable output type of functions. When true,
		 *                              output type depends only on the input types. When
		 *                              false (default), output type can vary depending
		 *                              on input values. For example `math.sqrt(-4)`
		 *                              returns `complex('2i')` when predictable is false, and
		 *                              returns `NaN` when true.
		 *                            {string} randomSeed
		 *                              Random seed for seeded pseudo random number generator.
		 *                              Set to null to randomly seed.
		 * @returns {Object} Returns a bare-bone math.js instance containing
		 *                   functions:
		 *                   - `import` to add new functions
		 *                   - `config` to change configuration
		 *                   - `on`, `off`, `once`, `emit` for events
		 */
		exports.create = function create(options) {
		  // simple test for ES5 support
		  if (typeof Object.create !== 'function') {
		    throw new Error('ES5 not supported by this JavaScript engine. ' + 'Please load the es5-shim and es5-sham library for compatibility.');
		  }
	
		  // cached factories and instances
		  var factories = [];
		  var instances = [];
	
		  // create a namespace for the mathjs instance, and attach emitter functions
		  var math = emitter.mixin({});
		  math.type = {};
		  math.expression = {
		    transform: {},
		    mathWithTransform: {}
		  };
	
		  // create a new typed instance
		  math.typed = typedFactory.create(math.type);
	
		  // create configuration options. These are private
		  var _config = {
		    // minimum relative difference between two compared values,
		    // used by all comparison functions
		    epsilon: 1e-12,
	
		    // type of default matrix output. Choose 'matrix' (default) or 'array'
		    matrix: 'Matrix',
	
		    // type of default number output. Choose 'number' (default) 'BigNumber', or 'Fraction
		    number: 'number',
	
		    // number of significant digits in BigNumbers
		    precision: 64,
	
		    // predictable output type of functions. When true, output type depends only
		    // on the input types. When false (default), output type can vary depending
		    // on input values. For example `math.sqrt(-4)` returns `complex('2i')` when
		    // predictable is false, and returns `NaN` when true.
		    predictable: false,
	
		    // random seed for seeded pseudo random number generation
		    // null = randomly seed
		    randomSeed: null
		  };
	
		  /**
		   * Load a function or data type from a factory.
		   * If the function or data type already exists, the existing instance is
		   * returned.
		   * @param {{type: string, name: string, factory: Function}} factory
		   * @returns {*}
		   */
		  function load(factory) {
		    if (!isFactory(factory)) {
		      throw new Error('Factory object with properties `type`, `name`, and `factory` expected');
		    }
	
		    var index = factories.indexOf(factory);
		    var instance;
		    if (index === -1) {
		      // doesn't yet exist
		      if (factory.math === true) {
		        // pass with math namespace
		        instance = factory.factory(math.type, _config, load, math.typed, math);
		      } else {
		        instance = factory.factory(math.type, _config, load, math.typed);
		      }
	
		      // append to the cache
		      factories.push(factory);
		      instances.push(instance);
		    } else {
		      // already existing function, return the cached instance
		      instance = instances[index];
		    }
	
		    return instance;
		  }
	
		  // load the import and config functions
		  math['import'] = load(importFactory);
		  math['config'] = load(configFactory);
		  math.expression.mathWithTransform['config'] = math['config'];
	
		  // apply options
		  if (options) {
		    math.config(options);
		  }
	
		  return math;
		};
	
	/***/ }),
	/* 14 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
	
		var isBigNumber = __webpack_require__(15);
	
		/**
		 * Clone an object
		 *
		 *     clone(x)
		 *
		 * Can clone any primitive type, array, and object.
		 * If x has a function clone, this function will be invoked to clone the object.
		 *
		 * @param {*} x
		 * @return {*} clone
		 */
		exports.clone = function clone(x) {
		  var type = typeof x === 'undefined' ? 'undefined' : _typeof(x);
	
		  // immutable primitive types
		  if (type === 'number' || type === 'string' || type === 'boolean' || x === null || x === undefined) {
		    return x;
		  }
	
		  // use clone function of the object when available
		  if (typeof x.clone === 'function') {
		    return x.clone();
		  }
	
		  // array
		  if (Array.isArray(x)) {
		    return x.map(function (value) {
		      return clone(value);
		    });
		  }
	
		  if (x instanceof Number) return new Number(x.valueOf());
		  if (x instanceof String) return new String(x.valueOf());
		  if (x instanceof Boolean) return new Boolean(x.valueOf());
		  if (x instanceof Date) return new Date(x.valueOf());
		  if (isBigNumber(x)) return x; // bignumbers are immutable
		  if (x instanceof RegExp) throw new TypeError('Cannot clone ' + x); // TODO: clone a RegExp
	
		  // object
		  return exports.map(x, clone);
		};
	
		/**
		 * Apply map to all properties of an object
		 * @param {Object} object
		 * @param {function} callback
		 * @return {Object} Returns a copy of the object with mapped properties
		 */
		exports.map = function (object, callback) {
		  var clone = {};
	
		  for (var key in object) {
		    if (exports.hasOwnProperty(object, key)) {
		      clone[key] = callback(object[key]);
		    }
		  }
	
		  return clone;
		};
	
		/**
		 * Extend object a with the properties of object b
		 * @param {Object} a
		 * @param {Object} b
		 * @return {Object} a
		 */
		exports.extend = function (a, b) {
		  for (var prop in b) {
		    if (exports.hasOwnProperty(b, prop)) {
		      a[prop] = b[prop];
		    }
		  }
		  return a;
		};
	
		/**
		 * Deep extend an object a with the properties of object b
		 * @param {Object} a
		 * @param {Object} b
		 * @returns {Object}
		 */
		exports.deepExtend = function deepExtend(a, b) {
		  // TODO: add support for Arrays to deepExtend
		  if (Array.isArray(b)) {
		    throw new TypeError('Arrays are not supported by deepExtend');
		  }
	
		  for (var prop in b) {
		    if (exports.hasOwnProperty(b, prop)) {
		      if (b[prop] && b[prop].constructor === Object) {
		        if (a[prop] === undefined) {
		          a[prop] = {};
		        }
		        if (a[prop].constructor === Object) {
		          deepExtend(a[prop], b[prop]);
		        } else {
		          a[prop] = b[prop];
		        }
		      } else if (Array.isArray(b[prop])) {
		        throw new TypeError('Arrays are not supported by deepExtend');
		      } else {
		        a[prop] = b[prop];
		      }
		    }
		  }
		  return a;
		};
	
		/**
		 * Deep test equality of all fields in two pairs of arrays or objects.
		 * @param {Array | Object} a
		 * @param {Array | Object} b
		 * @returns {boolean}
		 */
		exports.deepEqual = function deepEqual(a, b) {
		  var prop, i, len;
		  if (Array.isArray(a)) {
		    if (!Array.isArray(b)) {
		      return false;
		    }
	
		    if (a.length != b.length) {
		      return false;
		    }
	
		    for (i = 0, len = a.length; i < len; i++) {
		      if (!exports.deepEqual(a[i], b[i])) {
		        return false;
		      }
		    }
		    return true;
		  } else if (a instanceof Object) {
		    if (Array.isArray(b) || !(b instanceof Object)) {
		      return false;
		    }
	
		    for (prop in a) {
		      //noinspection JSUnfilteredForInLoop
		      if (!exports.deepEqual(a[prop], b[prop])) {
		        return false;
		      }
		    }
		    for (prop in b) {
		      //noinspection JSUnfilteredForInLoop
		      if (!exports.deepEqual(a[prop], b[prop])) {
		        return false;
		      }
		    }
		    return true;
		  } else {
		    return (typeof a === 'undefined' ? 'undefined' : _typeof(a)) === (typeof b === 'undefined' ? 'undefined' : _typeof(b)) && a == b;
		  }
		};
	
		/**
		 * Test whether the current JavaScript engine supports Object.defineProperty
		 * @returns {boolean} returns true if supported
		 */
		exports.canDefineProperty = function () {
		  // test needed for broken IE8 implementation
		  try {
		    if (Object.defineProperty) {
		      Object.defineProperty({}, 'x', { get: function get() {} });
		      return true;
		    }
		  } catch (e) {}
	
		  return false;
		};
	
		/**
		 * Attach a lazy loading property to a constant.
		 * The given function `fn` is called once when the property is first requested.
		 * On older browsers (<IE8), the function will fall back to direct evaluation
		 * of the properties value.
		 * @param {Object} object   Object where to add the property
		 * @param {string} prop     Property name
		 * @param {Function} fn     Function returning the property value. Called
		 *                          without arguments.
		 */
		exports.lazy = function (object, prop, fn) {
		  if (exports.canDefineProperty()) {
		    var _uninitialized = true;
		    var _value;
		    Object.defineProperty(object, prop, {
		      get: function get() {
		        if (_uninitialized) {
		          _value = fn();
		          _uninitialized = false;
		        }
		        return _value;
		      },
	
		      set: function set(value) {
		        _value = value;
		        _uninitialized = false;
		      },
	
		      configurable: true,
		      enumerable: true
		    });
		  } else {
		    // fall back to immediate evaluation
		    object[prop] = fn();
		  }
		};
	
		/**
		 * Traverse a path into an object.
		 * When a namespace is missing, it will be created
		 * @param {Object} object
		 * @param {string} path   A dot separated string like 'name.space'
		 * @return {Object} Returns the object at the end of the path
		 */
		exports.traverse = function (object, path) {
		  var obj = object;
	
		  if (path) {
		    var names = path.split('.');
		    for (var i = 0; i < names.length; i++) {
		      var name = names[i];
		      if (!(name in obj)) {
		        obj[name] = {};
		      }
		      obj = obj[name];
		    }
		  }
	
		  return obj;
		};
	
		/**
		 * A safe hasOwnProperty
		 * @param {Object} object
		 * @param {string} property
		 */
		exports.hasOwnProperty = function (object, property) {
		  return object && Object.hasOwnProperty.call(object, property);
		};
	
		/**
		 * Test whether an object is a factory. a factory has fields:
		 *
		 * - factory: function (type: Object, config: Object, load: function, typed: function [, math: Object])   (required)
		 * - name: string (optional)
		 * - path: string    A dot separated path (optional)
		 * - math: boolean   If true (false by default), the math namespace is passed
		 *                   as fifth argument of the factory function
		 *
		 * @param {*} object
		 * @returns {boolean}
		 */
		exports.isFactory = function (object) {
		  return object && typeof object.factory === 'function';
		};
	
	/***/ }),
	/* 15 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		/**
		 * Test whether a value is a BigNumber
		 * @param {*} x
		 * @return {boolean}
		 */
		module.exports = function isBigNumber(x) {
		  return x && x.constructor.prototype.isBigNumber || false;
		};
	
	/***/ }),
	/* 16 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
	
		var typedFunction = __webpack_require__(17);
		var digits = __webpack_require__(18).digits;
		var isBigNumber = __webpack_require__(15);
		var isMatrix = __webpack_require__(19);
	
		// returns a new instance of typed-function
		var _createTyped = function createTyped() {
		  // initially, return the original instance of typed-function
		  // consecutively, return a new instance from typed.create.
		  _createTyped = typedFunction.create;
		  return typedFunction;
		};
	
		/**
		 * Factory function for creating a new typed instance
		 * @param {Object} type   Object with data types like Complex and BigNumber
		 * @returns {Function}
		 */
		exports.create = function create(type) {
		  // TODO: typed-function must be able to silently ignore signatures with unknown data types
	
		  // type checks for all known types
		  //
		  // note that:
		  //
		  // - check by duck-typing on a property like `isUnit`, instead of checking instanceof.
		  //   instanceof cannot be used because that would not allow to pass data from
		  //   one instance of math.js to another since each has it's own instance of Unit.
		  // - check the `isUnit` property via the constructor, so there will be no
		  //   matches for "fake" instances like plain objects with a property `isUnit`.
		  //   That is important for security reasons.
		  // - It must not be possible to override the type checks used internally,
		  //   for security reasons, so these functions are not exposed in the expression
		  //   parser.
		  type.isNumber = function (x) {
		    return typeof x === 'number';
		  };
		  type.isComplex = function (x) {
		    return type.Complex && x instanceof type.Complex || false;
		  };
		  type.isBigNumber = isBigNumber;
		  type.isFraction = function (x) {
		    return type.Fraction && x instanceof type.Fraction || false;
		  };
		  type.isUnit = function (x) {
		    return x && x.constructor.prototype.isUnit || false;
		  };
		  type.isString = function (x) {
		    return typeof x === 'string';
		  };
		  type.isArray = Array.isArray;
		  type.isMatrix = isMatrix;
		  type.isDenseMatrix = function (x) {
		    return x && x.isDenseMatrix && x.constructor.prototype.isMatrix || false;
		  };
		  type.isSparseMatrix = function (x) {
		    return x && x.isSparseMatrix && x.constructor.prototype.isMatrix || false;
		  };
		  type.isRange = function (x) {
		    return x && x.constructor.prototype.isRange || false;
		  };
		  type.isIndex = function (x) {
		    return x && x.constructor.prototype.isIndex || false;
		  };
		  type.isBoolean = function (x) {
		    return typeof x === 'boolean';
		  };
		  type.isResultSet = function (x) {
		    return x && x.constructor.prototype.isResultSet || false;
		  };
		  type.isHelp = function (x) {
		    return x && x.constructor.prototype.isHelp || false;
		  };
		  type.isFunction = function (x) {
		    return typeof x === 'function';
		  };
		  type.isDate = function (x) {
		    return x instanceof Date;
		  };
		  type.isRegExp = function (x) {
		    return x instanceof RegExp;
		  };
		  type.isObject = function (x) {
		    return (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object';
		  };
		  type.isNull = function (x) {
		    return x === null;
		  };
		  type.isUndefined = function (x) {
		    return x === undefined;
		  };
	
		  type.isAccessorNode = function (x) {
		    return x && x.isAccessorNode && x.constructor.prototype.isNode || false;
		  };
		  type.isArrayNode = function (x) {
		    return x && x.isArrayNode && x.constructor.prototype.isNode || false;
		  };
		  type.isAssignmentNode = function (x) {
		    return x && x.isAssignmentNode && x.constructor.prototype.isNode || false;
		  };
		  type.isBlockNode = function (x) {
		    return x && x.isBlockNode && x.constructor.prototype.isNode || false;
		  };
		  type.isConditionalNode = function (x) {
		    return x && x.isConditionalNode && x.constructor.prototype.isNode || false;
		  };
		  type.isConstantNode = function (x) {
		    return x && x.isConstantNode && x.constructor.prototype.isNode || false;
		  };
		  type.isFunctionAssignmentNode = function (x) {
		    return x && x.isFunctionAssignmentNode && x.constructor.prototype.isNode || false;
		  };
		  type.isFunctionNode = function (x) {
		    return x && x.isFunctionNode && x.constructor.prototype.isNode || false;
		  };
		  type.isIndexNode = function (x) {
		    return x && x.isIndexNode && x.constructor.prototype.isNode || false;
		  };
		  type.isNode = function (x) {
		    return x && x.isNode && x.constructor.prototype.isNode || false;
		  };
		  type.isObjectNode = function (x) {
		    return x && x.isObjectNode && x.constructor.prototype.isNode || false;
		  };
		  type.isOperatorNode = function (x) {
		    return x && x.isOperatorNode && x.constructor.prototype.isNode || false;
		  };
		  type.isParenthesisNode = function (x) {
		    return x && x.isParenthesisNode && x.constructor.prototype.isNode || false;
		  };
		  type.isRangeNode = function (x) {
		    return x && x.isRangeNode && x.constructor.prototype.isNode || false;
		  };
		  type.isSymbolNode = function (x) {
		    return x && x.isSymbolNode && x.constructor.prototype.isNode || false;
		  };
	
		  type.isChain = function (x) {
		    return x && x.constructor.prototype.isChain || false;
		  };
	
		  // get a new instance of typed-function
		  var typed = _createTyped();
	
		  // define all types. The order of the types determines in which order function
		  // arguments are type-checked (so for performance it's important to put the
		  // most used types first).
		  typed.types = [{ name: 'number', test: type.isNumber }, { name: 'Complex', test: type.isComplex }, { name: 'BigNumber', test: type.isBigNumber }, { name: 'Fraction', test: type.isFraction }, { name: 'Unit', test: type.isUnit }, { name: 'string', test: type.isString }, { name: 'Array', test: type.isArray }, { name: 'Matrix', test: type.isMatrix }, { name: 'DenseMatrix', test: type.isDenseMatrix }, { name: 'SparseMatrix', test: type.isSparseMatrix }, { name: 'Range', test: type.isRange }, { name: 'Index', test: type.isIndex }, { name: 'boolean', test: type.isBoolean }, { name: 'ResultSet', test: type.isResultSet }, { name: 'Help', test: type.isHelp }, { name: 'function', test: type.isFunction }, { name: 'Date', test: type.isDate }, { name: 'RegExp', test: type.isRegExp }, { name: 'Object', test: type.isObject }, { name: 'null', test: type.isNull }, { name: 'undefined', test: type.isUndefined }, { name: 'OperatorNode', test: type.isOperatorNode }, { name: 'ConstantNode', test: type.isConstantNode }, { name: 'SymbolNode', test: type.isSymbolNode }, { name: 'ParenthesisNode', test: type.isParenthesisNode }, { name: 'FunctionNode', test: type.isFunctionNode }, { name: 'FunctionAssignmentNode', test: type.isFunctionAssignmentNode }, { name: 'ArrayNode', test: type.isArrayNode }, { name: 'AssignmentNode', test: type.isAssignmentNode }, { name: 'BlockNode', test: type.isBlockNode }, { name: 'ConditionalNode', test: type.isConditionalNode }, { name: 'IndexNode', test: type.isIndexNode }, { name: 'RangeNode', test: type.isRangeNode }, { name: 'Node', test: type.isNode }];
	
		  // TODO: add conversion from BigNumber to number?
		  typed.conversions = [{
		    from: 'number',
		    to: 'BigNumber',
		    convert: function convert(x) {
		      // note: conversion from number to BigNumber can fail if x has >15 digits
		      if (digits(x) > 15) {
		        throw new TypeError('Cannot implicitly convert a number with >15 significant digits to BigNumber ' + '(value: ' + x + '). ' + 'Use function bignumber(x) to convert to BigNumber.');
		      }
		      return new type.BigNumber(x);
		    }
		  }, {
		    from: 'number',
		    to: 'Complex',
		    convert: function convert(x) {
		      return new type.Complex(x, 0);
		    }
		  }, {
		    from: 'number',
		    to: 'string',
		    convert: function convert(x) {
		      return x + '';
		    }
		  }, {
		    from: 'BigNumber',
		    to: 'Complex',
		    convert: function convert(x) {
		      return new type.Complex(x.toNumber(), 0);
		    }
		  }, {
		    from: 'Fraction',
		    to: 'BigNumber',
		    convert: function convert(x) {
		      throw new TypeError('Cannot implicitly convert a Fraction to BigNumber or vice versa. ' + 'Use function bignumber(x) to convert to BigNumber or fraction(x) to convert to Fraction.');
		    }
		  }, {
		    from: 'Fraction',
		    to: 'Complex',
		    convert: function convert(x) {
		      return new type.Complex(x.valueOf(), 0);
		    }
		  }, {
		    from: 'number',
		    to: 'Fraction',
		    convert: function convert(x) {
		      var f = new type.Fraction(x);
		      if (f.valueOf() !== x) {
		        throw new TypeError('Cannot implicitly convert a number to a Fraction when there will be a loss of precision ' + '(value: ' + x + '). ' + 'Use function fraction(x) to convert to Fraction.');
		      }
		      return new type.Fraction(x);
		    }
		  }, {
		    // FIXME: add conversion from Fraction to number, for example for `sqrt(fraction(1,3))`
		    //  from: 'Fraction',
		    //  to: 'number',
		    //  convert: function (x) {
		    //    return x.valueOf();
		    //  }
		    //}, {
		    from: 'string',
		    to: 'number',
		    convert: function convert(x) {
		      var n = Number(x);
		      if (isNaN(n)) {
		        throw new Error('Cannot convert "' + x + '" to a number');
		      }
		      return n;
		    }
		  }, {
		    from: 'string',
		    to: 'BigNumber',
		    convert: function convert(x) {
		      try {
		        return new type.BigNumber(x);
		      } catch (err) {
		        throw new Error('Cannot convert "' + x + '" to BigNumber');
		      }
		    }
		  }, {
		    from: 'string',
		    to: 'Fraction',
		    convert: function convert(x) {
		      try {
		        return new type.Fraction(x);
		      } catch (err) {
		        throw new Error('Cannot convert "' + x + '" to Fraction');
		      }
		    }
		  }, {
		    from: 'string',
		    to: 'Complex',
		    convert: function convert(x) {
		      try {
		        return new type.Complex(x);
		      } catch (err) {
		        throw new Error('Cannot convert "' + x + '" to Complex');
		      }
		    }
		  }, {
		    from: 'boolean',
		    to: 'number',
		    convert: function convert(x) {
		      return +x;
		    }
		  }, {
		    from: 'boolean',
		    to: 'BigNumber',
		    convert: function convert(x) {
		      return new type.BigNumber(+x);
		    }
		  }, {
		    from: 'boolean',
		    to: 'Fraction',
		    convert: function convert(x) {
		      return new type.Fraction(+x);
		    }
		  }, {
		    from: 'boolean',
		    to: 'string',
		    convert: function convert(x) {
		      return +x;
		    }
		  }, {
		    from: 'null',
		    to: 'number',
		    convert: function convert() {
		      return 0;
		    }
		  }, {
		    from: 'null',
		    to: 'string',
		    convert: function convert() {
		      return 'null';
		    }
		  }, {
		    from: 'null',
		    to: 'BigNumber',
		    convert: function convert() {
		      return new type.BigNumber(0);
		    }
		  }, {
		    from: 'null',
		    to: 'Fraction',
		    convert: function convert() {
		      return new type.Fraction(0);
		    }
		  }, {
		    from: 'Array',
		    to: 'Matrix',
		    convert: function convert(array) {
		      // TODO: how to decide on the right type of matrix to create?
		      return new type.DenseMatrix(array);
		    }
		  }, {
		    from: 'Matrix',
		    to: 'Array',
		    convert: function convert(matrix) {
		      return matrix.valueOf();
		    }
		  }];
	
		  return typed;
		};
	
	/***/ }),
	/* 17 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/**
		 * typed-function
		 *
		 * Type checking for JavaScript functions
		 *
		 * https://github.com/josdejong/typed-function
		 */
		'use strict';
	
		var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
	
		(function (root, factory) {
		  if (true) {
		    // AMD. Register as an anonymous module.
		    !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
		  } else if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
		    // OldNode. Does not work with strict CommonJS, but
		    // only CommonJS-like environments that support module.exports,
		    // like OldNode.
		    module.exports = factory();
		  } else {
		    // Browser globals (root is window)
		    root.typed = factory();
		  }
		})(undefined, function () {
		  // factory function to create a new instance of typed-function
		  // TODO: allow passing configuration, types, tests via the factory function
		  function create() {
		    /**
		     * Get a type test function for a specific data type
		     * @param {string} name                   Name of a data type like 'number' or 'string'
		     * @returns {Function(obj: *) : boolean}  Returns a type testing function.
		     *                                        Throws an error for an unknown type.
		     */
		    function getTypeTest(name) {
		      var test;
		      for (var i = 0; i < typed.types.length; i++) {
		        var entry = typed.types[i];
		        if (entry.name === name) {
		          test = entry.test;
		          break;
		        }
		      }
	
		      if (!test) {
		        var hint;
		        for (i = 0; i < typed.types.length; i++) {
		          entry = typed.types[i];
		          if (entry.name.toLowerCase() == name.toLowerCase()) {
		            hint = entry.name;
		            break;
		          }
		        }
	
		        throw new Error('Unknown type "' + name + '"' + (hint ? '. Did you mean "' + hint + '"?' : ''));
		      }
		      return test;
		    }
	
		    /**
		     * Retrieve the function name from a set of functions, and check
		     * whether the name of all functions match (if given)
		     * @param {Array.<function>} fns
		     */
		    function getName(fns) {
		      var name = '';
	
		      for (var i = 0; i < fns.length; i++) {
		        var fn = fns[i];
	
		        // merge function name when this is a typed function
		        if (fn.signatures && fn.name != '') {
		          if (name == '') {
		            name = fn.name;
		          } else if (name != fn.name) {
		            var err = new Error('Function names do not match (expected: ' + name + ', actual: ' + fn.name + ')');
		            err.data = {
		              actual: fn.name,
		              expected: name
		            };
		            throw err;
		          }
		        }
		      }
	
		      return name;
		    }
	
		    /**
		     * Create an ArgumentsError. Creates messages like:
		     *
		     *   Unexpected type of argument (expected: ..., actual: ..., index: ...)
		     *   Too few arguments (expected: ..., index: ...)
		     *   Too many arguments (expected: ..., actual: ...)
		     *
		     * @param {String} fn         Function name
		     * @param {number} argCount   Number of arguments
		     * @param {Number} index      Current argument index
		     * @param {*} actual          Current argument
		     * @param {string} [expected] An optional, comma separated string with
		     *                            expected types on given index
		     * @extends Error
		     */
		    function createError(fn, argCount, index, actual, expected) {
		      var actualType = getTypeOf(actual);
		      var _expected = expected ? expected.split(',') : null;
		      var _fn = fn || 'unnamed';
		      var anyType = _expected && contains(_expected, 'any');
		      var message;
		      var data = {
		        fn: fn,
		        index: index,
		        actual: actual,
		        expected: _expected
		      };
	
		      if (_expected) {
		        if (argCount > index && !anyType) {
		          // unexpected type
		          message = 'Unexpected type of argument in function ' + _fn + ' (expected: ' + _expected.join(' or ') + ', actual: ' + actualType + ', index: ' + index + ')';
		        } else {
		          // too few arguments
		          message = 'Too few arguments in function ' + _fn + ' (expected: ' + _expected.join(' or ') + ', index: ' + index + ')';
		        }
		      } else {
		        // too many arguments
		        message = 'Too many arguments in function ' + _fn + ' (expected: ' + index + ', actual: ' + argCount + ')';
		      }
	
		      var err = new TypeError(message);
		      err.data = data;
		      return err;
		    }
	
		    /**
		     * Collection with function references (local shortcuts to functions)
		     * @constructor
		     * @param {string} [name='refs']  Optional name for the refs, used to generate
		     *                                JavaScript code
		     */
		    function Refs(name) {
		      this.name = name || 'refs';
		      this.categories = {};
		    }
	
		    /**
		     * Add a function reference.
		     * @param {Function} fn
		     * @param {string} [category='fn']    A function category, like 'fn' or 'signature'
		     * @returns {string} Returns the function name, for example 'fn0' or 'signature2'
		     */
		    Refs.prototype.add = function (fn, category) {
		      var cat = category || 'fn';
		      if (!this.categories[cat]) this.categories[cat] = [];
	
		      var index = this.categories[cat].indexOf(fn);
		      if (index == -1) {
		        index = this.categories[cat].length;
		        this.categories[cat].push(fn);
		      }
	
		      return cat + index;
		    };
	
		    /**
		     * Create code lines for all function references
		     * @returns {string} Returns the code containing all function references
		     */
		    Refs.prototype.toCode = function () {
		      var code = [];
		      var path = this.name + '.categories';
		      var categories = this.categories;
	
		      for (var cat in categories) {
		        if (categories.hasOwnProperty(cat)) {
		          var category = categories[cat];
	
		          for (var i = 0; i < category.length; i++) {
		            code.push('var ' + cat + i + ' = ' + path + '[\'' + cat + '\'][' + i + '];');
		          }
		        }
		      }
	
		      return code.join('\n');
		    };
	
		    /**
		     * A function parameter
		     * @param {string | string[] | Param} types    A parameter type like 'string',
		     *                                             'number | boolean'
		     * @param {boolean} [varArgs=false]            Variable arguments if true
		     * @constructor
		     */
		    function Param(types, varArgs) {
		      // parse the types, can be a string with types separated by pipe characters |
		      if (typeof types === 'string') {
		        // parse variable arguments operator (ellipses '...number')
		        var _types = types.trim();
		        var _varArgs = _types.substr(0, 3) === '...';
		        if (_varArgs) {
		          _types = _types.substr(3);
		        }
		        if (_types === '') {
		          this.types = ['any'];
		        } else {
		          this.types = _types.split('|');
		          for (var i = 0; i < this.types.length; i++) {
		            this.types[i] = this.types[i].trim();
		          }
		        }
		      } else if (Array.isArray(types)) {
		        this.types = types;
		      } else if (types instanceof Param) {
		        return types.clone();
		      } else {
		        throw new Error('String or Array expected');
		      }
	
		      // can hold a type to which to convert when handling this parameter
		      this.conversions = [];
		      // TODO: implement better API for conversions, be able to add conversions via constructor (support a new type Object?)
	
		      // variable arguments
		      this.varArgs = _varArgs || varArgs || false;
	
		      // check for any type arguments
		      this.anyType = this.types.indexOf('any') !== -1;
		    }
	
		    /**
		     * Order Params
		     * any type ('any') will be ordered last, and object as second last (as other
		     * types may be an object as well, like Array).
		     *
		     * @param {Param} a
		     * @param {Param} b
		     * @returns {number} Returns 1 if a > b, -1 if a < b, and else 0.
		     */
		    Param.compare = function (a, b) {
		      // TODO: simplify parameter comparison, it's a mess
		      if (a.anyType) return 1;
		      if (b.anyType) return -1;
	
		      if (contains(a.types, 'Object')) return 1;
		      if (contains(b.types, 'Object')) return -1;
	
		      if (a.hasConversions()) {
		        if (b.hasConversions()) {
		          var i, ac, bc;
	
		          for (i = 0; i < a.conversions.length; i++) {
		            if (a.conversions[i] !== undefined) {
		              ac = a.conversions[i];
		              break;
		            }
		          }
	
		          for (i = 0; i < b.conversions.length; i++) {
		            if (b.conversions[i] !== undefined) {
		              bc = b.conversions[i];
		              break;
		            }
		          }
	
		          return typed.conversions.indexOf(ac) - typed.conversions.indexOf(bc);
		        } else {
		          return 1;
		        }
		      } else {
		        if (b.hasConversions()) {
		          return -1;
		        } else {
		          // both params have no conversions
		          var ai, bi;
	
		          for (i = 0; i < typed.types.length; i++) {
		            if (typed.types[i].name === a.types[0]) {
		              ai = i;
		              break;
		            }
		          }
	
		          for (i = 0; i < typed.types.length; i++) {
		            if (typed.types[i].name === b.types[0]) {
		              bi = i;
		              break;
		            }
		          }
	
		          return ai - bi;
		        }
		      }
		    };
	
		    /**
		     * Test whether this parameters types overlap an other parameters types.
		     * Will not match ['any'] with ['number']
		     * @param {Param} other
		     * @return {boolean} Returns true when there are overlapping types
		     */
		    Param.prototype.overlapping = function (other) {
		      for (var i = 0; i < this.types.length; i++) {
		        if (contains(other.types, this.types[i])) {
		          return true;
		        }
		      }
		      return false;
		    };
	
		    /**
		     * Test whether this parameters types matches an other parameters types.
		     * When any of the two parameters contains `any`, true is returned
		     * @param {Param} other
		     * @return {boolean} Returns true when there are matching types
		     */
		    Param.prototype.matches = function (other) {
		      return this.anyType || other.anyType || this.overlapping(other);
		    };
	
		    /**
		     * Create a clone of this param
		     * @returns {Param} Returns a cloned version of this param
		     */
		    Param.prototype.clone = function () {
		      var param = new Param(this.types.slice(), this.varArgs);
		      param.conversions = this.conversions.slice();
		      return param;
		    };
	
		    /**
		     * Test whether this parameter contains conversions
		     * @returns {boolean} Returns true if the parameter contains one or
		     *                    multiple conversions.
		     */
		    Param.prototype.hasConversions = function () {
		      return this.conversions.length > 0;
		    };
	
		    /**
		     * Tests whether this parameters contains any of the provided types
		     * @param {Object} types  A Map with types, like {'number': true}
		     * @returns {boolean}     Returns true when the parameter contains any
		     *                        of the provided types
		     */
		    Param.prototype.contains = function (types) {
		      for (var i = 0; i < this.types.length; i++) {
		        if (types[this.types[i]]) {
		          return true;
		        }
		      }
		      return false;
		    };
	
		    /**
		     * Return a string representation of this params types, like 'string' or
		     * 'number | boolean' or '...number'
		     * @param {boolean} [toConversion]   If true, the returned types string
		     *                                   contains the types where the parameter
		     *                                   will convert to. If false (default)
		     *                                   the "from" types are returned
		     * @returns {string}
		     */
		    Param.prototype.toString = function (toConversion) {
		      var types = [];
		      var keys = {};
	
		      for (var i = 0; i < this.types.length; i++) {
		        var conversion = this.conversions[i];
		        var type = toConversion && conversion ? conversion.to : this.types[i];
		        if (!(type in keys)) {
		          keys[type] = true;
		          types.push(type);
		        }
		      }
	
		      return (this.varArgs ? '...' : '') + types.join('|');
		    };
	
		    /**
		     * A function signature
		     * @param {string | string[] | Param[]} params
		     *                         Array with the type(s) of each parameter,
		     *                         or a comma separated string with types
		     * @param {Function} fn    The actual function
		     * @constructor
		     */
		    function Signature(params, fn) {
		      var _params;
		      if (typeof params === 'string') {
		        _params = params !== '' ? params.split(',') : [];
		      } else if (Array.isArray(params)) {
		        _params = params;
		      } else {
		        throw new Error('string or Array expected');
		      }
	
		      this.params = new Array(_params.length);
		      this.anyType = false;
		      this.varArgs = false;
		      for (var i = 0; i < _params.length; i++) {
		        var param = new Param(_params[i]);
		        this.params[i] = param;
		        if (param.anyType) {
		          this.anyType = true;
		        }
		        if (i === _params.length - 1) {
		          // the last argument
		          this.varArgs = param.varArgs;
		        } else {
		          // non-last argument
		          if (param.varArgs) {
		            throw new SyntaxError('Unexpected variable arguments operator "..."');
		          }
		        }
		      }
	
		      this.fn = fn;
		    }
	
		    /**
		     * Create a clone of this signature
		     * @returns {Signature} Returns a cloned version of this signature
		     */
		    Signature.prototype.clone = function () {
		      return new Signature(this.params.slice(), this.fn);
		    };
	
		    /**
		     * Expand a signature: split params with union types in separate signatures
		     * For example split a Signature "string | number" into two signatures.
		     * @return {Signature[]} Returns an array with signatures (at least one)
		     */
		    Signature.prototype.expand = function () {
		      var signatures = [];
	
		      function recurse(signature, path) {
		        if (path.length < signature.params.length) {
		          var i, newParam, conversion;
	
		          var param = signature.params[path.length];
		          if (param.varArgs) {
		            // a variable argument. do not split the types in the parameter
		            newParam = param.clone();
	
		            // add conversions to the parameter
		            // recurse for all conversions
		            for (i = 0; i < typed.conversions.length; i++) {
		              conversion = typed.conversions[i];
		              if (!contains(param.types, conversion.from) && contains(param.types, conversion.to)) {
		                var j = newParam.types.length;
		                newParam.types[j] = conversion.from;
		                newParam.conversions[j] = conversion;
		              }
		            }
	
		            recurse(signature, path.concat(newParam));
		          } else {
		            // split each type in the parameter
		            for (i = 0; i < param.types.length; i++) {
		              recurse(signature, path.concat(new Param(param.types[i])));
		            }
	
		            // recurse for all conversions
		            for (i = 0; i < typed.conversions.length; i++) {
		              conversion = typed.conversions[i];
		              if (!contains(param.types, conversion.from) && contains(param.types, conversion.to)) {
		                newParam = new Param(conversion.from);
		                newParam.conversions[0] = conversion;
		                recurse(signature, path.concat(newParam));
		              }
		            }
		          }
		        } else {
		          signatures.push(new Signature(path, signature.fn));
		        }
		      }
	
		      recurse(this, []);
	
		      return signatures;
		    };
	
		    /**
		     * Compare two signatures.
		     *
		     * When two params are equal and contain conversions, they will be sorted
		     * by lowest index of the first conversions.
		     *
		     * @param {Signature} a
		     * @param {Signature} b
		     * @returns {number} Returns 1 if a > b, -1 if a < b, and else 0.
		     */
		    Signature.compare = function (a, b) {
		      if (a.params.length > b.params.length) return 1;
		      if (a.params.length < b.params.length) return -1;
	
		      // count the number of conversions
		      var i;
		      var len = a.params.length; // a and b have equal amount of params
		      var ac = 0;
		      var bc = 0;
		      for (i = 0; i < len; i++) {
		        if (a.params[i].hasConversions()) ac++;
		        if (b.params[i].hasConversions()) bc++;
		      }
	
		      if (ac > bc) return 1;
		      if (ac < bc) return -1;
	
		      // compare the order per parameter
		      for (i = 0; i < a.params.length; i++) {
		        var cmp = Param.compare(a.params[i], b.params[i]);
		        if (cmp !== 0) {
		          return cmp;
		        }
		      }
	
		      return 0;
		    };
	
		    /**
		     * Test whether any of the signatures parameters has conversions
		     * @return {boolean} Returns true when any of the parameters contains
		     *                   conversions.
		     */
		    Signature.prototype.hasConversions = function () {
		      for (var i = 0; i < this.params.length; i++) {
		        if (this.params[i].hasConversions()) {
		          return true;
		        }
		      }
		      return false;
		    };
	
		    /**
		     * Test whether this signature should be ignored.
		     * Checks whether any of the parameters contains a type listed in
		     * typed.ignore
		     * @return {boolean} Returns true when the signature should be ignored
		     */
		    Signature.prototype.ignore = function () {
		      // create a map with ignored types
		      var types = {};
		      for (var i = 0; i < typed.ignore.length; i++) {
		        types[typed.ignore[i]] = true;
		      }
	
		      // test whether any of the parameters contains this type
		      for (i = 0; i < this.params.length; i++) {
		        if (this.params[i].contains(types)) {
		          return true;
		        }
		      }
	
		      return false;
		    };
	
		    /**
		     * Test whether the path of this signature matches a given path.
		     * @param {Param[]} params
		     */
		    Signature.prototype.paramsStartWith = function (params) {
		      if (params.length === 0) {
		        return true;
		      }
	
		      var aLast = last(this.params);
		      var bLast = last(params);
	
		      for (var i = 0; i < params.length; i++) {
		        var a = this.params[i] || (aLast.varArgs ? aLast : null);
		        var b = params[i] || (bLast.varArgs ? bLast : null);
	
		        if (!a || !b || !a.matches(b)) {
		          return false;
		        }
		      }
	
		      return true;
		    };
	
		    /**
		     * Generate the code to invoke this signature
		     * @param {Refs} refs
		     * @param {string} prefix
		     * @returns {string} Returns code
		     */
		    Signature.prototype.toCode = function (refs, prefix) {
		      var code = [];
	
		      var args = new Array(this.params.length);
		      for (var i = 0; i < this.params.length; i++) {
		        var param = this.params[i];
		        var conversion = param.conversions[0];
		        if (param.varArgs) {
		          args[i] = 'varArgs';
		        } else if (conversion) {
		          args[i] = refs.add(conversion.convert, 'convert') + '(arg' + i + ')';
		        } else {
		          args[i] = 'arg' + i;
		        }
		      }
	
		      var ref = this.fn ? refs.add(this.fn, 'signature') : undefined;
		      if (ref) {
		        return prefix + 'return ' + ref + '(' + args.join(', ') + '); // signature: ' + this.params.join(', ');
		      }
	
		      return code.join('\n');
		    };
	
		    /**
		     * Return a string representation of the signature
		     * @returns {string}
		     */
		    Signature.prototype.toString = function () {
		      return this.params.join(', ');
		    };
	
		    /**
		     * A group of signatures with the same parameter on given index
		     * @param {Param[]} path
		     * @param {Signature} [signature]
		     * @param {Node[]} childs
		     * @param {boolean} [fallThrough=false]
		     * @constructor
		     */
		    function Node(path, signature, childs, fallThrough) {
		      this.path = path || [];
		      this.param = path[path.length - 1] || null;
		      this.signature = signature || null;
		      this.childs = childs || [];
		      this.fallThrough = fallThrough || false;
		    }
	
		    /**
		     * Generate code for this group of signatures
		     * @param {Refs} refs
		     * @param {string} prefix
		     * @returns {string} Returns the code as string
		     */
		    Node.prototype.toCode = function (refs, prefix) {
		      // TODO: split this function in multiple functions, it's too large
		      var code = [];
	
		      if (this.param) {
		        var index = this.path.length - 1;
		        var conversion = this.param.conversions[0];
		        var comment = '// type: ' + (conversion ? conversion.from + ' (convert to ' + conversion.to + ')' : this.param);
	
		        // non-root node (path is non-empty)
		        if (this.param.varArgs) {
		          if (this.param.anyType) {
		            // variable arguments with any type
		            code.push(prefix + 'if (arguments.length > ' + index + ') {');
		            code.push(prefix + '  var varArgs = [];');
		            code.push(prefix + '  for (var i = ' + index + '; i < arguments.length; i++) {');
		            code.push(prefix + '    varArgs.push(arguments[i]);');
		            code.push(prefix + '  }');
		            code.push(this.signature.toCode(refs, prefix + '  '));
		            code.push(prefix + '}');
		          } else {
		            // variable arguments with a fixed type
		            var getTests = function (types, arg) {
		              var tests = [];
		              for (var i = 0; i < types.length; i++) {
		                tests[i] = refs.add(getTypeTest(types[i]), 'test') + '(' + arg + ')';
		              }
		              return tests.join(' || ');
		            }.bind(this);
	
		            var allTypes = this.param.types;
		            var exactTypes = [];
		            for (var i = 0; i < allTypes.length; i++) {
		              if (this.param.conversions[i] === undefined) {
		                exactTypes.push(allTypes[i]);
		              }
		            }
	
		            code.push(prefix + 'if (' + getTests(allTypes, 'arg' + index) + ') { ' + comment);
		            code.push(prefix + '  var varArgs = [arg' + index + '];');
		            code.push(prefix + '  for (var i = ' + (index + 1) + '; i < arguments.length; i++) {');
		            code.push(prefix + '    if (' + getTests(exactTypes, 'arguments[i]') + ') {');
		            code.push(prefix + '      varArgs.push(arguments[i]);');
	
		            for (var i = 0; i < allTypes.length; i++) {
		              var conversion_i = this.param.conversions[i];
		              if (conversion_i) {
		                var test = refs.add(getTypeTest(allTypes[i]), 'test');
		                var convert = refs.add(conversion_i.convert, 'convert');
		                code.push(prefix + '    }');
		                code.push(prefix + '    else if (' + test + '(arguments[i])) {');
		                code.push(prefix + '      varArgs.push(' + convert + '(arguments[i]));');
		              }
		            }
		            code.push(prefix + '    } else {');
		            code.push(prefix + '      throw createError(name, arguments.length, i, arguments[i], \'' + exactTypes.join(',') + '\');');
		            code.push(prefix + '    }');
		            code.push(prefix + '  }');
		            code.push(this.signature.toCode(refs, prefix + '  '));
		            code.push(prefix + '}');
		          }
		        } else {
		          if (this.param.anyType) {
		            // any type
		            code.push(prefix + '// type: any');
		            code.push(this._innerCode(refs, prefix));
		          } else {
		            // regular type
		            var type = this.param.types[0];
		            var test = type !== 'any' ? refs.add(getTypeTest(type), 'test') : null;
	
		            code.push(prefix + 'if (' + test + '(arg' + index + ')) { ' + comment);
		            code.push(this._innerCode(refs, prefix + '  '));
		            code.push(prefix + '}');
		          }
		        }
		      } else {
		        // root node (path is empty)
		        code.push(this._innerCode(refs, prefix));
		      }
	
		      return code.join('\n');
		    };
	
		    /**
		     * Generate inner code for this group of signatures.
		     * This is a helper function of Node.prototype.toCode
		     * @param {Refs} refs
		     * @param {string} prefix
		     * @returns {string} Returns the inner code as string
		     * @private
		     */
		    Node.prototype._innerCode = function (refs, prefix) {
		      var code = [];
		      var i;
	
		      if (this.signature) {
		        code.push(prefix + 'if (arguments.length === ' + this.path.length + ') {');
		        code.push(this.signature.toCode(refs, prefix + '  '));
		        code.push(prefix + '}');
		      }
	
		      for (i = 0; i < this.childs.length; i++) {
		        code.push(this.childs[i].toCode(refs, prefix));
		      }
	
		      // TODO: shouldn't the this.param.anyType check be redundant
		      if (!this.fallThrough || this.param && this.param.anyType) {
		        var exceptions = this._exceptions(refs, prefix);
		        if (exceptions) {
		          code.push(exceptions);
		        }
		      }
	
		      return code.join('\n');
		    };
	
		    /**
		     * Generate code to throw exceptions
		     * @param {Refs} refs
		     * @param {string} prefix
		     * @returns {string} Returns the inner code as string
		     * @private
		     */
		    Node.prototype._exceptions = function (refs, prefix) {
		      var index = this.path.length;
	
		      if (this.childs.length === 0) {
		        // TODO: can this condition be simplified? (we have a fall-through here)
		        return [prefix + 'if (arguments.length > ' + index + ') {', prefix + '  throw createError(name, arguments.length, ' + index + ', arguments[' + index + ']);', prefix + '}'].join('\n');
		      } else {
		        var keys = {};
		        var types = [];
	
		        for (var i = 0; i < this.childs.length; i++) {
		          var node = this.childs[i];
		          if (node.param) {
		            for (var j = 0; j < node.param.types.length; j++) {
		              var type = node.param.types[j];
		              if (!(type in keys) && !node.param.conversions[j]) {
		                keys[type] = true;
		                types.push(type);
		              }
		            }
		          }
		        }
	
		        return prefix + 'throw createError(name, arguments.length, ' + index + ', arguments[' + index + '], \'' + types.join(',') + '\');';
		      }
		    };
	
		    /**
		     * Split all raw signatures into an array with expanded Signatures
		     * @param {Object.<string, Function>} rawSignatures
		     * @return {Signature[]} Returns an array with expanded signatures
		     */
		    function parseSignatures(rawSignatures) {
		      // FIXME: need to have deterministic ordering of signatures, do not create via object
		      var signature;
		      var keys = {};
		      var signatures = [];
		      var i;
	
		      for (var types in rawSignatures) {
		        if (rawSignatures.hasOwnProperty(types)) {
		          var fn = rawSignatures[types];
		          signature = new Signature(types, fn);
	
		          if (signature.ignore()) {
		            continue;
		          }
	
		          var expanded = signature.expand();
	
		          for (i = 0; i < expanded.length; i++) {
		            var signature_i = expanded[i];
		            var key = signature_i.toString();
		            var existing = keys[key];
		            if (!existing) {
		              keys[key] = signature_i;
		            } else {
		              var cmp = Signature.compare(signature_i, existing);
		              if (cmp < 0) {
		                // override if sorted first
		                keys[key] = signature_i;
		              } else if (cmp === 0) {
		                throw new Error('Signature "' + key + '" is defined twice');
		              }
		              // else: just ignore
		            }
		          }
		        }
		      }
	
		      // convert from map to array
		      for (key in keys) {
		        if (keys.hasOwnProperty(key)) {
		          signatures.push(keys[key]);
		        }
		      }
	
		      // order the signatures
		      signatures.sort(function (a, b) {
		        return Signature.compare(a, b);
		      });
	
		      // filter redundant conversions from signatures with varArgs
		      // TODO: simplify this loop or move it to a separate function
		      for (i = 0; i < signatures.length; i++) {
		        signature = signatures[i];
	
		        if (signature.varArgs) {
		          var index = signature.params.length - 1;
		          var param = signature.params[index];
	
		          var t = 0;
		          while (t < param.types.length) {
		            if (param.conversions[t]) {
		              var type = param.types[t];
	
		              for (var j = 0; j < signatures.length; j++) {
		                var other = signatures[j];
		                var p = other.params[index];
	
		                if (other !== signature && p && contains(p.types, type) && !p.conversions[index]) {
		                  // this (conversion) type already exists, remove it
		                  param.types.splice(t, 1);
		                  param.conversions.splice(t, 1);
		                  t--;
		                  break;
		                }
		              }
		            }
		            t++;
		          }
		        }
		      }
	
		      return signatures;
		    }
	
		    /**
		     * Filter all any type signatures
		     * @param {Signature[]} signatures
		     * @return {Signature[]} Returns only any type signatures
		     */
		    function filterAnyTypeSignatures(signatures) {
		      var filtered = [];
	
		      for (var i = 0; i < signatures.length; i++) {
		        if (signatures[i].anyType) {
		          filtered.push(signatures[i]);
		        }
		      }
	
		      return filtered;
		    }
	
		    /**
		     * create a map with normalized signatures as key and the function as value
		     * @param {Signature[]} signatures   An array with split signatures
		     * @return {Object.<string, Function>} Returns a map with normalized
		     *                                     signatures as key, and the function
		     *                                     as value.
		     */
		    function mapSignatures(signatures) {
		      var normalized = {};
	
		      for (var i = 0; i < signatures.length; i++) {
		        var signature = signatures[i];
		        if (signature.fn && !signature.hasConversions()) {
		          var params = signature.params.join(',');
		          normalized[params] = signature.fn;
		        }
		      }
	
		      return normalized;
		    }
	
		    /**
		     * Parse signatures recursively in a node tree.
		     * @param {Signature[]} signatures  Array with expanded signatures
		     * @param {Param[]} path            Traversed path of parameter types
		     * @param {Signature[]} anys
		     * @return {Node}                   Returns a node tree
		     */
		    function parseTree(signatures, path, anys) {
		      var i, signature;
		      var index = path.length;
		      var nodeSignature;
	
		      var filtered = [];
		      for (i = 0; i < signatures.length; i++) {
		        signature = signatures[i];
	
		        // filter the first signature with the correct number of params
		        if (signature.params.length === index && !nodeSignature) {
		          nodeSignature = signature;
		        }
	
		        if (signature.params[index] != undefined) {
		          filtered.push(signature);
		        }
		      }
	
		      // sort the filtered signatures by param
		      filtered.sort(function (a, b) {
		        return Param.compare(a.params[index], b.params[index]);
		      });
	
		      // recurse over the signatures
		      var entries = [];
		      for (i = 0; i < filtered.length; i++) {
		        signature = filtered[i];
		        // group signatures with the same param at current index
		        var param = signature.params[index];
	
		        // TODO: replace the next filter loop
		        var existing = entries.filter(function (entry) {
		          return entry.param.overlapping(param);
		        })[0];
	
		        //var existing;
		        //for (var j = 0; j < entries.length; j++) {
		        //  if (entries[j].param.overlapping(param)) {
		        //    existing = entries[j];
		        //    break;
		        //  }
		        //}
	
		        if (existing) {
		          if (existing.param.varArgs) {
		            throw new Error('Conflicting types "' + existing.param + '" and "' + param + '"');
		          }
		          existing.signatures.push(signature);
		        } else {
		          entries.push({
		            param: param,
		            signatures: [signature]
		          });
		        }
		      }
	
		      // find all any type signature that can still match our current path
		      var matchingAnys = [];
		      for (i = 0; i < anys.length; i++) {
		        if (anys[i].paramsStartWith(path)) {
		          matchingAnys.push(anys[i]);
		        }
		      }
	
		      // see if there are any type signatures that don't match any of the
		      // signatures that we have in our tree, i.e. we have alternative
		      // matching signature(s) outside of our current tree and we should
		      // fall through to them instead of throwing an exception
		      var fallThrough = false;
		      for (i = 0; i < matchingAnys.length; i++) {
		        if (!contains(signatures, matchingAnys[i])) {
		          fallThrough = true;
		          break;
		        }
		      }
	
		      // parse the childs
		      var childs = new Array(entries.length);
		      for (i = 0; i < entries.length; i++) {
		        var entry = entries[i];
		        childs[i] = parseTree(entry.signatures, path.concat(entry.param), matchingAnys);
		      }
	
		      return new Node(path, nodeSignature, childs, fallThrough);
		    }
	
		    /**
		     * Generate an array like ['arg0', 'arg1', 'arg2']
		     * @param {number} count Number of arguments to generate
		     * @returns {Array} Returns an array with argument names
		     */
		    function getArgs(count) {
		      // create an array with all argument names
		      var args = [];
		      for (var i = 0; i < count; i++) {
		        args[i] = 'arg' + i;
		      }
	
		      return args;
		    }
	
		    /**
		     * Compose a function from sub-functions each handling a single type signature.
		     * Signatures:
		     *   typed(signature: string, fn: function)
		     *   typed(name: string, signature: string, fn: function)
		     *   typed(signatures: Object.<string, function>)
		     *   typed(name: string, signatures: Object.<string, function>)
		     *
		     * @param {string | null} name
		     * @param {Object.<string, Function>} signatures
		     * @return {Function} Returns the typed function
		     * @private
		     */
		    function _typed(name, signatures) {
		      var refs = new Refs();
	
		      // parse signatures, expand them
		      var _signatures = parseSignatures(signatures);
		      if (_signatures.length == 0) {
		        throw new Error('No signatures provided');
		      }
	
		      // filter all any type signatures
		      var anys = filterAnyTypeSignatures(_signatures);
	
		      // parse signatures into a node tree
		      var node = parseTree(_signatures, [], anys);
	
		      //var util = require('util');
		      //console.log('ROOT');
		      //console.log(util.inspect(node, { depth: null }));
	
		      // generate code for the typed function
		      // safeName is a conservative replacement of characters 
		      // to prevend being able to inject JS code at the place of the function name 
		      // the name is useful for stack trackes therefore we want have it there
		      var code = [];
		      var safeName = (name || '').replace(/[^a-zA-Z0-9_$]/g, '_');
		      var args = getArgs(maxParams(_signatures));
		      code.push('function ' + safeName + '(' + args.join(', ') + ') {');
		      code.push('  "use strict";');
		      code.push('  var name = ' + JSON.stringify(name || '') + ';');
		      code.push(node.toCode(refs, '  ', false));
		      code.push('}');
	
		      // generate body for the factory function
		      var body = [refs.toCode(), 'return ' + code.join('\n')].join('\n');
	
		      // evaluate the JavaScript code and attach function references
		      var factory = new Function(refs.name, 'createError', body);
		      var fn = factory(refs, createError);
	
		      //console.log('FN\n' + fn.toString()); // TODO: cleanup
	
		      // attach the signatures with sub-functions to the constructed function
		      fn.signatures = mapSignatures(_signatures);
	
		      return fn;
		    }
	
		    /**
		     * Calculate the maximum number of parameters in givens signatures
		     * @param {Signature[]} signatures
		     * @returns {number} The maximum number of parameters
		     */
		    function maxParams(signatures) {
		      var max = 0;
	
		      for (var i = 0; i < signatures.length; i++) {
		        var len = signatures[i].params.length;
		        if (len > max) {
		          max = len;
		        }
		      }
	
		      return max;
		    }
	
		    /**
		     * Get the type of a value
		     * @param {*} x
		     * @returns {string} Returns a string with the type of value
		     */
		    function getTypeOf(x) {
		      var obj;
	
		      for (var i = 0; i < typed.types.length; i++) {
		        var entry = typed.types[i];
	
		        if (entry.name === 'Object') {
		          // Array and Date are also Object, so test for Object afterwards
		          obj = entry;
		        } else {
		          if (entry.test(x)) return entry.name;
		        }
		      }
	
		      // at last, test whether an object
		      if (obj && obj.test(x)) return obj.name;
	
		      return 'unknown';
		    }
	
		    /**
		     * Test whether an array contains some item
		     * @param {Array} array
		     * @param {*} item
		     * @return {boolean} Returns true if array contains item, false if not.
		     */
		    function contains(array, item) {
		      return array.indexOf(item) !== -1;
		    }
	
		    /**
		     * Returns the last item in the array
		     * @param {Array} array
		     * @return {*} item
		     */
		    function last(array) {
		      return array[array.length - 1];
		    }
	
		    // data type tests
		    var types = [{ name: 'number', test: function test(x) {
		        return typeof x === 'number';
		      } }, { name: 'string', test: function test(x) {
		        return typeof x === 'string';
		      } }, { name: 'boolean', test: function test(x) {
		        return typeof x === 'boolean';
		      } }, { name: 'Function', test: function test(x) {
		        return typeof x === 'function';
		      } }, { name: 'Array', test: Array.isArray }, { name: 'Date', test: function test(x) {
		        return x instanceof Date;
		      } }, { name: 'RegExp', test: function test(x) {
		        return x instanceof RegExp;
		      } }, { name: 'Object', test: function test(x) {
		        return (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object';
		      } }, { name: 'null', test: function test(x) {
		        return x === null;
		      } }, { name: 'undefined', test: function test(x) {
		        return x === undefined;
		      } }];
	
		    // configuration
		    var config = {};
	
		    // type conversions. Order is important
		    var conversions = [];
	
		    // types to be ignored
		    var ignore = [];
	
		    // temporary object for holding types and conversions, for constructing
		    // the `typed` function itself
		    // TODO: find a more elegant solution for this
		    var typed = {
		      config: config,
		      types: types,
		      conversions: conversions,
		      ignore: ignore
		    };
	
		    /**
		     * Construct the typed function itself with various signatures
		     *
		     * Signatures:
		     *
		     *   typed(signatures: Object.<string, function>)
		     *   typed(name: string, signatures: Object.<string, function>)
		     */
		    typed = _typed('typed', {
		      'Object': function Object(signatures) {
		        var fns = [];
		        for (var signature in signatures) {
		          if (signatures.hasOwnProperty(signature)) {
		            fns.push(signatures[signature]);
		          }
		        }
		        var name = getName(fns);
	
		        return _typed(name, signatures);
		      },
		      'string, Object': _typed,
		      // TODO: add a signature 'Array.<function>'
		      '...Function': function Function(fns) {
		        var err;
		        var name = getName(fns);
		        var signatures = {};
	
		        for (var i = 0; i < fns.length; i++) {
		          var fn = fns[i];
	
		          // test whether this is a typed-function
		          if (!(_typeof(fn.signatures) === 'object')) {
		            err = new TypeError('Function is no typed-function (index: ' + i + ')');
		            err.data = { index: i };
		            throw err;
		          }
	
		          // merge the signatures
		          for (var signature in fn.signatures) {
		            if (fn.signatures.hasOwnProperty(signature)) {
		              if (signatures.hasOwnProperty(signature)) {
		                if (fn.signatures[signature] !== signatures[signature]) {
		                  err = new Error('Signature "' + signature + '" is defined twice');
		                  err.data = { signature: signature };
		                  throw err;
		                }
		                // else: both signatures point to the same function, that's fine
		              } else {
		                signatures[signature] = fn.signatures[signature];
		              }
		            }
		          }
		        }
	
		        return _typed(name, signatures);
		      }
		    });
	
		    /**
		     * Find a specific signature from a (composed) typed function, for
		     * example:
		     *
		     *   typed.find(fn, ['number', 'string'])
		     *   typed.find(fn, 'number, string')
		     *
		     * Function find only only works for exact matches.
		     *
		     * @param {Function} fn                   A typed-function
		     * @param {string | string[]} signature   Signature to be found, can be
		     *                                        an array or a comma separated string.
		     * @return {Function}                     Returns the matching signature, or
		     *                                        throws an errror when no signature
		     *                                        is found.
		     */
		    function find(fn, signature) {
		      if (!fn.signatures) {
		        throw new TypeError('Function is no typed-function');
		      }
	
		      // normalize input
		      var arr;
		      if (typeof signature === 'string') {
		        arr = signature.split(',');
		        for (var i = 0; i < arr.length; i++) {
		          arr[i] = arr[i].trim();
		        }
		      } else if (Array.isArray(signature)) {
		        arr = signature;
		      } else {
		        throw new TypeError('String array or a comma separated string expected');
		      }
	
		      var str = arr.join(',');
	
		      // find an exact match
		      var match = fn.signatures[str];
		      if (match) {
		        return match;
		      }
	
		      // TODO: extend find to match non-exact signatures
	
		      throw new TypeError('Signature not found (signature: ' + (fn.name || 'unnamed') + '(' + arr.join(', ') + '))');
		    }
	
		    /**
		     * Convert a given value to another data type.
		     * @param {*} value
		     * @param {string} type
		     */
		    function convert(value, type) {
		      var from = getTypeOf(value);
	
		      // check conversion is needed
		      if (type === from) {
		        return value;
		      }
	
		      for (var i = 0; i < typed.conversions.length; i++) {
		        var conversion = typed.conversions[i];
		        if (conversion.from === from && conversion.to === type) {
		          return conversion.convert(value);
		        }
		      }
	
		      throw new Error('Cannot convert from ' + from + ' to ' + type);
		    }
	
		    // attach types and conversions to the final `typed` function
		    typed.config = config;
		    typed.types = types;
		    typed.conversions = conversions;
		    typed.ignore = ignore;
		    typed.create = create;
		    typed.find = find;
		    typed.convert = convert;
	
		    // add a type
		    typed.addType = function (type) {
		      if (!type || typeof type.name !== 'string' || typeof type.test !== 'function') {
		        throw new TypeError('Object with properties {name: string, test: function} expected');
		      }
	
		      typed.types.push(type);
		    };
	
		    // add a conversion
		    typed.addConversion = function (conversion) {
		      if (!conversion || typeof conversion.from !== 'string' || typeof conversion.to !== 'string' || typeof conversion.convert !== 'function') {
		        throw new TypeError('Object with properties {from: string, to: string, convert: function} expected');
		      }
	
		      typed.conversions.push(conversion);
		    };
	
		    return typed;
		  }
	
		  return create();
		});
	
	/***/ }),
	/* 18 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * @typedef {{sign: '+' | '-' | '', coefficients: number[], exponent: number}} SplitValue
		 */
	
		/**
		 * Test whether value is a number
		 * @param {*} value
		 * @return {boolean} isNumber
		 */
	
		exports.isNumber = function (value) {
		  return typeof value === 'number';
		};
	
		/**
		 * Check if a number is integer
		 * @param {number | boolean} value
		 * @return {boolean} isInteger
		 */
		exports.isInteger = function (value) {
		  return isFinite(value) ? value == Math.round(value) : false;
		  // Note: we use ==, not ===, as we can have Booleans as well
		};
	
		/**
		 * Calculate the sign of a number
		 * @param {number} x
		 * @returns {*}
		 */
		exports.sign = Math.sign || function (x) {
		  if (x > 0) {
		    return 1;
		  } else if (x < 0) {
		    return -1;
		  } else {
		    return 0;
		  }
		};
	
		/**
		 * Convert a number to a formatted string representation.
		 *
		 * Syntax:
		 *
		 *    format(value)
		 *    format(value, options)
		 *    format(value, precision)
		 *    format(value, fn)
		 *
		 * Where:
		 *
		 *    {number} value   The value to be formatted
		 *    {Object} options An object with formatting options. Available options:
		 *                     {string} notation
		 *                         Number notation. Choose from:
		 *                         'fixed'          Always use regular number notation.
		 *                                          For example '123.40' and '14000000'
		 *                         'exponential'    Always use exponential notation.
		 *                                          For example '1.234e+2' and '1.4e+7'
		 *                         'engineering'    Always use engineering notation.
		 *                                          For example '123.4e+0' and '14.0e+6'
		 *                         'auto' (default) Regular number notation for numbers
		 *                                          having an absolute value between
		 *                                          `lower` and `upper` bounds, and uses
		 *                                          exponential notation elsewhere.
		 *                                          Lower bound is included, upper bound
		 *                                          is excluded.
		 *                                          For example '123.4' and '1.4e7'.
		 *                     {number} precision   A number between 0 and 16 to round
		 *                                          the digits of the number.
		 *                                          In case of notations 'exponential' and
		 *                                          'auto', `precision` defines the total
		 *                                          number of significant digits returned
		 *                                          and is undefined by default.
		 *                                          In case of notation 'fixed',
		 *                                          `precision` defines the number of
		 *                                          significant digits after the decimal
		 *                                          point, and is 0 by default.
		 *                     {Object} exponential An object containing two parameters,
		 *                                          {number} lower and {number} upper,
		 *                                          used by notation 'auto' to determine
		 *                                          when to return exponential notation.
		 *                                          Default values are `lower=1e-3` and
		 *                                          `upper=1e5`.
		 *                                          Only applicable for notation `auto`.
		 *    {Function} fn    A custom formatting function. Can be used to override the
		 *                     built-in notations. Function `fn` is called with `value` as
		 *                     parameter and must return a string. Is useful for example to
		 *                     format all values inside a matrix in a particular way.
		 *
		 * Examples:
		 *
		 *    format(6.4);                                        // '6.4'
		 *    format(1240000);                                    // '1.24e6'
		 *    format(1/3);                                        // '0.3333333333333333'
		 *    format(1/3, 3);                                     // '0.333'
		 *    format(21385, 2);                                   // '21000'
		 *    format(12.071, {notation: 'fixed'});                // '12'
		 *    format(2.3,    {notation: 'fixed', precision: 2});  // '2.30'
		 *    format(52.8,   {notation: 'exponential'});          // '5.28e+1'
		 *    format(12345678, {notation: 'engineering'});        // '12.345678e+6'
		 *
		 * @param {number} value
		 * @param {Object | Function | number} [options]
		 * @return {string} str The formatted value
		 */
		exports.format = function (value, options) {
		  if (typeof options === 'function') {
		    // handle format(value, fn)
		    return options(value);
		  }
	
		  // handle special cases
		  if (value === Infinity) {
		    return 'Infinity';
		  } else if (value === -Infinity) {
		    return '-Infinity';
		  } else if (isNaN(value)) {
		    return 'NaN';
		  }
	
		  // default values for options
		  var notation = 'auto';
		  var precision = undefined;
	
		  if (options) {
		    // determine notation from options
		    if (options.notation) {
		      notation = options.notation;
		    }
	
		    // determine precision from options
		    if (exports.isNumber(options)) {
		      precision = options;
		    } else if (options.precision) {
		      precision = options.precision;
		    }
		  }
	
		  // handle the various notations
		  switch (notation) {
		    case 'fixed':
		      return exports.toFixed(value, precision);
	
		    case 'exponential':
		      return exports.toExponential(value, precision);
	
		    case 'engineering':
		      return exports.toEngineering(value, precision);
	
		    case 'auto':
		      return exports.toPrecision(value, precision, options && options.exponential)
	
		      // remove trailing zeros after the decimal point
		      .replace(/((\.\d*?)(0+))($|e)/, function () {
		        var digits = arguments[2];
		        var e = arguments[4];
		        return digits !== '.' ? digits + e : e;
		      });
	
		    default:
		      throw new Error('Unknown notation "' + notation + '". ' + 'Choose "auto", "exponential", or "fixed".');
		  }
		};
	
		/**
		 * Split a number into sign, coefficients, and exponent
		 * @param {number | string} value
		 * @return {SplitValue}
		 *              Returns an object containing sign, coefficients, and exponent
		 */
		exports.splitNumber = function (value) {
		  // parse the input value
		  var match = String(value).toLowerCase().match(/^0*?(-?)(\d+\.?\d*)(e([+-]?\d+))?$/);
		  if (!match) {
		    throw new SyntaxError('Invalid number ' + value);
		  }
	
		  var sign = match[1];
		  var digits = match[2];
		  var exponent = parseFloat(match[4] || '0');
	
		  var dot = digits.indexOf('.');
		  exponent += dot !== -1 ? dot - 1 : digits.length - 1;
	
		  var coefficients = digits.replace('.', '') // remove the dot (must be removed before removing leading zeros)
		  .replace(/^0*/, function (zeros) {
		    // remove leading zeros, add their count to the exponent
		    exponent -= zeros.length;
		    return '';
		  }).replace(/0*$/, '') // remove trailing zeros
		  .split('').map(function (d) {
		    return parseInt(d);
		  });
	
		  if (coefficients.length === 0) {
		    coefficients.push(0);
		    exponent++;
		  }
	
		  return {
		    sign: sign,
		    coefficients: coefficients,
		    exponent: exponent
		  };
		};
	
		/**
		 * Format a number in engineering notation. Like '1.23e+6', '2.3e+0', '3.500e-3'
		 * @param {number | string} value
		 * @param {number} [precision=0]        Optional number of decimals after the
		 *                                      decimal point. Zero by default.
		 */
		exports.toEngineering = function (value, precision) {
		  if (isNaN(value) || !isFinite(value)) {
		    return String(value);
		  }
	
		  var rounded = exports.roundDigits(exports.splitNumber(value), precision);
	
		  var e = rounded.exponent;
		  var c = rounded.coefficients;
	
		  // find nearest lower multiple of 3 for exponent
		  var newExp = e % 3 === 0 ? e : e < 0 ? e - 3 - e % 3 : e - e % 3;
	
		  // concatenate coefficients with necessary zeros
		  var significandsDiff = e >= 0 ? e : Math.abs(newExp);
	
		  // add zeros if necessary (for ex: 1e+8)
		  if (c.length - 1 < significandsDiff) c = c.concat(zeros(significandsDiff - (c.length - 1)));
	
		  // find difference in exponents
		  var expDiff = Math.abs(e - newExp);
	
		  var decimalIdx = 1;
	
		  // push decimal index over by expDiff times
		  while (--expDiff >= 0) {
		    decimalIdx++;
		  } // if all coefficient values are zero after the decimal point, don't add a decimal value.
		  // otherwise concat with the rest of the coefficients
		  var decimals = c.slice(decimalIdx).join('');
		  var decimalVal = decimals.match(/[1-9]/) ? '.' + decimals : '';
	
		  var str = c.slice(0, decimalIdx).join('') + decimalVal + 'e' + (e >= 0 ? '+' : '') + newExp.toString();
		  return rounded.sign + str;
		};
	
		/**
		 * Format a number with fixed notation.
		 * @param {number | string} value
		 * @param {number} [precision=0]        Optional number of decimals after the
		 *                                      decimal point. Zero by default.
		 */
		exports.toFixed = function (value, precision) {
		  if (isNaN(value) || !isFinite(value)) {
		    return String(value);
		  }
	
		  var splitValue = exports.splitNumber(value);
		  var rounded = exports.roundDigits(splitValue, splitValue.exponent + 1 + (precision || 0));
		  var c = rounded.coefficients;
		  var p = rounded.exponent + 1; // exponent may have changed
	
		  // append zeros if needed
		  var pp = p + (precision || 0);
		  if (c.length < pp) {
		    c = c.concat(zeros(pp - c.length));
		  }
	
		  // prepend zeros if needed
		  if (p < 0) {
		    c = zeros(-p + 1).concat(c);
		    p = 1;
		  }
	
		  // insert a dot if needed
		  if (precision) {
		    c.splice(p, 0, p === 0 ? '0.' : '.');
		  }
	
		  return rounded.sign + c.join('');
		};
	
		/**
		 * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3'
		 * @param {number | string} value
		 * @param {number} [precision]  Number of digits in formatted output.
		 *                              If not provided, the maximum available digits
		 *                              is used.
		 */
		exports.toExponential = function (value, precision) {
		  if (isNaN(value) || !isFinite(value)) {
		    return String(value);
		  }
	
		  // round if needed, else create a clone
		  var split = exports.splitNumber(value);
		  var rounded = precision ? exports.roundDigits(split, precision) : split;
		  var c = rounded.coefficients;
		  var e = rounded.exponent;
	
		  // append zeros if needed
		  if (c.length < precision) {
		    c = c.concat(zeros(precision - c.length));
		  }
	
		  // format as `C.CCCe+EEE` or `C.CCCe-EEE`
		  var first = c.shift();
		  return rounded.sign + first + (c.length > 0 ? '.' + c.join('') : '') + 'e' + (e >= 0 ? '+' : '') + e;
		};
	
		/**
		 * Format a number with a certain precision
		 * @param {number | string} value
		 * @param {number} [precision=undefined] Optional number of digits.
		 * @param {{lower: number | undefined, upper: number | undefined}} [options]
		 *                                       By default:
		 *                                         lower = 1e-3 (excl)
		 *                                         upper = 1e+5 (incl)
		 * @return {string}
		 */
		exports.toPrecision = function (value, precision, options) {
		  if (isNaN(value) || !isFinite(value)) {
		    return String(value);
		  }
	
		  // determine lower and upper bound for exponential notation.
		  var lower = options && options.lower !== undefined ? options.lower : 1e-3;
		  var upper = options && options.upper !== undefined ? options.upper : 1e+5;
	
		  var split = exports.splitNumber(value);
		  var abs = Math.abs(Math.pow(10, split.exponent));
		  if (abs < lower || abs >= upper) {
		    // exponential notation
		    return exports.toExponential(value, precision);
		  } else {
		    var rounded = precision ? exports.roundDigits(split, precision) : split;
		    var c = rounded.coefficients;
		    var e = rounded.exponent;
	
		    // append trailing zeros
		    if (c.length < precision) {
		      c = c.concat(zeros(precision - c.length));
		    }
	
		    // append trailing zeros
		    // TODO: simplify the next statement
		    c = c.concat(zeros(e - c.length + 1 + (c.length < precision ? precision - c.length : 0)));
	
		    // prepend zeros
		    c = zeros(-e).concat(c);
	
		    var dot = e > 0 ? e : 0;
		    if (dot < c.length - 1) {
		      c.splice(dot + 1, 0, '.');
		    }
	
		    return rounded.sign + c.join('');
		  }
		};
	
		/**
		 * Round the number of digits of a number *
		 * @param {SplitValue} split       A value split with .splitNumber(value)
		 * @param {number} precision  A positive integer
		 * @return {SplitValue}
		 *              Returns an object containing sign, coefficients, and exponent
		 *              with rounded digits
		 */
		exports.roundDigits = function (split, precision) {
		  // create a clone
		  var rounded = {
		    sign: split.sign,
		    coefficients: split.coefficients,
		    exponent: split.exponent
		  };
		  var c = rounded.coefficients;
	
		  // prepend zeros if needed
		  while (precision <= 0) {
		    c.unshift(0);
		    rounded.exponent++;
		    precision++;
		  }
	
		  if (c.length > precision) {
		    var removed = c.splice(precision, c.length - precision);
	
		    if (removed[0] >= 5) {
		      var i = precision - 1;
		      c[i]++;
		      while (c[i] === 10) {
		        c.pop();
		        if (i === 0) {
		          c.unshift(0);
		          rounded.exponent++;
		          i++;
		        }
		        i--;
		        c[i]++;
		      }
		    }
		  }
	
		  return rounded;
		};
	
		/**
		 * Create an array filled with zeros.
		 * @param {number} length
		 * @return {Array}
		 */
		function zeros(length) {
		  var arr = [];
		  for (var i = 0; i < length; i++) {
		    arr.push(0);
		  }
		  return arr;
		}
	
		/**
		 * Count the number of significant digits of a number.
		 *
		 * For example:
		 *   2.34 returns 3
		 *   0.0034 returns 2
		 *   120.5e+30 returns 4
		 *
		 * @param {number} value
		 * @return {number} digits   Number of significant digits
		 */
		exports.digits = function (value) {
		  return value.toExponential().replace(/e.*$/, '') // remove exponential notation
		  .replace(/^0\.?0*|\./, '') // remove decimal point and leading zeros
		  .length;
		};
	
		/**
		 * Minimum number added to one that makes the result different than one
		 */
		exports.DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-16;
	
		/**
		 * Compares two floating point numbers.
		 * @param {number} x          First value to compare
		 * @param {number} y          Second value to compare
		 * @param {number} [epsilon]  The maximum relative difference between x and y
		 *                            If epsilon is undefined or null, the function will
		 *                            test whether x and y are exactly equal.
		 * @return {boolean} whether the two numbers are nearly equal
		*/
		exports.nearlyEqual = function (x, y, epsilon) {
		  // if epsilon is null or undefined, test whether x and y are exactly equal
		  if (epsilon == null) {
		    return x == y;
		  }
	
		  // use "==" operator, handles infinities
		  if (x == y) {
		    return true;
		  }
	
		  // NaN
		  if (isNaN(x) || isNaN(y)) {
		    return false;
		  }
	
		  // at this point x and y should be finite
		  if (isFinite(x) && isFinite(y)) {
		    // check numbers are very close, needed when comparing numbers near zero
		    var diff = Math.abs(x - y);
		    if (diff < exports.DBL_EPSILON) {
		      return true;
		    } else {
		      // use relative error
		      return diff <= Math.max(Math.abs(x), Math.abs(y)) * epsilon;
		    }
		  }
	
		  // Infinite and Number or negative Infinite and positive Infinite cases
		  return false;
		};
	
	/***/ }),
	/* 19 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Test whether a value is a Matrix
		 * @param {*} x
		 * @returns {boolean} returns true with input is a Matrix
		 *                    (like a DenseMatrix or SparseMatrix)
		 */
	
		module.exports = function isMatrix(x) {
		  return x && x.constructor.prototype.isMatrix || false;
		};
	
	/***/ }),
	/* 20 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var Emitter = __webpack_require__(21);
	
		/**
		 * Extend given object with emitter functions `on`, `off`, `once`, `emit`
		 * @param {Object} obj
		 * @return {Object} obj
		 */
		exports.mixin = function (obj) {
		  // create event emitter
		  var emitter = new Emitter();
	
		  // bind methods to obj (we don't want to expose the emitter.e Array...)
		  obj.on = emitter.on.bind(emitter);
		  obj.off = emitter.off.bind(emitter);
		  obj.once = emitter.once.bind(emitter);
		  obj.emit = emitter.emit.bind(emitter);
	
		  return obj;
		};
	
	/***/ }),
	/* 21 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		function E() {
		  // Keep this empty so it's easier to inherit from
		  // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
		}
	
		E.prototype = {
		  on: function on(name, callback, ctx) {
		    var e = this.e || (this.e = {});
	
		    (e[name] || (e[name] = [])).push({
		      fn: callback,
		      ctx: ctx
		    });
	
		    return this;
		  },
	
		  once: function once(name, callback, ctx) {
		    var self = this;
		    function listener() {
		      self.off(name, listener);
		      callback.apply(ctx, arguments);
		    };
	
		    listener._ = callback;
		    return this.on(name, listener, ctx);
		  },
	
		  emit: function emit(name) {
		    var data = [].slice.call(arguments, 1);
		    var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
		    var i = 0;
		    var len = evtArr.length;
	
		    for (i; i < len; i++) {
		      evtArr[i].fn.apply(evtArr[i].ctx, data);
		    }
	
		    return this;
		  },
	
		  off: function off(name, callback) {
		    var e = this.e || (this.e = {});
		    var evts = e[name];
		    var liveEvents = [];
	
		    if (evts && callback) {
		      for (var i = 0, len = evts.length; i < len; i++) {
		        if (evts[i].fn !== callback && evts[i].fn._ !== callback) liveEvents.push(evts[i]);
		      }
		    }
	
		    // Remove event from queue to prevent memory leak
		    // Suggested by https://github.com/lazd
		    // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
	
		    liveEvents.length ? e[name] = liveEvents : delete e[name];
	
		    return this;
		  }
		};
	
			module.exports = E;
	
	/***/ }),
	/* 22 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
	
		var lazy = __webpack_require__(14).lazy;
		var isFactory = __webpack_require__(14).isFactory;
		var traverse = __webpack_require__(14).traverse;
		var ArgumentsError = __webpack_require__(23);
	
		function factory(type, config, load, typed, math) {
		  /**
		   * Import functions from an object or a module
		   *
		   * Syntax:
		   *
		   *    math.import(object)
		   *    math.import(object, options)
		   *
		   * Where:
		   *
		   * - `object: Object`
		   *   An object with functions to be imported.
		   * - `options: Object` An object with import options. Available options:
		   *   - `override: boolean`
		   *     If true, existing functions will be overwritten. False by default.
		   *   - `silent: boolean`
		   *     If true, the function will not throw errors on duplicates or invalid
		   *     types. False by default.
		   *   - `wrap: boolean`
		   *     If true, the functions will be wrapped in a wrapper function
		   *     which converts data types like Matrix to primitive data types like Array.
		   *     The wrapper is needed when extending math.js with libraries which do not
		   *     support these data type. False by default.
		   *
		   * Examples:
		   *
		   *    // define new functions and variables
		   *    math.import({
		   *      myvalue: 42,
		   *      hello: function (name) {
		   *        return 'hello, ' + name + '!';
		   *      }
		   *    });
		   *
		   *    // use the imported function and variable
		   *    math.myvalue * 2;               // 84
		   *    math.hello('user');             // 'hello, user!'
		   *
		   *    // import the npm module 'numbers'
		   *    // (must be installed first with `npm install numbers`)
		   *    math.import(require('numbers'), {wrap: true});
		   *
		   *    math.fibonacci(7); // returns 13
		   *
		   * @param {Object | Array} object   Object with functions to be imported.
		   * @param {Object} [options]        Import options.
		   */
		  function math_import(object, options) {
		    var num = arguments.length;
		    if (num !== 1 && num !== 2) {
		      throw new ArgumentsError('import', num, 1, 2);
		    }
	
		    if (!options) {
		      options = {};
		    }
	
		    if (isFactory(object)) {
		      _importFactory(object, options);
		    }
		    // TODO: allow a typed-function with name too
		    else if (Array.isArray(object)) {
		        object.forEach(function (entry) {
		          math_import(entry, options);
		        });
		      } else if ((typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object') {
		        // a map with functions
		        for (var name in object) {
		          if (object.hasOwnProperty(name)) {
		            var value = object[name];
		            if (isSupportedType(value)) {
		              _import(name, value, options);
		            } else if (isFactory(object)) {
		              _importFactory(object, options);
		            } else {
		              math_import(value, options);
		            }
		          }
		        }
		      } else {
		        if (!options.silent) {
		          throw new TypeError('Factory, Object, or Array expected');
		        }
		      }
		  }
	
		  /**
		   * Add a property to the math namespace and create a chain proxy for it.
		   * @param {string} name
		   * @param {*} value
		   * @param {Object} options  See import for a description of the options
		   * @private
		   */
		  function _import(name, value, options) {
		    // TODO: refactor this function, it's to complicated and contains duplicate code
		    if (options.wrap && typeof value === 'function') {
		      // create a wrapper around the function
		      value = _wrap(value);
		    }
	
		    if (isTypedFunction(math[name]) && isTypedFunction(value)) {
		      if (options.override) {
		        // give the typed function the right name
		        value = typed(name, value.signatures);
		      } else {
		        // merge the existing and typed function
		        value = typed(math[name], value);
		      }
	
		      math[name] = value;
		      _importTransform(name, value);
		      math.emit('import', name, function resolver() {
		        return value;
		      });
		      return;
		    }
	
		    if (math[name] === undefined || options.override) {
		      math[name] = value;
		      _importTransform(name, value);
		      math.emit('import', name, function resolver() {
		        return value;
		      });
		      return;
		    }
	
		    if (!options.silent) {
		      throw new Error('Cannot import "' + name + '": already exists');
		    }
		  }
	
		  function _importTransform(name, value) {
		    if (value && typeof value.transform === 'function') {
		      math.expression.transform[name] = value.transform;
		      if (allowedInExpressions(name)) {
		        math.expression.mathWithTransform[name] = value.transform;
		      }
		    } else {
		      // remove existing transform
		      delete math.expression.transform[name];
		      if (allowedInExpressions(name)) {
		        math.expression.mathWithTransform[name] = value;
		      }
		    }
		  }
	
		  /**
		   * Create a wrapper a round an function which converts the arguments
		   * to their primitive values (like convert a Matrix to Array)
		   * @param {Function} fn
		   * @return {Function} Returns the wrapped function
		   * @private
		   */
		  function _wrap(fn) {
		    var wrapper = function wrapper() {
		      var args = [];
		      for (var i = 0, len = arguments.length; i < len; i++) {
		        var arg = arguments[i];
		        args[i] = arg && arg.valueOf();
		      }
		      return fn.apply(math, args);
		    };
	
		    if (fn.transform) {
		      wrapper.transform = fn.transform;
		    }
	
		    return wrapper;
		  }
	
		  /**
		   * Import an instance of a factory into math.js
		   * @param {{factory: Function, name: string, path: string, math: boolean}} factory
		   * @param {Object} options  See import for a description of the options
		   * @private
		   */
		  function _importFactory(factory, options) {
		    if (typeof factory.name === 'string') {
		      var name = factory.name;
		      var existingTransform = name in math.expression.transform;
		      var namespace = factory.path ? traverse(math, factory.path) : math;
		      var existing = namespace.hasOwnProperty(name) ? namespace[name] : undefined;
	
		      var resolver = function resolver() {
		        var instance = load(factory);
		        if (instance && typeof instance.transform === 'function') {
		          throw new Error('Transforms cannot be attached to factory functions. ' + 'Please create a separate function for it with exports.path="expression.transform"');
		        }
	
		        if (isTypedFunction(existing) && isTypedFunction(instance)) {
		          if (options.override) {
		            // replace the existing typed function (nothing to do)
		          } else {
		            // merge the existing and new typed function
		            instance = typed(existing, instance);
		          }
	
		          return instance;
		        }
	
		        if (existing === undefined || options.override) {
		          return instance;
		        }
	
		        if (!options.silent) {
		          throw new Error('Cannot import "' + name + '": already exists');
		        }
		      };
	
		      if (factory.lazy !== false) {
		        lazy(namespace, name, resolver);
	
		        if (!existingTransform) {
		          if (factory.path === 'expression.transform' || factoryAllowedInExpressions(factory)) {
		            lazy(math.expression.mathWithTransform, name, resolver);
		          }
		        }
		      } else {
		        namespace[name] = resolver();
	
		        if (!existingTransform) {
		          if (factory.path === 'expression.transform' || factoryAllowedInExpressions(factory)) {
		            math.expression.mathWithTransform[name] = resolver();
		          }
		        }
		      }
	
		      math.emit('import', name, resolver, factory.path);
		    } else {
		      // unnamed factory.
		      // no lazy loading
		      load(factory);
		    }
		  }
	
		  /**
		   * Check whether given object is a type which can be imported
		   * @param {Function | number | string | boolean | null | Unit | Complex} object
		   * @return {boolean}
		   * @private
		   */
		  function isSupportedType(object) {
		    return typeof object === 'function' || typeof object === 'number' || typeof object === 'string' || typeof object === 'boolean' || object === null || object && type.isUnit(object) || object && type.isComplex(object) || object && type.isBigNumber(object) || object && type.isFraction(object) || object && type.isMatrix(object) || object && Array.isArray(object);
		  }
	
		  /**
		   * Test whether a given thing is a typed-function
		   * @param {*} fn
		   * @return {boolean} Returns true when `fn` is a typed-function
		   */
		  function isTypedFunction(fn) {
		    return typeof fn === 'function' && _typeof(fn.signatures) === 'object';
		  }
	
		  function allowedInExpressions(name) {
		    return !unsafe.hasOwnProperty(name);
		  }
	
		  function factoryAllowedInExpressions(factory) {
		    return factory.path === undefined && !unsafe.hasOwnProperty(factory.name);
		  }
	
		  // namespaces and functions not available in the parser for safety reasons
		  var unsafe = {
		    'expression': true,
		    'type': true,
		    'docs': true,
		    'error': true,
		    'json': true,
		    'chain': true // chain method not supported. Note that there is a unit chain too.
		  };
	
		  return math_import;
		}
	
		exports.math = true; // request access to the math namespace as 5th argument of the factory function
		exports.name = 'import';
		exports.factory = factory;
		exports.lazy = true;
	
	/***/ }),
	/* 23 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Create a syntax error with the message:
		 *     'Wrong number of arguments in function <fn> (<count> provided, <min>-<max> expected)'
		 * @param {string} fn     Function name
		 * @param {number} count  Actual argument count
		 * @param {number} min    Minimum required argument count
		 * @param {number} [max]  Maximum required argument count
		 * @extends Error
		 */
	
		function ArgumentsError(fn, count, min, max) {
		  if (!(this instanceof ArgumentsError)) {
		    throw new SyntaxError('Constructor must be called with the new operator');
		  }
	
		  this.fn = fn;
		  this.count = count;
		  this.min = min;
		  this.max = max;
	
		  this.message = 'Wrong number of arguments in function ' + fn + ' (' + count + ' provided, ' + min + (max != undefined ? '-' + max : '') + ' expected)';
	
		  this.stack = new Error().stack;
		}
	
		ArgumentsError.prototype = new Error();
		ArgumentsError.prototype.constructor = Error;
		ArgumentsError.prototype.name = 'ArgumentsError';
		ArgumentsError.prototype.isArgumentsError = true;
	
		module.exports = ArgumentsError;
	
	/***/ }),
	/* 24 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var object = __webpack_require__(14);
	
		function factory(type, config, load, typed, math) {
		  var MATRIX = ['Matrix', 'Array']; // valid values for option matrix
		  var NUMBER = ['number', 'BigNumber', 'Fraction']; // valid values for option number
	
		  /**
		   * Set configuration options for math.js, and get current options.
		   * Will emit a 'config' event, with arguments (curr, prev, changes).
		   *
		   * Syntax:
		   *
		   *     math.config(config: Object): Object
		   *
		   * Examples:
		   *
		   *     math.config().number;                // outputs 'number'
		   *     math.eval('0.4');                    // outputs number 0.4
		   *     math.config({number: 'Fraction'});
		   *     math.eval('0.4');                    // outputs Fraction 2/5
		   *
		   * @param {Object} [options] Available options:
		   *                            {number} epsilon
		   *                              Minimum relative difference between two
		   *                              compared values, used by all comparison functions.
		   *                            {string} matrix
		   *                              A string 'Matrix' (default) or 'Array'.
		   *                            {string} number
		   *                              A string 'number' (default), 'BigNumber', or 'Fraction'
		   *                            {number} precision
		   *                              The number of significant digits for BigNumbers.
		   *                              Not applicable for Numbers.
		   *                            {string} parenthesis
		   *                              How to display parentheses in LaTeX and string
		   *                              output.
		   *                            {string} randomSeed
		   *                              Random seed for seeded pseudo random number generator.
		   *                              Set to null to randomly seed.
		   * @return {Object} Returns the current configuration
		   */
		  function _config(options) {
		    if (options) {
		      var prev = object.map(config, object.clone);
	
		      // validate some of the options
		      validateOption(options, 'matrix', MATRIX);
		      validateOption(options, 'number', NUMBER);
	
		      // merge options
		      object.deepExtend(config, options);
	
		      var curr = object.map(config, object.clone);
	
		      var changes = object.map(options, object.clone);
	
		      // emit 'config' event
		      math.emit('config', curr, prev, changes);
	
		      return curr;
		    } else {
		      return object.map(config, object.clone);
		    }
		  }
	
		  // attach the valid options to the function so they can be extended
		  _config.MATRIX = MATRIX;
		  _config.NUMBER = NUMBER;
	
		  return _config;
		}
	
		/**
		 * Test whether an Array contains a specific item.
		 * @param {Array.<string>} array
		 * @param {string} item
		 * @return {boolean}
		 */
		function contains(array, item) {
		  return array.indexOf(item) !== -1;
		}
	
		/**
		 * Find a string in an array. Case insensitive search
		 * @param {Array.<string>} array
		 * @param {string} item
		 * @return {number} Returns the index when found. Returns -1 when not found
		 */
		function findIndex(array, item) {
		  return array.map(function (i) {
		    return i.toLowerCase();
		  }).indexOf(item.toLowerCase());
		}
	
		/**
		 * Validate an option
		 * @param {Object} options         Object with options
		 * @param {string} name            Name of the option to validate
		 * @param {Array.<string>} values  Array with valid values for this option
		 */
		function validateOption(options, name, values) {
		  if (options[name] !== undefined && !contains(values, options[name])) {
		    var index = findIndex(values, options[name]);
		    if (index !== -1) {
		      // right value, wrong casing
		      // TODO: lower case values are deprecated since v3, remove this warning some day.
		      console.warn('Warning: Wrong casing for configuration option "' + name + '", should be "' + values[index] + '" instead of "' + options[name] + '".');
	
		      options[name] = values[index]; // change the option to the right casing
		    } else {
		      // unknown value
		      console.warn('Warning: Unknown value "' + options[name] + '" for configuration option "' + name + '". Available options: ' + values.map(JSON.stringify).join(', ') + '.');
		    }
		  }
		}
	
		exports.name = 'config';
		exports.math = true; // request the math namespace as fifth argument
		exports.factory = factory;
	
	/***/ }),
	/* 25 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		module.exports = [
		// types
		__webpack_require__(26), __webpack_require__(36), __webpack_require__(38), __webpack_require__(41), __webpack_require__(51), __webpack_require__(57), __webpack_require__(58), __webpack_require__(59),
	
		// construction functions
		__webpack_require__(60), __webpack_require__(43), __webpack_require__(61)];
	
	/***/ }),
	/* 26 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var util = __webpack_require__(27);
	
		var string = util.string;
	
		var isString = string.isString;
	
		function factory(type, config, load, typed) {
		  /**
		   * @constructor Matrix
		   *
		   * A Matrix is a wrapper around an Array. A matrix can hold a multi dimensional
		   * array. A matrix can be constructed as:
		   *     var matrix = math.matrix(data)
		   *
		   * Matrix contains the functions to resize, get and set values, get the size,
		   * clone the matrix and to convert the matrix to a vector, array, or scalar.
		   * Furthermore, one can iterate over the matrix using map and forEach.
		   * The internal Array of the Matrix can be accessed using the function valueOf.
		   *
		   * Example usage:
		   *     var matrix = math.matrix([[1, 2], [3, 4]]);
		   *     matix.size();              // [2, 2]
		   *     matrix.resize([3, 2], 5);
		   *     matrix.valueOf();          // [[1, 2], [3, 4], [5, 5]]
		   *     matrix.subset([1,2])       // 3 (indexes are zero-based)
		   *
		   */
		  function Matrix() {
		    if (!(this instanceof Matrix)) {
		      throw new SyntaxError('Constructor must be called with the new operator');
		    }
		  }
	
		  /**
		   * Attach type information
		   */
		  Matrix.prototype.type = 'Matrix';
		  Matrix.prototype.isMatrix = true;
	
		  /**
		   * Get the Matrix storage constructor for the given format.
		   *
		   * @param {string} format       The Matrix storage format.
		   *
		   * @return {Function}           The Matrix storage constructor.
		   */
		  Matrix.storage = function (format) {
		    // check storage format is a string
		    if (!isString(format)) {
		      throw new TypeError('format must be a string value');
		    }
	
		    // get storage format constructor
		    var constructor = Matrix._storage[format];
		    if (!constructor) {
		      throw new SyntaxError('Unsupported matrix storage format: ' + format);
		    }
	
		    // return storage constructor
		    return constructor;
		  };
	
		  // a map with all constructors for all storage types
		  Matrix._storage = {};
	
		  /**
		   * Get the storage format used by the matrix.
		   *
		   * Usage:
		   *     var format = matrix.storage()                   // retrieve storage format
		   *
		   * @return {string}           The storage format.
		   */
		  Matrix.prototype.storage = function () {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke storage on a Matrix interface');
		  };
	
		  /**
		   * Get the datatype of the data stored in the matrix.
		   *
		   * Usage:
		   *     var format = matrix.datatype()                   // retrieve matrix datatype
		   *
		   * @return {string}           The datatype.
		   */
		  Matrix.prototype.datatype = function () {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke datatype on a Matrix interface');
		  };
	
		  /**
		   * Create a new Matrix With the type of the current matrix instance
		   * @param {Array | Object} data
		   * @param {string} [datatype]
		   */
		  Matrix.prototype.create = function (data, datatype) {
		    throw new Error('Cannot invoke create on a Matrix interface');
		  };
	
		  /**
		   * Get a subset of the matrix, or replace a subset of the matrix.
		   *
		   * Usage:
		   *     var subset = matrix.subset(index)               // retrieve subset
		   *     var value = matrix.subset(index, replacement)   // replace subset
		   *
		   * @param {Index} index
		   * @param {Array | Matrix | *} [replacement]
		   * @param {*} [defaultValue=0]      Default value, filled in on new entries when
		   *                                  the matrix is resized. If not provided,
		   *                                  new matrix elements will be filled with zeros.
		   */
		  Matrix.prototype.subset = function (index, replacement, defaultValue) {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke subset on a Matrix interface');
		  };
	
		  /**
		   * Get a single element from the matrix.
		   * @param {number[]} index   Zero-based index
		   * @return {*} value
		   */
		  Matrix.prototype.get = function (index) {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke get on a Matrix interface');
		  };
	
		  /**
		   * Replace a single element in the matrix.
		   * @param {number[]} index   Zero-based index
		   * @param {*} value
		   * @param {*} [defaultValue]        Default value, filled in on new entries when
		   *                                  the matrix is resized. If not provided,
		   *                                  new matrix elements will be left undefined.
		   * @return {Matrix} self
		   */
		  Matrix.prototype.set = function (index, value, defaultValue) {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke set on a Matrix interface');
		  };
	
		  /**
		   * Resize the matrix to the given size. Returns a copy of the matrix when 
		   * `copy=true`, otherwise return the matrix itself (resize in place).
		   *
		   * @param {number[]} size           The new size the matrix should have.
		   * @param {*} [defaultValue=0]      Default value, filled in on new entries.
		   *                                  If not provided, the matrix elements will
		   *                                  be filled with zeros.
		   * @param {boolean} [copy]          Return a resized copy of the matrix
		   *
		   * @return {Matrix}                 The resized matrix
		   */
		  Matrix.prototype.resize = function (size, defaultValue) {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke resize on a Matrix interface');
		  };
	
		  /**
		   * Reshape the matrix to the given size. Returns a copy of the matrix when
		   * `copy=true`, otherwise return the matrix itself (reshape in place).
		   *
		   * @param {number[]} size           The new size the matrix should have.
		   * @param {boolean} [copy]          Return a reshaped copy of the matrix
		   *
		   * @return {Matrix}                 The reshaped matrix
		   */
		  Matrix.prototype.reshape = function (size, defaultValue) {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke reshape on a Matrix interface');
		  };
	
		  /**
		   * Create a clone of the matrix
		   * @return {Matrix} clone
		   */
		  Matrix.prototype.clone = function () {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke clone on a Matrix interface');
		  };
	
		  /**
		   * Retrieve the size of the matrix.
		   * @returns {number[]} size
		   */
		  Matrix.prototype.size = function () {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke size on a Matrix interface');
		  };
	
		  /**
		   * Create a new matrix with the results of the callback function executed on
		   * each entry of the matrix.
		   * @param {Function} callback   The callback function is invoked with three
		   *                              parameters: the value of the element, the index
		   *                              of the element, and the Matrix being traversed.
		   * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
		   *
		   * @return {Matrix} matrix
		   */
		  Matrix.prototype.map = function (callback, skipZeros) {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke map on a Matrix interface');
		  };
	
		  /**
		   * Execute a callback function on each entry of the matrix.
		   * @param {Function} callback   The callback function is invoked with three
		   *                              parameters: the value of the element, the index
		   *                              of the element, and the Matrix being traversed.
		   */
		  Matrix.prototype.forEach = function (callback) {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke forEach on a Matrix interface');
		  };
	
		  /**
		   * Create an Array with a copy of the data of the Matrix
		   * @returns {Array} array
		   */
		  Matrix.prototype.toArray = function () {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke toArray on a Matrix interface');
		  };
	
		  /**
		   * Get the primitive value of the Matrix: a multidimensional array
		   * @returns {Array} array
		   */
		  Matrix.prototype.valueOf = function () {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke valueOf on a Matrix interface');
		  };
	
		  /**
		   * Get a string representation of the matrix, with optional formatting options.
		   * @param {Object | number | Function} [options]  Formatting options. See
		   *                                                lib/utils/number:format for a
		   *                                                description of the available
		   *                                                options.
		   * @returns {string} str
		   */
		  Matrix.prototype.format = function (options) {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke format on a Matrix interface');
		  };
	
		  /**
		   * Get a string representation of the matrix
		   * @returns {string} str
		   */
		  Matrix.prototype.toString = function () {
		    // must be implemented by each of the Matrix implementations
		    throw new Error('Cannot invoke toString on a Matrix interface');
		  };
	
		  // exports
		  return Matrix;
		}
	
		exports.name = 'Matrix';
		exports.path = 'type';
		exports.factory = factory;
	
	/***/ }),
	/* 27 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		exports.array = __webpack_require__(28);
		exports['boolean'] = __webpack_require__(34);
		exports['function'] = __webpack_require__(35);
		exports.number = __webpack_require__(18);
		exports.object = __webpack_require__(14);
		exports.string = __webpack_require__(29);
		exports.types = __webpack_require__(31);
		exports.emitter = __webpack_require__(20);
	
	/***/ }),
	/* 28 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var number = __webpack_require__(18);
		var string = __webpack_require__(29);
		var object = __webpack_require__(14);
		var types = __webpack_require__(31);
	
		var DimensionError = __webpack_require__(32);
		var IndexError = __webpack_require__(33);
	
		/**
		 * Calculate the size of a multi dimensional array.
		 * This function checks the size of the first entry, it does not validate
		 * whether all dimensions match. (use function `validate` for that)
		 * @param {Array} x
		 * @Return {Number[]} size
		 */
		exports.size = function (x) {
		  var s = [];
	
		  while (Array.isArray(x)) {
		    s.push(x.length);
		    x = x[0];
		  }
	
		  return s;
		};
	
		/**
		 * Recursively validate whether each element in a multi dimensional array
		 * has a size corresponding to the provided size array.
		 * @param {Array} array    Array to be validated
		 * @param {number[]} size  Array with the size of each dimension
		 * @param {number} dim   Current dimension
		 * @throws DimensionError
		 * @private
		 */
		function _validate(array, size, dim) {
		  var i;
		  var len = array.length;
	
		  if (len != size[dim]) {
		    throw new DimensionError(len, size[dim]);
		  }
	
		  if (dim < size.length - 1) {
		    // recursively validate each child array
		    var dimNext = dim + 1;
		    for (i = 0; i < len; i++) {
		      var child = array[i];
		      if (!Array.isArray(child)) {
		        throw new DimensionError(size.length - 1, size.length, '<');
		      }
		      _validate(array[i], size, dimNext);
		    }
		  } else {
		    // last dimension. none of the childs may be an array
		    for (i = 0; i < len; i++) {
		      if (Array.isArray(array[i])) {
		        throw new DimensionError(size.length + 1, size.length, '>');
		      }
		    }
		  }
		}
	
		/**
		 * Validate whether each element in a multi dimensional array has
		 * a size corresponding to the provided size array.
		 * @param {Array} array    Array to be validated
		 * @param {number[]} size  Array with the size of each dimension
		 * @throws DimensionError
		 */
		exports.validate = function (array, size) {
		  var isScalar = size.length == 0;
		  if (isScalar) {
		    // scalar
		    if (Array.isArray(array)) {
		      throw new DimensionError(array.length, 0);
		    }
		  } else {
		    // array
		    _validate(array, size, 0);
		  }
		};
	
		/**
		 * Test whether index is an integer number with index >= 0 and index < length
		 * when length is provided
		 * @param {number} index    Zero-based index
		 * @param {number} [length] Length of the array
		 */
		exports.validateIndex = function (index, length) {
		  if (!number.isNumber(index) || !number.isInteger(index)) {
		    throw new TypeError('Index must be an integer (value: ' + index + ')');
		  }
		  if (index < 0 || typeof length === 'number' && index >= length) {
		    throw new IndexError(index, length);
		  }
		};
	
		// a constant used to specify an undefined defaultValue
		exports.UNINITIALIZED = {};
	
		/**
		 * Resize a multi dimensional array. The resized array is returned.
		 * @param {Array} array         Array to be resized
		 * @param {Array.<number>} size Array with the size of each dimension
		 * @param {*} [defaultValue=0]  Value to be filled in in new entries,
		 *                              zero by default. To leave new entries undefined,
		 *                              specify array.UNINITIALIZED as defaultValue
		 * @return {Array} array         The resized array
		 */
		exports.resize = function (array, size, defaultValue) {
		  // TODO: add support for scalars, having size=[] ?
	
		  // check the type of the arguments
		  if (!Array.isArray(array) || !Array.isArray(size)) {
		    throw new TypeError('Array expected');
		  }
		  if (size.length === 0) {
		    throw new Error('Resizing to scalar is not supported');
		  }
	
		  // check whether size contains positive integers
		  size.forEach(function (value) {
		    if (!number.isNumber(value) || !number.isInteger(value) || value < 0) {
		      throw new TypeError('Invalid size, must contain positive integers ' + '(size: ' + string.format(size) + ')');
		    }
		  });
	
		  // recursively resize the array
		  var _defaultValue = defaultValue !== undefined ? defaultValue : 0;
		  _resize(array, size, 0, _defaultValue);
	
		  return array;
		};
	
		/**
		 * Recursively resize a multi dimensional array
		 * @param {Array} array         Array to be resized
		 * @param {number[]} size       Array with the size of each dimension
		 * @param {number} dim          Current dimension
		 * @param {*} [defaultValue]    Value to be filled in in new entries,
		 *                              undefined by default.
		 * @private
		 */
		function _resize(array, size, dim, defaultValue) {
		  var i;
		  var elem;
		  var oldLen = array.length;
		  var newLen = size[dim];
		  var minLen = Math.min(oldLen, newLen);
	
		  // apply new length
		  array.length = newLen;
	
		  if (dim < size.length - 1) {
		    // non-last dimension
		    var dimNext = dim + 1;
	
		    // resize existing child arrays
		    for (i = 0; i < minLen; i++) {
		      // resize child array
		      elem = array[i];
		      if (!Array.isArray(elem)) {
		        elem = [elem]; // add a dimension
		        array[i] = elem;
		      }
		      _resize(elem, size, dimNext, defaultValue);
		    }
	
		    // create new child arrays
		    for (i = minLen; i < newLen; i++) {
		      // get child array
		      elem = [];
		      array[i] = elem;
	
		      // resize new child array
		      _resize(elem, size, dimNext, defaultValue);
		    }
		  } else {
		    // last dimension
	
		    // remove dimensions of existing values
		    for (i = 0; i < minLen; i++) {
		      while (Array.isArray(array[i])) {
		        array[i] = array[i][0];
		      }
		    }
	
		    if (defaultValue !== exports.UNINITIALIZED) {
		      // fill new elements with the default value
		      for (i = minLen; i < newLen; i++) {
		        array[i] = defaultValue;
		      }
		    }
		  }
		}
	
		/**
		 * Re-shape a multi dimensional array to fit the specified dimensions
		 * @param {Array} array           Array to be reshaped
		 * @param {Array.<number>} sizes  List of sizes for each dimension
		 * @returns {Array}               Array whose data has been formatted to fit the
		 *                                specified dimensions
		 *
		 * @throws {DimensionError}       If the product of the new dimension sizes does
		 *                                not equal that of the old ones
		 */
		exports.reshape = function (array, sizes) {
		  var flatArray = exports.flatten(array);
		  var newArray;
	
		  var product = function product(arr) {
		    return arr.reduce(function (prev, curr) {
		      return prev * curr;
		    });
		  };
	
		  if (!Array.isArray(array) || !Array.isArray(sizes)) {
		    throw new TypeError('Array expected');
		  }
	
		  if (sizes.length === 0) {
		    throw new DimensionError(0, product(exports.size(array)), '!=');
		  }
	
		  try {
		    newArray = _reshape(flatArray, sizes);
		  } catch (e) {
		    if (e instanceof DimensionError) {
		      throw new DimensionError(product(sizes), product(exports.size(array)), '!=');
		    }
		    throw e;
		  }
	
		  if (flatArray.length > 0) {
		    throw new DimensionError(product(sizes), product(exports.size(array)), '!=');
		  }
	
		  return newArray;
		};
	
		/**
		 * Recursively re-shape a multi dimensional array to fit the specified dimensions
		 * @param {Array} array           Array to be reshaped
		 * @param {Array.<number>} sizes  List of sizes for each dimension
		 * @returns {Array}               Array whose data has been formatted to fit the
		 *                                specified dimensions
		 *
		 * @throws {DimensionError}       If the product of the new dimension sizes does
		 *                                not equal that of the old ones
		 */
		function _reshape(array, sizes) {
		  var accumulator = [];
		  var i;
	
		  if (sizes.length === 0) {
		    if (array.length === 0) {
		      throw new DimensionError(null, null, '!=');
		    }
		    return array.shift();
		  }
		  for (i = 0; i < sizes[0]; i += 1) {
		    accumulator.push(_reshape(array, sizes.slice(1)));
		  }
		  return accumulator;
		}
	
		/**
		 * Squeeze a multi dimensional array
		 * @param {Array} array
		 * @param {Array} [size]
		 * @returns {Array} returns the array itself
		 */
		exports.squeeze = function (array, size) {
		  var s = size || exports.size(array);
	
		  // squeeze outer dimensions
		  while (Array.isArray(array) && array.length === 1) {
		    array = array[0];
		    s.shift();
		  }
	
		  // find the first dimension to be squeezed
		  var dims = s.length;
		  while (s[dims - 1] === 1) {
		    dims--;
		  }
	
		  // squeeze inner dimensions
		  if (dims < s.length) {
		    array = _squeeze(array, dims, 0);
		    s.length = dims;
		  }
	
		  return array;
		};
	
		/**
		 * Recursively squeeze a multi dimensional array
		 * @param {Array} array
		 * @param {number} dims Required number of dimensions
		 * @param {number} dim  Current dimension
		 * @returns {Array | *} Returns the squeezed array
		 * @private
		 */
		function _squeeze(array, dims, dim) {
		  var i, ii;
	
		  if (dim < dims) {
		    var next = dim + 1;
		    for (i = 0, ii = array.length; i < ii; i++) {
		      array[i] = _squeeze(array[i], dims, next);
		    }
		  } else {
		    while (Array.isArray(array)) {
		      array = array[0];
		    }
		  }
	
		  return array;
		}
	
		/**
		 * Unsqueeze a multi dimensional array: add dimensions when missing
		 * 
		 * Paramter `size` will be mutated to match the new, unqueezed matrix size.
		 * 
		 * @param {Array} array
		 * @param {number} dims     Desired number of dimensions of the array
		 * @param {number} [outer]  Number of outer dimensions to be added
		 * @param {Array} [size]    Current size of array.
		 * @returns {Array} returns the array itself
		 * @private
		 */
		exports.unsqueeze = function (array, dims, outer, size) {
		  var s = size || exports.size(array);
	
		  // unsqueeze outer dimensions
		  if (outer) {
		    for (var i = 0; i < outer; i++) {
		      array = [array];
		      s.unshift(1);
		    }
		  }
	
		  // unsqueeze inner dimensions
		  array = _unsqueeze(array, dims, 0);
		  while (s.length < dims) {
		    s.push(1);
		  }
	
		  return array;
		};
	
		/**
		 * Recursively unsqueeze a multi dimensional array
		 * @param {Array} array
		 * @param {number} dims Required number of dimensions
		 * @param {number} dim  Current dimension
		 * @returns {Array | *} Returns the squeezed array
		 * @private
		 */
		function _unsqueeze(array, dims, dim) {
		  var i, ii;
	
		  if (Array.isArray(array)) {
		    var next = dim + 1;
		    for (i = 0, ii = array.length; i < ii; i++) {
		      array[i] = _unsqueeze(array[i], dims, next);
		    }
		  } else {
		    for (var d = dim; d < dims; d++) {
		      array = [array];
		    }
		  }
	
		  return array;
		}
		/**
		 * Flatten a multi dimensional array, put all elements in a one dimensional
		 * array
		 * @param {Array} array   A multi dimensional array
		 * @return {Array}        The flattened array (1 dimensional)
		 */
		exports.flatten = function (array) {
		  if (!Array.isArray(array)) {
		    //if not an array, return as is
		    return array;
		  }
		  var flat = [];
	
		  array.forEach(function callback(value) {
		    if (Array.isArray(value)) {
		      value.forEach(callback); //traverse through sub-arrays recursively
		    } else {
		      flat.push(value);
		    }
		  });
	
		  return flat;
		};
	
		/**
		 * A safe map
		 * @param {Array} array
		 * @param {function} callback
		 */
		exports.map = function (array, callback) {
		  return Array.prototype.map.call(array, callback);
		};
	
		/**
		 * A safe forEach
		 * @param {Array} array
		 * @param {function} callback
		 */
		exports.forEach = function (array, callback) {
		  Array.prototype.forEach.call(array, callback);
		};
	
		/**
		 * A safe filter
		 * @param {Array} array
		 * @param {function} callback
		 */
		exports.filter = function (array, callback) {
		  if (exports.size(array).length !== 1) {
		    throw new Error('Only one dimensional matrices supported');
		  }
	
		  return Array.prototype.filter.call(array, callback);
		};
	
		/**
		 * Filter values in a callback given a regular expression
		 * @param {Array} array
		 * @param {RegExp} regexp
		 * @return {Array} Returns the filtered array
		 * @private
		 */
		exports.filterRegExp = function (array, regexp) {
		  if (exports.size(array).length !== 1) {
		    throw new Error('Only one dimensional matrices supported');
		  }
	
		  return Array.prototype.filter.call(array, function (entry) {
		    return regexp.test(entry);
		  });
		};
	
		/**
		 * A safe join
		 * @param {Array} array
		 * @param {string} separator
		 */
		exports.join = function (array, separator) {
		  return Array.prototype.join.call(array, separator);
		};
	
		/**
		 * Assign a numeric identifier to every element of a sorted array
		 * @param {Array}	a  An array
		 * @return {Array}	An array of objects containing the original value and its identifier
		 */
		exports.identify = function (a) {
		  if (!Array.isArray(a)) {
		    throw new TypeError('Array input expected');
		  }
	
		  if (a.length === 0) {
		    return a;
		  }
	
		  var b = [];
		  var count = 0;
		  b[0] = { value: a[0], identifier: 0 };
		  for (var i = 1; i < a.length; i++) {
		    if (a[i] === a[i - 1]) {
		      count++;
		    } else {
		      count = 0;
		    }
		    b.push({ value: a[i], identifier: count });
		  }
		  return b;
		};
	
		/**
		 * Remove the numeric identifier from the elements
		 * @param	a  An array
		 * @return	An array of values without identifiers
		 */
		exports.generalize = function (a) {
		  if (!Array.isArray(a)) {
		    throw new TypeError('Array input expected');
		  }
	
		  if (a.length === 0) {
		    return a;
		  }
	
		  var b = [];
		  for (var i = 0; i < a.length; i++) {
		    b.push(a[i].value);
		  }
		  return b;
		};
	
		/**
		 * Test whether an object is an array
		 * @param {*} value
		 * @return {boolean} isArray
		 */
			exports.isArray = Array.isArray;
	
	/***/ }),
	/* 29 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
	
		var formatNumber = __webpack_require__(18).format;
		var formatBigNumber = __webpack_require__(30).format;
		var isBigNumber = __webpack_require__(15);
	
		/**
		 * Test whether value is a string
		 * @param {*} value
		 * @return {boolean} isString
		 */
		exports.isString = function (value) {
		  return typeof value === 'string';
		};
	
		/**
		 * Check if a text ends with a certain string.
		 * @param {string} text
		 * @param {string} search
		 */
		exports.endsWith = function (text, search) {
		  var start = text.length - search.length;
		  var end = text.length;
		  return text.substring(start, end) === search;
		};
	
		/**
		 * Format a value of any type into a string.
		 *
		 * Usage:
		 *     math.format(value)
		 *     math.format(value, precision)
		 *
		 * When value is a function:
		 *
		 * - When the function has a property `syntax`, it returns this
		 *   syntax description.
		 * - In other cases, a string `'function'` is returned.
		 *
		 * When `value` is an Object:
		 *
		 * - When the object contains a property `format` being a function, this
		 *   function is invoked as `value.format(options)` and the result is returned.
		 * - When the object has its own `toString` method, this method is invoked
		 *   and the result is returned.
		 * - In other cases the function will loop over all object properties and
		 *   return JSON object notation like '{"a": 2, "b": 3}'.
		 *
		 * Example usage:
		 *     math.format(2/7);                // '0.2857142857142857'
		 *     math.format(math.pi, 3);         // '3.14'
		 *     math.format(new Complex(2, 3));  // '2 + 3i'
		 *     math.format('hello');            // '"hello"'
		 *
		 * @param {*} value             Value to be stringified
		 * @param {Object | number | Function} [options]  Formatting options. See
		 *                                                lib/utils/number:format for a
		 *                                                description of the available
		 *                                                options.
		 * @return {string} str
		 */
		exports.format = function (value, options) {
		  if (typeof value === 'number') {
		    return formatNumber(value, options);
		  }
	
		  if (isBigNumber(value)) {
		    return formatBigNumber(value, options);
		  }
	
		  // note: we use unsafe duck-typing here to check for Fractions, this is
		  // ok here since we're only invoking toString or concatenating its values
		  if (looksLikeFraction(value)) {
		    if (!options || options.fraction !== 'decimal') {
		      // output as ratio, like '1/3'
		      return value.s * value.n + '/' + value.d;
		    } else {
		      // output as decimal, like '0.(3)'
		      return value.toString();
		    }
		  }
	
		  if (Array.isArray(value)) {
		    return formatArray(value, options);
		  }
	
		  if (exports.isString(value)) {
		    return '"' + value + '"';
		  }
	
		  if (typeof value === 'function') {
		    return value.syntax ? String(value.syntax) : 'function';
		  }
	
		  if (value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object') {
		    if (typeof value.format === 'function') {
		      return value.format(options);
		    } else if (value && value.toString() !== {}.toString()) {
		      // this object has a non-native toString method, use that one
		      return value.toString();
		    } else {
		      var entries = [];
	
		      for (var key in value) {
		        if (value.hasOwnProperty(key)) {
		          entries.push('"' + key + '": ' + exports.format(value[key], options));
		        }
		      }
	
		      return '{' + entries.join(', ') + '}';
		    }
		  }
	
		  return String(value);
		};
	
		/**
		 * Stringify a value into a string enclosed in double quotes.
		 * Unescaped double quotes and backslashes inside the value are escaped.
		 * @param {*} value
		 * @return {string}
		 */
		exports.stringify = function (value) {
		  var text = String(value);
		  var escaped = '';
		  var i = 0;
		  while (i < text.length) {
		    var c = text.charAt(i);
	
		    if (c === '\\') {
		      escaped += c;
		      i++;
	
		      c = text.charAt(i);
		      if (c === '' || '"\\/bfnrtu'.indexOf(c) === -1) {
		        escaped += '\\'; // no valid escape character -> escape it
		      }
		      escaped += c;
		    } else if (c === '"') {
		      escaped += '\\"';
		    } else {
		      escaped += c;
		    }
		    i++;
		  }
	
		  return '"' + escaped + '"';
		};
	
		/**
		 * Escape special HTML characters
		 * @param {*} value
		 * @return {string}
		 */
		exports.escape = function (value) {
		  var text = String(value);
		  text = text.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
	
		  return text;
		};
	
		/**
		 * Recursively format an n-dimensional matrix
		 * Example output: "[[1, 2], [3, 4]]"
		 * @param {Array} array
		 * @param {Object | number | Function} [options]  Formatting options. See
		 *                                                lib/utils/number:format for a
		 *                                                description of the available
		 *                                                options.
		 * @returns {string} str
		 */
		function formatArray(array, options) {
		  if (Array.isArray(array)) {
		    var str = '[';
		    var len = array.length;
		    for (var i = 0; i < len; i++) {
		      if (i != 0) {
		        str += ', ';
		      }
		      str += formatArray(array[i], options);
		    }
		    str += ']';
		    return str;
		  } else {
		    return exports.format(array, options);
		  }
		}
	
		/**
		 * Check whether a value looks like a Fraction (unsafe duck-type check)
		 * @param {*} value
		 * @return {boolean}
		 */
		function looksLikeFraction(value) {
		  return value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && typeof value.s === 'number' && typeof value.n === 'number' && typeof value.d === 'number' || false;
			}
	
	/***/ }),
	/* 30 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Convert a BigNumber to a formatted string representation.
		 *
		 * Syntax:
		 *
		 *    format(value)
		 *    format(value, options)
		 *    format(value, precision)
		 *    format(value, fn)
		 *
		 * Where:
		 *
		 *    {number} value   The value to be formatted
		 *    {Object} options An object with formatting options. Available options:
		 *                     {string} notation
		 *                         Number notation. Choose from:
		 *                         'fixed'          Always use regular number notation.
		 *                                          For example '123.40' and '14000000'
		 *                         'exponential'    Always use exponential notation.
		 *                                          For example '1.234e+2' and '1.4e+7'
		 *                         'auto' (default) Regular number notation for numbers
		 *                                          having an absolute value between
		 *                                          `lower` and `upper` bounds, and uses
		 *                                          exponential notation elsewhere.
		 *                                          Lower bound is included, upper bound
		 *                                          is excluded.
		 *                                          For example '123.4' and '1.4e7'.
		 *                     {number} precision   A number between 0 and 16 to round
		 *                                          the digits of the number.
		 *                                          In case of notations 'exponential' and
		 *                                          'auto', `precision` defines the total
		 *                                          number of significant digits returned
		 *                                          and is undefined by default.
		 *                                          In case of notation 'fixed',
		 *                                          `precision` defines the number of
		 *                                          significant digits after the decimal
		 *                                          point, and is 0 by default.
		 *                     {Object} exponential An object containing two parameters,
		 *                                          {number} lower and {number} upper,
		 *                                          used by notation 'auto' to determine
		 *                                          when to return exponential notation.
		 *                                          Default values are `lower=1e-3` and
		 *                                          `upper=1e5`.
		 *                                          Only applicable for notation `auto`.
		 *    {Function} fn    A custom formatting function. Can be used to override the
		 *                     built-in notations. Function `fn` is called with `value` as
		 *                     parameter and must return a string. Is useful for example to
		 *                     format all values inside a matrix in a particular way.
		 *
		 * Examples:
		 *
		 *    format(6.4);                                        // '6.4'
		 *    format(1240000);                                    // '1.24e6'
		 *    format(1/3);                                        // '0.3333333333333333'
		 *    format(1/3, 3);                                     // '0.333'
		 *    format(21385, 2);                                   // '21000'
		 *    format(12.071, {notation: 'fixed'});                // '12'
		 *    format(2.3,    {notation: 'fixed', precision: 2});  // '2.30'
		 *    format(52.8,   {notation: 'exponential'});          // '5.28e+1'
		 *
		 * @param {BigNumber} value
		 * @param {Object | Function | number} [options]
		 * @return {string} str The formatted value
		 */
		exports.format = function (value, options) {
		  if (typeof options === 'function') {
		    // handle format(value, fn)
		    return options(value);
		  }
	
		  // handle special cases
		  if (!value.isFinite()) {
		    return value.isNaN() ? 'NaN' : value.gt(0) ? 'Infinity' : '-Infinity';
		  }
	
		  // default values for options
		  var notation = 'auto';
		  var precision = undefined;
	
		  if (options !== undefined) {
		    // determine notation from options
		    if (options.notation) {
		      notation = options.notation;
		    }
	
		    // determine precision from options
		    if (typeof options === 'number') {
		      precision = options;
		    } else if (options.precision) {
		      precision = options.precision;
		    }
		  }
	
		  // handle the various notations
		  switch (notation) {
		    case 'fixed':
		      return exports.toFixed(value, precision);
	
		    case 'exponential':
		      return exports.toExponential(value, precision);
	
		    case 'auto':
		      // determine lower and upper bound for exponential notation.
		      // TODO: implement support for upper and lower to be BigNumbers themselves
		      var lower = 1e-3;
		      var upper = 1e5;
		      if (options && options.exponential) {
		        if (options.exponential.lower !== undefined) {
		          lower = options.exponential.lower;
		        }
		        if (options.exponential.upper !== undefined) {
		          upper = options.exponential.upper;
		        }
		      }
	
		      // adjust the configuration of the BigNumber constructor (yeah, this is quite tricky...)
		      var oldConfig = {
		        toExpNeg: value.constructor.toExpNeg,
		        toExpPos: value.constructor.toExpPos
		      };
	
		      value.constructor.config({
		        toExpNeg: Math.round(Math.log(lower) / Math.LN10),
		        toExpPos: Math.round(Math.log(upper) / Math.LN10)
		      });
	
		      // handle special case zero
		      if (value.isZero()) return '0';
	
		      // determine whether or not to output exponential notation
		      var str;
		      var abs = value.abs();
		      if (abs.gte(lower) && abs.lt(upper)) {
		        // normal number notation
		        str = value.toSignificantDigits(precision).toFixed();
		      } else {
		        // exponential notation
		        str = exports.toExponential(value, precision);
		      }
	
		      // remove trailing zeros after the decimal point
		      return str.replace(/((\.\d*?)(0+))($|e)/, function () {
		        var digits = arguments[2];
		        var e = arguments[4];
		        return digits !== '.' ? digits + e : e;
		      });
	
		    default:
		      throw new Error('Unknown notation "' + notation + '". ' + 'Choose "auto", "exponential", or "fixed".');
		  }
		};
	
		/**
		 * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3'
		 * @param {BigNumber} value
		 * @param {number} [precision]  Number of digits in formatted output.
		 *                              If not provided, the maximum available digits
		 *                              is used.
		 * @returns {string} str
		 */
		exports.toExponential = function (value, precision) {
		  if (precision !== undefined) {
		    return value.toExponential(precision - 1); // Note the offset of one
		  } else {
		    return value.toExponential();
		  }
		};
	
		/**
		 * Format a number with fixed notation.
		 * @param {BigNumber} value
		 * @param {number} [precision=0]        Optional number of decimals after the
		 *                                      decimal point. Zero by default.
		 */
		exports.toFixed = function (value, precision) {
		  return value.toFixed(precision || 0);
		  // Note: the (precision || 0) is needed as the toFixed of BigNumber has an
		  // undefined default precision instead of 0.
		};
	
	/***/ }),
	/* 31 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Determine the type of a variable
		 *
		 *     type(x)
		 *
		 * The following types are recognized:
		 *
		 *     'undefined'
		 *     'null'
		 *     'boolean'
		 *     'number'
		 *     'string'
		 *     'Array'
		 *     'Function'
		 *     'Date'
		 *     'RegExp'
		 *     'Object'
		 *
		 * @param {*} x
		 * @return {string} Returns the name of the type. Primitive types are lower case,
		 *                  non-primitive types are upper-camel-case.
		 *                  For example 'number', 'string', 'Array', 'Date'.
		 */
	
		var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
	
		exports.type = function (x) {
		  var type = typeof x === 'undefined' ? 'undefined' : _typeof(x);
	
		  if (type === 'object') {
		    if (x === null) return 'null';
		    if (Array.isArray(x)) return 'Array';
		    if (x instanceof Date) return 'Date';
		    if (x instanceof RegExp) return 'RegExp';
		    if (x instanceof Boolean) return 'boolean';
		    if (x instanceof Number) return 'number';
		    if (x instanceof String) return 'string';
	
		    return 'Object';
		  }
	
		  if (type === 'function') return 'Function';
	
		  return type;
		};
	
	/***/ }),
	/* 32 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Create a range error with the message:
		 *     'Dimension mismatch (<actual size> != <expected size>)'
		 * @param {number | number[]} actual        The actual size
		 * @param {number | number[]} expected      The expected size
		 * @param {string} [relation='!=']          Optional relation between actual
		 *                                          and expected size: '!=', '<', etc.
		 * @extends RangeError
		 */
	
		function DimensionError(actual, expected, relation) {
		  if (!(this instanceof DimensionError)) {
		    throw new SyntaxError('Constructor must be called with the new operator');
		  }
	
		  this.actual = actual;
		  this.expected = expected;
		  this.relation = relation;
	
		  this.message = 'Dimension mismatch (' + (Array.isArray(actual) ? '[' + actual.join(', ') + ']' : actual) + ' ' + (this.relation || '!=') + ' ' + (Array.isArray(expected) ? '[' + expected.join(', ') + ']' : expected) + ')';
	
		  this.stack = new Error().stack;
		}
	
		DimensionError.prototype = new RangeError();
		DimensionError.prototype.constructor = RangeError;
		DimensionError.prototype.name = 'DimensionError';
		DimensionError.prototype.isDimensionError = true;
	
		module.exports = DimensionError;
	
	/***/ }),
	/* 33 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Create a range error with the message:
		 *     'Index out of range (index < min)'
		 *     'Index out of range (index < max)'
		 *
		 * @param {number} index     The actual index
		 * @param {number} [min=0]   Minimum index (included)
		 * @param {number} [max]     Maximum index (excluded)
		 * @extends RangeError
		 */
	
		function IndexError(index, min, max) {
		  if (!(this instanceof IndexError)) {
		    throw new SyntaxError('Constructor must be called with the new operator');
		  }
	
		  this.index = index;
		  if (arguments.length < 3) {
		    this.min = 0;
		    this.max = min;
		  } else {
		    this.min = min;
		    this.max = max;
		  }
	
		  if (this.min !== undefined && this.index < this.min) {
		    this.message = 'Index out of range (' + this.index + ' < ' + this.min + ')';
		  } else if (this.max !== undefined && this.index >= this.max) {
		    this.message = 'Index out of range (' + this.index + ' > ' + (this.max - 1) + ')';
		  } else {
		    this.message = 'Index out of range (' + this.index + ')';
		  }
	
		  this.stack = new Error().stack;
		}
	
		IndexError.prototype = new RangeError();
		IndexError.prototype.constructor = RangeError;
		IndexError.prototype.name = 'IndexError';
		IndexError.prototype.isIndexError = true;
	
		module.exports = IndexError;
	
	/***/ }),
	/* 34 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Test whether value is a boolean
		 * @param {*} value
		 * @return {boolean} isBoolean
		 */
	
		exports.isBoolean = function (value) {
		  return typeof value == 'boolean';
		};
	
	/***/ }),
	/* 35 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
	
		// function utils
	
		/**
		 * Memoize a given function by caching the computed result.
		 * The cache of a memoized function can be cleared by deleting the `cache`
		 * property of the function.
		 *
		 * @param {function} fn                     The function to be memoized.
		 *                                          Must be a pure function.
		 * @param {function(args: Array)} [hasher]  A custom hash builder.
		 *                                          Is JSON.stringify by default.
		 * @return {function}                       Returns the memoized function
		 */
		exports.memoize = function (fn, hasher) {
		  return function memoize() {
		    if (_typeof(memoize.cache) !== 'object') {
		      memoize.cache = {};
		    }
	
		    var args = [];
		    for (var i = 0; i < arguments.length; i++) {
		      args[i] = arguments[i];
		    }
	
		    var hash = hasher ? hasher(args) : JSON.stringify(args);
		    if (!(hash in memoize.cache)) {
		      return memoize.cache[hash] = fn.apply(fn, args);
		    }
		    return memoize.cache[hash];
		  };
		};
	
		/**
		 * Find the maximum number of arguments expected by a typed function.
		 * @param {function} fn   A typed function
		 * @return {number} Returns the maximum number of expected arguments.
		 *                  Returns -1 when no signatures where found on the function.
		 */
		exports.maxArgumentCount = function (fn) {
		  return Object.keys(fn.signatures || {}).reduce(function (args, signature) {
		    var count = (signature.match(/,/g) || []).length + 1;
		    return Math.max(args, count);
		  }, -1);
		};
	
		/**
		 * Call a typed function with the
		 * @param {function} fn   A function or typed function
		 * @return {number} Returns the maximum number of expected arguments.
		 *                  Returns -1 when no signatures where found on the function.
		 */
		exports.callWithRightArgumentCount = function (fn, args, argCount) {
		  return Object.keys(fn.signatures || {}).reduce(function (args, signature) {
		    var count = (signature.match(/,/g) || []).length + 1;
		    return Math.max(args, count);
		  }, -1);
		};
	
	/***/ }),
	/* 36 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var util = __webpack_require__(27);
		var DimensionError = __webpack_require__(32);
		var getSafeProperty = __webpack_require__(37).getSafeProperty;
		var setSafeProperty = __webpack_require__(37).setSafeProperty;
	
		var string = util.string;
		var array = util.array;
		var object = util.object;
		var number = util.number;
	
		var isArray = Array.isArray;
		var isNumber = number.isNumber;
		var isInteger = number.isInteger;
		var isString = string.isString;
	
		var validateIndex = array.validateIndex;
	
		function factory(type, config, load, typed) {
		  var Matrix = load(__webpack_require__(26)); // force loading Matrix (do not use via type.Matrix)
	
		  /**
		   * Dense Matrix implementation. A regular, dense matrix, supporting multi-dimensional matrices. This is the default matrix type.
		   * @class DenseMatrix
		   */
		  function DenseMatrix(data, datatype) {
		    if (!(this instanceof DenseMatrix)) throw new SyntaxError('Constructor must be called with the new operator');
		    if (datatype && !isString(datatype)) throw new Error('Invalid datatype: ' + datatype);
	
		    if (type.isMatrix(data)) {
		      // check data is a DenseMatrix
		      if (data.type === 'DenseMatrix') {
		        // clone data & size
		        this._data = object.clone(data._data);
		        this._size = object.clone(data._size);
		        this._datatype = datatype || data._datatype;
		      } else {
		        // build data from existing matrix
		        this._data = data.toArray();
		        this._size = data.size();
		        this._datatype = datatype || data._datatype;
		      }
		    } else if (data && isArray(data.data) && isArray(data.size)) {
		      // initialize fields from JSON representation
		      this._data = data.data;
		      this._size = data.size;
		      this._datatype = datatype || data.datatype;
		    } else if (isArray(data)) {
		      // replace nested Matrices with Arrays
		      this._data = preprocess(data);
		      // get the dimensions of the array
		      this._size = array.size(this._data);
		      // verify the dimensions of the array, TODO: compute size while processing array
		      array.validate(this._data, this._size);
		      // data type unknown
		      this._datatype = datatype;
		    } else if (data) {
		      // unsupported type
		      throw new TypeError('Unsupported type of data (' + util.types.type(data) + ')');
		    } else {
		      // nothing provided
		      this._data = [];
		      this._size = [0];
		      this._datatype = datatype;
		    }
		  }
	
		  DenseMatrix.prototype = new Matrix();
	
		  /**
		   * Attach type information
		   */
		  DenseMatrix.prototype.type = 'DenseMatrix';
		  DenseMatrix.prototype.isDenseMatrix = true;
	
		  /**
		   * Get the storage format used by the matrix.
		   *
		   * Usage:
		   *     var format = matrix.storage()                   // retrieve storage format
		   *
		   * @memberof DenseMatrix
		   * @return {string}           The storage format.
		   */
		  DenseMatrix.prototype.storage = function () {
		    return 'dense';
		  };
	
		  /**
		   * Get the datatype of the data stored in the matrix.
		   *
		   * Usage:
		   *     var format = matrix.datatype()                   // retrieve matrix datatype
		   *
		   * @memberof DenseMatrix
		   * @return {string}           The datatype.
		   */
		  DenseMatrix.prototype.datatype = function () {
		    return this._datatype;
		  };
	
		  /**
		   * Create a new DenseMatrix
		   * @memberof DenseMatrix
		   * @param {Array} data
		   * @param {string} [datatype]
		   */
		  DenseMatrix.prototype.create = function (data, datatype) {
		    return new DenseMatrix(data, datatype);
		  };
	
		  /**
		   * Get a subset of the matrix, or replace a subset of the matrix.
		   *
		   * Usage:
		   *     var subset = matrix.subset(index)               // retrieve subset
		   *     var value = matrix.subset(index, replacement)   // replace subset
		   *
		   * @memberof DenseMatrix
		   * @param {Index} index
		   * @param {Array | DenseMatrix | *} [replacement]
		   * @param {*} [defaultValue=0]      Default value, filled in on new entries when
		   *                                  the matrix is resized. If not provided,
		   *                                  new matrix elements will be filled with zeros.
		   */
		  DenseMatrix.prototype.subset = function (index, replacement, defaultValue) {
		    switch (arguments.length) {
		      case 1:
		        return _get(this, index);
	
		      // intentional fall through
		      case 2:
		      case 3:
		        return _set(this, index, replacement, defaultValue);
	
		      default:
		        throw new SyntaxError('Wrong number of arguments');
		    }
		  };
	
		  /**
		   * Get a single element from the matrix.
		   * @memberof DenseMatrix
		   * @param {number[]} index   Zero-based index
		   * @return {*} value
		   */
		  DenseMatrix.prototype.get = function (index) {
		    if (!isArray(index)) throw new TypeError('Array expected');
		    if (index.length != this._size.length) throw new DimensionError(index.length, this._size.length);
	
		    // check index
		    for (var x = 0; x < index.length; x++) {
		      validateIndex(index[x], this._size[x]);
		    }var data = this._data;
		    for (var i = 0, ii = index.length; i < ii; i++) {
		      var index_i = index[i];
		      validateIndex(index_i, data.length);
		      data = data[index_i];
		    }
	
		    return data;
		  };
	
		  /**
		   * Replace a single element in the matrix.
		   * @memberof DenseMatrix
		   * @param {number[]} index   Zero-based index
		   * @param {*} value
		   * @param {*} [defaultValue]        Default value, filled in on new entries when
		   *                                  the matrix is resized. If not provided,
		   *                                  new matrix elements will be left undefined.
		   * @return {DenseMatrix} self
		   */
		  DenseMatrix.prototype.set = function (index, value, defaultValue) {
		    if (!isArray(index)) throw new TypeError('Array expected');
		    if (index.length < this._size.length) throw new DimensionError(index.length, this._size.length, '<');
	
		    var i, ii, index_i;
	
		    // enlarge matrix when needed
		    var size = index.map(function (i) {
		      return i + 1;
		    });
		    _fit(this, size, defaultValue);
	
		    // traverse over the dimensions
		    var data = this._data;
		    for (i = 0, ii = index.length - 1; i < ii; i++) {
		      index_i = index[i];
		      validateIndex(index_i, data.length);
		      data = data[index_i];
		    }
	
		    // set new value
		    index_i = index[index.length - 1];
		    validateIndex(index_i, data.length);
		    data[index_i] = value;
	
		    return this;
		  };
	
		  /**
		   * Get a submatrix of this matrix
		   * @memberof DenseMatrix
		   * @param {DenseMatrix} matrix
		   * @param {Index} index   Zero-based index
		   * @private
		   */
		  function _get(matrix, index) {
		    if (!type.isIndex(index)) {
		      throw new TypeError('Invalid index');
		    }
	
		    var isScalar = index.isScalar();
		    if (isScalar) {
		      // return a scalar
		      return matrix.get(index.min());
		    } else {
		      // validate dimensions
		      var size = index.size();
		      if (size.length != matrix._size.length) {
		        throw new DimensionError(size.length, matrix._size.length);
		      }
	
		      // validate if any of the ranges in the index is out of range
		      var min = index.min();
		      var max = index.max();
		      for (var i = 0, ii = matrix._size.length; i < ii; i++) {
		        validateIndex(min[i], matrix._size[i]);
		        validateIndex(max[i], matrix._size[i]);
		      }
	
		      // retrieve submatrix
		      // TODO: more efficient when creating an empty matrix and setting _data and _size manually
		      return new DenseMatrix(_getSubmatrix(matrix._data, index, size.length, 0), matrix._datatype);
		    }
		  }
	
		  /**
		   * Recursively get a submatrix of a multi dimensional matrix.
		   * Index is not checked for correct number or length of dimensions.
		   * @memberof DenseMatrix
		   * @param {Array} data
		   * @param {Index} index
		   * @param {number} dims   Total number of dimensions
		   * @param {number} dim    Current dimension
		   * @return {Array} submatrix
		   * @private
		   */
		  function _getSubmatrix(data, index, dims, dim) {
		    var last = dim === dims - 1;
		    var range = index.dimension(dim);
	
		    if (last) {
		      return range.map(function (i) {
		        validateIndex(i, data.length);
		        return data[i];
		      }).valueOf();
		    } else {
		      return range.map(function (i) {
		        validateIndex(i, data.length);
		        var child = data[i];
		        return _getSubmatrix(child, index, dims, dim + 1);
		      }).valueOf();
		    }
		  }
	
		  /**
		   * Replace a submatrix in this matrix
		   * Indexes are zero-based.
		   * @memberof DenseMatrix
		   * @param {DenseMatrix} matrix
		   * @param {Index} index
		   * @param {DenseMatrix | Array | *} submatrix
		   * @param {*} defaultValue          Default value, filled in on new entries when
		   *                                  the matrix is resized.
		   * @return {DenseMatrix} matrix
		   * @private
		   */
		  function _set(matrix, index, submatrix, defaultValue) {
		    if (!index || index.isIndex !== true) {
		      throw new TypeError('Invalid index');
		    }
	
		    // get index size and check whether the index contains a single value
		    var iSize = index.size(),
		        isScalar = index.isScalar();
	
		    // calculate the size of the submatrix, and convert it into an Array if needed
		    var sSize;
		    if (type.isMatrix(submatrix)) {
		      sSize = submatrix.size();
		      submatrix = submatrix.valueOf();
		    } else {
		      sSize = array.size(submatrix);
		    }
	
		    if (isScalar) {
		      // set a scalar
	
		      // check whether submatrix is a scalar
		      if (sSize.length !== 0) {
		        throw new TypeError('Scalar expected');
		      }
	
		      matrix.set(index.min(), submatrix, defaultValue);
		    } else {
		      // set a submatrix
	
		      // validate dimensions
		      if (iSize.length < matrix._size.length) {
		        throw new DimensionError(iSize.length, matrix._size.length, '<');
		      }
	
		      if (sSize.length < iSize.length) {
		        // calculate number of missing outer dimensions
		        var i = 0;
		        var outer = 0;
		        while (iSize[i] === 1 && sSize[i] === 1) {
		          i++;
		        }
		        while (iSize[i] === 1) {
		          outer++;
		          i++;
		        }
	
		        // unsqueeze both outer and inner dimensions
		        submatrix = array.unsqueeze(submatrix, iSize.length, outer, sSize);
		      }
	
		      // check whether the size of the submatrix matches the index size
		      if (!object.deepEqual(iSize, sSize)) {
		        throw new DimensionError(iSize, sSize, '>');
		      }
	
		      // enlarge matrix when needed
		      var size = index.max().map(function (i) {
		        return i + 1;
		      });
		      _fit(matrix, size, defaultValue);
	
		      // insert the sub matrix
		      var dims = iSize.length,
		          dim = 0;
		      _setSubmatrix(matrix._data, index, submatrix, dims, dim);
		    }
	
		    return matrix;
		  }
	
		  /**
		   * Replace a submatrix of a multi dimensional matrix.
		   * @memberof DenseMatrix
		   * @param {Array} data
		   * @param {Index} index
		   * @param {Array} submatrix
		   * @param {number} dims   Total number of dimensions
		   * @param {number} dim
		   * @private
		   */
		  function _setSubmatrix(data, index, submatrix, dims, dim) {
		    var last = dim === dims - 1,
		        range = index.dimension(dim);
	
		    if (last) {
		      range.forEach(function (dataIndex, subIndex) {
		        validateIndex(dataIndex);
		        data[dataIndex] = submatrix[subIndex[0]];
		      });
		    } else {
		      range.forEach(function (dataIndex, subIndex) {
		        validateIndex(dataIndex);
		        _setSubmatrix(data[dataIndex], index, submatrix[subIndex[0]], dims, dim + 1);
		      });
		    }
		  }
	
		  /**
		   * Resize the matrix to the given size. Returns a copy of the matrix when
		   * `copy=true`, otherwise return the matrix itself (resize in place).
		   *
		   * @memberof DenseMatrix
		   * @param {number[]} size           The new size the matrix should have.
		   * @param {*} [defaultValue=0]      Default value, filled in on new entries.
		   *                                  If not provided, the matrix elements will
		   *                                  be filled with zeros.
		   * @param {boolean} [copy]          Return a resized copy of the matrix
		   *
		   * @return {Matrix}                 The resized matrix
		   */
		  DenseMatrix.prototype.resize = function (size, defaultValue, copy) {
		    // validate arguments
		    if (!isArray(size)) throw new TypeError('Array expected');
	
		    // matrix to resize
		    var m = copy ? this.clone() : this;
		    // resize matrix
		    return _resize(m, size, defaultValue);
		  };
	
		  var _resize = function _resize(matrix, size, defaultValue) {
		    // check size
		    if (size.length === 0) {
		      // first value in matrix
		      var v = matrix._data;
		      // go deep
		      while (isArray(v)) {
		        v = v[0];
		      }
		      return v;
		    }
		    // resize matrix
		    matrix._size = size.slice(0); // copy the array
		    matrix._data = array.resize(matrix._data, matrix._size, defaultValue);
		    // return matrix
		    return matrix;
		  };
	
		  /**
		   * Reshape the matrix to the given size. Returns a copy of the matrix when
		   * `copy=true`, otherwise return the matrix itself (reshape in place).
		   *
		   * NOTE: This might be better suited to copy by default, instead of modifying
		   *       in place. For now, it operates in place to remain consistent with
		   *       resize().
		   *
		   * @memberof DenseMatrix
		   * @param {number[]} size           The new size the matrix should have.
		   * @param {boolean} [copy]          Return a reshaped copy of the matrix
		   *
		   * @return {Matrix}                 The reshaped matrix
		   */
		  DenseMatrix.prototype.reshape = function (size, copy) {
		    var m = copy ? this.clone() : this;
	
		    m._data = array.reshape(m._data, size);
		    m._size = size.slice(0);
		    return m;
		  };
	
		  /**
		   * Enlarge the matrix when it is smaller than given size.
		   * If the matrix is larger or equal sized, nothing is done.
		   * @memberof DenseMatrix
		   * @param {DenseMatrix} matrix           The matrix to be resized
		   * @param {number[]} size
		   * @param {*} defaultValue          Default value, filled in on new entries.
		   * @private
		   */
		  function _fit(matrix, size, defaultValue) {
		    var newSize = matrix._size.slice(0),
		        // copy the array
		    changed = false;
	
		    // add dimensions when needed
		    while (newSize.length < size.length) {
		      newSize.push(0);
		      changed = true;
		    }
	
		    // enlarge size when needed
		    for (var i = 0, ii = size.length; i < ii; i++) {
		      if (size[i] > newSize[i]) {
		        newSize[i] = size[i];
		        changed = true;
		      }
		    }
	
		    if (changed) {
		      // resize only when size is changed
		      _resize(matrix, newSize, defaultValue);
		    }
		  }
	
		  /**
		   * Create a clone of the matrix
		   * @memberof DenseMatrix
		   * @return {DenseMatrix} clone
		   */
		  DenseMatrix.prototype.clone = function () {
		    var m = new DenseMatrix({
		      data: object.clone(this._data),
		      size: object.clone(this._size),
		      datatype: this._datatype
		    });
		    return m;
		  };
	
		  /**
		   * Retrieve the size of the matrix.
		   * @memberof DenseMatrix
		   * @returns {number[]} size
		   */
		  DenseMatrix.prototype.size = function () {
		    return this._size.slice(0); // return a clone of _size
		  };
	
		  /**
		   * Create a new matrix with the results of the callback function executed on
		   * each entry of the matrix.
		   * @memberof DenseMatrix
		   * @param {Function} callback   The callback function is invoked with three
		   *                              parameters: the value of the element, the index
		   *                              of the element, and the Matrix being traversed.
		   *
		   * @return {DenseMatrix} matrix
		   */
		  DenseMatrix.prototype.map = function (callback) {
		    // matrix instance
		    var me = this;
		    var recurse = function recurse(value, index) {
		      if (isArray(value)) {
		        return value.map(function (child, i) {
		          return recurse(child, index.concat(i));
		        });
		      } else {
		        return callback(value, index, me);
		      }
		    };
		    // return dense format
		    return new DenseMatrix({
		      data: recurse(this._data, []),
		      size: object.clone(this._size),
		      datatype: this._datatype
		    });
		  };
	
		  /**
		   * Execute a callback function on each entry of the matrix.
		   * @memberof DenseMatrix
		   * @param {Function} callback   The callback function is invoked with three
		   *                              parameters: the value of the element, the index
		   *                              of the element, and the Matrix being traversed.
		   */
		  DenseMatrix.prototype.forEach = function (callback) {
		    // matrix instance
		    var me = this;
		    var recurse = function recurse(value, index) {
		      if (isArray(value)) {
		        value.forEach(function (child, i) {
		          recurse(child, index.concat(i));
		        });
		      } else {
		        callback(value, index, me);
		      }
		    };
		    recurse(this._data, []);
		  };
	
		  /**
		   * Create an Array with a copy of the data of the DenseMatrix
		   * @memberof DenseMatrix
		   * @returns {Array} array
		   */
		  DenseMatrix.prototype.toArray = function () {
		    return object.clone(this._data);
		  };
	
		  /**
		   * Get the primitive value of the DenseMatrix: a multidimensional array
		   * @memberof DenseMatrix
		   * @returns {Array} array
		   */
		  DenseMatrix.prototype.valueOf = function () {
		    return this._data;
		  };
	
		  /**
		   * Get a string representation of the matrix, with optional formatting options.
		   * @memberof DenseMatrix
		   * @param {Object | number | Function} [options]  Formatting options. See
		   *                                                lib/utils/number:format for a
		   *                                                description of the available
		   *                                                options.
		   * @returns {string} str
		   */
		  DenseMatrix.prototype.format = function (options) {
		    return string.format(this._data, options);
		  };
	
		  /**
		   * Get a string representation of the matrix
		   * @memberof DenseMatrix
		   * @returns {string} str
		   */
		  DenseMatrix.prototype.toString = function () {
		    return string.format(this._data);
		  };
	
		  /**
		   * Get a JSON representation of the matrix
		   * @memberof DenseMatrix
		   * @returns {Object}
		   */
		  DenseMatrix.prototype.toJSON = function () {
		    return {
		      mathjs: 'DenseMatrix',
		      data: this._data,
		      size: this._size,
		      datatype: this._datatype
		    };
		  };
	
		  /**
		   * Get the kth Matrix diagonal.
		   *
		   * @memberof DenseMatrix
		   * @param {number | BigNumber} [k=0]     The kth diagonal where the vector will retrieved.
		   *
		   * @returns {Array}                      The array vector with the diagonal values.
		   */
		  DenseMatrix.prototype.diagonal = function (k) {
		    // validate k if any
		    if (k) {
		      // convert BigNumber to a number
		      if (type.isBigNumber(k)) k = k.toNumber();
		      // is must be an integer
		      if (!isNumber(k) || !isInteger(k)) {
		        throw new TypeError('The parameter k must be an integer number');
		      }
		    } else {
		      // default value
		      k = 0;
		    }
	
		    var kSuper = k > 0 ? k : 0;
		    var kSub = k < 0 ? -k : 0;
	
		    // rows & columns
		    var rows = this._size[0];
		    var columns = this._size[1];
	
		    // number diagonal values
		    var n = Math.min(rows - kSub, columns - kSuper);
	
		    // x is a matrix get diagonal from matrix
		    var data = [];
	
		    // loop rows
		    for (var i = 0; i < n; i++) {
		      data[i] = this._data[i + kSub][i + kSuper];
		    }
	
		    // create DenseMatrix
		    return new DenseMatrix({
		      data: data,
		      size: [n],
		      datatype: this._datatype
		    });
		  };
	
		  /**
		   * Create a diagonal matrix.
		   *
		   * @memberof DenseMatrix
		   * @param {Array} size                   The matrix size.
		   * @param {number | Array} value          The values for the diagonal.
		   * @param {number | BigNumber} [k=0]     The kth diagonal where the vector will be filled in.
		   * @param {number} [defaultValue]        The default value for non-diagonal
		   *
		   * @returns {DenseMatrix}
		   */
		  DenseMatrix.diagonal = function (size, value, k, defaultValue, datatype) {
		    if (!isArray(size)) throw new TypeError('Array expected, size parameter');
		    if (size.length !== 2) throw new Error('Only two dimensions matrix are supported');
	
		    // map size & validate
		    size = size.map(function (s) {
		      // check it is a big number
		      if (type.isBigNumber(s)) {
		        // convert it
		        s = s.toNumber();
		      }
		      // validate arguments
		      if (!isNumber(s) || !isInteger(s) || s < 1) {
		        throw new Error('Size values must be positive integers');
		      }
		      return s;
		    });
	
		    // validate k if any
		    if (k) {
		      // convert BigNumber to a number
		      if (type.isBigNumber(k)) k = k.toNumber();
		      // is must be an integer
		      if (!isNumber(k) || !isInteger(k)) {
		        throw new TypeError('The parameter k must be an integer number');
		      }
		    } else {
		      // default value
		      k = 0;
		    }
	
		    if (defaultValue && isString(datatype)) {
		      // convert defaultValue to the same datatype
		      defaultValue = typed.convert(defaultValue, datatype);
		    }
	
		    var kSuper = k > 0 ? k : 0;
		    var kSub = k < 0 ? -k : 0;
	
		    // rows and columns
		    var rows = size[0];
		    var columns = size[1];
	
		    // number of non-zero items
		    var n = Math.min(rows - kSub, columns - kSuper);
	
		    // value extraction function
		    var _value;
	
		    // check value
		    if (isArray(value)) {
		      // validate array
		      if (value.length !== n) {
		        // number of values in array must be n
		        throw new Error('Invalid value array length');
		      }
		      // define function
		      _value = function _value(i) {
		        // return value @ i
		        return value[i];
		      };
		    } else if (type.isMatrix(value)) {
		      // matrix size
		      var ms = value.size();
		      // validate matrix
		      if (ms.length !== 1 || ms[0] !== n) {
		        // number of values in array must be n
		        throw new Error('Invalid matrix length');
		      }
		      // define function
		      _value = function _value(i) {
		        // return value @ i
		        return value.get([i]);
		      };
		    } else {
		      // define function
		      _value = function _value() {
		        // return value
		        return value;
		      };
		    }
	
		    // discover default value if needed
		    if (!defaultValue) {
		      // check first value in array
		      defaultValue = type.isBigNumber(_value(0)) ? new type.BigNumber(0) : 0;
		    }
	
		    // empty array
		    var data = [];
	
		    // check we need to resize array
		    if (size.length > 0) {
		      // resize array
		      data = array.resize(data, size, defaultValue);
		      // fill diagonal
		      for (var d = 0; d < n; d++) {
		        data[d + kSub][d + kSuper] = _value(d);
		      }
		    }
	
		    // create DenseMatrix
		    return new DenseMatrix({
		      data: data,
		      size: [rows, columns]
		    });
		  };
	
		  /**
		   * Generate a matrix from a JSON object
		   * @memberof DenseMatrix
		   * @param {Object} json  An object structured like
		   *                       `{"mathjs": "DenseMatrix", data: [], size: []}`,
		   *                       where mathjs is optional
		   * @returns {DenseMatrix}
		   */
		  DenseMatrix.fromJSON = function (json) {
		    return new DenseMatrix(json);
		  };
	
		  /**
		   * Swap rows i and j in Matrix.
		   *
		   * @memberof DenseMatrix
		   * @param {number} i       Matrix row index 1
		   * @param {number} j       Matrix row index 2
		   *
		   * @return {Matrix}        The matrix reference
		   */
		  DenseMatrix.prototype.swapRows = function (i, j) {
		    // check index
		    if (!isNumber(i) || !isInteger(i) || !isNumber(j) || !isInteger(j)) {
		      throw new Error('Row index must be positive integers');
		    }
		    // check dimensions
		    if (this._size.length !== 2) {
		      throw new Error('Only two dimensional matrix is supported');
		    }
		    // validate index
		    validateIndex(i, this._size[0]);
		    validateIndex(j, this._size[0]);
	
		    // swap rows
		    DenseMatrix._swapRows(i, j, this._data);
		    // return current instance
		    return this;
		  };
	
		  /**
		   * Swap rows i and j in Dense Matrix data structure.
		   *
		   * @param {number} i       Matrix row index 1
		   * @param {number} j       Matrix row index 2
		   */
		  DenseMatrix._swapRows = function (i, j, data) {
		    // swap values i <-> j
		    var vi = data[i];
		    data[i] = data[j];
		    data[j] = vi;
		  };
	
		  /**
		   * Preprocess data, which can be an Array or DenseMatrix with nested Arrays and
		   * Matrices. Replaces all nested Matrices with Arrays
		   * @memberof DenseMatrix
		   * @param {Array} data
		   * @return {Array} data
		   */
		  function preprocess(data) {
		    for (var i = 0, ii = data.length; i < ii; i++) {
		      var elem = data[i];
		      if (isArray(elem)) {
		        data[i] = preprocess(elem);
		      } else if (elem && elem.isMatrix === true) {
		        data[i] = preprocess(elem.valueOf());
		      }
		    }
	
		    return data;
		  }
	
		  // register this type in the base class Matrix
		  type.Matrix._storage.dense = DenseMatrix;
		  type.Matrix._storage['default'] = DenseMatrix;
	
		  // exports
		  return DenseMatrix;
		}
	
		exports.name = 'DenseMatrix';
		exports.path = 'type';
		exports.factory = factory;
		exports.lazy = false; // no lazy loading, as we alter type.Matrix._storage
	
	/***/ }),
	/* 37 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
	
		var hasOwnProperty = __webpack_require__(14).hasOwnProperty;
	
		/**
		 * Get a property of a plain object
		 * Throws an error in case the object is not a plain object or the
		 * property is not defined on the object itself
		 * @param {Object} object
		 * @param {string} prop
		 * @return {*} Returns the property value when safe
		 */
		function getSafeProperty(object, prop) {
		  // only allow getting safe properties of a plain object
		  if (isPlainObject(object) && isSafeProperty(object, prop)) {
		    return object[prop];
		  }
	
		  if (typeof object[prop] === 'function' && isSafeMethod(object, prop)) {
		    throw new Error('Cannot access method "' + prop + '" as a property');
		  }
	
		  throw new Error('No access to property "' + prop + '"');
		}
	
		/**
		 * Set a property on a plain object.
		 * Throws an error in case the object is not a plain object or the
		 * property would override an inherited property like .constructor or .toString
		 * @param {Object} object
		 * @param {string} prop
		 * @param {*} value
		 * @return {*} Returns the value
		 */
		// TODO: merge this function into access.js?
		function setSafeProperty(object, prop, value) {
		  // only allow setting safe properties of a plain object
		  if (isPlainObject(object) && isSafeProperty(object, prop)) {
		    return object[prop] = value;
		  }
	
		  throw new Error('No access to property "' + prop + '"');
		}
	
		/**
		 * Test whether a property is safe to use for an object.
		 * For example .toString and .constructor are not safe
		 * @param {string} prop
		 * @return {boolean} Returns true when safe
		 */
		function isSafeProperty(object, prop) {
		  if (!object || (typeof object === 'undefined' ? 'undefined' : _typeof(object)) !== 'object') {
		    return false;
		  }
		  // SAFE: whitelisted
		  // e.g length
		  if (hasOwnProperty(safeNativeProperties, prop)) {
		    return true;
		  }
		  // UNSAFE: inherited from Object prototype
		  // e.g constructor
		  if (prop in Object.prototype) {
		    // 'in' is used instead of hasOwnProperty for nodejs v0.10
		    // which is inconsistent on root prototypes. It is safe
		    // here because Object.prototype is a root object
		    return false;
		  }
		  // UNSAFE: inherited from Function prototype
		  // e.g call, apply
		  if (prop in Function.prototype) {
		    // 'in' is used instead of hasOwnProperty for nodejs v0.10
		    // which is inconsistent on root prototypes. It is safe
		    // here because Function.prototype is a root object
		    return false;
		  }
		  return true;
		}
	
		/**
		 * Validate whether a method is safe.
		 * Throws an error when that's not the case.
		 * @param {Object} object
		 * @param {string} method
		 */
		// TODO: merge this function into assign.js?
		function validateSafeMethod(object, method) {
		  if (!isSafeMethod(object, method)) {
		    throw new Error('No access to method "' + method + '"');
		  }
		}
	
		/**
		 * Check whether a method is safe.
		 * Throws an error when that's not the case (for example for `constructor`).
		 * @param {Object} object
		 * @param {string} method
		 * @return {boolean} Returns true when safe, false otherwise
		 */
		function isSafeMethod(object, method) {
		  if (!object || typeof object[method] !== 'function') {
		    return false;
		  }
		  // UNSAFE: ghosted
		  // e.g overridden toString
		  // Note that IE10 doesn't support __proto__ and we can't do this check there.
		  if (hasOwnProperty(object, method) && object.__proto__ && method in object.__proto__) {
		    return false;
		  }
		  // SAFE: whitelisted
		  // e.g toString
		  if (hasOwnProperty(safeNativeMethods, method)) {
		    return true;
		  }
		  // UNSAFE: inherited from Object prototype
		  // e.g constructor
		  if (method in Object.prototype) {
		    // 'in' is used instead of hasOwnProperty for nodejs v0.10
		    // which is inconsistent on root prototypes. It is safe
		    // here because Object.prototype is a root object
		    return false;
		  }
		  // UNSAFE: inherited from Function prototype
		  // e.g call, apply
		  if (method in Function.prototype) {
		    // 'in' is used instead of hasOwnProperty for nodejs v0.10
		    // which is inconsistent on root prototypes. It is safe
		    // here because Function.prototype is a root object
		    return false;
		  }
		  return true;
		}
	
		function isPlainObject(object) {
		  return (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object' && object && object.constructor === Object;
		}
	
		var safeNativeProperties = {
		  length: true,
		  name: true
		};
	
		var safeNativeMethods = {
		  toString: true,
		  valueOf: true,
		  toLocaleString: true
		};
	
		exports.getSafeProperty = getSafeProperty;
		exports.setSafeProperty = setSafeProperty;
		exports.isSafeProperty = isSafeProperty;
		exports.validateSafeMethod = validateSafeMethod;
		exports.isSafeMethod = isSafeMethod;
		exports.isPlainObject = isPlainObject;
	
	/***/ }),
	/* 38 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var util = __webpack_require__(27);
		var DimensionError = __webpack_require__(32);
	
		var array = util.array;
		var object = util.object;
		var string = util.string;
		var number = util.number;
	
		var isArray = Array.isArray;
		var isNumber = number.isNumber;
		var isInteger = number.isInteger;
		var isString = string.isString;
	
		var validateIndex = array.validateIndex;
	
		function factory(type, config, load, typed) {
		  var Matrix = load(__webpack_require__(26)); // force loading Matrix (do not use via type.Matrix)
		  var equalScalar = load(__webpack_require__(39));
	
		  /**
		   * Sparse Matrix implementation. This type implements a Compressed Column Storage format
		   * for sparse matrices.
		   * @class SparseMatrix
		   */
		  function SparseMatrix(data, datatype) {
		    if (!(this instanceof SparseMatrix)) throw new SyntaxError('Constructor must be called with the new operator');
		    if (datatype && !isString(datatype)) throw new Error('Invalid datatype: ' + datatype);
	
		    if (type.isMatrix(data)) {
		      // create from matrix
		      _createFromMatrix(this, data, datatype);
		    } else if (data && isArray(data.index) && isArray(data.ptr) && isArray(data.size)) {
		      // initialize fields
		      this._values = data.values;
		      this._index = data.index;
		      this._ptr = data.ptr;
		      this._size = data.size;
		      this._datatype = datatype || data.datatype;
		    } else if (isArray(data)) {
		      // create from array
		      _createFromArray(this, data, datatype);
		    } else if (data) {
		      // unsupported type
		      throw new TypeError('Unsupported type of data (' + util.types.type(data) + ')');
		    } else {
		      // nothing provided
		      this._values = [];
		      this._index = [];
		      this._ptr = [0];
		      this._size = [0, 0];
		      this._datatype = datatype;
		    }
		  }
	
		  var _createFromMatrix = function _createFromMatrix(matrix, source, datatype) {
		    // check matrix type
		    if (source.type === 'SparseMatrix') {
		      // clone arrays
		      matrix._values = source._values ? object.clone(source._values) : undefined;
		      matrix._index = object.clone(source._index);
		      matrix._ptr = object.clone(source._ptr);
		      matrix._size = object.clone(source._size);
		      matrix._datatype = datatype || source._datatype;
		    } else {
		      // build from matrix data
		      _createFromArray(matrix, source.valueOf(), datatype || source._datatype);
		    }
		  };
	
		  var _createFromArray = function _createFromArray(matrix, data, datatype) {
		    // initialize fields
		    matrix._values = [];
		    matrix._index = [];
		    matrix._ptr = [];
		    matrix._datatype = datatype;
		    // discover rows & columns, do not use math.size() to avoid looping array twice
		    var rows = data.length;
		    var columns = 0;
	
		    // equal signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
	
		    if (isString(datatype)) {
		      // find signature that matches (datatype, datatype)
		      eq = typed.find(equalScalar, [datatype, datatype]) || equalScalar;
		      // convert 0 to the same datatype
		      zero = typed.convert(0, datatype);
		    }
	
		    // check we have rows (empty array)
		    if (rows > 0) {
		      // column index
		      var j = 0;
		      do {
		        // store pointer to values index
		        matrix._ptr.push(matrix._index.length);
		        // loop rows
		        for (var i = 0; i < rows; i++) {
		          // current row
		          var row = data[i];
		          // check row is an array
		          if (isArray(row)) {
		            // update columns if needed (only on first column)
		            if (j === 0 && columns < row.length) columns = row.length;
		            // check row has column
		            if (j < row.length) {
		              // value
		              var v = row[j];
		              // check value != 0
		              if (!eq(v, zero)) {
		                // store value
		                matrix._values.push(v);
		                // index
		                matrix._index.push(i);
		              }
		            }
		          } else {
		            // update columns if needed (only on first column)
		            if (j === 0 && columns < 1) columns = 1;
		            // check value != 0 (row is a scalar)
		            if (!eq(row, zero)) {
		              // store value
		              matrix._values.push(row);
		              // index
		              matrix._index.push(i);
		            }
		          }
		        }
		        // increment index
		        j++;
		      } while (j < columns);
		    }
		    // store number of values in ptr
		    matrix._ptr.push(matrix._index.length);
		    // size
		    matrix._size = [rows, columns];
		  };
	
		  SparseMatrix.prototype = new Matrix();
	
		  /**
		   * Attach type information
		   */
		  SparseMatrix.prototype.type = 'SparseMatrix';
		  SparseMatrix.prototype.isSparseMatrix = true;
	
		  /**
		   * Get the storage format used by the matrix.
		   *
		   * Usage:
		   *     var format = matrix.storage()                   // retrieve storage format
		   *
		   * @memberof SparseMatrix
		   * @return {string}           The storage format.
		   */
		  SparseMatrix.prototype.storage = function () {
		    return 'sparse';
		  };
	
		  /**
		   * Get the datatype of the data stored in the matrix.
		   *
		   * Usage:
		   *     var format = matrix.datatype()                   // retrieve matrix datatype
		   *
		   * @memberof SparseMatrix
		   * @return {string}           The datatype.
		   */
		  SparseMatrix.prototype.datatype = function () {
		    return this._datatype;
		  };
	
		  /**
		   * Create a new SparseMatrix
		   * @memberof SparseMatrix
		   * @param {Array} data
		   * @param {string} [datatype]
		   */
		  SparseMatrix.prototype.create = function (data, datatype) {
		    return new SparseMatrix(data, datatype);
		  };
	
		  /**
		   * Get the matrix density.
		   *
		   * Usage:
		   *     var density = matrix.density()                   // retrieve matrix density
		   *
		   * @memberof SparseMatrix
		   * @return {number}           The matrix density.
		   */
		  SparseMatrix.prototype.density = function () {
		    // rows & columns
		    var rows = this._size[0];
		    var columns = this._size[1];
		    // calculate density
		    return rows !== 0 && columns !== 0 ? this._index.length / (rows * columns) : 0;
		  };
	
		  /**
		   * Get a subset of the matrix, or replace a subset of the matrix.
		   *
		   * Usage:
		   *     var subset = matrix.subset(index)               // retrieve subset
		   *     var value = matrix.subset(index, replacement)   // replace subset
		   *
		   * @memberof SparseMatrix
		   * @param {Index} index
		   * @param {Array | Maytrix | *} [replacement]
		   * @param {*} [defaultValue=0]      Default value, filled in on new entries when
		   *                                  the matrix is resized. If not provided,
		   *                                  new matrix elements will be filled with zeros.
		   */
		  SparseMatrix.prototype.subset = function (index, replacement, defaultValue) {
		    // check it is a pattern matrix
		    if (!this._values) throw new Error('Cannot invoke subset on a Pattern only matrix');
	
		    // check arguments
		    switch (arguments.length) {
		      case 1:
		        return _getsubset(this, index);
	
		      // intentional fall through
		      case 2:
		      case 3:
		        return _setsubset(this, index, replacement, defaultValue);
	
		      default:
		        throw new SyntaxError('Wrong number of arguments');
		    }
		  };
	
		  var _getsubset = function _getsubset(matrix, idx) {
		    // check idx
		    if (!type.isIndex(idx)) {
		      throw new TypeError('Invalid index');
		    }
	
		    var isScalar = idx.isScalar();
		    if (isScalar) {
		      // return a scalar
		      return matrix.get(idx.min());
		    }
		    // validate dimensions
		    var size = idx.size();
		    if (size.length != matrix._size.length) {
		      throw new DimensionError(size.length, matrix._size.length);
		    }
	
		    // vars
		    var i, ii, k, kk;
	
		    // validate if any of the ranges in the index is out of range
		    var min = idx.min();
		    var max = idx.max();
		    for (i = 0, ii = matrix._size.length; i < ii; i++) {
		      validateIndex(min[i], matrix._size[i]);
		      validateIndex(max[i], matrix._size[i]);
		    }
	
		    // matrix arrays
		    var mvalues = matrix._values;
		    var mindex = matrix._index;
		    var mptr = matrix._ptr;
	
		    // rows & columns dimensions for result matrix
		    var rows = idx.dimension(0);
		    var columns = idx.dimension(1);
	
		    // workspace & permutation vector
		    var w = [];
		    var pv = [];
	
		    // loop rows in resulting matrix
		    rows.forEach(function (i, r) {
		      // update permutation vector
		      pv[i] = r[0];
		      // mark i in workspace
		      w[i] = true;
		    });
	
		    // result matrix arrays
		    var values = mvalues ? [] : undefined;
		    var index = [];
		    var ptr = [];
	
		    // loop columns in result matrix
		    columns.forEach(function (j) {
		      // update ptr
		      ptr.push(index.length);
		      // loop values in column j
		      for (k = mptr[j], kk = mptr[j + 1]; k < kk; k++) {
		        // row
		        i = mindex[k];
		        // check row is in result matrix
		        if (w[i] === true) {
		          // push index
		          index.push(pv[i]);
		          // check we need to process values
		          if (values) values.push(mvalues[k]);
		        }
		      }
		    });
		    // update ptr
		    ptr.push(index.length);
	
		    // return matrix
		    return new SparseMatrix({
		      values: values,
		      index: index,
		      ptr: ptr,
		      size: size,
		      datatype: matrix._datatype
		    });
		  };
	
		  var _setsubset = function _setsubset(matrix, index, submatrix, defaultValue) {
		    // check index
		    if (!index || index.isIndex !== true) {
		      throw new TypeError('Invalid index');
		    }
	
		    // get index size and check whether the index contains a single value
		    var iSize = index.size(),
		        isScalar = index.isScalar();
	
		    // calculate the size of the submatrix, and convert it into an Array if needed
		    var sSize;
		    if (type.isMatrix(submatrix)) {
		      // submatrix size
		      sSize = submatrix.size();
		      // use array representation
		      submatrix = submatrix.toArray();
		    } else {
		      // get submatrix size (array, scalar)
		      sSize = array.size(submatrix);
		    }
	
		    // check index is a scalar
		    if (isScalar) {
		      // verify submatrix is a scalar
		      if (sSize.length !== 0) {
		        throw new TypeError('Scalar expected');
		      }
		      // set value
		      matrix.set(index.min(), submatrix, defaultValue);
		    } else {
		      // validate dimensions, index size must be one or two dimensions
		      if (iSize.length !== 1 && iSize.length !== 2) {
		        throw new DimensionError(iSize.length, matrix._size.length, '<');
		      }
	
		      // check submatrix and index have the same dimensions
		      if (sSize.length < iSize.length) {
		        // calculate number of missing outer dimensions
		        var i = 0;
		        var outer = 0;
		        while (iSize[i] === 1 && sSize[i] === 1) {
		          i++;
		        }
		        while (iSize[i] === 1) {
		          outer++;
		          i++;
		        }
		        // unsqueeze both outer and inner dimensions
		        submatrix = array.unsqueeze(submatrix, iSize.length, outer, sSize);
		      }
	
		      // check whether the size of the submatrix matches the index size
		      if (!object.deepEqual(iSize, sSize)) {
		        throw new DimensionError(iSize, sSize, '>');
		      }
	
		      // offsets
		      var x0 = index.min()[0];
		      var y0 = index.min()[1];
	
		      // submatrix rows and columns
		      var m = sSize[0];
		      var n = sSize[1];
	
		      // loop submatrix
		      for (var x = 0; x < m; x++) {
		        // loop columns
		        for (var y = 0; y < n; y++) {
		          // value at i, j
		          var v = submatrix[x][y];
		          // invoke set (zero value will remove entry from matrix)
		          matrix.set([x + x0, y + y0], v, defaultValue);
		        }
		      }
		    }
		    return matrix;
		  };
	
		  /**
		   * Get a single element from the matrix.
		   * @memberof SparseMatrix
		   * @param {number[]} index   Zero-based index
		   * @return {*} value
		   */
		  SparseMatrix.prototype.get = function (index) {
		    if (!isArray(index)) throw new TypeError('Array expected');
		    if (index.length != this._size.length) throw new DimensionError(index.length, this._size.length);
	
		    // check it is a pattern matrix
		    if (!this._values) throw new Error('Cannot invoke get on a Pattern only matrix');
	
		    // row and column
		    var i = index[0];
		    var j = index[1];
	
		    // check i, j are valid
		    validateIndex(i, this._size[0]);
		    validateIndex(j, this._size[1]);
	
		    // find value index
		    var k = _getValueIndex(i, this._ptr[j], this._ptr[j + 1], this._index);
		    // check k is prior to next column k and it is in the correct row
		    if (k < this._ptr[j + 1] && this._index[k] === i) return this._values[k];
	
		    return 0;
		  };
	
		  /**
		   * Replace a single element in the matrix.
		   * @memberof SparseMatrix
		   * @param {number[]} index   Zero-based index
		   * @param {*} value
		   * @param {*} [defaultValue]        Default value, filled in on new entries when
		   *                                  the matrix is resized. If not provided,
		   *                                  new matrix elements will be set to zero.
		   * @return {SparseMatrix} self
		   */
		  SparseMatrix.prototype.set = function (index, v, defaultValue) {
		    if (!isArray(index)) throw new TypeError('Array expected');
		    if (index.length != this._size.length) throw new DimensionError(index.length, this._size.length);
	
		    // check it is a pattern matrix
		    if (!this._values) throw new Error('Cannot invoke set on a Pattern only matrix');
	
		    // row and column
		    var i = index[0];
		    var j = index[1];
	
		    // rows & columns
		    var rows = this._size[0];
		    var columns = this._size[1];
	
		    // equal signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
	
		    if (isString(this._datatype)) {
		      // find signature that matches (datatype, datatype)
		      eq = typed.find(equalScalar, [this._datatype, this._datatype]) || equalScalar;
		      // convert 0 to the same datatype
		      zero = typed.convert(0, this._datatype);
		    }
	
		    // check we need to resize matrix
		    if (i > rows - 1 || j > columns - 1) {
		      // resize matrix
		      _resize(this, Math.max(i + 1, rows), Math.max(j + 1, columns), defaultValue);
		      // update rows & columns
		      rows = this._size[0];
		      columns = this._size[1];
		    }
	
		    // check i, j are valid
		    validateIndex(i, rows);
		    validateIndex(j, columns);
	
		    // find value index
		    var k = _getValueIndex(i, this._ptr[j], this._ptr[j + 1], this._index);
		    // check k is prior to next column k and it is in the correct row
		    if (k < this._ptr[j + 1] && this._index[k] === i) {
		      // check value != 0
		      if (!eq(v, zero)) {
		        // update value
		        this._values[k] = v;
		      } else {
		        // remove value from matrix
		        _remove(k, j, this._values, this._index, this._ptr);
		      }
		    } else {
		      // insert value @ (i, j)
		      _insert(k, i, j, v, this._values, this._index, this._ptr);
		    }
	
		    return this;
		  };
	
		  var _getValueIndex = function _getValueIndex(i, top, bottom, index) {
		    // check row is on the bottom side
		    if (bottom - top === 0) return bottom;
		    // loop rows [top, bottom[
		    for (var r = top; r < bottom; r++) {
		      // check we found value index
		      if (index[r] === i) return r;
		    }
		    // we did not find row
		    return top;
		  };
	
		  var _remove = function _remove(k, j, values, index, ptr) {
		    // remove value @ k
		    values.splice(k, 1);
		    index.splice(k, 1);
		    // update pointers
		    for (var x = j + 1; x < ptr.length; x++) {
		      ptr[x]--;
		    }
		  };
	
		  var _insert = function _insert(k, i, j, v, values, index, ptr) {
		    // insert value
		    values.splice(k, 0, v);
		    // update row for k
		    index.splice(k, 0, i);
		    // update column pointers
		    for (var x = j + 1; x < ptr.length; x++) {
		      ptr[x]++;
		    }
		  };
	
		  /**
		   * Resize the matrix to the given size. Returns a copy of the matrix when 
		   * `copy=true`, otherwise return the matrix itself (resize in place).
		   *
		   * @memberof SparseMatrix
		   * @param {number[]} size           The new size the matrix should have.
		   * @param {*} [defaultValue=0]      Default value, filled in on new entries.
		   *                                  If not provided, the matrix elements will
		   *                                  be filled with zeros.
		   * @param {boolean} [copy]          Return a resized copy of the matrix
		   *
		   * @return {Matrix}                 The resized matrix
		   */
		  SparseMatrix.prototype.resize = function (size, defaultValue, copy) {
		    // validate arguments
		    if (!isArray(size)) throw new TypeError('Array expected');
		    if (size.length !== 2) throw new Error('Only two dimensions matrix are supported');
	
		    // check sizes
		    size.forEach(function (value) {
		      if (!number.isNumber(value) || !number.isInteger(value) || value < 0) {
		        throw new TypeError('Invalid size, must contain positive integers ' + '(size: ' + string.format(size) + ')');
		      }
		    });
	
		    // matrix to resize
		    var m = copy ? this.clone() : this;
		    // resize matrix
		    return _resize(m, size[0], size[1], defaultValue);
		  };
	
		  var _resize = function _resize(matrix, rows, columns, defaultValue) {
		    // value to insert at the time of growing matrix
		    var value = defaultValue || 0;
	
		    // equal signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
	
		    if (isString(matrix._datatype)) {
		      // find signature that matches (datatype, datatype)
		      eq = typed.find(equalScalar, [matrix._datatype, matrix._datatype]) || equalScalar;
		      // convert 0 to the same datatype
		      zero = typed.convert(0, matrix._datatype);
		      // convert value to the same datatype
		      value = typed.convert(value, matrix._datatype);
		    }
	
		    // should we insert the value?
		    var ins = !eq(value, zero);
	
		    // old columns and rows
		    var r = matrix._size[0];
		    var c = matrix._size[1];
	
		    var i, j, k;
	
		    // check we need to increase columns
		    if (columns > c) {
		      // loop new columns
		      for (j = c; j < columns; j++) {
		        // update matrix._ptr for current column
		        matrix._ptr[j] = matrix._values.length;
		        // check we need to insert matrix._values
		        if (ins) {
		          // loop rows
		          for (i = 0; i < r; i++) {
		            // add new matrix._values
		            matrix._values.push(value);
		            // update matrix._index
		            matrix._index.push(i);
		          }
		        }
		      }
		      // store number of matrix._values in matrix._ptr
		      matrix._ptr[columns] = matrix._values.length;
		    } else if (columns < c) {
		      // truncate matrix._ptr
		      matrix._ptr.splice(columns + 1, c - columns);
		      // truncate matrix._values and matrix._index
		      matrix._values.splice(matrix._ptr[columns], matrix._values.length);
		      matrix._index.splice(matrix._ptr[columns], matrix._index.length);
		    }
		    // update columns
		    c = columns;
	
		    // check we need to increase rows
		    if (rows > r) {
		      // check we have to insert values
		      if (ins) {
		        // inserts
		        var n = 0;
		        // loop columns
		        for (j = 0; j < c; j++) {
		          // update matrix._ptr for current column
		          matrix._ptr[j] = matrix._ptr[j] + n;
		          // where to insert matrix._values
		          k = matrix._ptr[j + 1] + n;
		          // pointer
		          var p = 0;
		          // loop new rows, initialize pointer
		          for (i = r; i < rows; i++, p++) {
		            // add value
		            matrix._values.splice(k + p, 0, value);
		            // update matrix._index
		            matrix._index.splice(k + p, 0, i);
		            // increment inserts
		            n++;
		          }
		        }
		        // store number of matrix._values in matrix._ptr
		        matrix._ptr[c] = matrix._values.length;
		      }
		    } else if (rows < r) {
		      // deletes
		      var d = 0;
		      // loop columns
		      for (j = 0; j < c; j++) {
		        // update matrix._ptr for current column
		        matrix._ptr[j] = matrix._ptr[j] - d;
		        // where matrix._values start for next column
		        var k0 = matrix._ptr[j];
		        var k1 = matrix._ptr[j + 1] - d;
		        // loop matrix._index
		        for (k = k0; k < k1; k++) {
		          // row
		          i = matrix._index[k];
		          // check we need to delete value and matrix._index
		          if (i > rows - 1) {
		            // remove value
		            matrix._values.splice(k, 1);
		            // remove item from matrix._index
		            matrix._index.splice(k, 1);
		            // increase deletes
		            d++;
		          }
		        }
		      }
		      // update matrix._ptr for current column
		      matrix._ptr[j] = matrix._values.length;
		    }
		    // update matrix._size
		    matrix._size[0] = rows;
		    matrix._size[1] = columns;
		    // return matrix
		    return matrix;
		  };
	
		  /**
		   * Reshape the matrix to the given size. Returns a copy of the matrix when
		   * `copy=true`, otherwise return the matrix itself (reshape in place).
		   *
		   * NOTE: This might be better suited to copy by default, instead of modifying
		   *       in place. For now, it operates in place to remain consistent with
		   *       resize().
		   *
		   * @memberof SparseMatrix
		   * @param {number[]} size           The new size the matrix should have.
		   * @param {boolean} [copy]          Return a reshaped copy of the matrix
		   *
		   * @return {Matrix}                 The reshaped matrix
		   */
		  SparseMatrix.prototype.reshape = function (size, copy) {
	
		    // validate arguments
		    if (!isArray(size)) throw new TypeError('Array expected');
		    if (size.length !== 2) throw new Error('Sparse matrices can only be reshaped in two dimensions');
	
		    // check sizes
		    size.forEach(function (value) {
		      if (!number.isNumber(value) || !number.isInteger(value) || value < 0) {
		        throw new TypeError('Invalid size, must contain positive integers ' + '(size: ' + string.format(size) + ')');
		      }
		    });
	
		    // m * n must not change
		    if (this._size[0] * this._size[1] !== size[0] * size[1]) {
		      throw new Error('Reshaping sparse matrix will result in the wrong number of elements');
		    }
	
		    // matrix to reshape
		    var m = copy ? this.clone() : this;
	
		    // return unchanged if the same shape
		    if (this._size[0] === size[0] && this._size[1] === size[1]) {
		      return m;
		    }
	
		    // Convert to COO format (generate a column index)
		    var colIndex = [];
		    for (var i = 0; i < m._ptr.length; i++) {
		      for (var j = 0; j < m._ptr[i + 1] - m._ptr[i]; j++) {
		        colIndex.push(i);
		      }
		    }
	
		    // Clone the values array
		    var values = m._values.slice();
	
		    // Clone the row index array
		    var rowIndex = m._index.slice();
	
		    // Transform the (row, column) indices
		    for (var i = 0; i < m._index.length; i++) {
		      var r1 = rowIndex[i];
		      var c1 = colIndex[i];
		      var flat = r1 * m._size[1] + c1;
		      colIndex[i] = flat % size[1];
		      rowIndex[i] = Math.floor(flat / size[1]);
		    }
	
		    // Now reshaping is supposed to preserve the row-major order, BUT these sparse matrices are stored
		    // in column-major order, so we have to reorder the value array now. One option is to use a multisort,
		    // sorting several arrays based on some other array.
	
		    // OR, we could easily just:
	
		    // 1. Remove all values from the matrix
		    m._values.length = 0;
		    m._index.length = 0;
		    m._ptr.length = size[1] + 1;
		    m._size = size.slice();
		    for (var i = 0; i < m._ptr.length; i++) {
		      m._ptr[i] = 0;
		    }
	
		    // 2. Re-insert all elements in the proper order (simplified code from SparseMatrix.prototype.set)
		    // This step is probably the most time-consuming
		    for (var h = 0; h < values.length; h++) {
		      var i = rowIndex[h];
		      var j = colIndex[h];
		      var v = values[h];
		      var k = _getValueIndex(i, m._ptr[j], m._ptr[j + 1], m._index);
		      _insert(k, i, j, v, m._values, m._index, m._ptr);
		    }
	
		    // The value indices are inserted out of order, but apparently that's... still OK?
	
		    return m;
		  };
	
		  /**
		   * Create a clone of the matrix
		   * @memberof SparseMatrix
		   * @return {SparseMatrix} clone
		   */
		  SparseMatrix.prototype.clone = function () {
		    var m = new SparseMatrix({
		      values: this._values ? object.clone(this._values) : undefined,
		      index: object.clone(this._index),
		      ptr: object.clone(this._ptr),
		      size: object.clone(this._size),
		      datatype: this._datatype
		    });
		    return m;
		  };
	
		  /**
		   * Retrieve the size of the matrix.
		   * @memberof SparseMatrix
		   * @returns {number[]} size
		   */
		  SparseMatrix.prototype.size = function () {
		    return this._size.slice(0); // copy the Array
		  };
	
		  /**
		   * Create a new matrix with the results of the callback function executed on
		   * each entry of the matrix.
		   * @memberof SparseMatrix
		   * @param {Function} callback   The callback function is invoked with three
		   *                              parameters: the value of the element, the index
		   *                              of the element, and the Matrix being traversed.
		   * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
		   *
		   * @return {SparseMatrix} matrix
		   */
		  SparseMatrix.prototype.map = function (callback, skipZeros) {
		    // check it is a pattern matrix
		    if (!this._values) throw new Error('Cannot invoke map on a Pattern only matrix');
		    // matrix instance
		    var me = this;
		    // rows and columns
		    var rows = this._size[0];
		    var columns = this._size[1];
		    // invoke callback
		    var invoke = function invoke(v, i, j) {
		      // invoke callback
		      return callback(v, [i, j], me);
		    };
		    // invoke _map
		    return _map(this, 0, rows - 1, 0, columns - 1, invoke, skipZeros);
		  };
	
		  /**
		   * Create a new matrix with the results of the callback function executed on the interval
		   * [minRow..maxRow, minColumn..maxColumn].
		   */
		  var _map = function _map(matrix, minRow, maxRow, minColumn, maxColumn, callback, skipZeros) {
		    // result arrays
		    var values = [];
		    var index = [];
		    var ptr = [];
	
		    // equal signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
	
		    if (isString(matrix._datatype)) {
		      // find signature that matches (datatype, datatype)
		      eq = typed.find(equalScalar, [matrix._datatype, matrix._datatype]) || equalScalar;
		      // convert 0 to the same datatype
		      zero = typed.convert(0, matrix._datatype);
		    }
	
		    // invoke callback
		    var invoke = function invoke(v, x, y) {
		      // invoke callback
		      v = callback(v, x, y);
		      // check value != 0
		      if (!eq(v, zero)) {
		        // store value
		        values.push(v);
		        // index
		        index.push(x);
		      }
		    };
		    // loop columns
		    for (var j = minColumn; j <= maxColumn; j++) {
		      // store pointer to values index
		      ptr.push(values.length);
		      // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
		      var k0 = matrix._ptr[j];
		      var k1 = matrix._ptr[j + 1];
		      // row pointer
		      var p = minRow;
		      // loop k within [k0, k1[
		      for (var k = k0; k < k1; k++) {
		        // row index
		        var i = matrix._index[k];
		        // check i is in range
		        if (i >= minRow && i <= maxRow) {
		          // zero values
		          if (!skipZeros) {
		            for (var x = p; x < i; x++) {
		              invoke(0, x - minRow, j - minColumn);
		            }
		          }
		          // value @ k
		          invoke(matrix._values[k], i - minRow, j - minColumn);
		        }
		        // update pointer
		        p = i + 1;
		      }
		      // zero values
		      if (!skipZeros) {
		        for (var y = p; y <= maxRow; y++) {
		          invoke(0, y - minRow, j - minColumn);
		        }
		      }
		    }
		    // store number of values in ptr
		    ptr.push(values.length);
		    // return sparse matrix
		    return new SparseMatrix({
		      values: values,
		      index: index,
		      ptr: ptr,
		      size: [maxRow - minRow + 1, maxColumn - minColumn + 1]
		    });
		  };
	
		  /**
		   * Execute a callback function on each entry of the matrix.
		   * @memberof SparseMatrix
		   * @param {Function} callback   The callback function is invoked with three
		   *                              parameters: the value of the element, the index
		   *                              of the element, and the Matrix being traversed.
		   * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
		   */
		  SparseMatrix.prototype.forEach = function (callback, skipZeros) {
		    // check it is a pattern matrix
		    if (!this._values) throw new Error('Cannot invoke forEach on a Pattern only matrix');
		    // matrix instance
		    var me = this;
		    // rows and columns
		    var rows = this._size[0];
		    var columns = this._size[1];
		    // loop columns
		    for (var j = 0; j < columns; j++) {
		      // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
		      var k0 = this._ptr[j];
		      var k1 = this._ptr[j + 1];
		      // column pointer
		      var p = 0;
		      // loop k within [k0, k1[
		      for (var k = k0; k < k1; k++) {
		        // row index
		        var i = this._index[k];
		        // check we need to process zeros
		        if (!skipZeros) {
		          // zero values
		          for (var x = p; x < i; x++) {
		            callback(0, [x, j], me);
		          }
		        }
		        // value @ k
		        callback(this._values[k], [i, j], me);
		        // update pointer
		        p = i + 1;
		      }
		      // check we need to process zeros
		      if (!skipZeros) {
		        // zero values
		        for (var y = p; y < rows; y++) {
		          callback(0, [y, j], me);
		        }
		      }
		    }
		  };
	
		  /**
		   * Create an Array with a copy of the data of the SparseMatrix
		   * @memberof SparseMatrix
		   * @returns {Array} array
		   */
		  SparseMatrix.prototype.toArray = function () {
		    return _toArray(this._values, this._index, this._ptr, this._size, true);
		  };
	
		  /**
		   * Get the primitive value of the SparseMatrix: a two dimensions array
		   * @memberof SparseMatrix
		   * @returns {Array} array
		   */
		  SparseMatrix.prototype.valueOf = function () {
		    return _toArray(this._values, this._index, this._ptr, this._size, false);
		  };
	
		  var _toArray = function _toArray(values, index, ptr, size, copy) {
		    // rows and columns
		    var rows = size[0];
		    var columns = size[1];
		    // result
		    var a = [];
		    // vars
		    var i, j;
		    // initialize array
		    for (i = 0; i < rows; i++) {
		      a[i] = [];
		      for (j = 0; j < columns; j++) {
		        a[i][j] = 0;
		      }
		    }
	
		    // loop columns
		    for (j = 0; j < columns; j++) {
		      // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
		      var k0 = ptr[j];
		      var k1 = ptr[j + 1];
		      // loop k within [k0, k1[
		      for (var k = k0; k < k1; k++) {
		        // row index
		        i = index[k];
		        // set value (use one for pattern matrix)
		        a[i][j] = values ? copy ? object.clone(values[k]) : values[k] : 1;
		      }
		    }
		    return a;
		  };
	
		  /**
		   * Get a string representation of the matrix, with optional formatting options.
		   * @memberof SparseMatrix
		   * @param {Object | number | Function} [options]  Formatting options. See
		   *                                                lib/utils/number:format for a
		   *                                                description of the available
		   *                                                options.
		   * @returns {string} str
		   */
		  SparseMatrix.prototype.format = function (options) {
		    // rows and columns
		    var rows = this._size[0];
		    var columns = this._size[1];
		    // density
		    var density = this.density();
		    // rows & columns
		    var str = 'Sparse Matrix [' + string.format(rows, options) + ' x ' + string.format(columns, options) + '] density: ' + string.format(density, options) + '\n';
		    // loop columns
		    for (var j = 0; j < columns; j++) {
		      // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
		      var k0 = this._ptr[j];
		      var k1 = this._ptr[j + 1];
		      // loop k within [k0, k1[
		      for (var k = k0; k < k1; k++) {
		        // row index
		        var i = this._index[k];
		        // append value
		        str += '\n    (' + string.format(i, options) + ', ' + string.format(j, options) + ') ==> ' + (this._values ? string.format(this._values[k], options) : 'X');
		      }
		    }
		    return str;
		  };
	
		  /**
		   * Get a string representation of the matrix
		   * @memberof SparseMatrix
		   * @returns {string} str
		   */
		  SparseMatrix.prototype.toString = function () {
		    return string.format(this.toArray());
		  };
	
		  /**
		   * Get a JSON representation of the matrix
		   * @memberof SparseMatrix
		   * @returns {Object}
		   */
		  SparseMatrix.prototype.toJSON = function () {
		    return {
		      mathjs: 'SparseMatrix',
		      values: this._values,
		      index: this._index,
		      ptr: this._ptr,
		      size: this._size,
		      datatype: this._datatype
		    };
		  };
	
		  /**
		   * Get the kth Matrix diagonal.
		   *
		   * @memberof SparseMatrix
		   * @param {number | BigNumber} [k=0]     The kth diagonal where the vector will retrieved.
		   *
		   * @returns {Matrix}                     The matrix vector with the diagonal values.
		   */
		  SparseMatrix.prototype.diagonal = function (k) {
		    // validate k if any
		    if (k) {
		      // convert BigNumber to a number
		      if (type.isBigNumber(k)) k = k.toNumber();
		      // is must be an integer
		      if (!isNumber(k) || !isInteger(k)) {
		        throw new TypeError('The parameter k must be an integer number');
		      }
		    } else {
		      // default value
		      k = 0;
		    }
	
		    var kSuper = k > 0 ? k : 0;
		    var kSub = k < 0 ? -k : 0;
	
		    // rows & columns
		    var rows = this._size[0];
		    var columns = this._size[1];
	
		    // number diagonal values
		    var n = Math.min(rows - kSub, columns - kSuper);
	
		    // diagonal arrays
		    var values = [];
		    var index = [];
		    var ptr = [];
		    // initial ptr value
		    ptr[0] = 0;
		    // loop columns
		    for (var j = kSuper; j < columns && values.length < n; j++) {
		      // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
		      var k0 = this._ptr[j];
		      var k1 = this._ptr[j + 1];
		      // loop x within [k0, k1[
		      for (var x = k0; x < k1; x++) {
		        // row index
		        var i = this._index[x];
		        // check row
		        if (i === j - kSuper + kSub) {
		          // value on this column
		          values.push(this._values[x]);
		          // store row
		          index[values.length - 1] = i - kSub;
		          // exit loop
		          break;
		        }
		      }
		    }
		    // close ptr
		    ptr.push(values.length);
		    // return matrix
		    return new SparseMatrix({
		      values: values,
		      index: index,
		      ptr: ptr,
		      size: [n, 1]
		    });
		  };
	
		  /**
		   * Generate a matrix from a JSON object
		   * @memberof SparseMatrix
		   * @param {Object} json  An object structured like
		   *                       `{"mathjs": "SparseMatrix", "values": [], "index": [], "ptr": [], "size": []}`,
		   *                       where mathjs is optional
		   * @returns {SparseMatrix}
		   */
		  SparseMatrix.fromJSON = function (json) {
		    return new SparseMatrix(json);
		  };
	
		  /**
		   * Create a diagonal matrix.
		   *
		   * @memberof SparseMatrix
		   * @param {Array} size                       The matrix size.
		   * @param {number | Array | Matrix } value   The values for the diagonal.
		   * @param {number | BigNumber} [k=0]         The kth diagonal where the vector will be filled in.
		   * @param {string} [datatype]                The Matrix datatype, values must be of this datatype.
		   *
		   * @returns {SparseMatrix}
		   */
		  SparseMatrix.diagonal = function (size, value, k, defaultValue, datatype) {
		    if (!isArray(size)) throw new TypeError('Array expected, size parameter');
		    if (size.length !== 2) throw new Error('Only two dimensions matrix are supported');
	
		    // map size & validate
		    size = size.map(function (s) {
		      // check it is a big number
		      if (type.isBigNumber(s)) {
		        // convert it
		        s = s.toNumber();
		      }
		      // validate arguments
		      if (!isNumber(s) || !isInteger(s) || s < 1) {
		        throw new Error('Size values must be positive integers');
		      }
		      return s;
		    });
	
		    // validate k if any
		    if (k) {
		      // convert BigNumber to a number
		      if (type.isBigNumber(k)) k = k.toNumber();
		      // is must be an integer
		      if (!isNumber(k) || !isInteger(k)) {
		        throw new TypeError('The parameter k must be an integer number');
		      }
		    } else {
		      // default value
		      k = 0;
		    }
	
		    // equal signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
	
		    if (isString(datatype)) {
		      // find signature that matches (datatype, datatype)
		      eq = typed.find(equalScalar, [datatype, datatype]) || equalScalar;
		      // convert 0 to the same datatype
		      zero = typed.convert(0, datatype);
		    }
	
		    var kSuper = k > 0 ? k : 0;
		    var kSub = k < 0 ? -k : 0;
	
		    // rows and columns
		    var rows = size[0];
		    var columns = size[1];
	
		    // number of non-zero items
		    var n = Math.min(rows - kSub, columns - kSuper);
	
		    // value extraction function
		    var _value;
	
		    // check value
		    if (isArray(value)) {
		      // validate array
		      if (value.length !== n) {
		        // number of values in array must be n
		        throw new Error('Invalid value array length');
		      }
		      // define function
		      _value = function _value(i) {
		        // return value @ i
		        return value[i];
		      };
		    } else if (type.isMatrix(value)) {
		      // matrix size
		      var ms = value.size();
		      // validate matrix
		      if (ms.length !== 1 || ms[0] !== n) {
		        // number of values in array must be n
		        throw new Error('Invalid matrix length');
		      }
		      // define function
		      _value = function _value(i) {
		        // return value @ i
		        return value.get([i]);
		      };
		    } else {
		      // define function
		      _value = function _value() {
		        // return value
		        return value;
		      };
		    }
	
		    // create arrays
		    var values = [];
		    var index = [];
		    var ptr = [];
	
		    // loop items
		    for (var j = 0; j < columns; j++) {
		      // number of rows with value
		      ptr.push(values.length);
		      // diagonal index
		      var i = j - kSuper;
		      // check we need to set diagonal value
		      if (i >= 0 && i < n) {
		        // get value @ i
		        var v = _value(i);
		        // check for zero
		        if (!eq(v, zero)) {
		          // column
		          index.push(i + kSub);
		          // add value
		          values.push(v);
		        }
		      }
		    }
		    // last value should be number of values
		    ptr.push(values.length);
		    // create SparseMatrix
		    return new SparseMatrix({
		      values: values,
		      index: index,
		      ptr: ptr,
		      size: [rows, columns]
		    });
		  };
	
		  /**
		   * Swap rows i and j in Matrix.
		   *
		   * @memberof SparseMatrix
		   * @param {number} i       Matrix row index 1
		   * @param {number} j       Matrix row index 2
		   *
		   * @return {Matrix}        The matrix reference
		   */
		  SparseMatrix.prototype.swapRows = function (i, j) {
		    // check index
		    if (!isNumber(i) || !isInteger(i) || !isNumber(j) || !isInteger(j)) {
		      throw new Error('Row index must be positive integers');
		    }
		    // check dimensions
		    if (this._size.length !== 2) {
		      throw new Error('Only two dimensional matrix is supported');
		    }
		    // validate index
		    validateIndex(i, this._size[0]);
		    validateIndex(j, this._size[0]);
	
		    // swap rows
		    SparseMatrix._swapRows(i, j, this._size[1], this._values, this._index, this._ptr);
		    // return current instance
		    return this;
		  };
	
		  /**
		   * Loop rows with data in column j.
		   *
		   * @param {number} j            Column
		   * @param {Array} values        Matrix values
		   * @param {Array} index         Matrix row indeces
		   * @param {Array} ptr           Matrix column pointers
		   * @param {Function} callback   Callback function invoked for every row in column j
		   */
		  SparseMatrix._forEachRow = function (j, values, index, ptr, callback) {
		    // indeces for column j
		    var k0 = ptr[j];
		    var k1 = ptr[j + 1];
		    // loop
		    for (var k = k0; k < k1; k++) {
		      // invoke callback
		      callback(index[k], values[k]);
		    }
		  };
	
		  /**
		   * Swap rows x and y in Sparse Matrix data structures.
		   *
		   * @param {number} x         Matrix row index 1
		   * @param {number} y         Matrix row index 2
		   * @param {number} columns   Number of columns in matrix
		   * @param {Array} values     Matrix values
		   * @param {Array} index      Matrix row indeces
		   * @param {Array} ptr        Matrix column pointers
		   */
		  SparseMatrix._swapRows = function (x, y, columns, values, index, ptr) {
		    // loop columns
		    for (var j = 0; j < columns; j++) {
		      // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1]
		      var k0 = ptr[j];
		      var k1 = ptr[j + 1];
		      // find value index @ x
		      var kx = _getValueIndex(x, k0, k1, index);
		      // find value index @ x
		      var ky = _getValueIndex(y, k0, k1, index);
		      // check both rows exist in matrix
		      if (kx < k1 && ky < k1 && index[kx] === x && index[ky] === y) {
		        // swap values (check for pattern matrix)
		        if (values) {
		          var v = values[kx];
		          values[kx] = values[ky];
		          values[ky] = v;
		        }
		        // next column
		        continue;
		      }
		      // check x row exist & no y row
		      if (kx < k1 && index[kx] === x && (ky >= k1 || index[ky] !== y)) {
		        // value @ x (check for pattern matrix)
		        var vx = values ? values[kx] : undefined;
		        // insert value @ y
		        index.splice(ky, 0, y);
		        if (values) values.splice(ky, 0, vx);
		        // remove value @ x (adjust array index if needed)
		        index.splice(ky <= kx ? kx + 1 : kx, 1);
		        if (values) values.splice(ky <= kx ? kx + 1 : kx, 1);
		        // next column
		        continue;
		      }
		      // check y row exist & no x row
		      if (ky < k1 && index[ky] === y && (kx >= k1 || index[kx] !== x)) {
		        // value @ y (check for pattern matrix)
		        var vy = values ? values[ky] : undefined;
		        // insert value @ x
		        index.splice(kx, 0, x);
		        if (values) values.splice(kx, 0, vy);
		        // remove value @ y (adjust array index if needed)
		        index.splice(kx <= ky ? ky + 1 : ky, 1);
		        if (values) values.splice(kx <= ky ? ky + 1 : ky, 1);
		      }
		    }
		  };
	
		  // register this type in the base class Matrix
		  type.Matrix._storage.sparse = SparseMatrix;
	
		  return SparseMatrix;
		}
	
		exports.name = 'SparseMatrix';
		exports.path = 'type';
		exports.factory = factory;
		exports.lazy = false; // no lazy loading, as we alter type.Matrix._storage
	
	/***/ }),
	/* 39 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var nearlyEqual = __webpack_require__(18).nearlyEqual;
		var bigNearlyEqual = __webpack_require__(40);
	
		function factory(type, config, load, typed) {
	
		  /**
		   * Test whether two values are equal.
		   *
		   * @param  {number | BigNumber | Fraction | boolean | Complex | Unit} x   First value to compare
		   * @param  {number | BigNumber | Fraction | boolean | Complex} y          Second value to compare
		   * @return {boolean}                                                  Returns true when the compared values are equal, else returns false
		   * @private
		   */
		  var equalScalar = typed('equalScalar', {
	
		    'boolean, boolean': function booleanBoolean(x, y) {
		      return x === y;
		    },
	
		    'number, number': function numberNumber(x, y) {
		      return x === y || nearlyEqual(x, y, config.epsilon);
		    },
	
		    'BigNumber, BigNumber': function BigNumberBigNumber(x, y) {
		      return x.eq(y) || bigNearlyEqual(x, y, config.epsilon);
		    },
	
		    'Fraction, Fraction': function FractionFraction(x, y) {
		      return x.equals(y);
		    },
	
		    'Complex, Complex': function ComplexComplex(x, y) {
		      return x.equals(y);
		    },
	
		    'Unit, Unit': function UnitUnit(x, y) {
		      if (!x.equalBase(y)) {
		        throw new Error('Cannot compare units with different base');
		      }
		      return equalScalar(x.value, y.value);
		    },
	
		    'string, string': function stringString(x, y) {
		      return x === y;
		    }
		  });
	
		  return equalScalar;
		}
	
		exports.factory = factory;
	
	/***/ }),
	/* 40 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Compares two BigNumbers.
		 * @param {BigNumber} x       First value to compare
		 * @param {BigNumber} y       Second value to compare
		 * @param {number} [epsilon]  The maximum relative difference between x and y
		 *                            If epsilon is undefined or null, the function will
		 *                            test whether x and y are exactly equal.
		 * @return {boolean} whether the two numbers are nearly equal
		 */
	
		module.exports = function nearlyEqual(x, y, epsilon) {
		  // if epsilon is null or undefined, test whether x and y are exactly equal
		  if (epsilon == null) {
		    return x.eq(y);
		  }
	
		  // use "==" operator, handles infinities
		  if (x.eq(y)) {
		    return true;
		  }
	
		  // NaN
		  if (x.isNaN() || y.isNaN()) {
		    return false;
		  }
	
		  // at this point x and y should be finite
		  if (x.isFinite() && y.isFinite()) {
		    // check numbers are very close, needed when comparing numbers near zero
		    var diff = x.minus(y).abs();
		    if (diff.isZero()) {
		      return true;
		    } else {
		      // use relative error
		      var max = x.constructor.max(x.abs(), y.abs());
		      return diff.lte(max.times(epsilon));
		    }
		  }
	
		  // Infinite and Number or negative Infinite and positive Infinite cases
		  return false;
		};
	
	/***/ }),
	/* 41 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		function factory(type, config, load) {
	
		  var add = load(__webpack_require__(42));
		  var equalScalar = load(__webpack_require__(39));
	
		  /**
		   * An ordered Sparse Accumulator is a representation for a sparse vector that includes a dense array 
		   * of the vector elements and an ordered list of non-zero elements.
		   */
		  function Spa() {
		    if (!(this instanceof Spa)) throw new SyntaxError('Constructor must be called with the new operator');
	
		    // allocate vector, TODO use typed arrays
		    this._values = [];
		    this._heap = new type.FibonacciHeap();
		  }
	
		  /**
		   * Attach type information
		   */
		  Spa.prototype.type = 'Spa';
		  Spa.prototype.isSpa = true;
	
		  /**
		   * Set the value for index i.
		   *
		   * @param {number} i                       The index
		   * @param {number | BigNumber | Complex}   The value at index i
		   */
		  Spa.prototype.set = function (i, v) {
		    // check we have a value @ i
		    if (!this._values[i]) {
		      // insert in heap
		      var node = this._heap.insert(i, v);
		      // set the value @ i
		      this._values[i] = node;
		    } else {
		      // update the value @ i
		      this._values[i].value = v;
		    }
		  };
	
		  Spa.prototype.get = function (i) {
		    var node = this._values[i];
		    if (node) return node.value;
		    return 0;
		  };
	
		  Spa.prototype.accumulate = function (i, v) {
		    // node @ i
		    var node = this._values[i];
		    if (!node) {
		      // insert in heap
		      node = this._heap.insert(i, v);
		      // initialize value
		      this._values[i] = node;
		    } else {
		      // accumulate value
		      node.value = add(node.value, v);
		    }
		  };
	
		  Spa.prototype.forEach = function (from, to, callback) {
		    // references
		    var heap = this._heap;
		    var values = this._values;
		    // nodes
		    var nodes = [];
		    // node with minimum key, save it
		    var node = heap.extractMinimum();
		    if (node) nodes.push(node);
		    // extract nodes from heap (ordered)
		    while (node && node.key <= to) {
		      // check it is in range
		      if (node.key >= from) {
		        // check value is not zero
		        if (!equalScalar(node.value, 0)) {
		          // invoke callback
		          callback(node.key, node.value, this);
		        }
		      }
		      // extract next node, save it
		      node = heap.extractMinimum();
		      if (node) nodes.push(node);
		    }
		    // reinsert all nodes in heap
		    for (var i = 0; i < nodes.length; i++) {
		      // current node
		      var n = nodes[i];
		      // insert node in heap
		      node = heap.insert(n.key, n.value);
		      // update values
		      values[node.key] = node;
		    }
		  };
	
		  Spa.prototype.swap = function (i, j) {
		    // node @ i and j
		    var nodei = this._values[i];
		    var nodej = this._values[j];
		    // check we need to insert indeces
		    if (!nodei && nodej) {
		      // insert in heap
		      nodei = this._heap.insert(i, nodej.value);
		      // remove from heap
		      this._heap.remove(nodej);
		      // set values
		      this._values[i] = nodei;
		      this._values[j] = undefined;
		    } else if (nodei && !nodej) {
		      // insert in heap
		      nodej = this._heap.insert(j, nodei.value);
		      // remove from heap
		      this._heap.remove(nodei);
		      // set values
		      this._values[j] = nodej;
		      this._values[i] = undefined;
		    } else if (nodei && nodej) {
		      // swap values
		      var v = nodei.value;
		      nodei.value = nodej.value;
		      nodej.value = v;
		    }
		  };
	
		  return Spa;
		}
	
		exports.name = 'Spa';
		exports.path = 'type';
		exports.factory = factory;
	
	/***/ }),
	/* 42 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var extend = __webpack_require__(14).extend;
	
		function factory(type, config, load, typed) {
	
		  var matrix = load(__webpack_require__(43));
		  var addScalar = load(__webpack_require__(44));
		  var latex = __webpack_require__(45);
	
		  var algorithm01 = load(__webpack_require__(46));
		  var algorithm04 = load(__webpack_require__(47));
		  var algorithm10 = load(__webpack_require__(48));
		  var algorithm13 = load(__webpack_require__(49));
		  var algorithm14 = load(__webpack_require__(50));
	
		  /**
		   * Add two or more values, `x + y`.
		   * For matrices, the function is evaluated element wise.
		   *
		   * Syntax:
		   *
		   *    math.add(x, y)
		   *    math.add(x, y, z, ...)
		   *
		   * Examples:
		   *
		   *    math.add(2, 3);               // returns number 5
		   *    math.add(2, 3, 4);            // returns number 9
		   *
		   *    var a = math.complex(2, 3);
		   *    var b = math.complex(-4, 1);
		   *    math.add(a, b);               // returns Complex -2 + 4i
		   *
		   *    math.add([1, 2, 3], 4);       // returns Array [5, 6, 7]
		   *
		   *    var c = math.unit('5 cm');
		   *    var d = math.unit('2.1 mm');
		   *    math.add(c, d);               // returns Unit 52.1 mm
		   *
		   *    math.add("2.3", "4");         // returns number 6.3
		   *
		   * See also:
		   *
		   *    subtract, sum
		   *
		   * @param  {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First value to add
		   * @param  {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second value to add
		   * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Sum of `x` and `y`
		   */
		  var add = typed('add', extend({
		    // we extend the signatures of addScalar with signatures dealing with matrices
	
		    'Matrix, Matrix': function MatrixMatrix(x, y) {
		      // result
		      var c;
	
		      // process matrix storage
		      switch (x.storage()) {
		        case 'sparse':
		          switch (y.storage()) {
		            case 'sparse':
		              // sparse + sparse
		              c = algorithm04(x, y, addScalar);
		              break;
		            default:
		              // sparse + dense
		              c = algorithm01(y, x, addScalar, true);
		              break;
		          }
		          break;
		        default:
		          switch (y.storage()) {
		            case 'sparse':
		              // dense + sparse
		              c = algorithm01(x, y, addScalar, false);
		              break;
		            default:
		              // dense + dense
		              c = algorithm13(x, y, addScalar);
		              break;
		          }
		          break;
		      }
		      return c;
		    },
	
		    'Array, Array': function ArrayArray(x, y) {
		      // use matrix implementation
		      return add(matrix(x), matrix(y)).valueOf();
		    },
	
		    'Array, Matrix': function ArrayMatrix(x, y) {
		      // use matrix implementation
		      return add(matrix(x), y);
		    },
	
		    'Matrix, Array': function MatrixArray(x, y) {
		      // use matrix implementation
		      return add(x, matrix(y));
		    },
	
		    'Matrix, any': function MatrixAny(x, y) {
		      // result
		      var c;
		      // check storage format
		      switch (x.storage()) {
		        case 'sparse':
		          c = algorithm10(x, y, addScalar, false);
		          break;
		        default:
		          c = algorithm14(x, y, addScalar, false);
		          break;
		      }
		      return c;
		    },
	
		    'any, Matrix': function anyMatrix(x, y) {
		      // result
		      var c;
		      // check storage format
		      switch (y.storage()) {
		        case 'sparse':
		          c = algorithm10(y, x, addScalar, true);
		          break;
		        default:
		          c = algorithm14(y, x, addScalar, true);
		          break;
		      }
		      return c;
		    },
	
		    'Array, any': function ArrayAny(x, y) {
		      // use matrix implementation
		      return algorithm14(matrix(x), y, addScalar, false).valueOf();
		    },
	
		    'any, Array': function anyArray(x, y) {
		      // use matrix implementation
		      return algorithm14(matrix(y), x, addScalar, true).valueOf();
		    },
	
		    'any, any': addScalar,
	
		    'Array | Matrix | any, Array | Matrix | any, ...any': function ArrayMatrixAnyArrayMatrixAnyAny(x, y, rest) {
		      var result = add(x, y);
	
		      for (var i = 0; i < rest.length; i++) {
		        result = add(result, rest[i]);
		      }
	
		      return result;
		    }
		  }, addScalar.signatures));
	
		  add.toTex = {
		    2: '\\left(${args[0]}' + latex.operators['add'] + '${args[1]}\\right)'
		  };
	
		  return add;
		}
	
		exports.name = 'add';
		exports.factory = factory;
	
	/***/ }),
	/* 43 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
		  /**
		   * Create a Matrix. The function creates a new `math.type.Matrix` object from
		   * an `Array`. A Matrix has utility functions to manipulate the data in the
		   * matrix, like getting the size and getting or setting values in the matrix.
		   * Supported storage formats are 'dense' and 'sparse'.
		   *
		   * Syntax:
		   *
		   *    math.matrix()                         // creates an empty matrix using default storage format (dense).
		   *    math.matrix(data)                     // creates a matrix with initial data using default storage format (dense).
		   *    math.matrix('dense')                  // creates an empty matrix using the given storage format.
		   *    math.matrix(data, 'dense')            // creates a matrix with initial data using the given storage format.
		   *    math.matrix(data, 'sparse')           // creates a sparse matrix with initial data.
		   *    math.matrix(data, 'sparse', 'number') // creates a sparse matrix with initial data, number data type.
		   *
		   * Examples:
		   *
		   *    var m = math.matrix([[1, 2], [3, 4]]);
		   *    m.size();                        // Array [2, 2]
		   *    m.resize([3, 2], 5);
		   *    m.valueOf();                     // Array [[1, 2], [3, 4], [5, 5]]
		   *    m.get([1, 0])                    // number 3
		   *
		   * See also:
		   *
		   *    bignumber, boolean, complex, index, number, string, unit, sparse
		   *
		   * @param {Array | Matrix} [data]    A multi dimensional array
		   * @param {string} [format]          The Matrix storage format
		   *
		   * @return {Matrix} The created matrix
		   */
		  var matrix = typed('matrix', {
		    '': function _() {
		      return _create([]);
		    },
	
		    'string': function string(format) {
		      return _create([], format);
		    },
	
		    'string, string': function stringString(format, datatype) {
		      return _create([], format, datatype);
		    },
	
		    'Array': function Array(data) {
		      return _create(data);
		    },
	
		    'Matrix': function Matrix(data) {
		      return _create(data, data.storage());
		    },
	
		    'Array | Matrix, string': _create,
	
		    'Array | Matrix, string, string': _create
		  });
	
		  matrix.toTex = {
		    0: '\\begin{bmatrix}\\end{bmatrix}',
		    1: '\\left(${args[0]}\\right)',
		    2: '\\left(${args[0]}\\right)'
		  };
	
		  return matrix;
	
		  /**
		   * Create a new Matrix with given storage format
		   * @param {Array} data
		   * @param {string} [format]
		   * @param {string} [datatype]
		   * @returns {Matrix} Returns a new Matrix
		   * @private
		   */
		  function _create(data, format, datatype) {
		    // get storage format constructor
		    var M = type.Matrix.storage(format || 'default');
	
		    // create instance
		    return new M(data, datatype);
		  }
		}
	
		exports.name = 'matrix';
		exports.factory = factory;
	
	/***/ }),
	/* 44 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
	
		  /**
		   * Add two scalar values, `x + y`.
		   * This function is meant for internal use: it is used by the public function
		   * `add`
		   *
		   * This function does not support collections (Array or Matrix), and does
		   * not validate the number of of inputs.
		   *
		   * @param  {number | BigNumber | Fraction | Complex | Unit} x   First value to add
		   * @param  {number | BigNumber | Fraction | Complex} y          Second value to add
		   * @return {number | BigNumber | Fraction | Complex | Unit}                      Sum of `x` and `y`
		   * @private
		   */
		  var add = typed('add', {
	
		    'number, number': function numberNumber(x, y) {
		      return x + y;
		    },
	
		    'Complex, Complex': function ComplexComplex(x, y) {
		      return x.add(y);
		    },
	
		    'BigNumber, BigNumber': function BigNumberBigNumber(x, y) {
		      return x.plus(y);
		    },
	
		    'Fraction, Fraction': function FractionFraction(x, y) {
		      return x.add(y);
		    },
	
		    'Unit, Unit': function UnitUnit(x, y) {
		      if (x.value == null) throw new Error('Parameter x contains a unit with undefined value');
		      if (y.value == null) throw new Error('Parameter y contains a unit with undefined value');
		      if (!x.equalBase(y)) throw new Error('Units do not match');
	
		      var res = x.clone();
		      res.value = add(res.value, y.value);
		      res.fixPrefix = false;
		      return res;
		    }
		  });
	
		  return add;
		}
	
		exports.factory = factory;
	
	/***/ }),
	/* 45 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		exports.symbols = {
		  // GREEK LETTERS
		  Alpha: 'A', alpha: '\\alpha',
		  Beta: 'B', beta: '\\beta',
		  Gamma: '\\Gamma', gamma: '\\gamma',
		  Delta: '\\Delta', delta: '\\delta',
		  Epsilon: 'E', epsilon: '\\epsilon', varepsilon: '\\varepsilon',
		  Zeta: 'Z', zeta: '\\zeta',
		  Eta: 'H', eta: '\\eta',
		  Theta: '\\Theta', theta: '\\theta', vartheta: '\\vartheta',
		  Iota: 'I', iota: '\\iota',
		  Kappa: 'K', kappa: '\\kappa', varkappa: '\\varkappa',
		  Lambda: '\\Lambda', lambda: '\\lambda',
		  Mu: 'M', mu: '\\mu',
		  Nu: 'N', nu: '\\nu',
		  Xi: '\\Xi', xi: '\\xi',
		  Omicron: 'O', omicron: 'o',
		  Pi: '\\Pi', pi: '\\pi', varpi: '\\varpi',
		  Rho: 'P', rho: '\\rho', varrho: '\\varrho',
		  Sigma: '\\Sigma', sigma: '\\sigma', varsigma: '\\varsigma',
		  Tau: 'T', tau: '\\tau',
		  Upsilon: '\\Upsilon', upsilon: '\\upsilon',
		  Phi: '\\Phi', phi: '\\phi', varphi: '\\varphi',
		  Chi: 'X', chi: '\\chi',
		  Psi: '\\Psi', psi: '\\psi',
		  Omega: '\\Omega', omega: '\\omega',
		  //logic
		  'true': '\\mathrm{True}',
		  'false': '\\mathrm{False}',
		  //other
		  i: 'i', //TODO use \i ??
		  inf: '\\infty',
		  Inf: '\\infty',
		  infinity: '\\infty',
		  Infinity: '\\infty',
		  oo: '\\infty',
		  lim: '\\lim',
		  'undefined': '\\mathbf{?}'
		};
	
		exports.operators = {
		  'transpose': '^\\top',
		  'factorial': '!',
		  'pow': '^',
		  'dotPow': '.^\\wedge', //TODO find ideal solution
		  'unaryPlus': '+',
		  'unaryMinus': '-',
		  'bitNot': '~', //TODO find ideal solution
		  'not': '\\neg',
		  'multiply': '\\cdot',
		  'divide': '\\frac', //TODO how to handle that properly?
		  'dotMultiply': '.\\cdot', //TODO find ideal solution
		  'dotDivide': '.:', //TODO find ideal solution
		  'mod': '\\mod',
		  'add': '+',
		  'subtract': '-',
		  'to': '\\rightarrow',
		  'leftShift': '<<',
		  'rightArithShift': '>>',
		  'rightLogShift': '>>>',
		  'equal': '=',
		  'unequal': '\\neq',
		  'smaller': '<',
		  'larger': '>',
		  'smallerEq': '\\leq',
		  'largerEq': '\\geq',
		  'bitAnd': '\\&',
		  'bitXor': '\\underline{|}',
		  'bitOr': '|',
		  'and': '\\wedge',
		  'xor': '\\veebar',
		  'or': '\\vee'
		};
	
		exports.defaultTemplate = '\\mathrm{${name}}\\left(${args}\\right)';
	
		var units = {
		  deg: '^\\circ'
		};
	
		//@param {string} name
		//@param {boolean} isUnit
		exports.toSymbol = function (name, isUnit) {
		  isUnit = typeof isUnit === 'undefined' ? false : isUnit;
		  if (isUnit) {
		    if (units.hasOwnProperty(name)) {
		      return units[name];
		    }
		    return '\\mathrm{' + name + '}';
		  }
	
		  if (exports.symbols.hasOwnProperty(name)) {
		    return exports.symbols[name];
		  } else if (name.indexOf('_') !== -1) {
		    //symbol with index (eg. alpha_1)
		    var index = name.indexOf('_');
		    return exports.toSymbol(name.substring(0, index)) + '_{' + exports.toSymbol(name.substring(index + 1)) + '}';
		  }
		  return name;
		};
	
	/***/ }),
	/* 46 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var DimensionError = __webpack_require__(32);
	
		function factory(type, config, load, typed) {
	
		  var DenseMatrix = type.DenseMatrix;
	
		  /**
		   * Iterates over SparseMatrix nonzero items and invokes the callback function f(Dij, Sij). 
		   * Callback function invoked NNZ times (number of nonzero items in SparseMatrix).
		   *
		   *
		   *          ┌  f(Dij, Sij)  ; S(i,j) !== 0
		   * C(i,j) = ┤
		   *          └  Dij          ; otherwise
		   *
		   *
		   * @param {Matrix}   denseMatrix       The DenseMatrix instance (D)
		   * @param {Matrix}   sparseMatrix      The SparseMatrix instance (S)
		   * @param {Function} callback          The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j)
		   * @param {boolean}  inverse           A true value indicates callback should be invoked f(Sij,Dij)
		   *
		   * @return {Matrix}                    DenseMatrix (C)
		   *
		   * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571
		   */
		  var algorithm01 = function algorithm01(denseMatrix, sparseMatrix, callback, inverse) {
		    // dense matrix arrays
		    var adata = denseMatrix._data;
		    var asize = denseMatrix._size;
		    var adt = denseMatrix._datatype;
		    // sparse matrix arrays
		    var bvalues = sparseMatrix._values;
		    var bindex = sparseMatrix._index;
		    var bptr = sparseMatrix._ptr;
		    var bsize = sparseMatrix._size;
		    var bdt = sparseMatrix._datatype;
	
		    // validate dimensions
		    if (asize.length !== bsize.length) throw new DimensionError(asize.length, bsize.length);
	
		    // check rows & columns
		    if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')');
	
		    // sparse matrix cannot be a Pattern matrix
		    if (!bvalues) throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix');
	
		    // rows & columns
		    var rows = asize[0];
		    var columns = asize[1];
	
		    // process data types
		    var dt = typeof adt === 'string' && adt === bdt ? adt : undefined;
		    // callback function
		    var cf = dt ? typed.find(callback, [dt, dt]) : callback;
	
		    // vars
		    var i, j;
	
		    // result (DenseMatrix)
		    var cdata = [];
		    // initialize c
		    for (i = 0; i < rows; i++) {
		      cdata[i] = [];
		    } // workspace
		    var x = [];
		    // marks indicating we have a value in x for a given column
		    var w = [];
	
		    // loop columns in b
		    for (j = 0; j < columns; j++) {
		      // column mark
		      var mark = j + 1;
		      // values in column j
		      for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) {
		        // row
		        i = bindex[k];
		        // update workspace
		        x[i] = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]);
		        // mark i as updated
		        w[i] = mark;
		      }
		      // loop rows
		      for (i = 0; i < rows; i++) {
		        // check row is in workspace
		        if (w[i] === mark) {
		          // c[i][j] was already calculated
		          cdata[i][j] = x[i];
		        } else {
		          // item does not exist in S
		          cdata[i][j] = adata[i][j];
		        }
		      }
		    }
	
		    // return dense matrix
		    return new DenseMatrix({
		      data: cdata,
		      size: [rows, columns],
		      datatype: dt
		    });
		  };
	
		  return algorithm01;
		}
	
		exports.name = 'algorithm01';
		exports.factory = factory;
	
	/***/ }),
	/* 47 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var DimensionError = __webpack_require__(32);
	
		function factory(type, config, load, typed) {
	
		  var equalScalar = load(__webpack_require__(39));
	
		  var SparseMatrix = type.SparseMatrix;
	
		  /**
		   * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). 
		   * Callback function invoked MAX(NNZA, NNZB) times
		   *
		   *
		   *          ┌  f(Aij, Bij)  ; A(i,j) !== 0 && B(i,j) !== 0
		   * C(i,j) = ┤  A(i,j)       ; A(i,j) !== 0
		   *          └  B(i,j)       ; B(i,j) !== 0
		   *
		   *
		   * @param {Matrix}   a                 The SparseMatrix instance (A)
		   * @param {Matrix}   b                 The SparseMatrix instance (B)
		   * @param {Function} callback          The f(Aij,Bij) operation to invoke
		   *
		   * @return {Matrix}                    SparseMatrix (C)
		   *
		   * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294
		   */
		  var algorithm04 = function algorithm04(a, b, callback) {
		    // sparse matrix arrays
		    var avalues = a._values;
		    var aindex = a._index;
		    var aptr = a._ptr;
		    var asize = a._size;
		    var adt = a._datatype;
		    // sparse matrix arrays
		    var bvalues = b._values;
		    var bindex = b._index;
		    var bptr = b._ptr;
		    var bsize = b._size;
		    var bdt = b._datatype;
	
		    // validate dimensions
		    if (asize.length !== bsize.length) throw new DimensionError(asize.length, bsize.length);
	
		    // check rows & columns
		    if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')');
	
		    // rows & columns
		    var rows = asize[0];
		    var columns = asize[1];
	
		    // datatype
		    var dt;
		    // equal signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
		    // callback signature to use
		    var cf = callback;
	
		    // process data types
		    if (typeof adt === 'string' && adt === bdt) {
		      // datatype
		      dt = adt;
		      // find signature that matches (dt, dt)
		      eq = typed.find(equalScalar, [dt, dt]);
		      // convert 0 to the same datatype
		      zero = typed.convert(0, dt);
		      // callback
		      cf = typed.find(callback, [dt, dt]);
		    }
	
		    // result arrays
		    var cvalues = avalues && bvalues ? [] : undefined;
		    var cindex = [];
		    var cptr = [];
		    // matrix
		    var c = new SparseMatrix({
		      values: cvalues,
		      index: cindex,
		      ptr: cptr,
		      size: [rows, columns],
		      datatype: dt
		    });
	
		    // workspace
		    var xa = avalues && bvalues ? [] : undefined;
		    var xb = avalues && bvalues ? [] : undefined;
		    // marks indicating we have a value in x for a given column
		    var wa = [];
		    var wb = [];
	
		    // vars 
		    var i, j, k, k0, k1;
	
		    // loop columns
		    for (j = 0; j < columns; j++) {
		      // update cptr
		      cptr[j] = cindex.length;
		      // columns mark
		      var mark = j + 1;
		      // loop A(:,j)
		      for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) {
		        // row
		        i = aindex[k];
		        // update c
		        cindex.push(i);
		        // update workspace
		        wa[i] = mark;
		        // check we need to process values
		        if (xa) xa[i] = avalues[k];
		      }
		      // loop B(:,j)
		      for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) {
		        // row
		        i = bindex[k];
		        // check row exists in A
		        if (wa[i] === mark) {
		          // update record in xa @ i
		          if (xa) {
		            // invoke callback
		            var v = cf(xa[i], bvalues[k]);
		            // check for zero
		            if (!eq(v, zero)) {
		              // update workspace
		              xa[i] = v;
		            } else {
		              // remove mark (index will be removed later)
		              wa[i] = null;
		            }
		          }
		        } else {
		          // update c
		          cindex.push(i);
		          // update workspace
		          wb[i] = mark;
		          // check we need to process values
		          if (xb) xb[i] = bvalues[k];
		        }
		      }
		      // check we need to process values (non pattern matrix)
		      if (xa && xb) {
		        // initialize first index in j
		        k = cptr[j];
		        // loop index in j
		        while (k < cindex.length) {
		          // row
		          i = cindex[k];
		          // check workspace has value @ i
		          if (wa[i] === mark) {
		            // push value (Aij != 0 || (Aij != 0 && Bij != 0))
		            cvalues[k] = xa[i];
		            // increment pointer
		            k++;
		          } else if (wb[i] === mark) {
		            // push value (bij != 0)
		            cvalues[k] = xb[i];
		            // increment pointer
		            k++;
		          } else {
		            // remove index @ k
		            cindex.splice(k, 1);
		          }
		        }
		      }
		    }
		    // update cptr
		    cptr[columns] = cindex.length;
	
		    // return sparse matrix
		    return c;
		  };
	
		  return algorithm04;
		}
	
		exports.name = 'algorithm04';
		exports.factory = factory;
	
	/***/ }),
	/* 48 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
	
		  var DenseMatrix = type.DenseMatrix;
	
		  /**
		   * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). 
		   * Callback function invoked NZ times (number of nonzero items in S).
		   *
		   *
		   *          ┌  f(Sij, b)  ; S(i,j) !== 0
		   * C(i,j) = ┤  
		   *          └  b          ; otherwise
		   *
		   *
		   * @param {Matrix}   s                 The SparseMatrix instance (S)
		   * @param {Scalar}   b                 The Scalar value
		   * @param {Function} callback          The f(Aij,b) operation to invoke
		   * @param {boolean}  inverse           A true value indicates callback should be invoked f(b,Sij)
		   *
		   * @return {Matrix}                    DenseMatrix (C)
		   *
		   * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813
		   */
		  var algorithm10 = function algorithm10(s, b, callback, inverse) {
		    // sparse matrix arrays
		    var avalues = s._values;
		    var aindex = s._index;
		    var aptr = s._ptr;
		    var asize = s._size;
		    var adt = s._datatype;
	
		    // sparse matrix cannot be a Pattern matrix
		    if (!avalues) throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value');
	
		    // rows & columns
		    var rows = asize[0];
		    var columns = asize[1];
	
		    // datatype
		    var dt;
		    // callback signature to use
		    var cf = callback;
	
		    // process data types
		    if (typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // convert b to the same datatype
		      b = typed.convert(b, dt);
		      // callback
		      cf = typed.find(callback, [dt, dt]);
		    }
	
		    // result arrays
		    var cdata = [];
		    // matrix
		    var c = new DenseMatrix({
		      data: cdata,
		      size: [rows, columns],
		      datatype: dt
		    });
	
		    // workspaces
		    var x = [];
		    // marks indicating we have a value in x for a given column
		    var w = [];
	
		    // loop columns
		    for (var j = 0; j < columns; j++) {
		      // columns mark
		      var mark = j + 1;
		      // values in j
		      for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) {
		        // row
		        var r = aindex[k];
		        // update workspace
		        x[r] = avalues[k];
		        w[r] = mark;
		      }
		      // loop rows
		      for (var i = 0; i < rows; i++) {
		        // initialize C on first column
		        if (j === 0) {
		          // create row array
		          cdata[i] = [];
		        }
		        // check sparse matrix has a value @ i,j
		        if (w[i] === mark) {
		          // invoke callback, update C
		          cdata[i][j] = inverse ? cf(b, x[i]) : cf(x[i], b);
		        } else {
		          // dense matrix value @ i, j
		          cdata[i][j] = b;
		        }
		      }
		    }
	
		    // return sparse matrix
		    return c;
		  };
	
		  return algorithm10;
		}
	
		exports.name = 'algorithm10';
		exports.factory = factory;
	
	/***/ }),
	/* 49 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var util = __webpack_require__(27);
		var DimensionError = __webpack_require__(32);
	
		var string = util.string,
		    isString = string.isString;
	
		function factory(type, config, load, typed) {
	
		  var DenseMatrix = type.DenseMatrix;
	
		  /**
		   * Iterates over DenseMatrix items and invokes the callback function f(Aij..z, Bij..z). 
		   * Callback function invoked MxN times.
		   *
		   * C(i,j,...z) = f(Aij..z, Bij..z)
		   *
		   * @param {Matrix}   a                 The DenseMatrix instance (A)
		   * @param {Matrix}   b                 The DenseMatrix instance (B)
		   * @param {Function} callback          The f(Aij..z,Bij..z) operation to invoke
		   *
		   * @return {Matrix}                    DenseMatrix (C)
		   *
		   * https://github.com/josdejong/mathjs/pull/346#issuecomment-97658658
		   */
		  var algorithm13 = function algorithm13(a, b, callback) {
		    // a arrays
		    var adata = a._data;
		    var asize = a._size;
		    var adt = a._datatype;
		    // b arrays
		    var bdata = b._data;
		    var bsize = b._size;
		    var bdt = b._datatype;
		    // c arrays
		    var csize = [];
	
		    // validate dimensions
		    if (asize.length !== bsize.length) throw new DimensionError(asize.length, bsize.length);
	
		    // validate each one of the dimension sizes
		    for (var s = 0; s < asize.length; s++) {
		      // must match
		      if (asize[s] !== bsize[s]) throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')');
		      // update dimension in c
		      csize[s] = asize[s];
		    }
	
		    // datatype
		    var dt;
		    // callback signature to use
		    var cf = callback;
	
		    // process data types
		    if (typeof adt === 'string' && adt === bdt) {
		      // datatype
		      dt = adt;
		      // convert b to the same datatype
		      b = typed.convert(b, dt);
		      // callback
		      cf = typed.find(callback, [dt, dt]);
		    }
	
		    // populate cdata, iterate through dimensions
		    var cdata = csize.length > 0 ? _iterate(cf, 0, csize, csize[0], adata, bdata) : [];
	
		    // c matrix
		    return new DenseMatrix({
		      data: cdata,
		      size: csize,
		      datatype: dt
		    });
		  };
	
		  // recursive function
		  var _iterate = function _iterate(f, level, s, n, av, bv) {
		    // initialize array for this level
		    var cv = [];
		    // check we reach the last level
		    if (level === s.length - 1) {
		      // loop arrays in last level
		      for (var i = 0; i < n; i++) {
		        // invoke callback and store value
		        cv[i] = f(av[i], bv[i]);
		      }
		    } else {
		      // iterate current level
		      for (var j = 0; j < n; j++) {
		        // iterate next level
		        cv[j] = _iterate(f, level + 1, s, s[level + 1], av[j], bv[j]);
		      }
		    }
		    return cv;
		  };
	
		  return algorithm13;
		}
	
		exports.name = 'algorithm13';
		exports.factory = factory;
	
	/***/ }),
	/* 50 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var clone = __webpack_require__(14).clone;
	
		function factory(type, config, load, typed) {
	
		  var DenseMatrix = type.DenseMatrix;
	
		  /**
		   * Iterates over DenseMatrix items and invokes the callback function f(Aij..z, b). 
		   * Callback function invoked MxN times.
		   *
		   * C(i,j,...z) = f(Aij..z, b)
		   *
		   * @param {Matrix}   a                 The DenseMatrix instance (A)
		   * @param {Scalar}   b                 The Scalar value
		   * @param {Function} callback          The f(Aij..z,b) operation to invoke
		   * @param {boolean}  inverse           A true value indicates callback should be invoked f(b,Aij..z)
		   *
		   * @return {Matrix}                    DenseMatrix (C)
		   *
		   * https://github.com/josdejong/mathjs/pull/346#issuecomment-97659042
		   */
		  var algorithm14 = function algorithm14(a, b, callback, inverse) {
		    // a arrays
		    var adata = a._data;
		    var asize = a._size;
		    var adt = a._datatype;
	
		    // datatype
		    var dt;
		    // callback signature to use
		    var cf = callback;
	
		    // process data types
		    if (typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // convert b to the same datatype
		      b = typed.convert(b, dt);
		      // callback
		      cf = typed.find(callback, [dt, dt]);
		    }
	
		    // populate cdata, iterate through dimensions
		    var cdata = asize.length > 0 ? _iterate(cf, 0, asize, asize[0], adata, b, inverse) : [];
	
		    // c matrix
		    return new DenseMatrix({
		      data: cdata,
		      size: clone(asize),
		      datatype: dt
		    });
		  };
	
		  // recursive function
		  var _iterate = function _iterate(f, level, s, n, av, bv, inverse) {
		    // initialize array for this level
		    var cv = [];
		    // check we reach the last level
		    if (level === s.length - 1) {
		      // loop arrays in last level
		      for (var i = 0; i < n; i++) {
		        // invoke callback and store value
		        cv[i] = inverse ? f(bv, av[i]) : f(av[i], bv);
		      }
		    } else {
		      // iterate current level
		      for (var j = 0; j < n; j++) {
		        // iterate next level
		        cv[j] = _iterate(f, level + 1, s, s[level + 1], av[j], bv, inverse);
		      }
		    }
		    return cv;
		  };
	
		  return algorithm14;
		}
	
		exports.name = 'algorithm14';
		exports.factory = factory;
	
	/***/ }),
	/* 51 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
	
		  var smaller = load(__webpack_require__(52));
		  var larger = load(__webpack_require__(56));
	
		  var oneOverLogPhi = 1.0 / Math.log((1.0 + Math.sqrt(5.0)) / 2.0);
	
		  /**
		   * Fibonacci Heap implementation, used interally for Matrix math.
		   * @class FibonacciHeap
		   * @constructor FibonacciHeap
		   */
		  function FibonacciHeap() {
		    if (!(this instanceof FibonacciHeap)) throw new SyntaxError('Constructor must be called with the new operator');
	
		    // initialize fields
		    this._minimum = null;
		    this._size = 0;
		  }
	
		  /**
		   * Attach type information
		   */
		  FibonacciHeap.prototype.type = 'FibonacciHeap';
		  FibonacciHeap.prototype.isFibonacciHeap = true;
	
		  /**
		   * Inserts a new data element into the heap. No heap consolidation is
		   * performed at this time, the new node is simply inserted into the root
		   * list of this heap. Running time: O(1) actual.
		   * @memberof FibonacciHeap
		   */
		  FibonacciHeap.prototype.insert = function (key, value) {
		    // create node
		    var node = {
		      key: key,
		      value: value,
		      degree: 0
		    };
		    // check we have a node in the minimum
		    if (this._minimum) {
		      // minimum node
		      var minimum = this._minimum;
		      // update left & right of node
		      node.left = minimum;
		      node.right = minimum.right;
		      minimum.right = node;
		      node.right.left = node;
		      // update minimum node in heap if needed
		      if (smaller(key, minimum.key)) {
		        // node has a smaller key, use it as minimum
		        this._minimum = node;
		      }
		    } else {
		      // set left & right
		      node.left = node;
		      node.right = node;
		      // this is the first node
		      this._minimum = node;
		    }
		    // increment number of nodes in heap
		    this._size++;
		    // return node
		    return node;
		  };
	
		  /**
		   * Returns the number of nodes in heap. Running time: O(1) actual.
		   * @memberof FibonacciHeap
		   */
		  FibonacciHeap.prototype.size = function () {
		    return this._size;
		  };
	
		  /**
		   * Removes all elements from this heap.
		   * @memberof FibonacciHeap
		   */
		  FibonacciHeap.prototype.clear = function () {
		    this._minimum = null;
		    this._size = 0;
		  };
	
		  /**
		   * Returns true if the heap is empty, otherwise false.
		   * @memberof FibonacciHeap
		   */
		  FibonacciHeap.prototype.isEmpty = function () {
		    return this._size === 0;
		  };
	
		  /**
		   * Extracts the node with minimum key from heap. Amortized running 
		   * time: O(log n).
		   * @memberof FibonacciHeap
		   */
		  FibonacciHeap.prototype.extractMinimum = function () {
		    // node to remove
		    var node = this._minimum;
		    // check we have a minimum
		    if (node === null) return node;
		    // current minimum
		    var minimum = this._minimum;
		    // get number of children
		    var numberOfChildren = node.degree;
		    // pointer to the first child
		    var x = node.child;
		    // for each child of node do...
		    while (numberOfChildren > 0) {
		      // store node in right side
		      var tempRight = x.right;
		      // remove x from child list
		      x.left.right = x.right;
		      x.right.left = x.left;
		      // add x to root list of heap
		      x.left = minimum;
		      x.right = minimum.right;
		      minimum.right = x;
		      x.right.left = x;
		      // set Parent[x] to null
		      x.parent = null;
		      x = tempRight;
		      numberOfChildren--;
		    }
		    // remove node from root list of heap
		    node.left.right = node.right;
		    node.right.left = node.left;
		    // update minimum
		    if (node == node.right) {
		      // empty
		      minimum = null;
		    } else {
		      // update minimum
		      minimum = node.right;
		      // we need to update the pointer to the root with minimum key
		      minimum = _findMinimumNode(minimum, this._size);
		    }
		    // decrement size of heap
		    this._size--;
		    // update minimum
		    this._minimum = minimum;
		    // return node
		    return node;
		  };
	
		  /**
		   * Removes a node from the heap given the reference to the node. The trees
		   * in the heap will be consolidated, if necessary. This operation may fail
		   * to remove the correct element if there are nodes with key value -Infinity.
		   * Running time: O(log n) amortized.
		   * @memberof FibonacciHeap
		   */
		  FibonacciHeap.prototype.remove = function (node) {
		    // decrease key value
		    this._minimum = _decreaseKey(this._minimum, node, -1);
		    // remove the smallest
		    this.extractMinimum();
		  };
	
		  /**
		   * Decreases the key value for a heap node, given the new value to take on.
		   * The structure of the heap may be changed and will not be consolidated. 
		   * Running time: O(1) amortized.
		   * @memberof FibonacciHeap
		   */
		  var _decreaseKey = function _decreaseKey(minimum, node, key) {
		    // set node key
		    node.key = key;
		    // get parent node
		    var parent = node.parent;
		    if (parent && smaller(node.key, parent.key)) {
		      // remove node from parent
		      _cut(minimum, node, parent);
		      // remove all nodes from parent to the root parent
		      _cascadingCut(minimum, parent);
		    }
		    // update minimum node if needed
		    if (smaller(node.key, minimum.key)) minimum = node;
		    // return minimum
		    return minimum;
		  };
	
		  /**
		   * The reverse of the link operation: removes node from the child list of parent.
		   * This method assumes that min is non-null. Running time: O(1).
		   * @memberof FibonacciHeap
		   */
		  var _cut = function _cut(minimum, node, parent) {
		    // remove node from parent children and decrement Degree[parent]
		    node.left.right = node.right;
		    node.right.left = node.left;
		    parent.degree--;
		    // reset y.child if necessary
		    if (parent.child == node) parent.child = node.right;
		    // remove child if degree is 0
		    if (parent.degree === 0) parent.child = null;
		    // add node to root list of heap
		    node.left = minimum;
		    node.right = minimum.right;
		    minimum.right = node;
		    node.right.left = node;
		    // set parent[node] to null
		    node.parent = null;
		    // set mark[node] to false
		    node.mark = false;
		  };
	
		  /**
		   * Performs a cascading cut operation. This cuts node from its parent and then
		   * does the same for its parent, and so on up the tree.
		   * Running time: O(log n); O(1) excluding the recursion.
		   * @memberof FibonacciHeap
		   */
		  var _cascadingCut = function _cascadingCut(minimum, node) {
		    // store parent node
		    var parent = node.parent;
		    // if there's a parent...
		    if (!parent) return;
		    // if node is unmarked, set it marked
		    if (!node.mark) {
		      node.mark = true;
		    } else {
		      // it's marked, cut it from parent
		      _cut(minimum, node, parent);
		      // cut its parent as well
		      _cascadingCut(parent);
		    }
		  };
	
		  /**
		   * Make the first node a child of the second one. Running time: O(1) actual.
		   * @memberof FibonacciHeap
		   */
		  var _linkNodes = function _linkNodes(node, parent) {
		    // remove node from root list of heap
		    node.left.right = node.right;
		    node.right.left = node.left;
		    // make node a Child of parent
		    node.parent = parent;
		    if (!parent.child) {
		      parent.child = node;
		      node.right = node;
		      node.left = node;
		    } else {
		      node.left = parent.child;
		      node.right = parent.child.right;
		      parent.child.right = node;
		      node.right.left = node;
		    }
		    // increase degree[parent]
		    parent.degree++;
		    // set mark[node] false
		    node.mark = false;
		  };
	
		  var _findMinimumNode = function _findMinimumNode(minimum, size) {
		    // to find trees of the same degree efficiently we use an array of length O(log n) in which we keep a pointer to one root of each degree
		    var arraySize = Math.floor(Math.log(size) * oneOverLogPhi) + 1;
		    // create list with initial capacity
		    var array = new Array(arraySize);
		    // find the number of root nodes.
		    var numRoots = 0;
		    var x = minimum;
		    if (x) {
		      numRoots++;
		      x = x.right;
		      while (x !== minimum) {
		        numRoots++;
		        x = x.right;
		      }
		    }
		    // vars
		    var y;
		    // For each node in root list do...
		    while (numRoots > 0) {
		      // access this node's degree..
		      var d = x.degree;
		      // get next node
		      var next = x.right;
		      // check if there is a node already in array with the same degree
		      while (true) {
		        // get node with the same degree is any
		        y = array[d];
		        if (!y) break;
		        // make one node with the same degree a child of the other, do this based on the key value.
		        if (larger(x.key, y.key)) {
		          var temp = y;
		          y = x;
		          x = temp;
		        }
		        // make y a child of x
		        _linkNodes(y, x);
		        // we have handled this degree, go to next one.
		        array[d] = null;
		        d++;
		      }
		      // save this node for later when we might encounter another of the same degree.
		      array[d] = x;
		      // move forward through list.
		      x = next;
		      numRoots--;
		    }
		    // Set min to null (effectively losing the root list) and reconstruct the root list from the array entries in array[].
		    minimum = null;
		    // loop nodes in array
		    for (var i = 0; i < arraySize; i++) {
		      // get current node
		      y = array[i];
		      if (!y) continue;
		      // check if we have a linked list
		      if (minimum) {
		        // First remove node from root list.
		        y.left.right = y.right;
		        y.right.left = y.left;
		        // now add to root list, again.
		        y.left = minimum;
		        y.right = minimum.right;
		        minimum.right = y;
		        y.right.left = y;
		        // check if this is a new min.
		        if (smaller(y.key, minimum.key)) minimum = y;
		      } else minimum = y;
		    }
		    return minimum;
		  };
	
		  return FibonacciHeap;
		}
	
		exports.name = 'FibonacciHeap';
		exports.path = 'type';
		exports.factory = factory;
	
	/***/ }),
	/* 52 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var nearlyEqual = __webpack_require__(18).nearlyEqual;
		var bigNearlyEqual = __webpack_require__(40);
	
		function factory(type, config, load, typed) {
	
		  var matrix = load(__webpack_require__(43));
	
		  var algorithm03 = load(__webpack_require__(53));
		  var algorithm07 = load(__webpack_require__(54));
		  var algorithm12 = load(__webpack_require__(55));
		  var algorithm13 = load(__webpack_require__(49));
		  var algorithm14 = load(__webpack_require__(50));
	
		  var latex = __webpack_require__(45);
	
		  /**
		   * Test whether value x is smaller than y.
		   *
		   * The function returns true when x is smaller than y and the relative
		   * difference between x and y is smaller than the configured epsilon. The
		   * function cannot be used to compare values smaller than approximately 2.22e-16.
		   *
		   * For matrices, the function is evaluated element wise.
		   *
		   * Syntax:
		   *
		   *    math.smaller(x, y)
		   *
		   * Examples:
		   *
		   *    math.smaller(2, 3);            // returns true
		   *    math.smaller(5, 2 * 2);        // returns false
		   *
		   *    var a = math.unit('5 cm');
		   *    var b = math.unit('2 inch');
		   *    math.smaller(a, b);            // returns true
		   *
		   * See also:
		   *
		   *    equal, unequal, smallerEq, smaller, smallerEq, compare
		   *
		   * @param  {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare
		   * @param  {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare
		   * @return {boolean | Array | Matrix} Returns true when the x is smaller than y, else returns false
		   */
		  var smaller = typed('smaller', {
	
		    'boolean, boolean': function booleanBoolean(x, y) {
		      return x < y;
		    },
	
		    'number, number': function numberNumber(x, y) {
		      return x < y && !nearlyEqual(x, y, config.epsilon);
		    },
	
		    'BigNumber, BigNumber': function BigNumberBigNumber(x, y) {
		      return x.lt(y) && !bigNearlyEqual(x, y, config.epsilon);
		    },
	
		    'Fraction, Fraction': function FractionFraction(x, y) {
		      return x.compare(y) === -1;
		    },
	
		    'Complex, Complex': function ComplexComplex(x, y) {
		      throw new TypeError('No ordering relation is defined for complex numbers');
		    },
	
		    'Unit, Unit': function UnitUnit(x, y) {
		      if (!x.equalBase(y)) {
		        throw new Error('Cannot compare units with different base');
		      }
		      return smaller(x.value, y.value);
		    },
	
		    'string, string': function stringString(x, y) {
		      return x < y;
		    },
	
		    'Matrix, Matrix': function MatrixMatrix(x, y) {
		      // result
		      var c;
	
		      // process matrix storage
		      switch (x.storage()) {
		        case 'sparse':
		          switch (y.storage()) {
		            case 'sparse':
		              // sparse + sparse
		              c = algorithm07(x, y, smaller);
		              break;
		            default:
		              // sparse + dense
		              c = algorithm03(y, x, smaller, true);
		              break;
		          }
		          break;
		        default:
		          switch (y.storage()) {
		            case 'sparse':
		              // dense + sparse
		              c = algorithm03(x, y, smaller, false);
		              break;
		            default:
		              // dense + dense
		              c = algorithm13(x, y, smaller);
		              break;
		          }
		          break;
		      }
		      return c;
		    },
	
		    'Array, Array': function ArrayArray(x, y) {
		      // use matrix implementation
		      return smaller(matrix(x), matrix(y)).valueOf();
		    },
	
		    'Array, Matrix': function ArrayMatrix(x, y) {
		      // use matrix implementation
		      return smaller(matrix(x), y);
		    },
	
		    'Matrix, Array': function MatrixArray(x, y) {
		      // use matrix implementation
		      return smaller(x, matrix(y));
		    },
	
		    'Matrix, any': function MatrixAny(x, y) {
		      // result
		      var c;
		      // check storage format
		      switch (x.storage()) {
		        case 'sparse':
		          c = algorithm12(x, y, smaller, false);
		          break;
		        default:
		          c = algorithm14(x, y, smaller, false);
		          break;
		      }
		      return c;
		    },
	
		    'any, Matrix': function anyMatrix(x, y) {
		      // result
		      var c;
		      // check storage format
		      switch (y.storage()) {
		        case 'sparse':
		          c = algorithm12(y, x, smaller, true);
		          break;
		        default:
		          c = algorithm14(y, x, smaller, true);
		          break;
		      }
		      return c;
		    },
	
		    'Array, any': function ArrayAny(x, y) {
		      // use matrix implementation
		      return algorithm14(matrix(x), y, smaller, false).valueOf();
		    },
	
		    'any, Array': function anyArray(x, y) {
		      // use matrix implementation
		      return algorithm14(matrix(y), x, smaller, true).valueOf();
		    }
		  });
	
		  smaller.toTex = {
		    2: '\\left(${args[0]}' + latex.operators['smaller'] + '${args[1]}\\right)'
		  };
	
		  return smaller;
		}
	
		exports.name = 'smaller';
		exports.factory = factory;
	
	/***/ }),
	/* 53 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var DimensionError = __webpack_require__(32);
	
		function factory(type, config, load, typed) {
	
		  var DenseMatrix = type.DenseMatrix;
	
		  /**
		   * Iterates over SparseMatrix items and invokes the callback function f(Dij, Sij).
		   * Callback function invoked M*N times.
		   *
		   *
		   *          ┌  f(Dij, Sij)  ; S(i,j) !== 0
		   * C(i,j) = ┤
		   *          └  f(Dij, 0)    ; otherwise
		   *
		   *
		   * @param {Matrix}   denseMatrix       The DenseMatrix instance (D)
		   * @param {Matrix}   sparseMatrix      The SparseMatrix instance (C)
		   * @param {Function} callback          The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j)
		   * @param {boolean}  inverse           A true value indicates callback should be invoked f(Sij,Dij)
		   *
		   * @return {Matrix}                    DenseMatrix (C)
		   *
		   * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571
		   */
		  var algorithm03 = function algorithm03(denseMatrix, sparseMatrix, callback, inverse) {
		    // dense matrix arrays
		    var adata = denseMatrix._data;
		    var asize = denseMatrix._size;
		    var adt = denseMatrix._datatype;
		    // sparse matrix arrays
		    var bvalues = sparseMatrix._values;
		    var bindex = sparseMatrix._index;
		    var bptr = sparseMatrix._ptr;
		    var bsize = sparseMatrix._size;
		    var bdt = sparseMatrix._datatype;
	
		    // validate dimensions
		    if (asize.length !== bsize.length) throw new DimensionError(asize.length, bsize.length);
	
		    // check rows & columns
		    if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')');
	
		    // sparse matrix cannot be a Pattern matrix
		    if (!bvalues) throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix');
	
		    // rows & columns
		    var rows = asize[0];
		    var columns = asize[1];
	
		    // datatype
		    var dt;
		    // zero value
		    var zero = 0;
		    // callback signature to use
		    var cf = callback;
	
		    // process data types
		    if (typeof adt === 'string' && adt === bdt) {
		      // datatype
		      dt = adt;
		      // convert 0 to the same datatype
		      zero = typed.convert(0, dt);
		      // callback
		      cf = typed.find(callback, [dt, dt]);
		    }
	
		    // result (DenseMatrix)
		    var cdata = [];
	
		    // initialize dense matrix
		    for (var z = 0; z < rows; z++) {
		      // initialize row
		      cdata[z] = [];
		    }
	
		    // workspace
		    var x = [];
		    // marks indicating we have a value in x for a given column
		    var w = [];
	
		    // loop columns in b
		    for (var j = 0; j < columns; j++) {
		      // column mark
		      var mark = j + 1;
		      // values in column j
		      for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) {
		        // row
		        var i = bindex[k];
		        // update workspace
		        x[i] = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]);
		        w[i] = mark;
		      }
		      // process workspace
		      for (var y = 0; y < rows; y++) {
		        // check we have a calculated value for current row
		        if (w[y] === mark) {
		          // use calculated value
		          cdata[y][j] = x[y];
		        } else {
		          // calculate value
		          cdata[y][j] = inverse ? cf(zero, adata[y][j]) : cf(adata[y][j], zero);
		        }
		      }
		    }
	
		    // return dense matrix
		    return new DenseMatrix({
		      data: cdata,
		      size: [rows, columns],
		      datatype: dt
		    });
		  };
	
		  return algorithm03;
		}
	
		exports.name = 'algorithm03';
		exports.factory = factory;
	
	/***/ }),
	/* 54 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var DimensionError = __webpack_require__(32);
	
		function factory(type, config, load, typed) {
	
		  var DenseMatrix = type.DenseMatrix;
	
		  /**
		   * Iterates over SparseMatrix A and SparseMatrix B items (zero and nonzero) and invokes the callback function f(Aij, Bij). 
		   * Callback function invoked MxN times.
		   *
		   * C(i,j) = f(Aij, Bij)
		   *
		   * @param {Matrix}   a                 The SparseMatrix instance (A)
		   * @param {Matrix}   b                 The SparseMatrix instance (B)
		   * @param {Function} callback          The f(Aij,Bij) operation to invoke
		   *
		   * @return {Matrix}                    DenseMatrix (C)
		   *
		   * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294
		   */
		  var algorithm07 = function algorithm07(a, b, callback) {
		    // sparse matrix arrays
		    var asize = a._size;
		    var adt = a._datatype;
		    // sparse matrix arrays
		    var bsize = b._size;
		    var bdt = b._datatype;
	
		    // validate dimensions
		    if (asize.length !== bsize.length) throw new DimensionError(asize.length, bsize.length);
	
		    // check rows & columns
		    if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')');
	
		    // rows & columns
		    var rows = asize[0];
		    var columns = asize[1];
	
		    // datatype
		    var dt;
		    // zero value
		    var zero = 0;
		    // callback signature to use
		    var cf = callback;
	
		    // process data types
		    if (typeof adt === 'string' && adt === bdt) {
		      // datatype
		      dt = adt;
		      // convert 0 to the same datatype
		      zero = typed.convert(0, dt);
		      // callback
		      cf = typed.find(callback, [dt, dt]);
		    }
	
		    // vars
		    var i, j;
	
		    // result arrays
		    var cdata = [];
		    // initialize c
		    for (i = 0; i < rows; i++) {
		      cdata[i] = [];
		    } // matrix
		    var c = new DenseMatrix({
		      data: cdata,
		      size: [rows, columns],
		      datatype: dt
		    });
	
		    // workspaces
		    var xa = [];
		    var xb = [];
		    // marks indicating we have a value in x for a given column
		    var wa = [];
		    var wb = [];
	
		    // loop columns
		    for (j = 0; j < columns; j++) {
		      // columns mark
		      var mark = j + 1;
		      // scatter the values of A(:,j) into workspace
		      _scatter(a, j, wa, xa, mark);
		      // scatter the values of B(:,j) into workspace
		      _scatter(b, j, wb, xb, mark);
		      // loop rows
		      for (i = 0; i < rows; i++) {
		        // matrix values @ i,j
		        var va = wa[i] === mark ? xa[i] : zero;
		        var vb = wb[i] === mark ? xb[i] : zero;
		        // invoke callback
		        cdata[i][j] = cf(va, vb);
		      }
		    }
	
		    // return sparse matrix
		    return c;
		  };
	
		  var _scatter = function _scatter(m, j, w, x, mark) {
		    // a arrays
		    var values = m._values;
		    var index = m._index;
		    var ptr = m._ptr;
		    // loop values in column j
		    for (var k = ptr[j], k1 = ptr[j + 1]; k < k1; k++) {
		      // row
		      var i = index[k];
		      // update workspace
		      w[i] = mark;
		      x[i] = values[k];
		    }
		  };
	
		  return algorithm07;
		}
	
		exports.name = 'algorithm07';
		exports.factory = factory;
	
	/***/ }),
	/* 55 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
	
		  var DenseMatrix = type.DenseMatrix;
	
		  /**
		   * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). 
		   * Callback function invoked MxN times.
		   *
		   *
		   *          ┌  f(Sij, b)  ; S(i,j) !== 0
		   * C(i,j) = ┤  
		   *          └  f(0, b)    ; otherwise
		   *
		   *
		   * @param {Matrix}   s                 The SparseMatrix instance (S)
		   * @param {Scalar}   b                 The Scalar value
		   * @param {Function} callback          The f(Aij,b) operation to invoke
		   * @param {boolean}  inverse           A true value indicates callback should be invoked f(b,Sij)
		   *
		   * @return {Matrix}                    DenseMatrix (C)
		   *
		   * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813
		   */
		  var algorithm12 = function algorithm12(s, b, callback, inverse) {
		    // sparse matrix arrays
		    var avalues = s._values;
		    var aindex = s._index;
		    var aptr = s._ptr;
		    var asize = s._size;
		    var adt = s._datatype;
	
		    // sparse matrix cannot be a Pattern matrix
		    if (!avalues) throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value');
	
		    // rows & columns
		    var rows = asize[0];
		    var columns = asize[1];
	
		    // datatype
		    var dt;
		    // callback signature to use
		    var cf = callback;
	
		    // process data types
		    if (typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // convert b to the same datatype
		      b = typed.convert(b, dt);
		      // callback
		      cf = typed.find(callback, [dt, dt]);
		    }
	
		    // result arrays
		    var cdata = [];
		    // matrix
		    var c = new DenseMatrix({
		      data: cdata,
		      size: [rows, columns],
		      datatype: dt
		    });
	
		    // workspaces
		    var x = [];
		    // marks indicating we have a value in x for a given column
		    var w = [];
	
		    // loop columns
		    for (var j = 0; j < columns; j++) {
		      // columns mark
		      var mark = j + 1;
		      // values in j
		      for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) {
		        // row
		        var r = aindex[k];
		        // update workspace
		        x[r] = avalues[k];
		        w[r] = mark;
		      }
		      // loop rows
		      for (var i = 0; i < rows; i++) {
		        // initialize C on first column
		        if (j === 0) {
		          // create row array
		          cdata[i] = [];
		        }
		        // check sparse matrix has a value @ i,j
		        if (w[i] === mark) {
		          // invoke callback, update C
		          cdata[i][j] = inverse ? cf(b, x[i]) : cf(x[i], b);
		        } else {
		          // dense matrix value @ i, j
		          cdata[i][j] = inverse ? cf(b, 0) : cf(0, b);
		        }
		      }
		    }
	
		    // return sparse matrix
		    return c;
		  };
	
		  return algorithm12;
		}
	
		exports.name = 'algorithm12';
		exports.factory = factory;
	
	/***/ }),
	/* 56 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var nearlyEqual = __webpack_require__(18).nearlyEqual;
		var bigNearlyEqual = __webpack_require__(40);
	
		function factory(type, config, load, typed) {
	
		  var matrix = load(__webpack_require__(43));
	
		  var algorithm03 = load(__webpack_require__(53));
		  var algorithm07 = load(__webpack_require__(54));
		  var algorithm12 = load(__webpack_require__(55));
		  var algorithm13 = load(__webpack_require__(49));
		  var algorithm14 = load(__webpack_require__(50));
	
		  var latex = __webpack_require__(45);
	
		  /**
		   * Test whether value x is larger than y.
		   *
		   * The function returns true when x is larger than y and the relative
		   * difference between x and y is larger than the configured epsilon. The
		   * function cannot be used to compare values smaller than approximately 2.22e-16.
		   *
		   * For matrices, the function is evaluated element wise.
		   *
		   * Syntax:
		   *
		   *    math.larger(x, y)
		   *
		   * Examples:
		   *
		   *    math.larger(2, 3);             // returns false
		   *    math.larger(5, 2 + 2);         // returns true
		   *
		   *    var a = math.unit('5 cm');
		   *    var b = math.unit('2 inch');
		   *    math.larger(a, b);             // returns false
		   *
		   * See also:
		   *
		   *    equal, unequal, smaller, smallerEq, largerEq, compare
		   *
		   * @param  {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare
		   * @param  {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare
		   * @return {boolean | Array | Matrix} Returns true when the x is larger than y, else returns false
		   */
		  var larger = typed('larger', {
	
		    'boolean, boolean': function booleanBoolean(x, y) {
		      return x > y;
		    },
	
		    'number, number': function numberNumber(x, y) {
		      return x > y && !nearlyEqual(x, y, config.epsilon);
		    },
	
		    'BigNumber, BigNumber': function BigNumberBigNumber(x, y) {
		      return x.gt(y) && !bigNearlyEqual(x, y, config.epsilon);
		    },
	
		    'Fraction, Fraction': function FractionFraction(x, y) {
		      return x.compare(y) === 1;
		    },
	
		    'Complex, Complex': function ComplexComplex() {
		      throw new TypeError('No ordering relation is defined for complex numbers');
		    },
	
		    'Unit, Unit': function UnitUnit(x, y) {
		      if (!x.equalBase(y)) {
		        throw new Error('Cannot compare units with different base');
		      }
		      return larger(x.value, y.value);
		    },
	
		    'string, string': function stringString(x, y) {
		      return x > y;
		    },
	
		    'Matrix, Matrix': function MatrixMatrix(x, y) {
		      // result
		      var c;
	
		      // process matrix storage
		      switch (x.storage()) {
		        case 'sparse':
		          switch (y.storage()) {
		            case 'sparse':
		              // sparse + sparse
		              c = algorithm07(x, y, larger);
		              break;
		            default:
		              // sparse + dense
		              c = algorithm03(y, x, larger, true);
		              break;
		          }
		          break;
		        default:
		          switch (y.storage()) {
		            case 'sparse':
		              // dense + sparse
		              c = algorithm03(x, y, larger, false);
		              break;
		            default:
		              // dense + dense
		              c = algorithm13(x, y, larger);
		              break;
		          }
		          break;
		      }
		      return c;
		    },
	
		    'Array, Array': function ArrayArray(x, y) {
		      // use matrix implementation
		      return larger(matrix(x), matrix(y)).valueOf();
		    },
	
		    'Array, Matrix': function ArrayMatrix(x, y) {
		      // use matrix implementation
		      return larger(matrix(x), y);
		    },
	
		    'Matrix, Array': function MatrixArray(x, y) {
		      // use matrix implementation
		      return larger(x, matrix(y));
		    },
	
		    'Matrix, any': function MatrixAny(x, y) {
		      // result
		      var c;
		      // check storage format
		      switch (x.storage()) {
		        case 'sparse':
		          c = algorithm12(x, y, larger, false);
		          break;
		        default:
		          c = algorithm14(x, y, larger, false);
		          break;
		      }
		      return c;
		    },
	
		    'any, Matrix': function anyMatrix(x, y) {
		      // result
		      var c;
		      // check storage format
		      switch (y.storage()) {
		        case 'sparse':
		          c = algorithm12(y, x, larger, true);
		          break;
		        default:
		          c = algorithm14(y, x, larger, true);
		          break;
		      }
		      return c;
		    },
	
		    'Array, any': function ArrayAny(x, y) {
		      // use matrix implementation
		      return algorithm14(matrix(x), y, larger, false).valueOf();
		    },
	
		    'any, Array': function anyArray(x, y) {
		      // use matrix implementation
		      return algorithm14(matrix(y), x, larger, true).valueOf();
		    }
		  });
	
		  larger.toTex = {
		    2: '\\left(${args[0]}' + latex.operators['larger'] + '${args[1]}\\right)'
		  };
	
		  return larger;
		}
	
		exports.name = 'larger';
		exports.factory = factory;
	
	/***/ }),
	/* 57 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var util = __webpack_require__(27);
	
		var string = util.string;
		var object = util.object;
	
		var isArray = Array.isArray;
		var isString = string.isString;
	
		function factory(type, config, load) {
	
		  var DenseMatrix = load(__webpack_require__(36));
	
		  var smaller = load(__webpack_require__(52));
	
		  function ImmutableDenseMatrix(data, datatype) {
		    if (!(this instanceof ImmutableDenseMatrix)) throw new SyntaxError('Constructor must be called with the new operator');
		    if (datatype && !isString(datatype)) throw new Error('Invalid datatype: ' + datatype);
	
		    if (type.isMatrix(data) || isArray(data)) {
		      // use DenseMatrix implementation
		      var matrix = new DenseMatrix(data, datatype);
		      // internal structures
		      this._data = matrix._data;
		      this._size = matrix._size;
		      this._datatype = matrix._datatype;
		      this._min = null;
		      this._max = null;
		    } else if (data && isArray(data.data) && isArray(data.size)) {
		      // initialize fields from JSON representation
		      this._data = data.data;
		      this._size = data.size;
		      this._datatype = data.datatype;
		      this._min = typeof data.min !== 'undefined' ? data.min : null;
		      this._max = typeof data.max !== 'undefined' ? data.max : null;
		    } else if (data) {
		      // unsupported type
		      throw new TypeError('Unsupported type of data (' + util.types.type(data) + ')');
		    } else {
		      // nothing provided
		      this._data = [];
		      this._size = [0];
		      this._datatype = datatype;
		      this._min = null;
		      this._max = null;
		    }
		  }
	
		  ImmutableDenseMatrix.prototype = new DenseMatrix();
	
		  /**
		   * Attach type information
		   */
		  ImmutableDenseMatrix.prototype.type = 'ImmutableDenseMatrix';
		  ImmutableDenseMatrix.prototype.isImmutableDenseMatrix = true;
	
		  /**
		   * Get a subset of the matrix, or replace a subset of the matrix.
		   *
		   * Usage:
		   *     var subset = matrix.subset(index)               // retrieve subset
		   *     var value = matrix.subset(index, replacement)   // replace subset
		   *
		   * @param {Index} index
		   * @param {Array | ImmutableDenseMatrix | *} [replacement]
		   * @param {*} [defaultValue=0]      Default value, filled in on new entries when
		   *                                  the matrix is resized. If not provided,
		   *                                  new matrix elements will be filled with zeros.
		   */
		  ImmutableDenseMatrix.prototype.subset = function (index) {
		    switch (arguments.length) {
		      case 1:
		        // use base implementation
		        var m = DenseMatrix.prototype.subset.call(this, index);
		        // check result is a matrix
		        if (type.isMatrix(m)) {
		          // return immutable matrix
		          return new ImmutableDenseMatrix({
		            data: m._data,
		            size: m._size,
		            datatype: m._datatype
		          });
		        }
		        return m;
	
		      // intentional fall through
		      case 2:
		      case 3:
		        throw new Error('Cannot invoke set subset on an Immutable Matrix instance');
	
		      default:
		        throw new SyntaxError('Wrong number of arguments');
		    }
		  };
	
		  /**
		   * Replace a single element in the matrix.
		   * @param {Number[]} index   Zero-based index
		   * @param {*} value
		   * @param {*} [defaultValue]        Default value, filled in on new entries when
		   *                                  the matrix is resized. If not provided,
		   *                                  new matrix elements will be left undefined.
		   * @return {ImmutableDenseMatrix} self
		   */
		  ImmutableDenseMatrix.prototype.set = function () {
		    throw new Error('Cannot invoke set on an Immutable Matrix instance');
		  };
	
		  /**
		   * Resize the matrix to the given size. Returns a copy of the matrix when
		   * `copy=true`, otherwise return the matrix itself (resize in place).
		   *
		   * @param {Number[]} size           The new size the matrix should have.
		   * @param {*} [defaultValue=0]      Default value, filled in on new entries.
		   *                                  If not provided, the matrix elements will
		   *                                  be filled with zeros.
		   * @param {boolean} [copy]          Return a resized copy of the matrix
		   *
		   * @return {Matrix}                 The resized matrix
		   */
		  ImmutableDenseMatrix.prototype.resize = function () {
		    throw new Error('Cannot invoke resize on an Immutable Matrix instance');
		  };
	
		  /**
		   * Disallows reshaping in favor of immutability.
		   *
		   * @throws {Error} Operation not allowed
		   */
		  ImmutableDenseMatrix.prototype.reshape = function () {
		    throw new Error('Cannot invoke reshape on an Immutable Matrix instance');
		  };
	
		  /**
		   * Create a clone of the matrix
		   * @return {ImmutableDenseMatrix} clone
		   */
		  ImmutableDenseMatrix.prototype.clone = function () {
		    var m = new ImmutableDenseMatrix({
		      data: object.clone(this._data),
		      size: object.clone(this._size),
		      datatype: this._datatype
		    });
		    return m;
		  };
	
		  /**
		   * Get a JSON representation of the matrix
		   * @returns {Object}
		   */
		  ImmutableDenseMatrix.prototype.toJSON = function () {
		    return {
		      mathjs: 'ImmutableDenseMatrix',
		      data: this._data,
		      size: this._size,
		      datatype: this._datatype
		    };
		  };
	
		  /**
		   * Generate a matrix from a JSON object
		   * @param {Object} json  An object structured like
		   *                       `{"mathjs": "ImmutableDenseMatrix", data: [], size: []}`,
		   *                       where mathjs is optional
		   * @returns {ImmutableDenseMatrix}
		   */
		  ImmutableDenseMatrix.fromJSON = function (json) {
		    return new ImmutableDenseMatrix(json);
		  };
	
		  /**
		   * Swap rows i and j in Matrix.
		   *
		   * @param {Number} i       Matrix row index 1
		   * @param {Number} j       Matrix row index 2
		   *
		   * @return {Matrix}        The matrix reference
		   */
		  ImmutableDenseMatrix.prototype.swapRows = function () {
		    throw new Error('Cannot invoke swapRows on an Immutable Matrix instance');
		  };
	
		  /**
		   * Calculate the minimum value in the set
		   * @return {Number | undefined} min
		   */
		  ImmutableDenseMatrix.prototype.min = function () {
		    // check min has been calculated before
		    if (this._min === null) {
		      // minimum
		      var m = null;
		      // compute min
		      this.forEach(function (v) {
		        if (m === null || smaller(v, m)) m = v;
		      });
		      this._min = m !== null ? m : undefined;
		    }
		    return this._min;
		  };
	
		  /**
		   * Calculate the maximum value in the set
		   * @return {Number | undefined} max
		   */
		  ImmutableDenseMatrix.prototype.max = function () {
		    // check max has been calculated before
		    if (this._max === null) {
		      // maximum
		      var m = null;
		      // compute max
		      this.forEach(function (v) {
		        if (m === null || smaller(m, v)) m = v;
		      });
		      this._max = m !== null ? m : undefined;
		    }
		    return this._max;
		  };
	
		  // exports
		  return ImmutableDenseMatrix;
		}
	
		exports.name = 'ImmutableDenseMatrix';
		exports.path = 'type';
		exports.factory = factory;
	
	/***/ }),
	/* 58 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var clone = __webpack_require__(14).clone;
		var isInteger = __webpack_require__(18).isInteger;
	
		function factory(type) {
	
		  /**
		   * Create an index. An Index can store ranges and sets for multiple dimensions.
		   * Matrix.get, Matrix.set, and math.subset accept an Index as input.
		   *
		   * Usage:
		   *     var index = new Index(range1, range2, matrix1, array1, ...);
		   *
		   * Where each parameter can be any of:
		   *     A number
		   *     A string (containing a name of an object property)
		   *     An instance of Range
		   *     An Array with the Set values
		   *     A Matrix with the Set values
		   *
		   * The parameters start, end, and step must be integer numbers.
		   *
		   * @class Index
		   * @Constructor Index
		   * @param {...*} ranges
		   */
		  function Index(ranges) {
		    if (!(this instanceof Index)) {
		      throw new SyntaxError('Constructor must be called with the new operator');
		    }
	
		    this._dimensions = [];
		    this._isScalar = true;
	
		    for (var i = 0, ii = arguments.length; i < ii; i++) {
		      var arg = arguments[i];
	
		      if (type.isRange(arg)) {
		        this._dimensions.push(arg);
		        this._isScalar = false;
		      } else if (Array.isArray(arg) || type.isMatrix(arg)) {
		        // create matrix
		        var m = _createImmutableMatrix(arg.valueOf());
		        this._dimensions.push(m);
		        // size
		        var size = m.size();
		        // scalar
		        if (size.length !== 1 || size[0] !== 1) {
		          this._isScalar = false;
		        }
		      } else if (typeof arg === 'number') {
		        this._dimensions.push(_createImmutableMatrix([arg]));
		      } else if (typeof arg === 'string') {
		        // object property (arguments.count should be 1)
		        this._dimensions.push(arg);
		      }
		      // TODO: implement support for wildcard '*'
		      else {
		          throw new TypeError('Dimension must be an Array, Matrix, number, string, or Range');
		        }
		    }
		  }
	
		  /**
		   * Attach type information
		   */
		  Index.prototype.type = 'Index';
		  Index.prototype.isIndex = true;
	
		  function _createImmutableMatrix(arg) {
		    // loop array elements
		    for (var i = 0, l = arg.length; i < l; i++) {
		      if (typeof arg[i] !== 'number' || !isInteger(arg[i])) {
		        throw new TypeError('Index parameters must be positive integer numbers');
		      }
		    }
		    // create matrix
		    return new type.ImmutableDenseMatrix(arg);
		  }
	
		  /**
		   * Create a clone of the index
		   * @memberof Index
		   * @return {Index} clone
		   */
		  Index.prototype.clone = function () {
		    var index = new Index();
		    index._dimensions = clone(this._dimensions);
		    index._isScalar = this._isScalar;
		    return index;
		  };
	
		  /**
		   * Create an index from an array with ranges/numbers
		   * @memberof Index
		   * @param {Array.<Array | number>} ranges
		   * @return {Index} index
		   * @private
		   */
		  Index.create = function (ranges) {
		    var index = new Index();
		    Index.apply(index, ranges);
		    return index;
		  };
	
		  /**
		   * Retrieve the size of the index, the number of elements for each dimension.
		   * @memberof Index
		   * @returns {number[]} size
		   */
		  Index.prototype.size = function () {
		    var size = [];
	
		    for (var i = 0, ii = this._dimensions.length; i < ii; i++) {
		      var d = this._dimensions[i];
		      size[i] = typeof d === 'string' ? 1 : d.size()[0];
		    }
	
		    return size;
		  };
	
		  /**
		   * Get the maximum value for each of the indexes ranges.
		   * @memberof Index
		   * @returns {number[]} max
		   */
		  Index.prototype.max = function () {
		    var values = [];
	
		    for (var i = 0, ii = this._dimensions.length; i < ii; i++) {
		      var range = this._dimensions[i];
		      values[i] = typeof range === 'string' ? range : range.max();
		    }
	
		    return values;
		  };
	
		  /**
		   * Get the minimum value for each of the indexes ranges.
		   * @memberof Index
		   * @returns {number[]} min
		   */
		  Index.prototype.min = function () {
		    var values = [];
	
		    for (var i = 0, ii = this._dimensions.length; i < ii; i++) {
		      var range = this._dimensions[i];
		      values[i] = typeof range === 'string' ? range : range.min();
		    }
	
		    return values;
		  };
	
		  /**
		   * Loop over each of the ranges of the index
		   * @memberof Index
		   * @param {Function} callback   Called for each range with a Range as first
		   *                              argument, the dimension as second, and the
		   *                              index object as third.
		   */
		  Index.prototype.forEach = function (callback) {
		    for (var i = 0, ii = this._dimensions.length; i < ii; i++) {
		      callback(this._dimensions[i], i, this);
		    }
		  };
	
		  /**
		   * Retrieve the dimension for the given index
		   * @memberof Index
		   * @param {Number} dim                  Number of the dimension
		   * @returns {Range | null} range
		   */
		  Index.prototype.dimension = function (dim) {
		    return this._dimensions[dim] || null;
		  };
	
		  /**
		   * Test whether this index contains an object property
		   * @returns {boolean} Returns true if the index is an object property
		   */
		  Index.prototype.isObjectProperty = function () {
		    return this._dimensions.length === 1 && typeof this._dimensions[0] === 'string';
		  };
	
		  /**
		   * Returns the object property name when the Index holds a single object property,
		   * else returns null
		   * @returns {string | null}
		   */
		  Index.prototype.getObjectProperty = function () {
		    return this.isObjectProperty() ? this._dimensions[0] : null;
		  };
	
		  /**
		   * Test whether this index contains only a single value.
		   *
		   * This is the case when the index is created with only scalar values as ranges,
		   * not for ranges resolving into a single value.
		   * @memberof Index
		   * @return {boolean} isScalar
		   */
		  Index.prototype.isScalar = function () {
		    return this._isScalar;
		  };
	
		  /**
		   * Expand the Index into an array.
		   * For example new Index([0,3], [2,7]) returns [[0,1,2], [2,3,4,5,6]]
		   * @memberof Index
		   * @returns {Array} array
		   */
		  Index.prototype.toArray = function () {
		    var array = [];
		    for (var i = 0, ii = this._dimensions.length; i < ii; i++) {
		      var dimension = this._dimensions[i];
		      array.push(typeof dimension === 'string' ? dimension : dimension.toArray());
		    }
		    return array;
		  };
	
		  /**
		   * Get the primitive value of the Index, a two dimensional array.
		   * Equivalent to Index.toArray().
		   * @memberof Index
		   * @returns {Array} array
		   */
		  Index.prototype.valueOf = Index.prototype.toArray;
	
		  /**
		   * Get the string representation of the index, for example '[2:6]' or '[0:2:10, 4:7, [1,2,3]]'
		   * @memberof Index
		   * @returns {String} str
		   */
		  Index.prototype.toString = function () {
		    var strings = [];
	
		    for (var i = 0, ii = this._dimensions.length; i < ii; i++) {
		      var dimension = this._dimensions[i];
		      if (typeof dimension === 'string') {
		        strings.push(JSON.stringify(dimension));
		      } else {
		        strings.push(dimension.toString());
		      }
		    }
	
		    return '[' + strings.join(', ') + ']';
		  };
	
		  /**
		   * Get a JSON representation of the Index
		   * @memberof Index
		   * @returns {Object} Returns a JSON object structured as:
		   *                   `{"mathjs": "Index", "ranges": [{"mathjs": "Range", start: 0, end: 10, step:1}, ...]}`
		   */
		  Index.prototype.toJSON = function () {
		    return {
		      mathjs: 'Index',
		      dimensions: this._dimensions
		    };
		  };
	
		  /**
		   * Instantiate an Index from a JSON object
		   * @memberof Index
		   * @param {Object} json A JSON object structured as:
		   *                     `{"mathjs": "Index", "dimensions": [{"mathjs": "Range", start: 0, end: 10, step:1}, ...]}`
		   * @return {Index}
		   */
		  Index.fromJSON = function (json) {
		    return Index.create(json.dimensions);
		  };
	
		  return Index;
		}
	
		exports.name = 'Index';
		exports.path = 'type';
		exports.factory = factory;
	
	/***/ }),
	/* 59 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var number = __webpack_require__(18);
	
		function factory(type, config, load, typed) {
		  /**
		   * Create a range. A range has a start, step, and end, and contains functions
		   * to iterate over the range.
		   *
		   * A range can be constructed as:
		   *     var range = new Range(start, end);
		   *     var range = new Range(start, end, step);
		   *
		   * To get the result of the range:
		   *     range.forEach(function (x) {
		   *         console.log(x);
		   *     });
		   *     range.map(function (x) {
		   *         return math.sin(x);
		   *     });
		   *     range.toArray();
		   *
		   * Example usage:
		   *     var c = new Range(2, 6);         // 2:1:5
		   *     c.toArray();                     // [2, 3, 4, 5]
		   *     var d = new Range(2, -3, -1);    // 2:-1:-2
		   *     d.toArray();                     // [2, 1, 0, -1, -2]
		   *
		   * @class Range
		   * @constructor Range
		   * @param {number} start  included lower bound
		   * @param {number} end    excluded upper bound
		   * @param {number} [step] step size, default value is 1
		   */
		  function Range(start, end, step) {
		    if (!(this instanceof Range)) {
		      throw new SyntaxError('Constructor must be called with the new operator');
		    }
	
		    if (start != null) {
		      if (type.isBigNumber(start)) start = start.toNumber();else if (typeof start !== 'number') throw new TypeError('Parameter start must be a number');
		    }
		    if (end != null) {
		      if (type.isBigNumber(end)) end = end.toNumber();else if (typeof end !== 'number') throw new TypeError('Parameter end must be a number');
		    }
		    if (step != null) {
		      if (type.isBigNumber(step)) step = step.toNumber();else if (typeof step !== 'number') throw new TypeError('Parameter step must be a number');
		    }
	
		    this.start = start != null ? parseFloat(start) : 0;
		    this.end = end != null ? parseFloat(end) : 0;
		    this.step = step != null ? parseFloat(step) : 1;
		  }
	
		  /**
		   * Attach type information
		   */
		  Range.prototype.type = 'Range';
		  Range.prototype.isRange = true;
	
		  /**
		   * Parse a string into a range,
		   * The string contains the start, optional step, and end, separated by a colon.
		   * If the string does not contain a valid range, null is returned.
		   * For example str='0:2:11'.
		   * @memberof Range
		   * @param {string} str
		   * @return {Range | null} range
		   */
		  Range.parse = function (str) {
		    if (typeof str !== 'string') {
		      return null;
		    }
	
		    var args = str.split(':');
		    var nums = args.map(function (arg) {
		      return parseFloat(arg);
		    });
	
		    var invalid = nums.some(function (num) {
		      return isNaN(num);
		    });
		    if (invalid) {
		      return null;
		    }
	
		    switch (nums.length) {
		      case 2:
		        return new Range(nums[0], nums[1]);
		      case 3:
		        return new Range(nums[0], nums[2], nums[1]);
		      default:
		        return null;
		    }
		  };
	
		  /**
		   * Create a clone of the range
		   * @return {Range} clone
		   */
		  Range.prototype.clone = function () {
		    return new Range(this.start, this.end, this.step);
		  };
	
		  /**
		   * Retrieve the size of the range.
		   * Returns an array containing one number, the number of elements in the range.
		   * @memberof Range
		   * @returns {number[]} size
		   */
		  Range.prototype.size = function () {
		    var len = 0,
		        start = this.start,
		        step = this.step,
		        end = this.end,
		        diff = end - start;
	
		    if (number.sign(step) == number.sign(diff)) {
		      len = Math.ceil(diff / step);
		    } else if (diff == 0) {
		      len = 0;
		    }
	
		    if (isNaN(len)) {
		      len = 0;
		    }
		    return [len];
		  };
	
		  /**
		   * Calculate the minimum value in the range
		   * @memberof Range
		   * @return {number | undefined} min
		   */
		  Range.prototype.min = function () {
		    var size = this.size()[0];
	
		    if (size > 0) {
		      if (this.step > 0) {
		        // positive step
		        return this.start;
		      } else {
		        // negative step
		        return this.start + (size - 1) * this.step;
		      }
		    } else {
		      return undefined;
		    }
		  };
	
		  /**
		   * Calculate the maximum value in the range
		   * @memberof Range
		   * @return {number | undefined} max
		   */
		  Range.prototype.max = function () {
		    var size = this.size()[0];
	
		    if (size > 0) {
		      if (this.step > 0) {
		        // positive step
		        return this.start + (size - 1) * this.step;
		      } else {
		        // negative step
		        return this.start;
		      }
		    } else {
		      return undefined;
		    }
		  };
	
		  /**
		   * Execute a callback function for each value in the range.
		   * @memberof Range
		   * @param {function} callback   The callback method is invoked with three
		   *                              parameters: the value of the element, the index
		   *                              of the element, and the Range being traversed.
		   */
		  Range.prototype.forEach = function (callback) {
		    var x = this.start;
		    var step = this.step;
		    var end = this.end;
		    var i = 0;
	
		    if (step > 0) {
		      while (x < end) {
		        callback(x, [i], this);
		        x += step;
		        i++;
		      }
		    } else if (step < 0) {
		      while (x > end) {
		        callback(x, [i], this);
		        x += step;
		        i++;
		      }
		    }
		  };
	
		  /**
		   * Execute a callback function for each value in the Range, and return the
		   * results as an array
		   * @memberof Range
		   * @param {function} callback   The callback method is invoked with three
		   *                              parameters: the value of the element, the index
		   *                              of the element, and the Matrix being traversed.
		   * @returns {Array} array
		   */
		  Range.prototype.map = function (callback) {
		    var array = [];
		    this.forEach(function (value, index, obj) {
		      array[index[0]] = callback(value, index, obj);
		    });
		    return array;
		  };
	
		  /**
		   * Create an Array with a copy of the Ranges data
		   * @memberof Range
		   * @returns {Array} array
		   */
		  Range.prototype.toArray = function () {
		    var array = [];
		    this.forEach(function (value, index) {
		      array[index[0]] = value;
		    });
		    return array;
		  };
	
		  /**
		   * Get the primitive value of the Range, a one dimensional array
		   * @memberof Range
		   * @returns {Array} array
		   */
		  Range.prototype.valueOf = function () {
		    // TODO: implement a caching mechanism for range.valueOf()
		    return this.toArray();
		  };
	
		  /**
		   * Get a string representation of the range, with optional formatting options.
		   * Output is formatted as 'start:step:end', for example '2:6' or '0:0.2:11'
		   * @memberof Range
		   * @param {Object | number | function} [options]  Formatting options. See
		   *                                                lib/utils/number:format for a
		   *                                                description of the available
		   *                                                options.
		   * @returns {string} str
		   */
		  Range.prototype.format = function (options) {
		    var str = number.format(this.start, options);
	
		    if (this.step != 1) {
		      str += ':' + number.format(this.step, options);
		    }
		    str += ':' + number.format(this.end, options);
		    return str;
		  };
	
		  /**
		   * Get a string representation of the range.
		   * @memberof Range
		   * @returns {string}
		   */
		  Range.prototype.toString = function () {
		    return this.format();
		  };
	
		  /**
		   * Get a JSON representation of the range
		   * @memberof Range
		   * @returns {Object} Returns a JSON object structured as:
		   *                   `{"mathjs": "Range", "start": 2, "end": 4, "step": 1}`
		   */
		  Range.prototype.toJSON = function () {
		    return {
		      mathjs: 'Range',
		      start: this.start,
		      end: this.end,
		      step: this.step
		    };
		  };
	
		  /**
		   * Instantiate a Range from a JSON object
		   * @memberof Range
		   * @param {Object} json A JSON object structured as:
		   *                      `{"mathjs": "Range", "start": 2, "end": 4, "step": 1}`
		   * @return {Range}
		   */
		  Range.fromJSON = function (json) {
		    return new Range(json.start, json.end, json.step);
		  };
	
		  return Range;
		}
	
		exports.name = 'Range';
		exports.path = 'type';
		exports.factory = factory;
	
	/***/ }),
	/* 60 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
		  /**
		   * Create an index. An Index can store ranges having start, step, and end
		   * for multiple dimensions.
		   * Matrix.get, Matrix.set, and math.subset accept an Index as input.
		   *
		   * Syntax:
		   *
		   *     math.index(range1, range2, ...)
		   *
		   * Where each range can be any of:
		   *
		   * - A number
		   * - A string for getting/setting an object property
		   * - An instance of `Range`
		   * - A one-dimensional Array or a Matrix with numbers
		   *
		   * Indexes must be zero-based, integer numbers.
		   *
		   * Examples:
		   *
		   *    var math = math.js
		   *
		   *    var b = [1, 2, 3, 4, 5];
		   *    math.subset(b, math.index([1, 2, 3]));     // returns [2, 3, 4]
		   *
		   *    var a = math.matrix([[1, 2], [3, 4]]);
		   *    a.subset(math.index(0, 1));             // returns 2
		   *
		   * See also:
		   *
		   *    bignumber, boolean, complex, matrix, number, string, unit
		   *
		   * @param {...*} ranges   Zero or more ranges or numbers.
		   * @return {Index}        Returns the created index
		   */
		  return typed('index', {
		    '...number | string | BigNumber | Range | Array | Matrix': function numberStringBigNumberRangeArrayMatrix(args) {
		      var ranges = args.map(function (arg) {
		        if (type.isBigNumber(arg)) {
		          return arg.toNumber(); // convert BigNumber to Number
		        } else if (Array.isArray(arg) || type.isMatrix(arg)) {
		          return arg.map(function (elem) {
		            // convert BigNumber to Number
		            return type.isBigNumber(elem) ? elem.toNumber() : elem;
		          });
		        } else {
		          return arg;
		        }
		      });
	
		      var res = new type.Index();
		      type.Index.apply(res, ranges);
		      return res;
		    }
		  });
		}
	
		exports.name = 'index';
		exports.factory = factory;
	
	/***/ }),
	/* 61 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
	
		  var SparseMatrix = type.SparseMatrix;
	
		  /**
		   * Create a Sparse Matrix. The function creates a new `math.type.Matrix` object from
		   * an `Array`. A Matrix has utility functions to manipulate the data in the
		   * matrix, like getting the size and getting or setting values in the matrix.
		   *
		   * Syntax:
		   *
		   *    math.sparse()               // creates an empty sparse matrix.
		   *    math.sparse(data)           // creates a sparse matrix with initial data.
		   *    math.sparse(data, 'number') // creates a sparse matrix with initial data, number datatype.
		   *
		   * Examples:
		   *
		   *    var m = math.sparse([[1, 2], [3, 4]]);
		   *    m.size();                        // Array [2, 2]
		   *    m.resize([3, 2], 5);
		   *    m.valueOf();                     // Array [[1, 2], [3, 4], [5, 5]]
		   *    m.get([1, 0])                    // number 3
		   *
		   * See also:
		   *
		   *    bignumber, boolean, complex, index, number, string, unit, matrix
		   *
		   * @param {Array | Matrix} [data]    A two dimensional array
		   *
		   * @return {Matrix} The created matrix
		   */
		  var sparse = typed('sparse', {
		    '': function _() {
		      return new SparseMatrix([]);
		    },
	
		    'string': function string(datatype) {
		      return new SparseMatrix([], datatype);
		    },
	
		    'Array | Matrix': function ArrayMatrix(data) {
		      return new SparseMatrix(data);
		    },
	
		    'Array | Matrix, string': function ArrayMatrixString(data, datatype) {
		      return new SparseMatrix(data, datatype);
		    }
		  });
	
		  sparse.toTex = {
		    0: '\\begin{bsparse}\\end{bsparse}',
		    1: '\\left(${args[0]}\\right)'
		  };
	
		  return sparse;
		}
	
		exports.name = 'sparse';
		exports.factory = factory;
	
	/***/ }),
	/* 62 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var isInteger = __webpack_require__(18).isInteger;
		var resize = __webpack_require__(28).resize;
	
		function factory(type, config, load, typed) {
		  var matrix = load(__webpack_require__(43));
	
		  /**
		   * Create a matrix filled with zeros. The created matrix can have one or
		   * multiple dimensions.
		   *
		   * Syntax:
		   *
		   *    math.zeros(m)
		   *    math.zeros(m, format)
		   *    math.zeros(m, n)
		   *    math.zeros(m, n, format)
		   *    math.zeros([m, n])
		   *    math.zeros([m, n], format)
		   *
		   * Examples:
		   *
		   *    math.zeros(3);                  // returns [0, 0, 0]
		   *    math.zeros(3, 2);               // returns [[0, 0], [0, 0], [0, 0]]
		   *    math.zeros(3, 'dense');         // returns [0, 0, 0]
		   *
		   *    var A = [[1, 2, 3], [4, 5, 6]];
		   *    math.zeros(math.size(A));       // returns [[0, 0, 0], [0, 0, 0]]
		   *
		   * See also:
		   *
		   *    ones, eye, size, range
		   *
		   * @param {...number | Array} size    The size of each dimension of the matrix
		   * @param {string} [format]           The Matrix storage format
		   *
		   * @return {Array | Matrix}           A matrix filled with zeros
		   */
		  var zeros = typed('zeros', {
		    '': function _() {
		      return config.matrix === 'Array' ? _zeros([]) : _zeros([], 'default');
		    },
	
		    // math.zeros(m, n, p, ..., format)
		    // TODO: more accurate signature '...number | BigNumber, string' as soon as typed-function supports this
		    '...number | BigNumber | string': function numberBigNumberString(size) {
		      var last = size[size.length - 1];
		      if (typeof last === 'string') {
		        var format = size.pop();
		        return _zeros(size, format);
		      } else if (config.matrix === 'Array') {
		        return _zeros(size);
		      } else {
		        return _zeros(size, 'default');
		      }
		    },
	
		    'Array': _zeros,
	
		    'Matrix': function Matrix(size) {
		      var format = size.storage();
		      return _zeros(size.valueOf(), format);
		    },
	
		    'Array | Matrix, string': function ArrayMatrixString(size, format) {
		      return _zeros(size.valueOf(), format);
		    }
		  });
	
		  zeros.toTex = undefined; // use default template
	
		  return zeros;
	
		  /**
		   * Create an Array or Matrix with zeros
		   * @param {Array} size
		   * @param {string} [format='default']
		   * @return {Array | Matrix}
		   * @private
		   */
		  function _zeros(size, format) {
		    var hasBigNumbers = _normalize(size);
		    var defaultValue = hasBigNumbers ? new type.BigNumber(0) : 0;
		    _validate(size);
	
		    if (format) {
		      // return a matrix
		      var m = matrix(format);
		      if (size.length > 0) {
		        return m.resize(size, defaultValue);
		      }
		      return m;
		    } else {
		      // return an Array
		      var arr = [];
		      if (size.length > 0) {
		        return resize(arr, size, defaultValue);
		      }
		      return arr;
		    }
		  }
	
		  // replace BigNumbers with numbers, returns true if size contained BigNumbers
		  function _normalize(size) {
		    var hasBigNumbers = false;
		    size.forEach(function (value, index, arr) {
		      if (type.isBigNumber(value)) {
		        hasBigNumbers = true;
		        arr[index] = value.toNumber();
		      }
		    });
		    return hasBigNumbers;
		  }
	
		  // validate arguments
		  function _validate(size) {
		    size.forEach(function (value) {
		      if (typeof value !== 'number' || !isInteger(value) || value < 0) {
		        throw new Error('Parameters in function zeros must be positive integers');
		      }
		    });
		  }
		}
	
		// TODO: zeros contains almost the same code as ones. Reuse this?
	
		exports.name = 'zeros';
		exports.factory = factory;
	
	/***/ }),
	/* 63 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
		var get_filter_default_state = __webpack_require__(5);
	
		module.exports = function get_subset_views(params, views, requested_view) {
	
		  var inst_value;
		  var found_filter;
	
		  var request_filters = _.keys(requested_view);
	
		  // find a view that matches all of the requested view/filter-attributes 
		  _.each(request_filters, function (inst_filter) {
	
		    inst_value = requested_view[inst_filter];
	
		    // if the value is a number, then convert it to an integer 
		    if (/[^a-z_]/i.test(inst_value)) {
		      inst_value = parseInt(inst_value, 10);
		    }
	
		    // only run filtering if any of the views has the filter 
		    found_filter = false;
		    _.each(views, function (tmp_view) {
		      if (utils.has(tmp_view, inst_filter)) {
		        found_filter = true;
		      }
		    });
	
		    if (found_filter) {
		      views = _.filter(views, function (d) {
		        return d[inst_filter] == inst_value;
		      });
		    }
		  });
	
		  // remove duplicate complete default states 
		  var export_views = [];
		  var found_default = false;
		  var check_default;
		  var inst_default_state;
	
		  // check if each view is a default state: all filters are at default 
		  // there can only be one of these 
		  _.each(views, function (inst_view) {
	
		    check_default = true;
	
		    // check each filter in a view to see if it is in the default state 
		    _.each(_.keys(params.viz.possible_filters), function (inst_filter) {
	
		      inst_default_state = get_filter_default_state(params.viz.filter_data, inst_filter);
	
		      if (inst_view[inst_filter] != inst_default_state) {
		        check_default = false;
		      }
		    });
	
		    // found defaule view, only append if you have not already found a default
		    if (check_default) {
		      if (found_default === false) {
		        found_default = true;
		        export_views.push(inst_view);
		      }
		    } else {
		      export_views.push(inst_view);
		    }
		  });
	
		  // if (export_views.length > 1){
		  //   console.log('found more than one view in get_subset_views')
		  //   console.log(requested_view)
		  //   console.log(export_views)
		  // } else {
		  //   console.log('found single view in get_subset_views')
		  //   console.log(requested_view)
		  //   console.log(export_views[0])
		  //   console.log('\n')
		  // }
	
		  return export_views;
			};
	
	/***/ }),
	/* 64 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function ini_sidebar_params(params) {
		  var sidebar = {};
	
		  sidebar.wrapper = {};
		  // sidebar.wrapper.width = 170;
	
		  sidebar.row_search = {};
		  sidebar.row_search.box = {};
		  sidebar.row_search.box.height = 34;
		  sidebar.row_search.box.width = 95;
		  sidebar.row_search.placeholder = params.row_search_placeholder;
		  sidebar.row_search.margin_left = 7;
	
		  sidebar.slider = {};
		  sidebar.slider.width = params.sidebar_width - 30;
		  sidebar.slider.margin_left = 15;
	
		  sidebar.key_cat = {};
		  sidebar.key_cat.width = params.sidebar_width - 15;
		  sidebar.key_cat.margin_left = 5;
		  sidebar.key_cat.max_height = 100;
	
		  sidebar.title = params.title;
		  sidebar.title_margin_left = 7;
		  sidebar.about = params.about;
		  sidebar.width = params.sidebar_width;
	
		  sidebar.buttons = {};
		  sidebar.buttons.width = params.sidebar_width - 15;
	
		  sidebar.text = {};
	
		  sidebar.icons = params.sidebar_icons;
		  sidebar.icon_margin_left = -5;
	
		  return sidebar;
		};
	
	/***/ }),
	/* 65 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function make_view_request(params, requested_view) {
	
		  // this will add all necessary information to a view request 
		  // it will grab necessary view information from the sliders 
	
		  // only one component will be changed at a time 
		  var changed_component = _.keys(requested_view)[0];
	
		  // add additional filter information from othe possible filters 
		  _.each(_.keys(params.viz.possible_filters), function (inst_filter) {
	
		    if (inst_filter != changed_component) {
	
		      if (!d3.select(params.root + ' .slider_' + inst_filter).empty()) {
	
		        var inst_state = d3.select(params.root + ' .slider_' + inst_filter).attr('current_state');
	
		        requested_view[inst_filter] = inst_state;
		      }
		    }
		  });
	
		  return requested_view;
			};
	
	/***/ }),
	/* 66 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var ini_label_params = __webpack_require__(67);
		var set_viz_wrapper_size = __webpack_require__(69);
		var get_svg_dim = __webpack_require__(71);
		var calc_label_params = __webpack_require__(72);
		var calc_clust_width = __webpack_require__(73);
		var calc_clust_height = __webpack_require__(74);
		var calc_val_max = __webpack_require__(75);
		var calc_matrix_params = __webpack_require__(76);
		var set_zoom_params = __webpack_require__(81);
		var calc_default_fs = __webpack_require__(83);
		var utils = __webpack_require__(2);
		var get_available_filters = __webpack_require__(4);
		var make_cat_params = __webpack_require__(84);
	
		module.exports = function calc_viz_params(params) {
		  var predefined_cat_colors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
	
	
		  params.labels = ini_label_params(params);
		  params.viz = ini_viz_params(params, predefined_cat_colors);
	
		  set_viz_wrapper_size(params);
	
		  params = get_svg_dim(params);
		  params.viz = calc_label_params(params.viz);
		  params.viz = calc_clust_width(params.viz);
		  params.viz = calc_clust_height(params.viz);
	
		  if (params.sim_mat) {
		    if (params.viz.clust.dim.width <= params.viz.clust.dim.height) {
		      params.viz.clust.dim.height = params.viz.clust.dim.width;
		    } else {
		      params.viz.clust.dim.width = params.viz.clust.dim.height;
		    }
		  }
	
		  params = calc_val_max(params);
		  params = calc_matrix_params(params);
		  params = set_zoom_params(params);
		  params = calc_default_fs(params);
	
		  function ini_viz_params(params) {
		    var predefined_cat_colors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
	
	
		    var viz = {};
	
		    viz.root = params.root;
	
		    viz.root_tips = params.root.replace('#', '.') + '_' + 'd3-tip';
	
		    viz.viz_wrapper = params.root + ' .viz_wrapper';
		    viz.do_zoom = params.do_zoom;
		    viz.background_color = params.background_color;
		    viz.super_border_color = params.super_border_color;
		    viz.outer_margins = params.outer_margins;
		    viz.is_expand = params.ini_expand;
		    viz.grey_border_width = params.grey_border_width;
		    viz.show_dendrogram = params.show_dendrogram;
		    viz.tile_click_hlight = params.tile_click_hlight;
		    viz.inst_order = params.inst_order;
		    viz.expand_button = params.expand_button;
		    viz.sim_mat = params.sim_mat;
		    viz.dendro_filter = params.dendro_filter;
		    viz.cat_filter = params.cat_filter;
		    viz.cat_value_colors = params.cat_value_colors;
	
		    viz.viz_svg = viz.viz_wrapper + ' .viz_svg';
	
		    viz.zoom_element = viz.viz_wrapper + ' .viz_svg';
	
		    viz.uni_duration = 1000;
		    // extra space below the clustergram (was 5)
		    // will increase this to accomidate dendro slider
		    viz.bottom_space = 10;
		    viz.run_trans = false;
		    viz.duration = 1000;
	
		    viz.resize = params.resize;
		    if (utils.has(params, 'size')) {
		      viz.fixed_size = params.size;
		    } else {
		      viz.fixed_size = false;
		    }
	
		    // width is 1 over this value
		    viz.border_fraction = 65;
		    viz.uni_margin = 5;
	
		    viz.super_labels = {};
		    viz.super_labels.margin = {};
		    viz.super_labels.dim = {};
		    viz.super_labels.margin.left = viz.grey_border_width;
		    viz.super_labels.margin.top = viz.grey_border_width;
		    viz.super_labels.dim.width = 0;
		    if (params.labels.super_labels) {
		      viz.super_labels.dim.width = 15 * params.labels.super_label_scale;
		    }
	
		    viz.triangle_opacity = 0.6;
	
		    viz.norm_labels = {};
		    viz.norm_labels.width = {};
	
		    viz.dendro_room = {};
		    if (viz.show_dendrogram) {
		      viz.dendro_room.symbol_width = 10;
		    } else {
		      viz.dendro_room.symbol_width = 0;
		    }
	
		    viz.cat_colors = params.cat_colors;
	
		    // console.log('ini_viz_params -> make_cat_params')
		    // console.log('predefined_cat_colors outside function ' + String(predefined_cat_colors))
	
		    viz = make_cat_params(params, viz, predefined_cat_colors);
	
		    // // always make group level dict
		    // params.group_level = {};
	
		    if (_.has(params, 'group_level') == false) {
		      if (viz.show_dendrogram) {
		        params.group_level = {};
		      }
	
		      // preventing error when un-clustered, above statement
		      // preserves dendro state while updating
		      if (_.has(params, 'group_level') == false) {
		        params.group_level = {};
		      }
	
		      params.group_level.row = 5;
		      params.group_level.col = 5;
		    }
	
		    viz.dendro_opacity = 0.35;
	
		    viz.spillover_col_slant = viz.norm_labels.width.col;
	
		    var filters = get_available_filters(params.network_data.views);
	
		    viz.possible_filters = filters.possible_filters;
		    viz.filter_data = filters.filter_data;
	
		    viz.viz_nodes = {};
	
		    // nodes that should be visible based on visible area
		    viz.viz_nodes.row = params.network_data.row_nodes_names;
		    viz.viz_nodes.col = params.network_data.col_nodes_names;
	
		    // nodes that are currently visible
		    viz.viz_nodes.curr_row = params.network_data.row_nodes_names;
		    viz.viz_nodes.curr_col = params.network_data.col_nodes_names;
	
		    // correct panning in x direction
		    viz.x_offset = 0;
	
		    return viz;
		  }
	
		  return params;
		};
	
	/***/ }),
	/* 67 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var underscore = __webpack_require__(68);
	
		module.exports = function ini_label_params(params) {
	
		  var labels = {};
		  labels.super_label_scale = params.super_label_scale;
		  labels.super_labels = params.super_labels;
		  labels.super_label_fs = 13.8;
	
		  if (labels.super_labels) {
		    labels.super = {};
		    labels.super.row = params.super.row;
		    labels.super.col = params.super.col;
		  }
	
		  labels.show_label_tooltips = params.show_label_tooltips;
	
		  labels.row_max_char = underscore.max(params.network_data.row_nodes, function (inst) {
		    return inst.name.length;
		  }).name.length;
	
		  labels.col_max_char = underscore.max(params.network_data.col_nodes, function (inst) {
		    return inst.name.length;
		  }).name.length;
	
		  labels.max_allow_fs = params.max_allow_fs;
	
		  return labels;
		};
	
	/***/ }),
	/* 68 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;'use strict';
	
		var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
	
		//     Underscore.js 1.8.3
		//     http://underscorejs.org
		//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
		//     Underscore may be freely distributed under the MIT license.
	
		(function () {
	
		  // Baseline setup
		  // --------------
	
		  // Establish the root object, `window` in the browser, or `exports` on the server.
		  var root = this;
	
		  // Save the previous value of the `_` variable.
		  var previousUnderscore = root._;
	
		  // Save bytes in the minified (but not gzipped) version:
		  var ArrayProto = Array.prototype,
		      ObjProto = Object.prototype,
		      FuncProto = Function.prototype;
	
		  // Create quick reference variables for speed access to core prototypes.
		  var push = ArrayProto.push,
		      slice = ArrayProto.slice,
		      toString = ObjProto.toString,
		      hasOwnProperty = ObjProto.hasOwnProperty;
	
		  // All **ECMAScript 5** native function implementations that we hope to use
		  // are declared here.
		  var nativeIsArray = Array.isArray,
		      nativeKeys = Object.keys,
		      nativeBind = FuncProto.bind,
		      nativeCreate = Object.create;
	
		  // Naked function reference for surrogate-prototype-swapping.
		  var Ctor = function Ctor() {};
	
		  // Create a safe reference to the Underscore object for use below.
		  var _ = function _(obj) {
		    if (obj instanceof _) return obj;
		    if (!(this instanceof _)) return new _(obj);
		    this._wrapped = obj;
		  };
	
		  // Export the Underscore object for **Node.js**, with
		  // backwards-compatibility for the old `require()` API. If we're in
		  // the browser, add `_` as a global object.
		  if (true) {
		    if (typeof module !== 'undefined' && module.exports) {
		      exports = module.exports = _;
		    }
		    exports._ = _;
		  } else {
		    root._ = _;
		  }
	
		  // Current version.
		  _.VERSION = '1.8.3';
	
		  // Internal function that returns an efficient (for current engines) version
		  // of the passed-in callback, to be repeatedly applied in other Underscore
		  // functions.
		  var optimizeCb = function optimizeCb(func, context, argCount) {
		    if (context === void 0) return func;
		    switch (argCount == null ? 3 : argCount) {
		      case 1:
		        return function (value) {
		          return func.call(context, value);
		        };
		      case 2:
		        return function (value, other) {
		          return func.call(context, value, other);
		        };
		      case 3:
		        return function (value, index, collection) {
		          return func.call(context, value, index, collection);
		        };
		      case 4:
		        return function (accumulator, value, index, collection) {
		          return func.call(context, accumulator, value, index, collection);
		        };
		    }
		    return function () {
		      return func.apply(context, arguments);
		    };
		  };
	
		  // A mostly-internal function to generate callbacks that can be applied
		  // to each element in a collection, returning the desired result — either
		  // identity, an arbitrary callback, a property matcher, or a property accessor.
		  var cb = function cb(value, context, argCount) {
		    if (value == null) return _.identity;
		    if (_.isFunction(value)) return optimizeCb(value, context, argCount);
		    if (_.isObject(value)) return _.matcher(value);
		    return _.property(value);
		  };
		  _.iteratee = function (value, context) {
		    return cb(value, context, Infinity);
		  };
	
		  // An internal function for creating assigner functions.
		  var createAssigner = function createAssigner(keysFunc, undefinedOnly) {
		    return function (obj) {
		      var length = arguments.length;
		      if (length < 2 || obj == null) return obj;
		      for (var index = 1; index < length; index++) {
		        var source = arguments[index],
		            keys = keysFunc(source),
		            l = keys.length;
		        for (var i = 0; i < l; i++) {
		          var key = keys[i];
		          if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
		        }
		      }
		      return obj;
		    };
		  };
	
		  // An internal function for creating a new object that inherits from another.
		  var baseCreate = function baseCreate(prototype) {
		    if (!_.isObject(prototype)) return {};
		    if (nativeCreate) return nativeCreate(prototype);
		    Ctor.prototype = prototype;
		    var result = new Ctor();
		    Ctor.prototype = null;
		    return result;
		  };
	
		  var property = function property(key) {
		    return function (obj) {
		      return obj == null ? void 0 : obj[key];
		    };
		  };
	
		  // Helper for collection methods to determine whether a collection
		  // should be iterated as an array or as an object
		  // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
		  // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
		  var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
		  var getLength = property('length');
		  var isArrayLike = function isArrayLike(collection) {
		    var length = getLength(collection);
		    return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
		  };
	
		  // Collection Functions
		  // --------------------
	
		  // The cornerstone, an `each` implementation, aka `forEach`.
		  // Handles raw objects in addition to array-likes. Treats all
		  // sparse array-likes as if they were dense.
		  _.each = _.forEach = function (obj, iteratee, context) {
		    iteratee = optimizeCb(iteratee, context);
		    var i, length;
		    if (isArrayLike(obj)) {
		      for (i = 0, length = obj.length; i < length; i++) {
		        iteratee(obj[i], i, obj);
		      }
		    } else {
		      var keys = _.keys(obj);
		      for (i = 0, length = keys.length; i < length; i++) {
		        iteratee(obj[keys[i]], keys[i], obj);
		      }
		    }
		    return obj;
		  };
	
		  // Return the results of applying the iteratee to each element.
		  _.map = _.collect = function (obj, iteratee, context) {
		    iteratee = cb(iteratee, context);
		    var keys = !isArrayLike(obj) && _.keys(obj),
		        length = (keys || obj).length,
		        results = Array(length);
		    for (var index = 0; index < length; index++) {
		      var currentKey = keys ? keys[index] : index;
		      results[index] = iteratee(obj[currentKey], currentKey, obj);
		    }
		    return results;
		  };
	
		  // Create a reducing function iterating left or right.
		  function createReduce(dir) {
		    // Optimized iterator function as using arguments.length
		    // in the main function will deoptimize the, see #1991.
		    function iterator(obj, iteratee, memo, keys, index, length) {
		      for (; index >= 0 && index < length; index += dir) {
		        var currentKey = keys ? keys[index] : index;
		        memo = iteratee(memo, obj[currentKey], currentKey, obj);
		      }
		      return memo;
		    }
	
		    return function (obj, iteratee, memo, context) {
		      iteratee = optimizeCb(iteratee, context, 4);
		      var keys = !isArrayLike(obj) && _.keys(obj),
		          length = (keys || obj).length,
		          index = dir > 0 ? 0 : length - 1;
		      // Determine the initial value if none is provided.
		      if (arguments.length < 3) {
		        memo = obj[keys ? keys[index] : index];
		        index += dir;
		      }
		      return iterator(obj, iteratee, memo, keys, index, length);
		    };
		  }
	
		  // **Reduce** builds up a single result from a list of values, aka `inject`,
		  // or `foldl`.
		  _.reduce = _.foldl = _.inject = createReduce(1);
	
		  // The right-associative version of reduce, also known as `foldr`.
		  _.reduceRight = _.foldr = createReduce(-1);
	
		  // Return the first value which passes a truth test. Aliased as `detect`.
		  _.find = _.detect = function (obj, predicate, context) {
		    var key;
		    if (isArrayLike(obj)) {
		      key = _.findIndex(obj, predicate, context);
		    } else {
		      key = _.findKey(obj, predicate, context);
		    }
		    if (key !== void 0 && key !== -1) return obj[key];
		  };
	
		  // Return all the elements that pass a truth test.
		  // Aliased as `select`.
		  _.filter = _.select = function (obj, predicate, context) {
		    var results = [];
		    predicate = cb(predicate, context);
		    _.each(obj, function (value, index, list) {
		      if (predicate(value, index, list)) results.push(value);
		    });
		    return results;
		  };
	
		  // Return all the elements for which a truth test fails.
		  _.reject = function (obj, predicate, context) {
		    return _.filter(obj, _.negate(cb(predicate)), context);
		  };
	
		  // Determine whether all of the elements match a truth test.
		  // Aliased as `all`.
		  _.every = _.all = function (obj, predicate, context) {
		    predicate = cb(predicate, context);
		    var keys = !isArrayLike(obj) && _.keys(obj),
		        length = (keys || obj).length;
		    for (var index = 0; index < length; index++) {
		      var currentKey = keys ? keys[index] : index;
		      if (!predicate(obj[currentKey], currentKey, obj)) return false;
		    }
		    return true;
		  };
	
		  // Determine if at least one element in the object matches a truth test.
		  // Aliased as `any`.
		  _.some = _.any = function (obj, predicate, context) {
		    predicate = cb(predicate, context);
		    var keys = !isArrayLike(obj) && _.keys(obj),
		        length = (keys || obj).length;
		    for (var index = 0; index < length; index++) {
		      var currentKey = keys ? keys[index] : index;
		      if (predicate(obj[currentKey], currentKey, obj)) return true;
		    }
		    return false;
		  };
	
		  // Determine if the array or object contains a given item (using `===`).
		  // Aliased as `includes` and `include`.
		  _.contains = _.includes = _.include = function (obj, item, fromIndex, guard) {
		    if (!isArrayLike(obj)) obj = _.values(obj);
		    if (typeof fromIndex != 'number' || guard) fromIndex = 0;
		    return _.indexOf(obj, item, fromIndex) >= 0;
		  };
	
		  // Invoke a method (with arguments) on every item in a collection.
		  _.invoke = function (obj, method) {
		    var args = slice.call(arguments, 2);
		    var isFunc = _.isFunction(method);
		    return _.map(obj, function (value) {
		      var func = isFunc ? method : value[method];
		      return func == null ? func : func.apply(value, args);
		    });
		  };
	
		  // Convenience version of a common use case of `map`: fetching a property.
		  _.pluck = function (obj, key) {
		    return _.map(obj, _.property(key));
		  };
	
		  // Convenience version of a common use case of `filter`: selecting only objects
		  // containing specific `key:value` pairs.
		  _.where = function (obj, attrs) {
		    return _.filter(obj, _.matcher(attrs));
		  };
	
		  // Convenience version of a common use case of `find`: getting the first object
		  // containing specific `key:value` pairs.
		  _.findWhere = function (obj, attrs) {
		    return _.find(obj, _.matcher(attrs));
		  };
	
		  // Return the maximum element (or element-based computation).
		  _.max = function (obj, iteratee, context) {
		    var result = -Infinity,
		        lastComputed = -Infinity,
		        value,
		        computed;
		    if (iteratee == null && obj != null) {
		      obj = isArrayLike(obj) ? obj : _.values(obj);
		      for (var i = 0, length = obj.length; i < length; i++) {
		        value = obj[i];
		        if (value > result) {
		          result = value;
		        }
		      }
		    } else {
		      iteratee = cb(iteratee, context);
		      _.each(obj, function (value, index, list) {
		        computed = iteratee(value, index, list);
		        if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
		          result = value;
		          lastComputed = computed;
		        }
		      });
		    }
		    return result;
		  };
	
		  // Return the minimum element (or element-based computation).
		  _.min = function (obj, iteratee, context) {
		    var result = Infinity,
		        lastComputed = Infinity,
		        value,
		        computed;
		    if (iteratee == null && obj != null) {
		      obj = isArrayLike(obj) ? obj : _.values(obj);
		      for (var i = 0, length = obj.length; i < length; i++) {
		        value = obj[i];
		        if (value < result) {
		          result = value;
		        }
		      }
		    } else {
		      iteratee = cb(iteratee, context);
		      _.each(obj, function (value, index, list) {
		        computed = iteratee(value, index, list);
		        if (computed < lastComputed || computed === Infinity && result === Infinity) {
		          result = value;
		          lastComputed = computed;
		        }
		      });
		    }
		    return result;
		  };
	
		  // Shuffle a collection, using the modern version of the
		  // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
		  _.shuffle = function (obj) {
		    var set = isArrayLike(obj) ? obj : _.values(obj);
		    var length = set.length;
		    var shuffled = Array(length);
		    for (var index = 0, rand; index < length; index++) {
		      rand = _.random(0, index);
		      if (rand !== index) shuffled[index] = shuffled[rand];
		      shuffled[rand] = set[index];
		    }
		    return shuffled;
		  };
	
		  // Sample **n** random values from a collection.
		  // If **n** is not specified, returns a single random element.
		  // The internal `guard` argument allows it to work with `map`.
		  _.sample = function (obj, n, guard) {
		    if (n == null || guard) {
		      if (!isArrayLike(obj)) obj = _.values(obj);
		      return obj[_.random(obj.length - 1)];
		    }
		    return _.shuffle(obj).slice(0, Math.max(0, n));
		  };
	
		  // Sort the object's values by a criterion produced by an iteratee.
		  _.sortBy = function (obj, iteratee, context) {
		    iteratee = cb(iteratee, context);
		    return _.pluck(_.map(obj, function (value, index, list) {
		      return {
		        value: value,
		        index: index,
		        criteria: iteratee(value, index, list)
		      };
		    }).sort(function (left, right) {
		      var a = left.criteria;
		      var b = right.criteria;
		      if (a !== b) {
		        if (a > b || a === void 0) return 1;
		        if (a < b || b === void 0) return -1;
		      }
		      return left.index - right.index;
		    }), 'value');
		  };
	
		  // An internal function used for aggregate "group by" operations.
		  var group = function group(behavior) {
		    return function (obj, iteratee, context) {
		      var result = {};
		      iteratee = cb(iteratee, context);
		      _.each(obj, function (value, index) {
		        var key = iteratee(value, index, obj);
		        behavior(result, value, key);
		      });
		      return result;
		    };
		  };
	
		  // Groups the object's values by a criterion. Pass either a string attribute
		  // to group by, or a function that returns the criterion.
		  _.groupBy = group(function (result, value, key) {
		    if (_.has(result, key)) result[key].push(value);else result[key] = [value];
		  });
	
		  // Indexes the object's values by a criterion, similar to `groupBy`, but for
		  // when you know that your index values will be unique.
		  _.indexBy = group(function (result, value, key) {
		    result[key] = value;
		  });
	
		  // Counts instances of an object that group by a certain criterion. Pass
		  // either a string attribute to count by, or a function that returns the
		  // criterion.
		  _.countBy = group(function (result, value, key) {
		    if (_.has(result, key)) result[key]++;else result[key] = 1;
		  });
	
		  // Safely create a real, live array from anything iterable.
		  _.toArray = function (obj) {
		    if (!obj) return [];
		    if (_.isArray(obj)) return slice.call(obj);
		    if (isArrayLike(obj)) return _.map(obj, _.identity);
		    return _.values(obj);
		  };
	
		  // Return the number of elements in an object.
		  _.size = function (obj) {
		    if (obj == null) return 0;
		    return isArrayLike(obj) ? obj.length : _.keys(obj).length;
		  };
	
		  // Split a collection into two arrays: one whose elements all satisfy the given
		  // predicate, and one whose elements all do not satisfy the predicate.
		  _.partition = function (obj, predicate, context) {
		    predicate = cb(predicate, context);
		    var pass = [],
		        fail = [];
		    _.each(obj, function (value, key, obj) {
		      (predicate(value, key, obj) ? pass : fail).push(value);
		    });
		    return [pass, fail];
		  };
	
		  // Array Functions
		  // ---------------
	
		  // Get the first element of an array. Passing **n** will return the first N
		  // values in the array. Aliased as `head` and `take`. The **guard** check
		  // allows it to work with `_.map`.
		  _.first = _.head = _.take = function (array, n, guard) {
		    if (array == null) return void 0;
		    if (n == null || guard) return array[0];
		    return _.initial(array, array.length - n);
		  };
	
		  // Returns everything but the last entry of the array. Especially useful on
		  // the arguments object. Passing **n** will return all the values in
		  // the array, excluding the last N.
		  _.initial = function (array, n, guard) {
		    return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
		  };
	
		  // Get the last element of an array. Passing **n** will return the last N
		  // values in the array.
		  _.last = function (array, n, guard) {
		    if (array == null) return void 0;
		    if (n == null || guard) return array[array.length - 1];
		    return _.rest(array, Math.max(0, array.length - n));
		  };
	
		  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
		  // Especially useful on the arguments object. Passing an **n** will return
		  // the rest N values in the array.
		  _.rest = _.tail = _.drop = function (array, n, guard) {
		    return slice.call(array, n == null || guard ? 1 : n);
		  };
	
		  // Trim out all falsy values from an array.
		  _.compact = function (array) {
		    return _.filter(array, _.identity);
		  };
	
		  // Internal implementation of a recursive `flatten` function.
		  var flatten = function flatten(input, shallow, strict, startIndex) {
		    var output = [],
		        idx = 0;
		    for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
		      var value = input[i];
		      if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
		        //flatten current level of array or arguments object
		        if (!shallow) value = flatten(value, shallow, strict);
		        var j = 0,
		            len = value.length;
		        output.length += len;
		        while (j < len) {
		          output[idx++] = value[j++];
		        }
		      } else if (!strict) {
		        output[idx++] = value;
		      }
		    }
		    return output;
		  };
	
		  // Flatten out an array, either recursively (by default), or just one level.
		  _.flatten = function (array, shallow) {
		    return flatten(array, shallow, false);
		  };
	
		  // Return a version of the array that does not contain the specified value(s).
		  _.without = function (array) {
		    return _.difference(array, slice.call(arguments, 1));
		  };
	
		  // Produce a duplicate-free version of the array. If the array has already
		  // been sorted, you have the option of using a faster algorithm.
		  // Aliased as `unique`.
		  _.uniq = _.unique = function (array, isSorted, iteratee, context) {
		    if (!_.isBoolean(isSorted)) {
		      context = iteratee;
		      iteratee = isSorted;
		      isSorted = false;
		    }
		    if (iteratee != null) iteratee = cb(iteratee, context);
		    var result = [];
		    var seen = [];
		    for (var i = 0, length = getLength(array); i < length; i++) {
		      var value = array[i],
		          computed = iteratee ? iteratee(value, i, array) : value;
		      if (isSorted) {
		        if (!i || seen !== computed) result.push(value);
		        seen = computed;
		      } else if (iteratee) {
		        if (!_.contains(seen, computed)) {
		          seen.push(computed);
		          result.push(value);
		        }
		      } else if (!_.contains(result, value)) {
		        result.push(value);
		      }
		    }
		    return result;
		  };
	
		  // Produce an array that contains the union: each distinct element from all of
		  // the passed-in arrays.
		  _.union = function () {
		    return _.uniq(flatten(arguments, true, true));
		  };
	
		  // Produce an array that contains every item shared between all the
		  // passed-in arrays.
		  _.intersection = function (array) {
		    var result = [];
		    var argsLength = arguments.length;
		    for (var i = 0, length = getLength(array); i < length; i++) {
		      var item = array[i];
		      if (_.contains(result, item)) continue;
		      for (var j = 1; j < argsLength; j++) {
		        if (!_.contains(arguments[j], item)) break;
		      }
		      if (j === argsLength) result.push(item);
		    }
		    return result;
		  };
	
		  // Take the difference between one array and a number of other arrays.
		  // Only the elements present in just the first array will remain.
		  _.difference = function (array) {
		    var rest = flatten(arguments, true, true, 1);
		    return _.filter(array, function (value) {
		      return !_.contains(rest, value);
		    });
		  };
	
		  // Zip together multiple lists into a single array -- elements that share
		  // an index go together.
		  _.zip = function () {
		    return _.unzip(arguments);
		  };
	
		  // Complement of _.zip. Unzip accepts an array of arrays and groups
		  // each array's elements on shared indices
		  _.unzip = function (array) {
		    var length = array && _.max(array, getLength).length || 0;
		    var result = Array(length);
	
		    for (var index = 0; index < length; index++) {
		      result[index] = _.pluck(array, index);
		    }
		    return result;
		  };
	
		  // Converts lists into objects. Pass either a single array of `[key, value]`
		  // pairs, or two parallel arrays of the same length -- one of keys, and one of
		  // the corresponding values.
		  _.object = function (list, values) {
		    var result = {};
		    for (var i = 0, length = getLength(list); i < length; i++) {
		      if (values) {
		        result[list[i]] = values[i];
		      } else {
		        result[list[i][0]] = list[i][1];
		      }
		    }
		    return result;
		  };
	
		  // Generator function to create the findIndex and findLastIndex functions
		  function createPredicateIndexFinder(dir) {
		    return function (array, predicate, context) {
		      predicate = cb(predicate, context);
		      var length = getLength(array);
		      var index = dir > 0 ? 0 : length - 1;
		      for (; index >= 0 && index < length; index += dir) {
		        if (predicate(array[index], index, array)) return index;
		      }
		      return -1;
		    };
		  }
	
		  // Returns the first index on an array-like that passes a predicate test
		  _.findIndex = createPredicateIndexFinder(1);
		  _.findLastIndex = createPredicateIndexFinder(-1);
	
		  // Use a comparator function to figure out the smallest index at which
		  // an object should be inserted so as to maintain order. Uses binary search.
		  _.sortedIndex = function (array, obj, iteratee, context) {
		    iteratee = cb(iteratee, context, 1);
		    var value = iteratee(obj);
		    var low = 0,
		        high = getLength(array);
		    while (low < high) {
		      var mid = Math.floor((low + high) / 2);
		      if (iteratee(array[mid]) < value) low = mid + 1;else high = mid;
		    }
		    return low;
		  };
	
		  // Generator function to create the indexOf and lastIndexOf functions
		  function createIndexFinder(dir, predicateFind, sortedIndex) {
		    return function (array, item, idx) {
		      var i = 0,
		          length = getLength(array);
		      if (typeof idx == 'number') {
		        if (dir > 0) {
		          i = idx >= 0 ? idx : Math.max(idx + length, i);
		        } else {
		          length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
		        }
		      } else if (sortedIndex && idx && length) {
		        idx = sortedIndex(array, item);
		        return array[idx] === item ? idx : -1;
		      }
		      if (item !== item) {
		        idx = predicateFind(slice.call(array, i, length), _.isNaN);
		        return idx >= 0 ? idx + i : -1;
		      }
		      for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
		        if (array[idx] === item) return idx;
		      }
		      return -1;
		    };
		  }
	
		  // Return the position of the first occurrence of an item in an array,
		  // or -1 if the item is not included in the array.
		  // If the array is large and already in sort order, pass `true`
		  // for **isSorted** to use binary search.
		  _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
		  _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
	
		  // Generate an integer Array containing an arithmetic progression. A port of
		  // the native Python `range()` function. See
		  // [the Python documentation](http://docs.python.org/library/functions.html#range).
		  _.range = function (start, stop, step) {
		    if (stop == null) {
		      stop = start || 0;
		      start = 0;
		    }
		    step = step || 1;
	
		    var length = Math.max(Math.ceil((stop - start) / step), 0);
		    var range = Array(length);
	
		    for (var idx = 0; idx < length; idx++, start += step) {
		      range[idx] = start;
		    }
	
		    return range;
		  };
	
		  // Function (ahem) Functions
		  // ------------------
	
		  // Determines whether to execute a function as a constructor
		  // or a normal function with the provided arguments
		  var executeBound = function executeBound(sourceFunc, boundFunc, context, callingContext, args) {
		    if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
		    var self = baseCreate(sourceFunc.prototype);
		    var result = sourceFunc.apply(self, args);
		    if (_.isObject(result)) return result;
		    return self;
		  };
	
		  // Create a function bound to a given object (assigning `this`, and arguments,
		  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
		  // available.
		  _.bind = function (func, context) {
		    if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
		    if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
		    var args = slice.call(arguments, 2);
		    var bound = function bound() {
		      return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
		    };
		    return bound;
		  };
	
		  // Partially apply a function by creating a version that has had some of its
		  // arguments pre-filled, without changing its dynamic `this` context. _ acts
		  // as a placeholder, allowing any combination of arguments to be pre-filled.
		  _.partial = function (func) {
		    var boundArgs = slice.call(arguments, 1);
		    var bound = function bound() {
		      var position = 0,
		          length = boundArgs.length;
		      var args = Array(length);
		      for (var i = 0; i < length; i++) {
		        args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
		      }
		      while (position < arguments.length) {
		        args.push(arguments[position++]);
		      }return executeBound(func, bound, this, this, args);
		    };
		    return bound;
		  };
	
		  // Bind a number of an object's methods to that object. Remaining arguments
		  // are the method names to be bound. Useful for ensuring that all callbacks
		  // defined on an object belong to it.
		  _.bindAll = function (obj) {
		    var i,
		        length = arguments.length,
		        key;
		    if (length <= 1) throw new Error('bindAll must be passed function names');
		    for (i = 1; i < length; i++) {
		      key = arguments[i];
		      obj[key] = _.bind(obj[key], obj);
		    }
		    return obj;
		  };
	
		  // Memoize an expensive function by storing its results.
		  _.memoize = function (func, hasher) {
		    var memoize = function memoize(key) {
		      var cache = memoize.cache;
		      var address = '' + (hasher ? hasher.apply(this, arguments) : key);
		      if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
		      return cache[address];
		    };
		    memoize.cache = {};
		    return memoize;
		  };
	
		  // Delays a function for the given number of milliseconds, and then calls
		  // it with the arguments supplied.
		  _.delay = function (func, wait) {
		    var args = slice.call(arguments, 2);
		    return setTimeout(function () {
		      return func.apply(null, args);
		    }, wait);
		  };
	
		  // Defers a function, scheduling it to run after the current call stack has
		  // cleared.
		  _.defer = _.partial(_.delay, _, 1);
	
		  // Returns a function, that, when invoked, will only be triggered at most once
		  // during a given window of time. Normally, the throttled function will run
		  // as much as it can, without ever going more than once per `wait` duration;
		  // but if you'd like to disable the execution on the leading edge, pass
		  // `{leading: false}`. To disable execution on the trailing edge, ditto.
		  _.throttle = function (func, wait, options) {
		    var context, args, result;
		    var timeout = null;
		    var previous = 0;
		    if (!options) options = {};
		    var later = function later() {
		      previous = options.leading === false ? 0 : _.now();
		      timeout = null;
		      result = func.apply(context, args);
		      if (!timeout) context = args = null;
		    };
		    return function () {
		      var now = _.now();
		      if (!previous && options.leading === false) previous = now;
		      var remaining = wait - (now - previous);
		      context = this;
		      args = arguments;
		      if (remaining <= 0 || remaining > wait) {
		        if (timeout) {
		          clearTimeout(timeout);
		          timeout = null;
		        }
		        previous = now;
		        result = func.apply(context, args);
		        if (!timeout) context = args = null;
		      } else if (!timeout && options.trailing !== false) {
		        timeout = setTimeout(later, remaining);
		      }
		      return result;
		    };
		  };
	
		  // Returns a function, that, as long as it continues to be invoked, will not
		  // be triggered. The function will be called after it stops being called for
		  // N milliseconds. If `immediate` is passed, trigger the function on the
		  // leading edge, instead of the trailing.
		  _.debounce = function (func, wait, immediate) {
		    var timeout, args, context, timestamp, result;
	
		    var later = function later() {
		      var last = _.now() - timestamp;
	
		      if (last < wait && last >= 0) {
		        timeout = setTimeout(later, wait - last);
		      } else {
		        timeout = null;
		        if (!immediate) {
		          result = func.apply(context, args);
		          if (!timeout) context = args = null;
		        }
		      }
		    };
	
		    return function () {
		      context = this;
		      args = arguments;
		      timestamp = _.now();
		      var callNow = immediate && !timeout;
		      if (!timeout) timeout = setTimeout(later, wait);
		      if (callNow) {
		        result = func.apply(context, args);
		        context = args = null;
		      }
	
		      return result;
		    };
		  };
	
		  // Returns the first function passed as an argument to the second,
		  // allowing you to adjust arguments, run code before and after, and
		  // conditionally execute the original function.
		  _.wrap = function (func, wrapper) {
		    return _.partial(wrapper, func);
		  };
	
		  // Returns a negated version of the passed-in predicate.
		  _.negate = function (predicate) {
		    return function () {
		      return !predicate.apply(this, arguments);
		    };
		  };
	
		  // Returns a function that is the composition of a list of functions, each
		  // consuming the return value of the function that follows.
		  _.compose = function () {
		    var args = arguments;
		    var start = args.length - 1;
		    return function () {
		      var i = start;
		      var result = args[start].apply(this, arguments);
		      while (i--) {
		        result = args[i].call(this, result);
		      }return result;
		    };
		  };
	
		  // Returns a function that will only be executed on and after the Nth call.
		  _.after = function (times, func) {
		    return function () {
		      if (--times < 1) {
		        return func.apply(this, arguments);
		      }
		    };
		  };
	
		  // Returns a function that will only be executed up to (but not including) the Nth call.
		  _.before = function (times, func) {
		    var memo;
		    return function () {
		      if (--times > 0) {
		        memo = func.apply(this, arguments);
		      }
		      if (times <= 1) func = null;
		      return memo;
		    };
		  };
	
		  // Returns a function that will be executed at most one time, no matter how
		  // often you call it. Useful for lazy initialization.
		  _.once = _.partial(_.before, 2);
	
		  // Object Functions
		  // ----------------
	
		  // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
		  var hasEnumBug = !{ toString: null }.propertyIsEnumerable('toString');
		  var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
	
		  function collectNonEnumProps(obj, keys) {
		    var nonEnumIdx = nonEnumerableProps.length;
		    var constructor = obj.constructor;
		    var proto = _.isFunction(constructor) && constructor.prototype || ObjProto;
	
		    // Constructor is a special case.
		    var prop = 'constructor';
		    if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
	
		    while (nonEnumIdx--) {
		      prop = nonEnumerableProps[nonEnumIdx];
		      if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
		        keys.push(prop);
		      }
		    }
		  }
	
		  // Retrieve the names of an object's own properties.
		  // Delegates to **ECMAScript 5**'s native `Object.keys`
		  _.keys = function (obj) {
		    if (!_.isObject(obj)) return [];
		    if (nativeKeys) return nativeKeys(obj);
		    var keys = [];
		    for (var key in obj) {
		      if (_.has(obj, key)) keys.push(key);
		    } // Ahem, IE < 9.
		    if (hasEnumBug) collectNonEnumProps(obj, keys);
		    return keys;
		  };
	
		  // Retrieve all the property names of an object.
		  _.allKeys = function (obj) {
		    if (!_.isObject(obj)) return [];
		    var keys = [];
		    for (var key in obj) {
		      keys.push(key);
		    } // Ahem, IE < 9.
		    if (hasEnumBug) collectNonEnumProps(obj, keys);
		    return keys;
		  };
	
		  // Retrieve the values of an object's properties.
		  _.values = function (obj) {
		    var keys = _.keys(obj);
		    var length = keys.length;
		    var values = Array(length);
		    for (var i = 0; i < length; i++) {
		      values[i] = obj[keys[i]];
		    }
		    return values;
		  };
	
		  // Returns the results of applying the iteratee to each element of the object
		  // In contrast to _.map it returns an object
		  _.mapObject = function (obj, iteratee, context) {
		    iteratee = cb(iteratee, context);
		    var keys = _.keys(obj),
		        length = keys.length,
		        results = {},
		        currentKey;
		    for (var index = 0; index < length; index++) {
		      currentKey = keys[index];
		      results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
		    }
		    return results;
		  };
	
		  // Convert an object into a list of `[key, value]` pairs.
		  _.pairs = function (obj) {
		    var keys = _.keys(obj);
		    var length = keys.length;
		    var pairs = Array(length);
		    for (var i = 0; i < length; i++) {
		      pairs[i] = [keys[i], obj[keys[i]]];
		    }
		    return pairs;
		  };
	
		  // Invert the keys and values of an object. The values must be serializable.
		  _.invert = function (obj) {
		    var result = {};
		    var keys = _.keys(obj);
		    for (var i = 0, length = keys.length; i < length; i++) {
		      result[obj[keys[i]]] = keys[i];
		    }
		    return result;
		  };
	
		  // Return a sorted list of the function names available on the object.
		  // Aliased as `methods`
		  _.functions = _.methods = function (obj) {
		    var names = [];
		    for (var key in obj) {
		      if (_.isFunction(obj[key])) names.push(key);
		    }
		    return names.sort();
		  };
	
		  // Extend a given object with all the properties in passed-in object(s).
		  _.extend = createAssigner(_.allKeys);
	
		  // Assigns a given object with all the own properties in the passed-in object(s)
		  // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
		  _.extendOwn = _.assign = createAssigner(_.keys);
	
		  // Returns the first key on an object that passes a predicate test
		  _.findKey = function (obj, predicate, context) {
		    predicate = cb(predicate, context);
		    var keys = _.keys(obj),
		        key;
		    for (var i = 0, length = keys.length; i < length; i++) {
		      key = keys[i];
		      if (predicate(obj[key], key, obj)) return key;
		    }
		  };
	
		  // Return a copy of the object only containing the whitelisted properties.
		  _.pick = function (object, oiteratee, context) {
		    var result = {},
		        obj = object,
		        iteratee,
		        keys;
		    if (obj == null) return result;
		    if (_.isFunction(oiteratee)) {
		      keys = _.allKeys(obj);
		      iteratee = optimizeCb(oiteratee, context);
		    } else {
		      keys = flatten(arguments, false, false, 1);
		      iteratee = function iteratee(value, key, obj) {
		        return key in obj;
		      };
		      obj = Object(obj);
		    }
		    for (var i = 0, length = keys.length; i < length; i++) {
		      var key = keys[i];
		      var value = obj[key];
		      if (iteratee(value, key, obj)) result[key] = value;
		    }
		    return result;
		  };
	
		  // Return a copy of the object without the blacklisted properties.
		  _.omit = function (obj, iteratee, context) {
		    if (_.isFunction(iteratee)) {
		      iteratee = _.negate(iteratee);
		    } else {
		      var keys = _.map(flatten(arguments, false, false, 1), String);
		      iteratee = function iteratee(value, key) {
		        return !_.contains(keys, key);
		      };
		    }
		    return _.pick(obj, iteratee, context);
		  };
	
		  // Fill in a given object with default properties.
		  _.defaults = createAssigner(_.allKeys, true);
	
		  // Creates an object that inherits from the given prototype object.
		  // If additional properties are provided then they will be added to the
		  // created object.
		  _.create = function (prototype, props) {
		    var result = baseCreate(prototype);
		    if (props) _.extendOwn(result, props);
		    return result;
		  };
	
		  // Create a (shallow-cloned) duplicate of an object.
		  _.clone = function (obj) {
		    if (!_.isObject(obj)) return obj;
		    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
		  };
	
		  // Invokes interceptor with the obj, and then returns obj.
		  // The primary purpose of this method is to "tap into" a method chain, in
		  // order to perform operations on intermediate results within the chain.
		  _.tap = function (obj, interceptor) {
		    interceptor(obj);
		    return obj;
		  };
	
		  // Returns whether an object has a given set of `key:value` pairs.
		  _.isMatch = function (object, attrs) {
		    var keys = _.keys(attrs),
		        length = keys.length;
		    if (object == null) return !length;
		    var obj = Object(object);
		    for (var i = 0; i < length; i++) {
		      var key = keys[i];
		      if (attrs[key] !== obj[key] || !(key in obj)) return false;
		    }
		    return true;
		  };
	
		  // Internal recursive comparison function for `isEqual`.
		  var eq = function eq(a, b, aStack, bStack) {
		    // Identical objects are equal. `0 === -0`, but they aren't identical.
		    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
		    if (a === b) return a !== 0 || 1 / a === 1 / b;
		    // A strict comparison is necessary because `null == undefined`.
		    if (a == null || b == null) return a === b;
		    // Unwrap any wrapped objects.
		    if (a instanceof _) a = a._wrapped;
		    if (b instanceof _) b = b._wrapped;
		    // Compare `[[Class]]` names.
		    var className = toString.call(a);
		    if (className !== toString.call(b)) return false;
		    switch (className) {
		      // Strings, numbers, regular expressions, dates, and booleans are compared by value.
		      case '[object RegExp]':
		      // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
		      case '[object String]':
		        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
		        // equivalent to `new String("5")`.
		        return '' + a === '' + b;
		      case '[object Number]':
		        // `NaN`s are equivalent, but non-reflexive.
		        // Object(NaN) is equivalent to NaN
		        if (+a !== +a) return +b !== +b;
		        // An `egal` comparison is performed for other numeric values.
		        return +a === 0 ? 1 / +a === 1 / b : +a === +b;
		      case '[object Date]':
		      case '[object Boolean]':
		        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
		        // millisecond representations. Note that invalid dates with millisecond representations
		        // of `NaN` are not equivalent.
		        return +a === +b;
		    }
	
		    var areArrays = className === '[object Array]';
		    if (!areArrays) {
		      if ((typeof a === 'undefined' ? 'undefined' : _typeof(a)) != 'object' || (typeof b === 'undefined' ? 'undefined' : _typeof(b)) != 'object') return false;
	
		      // Objects with different constructors are not equivalent, but `Object`s or `Array`s
		      // from different frames are.
		      var aCtor = a.constructor,
		          bCtor = b.constructor;
		      if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && _.isFunction(bCtor) && bCtor instanceof bCtor) && 'constructor' in a && 'constructor' in b) {
		        return false;
		      }
		    }
		    // Assume equality for cyclic structures. The algorithm for detecting cyclic
		    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
	
		    // Initializing stack of traversed objects.
		    // It's done here since we only need them for objects and arrays comparison.
		    aStack = aStack || [];
		    bStack = bStack || [];
		    var length = aStack.length;
		    while (length--) {
		      // Linear search. Performance is inversely proportional to the number of
		      // unique nested structures.
		      if (aStack[length] === a) return bStack[length] === b;
		    }
	
		    // Add the first object to the stack of traversed objects.
		    aStack.push(a);
		    bStack.push(b);
	
		    // Recursively compare objects and arrays.
		    if (areArrays) {
		      // Compare array lengths to determine if a deep comparison is necessary.
		      length = a.length;
		      if (length !== b.length) return false;
		      // Deep compare the contents, ignoring non-numeric properties.
		      while (length--) {
		        if (!eq(a[length], b[length], aStack, bStack)) return false;
		      }
		    } else {
		      // Deep compare objects.
		      var keys = _.keys(a),
		          key;
		      length = keys.length;
		      // Ensure that both objects contain the same number of properties before comparing deep equality.
		      if (_.keys(b).length !== length) return false;
		      while (length--) {
		        // Deep compare each member
		        key = keys[length];
		        if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
		      }
		    }
		    // Remove the first object from the stack of traversed objects.
		    aStack.pop();
		    bStack.pop();
		    return true;
		  };
	
		  // Perform a deep comparison to check if two objects are equal.
		  _.isEqual = function (a, b) {
		    return eq(a, b);
		  };
	
		  // Is a given array, string, or object empty?
		  // An "empty" object has no enumerable own-properties.
		  _.isEmpty = function (obj) {
		    if (obj == null) return true;
		    if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
		    return _.keys(obj).length === 0;
		  };
	
		  // Is a given value a DOM element?
		  _.isElement = function (obj) {
		    return !!(obj && obj.nodeType === 1);
		  };
	
		  // Is a given value an array?
		  // Delegates to ECMA5's native Array.isArray
		  _.isArray = nativeIsArray || function (obj) {
		    return toString.call(obj) === '[object Array]';
		  };
	
		  // Is a given variable an object?
		  _.isObject = function (obj) {
		    var type = typeof obj === 'undefined' ? 'undefined' : _typeof(obj);
		    return type === 'function' || type === 'object' && !!obj;
		  };
	
		  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
		  _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function (name) {
		    _['is' + name] = function (obj) {
		      return toString.call(obj) === '[object ' + name + ']';
		    };
		  });
	
		  // Define a fallback version of the method in browsers (ahem, IE < 9), where
		  // there isn't any inspectable "Arguments" type.
		  if (!_.isArguments(arguments)) {
		    _.isArguments = function (obj) {
		      return _.has(obj, 'callee');
		    };
		  }
	
		  // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
		  // IE 11 (#1621), and in Safari 8 (#1929).
		  if (typeof /./ != 'function' && (typeof Int8Array === 'undefined' ? 'undefined' : _typeof(Int8Array)) != 'object') {
		    _.isFunction = function (obj) {
		      return typeof obj == 'function' || false;
		    };
		  }
	
		  // Is a given object a finite number?
		  _.isFinite = function (obj) {
		    return isFinite(obj) && !isNaN(parseFloat(obj));
		  };
	
		  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
		  _.isNaN = function (obj) {
		    return _.isNumber(obj) && obj !== +obj;
		  };
	
		  // Is a given value a boolean?
		  _.isBoolean = function (obj) {
		    return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
		  };
	
		  // Is a given value equal to null?
		  _.isNull = function (obj) {
		    return obj === null;
		  };
	
		  // Is a given variable undefined?
		  _.isUndefined = function (obj) {
		    return obj === void 0;
		  };
	
		  // Shortcut function for checking if an object has a given property directly
		  // on itself (in other words, not on a prototype).
		  _.has = function (obj, key) {
		    return obj != null && hasOwnProperty.call(obj, key);
		  };
	
		  // Utility Functions
		  // -----------------
	
		  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
		  // previous owner. Returns a reference to the Underscore object.
		  _.noConflict = function () {
		    root._ = previousUnderscore;
		    return this;
		  };
	
		  // Keep the identity function around for default iteratees.
		  _.identity = function (value) {
		    return value;
		  };
	
		  // Predicate-generating functions. Often useful outside of Underscore.
		  _.constant = function (value) {
		    return function () {
		      return value;
		    };
		  };
	
		  _.noop = function () {};
	
		  _.property = property;
	
		  // Generates a function for a given object that returns a given property.
		  _.propertyOf = function (obj) {
		    return obj == null ? function () {} : function (key) {
		      return obj[key];
		    };
		  };
	
		  // Returns a predicate for checking whether an object has a given set of
		  // `key:value` pairs.
		  _.matcher = _.matches = function (attrs) {
		    attrs = _.extendOwn({}, attrs);
		    return function (obj) {
		      return _.isMatch(obj, attrs);
		    };
		  };
	
		  // Run a function **n** times.
		  _.times = function (n, iteratee, context) {
		    var accum = Array(Math.max(0, n));
		    iteratee = optimizeCb(iteratee, context, 1);
		    for (var i = 0; i < n; i++) {
		      accum[i] = iteratee(i);
		    }return accum;
		  };
	
		  // Return a random integer between min and max (inclusive).
		  _.random = function (min, max) {
		    if (max == null) {
		      max = min;
		      min = 0;
		    }
		    return min + Math.floor(Math.random() * (max - min + 1));
		  };
	
		  // A (possibly faster) way to get the current timestamp as an integer.
		  _.now = Date.now || function () {
		    return new Date().getTime();
		  };
	
		  // List of HTML entities for escaping.
		  var escapeMap = {
		    '&': '&amp;',
		    '<': '&lt;',
		    '>': '&gt;',
		    '"': '&quot;',
		    "'": '&#x27;',
		    '`': '&#x60;'
		  };
		  var unescapeMap = _.invert(escapeMap);
	
		  // Functions for escaping and unescaping strings to/from HTML interpolation.
		  var createEscaper = function createEscaper(map) {
		    var escaper = function escaper(match) {
		      return map[match];
		    };
		    // Regexes for identifying a key that needs to be escaped
		    var source = '(?:' + _.keys(map).join('|') + ')';
		    var testRegexp = RegExp(source);
		    var replaceRegexp = RegExp(source, 'g');
		    return function (string) {
		      string = string == null ? '' : '' + string;
		      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
		    };
		  };
		  _.escape = createEscaper(escapeMap);
		  _.unescape = createEscaper(unescapeMap);
	
		  // If the value of the named `property` is a function then invoke it with the
		  // `object` as context; otherwise, return it.
		  _.result = function (object, property, fallback) {
		    var value = object == null ? void 0 : object[property];
		    if (value === void 0) {
		      value = fallback;
		    }
		    return _.isFunction(value) ? value.call(object) : value;
		  };
	
		  // Generate a unique integer id (unique within the entire client session).
		  // Useful for temporary DOM ids.
		  var idCounter = 0;
		  _.uniqueId = function (prefix) {
		    var id = ++idCounter + '';
		    return prefix ? prefix + id : id;
		  };
	
		  // By default, Underscore uses ERB-style template delimiters, change the
		  // following template settings to use alternative delimiters.
		  _.templateSettings = {
		    evaluate: /<%([\s\S]+?)%>/g,
		    interpolate: /<%=([\s\S]+?)%>/g,
		    escape: /<%-([\s\S]+?)%>/g
		  };
	
		  // When customizing `templateSettings`, if you don't want to define an
		  // interpolation, evaluation or escaping regex, we need one that is
		  // guaranteed not to match.
		  var noMatch = /(.)^/;
	
		  // Certain characters need to be escaped so that they can be put into a
		  // string literal.
		  var escapes = {
		    "'": "'",
		    '\\': '\\',
		    '\r': 'r',
		    '\n': 'n',
		    '\u2028': 'u2028',
		    '\u2029': 'u2029'
		  };
	
		  var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
	
		  var escapeChar = function escapeChar(match) {
		    return '\\' + escapes[match];
		  };
	
		  // JavaScript micro-templating, similar to John Resig's implementation.
		  // Underscore templating handles arbitrary delimiters, preserves whitespace,
		  // and correctly escapes quotes within interpolated code.
		  // NB: `oldSettings` only exists for backwards compatibility.
		  _.template = function (text, settings, oldSettings) {
		    if (!settings && oldSettings) settings = oldSettings;
		    settings = _.defaults({}, settings, _.templateSettings);
	
		    // Combine delimiters into one regular expression via alternation.
		    var matcher = RegExp([(settings.escape || noMatch).source, (settings.interpolate || noMatch).source, (settings.evaluate || noMatch).source].join('|') + '|$', 'g');
	
		    // Compile the template source, escaping string literals appropriately.
		    var index = 0;
		    var source = "__p+='";
		    text.replace(matcher, function (match, escape, interpolate, evaluate, offset) {
		      source += text.slice(index, offset).replace(escaper, escapeChar);
		      index = offset + match.length;
	
		      if (escape) {
		        source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
		      } else if (interpolate) {
		        source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
		      } else if (evaluate) {
		        source += "';\n" + evaluate + "\n__p+='";
		      }
	
		      // Adobe VMs need the match returned to produce the correct offest.
		      return match;
		    });
		    source += "';\n";
	
		    // If a variable is not specified, place data values in local scope.
		    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
	
		    source = "var __t,__p='',__j=Array.prototype.join," + "print=function(){__p+=__j.call(arguments,'');};\n" + source + 'return __p;\n';
	
		    try {
		      var render = new Function(settings.variable || 'obj', '_', source);
		    } catch (e) {
		      e.source = source;
		      throw e;
		    }
	
		    var template = function template(data) {
		      return render.call(this, data, _);
		    };
	
		    // Provide the compiled source as a convenience for precompilation.
		    var argument = settings.variable || 'obj';
		    template.source = 'function(' + argument + '){\n' + source + '}';
	
		    return template;
		  };
	
		  // Add a "chain" function. Start chaining a wrapped Underscore object.
		  _.chain = function (obj) {
		    var instance = _(obj);
		    instance._chain = true;
		    return instance;
		  };
	
		  // OOP
		  // ---------------
		  // If Underscore is called as a function, it returns a wrapped object that
		  // can be used OO-style. This wrapper holds altered versions of all the
		  // underscore functions. Wrapped objects may be chained.
	
		  // Helper function to continue chaining intermediate results.
		  var result = function result(instance, obj) {
		    return instance._chain ? _(obj).chain() : obj;
		  };
	
		  // Add your own custom functions to the Underscore object.
		  _.mixin = function (obj) {
		    _.each(_.functions(obj), function (name) {
		      var func = _[name] = obj[name];
		      _.prototype[name] = function () {
		        var args = [this._wrapped];
		        push.apply(args, arguments);
		        return result(this, func.apply(_, args));
		      };
		    });
		  };
	
		  // Add all of the Underscore functions to the wrapper object.
		  _.mixin(_);
	
		  // Add all mutator Array functions to the wrapper.
		  _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function (name) {
		    var method = ArrayProto[name];
		    _.prototype[name] = function () {
		      var obj = this._wrapped;
		      method.apply(obj, arguments);
		      if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
		      return result(this, obj);
		    };
		  });
	
		  // Add all accessor Array functions to the wrapper.
		  _.each(['concat', 'join', 'slice'], function (name) {
		    var method = ArrayProto[name];
		    _.prototype[name] = function () {
		      return result(this, method.apply(this._wrapped, arguments));
		    };
		  });
	
		  // Extracts the result from a wrapped and chained object.
		  _.prototype.value = function () {
		    return this._wrapped;
		  };
	
		  // Provide unwrapping proxy for some methods used in engine operations
		  // such as arithmetic and JSON stringification.
		  _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
	
		  _.prototype.toString = function () {
		    return '' + this._wrapped;
		  };
	
		  // AMD registration happens at the end for compatibility with AMD loaders
		  // that may not enforce next-turn semantics on modules. Even though general
		  // practice for AMD registration is to be anonymous, underscore registers
		  // as a named module because, like jQuery, it is a base library that is
		  // popular enough to be bundled in a third party lib, but not be part of
		  // an AMD load request. Those cases could generate an error when an
		  // anonymous define() is called outside of a loader request.
		  if (true) {
		    !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () {
		      return _;
		    }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
		  }
		}).call(undefined);
	
	/***/ }),
	/* 69 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var calc_viz_dimensions = __webpack_require__(70);
	
		module.exports = function set_viz_wrapper_size(params) {
	
		  // Create wrapper around SVG visualization
		  if (d3.select(params.root + ' .viz_wrapper').empty()) {
	
		    d3.select(params.root).append('div').classed('sidebar_wrapper', true);
	
		    d3.select(params.root).append('div').classed('viz_wrapper', true);
		  }
	
		  var cont_dim = calc_viz_dimensions(params);
	
		  d3.select(params.root + ' .sidebar_wrapper').style('float', 'left').style('width', params.sidebar_width + 'px').style('height', cont_dim.height + 'px').style('overflow', 'hidden');
	
		  d3.select(params.viz.viz_wrapper).style('float', 'left').style('width', cont_dim.width + 'px').style('height', cont_dim.height + 'px');
			};
	
	/***/ }),
	/* 70 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function calc_viz_dimensions(params) {
	
		  var cont_dim = {};
		  var extra_space = params.buffer_width;
	
		  // var screen_width = window.innerWidth;
		  // var screen_height = window.innerHeight;
	
		  // // resize container, then resize visualization within container
		  // d3.select(params.root)
		  //   .style('width', screen_width+'px')
		  //   .style('height', screen_height+'px');
	
		  var container_width = d3.select(params.root).style('width').replace('px', '');
		  var container_height = d3.select(params.root).style('height').replace('px', '');
	
		  // get outer_margins
		  var outer_margins;
		  if (params.viz.is_expand === false) {
		    outer_margins = params.viz.outer_margins;
		    cont_dim.width = container_width - params.sidebar_width - extra_space;
		  } else {
		    outer_margins = params.viz.outer_margins;
		    cont_dim.width = container_width - extra_space;
		  }
	
		  cont_dim.top = outer_margins.top;
		  cont_dim.left = outer_margins.left;
	
		  if (params.viz.resize) {
	
		    cont_dim.height = container_height;
		  } else {
	
		    if (params.viz.is_expand) {
		      cont_dim.width = params.viz.fixed_size.width;
		    } else {
		      cont_dim.width = params.viz.fixed_size.width - params.sidebar_width;
		    }
	
		    cont_dim.height = params.viz.fixed_size.height;
		  }
	
		  return cont_dim;
			};
	
	/***/ }),
	/* 71 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function get_svg_dim(params) {
	
		  params.viz.svg_dim = {};
		  params.viz.svg_dim.width = Number(d3.select(params.viz.viz_wrapper).style('width').replace('px', ''));
	
		  params.viz.svg_dim.height = Number(d3.select(params.viz.viz_wrapper).style('height').replace('px', ''));
	
		  return params;
		};
	
	/***/ }),
	/* 72 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function calc_label_params(viz) {
	
		  viz.norm_labels.margin = {};
	
		  viz.norm_labels.margin.left = viz.super_labels.margin.left + viz.super_labels.dim.width;
	
		  viz.norm_labels.margin.top = viz.super_labels.margin.top + viz.super_labels.dim.width;
	
		  viz.label_background = {};
	
		  viz.label_background.row = viz.norm_labels.width.row + viz.cat_room.row + viz.uni_margin;
	
		  viz.label_background.col = viz.norm_labels.width.col + viz.cat_room.col + viz.uni_margin;
	
		  return viz;
		};
	
	/***/ }),
	/* 73 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function calc_clust_width(viz) {
	
		  viz.clust = {};
		  viz.clust.margin = {};
	
		  // margin on left/top of the clustergram/matrix 
		  // 1) norm_label margin and width
		  // 2) cat_room and uni_margin 
		  viz.clust.margin.left = viz.norm_labels.margin.left + viz.norm_labels.width.row + viz.cat_room.row + viz.uni_margin;
	
		  viz.clust.margin.top = viz.norm_labels.margin.top + viz.norm_labels.width.col + viz.cat_room.col + viz.uni_margin;
	
		  // the clustergram/matrix width is the svg width minus:
		  // the margin of the clustergram on the left 
		  // the room for the spillover on the right 
		  // ** the dendro will fit in the spillover room on the right 
		  var ini_clust_width = viz.svg_dim.width - viz.clust.margin.left - viz.spillover_col_slant;
	
		  // make tmp scale to calc height of triangle col labels 
		  var tmp_x_scale = d3.scale.ordinal().rangeBands([0, ini_clust_width]).domain(_.range(viz.num_col_nodes));
	
		  var triangle_height = tmp_x_scale.rangeBand() / 2;
	
		  // prevent the visualization from being unnecessarily wide 
		  if (triangle_height > viz.norm_labels.width.col) {
		    var reduce_width = viz.norm_labels.width.col / triangle_height;
		    ini_clust_width = ini_clust_width * reduce_width;
		  }
	
		  viz.clust.dim = {};
		  viz.clust.dim.width = ini_clust_width;
	
		  return viz;
		};
	
	/***/ }),
	/* 74 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function calc_clust_height(viz) {
	
		  // the clustergram/matrix height is the svg width minus: 
		  // the margin of the clustergram on the top 
		  // the dendrogram 
		  // the bottom_space 
		  var ini_clust_height = viz.svg_dim.height - viz.clust.margin.top - viz.dendro_room.col - viz.bottom_space;
	
		  viz.clust.dim.height = ini_clust_height;
	
		  return viz;
		};
	
	/***/ }),
	/* 75 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var underscore = __webpack_require__(68);
	
		module.exports = function calc_val_max(params) {
	
		  var val_max = Math.abs(underscore.max(params.network_data.col_nodes, function (d) {
		    return Math.abs(d.value);
		  }).value);
	
		  params.labels.bar_scale_col = d3.scale.linear().domain([0, val_max]).range([0, 0.75 * params.viz.norm_labels.width.col]);
	
		  val_max = Math.abs(underscore.max(params.network_data.row_nodes, function (d) {
		    return Math.abs(d.value);
		  }).value);
	
		  params.labels.bar_scale_row = d3.scale.linear().domain([0, val_max]).range([0, params.viz.norm_labels.width.row]);
	
		  return params;
		};
	
	/***/ }),
	/* 76 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var ini_matrix_params = __webpack_require__(77);
		var calc_downsampled_levels = __webpack_require__(79);
	
		module.exports = function calc_matrix_params(params) {
	
		  params.matrix = ini_matrix_params(params);
	
		  // X and Y scales: set domains and ranges
		  //////////////////////////////////////////////
		  params.viz.x_scale = d3.scale.ordinal().rangeBands([0, params.viz.clust.dim.width]);
	
		  params.viz.y_scale = d3.scale.ordinal().rangeBands([0, params.viz.clust.dim.height]);
	
		  var inst_order;
	
		  _.each(['row', 'col'], function (inst_rc) {
	
		    inst_order = params.viz.inst_order[inst_rc];
	
		    if (inst_order === 'custom') {
		      inst_order = 'clust';
		    }
	
		    if (inst_rc === 'row') {
		      params.viz.x_scale.domain(params.matrix.orders[inst_order + '_' + inst_rc]);
		    } else {
		      params.viz.y_scale.domain(params.matrix.orders[inst_order + '_' + inst_rc]);
		    }
		  });
	
		  // border width
		  params.viz.border_width = {};
		  params.viz.border_width.x = params.viz.x_scale.rangeBand() / params.viz.border_fraction;
		  params.viz.border_width.y = params.viz.y_scale.rangeBand() / params.viz.border_fraction;
	
		  // rect width needs matrix and zoom parameters
		  params.viz.rect_width = params.viz.x_scale.rangeBand() - params.viz.border_width.x;
	
		  // moved calculateion to calc_matrix_params
		  params.viz.rect_height = params.viz.y_scale.rangeBand() - params.viz.border_width.y;
	
		  calc_downsampled_levels(params);
	
		  return params;
			};
	
	/***/ }),
	/* 77 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
		var initialize_matrix = __webpack_require__(78);
		var underscore = __webpack_require__(68);
	
		module.exports = function ini_matrix_params(params) {
	
		  var matrix = {};
	
		  var network_data = params.network_data;
	
		  matrix.tile_colors = params.tile_colors;
		  matrix.bar_colors = params.bar_colors;
		  matrix.outline_colors = params.outline_colors;
		  matrix.hlight_color = params.highlight_color;
		  matrix.tile_title = params.tile_title;
		  matrix.show_tile_tooltips = params.show_tile_tooltips;
		  matrix.make_tile_tooltip = params.make_tile_tooltip;
	
		  matrix.distance_metric = 'cosine';
		  matrix.linkage_type = 'average';
	
		  // initialized clicked tile and rows
		  matrix.click_hlight_x = -666;
		  matrix.click_hlight_y = -666;
		  matrix.click_hlight_row = -666;
		  matrix.click_hlight_col = -666;
	
		  // definition of a large matrix (num links) determines if transition is run
		  matrix.def_large_matrix = 10000;
		  matrix.opacity_function = params.opacity_scale;
	
		  matrix.orders = {};
	
		  _.each(['row', 'col'], function (inst_rc) {
	
		    // row ordering is based on col info and vice versa
		    var other_rc;
		    if (inst_rc === 'row') {
		      other_rc = 'col';
		    } else {
		      other_rc = 'row';
		    }
	
		    // the nodes are defined using other_rc
		    var inst_nodes = network_data[other_rc + '_nodes'];
		    var num_nodes = inst_nodes.length;
	
		    var nodes_names = utils.pluck(inst_nodes, 'name');
		    var tmp = nodes_names.sort();
	
		    var alpha_index = _.map(tmp, function (d) {
		      return network_data[other_rc + '_nodes_names'].indexOf(d);
		    });
	
		    matrix.orders['alpha_' + inst_rc] = alpha_index;
	
		    var possible_orders = ['clust', 'rank'];
	
		    if (_.has(inst_nodes[0], 'rankvar')) {
		      possible_orders.push('rankvar');
		    }
	
		    if (params.viz.all_cats[other_rc].length > 0) {
		      _.each(params.viz.all_cats[other_rc], function (inst_cat) {
		        // the index of the category has replaced - with _
		        inst_cat = inst_cat.replace('-', '_');
		        possible_orders.push(inst_cat + '_index');
		      });
		    }
	
		    _.each(possible_orders, function (inst_order) {
	
		      var tmp_order_index = d3.range(num_nodes).sort(function (a, b) {
		        return inst_nodes[b][inst_order] - inst_nodes[a][inst_order];
		      });
	
		      matrix.orders[inst_order + '_' + inst_rc] = tmp_order_index;
		    });
		  });
	
		  if (utils.has(network_data, 'all_links')) {
		    matrix.max_link = underscore.max(network_data.all_links, function (d) {
		      return Math.abs(d.value);
		    }).value;
		  } else {
		    matrix.max_link = underscore.max(network_data.links, function (d) {
		      return Math.abs(d.value);
		    }).value;
		  }
	
		  matrix.abs_max_val = Math.abs(matrix.max_link) * params.clamp_opacity;
	
		  if (params.input_domain === 0) {
		    if (matrix.opacity_function === 'linear') {
		      matrix.opacity_scale = d3.scale.linear().domain([0, matrix.abs_max_val]).clamp(true).range([0.0, 1.0]);
		    } else if (matrix.opacity_function === 'log') {
		      matrix.opacity_scale = d3.scale.log().domain([0.001, matrix.abs_max_val]).clamp(true).range([0.0, 1.0]);
		    }
		  } else {
		    if (matrix.opacity_function === 'linear') {
		      matrix.opacity_scale = d3.scale.linear().domain([0, params.input_domain]).clamp(true).range([0.0, 1.0]);
		    } else if (matrix.opacity_function === 'log') {
		      matrix.opacity_scale = d3.scale.log().domain([0.001, params.input_domain]).clamp(true).range([0.0, 1.0]);
		    }
		  }
	
		  var has_val_up = utils.has(network_data.links[0], 'value_up');
		  var has_val_dn = utils.has(network_data.links[0], 'value_dn');
	
		  if (has_val_up || has_val_dn) {
		    matrix.tile_type = 'updn';
		  } else {
		    matrix.tile_type = 'simple';
		  }
	
		  if (utils.has(network_data.links[0], 'highlight')) {
		    matrix.highlight = 1;
		  } else {
		    matrix.highlight = 0;
		  }
	
		  matrix.matrix = initialize_matrix(network_data);
	
		  matrix.wait_tooltip = 0;
	
		  return matrix;
		};
	
	/***/ }),
	/* 78 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
	
		module.exports = function (network_data) {
		  var matrix = [];
		  var ini_object;
	
		  var keep_orig;
		  if (utils.has(network_data.links[0], 'value_orig')) {
		    keep_orig = true;
		  } else {
		    keep_orig = false;
		  }
	
		  network_data.row_nodes.forEach(function (tmp, row_index) {
	
		    matrix[row_index] = {};
		    matrix[row_index].name = network_data.row_nodes[row_index].name;
		    matrix[row_index].row_index = row_index;
	
		    matrix[row_index].row_data = d3.range(network_data.col_nodes.length).map(function (col_index) {
	
		      if (utils.has(network_data.links[0], 'value_up') || utils.has(network_data.links[0], 'value_dn')) {
	
		        ini_object = {
		          pos_x: col_index,
		          pos_y: row_index,
		          value: 0,
		          value_up: 0,
		          value_dn: 0,
		          highlight: 0
		        };
		      } else {
	
		        ini_object = {
		          pos_x: col_index,
		          pos_y: row_index,
		          value: 0,
		          highlight: 0
		        };
		      }
	
		      if (keep_orig) {
		        ini_object.value_orig = 0;
		      }
	
		      return ini_object;
		    });
		  });
	
		  network_data.links.forEach(function (link) {
	
		    // transfer additional link information is necessary
		    matrix[link.source].row_data[link.target].value = link.value;
		    matrix[link.source].row_data[link.target].row_name = link.row_name;
		    matrix[link.source].row_data[link.target].col_name = link.col_name;
	
		    if (utils.has(link, 'value_up') || utils.has(link, 'value_dn')) {
		      matrix[link.source].row_data[link.target].value_up = link.value_up;
		      matrix[link.source].row_data[link.target].value_dn = link.value_dn;
		    }
	
		    if (keep_orig) {
		      matrix[link.source].row_data[link.target].value_orig = link.value_orig;
		    }
	
		    if (link.highlight) {
		      matrix[link.source].row_data[link.target].highlight = link.highlight;
		    }
		    if (link.info) {
		      matrix[link.source].row_data[link.target].info = link.info;
		    }
		  });
	
		  return matrix;
		};
	
	/***/ }),
	/* 79 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var calc_downsampled_matrix = __webpack_require__(80);
	
		module.exports = function calc_downsampled_levels(params) {
	
		  // console.log('---- before ---------')
		  // console.log(params.matrix.matrix[0].row_data[0].value)
	
		  // height of downsampled rectangles
		  var ds_height = 3;
	
		  var min_rect_height = 2;
	
		  var total_zoom = ds_height / params.viz.rect_height;
	
		  // amount of zooming that is tolerated for the downsampled rows
		  var inst_zt = 2;
		  params.viz.ds_zt = inst_zt;
	
		  var num_levels = Math.floor(Math.log(total_zoom) / Math.log(inst_zt));
	
		  if (params.viz.rect_height < min_rect_height && num_levels > 0) {
	
		    // increase ds opacity, as more rows are compressed into a single downsampled
		    // row, increase the opacity of the downsampled row. Max increase will be 2x
		    // when 100 or more rows are compressed
		    var max_opacity_scale = 2;
		    params.viz.ds_opacity_scale = d3.scale.linear().domain([1, 100]).range([1, max_opacity_scale]).clamp(true);
	
		    var ds;
	
		    params.viz.ds_num_levels = num_levels;
	
		    // array of downsampled parameters
		    params.viz.ds = [];
	
		    // array of downsampled matrices at varying levels
		    params.matrix.ds_matrix = [];
	
		    var inst_order = params.viz.inst_order.row;
	
		    // cloning
		    var mat = $.extend(true, {}, params.matrix.matrix);
	
		    // calculate parameters for different levels
		    for (var i = 0; i < num_levels; i++) {
	
		      // instantaneous ds_level (-1 means no downsampling)
		      params.viz.ds_level = 0;
	
		      ds = {};
	
		      ds.height = ds_height;
		      ds.num_levels = num_levels;
	
		      var inst_zoom_tolerance = Math.pow(inst_zt, i);
	
		      ds.zt = inst_zoom_tolerance;
	
		      // the number of downsampled rows is given by the height of the clustergram
		      // divided by the adjusted height of the downsampled rect.
		      // the adjusted height is the height divided by the zooming tolerance of
		      // the downsampled layer
	
		      // number of downsampled rows
		      ds.num_rows = Math.round(params.viz.clust.dim.height / (ds.height / inst_zoom_tolerance));
	
		      // x_scale
		      /////////////////////////
		      ds.x_scale = d3.scale.ordinal().rangeBands([0, params.viz.clust.dim.width]);
	
		      ds.x_scale.domain(params.matrix.orders[inst_order + '_row']);
	
		      // y_scale
		      /////////////////////////
		      ds.y_scale = d3.scale.ordinal().rangeBands([0, params.viz.clust.dim.height]);
		      ds.y_scale.domain(d3.range(ds.num_rows + 1));
	
		      ds.rect_height = ds.y_scale.rangeBand() - params.viz.border_width.y;
	
		      params.viz.ds.push(ds);
	
		      var matrix = calc_downsampled_matrix(params, mat, i);
		      params.matrix.ds_matrix.push(matrix);
		    }
	
		    // reset row viz_nodes since downsampling
		    params.viz.viz_nodes.row = d3.range(params.matrix.ds_matrix[0].length).map(String);
		  } else {
		    // set ds to null if no downsampling is done
		    params.viz.ds = null;
		    // instantaneous ds_level (-1 means no downsampling)
		    params.viz.ds_level = -1;
		    params.viz.ds_num_levels = 0;
		  }
	
		  // console.log('---- after ---------')
		  // console.log(params.matrix.matrix[0].row_data[0].value)
			};
	
	/***/ }),
	/* 80 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function calc_downsampled_matrix(params, mat, ds_level) {
	
		  var inst_num_rows = params.viz.ds[ds_level].num_rows;
	
		  var num_compressed_rows = params.network_data.row_nodes.length / inst_num_rows;
	
		  // increase ds opacity, as more rows are compressed into a single downsampled
		  // row, increase the opacity of the downsampled row.
		  var opacity_factor = params.viz.ds_opacity_scale(num_compressed_rows);
	
		  var mod_val = params.viz.clust.dim.height / inst_num_rows;
	
		  var ds_mat = [];
		  var inst_obj;
	
		  var len_ds_array = inst_num_rows + 1;
	
		  var i;
		  var x;
	
		  // initialize array of objects
		  for (i = 0; i < len_ds_array; i++) {
	
		    inst_obj = {};
		    inst_obj.row_index = i;
		    inst_obj.name = String(i);
		    inst_obj.all_names = [];
	
		    ds_mat.push(inst_obj);
		  }
	
		  _.each(mat, function (inst_row) {
	
		    // row ordering information is contained in y_scale
		    var inst_y = params.viz.y_scale(inst_row.row_index);
	
		    var ds_index = Math.round(inst_y / mod_val);
	
		    var inst_row_data = inst_row.row_data;
	
		    // gather names
		    ds_mat[ds_index].all_names.push(inst_row.name);
	
		    // gather row_data
		    if (_.has(ds_mat[ds_index], 'row_data')) {
	
		      for (x = 0; x < inst_row_data.length; x++) {
		        ds_mat[ds_index].row_data[x].value = ds_mat[ds_index].row_data[x].value + inst_row_data[x].value;
		      }
		    } else {
	
		      var new_data = [];
		      for (x = 0; x < inst_row_data.length; x++) {
		        new_data[x] = inst_row_data[x];
		      }
	
		      ds_mat[ds_index].row_data = new_data;
		    }
		  });
	
		  // average the values
		  _.each(ds_mat, function (tmp_ds) {
	
		    var tmp_row_data = tmp_ds.row_data;
	
		    var num_names = tmp_ds.all_names.length;
	
		    _.each(tmp_row_data, function (tmp_obj) {
		      tmp_obj.value = tmp_obj.value / num_names * opacity_factor;
		    });
		  });
	
		  // all names were found
		  var all_names = [];
	
		  _.each(ds_mat, function (inst_row) {
		    all_names = all_names.concat(inst_row.all_names);
		  });
	
		  return ds_mat;
			};
	
	/***/ }),
	/* 81 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var calc_zoom_switching = __webpack_require__(82);
	
		module.exports = function set_zoom_params(params) {
	
		  params.viz.zoom_scale_font = {};
		  params.viz.zoom_scale_font.row = 1;
		  params.viz.zoom_scale_font.col = 1;
	
		  var max_zoom_limit = 0.75;
		  var half_col_height = params.viz.x_scale.rangeBand() / 2;
		  params.viz.square_zoom = params.viz.norm_labels.width.col / half_col_height * max_zoom_limit;
	
		  params.viz = calc_zoom_switching(params.viz);
	
		  return params;
		};
	
	/***/ }),
	/* 82 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function calc_zoom_switching(viz) {
	
		  var width_by_col = viz.clust.dim.width / viz.num_col_nodes;
		  var height_by_row = viz.clust.dim.height / viz.num_row_nodes;
	
		  viz.zoom_ratio = {};
		  viz.zoom_ratio.x = width_by_col / height_by_row;
		  viz.zoom_ratio.y = 1;
	
		  if (viz.zoom_ratio.x < 1) {
		    viz.zoom_ratio.y = 1 / viz.zoom_ratio.x;
		    viz.zoom_ratio.x = 1;
		  }
	
		  return viz;
		};
	
	/***/ }),
	/* 83 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function calc_default_fs(params) {
	
		  params.labels.default_fs_row = params.viz.y_scale.rangeBand() * 1.01;
		  params.labels.default_fs_col = params.viz.x_scale.rangeBand() * 0.87;
	
		  if (params.labels.default_fs_row > params.labels.max_allow_fs) {
		    params.labels.default_fs_row = params.labels.max_allow_fs;
		  }
	
		  if (params.labels.default_fs_col > params.labels.max_allow_fs) {
		    params.labels.default_fs_col = params.labels.max_allow_fs;
		  }
	
		  return params;
			};
	
	/***/ }),
	/* 84 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var calc_cat_params = __webpack_require__(85);
		var utils = __webpack_require__(2);
		var colors = __webpack_require__(86);
		var check_if_value_cats = __webpack_require__(87);
	
		module.exports = function make_cat_params(params, viz) {
		  var predefined_cat_colors = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
	
	
		  var super_string = ': ';
		  var tmp_super;
		  var inst_info;
		  var inst_color;
	
		  viz.show_categories = {};
		  viz.all_cats = {};
		  viz.cat_names = {};
		  viz.cat_info = {};
	
		  // this will hold the information for calculating the opacity of the value
		  // function
		  var ini_val_opacity = {};
		  ini_val_opacity.row = null;
		  ini_val_opacity.col = null;
	
		  viz.cat_colors = {};
		  viz.cat_colors.value_opacity = ini_val_opacity;
	
		  var num_colors = 0;
		  _.each(['row', 'col'], function (inst_rc) {
	
		    viz.show_categories[inst_rc] = false;
	
		    viz.all_cats[inst_rc] = [];
		    var tmp_keys = _.keys(params.network_data[inst_rc + '_nodes'][0]);
	
		    tmp_keys = tmp_keys.sort();
	
		    _.each(tmp_keys, function (d) {
		      if (d.indexOf('cat-') >= 0) {
		        viz.show_categories[inst_rc] = true;
		        viz.all_cats[inst_rc].push(d);
		      }
		    });
	
		    viz.cat_info[inst_rc] = null;
	
		    if (viz.show_categories[inst_rc]) {
	
		      viz.cat_colors[inst_rc] = {};
		      viz.cat_info[inst_rc] = {};
		      viz.cat_names[inst_rc] = {};
	
		      _.each(viz.all_cats[inst_rc], function (cat_title) {
	
		        var inst_node = params.network_data[inst_rc + '_nodes'][0];
	
		        // look for title of category in category name
		        if (typeof inst_node[cat_title] === 'string') {
	
		          if (inst_node[cat_title].indexOf(super_string) > 0) {
		            tmp_super = inst_node[cat_title].split(super_string)[0];
		            viz.cat_names[inst_rc][cat_title] = tmp_super;
		          } else {
		            viz.cat_names[inst_rc][cat_title] = cat_title;
		          }
		        } else {
		          viz.cat_names[inst_rc][cat_title] = cat_title;
		        }
	
		        var cat_instances_titles = utils.pluck(params.network_data[inst_rc + '_nodes'], cat_title);
		        var cat_instances = [];
	
		        _.each(cat_instances_titles, function (inst_cat) {
	
		          var new_cat;
		          if (inst_cat.indexOf(': ') > 0) {
		            new_cat = inst_cat.split(': ')[1];
		          } else {
		            new_cat = inst_cat;
		          }
	
		          cat_instances.push(new_cat);
		        });
	
		        var cat_states = _.uniq(cat_instances_titles).sort();
	
		        // check whether all the categories are of value type
		        inst_info = check_if_value_cats(cat_states);
	
		        // add histogram to inst_info
		        if (inst_info.type === 'cat_strings') {
		          // remove titles from categories in hist
		          var cat_hist = _.countBy(cat_instances);
		          inst_info.cat_hist = cat_hist;
		        } else {
		          inst_info.cat_hist = null;
		        }
	
		        // pass info_info object
		        viz.cat_info[inst_rc][cat_title] = inst_info;
	
		        viz.cat_colors[inst_rc][cat_title] = {};
	
		        _.each(cat_states, function (cat_tmp, inst_index) {
	
		          inst_color = colors.get_random_color(inst_index + num_colors);
	
		          viz.cat_colors[inst_rc][cat_title][cat_tmp] = inst_color;
	
		          // hack to get 'Not' categories to not be dark colored
		          // also doing this for false
		          if (typeof cat_tmp === 'string') {
		            if (cat_tmp.indexOf('Not ') >= 0 || cat_tmp.indexOf(': false') > 0) {
		              viz.cat_colors[inst_rc][cat_title][cat_tmp] = '#eee';
		            }
		          }
	
		          num_colors = num_colors + 1;
		        });
		      });
		    }
	
		    if (_.has(params.network_data, 'cat_colors') && predefined_cat_colors === true) {
		      viz.cat_colors[inst_rc] = params.network_data.cat_colors[inst_rc];
		    }
	
		    if (params.sim_mat) {
		      // sending row color info to columns since row color info can be updated
		      viz.cat_colors.col = viz.cat_colors.row;
		    }
		  });
	
		  viz.cat_colors = viz.cat_colors;
	
		  viz.cat_colors.opacity = 0.6;
		  viz.cat_colors.active_opacity = 0.9;
	
		  viz = calc_cat_params(params, viz);
	
		  return viz;
			};
	
	/***/ }),
	/* 85 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function calc_cat_params(params, viz) {
	
		  var separtion_room;
	
		  // increase the width of the label container based on the label length
		  var label_scale = d3.scale.linear().domain([5, 15]).range([85, 120]).clamp('true');
	
		  viz.cat_room = {};
		  viz.cat_room.symbol_width = 12;
		  viz.cat_room.separation = 3;
	
		  _.each(['row', 'col'], function (inst_rc) {
	
		    viz.norm_labels.width[inst_rc] = label_scale(params.labels[inst_rc + '_max_char']) * params[inst_rc + '_label_scale'];
	
		    viz['num_' + inst_rc + '_nodes'] = params.network_data[inst_rc + '_nodes'].length;
	
		    // if (_.has(config, 'group_level')){
		    //   config.group_level[inst_rc] = 5;
		    // }
	
		    if (inst_rc === 'row') {
		      viz.dendro_room[inst_rc] = viz.dendro_room.symbol_width;
		    } else {
		      viz.dendro_room[inst_rc] = viz.dendro_room.symbol_width + 3 * viz.uni_margin;
		    }
	
		    var num_cats = viz.all_cats[inst_rc].length;
	
		    if (viz.show_categories[inst_rc]) {
	
		      separtion_room = (num_cats - 1) * viz.cat_room.separation;
	
		      var adjusted_cats;
		      if (inst_rc === 'row') {
		        adjusted_cats = num_cats + 1;
		      } else {
		        adjusted_cats = num_cats;
		      }
	
		      viz.cat_room[inst_rc] = adjusted_cats * viz.cat_room.symbol_width + separtion_room;
		    } else {
		      // no categories
		      if (inst_rc == 'row') {
		        viz.cat_room[inst_rc] = viz.cat_room.symbol_width;
		      } else {
		        viz.cat_room[inst_rc] = 0;
		      }
		    }
		  });
	
		  return viz;
			};
	
	/***/ }),
	/* 86 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		// colors from http://graphicdesign.stackexchange.com/revisions/3815/8
		var all_colors;
	
		all_colors = ["#393b79", "#aec7e8", "#ff7f0e", "#ffbb78", "#98df8a", "#bcbd22", "#404040", "#ff9896", "#c5b0d5", "#8c564b", "#1f77b4", "#5254a3", "#FFDB58", "#c49c94", "#e377c2", "#7f7f7f", "#2ca02c", "#9467bd", "#dbdb8d", "#17becf", "#637939", "#6b6ecf", "#9c9ede", "#d62728", "#8ca252", "#8c6d31", "#bd9e39", "#e7cb94", "#843c39", "#ad494a", "#d6616b", "#7b4173", "#a55194", "#ce6dbd", "#de9ed6"];
	
		// too light colors 
		// "#e7969c",
		// "#c7c7c7", 
		// "#f7b6d2", 
		// "#cedb9c", 
		// "#9edae5", 
	
		function get_default_color() {
		  return '#EEE';
		}
	
		function get_random_color(i) {
		  return all_colors[i % get_num_colors()];
		}
	
		function get_num_colors() {
		  return all_colors.length;
		}
	
		module.exports = {
		  get_default_color: get_default_color,
		  get_random_color: get_random_color,
		  get_num_colors: get_num_colors
			};
	
	/***/ }),
	/* 87 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var underscore = __webpack_require__(68);
	
		module.exports = function check_if_value_cats(cat_states) {
	
		  var tmp_cat = cat_states[0];
	
		  var has_title = false;
		  var might_have_values = false;
		  var cat_types = 'cat_strings';
		  var max_abs_val = NaN;
		  var all_values = [];
		  var cat_scale = null;
	
		  var super_string = ': ';
	
		  if (typeof tmp_cat === 'string') {
		    if (tmp_cat.indexOf(super_string) > -1) {
		      has_title = true;
		      tmp_cat = tmp_cat.split(super_string)[1];
		    }
		  }
	
		  if (isNaN(tmp_cat) == false) {
		    might_have_values = true;
		  }
	
		  // check each value for number
		  if (might_have_values) {
	
		    // the default state is that all are now values, check each one
		    cat_types = 'cat_values';
	
		    _.each(cat_states, function (inst_cat) {
	
		      if (has_title) {
		        inst_cat = inst_cat.split(super_string)[1];
		      }
	
		      // checking whether inst_cat is 'not a number'
		      if (isNaN(inst_cat) === true) {
		        cat_types = 'cat_strings';
		      } else {
		        inst_cat = parseFloat(inst_cat);
		        all_values.push(inst_cat);
		      }
		    });
		  }
	
		  if (cat_types === 'cat_values') {
	
		    // get absolute value
		    var max_value = underscore.max(all_values, function (d) {
		      return Math.abs(d);
		    });
	
		    max_abs_val = Math.abs(max_value);
	
		    cat_scale = d3.scale.linear().domain([0, max_abs_val]).range([0, 1]);
		  }
	
		  var inst_info = {};
		  inst_info.type = cat_types;
		  inst_info.max_abs_val = max_abs_val;
		  inst_info.cat_scale = cat_scale;
	
		  return inst_info;
			};
	
	/***/ }),
	/* 88 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function ini_zoom_info() {
	
		  var zoom_info = {};
		  zoom_info.zoom_x = 1;
		  zoom_info.zoom_y = 1;
		  zoom_info.trans_x = 0;
		  zoom_info.trans_y = 0;
	
		  return zoom_info;
			};
	
	/***/ }),
	/* 89 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var generate_matrix = __webpack_require__(90);
		var make_row_label_container = __webpack_require__(101);
		var make_col_label_container = __webpack_require__(131);
		var generate_super_labels = __webpack_require__(139);
		var spillover = __webpack_require__(140);
		var initialize_resizing = __webpack_require__(151);
		var ini_doubleclick = __webpack_require__(161);
		var make_col_cat = __webpack_require__(180);
		var make_row_cat = __webpack_require__(185);
		var trim_text = __webpack_require__(146);
		var make_row_dendro = __webpack_require__(186);
		var make_col_dendro = __webpack_require__(187);
		var make_svg_dendro_sliders = __webpack_require__(188);
		var make_row_dendro_spillover = __webpack_require__(228);
	
		module.exports = function make_viz(cgm) {
	
		  var params = cgm.params;
	
		  d3.select(params.viz.viz_wrapper + ' svg').remove();
	
		  var svg_group = d3.select(params.viz.viz_wrapper).append('svg').attr('class', 'viz_svg').attr('id', 'svg_' + params.root.replace('#', '')).attr('width', params.viz.svg_dim.width).attr('height', params.viz.svg_dim.height).attr('is_zoom', 0).attr('stopped_zoom', 1);
	
		  svg_group.append('rect').attr('class', 'super_background').style('width', params.viz.svg_dim.width).style('height', params.viz.svg_dim.height).style('fill', 'white');
	
		  generate_matrix(params, svg_group);
	
		  make_row_label_container(cgm);
	
		  if (params.viz.show_dendrogram) {
		    make_row_dendro(cgm);
		    make_col_dendro(cgm);
		    make_row_dendro_spillover(cgm);
		  }
	
		  make_col_label_container(cgm);
	
		  // initial trim text
		  if (params.viz.ds_level === -1) {
		    _.each(['row', 'col'], function (inst_rc) {
	
		      var inst_fs = Number(d3.select('.' + inst_rc + '_label_group').select('text').style('font-size').replace('px', ''));
	
		      var min_trim_fs = 8;
		      if (inst_fs > min_trim_fs) {
		        d3.selectAll(params.root + ' .' + inst_rc + '_label_group').each(function () {
		          trim_text(params, this, inst_rc);
		        });
		      }
		    });
		  }
	
		  // make category colorbars
		  make_row_cat(cgm);
		  if (params.viz.show_categories.col) {
		    make_col_cat(cgm);
		  }
	
		  spillover(cgm);
	
		  if (params.labels.super_labels) {
		    generate_super_labels(params);
		  }
	
		  if (params.viz.show_dendrogram) {
		    // sliders should go above super labels
		    make_svg_dendro_sliders(cgm);
		  }
	
		  function border_colors() {
		    var inst_color = params.viz.super_border_color;
		    if (params.viz.is_expand || params.show_viz_border == false) {
		      inst_color = 'white';
		    }
		    return inst_color;
		  }
	
		  // left border
		  d3.select(params.viz.viz_svg).append('rect').classed('left_border', true).classed('borders', true).attr('fill', border_colors).attr('width', params.viz.grey_border_width).attr('height', params.viz.svg_dim.height).attr('transform', 'translate(0,0)');
	
		  // right border
		  d3.select(params.viz.viz_svg).append('rect').classed('right_border', true).classed('borders', true).attr('fill', border_colors).attr('width', params.viz.grey_border_width).attr('height', params.viz.svg_dim.height).attr('transform', function () {
		    var inst_offset = params.viz.svg_dim.width - params.viz.grey_border_width;
		    return 'translate(' + inst_offset + ',0)';
		  });
	
		  // top border
		  d3.select(params.viz.viz_svg).append('rect').classed('top_border', true).classed('borders', true).attr('fill', border_colors).attr('width', params.viz.svg_dim.width).attr('height', params.viz.grey_border_width).attr('transform', function () {
		    var inst_offset = 0;
		    return 'translate(' + inst_offset + ',0)';
		  });
	
		  // bottom border
		  d3.select(params.viz.viz_svg).append('rect').classed('bottom_border', true).classed('borders', true).attr('fill', border_colors).attr('width', params.viz.svg_dim.width).attr('height', params.viz.grey_border_width).attr('transform', function () {
		    var inst_offset = params.viz.svg_dim.height - params.viz.grey_border_width;
		    return 'translate(0,' + inst_offset + ')';
		  });
	
		  initialize_resizing(cgm);
	
		  ini_doubleclick(cgm);
	
		  if (params.viz.do_zoom) {
		    d3.select(params.viz.zoom_element).call(params.zoom_behavior);
		  }
	
		  d3.select(params.viz.zoom_element).on('dblclick.zoom', null);
			};
	
	/***/ }),
	/* 90 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
		var draw_gridlines = __webpack_require__(91);
		var add_click_hlight = __webpack_require__(92);
		var make_matrix_rows = __webpack_require__(93);
	
		module.exports = function (params, svg_elem) {
		  var network_data = params.network_data;
	
		  var matrix = [];
		  var clust_group;
	
		  // append a group that will hold clust_group and position it once
		  clust_group = svg_elem.append('g').attr('class', 'clust_container').attr('transform', 'translate(' + params.viz.clust.margin.left + ',' + params.viz.clust.margin.top + ')').append('g').attr('class', 'clust_group').classed('clust_group', true);
	
		  // clustergram background rect
		  clust_group.append('rect').classed('background', true).classed('grey_background', true).style('fill', '#eee').style('opacity', 0.25).attr('width', params.viz.clust.dim.width).attr('height', params.viz.clust.dim.height);
	
		  // pass in params and the rows (row_nodes) that need to be made
		  // in this case all row nodes
		  // make_matrix_rows(params, params.matrix.matrix, params.network_data.row_nodes_names);
	
		  // initialize at ds_level 0
		  if (params.viz.ds === null) {
		    // do not use downsampled matrix
		    make_matrix_rows(params, params.matrix.matrix, 'all', params.viz.ds_level);
		  } else {
		    // use downsampled matrix
		    make_matrix_rows(params, params.matrix.ds_matrix[0], 'all', params.viz.ds_level);
		  }
	
		  // add callback function to tile group - if one is supplied by the user
		  if (typeof params.click_tile === 'function') {
		    d3.selectAll(params.root + ' .tile').on('click', function (d) {
	
		      // export row/col name and value from tile
		      var tile_info = {};
		      tile_info.row = params.network_data.row_nodes[d.pos_y].name;
		      tile_info.col = params.network_data.col_nodes[d.pos_x].name;
		      tile_info.value = d.value;
	
		      if (utils.has(d, 'value_up')) {
		        tile_info.value_up = d.value_up;
		      }
		      if (utils.has(d, 'value_dn')) {
		        tile_info.value_dn = d.value_dn;
		      }
		      if (utils.has(d, 'info')) {
		        tile_info.info = d.info;
		      }
		      // run the user supplied callback function
		      params.click_tile(tile_info);
		      add_click_hlight(params, this);
		    });
		  } else {
	
		    // highlight clicked tile
		    if (params.tile_click_hlight) {
		      d3.selectAll(params.root + ' .tile').on('click', function () {
		        add_click_hlight(params, this);
		      });
		    }
		  }
	
		  // draw grid lines after drawing tiles
		  var delays = {};
		  var duration = 0;
		  delays.enter = 0;
		  draw_gridlines(params, delays, duration);
	
		  // Matrix API
		  return {
		    get_clust_group: function get_clust_group() {
		      return clust_group;
		    },
		    get_matrix: function get_matrix() {
		      return matrix;
		    },
		    get_nodes: function get_nodes(type) {
		      if (type === 'row') {
		        return network_data.row_nodes;
		      }
		      return network_data.col_nodes;
		    }
		  };
			};
	
	/***/ }),
	/* 91 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		// var grid_lines_viz = require('./grid_lines_viz');
		// var toggle_grid_lines = require('./toggle_grid_lines');
	
		/* eslint-disable */
		module.exports = function draw_gridlines(params, delays, duration) {
	
		  // var row_nodes = params.network_data.row_nodes;
		  // var col_nodes = params.network_data.col_nodes;
	
		  // // Fade in new gridlines
		  // ///////////////////////////
	
		  // // append horizontal line groups
		  // var horz_lines = d3.select(params.root+' .clust_group')
		  //   .selectAll('.horz_lines')
		  //   .data(row_nodes, function(d){return d.name;})
		  //   .enter()
		  //   .append('g')
		  //   .attr('class','horz_lines');
	
		  // // append vertical line groups
		  // var vert_lines = d3.select(params.root+' .clust_group')
		  //   .selectAll('.vert_lines')
		  //   .data(col_nodes)
		  //   .enter()
		  //   .append('g')
		  //   .attr('class', 'vert_lines');
	
		  // grid_lines_viz(params, duration);
	
		  // horz_lines
		  //   .select('line')
		  //   .attr('opacity',0)
		  //   .attr('stroke','white')
		  //   .attr('opacity', 1);
	
		  // vert_lines
		  //   .select('line')
		  //   .style('stroke', 'white')
		  //   .attr('opacity',0)
		  //   .transition().delay(delays.enter).duration(2*duration)
		  //   .attr('opacity', 1);
	
		  // toggle_grid_lines(params);
	
		};
	
	/***/ }),
	/* 92 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function (params, clicked_rect) {
	
		  // get x position of rectangle
		  d3.select(clicked_rect).each(function (d) {
		    var pos_x = d.pos_x;
		    var pos_y = d.pos_y;
	
		    d3.selectAll(params.root + ' .click_hlight').remove();
	
		    if (pos_x != params.matrix.click_hlight_x || pos_y != params.matrix.click_hlight_y) {
	
		      // save pos_x to params.viz.click_hlight_x
		      params.matrix.click_hlight_x = pos_x;
		      params.matrix.click_hlight_y = pos_y;
	
		      // draw the highlighting rectangle as four rectangles
		      // so that the width and height can be controlled
		      // separately
	
		      var rel_width_hlight = 6;
		      var opacity_hlight = 0.85;
	
		      var hlight_width = rel_width_hlight * params.viz.border_width.x;
		      var hlight_height = rel_width_hlight * params.viz.border_width.y;
	
		      // top highlight
		      d3.select(clicked_rect.parentNode).append('rect').classed('click_hlight', true).classed('top_hlight', true).attr('width', params.viz.x_scale.rangeBand()).attr('height', hlight_height).attr('fill', params.matrix.hlight_color).attr('transform', function () {
		        return 'translate(' + params.viz.x_scale(pos_x) + ',0)';
		      }).attr('opacity', opacity_hlight);
	
		      // left highlight
		      d3.select(clicked_rect.parentNode).append('rect').classed('click_hlight', true).classed('left_hlight', true).attr('width', hlight_width).attr('height', params.viz.y_scale.rangeBand() - hlight_height * 0.99).attr('fill', params.matrix.hlight_color).attr('transform', function () {
		        return 'translate(' + params.viz.x_scale(pos_x) + ',' + hlight_height * 0.99 + ')';
		      }).attr('opacity', opacity_hlight);
	
		      // right highlight
		      d3.select(clicked_rect.parentNode).append('rect').classed('click_hlight', true).classed('right_hlight', true).attr('width', hlight_width).attr('height', params.viz.y_scale.rangeBand() - hlight_height * 0.99).attr('fill', params.matrix.hlight_color).attr('transform', function () {
		        var tmp_translate = params.viz.x_scale(pos_x) + params.viz.x_scale.rangeBand() - hlight_width;
		        return 'translate(' + tmp_translate + ',' + hlight_height * 0.99 + ')';
		      }).attr('opacity', opacity_hlight);
	
		      // bottom highlight
		      d3.select(clicked_rect.parentNode).append('rect').classed('click_hlight', true).classed('bottom_hlight', true).attr('width', function () {
		        return params.viz.x_scale.rangeBand() - 1.98 * hlight_width;
		      }).attr('height', hlight_height).attr('fill', params.matrix.hlight_color).attr('transform', function () {
		        var tmp_translate_x = params.viz.x_scale(pos_x) + hlight_width * 0.99;
		        var tmp_translate_y = params.viz.y_scale.rangeBand() - hlight_height;
		        return 'translate(' + tmp_translate_x + ',' + tmp_translate_y + ')';
		      }).attr('opacity', opacity_hlight);
		    } else {
		      params.matrix.click_hlight_x = -666;
		      params.matrix.click_hlight_y = -666;
		    }
		  });
		};
	
	/***/ }),
	/* 93 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_simple_rows = __webpack_require__(94);
		var d3_tip_custom = __webpack_require__(100);
		var underscore = __webpack_require__(68);
	
		// current matrix can change with downsampling
		module.exports = function make_matrix_rows(params, current_matrix) {
		  var row_names = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'all';
		  var ds_level = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : -1;
	
	
		  // defaults
		  var y_scale = params.viz.y_scale;
		  var make_tip = true;
		  var row_class = 'row';
	
		  if (ds_level >= 0) {
		    y_scale = params.viz.ds[ds_level].y_scale;
	
		    // do not show tip when rows are downsampled
		    make_tip = false;
		    row_class = 'ds' + String(ds_level) + '_row';
		  }
	
		  if (make_tip) {
	
		    // do not remove tile_tip here
		    /////////////////////////////////
	
		    // make rows in the matrix - add key names to rows in matrix
		    /////////////////////////////////////////////////////////////
		    // d3-tooltip - for tiles
		    var tip = d3_tip_custom().attr('class', function () {
		      var root_tip_selector = params.viz.root_tips.replace('.', '');
		      var class_string = root_tip_selector + ' d3-tip ' + root_tip_selector + '_tile_tip';
		      return class_string;
		    }).style('display', 'none').direction('nw').offset([0, 0]).html(function (d) {
		      var inst_value = String(d.value.toFixed(3));
		      var tooltip_string;
	
		      if (params.keep_orig) {
		        var orig_value = String(d.value_orig.toFixed(3));
		        tooltip_string = '<p>' + d.row_name + ' and ' + d.col_name + '</p>' + '<p> normalized value: ' + inst_value + '</p>' + '<div> original value: ' + orig_value + '</div>';
		      } else {
		        tooltip_string = '<p>' + d.row_name + ' and ' + d.col_name + '</p>' + '<div> value: ' + inst_value + '</div>';
		      }
	
		      return tooltip_string;
		    });
		  } else {
		    tip = null;
		  }
	
		  // gather a subset of row data from the matrix or use all rows
		  var matrix_subset = [];
		  if (row_names === 'all') {
		    matrix_subset = current_matrix;
		  } else {
		    _.each(current_matrix, function (inst_row) {
		      if (underscore.contains(row_names, inst_row.name)) {
		        matrix_subset.push(inst_row);
		      }
		    });
		  }
	
		  d3.select(params.root + ' .clust_group').selectAll('.row').data(matrix_subset, function (d) {
		    return d.name;
		  }).enter().append('g').classed(row_class, true).attr('transform', function (d) {
		    return 'translate(0,' + y_scale(d.row_index) + ')';
		  }).each(function (d) {
		    make_simple_rows(params, d, tip, this, ds_level);
		  });
	
		  if (params.viz.ds_level === -1 && tip != null) {
		    d3.selectAll(params.root + ' .row').call(tip);
		  }
			};
	
	/***/ }),
	/* 94 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		/* eslint-disable */
	
		var draw_up_tile = __webpack_require__(95);
		var draw_dn_tile = __webpack_require__(96);
		var mouseover_tile = __webpack_require__(97);
		var mouseout_tile = __webpack_require__(98);
		var fine_position_tile = __webpack_require__(99);
	
		module.exports = function make_simple_rows(params, inst_data, tip, row_selection) {
		  var ds_level = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : -1;
	
	
		  var inp_row_data = inst_data.row_data;
	
		  var make_tip = true;
		  var rect_height = params.viz.rect_height;
		  if (ds_level >= 0) {
		    // make_tip = false;
		    rect_height = params.viz.ds[ds_level].rect_height;
		  }
	
		  var keep_orig;
		  if (_.has(params.network_data.links[0], 'value_orig')) {
		    keep_orig = true;
		  } else {
		    keep_orig = false;
		  }
	
		  var row_values;
		  if (keep_orig === false) {
		    // value: remove zero values to make visualization faster
		    row_values = _.filter(inp_row_data, function (num) {
		      return num.value !== 0;
		    });
		  } else {
		    row_values = inp_row_data;
		  }
	
		  // generate tiles in the current row
		  var tile = d3.select(row_selection).selectAll('rect').data(row_values, function (d) {
		    return d.col_name;
		  }).enter().append('rect').attr('class', 'tile row_tile').attr('width', params.viz.rect_width).attr('height', rect_height).style('fill', function (d) {
		    // switch the color based on up/dn value
		    var inst_fill;
		    if (d.value_orig === 'NaN') {
		      inst_fill = '#000000';
		    } else {
		      inst_fill = d.value > 0 ? params.matrix.tile_colors[0] : params.matrix.tile_colors[1];
		    }
		    return inst_fill;
		  }).style('fill-opacity', function (d) {
		    // calculate output opacity using the opacity scale
		    var inst_opacity;
		    if (d.value_orig === 'NaN') {
		      // console.log('found NaN while making tiles');
		      inst_opacity = 0.175;
		    } else {
		      inst_opacity = params.matrix.opacity_scale(Math.abs(d.value));
		    }
		    return inst_opacity;
		  }).attr('transform', function (d) {
		    return fine_position_tile(params, d);
		  });
	
		  if (make_tip) {
		    tile.on('mouseover', function () {
		      for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
		        args[_key] = arguments[_key];
		      }
		      mouseover_tile(params, this, tip, args);
		    }).on('mouseout', function () {
		      mouseout_tile(params, this, tip);
		    });
		  }
	
		  // // tile circles
		  // /////////////////////////////
		  // var tile = d3.select(row_selection)
		  //   .selectAll('circle')
		  //   .data(row_values, function(d){ return d.col_name; })
		  //   .enter()
		  //   .append('circle')
		  //   .attr('cx', params.viz.rect_height/2)
		  //   .attr('cy', params.viz.rect_height/2)
		  //   .attr('r', params.viz.rect_height/3)
		  //   .attr('class', 'tile_circle')
		  //   // .attr('width', params.viz.rect_width/2)
		  //   // .attr('height', params.viz.rect_height/2)
		  //   // // switch the color based on up/dn value
		  //   // .style('fill', function(d) {
		  //   //   // return d.value > 0 ? params.matrix.tile_colors[0] : params.matrix.tile_colors[1];
		  //   //   return 'black';
		  //   // })
		  //   .on('mouseover', function(...args) {
		  //       mouseover_tile(params, this, tip, args);
		  //   })
		  //   .on('mouseout', function() {
		  //     mouseout_tile(params, this, tip);
		  //   })
		  //   .style('fill-opacity', function(d) {
		  //     // calculate output opacity using the opacity scale
		  //     var output_opacity = params.matrix.opacity_scale(Math.abs(d.value));
		  //     if (output_opacity < 0.3){
		  //       output_opacity = 0;
		  //     } else if (output_opacity < 0.6){
		  //       output_opacity = 0.35;
		  //     } else {
		  //       output_opacity = 1;
		  //     }
		  //     return output_opacity;
		  //     // return 0.1;
		  //   })
		  //   .attr('transform', function(d) {
		  //     return fine_position_tile(params, d);
		  //   });
	
	
		  if (params.matrix.tile_type == 'updn') {
	
		    // value split
		    var row_split_data = _.filter(inp_row_data, function (num) {
		      return num.value_up != 0 || num.value_dn != 0;
		    });
	
		    // tile_up
		    d3.select(row_selection).selectAll('.tile_up').data(row_split_data, function (d) {
		      return d.col_name;
		    }).enter().append('path').attr('class', 'tile_up').attr('d', function () {
		      return draw_up_tile(params);
		    }).attr('transform', function (d) {
		      fine_position_tile(params, d);
		    }).style('fill', function () {
		      return params.matrix.tile_colors[0];
		    }).style('fill-opacity', function (d) {
		      var inst_opacity = 0;
		      if (Math.abs(d.value_dn) > 0) {
		        inst_opacity = params.matrix.opacity_scale(Math.abs(d.value_up));
		      }
		      return inst_opacity;
		    }).on('mouseover', function () {
		      for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
		        args[_key2] = arguments[_key2];
		      }
	
		      mouseover_tile(params, this, tip, args);
		    }).on('mouseout', function () {
		      mouseout_tile(params, this, tip);
		    });
	
		    // tile_dn
		    d3.select(row_selection).selectAll('.tile_dn').data(row_split_data, function (d) {
		      return d.col_name;
		    }).enter().append('path').attr('class', 'tile_dn').attr('d', function () {
		      return draw_dn_tile(params);
		    }).attr('transform', function (d) {
		      fine_position_tile(params, d);
		    }).style('fill', function () {
		      return params.matrix.tile_colors[1];
		    }).style('fill-opacity', function (d) {
		      var inst_opacity = 0;
		      if (Math.abs(d.value_up) > 0) {
		        inst_opacity = params.matrix.opacity_scale(Math.abs(d.value_dn));
		      }
		      return inst_opacity;
		    }).on('mouseover', function () {
		      for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
		        args[_key3] = arguments[_key3];
		      }
	
		      mouseover_tile(params, this, tip, args);
		    }).on('mouseout', function () {
		      mouseout_tile(params, this, tip);
		    });
	
		    // remove rect when tile is split
		    tile.each(function (d) {
		      if (Math.abs(d.value_up) > 0 && Math.abs(d.value_dn) > 0) {
		        d3.select(this).remove();
		      }
		    });
		  }
	
		  // append title to group
		  if (params.matrix.tile_title) {
		    tile.append('title').text(function (d) {
		      var inst_string = 'value: ' + d.value;
		      return inst_string;
		    });
		  }
			};
	
	/***/ }),
	/* 95 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function draw_up_tile(params) {
	
		  var start_x = 0;
		  var final_x = params.viz.x_scale.rangeBand() - params.viz.border_width.x;
		  var start_y = 0;
		  var final_y = params.viz.y_scale.rangeBand() - params.viz.border_width.y;
	
		  var output_string = 'M' + start_x + ',' + start_y + ', L' + start_x + ', ' + final_y + ', L' + final_x + ',0 Z';
	
		  return output_string;
		};
	
	/***/ }),
	/* 96 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function draw_dn_tile(params) {
	
		  var start_x = 0;
		  var final_x = params.viz.x_scale.rangeBand() - params.viz.border_width.x;
		  var start_y = params.viz.y_scale.rangeBand() - params.viz.border_width.y;
		  var final_y = params.viz.y_scale.rangeBand() - params.viz.border_width.y;
	
		  var output_string = 'M' + start_x + ', ' + start_y + ' ,   L' + final_x + ', ' + final_y + ',  L' + final_x + ',0 Z';
	
		  return output_string;
		};
	
	/***/ }),
	/* 97 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function mouseover_tile(params, inst_selection, tip, inst_arguments) {
	
		  var inst_data = inst_arguments[0];
		  var args = [].slice.call(inst_arguments);
		  var timeout;
		  var delay = 1000;
	
		  d3.select(inst_selection).classed('hovering', true);
	
		  _.each(['row', 'col'], function (inst_rc) {
	
		    d3.selectAll(params.root + ' .' + inst_rc + '_label_group text').style('font-weight', function (d) {
		      var font_weight;
		      var inst_found = inst_data[inst_rc + '_name'].replace(/_/g, ' ') === d.name;
	
		      if (inst_found) {
		        font_weight = 'bold';
		      } else {
		        font_weight = 'normal';
		      }
		      return font_weight;
		    });
		  });
	
		  args.push(inst_selection);
		  clearTimeout(timeout);
		  timeout = setTimeout(check_if_hovering, delay, inst_selection);
	
		  function check_if_hovering() {
	
		    if (d3.select(inst_selection).classed('hovering')) {
	
		      var inst_zoom = Number(d3.select(params.root + ' .viz_svg').attr('is_zoom'));
	
		      if (inst_zoom === 0) {
	
		        if (params.matrix.show_tile_tooltips && tip !== null) {
	
		          d3.selectAll(params.viz.root_tips + '_tile_tip').style('display', 'block');
	
		          tip.show.apply(inst_selection, args);
	
		          if (params.tile_tip_callback != null) {
		            var tile_info = args[0];
		            params.tile_tip_callback(tile_info);
		          }
		        }
		      }
		    }
		  }
			};
	
	/***/ }),
	/* 98 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function mouseout_tile(params, inst_selection, tip) {
	
		  d3.select(inst_selection).classed('hovering', false);
	
		  d3.selectAll(params.viz.root_tips + '_tile_tip').style('display', 'none');
	
		  _.each(['row', 'col'], function (inst_rc) {
	
		    d3.selectAll(params.root + ' .' + inst_rc + '_label_group text').style('font-weight', 'normal');
		  });
	
		  if (tip != null) {
		    tip.hide();
		  }
		};
	
	/***/ }),
	/* 99 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function fine_position_tile(params, d) {
	
		  var offset_x;
	
		  // prevent rows not in x_scale domain from causing errors
		  if (d.pos_x in params.viz.x_scale.domain()) {
		    offset_x = params.viz.x_scale(d.pos_x);
		  } else {
		    offset_x = 0;
		  }
	
		  var x_pos = offset_x + 0.5 * params.viz.border_width.x;
		  var y_pos = 0.5 * params.viz.border_width.y;
		  return 'translate(' + x_pos + ',' + y_pos + ')';
		};
	
	/***/ }),
	/* 100 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function d3_tip_custom() {
		  /* eslint-disable */
		  // Copyright (c) 2013 Justin Palmer
		  //
		  // Tooltips for d3.js SVG visualizations
	
		  // Public - contructs a new tooltip
		  //
		  // Returns a tip
		  // ******************
		  // Nick Fernandez modified version 4-19-2016
		  // improved multiple svg, scrolling+zooming support
		  // made syntax fixes
		  //////////////////////////////////////////////
		  var direction = d3_tip_direction,
		      offset = d3_tip_offset,
		      html = d3_tip_html,
		      node = initNode(),
		      svg = null,
		      point = null,
		      target = null;
	
		  function tip(vis) {
		    svg = getSVGNode(vis);
		    point = svg.createSVGPoint();
		    document.body.appendChild(node);
		  }
	
		  // Public - show the tooltip on the screen
		  //
		  // Returns a tip
		  tip.show = function () {
	
		    var args = Array.prototype.slice.call(arguments);
		    if (args[args.length - 1] instanceof SVGElement) {
		      target = args.pop();
		    }
	
		    var content = html.apply(this, args);
		    var poffset = offset.apply(this, args);
		    var dir = direction.apply(this, args);
		    var nodel = d3.select(node);
		    var i = 0;
		    var coords;
	
		    // add z-index to make sure tooltips appear on top
		    nodel.html(content).style({ opacity: 1, 'pointer-events': 'all' }).style('z-index', 99);
	
		    while (i--) {
		      nodel.classed(directions[i], false);
		    }
		    coords = direction_callbacks.get(dir).apply(this);
		    nodel.classed(dir, true).style({
		      top: coords.top + poffset[0] + 'px',
		      left: coords.left + poffset[1] + 'px'
		    });
	
		    // quick fix for fading tile tooltips
		    if (isFunction(this) === false) {
	
		      var inst_class = d3.select(this).attr('class');
	
		      if (inst_class.indexOf('tile') >= 0) {
		        setTimeout(fade_tips, 5000, this);
		      }
		    }
	
		    return tip;
		  };
	
		  // Public - hide the tooltip
		  //
		  // Returns a tip
		  tip.hide = function () {
	
		    // // hide all d3-tip tooltips
		    // d3.selectAll('.d3-tip')
		    //   .style('display', 'none');
	
		    var nodel = d3.select(node);
		    nodel.style({ opacity: 0, 'pointer-events': 'none' });
		    return tip;
		  };
	
		  // Public: Proxy attr calls to the d3 tip container.  Sets or gets attribute value.
		  //
		  // n - name of the attribute
		  // v - value of the attribute
		  //
		  // Returns tip or attribute value
		  tip.attr = function (n) {
		    if (arguments.length < 2 && typeof n === 'string') {
		      return d3.select(node).attr(n);
		    } else {
		      var args = Array.prototype.slice.call(arguments);
		      d3.selection.prototype.attr.apply(d3.select(node), args);
		    }
	
		    return tip;
		  };
	
		  // Public: Proxy style calls to the d3 tip container.  Sets or gets a style value.
		  //
		  // n - name of the property
		  // v - value of the property
		  //
		  // Returns tip or style property value
		  tip.style = function (n) {
		    if (arguments.length < 2 && typeof n === 'string') {
		      return d3.select(node).style(n);
		    } else {
		      var args = Array.prototype.slice.call(arguments);
		      d3.selection.prototype.style.apply(d3.select(node), args);
		    }
	
		    return tip;
		  };
	
		  // Public: Set or get the direction of the tooltip
		  //
		  // v - One of n(north), s(south), e(east), or w(west), nw(northwest),
		  //     sw(southwest), ne(northeast) or se(southeast)
		  //
		  // Returns tip or direction
		  tip.direction = function (v) {
		    if (!arguments.length) {
		      return direction;
		    }
		    direction = v == null ? v : d3.functor(v);
	
		    return tip;
		  };
	
		  // Public: Sets or gets the offset of the tip
		  //
		  // v - Array of [x, y] offset
		  //
		  // Returns offset or
		  tip.offset = function (v) {
		    if (!arguments.length) {
		      return offset;
		    }
		    offset = v == null ? v : d3.functor(v);
	
		    return tip;
		  };
	
		  // Public: sets or gets the html value of the tooltip
		  //
		  // v - String value of the tip
		  //
		  // Returns html value or tip
		  tip.html = function (v) {
		    if (!arguments.length) {
		      return html;
		    }
		    html = v == null ? v : d3.functor(v);
	
		    return tip;
		  };
	
		  function d3_tip_direction() {
		    return 'n';
		  }
		  function d3_tip_offset() {
		    return [0, 0];
		  }
		  function d3_tip_html() {
		    return ' ';
		  }
	
		  var direction_callbacks = d3.map({
		    n: direction_n,
		    s: direction_s,
		    e: direction_e,
		    w: direction_w,
		    nw: direction_nw,
		    ne: direction_ne,
		    sw: direction_sw,
		    se: direction_se,
		    south_custom: direction_south_custom
		  }),
		      directions = direction_callbacks.keys();
	
		  function direction_south_custom() {
		    var bbox = getScreenBBox();
	
		    return {
		      top: bbox.s.y,
		      left: bbox.s.x
		    };
		  }
	
		  function direction_n() {
		    var bbox = getScreenBBox();
		    return {
		      top: bbox.n.y - node.offsetHeight,
		      left: bbox.n.x - node.offsetWidth / 2
		    };
		  }
	
		  function direction_s() {
		    var bbox = getScreenBBox();
		    return {
		      top: bbox.s.y,
		      left: bbox.s.x - node.offsetWidth / 2
		    };
		  }
	
		  function direction_e() {
		    var bbox = getScreenBBox();
		    return {
		      top: bbox.e.y - node.offsetHeight / 2,
		      left: bbox.e.x
		    };
		  }
	
		  function direction_w() {
		    var bbox = getScreenBBox();
		    return {
		      top: bbox.w.y - node.offsetHeight / 2,
		      left: bbox.w.x - node.offsetWidth
		    };
		  }
	
		  function direction_nw() {
		    var bbox = getScreenBBox();
		    return {
		      top: bbox.nw.y - node.offsetHeight,
		      left: bbox.nw.x - node.offsetWidth
		    };
		  }
	
		  function direction_ne() {
		    var bbox = getScreenBBox();
		    return {
		      top: bbox.ne.y - node.offsetHeight,
		      left: bbox.ne.x
		    };
		  }
	
		  function direction_sw() {
		    var bbox = getScreenBBox();
		    return {
		      top: bbox.sw.y,
		      left: bbox.sw.x - node.offsetWidth
		    };
		  }
	
		  function direction_se() {
		    var bbox = getScreenBBox();
		    return {
		      top: bbox.se.y,
		      left: bbox.e.x
		    };
		  }
	
		  function initNode() {
		    var node = d3.select(document.createElement('div'));
		    node.style({
		      position: 'absolute',
		      opacity: 0,
		      pointerEvents: 'none',
		      boxSizing: 'border-box'
		    });
	
		    return node.node();
		  }
	
		  function getSVGNode(el) {
		    el = el.node();
		    if (el.tagName.toLowerCase() == 'svg') {
		      return el;
		    }
	
		    return el.ownerSVGElement;
		  }
	
		  // Private - gets the screen coordinates of a shape
		  //
		  // Given a shape on the screen, will return an SVGPoint for the directions
		  // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest),
		  // sw(southwest).
		  //
		  //    +-+-+
		  //    |   |
		  //    +   +
		  //    |   |
		  //    +-+-+
		  //
		  // Returns an Object {n, s, e, w, nw, sw, ne, se}
		  function getScreenBBox() {
		    var targetel = target || d3.event.target;
		    var bbox = {};
		    var matrix = targetel.getScreenCTM();
		    var tbbox = targetel.getBBox();
		    var width = tbbox.width;
		    var height = tbbox.height;
		    var x = tbbox.x;
		    var y = tbbox.y;
		    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
		    var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
	
		    // Nick - prevents bugs with scrolling and zooming on the same object
		    matrix.a = 1;
		    matrix.d = 1;
		    // changing order of adding scrolling,
		    // original ordering was causing problems with pre-translated or rotated
		    // elements.
		    matrix.e = matrix.e + scrollLeft;
		    matrix.f = matrix.f + scrollTop;
		    point.x = x; //+ scrollLeft
		    point.y = y; //+ scrollTop
	
		    bbox.nw = point.matrixTransform(matrix);
		    point.x = point.x + width;
		    bbox.ne = point.matrixTransform(matrix);
		    point.y = point.y + height;
		    bbox.se = point.matrixTransform(matrix);
		    point.x = point.x - width;
		    bbox.sw = point.matrixTransform(matrix);
		    point.y = point.y - height / 2;
		    bbox.w = point.matrixTransform(matrix);
		    point.x = point.x + width;
		    bbox.e = point.matrixTransform(matrix);
		    point.x = point.x - width / 2;
		    point.y = point.y - height / 2;
		    bbox.n = point.matrixTransform(matrix);
		    point.y = point.y + height;
		    bbox.s = point.matrixTransform(matrix);
	
		    return bbox;
		  }
	
		  // only fade tips if you are still hovering on the current tip
		  function fade_tips(inst_selection) {
	
		    var is_hovering = d3.select(inst_selection).classed('hovering');
	
		    if (is_hovering) {
		      d3.selectAll('.d3-tip').transition().duration(250).style('opacity', 0).style('display', 'none');
		    }
		  }
	
		  function isFunction(functionToCheck) {
		    var getType = {};
		    return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
		  }
	
		  return tip;
		};
	
	/***/ }),
	/* 101 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_row_labels = __webpack_require__(102);
	
		module.exports = function make_row_label_container(cgm, text_delay) {
	
		  var params = cgm.params;
	
		  var row_container;
	
		  // row container holds all row text and row visualizations (triangles rects)
		  ////////////////////////////////////////////////////////////////////////////
		  if (d3.select(params.viz.viz_svg + ' .row_container').empty()) {
		    row_container = d3.select(params.viz.viz_svg).append('g').classed('row_container', true).attr('transform', 'translate(' + params.viz.norm_labels.margin.left + ',' + params.viz.clust.margin.top + ')');
		  } else {
		    row_container = d3.select(params.viz.viz_svg).select('.row_container').attr('transform', 'translate(' + params.viz.norm_labels.margin.left + ',' + params.viz.clust.margin.top + ')');
		  }
	
		  if (d3.select(params.root + ' .row_white_background').empty()) {
		    row_container.append('rect').classed('row_white_background', true).classed('white_bars', true).attr('fill', params.viz.background_color).attr('width', params.viz.label_background.row).attr('height', 30 * params.viz.clust.dim.height + 'px');
		  }
	
		  // add container to hold text row labels if not already there
		  if (d3.select(params.root + ' .row_label_container').empty()) {
		    row_container.append('g').classed('row_label_container', true).attr('transform', 'translate(' + params.viz.norm_labels.width.row + ',0)').append('g').classed('row_label_zoom_container', true);
		  } else {
		    row_container.select(params.root + ' .row_label_container').attr('transform', 'translate(' + params.viz.norm_labels.width.row + ',0)');
		  }
	
		  // make row labels in the container
		  ///////////////////////////////////////
		  if (params.viz.ds_level === -1) {
		    make_row_labels(cgm, 'all', text_delay);
		  }
			};
	
	/***/ }),
	/* 102 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
		var add_row_click_hlight = __webpack_require__(103);
		var row_reorder = __webpack_require__(104);
		var make_row_tooltips = __webpack_require__(130);
		var underscore = __webpack_require__(68);
	
		module.exports = function make_row_labels(cgm) {
		  var row_names = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'all';
		  var text_delay = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
	
	
		  // console.log('make_row_labels')
		  // console.log(row_names)
	
		  var params = cgm.params;
		  var row_nodes = [];
	
		  if (row_names === 'all') {
		    row_nodes = params.network_data.row_nodes;
		  } else {
		    _.each(params.network_data.row_nodes, function (inst_row) {
		      // if (_.contains(row_names, inst_row.name)){
		      if (underscore.contains(row_names, inst_row.name)) {
		        row_nodes.push(inst_row);
		      }
		    });
		  }
	
		  // make row labels in row_label_zoom_container, bind row_nodes data
		  var row_labels = d3.select(params.root + ' .row_label_zoom_container').selectAll('g').data(row_nodes, function (d) {
		    return d.name;
		  }).enter().append('g').classed('row_label_group', true);
	
		  var row_nodes_names = params.network_data.row_nodes_names;
		  row_labels.attr('transform', function (d) {
		    // var inst_index = d.row_index;
		    var inst_index = _.indexOf(row_nodes_names, d.name);
		    return 'translate(0,' + params.viz.y_scale(inst_index) + ')';
		  });
	
		  row_labels.on('dblclick', function (d) {
	
		    var data_attr = '__data__';
		    var row_name = this[data_attr].name;
	
		    // if (params.sim_mat){
		    //   row_reorder(cgm, this, row_name);
	
		    //   d3.selectAll(params.root+' .col_label_text')
		    //     .filter(function(d){
		    //       return d.name == row_name;}
		    //       )[0][0];
	
		    //   // this is causing buggyness may reenable
		    //   // col_reorder -> two_translate_zoom -> show_visible_area -> make_row_labels -> col_reorder
		    //   // col_reorder(cgm, col_selection, row_name);
	
		    // } else {
		    //   row_reorder(cgm, this, row_name);
		    // }
	
		    row_reorder(cgm, this, row_name);
	
		    if (params.tile_click_hlight) {
		      add_row_click_hlight(this, d.ini);
		    }
		  });
	
		  make_row_tooltips(params);
	
		  // append rectangle behind text
		  row_labels.insert('rect').style('opacity', 0);
	
		  // append row label text
		  row_labels.append('text').attr('y', params.viz.rect_height * 0.5 + params.labels.default_fs_row * 0.35).attr('text-anchor', 'end').style('font-size', params.labels.default_fs_row + 'px').text(function (d) {
		    return utils.normal_name(d);
		  }).attr('pointer-events', 'none').style('opacity', 0).style('cursor', 'default').transition().delay(text_delay).duration(text_delay).style('opacity', 1);
	
		  // change the size of the highlighting rects
		  row_labels.each(function () {
		    var bbox = d3.select(this).select('text')[0][0].getBBox();
		    d3.select(this).select('rect').attr('x', bbox.x).attr('y', 0).attr('width', bbox.width).attr('height', params.viz.y_scale.rangeBand()).style('fill', function () {
		      var inst_hl = 'yellow';
		      return inst_hl;
		    }).style('opacity', function (d) {
		      var inst_opacity = 0;
		      // highlight target genes
		      if (d.target === 1) {
		        inst_opacity = 1;
		      }
		      return inst_opacity;
		    });
		  });
	
		  // almost-deprecated row value bars
		  ///////////////////////////////
		  if (utils.has(params.network_data.row_nodes[0], 'value')) {
	
		    row_labels.append('rect').classed('row_bars', true).attr('width', function (d) {
		      var inst_value = 0;
		      inst_value = params.labels.bar_scale_row(Math.abs(d.value));
		      return inst_value;
		    }).attr('x', function (d) {
		      var inst_value = 0;
		      inst_value = -params.labels.bar_scale_row(Math.abs(d.value));
		      return inst_value;
		    }).attr('height', params.viz.y_scale.rangeBand()).attr('fill', function (d) {
		      return d.value > 0 ? params.matrix.bar_colors[0] : params.matrix.bar_colors[1];
		    }).attr('opacity', 0.4);
		  }
			};
	
	/***/ }),
	/* 103 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function (params, clicked_row, id_clicked_row) {
		  if (id_clicked_row != params.click_hlight_row) {
	
		    var rel_width_hlight = 6;
		    var opacity_hlight = 0.85;
		    var hlight_height = rel_width_hlight * params.viz.border_width.x;
	
		    d3.selectAll(params.root + ' .click_hlight').remove();
	
		    // // highlight selected row
		    // d3.selectAll(params.root+' .row_label_group')
		    //   .select('rect')
		    // d3.select(this)
		    //   .select('rect')
		    //   .style('opacity', 1);
	
		    d3.select(clicked_row).append('rect').classed('click_hlight', true).classed('row_top_hlight', true).attr('width', params.viz.svg_dim.width).attr('height', hlight_height).attr('fill', params.matrix.hlight_color).attr('opacity', opacity_hlight);
	
		    d3.select(clicked_row).append('rect').classed('click_hlight', true).classed('row_bottom_hlight', true).attr('width', params.viz.svg_dim.width).attr('height', hlight_height).attr('fill', params.matrix.hlight_color).attr('opacity', opacity_hlight).attr('transform', function () {
		      var tmp_translate_y = params.viz.y_scale.rangeBand() - hlight_height;
		      return 'translate(0,' + tmp_translate_y + ')';
		    });
		  } else {
		    d3.selectAll(params.root + ' .click_hlight').remove();
		    params.click_hlight_row = -666;
		  }
			};
	
	/***/ }),
	/* 104 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var reposition_tile_highlight = __webpack_require__(105);
		var toggle_dendro_view = __webpack_require__(106);
		var ini_zoom_info = __webpack_require__(88);
		var get_previous_zoom = __webpack_require__(129);
		var calc_downsampled_levels = __webpack_require__(79);
	
		module.exports = function row_reorder(cgm, row_selection, inst_row) {
	
		  var params = cgm.params;
		  var prev_zoom = get_previous_zoom(params);
	
		  if (prev_zoom.zoom_y === 1 && prev_zoom.zoom_x === 1) {
	
		    params.viz.inst_order.row = 'custom';
		    toggle_dendro_view(cgm, 'col');
	
		    d3.selectAll(params.root + ' .toggle_col_order .btn').classed('active', false);
	
		    params.viz.run_trans = true;
	
		    var mat = $.extend(true, {}, params.matrix.matrix);
		    var row_nodes = params.network_data.row_nodes;
		    var col_nodes = params.network_data.col_nodes;
	
		    // find the index of the row
		    var tmp_arr = [];
		    row_nodes.forEach(function (node) {
		      tmp_arr.push(node.name);
		    });
	
		    // find index
		    inst_row = _.indexOf(tmp_arr, inst_row);
	
		    // gather the values of the input genes
		    tmp_arr = [];
		    col_nodes.forEach(function (node, index) {
		      tmp_arr.push(mat[inst_row].row_data[index].value);
		    });
	
		    // sort the rows
		    var tmp_sort = d3.range(tmp_arr.length).sort(function (a, b) {
		      return tmp_arr[b] - tmp_arr[a];
		    });
	
		    // resort cols (cols are reorderd by double clicking a row)
		    params.viz.x_scale.domain(tmp_sort);
	
		    // save to custom col order
		    params.matrix.orders.custom_row = tmp_sort;
	
		    // reorder matrix
		    ////////////////////
		    var t;
		    if (params.network_data.links.length > params.matrix.def_large_matrix) {
		      t = d3.select(params.root + ' .viz_svg');
		    } else {
		      t = d3.select(params.root + ' .viz_svg').transition().duration(2500);
		    }
	
		    var col_nodes_names = params.network_data.col_nodes_names;
	
		    // Move Col Labels
		    t.select('.col_zoom_container').selectAll('.col_label_text').attr('transform', function (d) {
		      var inst_index = _.indexOf(col_nodes_names, d.name);
		      return 'translate(' + params.viz.x_scale(inst_index) + ')rotate(-90)';
		    });
	
		    // reorder col_class groups
		    t.selectAll('.col_cat_group').attr('transform', function (d) {
		      var inst_index = _.indexOf(col_nodes_names, d.name);
		      return 'translate(' + params.viz.x_scale(inst_index) + ',0)';
		    });
	
		    // reorder tiles in matrix (do not change row order)
		    if (params.viz.ds_level === -1) {
		      t.selectAll('.tile').attr('transform', function (d) {
		        return 'translate(' + params.viz.x_scale(d.pos_x) + ',0)';
		      });
	
		      t.selectAll('.tile_up').attr('transform', function (d) {
		        return 'translate(' + params.viz.x_scale(d.pos_x) + ',0)';
		      });
	
		      t.selectAll('.tile_dn').attr('transform', function (d) {
		        return 'translate(' + params.viz.x_scale(d.pos_x) + ',0)';
		      });
		    }
	
		    // highlight selected row
		    ///////////////////////////////
		    // unhilight and unbold all columns (already unbolded earlier)
		    d3.selectAll(params.root + ' .row_label_group').select('rect').style('opacity', 0);
		    // highlight column name
		    d3.select(row_selection).select('rect').style('opacity', 1);
	
		    reposition_tile_highlight(params);
	
		    // redefine x and y positions
		    params.network_data.links.forEach(function (d) {
		      d.x = params.viz.x_scale(d.target);
		      d.y = params.viz.y_scale(d.source);
		    });
	
		    params.zoom_info = ini_zoom_info();
	
		    setTimeout(function () {
		      params.viz.run_trans = false;
		    }, 2500);
	
		    // calculate downsmapling if necessary
		    if (params.viz.ds_num_levels > 0 && params.viz.ds_level >= 0) {
	
		      calc_downsampled_levels(params);
	
		      // var zooming_stopped = true;
		      // var zooming_out = true;
		      // var make_all_rows = true;
		      // // show_visible_area is also run with two_translate_zoom, but at that point
		      // // the parameters were not updated and two_translate_zoom if only run
		      // // if needed to reset zoom
		      // show_visible_area(cgm, zooming_stopped, zooming_out, make_all_rows);
		    }
		  }
			};
	
	/***/ }),
	/* 105 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function (params) {
	
		  // resize click hlight
		  var rel_width_hlight = 6;
		  // var opacity_hlight = 0.85;
	
		  var hlight_width = rel_width_hlight * params.viz.border_width.x;
		  var hlight_height = rel_width_hlight * params.viz.border_width.y;
	
		  // reposition tile highlight
		  ////////////////////////////////
		  // top highlight
		  d3.select(params.root + ' .top_hlight').attr('width', params.viz.x_scale.rangeBand()).attr('height', hlight_height).transition().duration(2500).attr('transform', function () {
		    return 'translate(' + params.viz.x_scale(params.matrix.click_hlight_x) + ',0)';
		  });
	
		  // left highlight
		  d3.select(params.root + ' .left_hlight').attr('width', hlight_width).attr('height', params.viz.y_scale.rangeBand() - hlight_height * 0.99).transition().duration(2500).attr('transform', function () {
		    return 'translate(' + params.viz.x_scale(params.matrix.click_hlight_x) + ',' + hlight_height * 0.99 + ')';
		  });
	
		  // right highlight
		  d3.select(params.root + ' .right_hlight').attr('width', hlight_width).attr('height', params.viz.y_scale.rangeBand() - hlight_height * 0.99).transition().duration(2500).attr('transform', function () {
		    var tmp_translate = params.viz.x_scale(params.matrix.click_hlight_x) + params.viz.x_scale.rangeBand() - hlight_width;
		    return 'translate(' + tmp_translate + ',' + hlight_height * 0.99 + ')';
		  });
	
		  // bottom highlight
		  d3.select(params.root + ' .bottom_hlight').attr('width', function () {
		    return params.viz.x_scale.rangeBand() - 1.98 * hlight_width;
		  }).attr('height', hlight_height).transition().duration(2500).attr('transform', function () {
		    var tmp_translate_x = params.viz.x_scale(params.matrix.click_hlight_x) + hlight_width * 0.99;
		    var tmp_translate_y = params.viz.y_scale.rangeBand() - hlight_height;
		    return 'translate(' + tmp_translate_x + ',' + tmp_translate_y + ')';
		  });
			};
	
	/***/ }),
	/* 106 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_dendro_triangles = __webpack_require__(107);
	
		module.exports = function toggle_dendro_view(cgm, inst_rc) {
		  var wait_time = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1500;
	
	
		  var params = cgm.params;
	
		  // row and col are reversed
		  if (inst_rc === 'row') {
		    if (params.viz.inst_order.col === 'clust') {
		      // the last true tells the viz that I'm chaning group size and not to
		      // delay the change in dendro
		      setTimeout(make_dendro_triangles, wait_time, cgm, 'row', true);
		    }
		  }
	
		  if (inst_rc === 'col') {
		    if (params.viz.inst_order.row === 'clust') {
		      setTimeout(make_dendro_triangles, wait_time, cgm, 'col', true);
		    }
		  }
	
		  if (params.viz.inst_order.row != 'clust' && params.viz.dendro_filter.col === false) {
		    d3.selectAll(params.root + ' .col_dendro_group').style('opacity', 0).on('mouseover', null).on('mouseout', null);
	
		    d3.select(params.root + ' .col_slider_group').style('opacity', 0);
	
		    // toggle crop buttons
		    d3.selectAll(params.root + ' .col_dendro_crop_buttons').style('opacity', 0).on('mouseover', null).on('mouseout', null);
		  }
	
		  if (params.viz.inst_order.col != 'clust' && params.viz.dendro_filter.row === false) {
	
		    d3.selectAll(params.root + ' .row_dendro_group').style('opacity', 0).on('mouseover', null).on('mouseout', null).on('click', null);
	
		    d3.select(params.root + ' .row_slider_group').style('opacity', 0);
	
		    // toggle crop buttons
		    d3.selectAll(params.root + ' .row_dendro_crop_buttons').style('opacity', 0).on('mouseover', null).on('mouseout', null);
		  }
		};
	
	/***/ }),
	/* 107 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var calc_row_dendro_triangles = __webpack_require__(108);
		var calc_col_dendro_triangles = __webpack_require__(109);
		var dendro_group_highlight = __webpack_require__(110);
		var d3_tip_custom = __webpack_require__(100);
		var make_dendro_crop_buttons = __webpack_require__(112);
		var make_cat_breakdown_graph = __webpack_require__(115);
	
		module.exports = function make_dendro_triangles(cgm, inst_rc) {
		  var is_change_group = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
	
	
		  var params = cgm.params;
	
		  // in case sim_mat
		  if (inst_rc === 'both') {
		    inst_rc = 'row';
		  }
	
		  var other_rc;
		  if (inst_rc === 'row') {
		    other_rc = 'col';
		  } else {
		    other_rc = 'row';
		  }
	
		  // orders are switched!
		  if (params.viz.inst_order[other_rc] === 'clust') {
		    d3.select(params.root + ' .' + inst_rc + '_slider_group').style('opacity', 1);
		  }
	
		  var dendro_info;
	
		  if (params.viz.show_dendrogram) {
		    if (inst_rc === 'row') {
		      dendro_info = calc_row_dendro_triangles(params);
		    } else {
		      dendro_info = calc_col_dendro_triangles(params);
		    }
	
		    if (d3.select(cgm.params.root + ' .' + inst_rc + '_dendro_crop_buttons').empty() === false) {
		      make_dendro_crop_buttons(cgm, inst_rc);
		    }
		  }
	
		  // constant dendrogram opacity
		  var inst_dendro_opacity = params.viz.dendro_opacity;
	
		  function still_hovering(inst_selection, inst_data, i) {
	
		    if (d3.select(inst_selection).classed('hovering')) {
	
		      // define where graph should be built
		      var inst_selector = params.viz.root_tips + '_' + inst_rc + '_dendro_tip';
	
		      // prevent mouseover from making multiple graphs
		      if (d3.select(inst_selector + ' .cat_graph').empty()) {
	
		        if (params.viz.cat_info[inst_rc] !== null) {
		          make_cat_breakdown_graph(params, inst_rc, inst_data, dendro_info[i], inst_selector, true);
		        }
		      }
	
		      d3.selectAll(params.viz.root_tips + '_' + inst_rc + '_dendro_tip').style('opacity', 1);
		    }
		  }
	
		  var wait_before_tooltip = 500;
	
		  // remove any old dendro tooltips from this visualization
		  d3.selectAll(cgm.params.viz.root_tips + '_' + inst_rc + '_dendro_tip').remove();
	
		  // run transition rules
		  var run_transition;
		  if (d3.selectAll(params.root + ' .' + inst_rc + '_dendro_group').empty()) {
		    run_transition = false;
		  } else {
		    run_transition = true;
		    d3.selectAll(params.root + ' .' + inst_rc + '_dendro_group').remove();
		    // d3.selectAll(params.root+' .dendro_tip').remove();
		  }
	
		  // d3-tooltip
		  var tmp_y_offset = 0;
		  var tmp_x_offset = -5;
		  var dendro_tip = d3_tip_custom().attr('class', function () {
		    // add root element to class
		    var root_tip_selector = params.viz.root_tips.replace('.', '');
		    var class_string = root_tip_selector + ' d3-tip ' + root_tip_selector + '_' + inst_rc + '_dendro_tip';
	
		    return class_string;
		  }).direction('nw').offset([tmp_y_offset, tmp_x_offset]).style('display', 'none').style('opacity', 0);
	
		  dendro_tip.html(function () {
		    var full_string = '<div class="cluster_info_container"></div>Click for cluster information <br>' + 'and additional options.';
		    return full_string;
		  });
	
		  if (is_change_group) {
		    run_transition = false;
		  }
	
		  var dendro_traps = d3.select(params.root + ' .' + inst_rc + '_dendro_container').selectAll('path').data(dendro_info, function (d) {
		    return d.name;
		  }).enter().append('path').style('opacity', 0).attr('class', inst_rc + '_dendro_group').style('fill', 'black');
	
		  // draw triangles (shown as trapezoids)
		  //////////////////////////////////////////
		  var start_x;
		  var start_y;
		  var mid_x;
		  var mid_y;
		  var final_x;
		  var final_y;
	
		  // row triangles
		  dendro_traps.attr('d', function (d) {
	
		    if (inst_rc === 'row') {
		      // row triangles
		      start_x = 0;
		      start_y = d.pos_top;
		      mid_x = 30;
		      mid_y = d.pos_mid;
		      final_x = 0;
		      final_y = d.pos_bot;
		    } else {
		      // column triangles
		      start_x = d.pos_top;
		      start_y = 0;
		      mid_x = d.pos_mid;
		      mid_y = 30;
		      final_x = d.pos_bot;
		      final_y = 0;
		    }
	
		    var output_string = 'M' + start_x + ',' + start_y + ', L' + mid_x + ', ' + mid_y + ', L' + final_x + ',' + final_y + ' Z';
		    return output_string;
		  });
	
		  dendro_traps.on('mouseover', function (d, i) {
	
		    // if (params.sim_mat){
		    //   inst_rc = 'both';
		    // }
	
		    // run instantly on mouseover
		    d3.select(this).classed('hovering', true);
	
		    if (cgm.params.dendro_callback != null) {
		      cgm.params.dendro_callback(this);
		    }
	
		    // display tip
		    // this is needed for it to show in the right place and the opacity
		    // will be toggled to delay the tooltip for the user
		    d3.select(params.viz.root_tips + '_' + inst_rc + '_dendro_tip').style('display', 'block');
	
		    dendro_group_highlight(params, this, d, inst_rc);
	
		    // show the tip (make sure it is displaying before it is shown)
		    dendro_tip.show(d);
	
		    // set opacity to zero
		    d3.select(params.viz.root_tips + '_' + inst_rc + '_dendro_tip').style('opacity', 0);
	
		    // check if still hovering
		    setTimeout(still_hovering, wait_before_tooltip, this, d, i);
		  }).on('mouseout', function () {
		    if (params.viz.inst_order[other_rc] === 'clust') {
		      d3.select(this).style('opacity', inst_dendro_opacity);
		    }
	
		    d3.selectAll(params.root + ' .dendro_shadow').remove();
	
		    d3.select(this).classed('hovering', false);
		    dendro_tip.hide(this);
		  }).on('click', function (d, i) {
	
		    $(params.root + ' .dendro_info').modal('toggle');
	
		    var group_string = d.all_names.join(', ');
		    d3.select(params.root + ' .dendro_info input').attr('value', group_string);
	
		    var inst_selector = params.root + ' .dendro_info';
	
		    // remove old graphs (modals are not within params.root)
		    d3.selectAll('.dendro_info .cluster_info_container .cat_graph').remove();
	
		    if (params.viz.cat_info[inst_rc] !== null) {
		      make_cat_breakdown_graph(params, inst_rc, d, dendro_info[i], inst_selector);
		    }
	
		    if (cgm.params.dendro_click_callback != null) {
		      cgm.params.dendro_click_callback(this);
		    }
		  }).call(dendro_tip);
	
		  var triangle_opacity;
		  if (params.viz.inst_order[other_rc] === 'clust') {
		    triangle_opacity = inst_dendro_opacity;
		  } else {
		    triangle_opacity = 0;
		  }
	
		  if (run_transition) {
	
		    d3.select(params.root + ' .' + inst_rc + '_dendro_container').selectAll('path').transition().delay(1000).duration(1000).style('opacity', triangle_opacity);
		  } else {
	
		    d3.select(params.root + ' .' + inst_rc + '_dendro_container').selectAll('path').style('opacity', triangle_opacity);
		  }
			};
	
	/***/ }),
	/* 108 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function calc_row_dendro_triangles(params) {
	
		  var triangle_info = {};
		  var inst_level = params.group_level.row;
		  var row_nodes = params.network_data.row_nodes;
		  var row_nodes_names = params.network_data.row_nodes_names;
	
		  _.each(row_nodes, function (d) {
	
		    // console.log('row_node '+d.name)
	
		    var tmp_group = d.group[inst_level];
		    var inst_index = _.indexOf(row_nodes_names, d.name);
		    var inst_top = params.viz.y_scale(inst_index);
		    var inst_bot = inst_top + params.viz.y_scale.rangeBand();
	
		    if (_.has(triangle_info, tmp_group) === false) {
		      triangle_info[tmp_group] = {};
		      triangle_info[tmp_group].name_top = d.name;
		      triangle_info[tmp_group].name_bot = d.name;
		      triangle_info[tmp_group].pos_top = inst_top;
		      triangle_info[tmp_group].pos_bot = inst_bot;
		      triangle_info[tmp_group].pos_mid = (inst_top + inst_bot) / 2;
		      triangle_info[tmp_group].name = tmp_group;
		      triangle_info[tmp_group].all_names = [];
		      triangle_info[tmp_group].inst_rc = 'row';
		    }
	
		    triangle_info[tmp_group].all_names.push(d.name);
	
		    if (inst_top < triangle_info[tmp_group].pos_top) {
		      triangle_info[tmp_group].name_top = d.name;
		      triangle_info[tmp_group].pos_top = inst_top;
		      triangle_info[tmp_group].pos_mid = (inst_top + triangle_info[tmp_group].pos_bot) / 2;
		    }
	
		    if (inst_bot > triangle_info[tmp_group].pos_bot) {
		      triangle_info[tmp_group].name_bot = d.name;
		      triangle_info[tmp_group].pos_bot = inst_bot;
		      triangle_info[tmp_group].pos_mid = (triangle_info[tmp_group].pos_top + inst_bot) / 2;
		    }
		  });
	
		  var group_info = [];
	
		  _.each(triangle_info, function (d) {
		    group_info.push(d);
		  });
	
		  return group_info;
		};
	
	/***/ }),
	/* 109 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function calc_col_dendro_triangles(params) {
	
		  var triangle_info = {};
		  var inst_level = params.group_level.col;
		  var col_nodes = params.network_data.col_nodes;
		  var col_nodes_names = params.network_data.col_nodes_names;
	
		  _.each(col_nodes, function (d) {
	
		    var tmp_group = d.group[inst_level];
		    var inst_index = _.indexOf(col_nodes_names, d.name);
		    var inst_top = params.viz.x_scale(inst_index);
		    var inst_bot = inst_top + params.viz.x_scale.rangeBand();
	
		    if (_.has(triangle_info, tmp_group) === false) {
		      triangle_info[tmp_group] = {};
		      triangle_info[tmp_group].name_top = d.name;
		      triangle_info[tmp_group].name_bot = d.name;
		      triangle_info[tmp_group].pos_top = inst_top;
		      triangle_info[tmp_group].pos_bot = inst_bot;
		      triangle_info[tmp_group].pos_mid = (inst_top + inst_bot) / 2;
		      triangle_info[tmp_group].name = tmp_group;
		      triangle_info[tmp_group].all_names = [];
		      triangle_info[tmp_group].inst_rc = 'col';
		    }
	
		    triangle_info[tmp_group].all_names.push(d.name);
	
		    if (inst_top < triangle_info[tmp_group].pos_top) {
		      triangle_info[tmp_group].name_top = d.name;
		      triangle_info[tmp_group].pos_top = inst_top;
		      triangle_info[tmp_group].pos_mid = (inst_top + triangle_info[tmp_group].pos_bot) / 2;
		    }
	
		    if (inst_bot > triangle_info[tmp_group].pos_bot) {
		      triangle_info[tmp_group].name_bot = d.name;
		      triangle_info[tmp_group].pos_bot = inst_bot;
		      triangle_info[tmp_group].pos_mid = (triangle_info[tmp_group].pos_top + inst_bot) / 2;
		    }
		  });
	
		  var group_info = [];
	
		  _.each(triangle_info, function (d) {
		    group_info.push(d);
		  });
	
		  return group_info;
			};
	
	/***/ }),
	/* 110 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var dendro_shade_bars = __webpack_require__(111);
	
		module.exports = function dendro_group_highlight(params, inst_selection, inst_data, inst_rc) {
	
		  // only make shadows if there is more than one crop button
		  if (d3.selectAll(params.root + ' .' + inst_rc + '_dendro_crop_buttons')[0].length > 1) {
		    setTimeout(still_hovering, 500);
		  } else {
		    d3.selectAll(params.root + ' .dendro_shadow').remove();
		  }
	
		  function still_hovering() {
	
		    // check that user is still hovering over dendrogram group
		    if (d3.select(inst_selection).classed('hovering')) {
	
		      // check that user is not using dendrogram slider
		      if (params.is_slider_drag === false) {
	
		        d3.select(inst_selection).style('opacity', 0.7);
	
		        if (d3.select(params.viz.viz_svg).classed('running_update') === false) {
		          make_shadow_bars();
		        }
		      }
		    }
		  }
	
		  function make_shadow_bars() {
	
		    if (inst_rc === 'row') {
	
		      // row and col labling are reversed
		      if (params.viz.inst_order.col === 'clust') {
		        dendro_shade_bars(params, inst_selection, inst_rc, inst_data);
		      }
		    } else if (inst_rc === 'col') {
	
		      // row and col labeling are reversed
		      if (params.viz.inst_order.row === 'clust') {
		        dendro_shade_bars(params, inst_selection, inst_rc, inst_data);
		      }
		    } else if (inst_rc === 'both') {
	
		      if (params.viz.inst_order.col === 'clust') {
		        dendro_shade_bars(params, inst_selection, 'row', inst_data);
		      }
		      if (params.viz.inst_order.row === 'clust') {
		        dendro_shade_bars(params, inst_selection, 'col', inst_data);
		      }
		    }
		  }
		};
	
	/***/ }),
	/* 111 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function dendro_shade_bars(params, inst_selection, inst_rc, inst_data) {
	
		  var inst_opacity = 0.2;
		  var bot_height;
	
		  d3.selectAll(params.root + ' .dendro_shadow').remove();
	
		  if (inst_rc == 'row') {
	
		    // top shade
		    d3.select(params.root + ' .clust_group').append('rect').attr('width', params.viz.clust.dim.width + 'px').attr('height', inst_data.pos_top + 'px').attr('fill', 'black').classed('dendro_shadow', true).attr('opacity', inst_opacity);
	
		    bot_height = params.viz.clust.dim.height - inst_data.pos_bot;
		    // bottom shade
		    d3.select(params.root + ' .clust_group').append('rect').attr('width', params.viz.clust.dim.width + 'px').attr('height', bot_height + 'px').attr('transform', 'translate(0,' + inst_data.pos_bot + ')').attr('fill', 'black').classed('dendro_shadow', true).attr('opacity', inst_opacity);
		  } else if (inst_rc === 'col') {
	
		    // top shade
		    d3.select(params.root + ' .clust_group').append('rect').attr('width', inst_data.pos_top + 'px').attr('height', params.viz.clust.dim.height + 'px').attr('fill', 'black').classed('dendro_shadow', true).attr('opacity', inst_opacity);
	
		    // bottom shade
		    bot_height = params.viz.clust.dim.width - inst_data.pos_bot;
		    d3.select(params.root + ' .clust_group').append('rect').attr('width', bot_height + 'px').attr('height', params.viz.clust.dim.height + 'px').attr('transform', 'translate(' + inst_data.pos_bot + ',0)').attr('fill', 'black').classed('dendro_shadow', true).attr('opacity', inst_opacity);
		  }
			};
	
	/***/ }),
	/* 112 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var calc_row_dendro_triangles = __webpack_require__(108);
		var calc_col_dendro_triangles = __webpack_require__(109);
		var d3_tip_custom = __webpack_require__(100);
		var dendro_group_highlight = __webpack_require__(110);
		var run_dendro_filter = __webpack_require__(113);
		var zoom_crop_triangles = __webpack_require__(114);
	
		module.exports = function make_dendro_crop_buttons(cgm, inst_rc) {
	
		  var params = cgm.params;
	
		  var button_opacity = params.viz.dendro_opacity * 0.60;
	
		  // information needed to make dendro
		  var dendro_info;
		  var other_rc;
		  if (inst_rc === 'row') {
		    dendro_info = calc_row_dendro_triangles(params);
		    other_rc = 'col';
		  } else {
		    dendro_info = calc_col_dendro_triangles(params);
		    other_rc = 'row';
		  }
	
		  // d3-tooltip
		  var tmp_y_offset = 5;
		  var tmp_x_offset = -5;
		  var dendro_crop_tip = d3_tip_custom().attr('class', function () {
		    var root_tip_selector = params.viz.root_tips.replace('.', '');
		    var class_string = root_tip_selector + ' d3-tip ' + root_tip_selector + '_' + inst_rc + '_dendro_crop_tip';
	
		    return class_string;
		  }).direction('nw').style('display', 'none').offset([tmp_y_offset, tmp_x_offset]);
	
		  var wait_before_tooltip = 500;
	
		  d3.selectAll(params.viz.root_tips + '_' + inst_rc + '_dendro_crop_tip').remove();
		  d3.selectAll(params.root + ' .' + inst_rc + '_dendro_crop_buttons').remove();
	
		  var icons;
		  // position triangles
		  var start_x;
		  var start_y;
		  var mid_x;
		  var mid_y;
		  var final_x;
		  var final_y;
	
		  // need to improve to account for zooming
		  var min_tri_height = 45;
		  var scale_down_tri = 0.25;
		  var tri_height;
		  var tri_width;
		  var tri_dim;
	
		  // make crop buttons or undo buttons
		  var button_class = inst_rc + '_dendro_crop_buttons';
		  if (d3.select(cgm.params.root + ' .' + inst_rc + '_dendro_icons_group').classed('ran_filter') === false) {
	
		    // Crop Triangle
		    //////////////////////////////
		    icons = d3.select(params.root + ' .' + inst_rc + '_dendro_icons_group').selectAll('path').data(dendro_info, function (d) {
		      return d.name;
		    }).enter().append('path').classed(button_class, true).attr('d', function (d) {
	
		      // redefine
		      tri_height = 10;
		      tri_width = 10;
	
		      var tmp_height = d.pos_bot - d.pos_top;
	
		      // Row Dendrogram Crop Triangle
		      if (inst_rc === 'row') {
	
		        if (tmp_height < min_tri_height) {
		          tri_height = tmp_height * scale_down_tri;
		        }
	
		        // pointing left
		        start_x = tri_width;
		        start_y = -tri_height;
		        mid_x = 0;
		        mid_y = 0;
		        final_x = tri_width;
		        final_y = tri_height;
	
		        tri_dim = tri_height;
	
		        // Column Dendrogram Crop Triangle
		      } else {
	
		        if (tmp_height < min_tri_height) {
		          tri_width = tmp_height * scale_down_tri;
		        }
	
		        // pointing upward
		        start_x = -tri_width;
		        start_y = tri_height;
		        mid_x = 0;
		        mid_y = 0;
		        final_x = tri_width;
		        final_y = tri_height;
	
		        tri_dim = tri_width;
		      }
	
		      // save triangle height
		      // d3.select(this)[0][0].__data__.tri_dim = tri_dim;
		      var data_key = '__data__';
		      d3.select(this)[0][0][data_key].tri_dim = tri_dim;
	
		      var output_string = 'M' + start_x + ',' + start_y + ', L' + mid_x + ', ' + mid_y + ', L' + final_x + ',' + final_y + ' Z';
	
		      return output_string;
		    });
	
		    dendro_crop_tip.html(function () {
		      var full_string = 'Click to crop cluster';
		      return full_string;
		    });
		  } else {
	
		    // Undo Triangle
		    //////////////////////////////
		    icons = d3.select(params.root + ' .' + inst_rc + '_dendro_icons_group').selectAll('path').data(dendro_info, function (d) {
		      return d.name;
		    }).enter().append('path').classed(button_class, true).attr('d', function (d) {
	
		      // redefine
		      tri_height = 10;
		      tri_width = 12;
	
		      var tmp_height = d.pos_bot - d.pos_top;
	
		      if (inst_rc === 'row') {
	
		        if (tmp_height < min_tri_height) {
		          tri_height = tmp_height * scale_down_tri;
		        }
	
		        // pointing right
		        start_x = 0;
		        start_y = -tri_height;
		        mid_x = tri_width;
		        mid_y = 0;
		        final_x = 0;
		        final_y = tri_height;
		      } else {
	
		        if (tmp_height < min_tri_height) {
		          tri_width = tmp_height * scale_down_tri;
		        }
	
		        // pointing downward
		        start_x = -tri_width;
		        start_y = 0;
		        mid_x = 0;
		        mid_y = tri_height;
		        final_x = tri_width;
		        final_y = 0;
		      }
	
		      // save triangle height
		      var data_key = '__data__';
		      d3.select(this)[0][0][data_key].tri_dim = 10;
	
		      var output_string = 'M' + start_x + ',' + start_y + ', L' + mid_x + ', ' + mid_y + ', L' + final_x + ',' + final_y + ' Z';
	
		      return output_string;
		    });
	
		    dendro_crop_tip.html(function () {
		      var full_string = 'Click to undo crop';
		      return full_string;
		    });
		  }
	
		  icons.style('cursor', 'pointer').style('opacity', function () {
	
		    var inst_opacity;
	
		    // if (d3.select(this).classed('hide_crop')){
		    //   inst_opacity = 0;
		    // } else {
		    //   inst_opacity = button_opacity;
		    // }
	
		    inst_opacity = button_opacity;
		    return inst_opacity;
		  }).attr('transform', function (d) {
		    var inst_translate;
	
		    var inst_x;
		    var inst_y;
	
		    if (inst_rc === 'row') {
		      inst_x = params.viz.uni_margin;
		      inst_y = d.pos_mid;
		    } else {
		      inst_x = d.pos_mid;
		      inst_y = params.viz.uni_margin;
		    }
	
		    inst_translate = 'translate(' + inst_x + ',' + inst_y + ')';
		    return inst_translate;
		  }).on('mouseover', function (d) {
	
		    d3.select(this).classed('hovering', true);
	
		    dendro_crop_tip.show(d);
	
		    dendro_group_highlight(params, this, d, inst_rc);
	
		    // display with zero opacity
		    d3.selectAll(params.viz.root_tips + '_' + inst_rc + '_dendro_crop_tip').style('opacity', 0).style('display', 'block');
	
		    // check if still hovering
		    setTimeout(still_hovering, wait_before_tooltip, this);
		  }).on('mouseout', function () {
	
		    d3.select(this).classed('hovering', false);
	
		    d3.selectAll(params.root + ' .dendro_shadow').remove();
	
		    d3.select(this).style('opacity', button_opacity);
	
		    dendro_crop_tip.hide(this);
		  }).on('click', function (d) {
	
		    // give user visual cue
		    d3.select(this).style('opacity', 0.9).transition().duration(1000).style('opacity', 0);
	
		    // remove dendro shadows when clicked
		    d3.selectAll(params.root + ' .dendro_shadow').remove();
	
		    /* filter using dendrogram */
		    if (cgm.params.dendro_filter.row === false && cgm.params.dendro_filter.col === false && cgm.params.cat_filter.row === false && cgm.params.cat_filter.col === false) {
	
		      // Run Filtering
		      ///////////////////
	
		      // use class as 'global' variable
		      d3.select(cgm.params.root + ' .' + inst_rc + '_dendro_icons_group').attr('transform', 'translate(0,0), scale(1,1)').classed('ran_filter', true);
	
		      d3.select(cgm.params.root + ' .' + other_rc + '_dendro_icons_group').attr('transform', 'translate(0,0), scale(1,1)');
	
		      // do not display dendrogram slider if filtering has been run
		      d3.select(cgm.params.root + ' .' + inst_rc + '_slider_group').style('display', 'none');
	
		      // do not display other crop buttons since they are inactive
		      d3.select(cgm.params.root + ' .' + other_rc + '_dendro_icons_container').style('display', 'none');
	
		      // do not display brush-crop button if performing dendro crop
		      d3.select(cgm.params.root + ' .crop_button').style('opacity', 0.2);
		    } else {
	
		      // Undo Filtering
		      ///////////////////
		      // use class as 'global' variable
		      d3.select(cgm.params.root + ' .' + inst_rc + '_dendro_icons_group').attr('transform', 'translate(0,0), scale(1,1)').classed('ran_filter', false);
	
		      d3.select(cgm.params.root + ' .' + other_rc + '_dendro_icons_group').attr('transform', 'translate(0,0), scale(1,1)');
	
		      if (params.viz.inst_order[other_rc] === 'clust') {
		        // display slider when cropping has not been done
		        d3.select(cgm.params.root + ' .' + inst_rc + '_slider_group').style('display', 'block');
		      }
	
		      // display other crop buttons when cropping has not been done
		      d3.select(cgm.params.root + ' .' + other_rc + '_dendro_icons_container').style('display', 'block');
	
		      // display brush-crop button if not performing dendro crop
		      d3.select(cgm.params.root + ' .crop_button').style('opacity', 1);
		    }
	
		    run_dendro_filter(cgm, d, inst_rc);
		  }).call(dendro_crop_tip);
	
		  // ordering has been reversed
		  if (params.viz.inst_order[other_rc] != 'clust') {
		    // do not display if not in cluster order
		    d3.select(params.root + ' .' + inst_rc + '_dendro_icons_group').selectAll('path').style('display', 'none');
		  }
	
		  function still_hovering(inst_selection) {
	
		    if (d3.select(inst_selection).classed('hovering')) {
		      // increase opacity
		      d3.selectAll(params.viz.root_tips + '_' + inst_rc + '_dendro_crop_tip').style('opacity', 1).style('display', 'block');
		    }
		  }
	
		  zoom_crop_triangles(params, params.zoom_info, inst_rc);
			};
	
	/***/ }),
	/* 113 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function run_dendro_filter(cgm, d, inst_rc) {
	
		  var names = {};
	
		  if (cgm.params.dendro_filter.row === false && cgm.params.dendro_filter.col === false && cgm.params.cat_filter.row === false && cgm.params.cat_filter.col === false) {
	
		    d3.select(cgm.params.root + ' .' + inst_rc + '_slider_group').style('opacity', 0.35).style('pointer-events', 'none');
	
		    names[inst_rc] = d.all_names;
	
		    var tmp_names = cgm.params.network_data[inst_rc + '_nodes_names'];
	
		    // keep a backup of the inst_view
		    var inst_row_nodes = cgm.params.network_data.row_nodes;
		    var inst_col_nodes = cgm.params.network_data.col_nodes;
	
		    cgm.filter_viz_using_names(names);
	
		    // overwrite with backup of original nodes
		    cgm.params.inst_nodes.row_nodes = inst_row_nodes;
		    cgm.params.inst_nodes.col_nodes = inst_col_nodes;
	
		    d3.selectAll(cgm.params.root + ' .dendro_shadow').transition().duration(1000).style('opacity', 0).remove();
	
		    // keep the names of all the nodes
		    cgm.params.dendro_filter[inst_rc] = tmp_names;
	
		    /* reset filter */
		  } else {
	
		    names[inst_rc] = cgm.params.dendro_filter[inst_rc];
	
		    cgm.filter_viz_using_names(names);
		    cgm.params.dendro_filter[inst_rc] = false;
		  }
			};
	
	/***/ }),
	/* 114 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function zoom_crop_triangles(params, zoom_info, inst_rc) {
	
		  if (inst_rc === 'row') {
	
		    // transform icons (undo zoom on triangles)
		    d3.select(params.root + ' .row_dendro_icons_group').selectAll('path').attr('transform', function (d) {
		      var inst_x = params.viz.uni_margin;
		      var inst_y = d.pos_mid;
		      var curr_zoom = zoom_info.zoom_y;
		      var tri_dim = d3.select(this).data()[0].tri_dim;
		      var inst_zoom = constrain_zoom(curr_zoom, tri_dim);
		      return 'translate(' + inst_x + ',' + inst_y + ') ' + 'scale(1, ' + 1 / inst_zoom + ')';
		    });
		  } else {
	
		    // transform icons (undo zoom on triangles)
		    d3.select(params.root + ' .col_dendro_icons_group').selectAll('path').attr('transform', function (d) {
		      var inst_x = d.pos_mid;
		      var inst_y = params.viz.uni_margin;
		      var curr_zoom = zoom_info.zoom_x;
		      var tri_dim = d3.select(this).data()[0].tri_dim;
		      var inst_zoom = constrain_zoom(curr_zoom, tri_dim);
		      return 'translate(' + inst_x + ',' + inst_y + ') ' + 'scale(' + 1 / inst_zoom + ', 1)';
		    });
		  }
	
		  function constrain_zoom(curr_zoom, tri_height) {
		    var inst_zoom;
		    var default_tri_height = 10;
		    if (tri_height * curr_zoom < default_tri_height) {
		      inst_zoom = 1;
		    } else {
		      var max_zoom = default_tri_height / tri_height;
		      inst_zoom = curr_zoom / max_zoom;
		    }
		    return inst_zoom;
		  }
			};
	
	/***/ }),
	/* 115 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var calc_cat_cluster_breakdown = __webpack_require__(116);
	
		module.exports = function make_cat_breakdown_graph(params, inst_rc, inst_data, dendro_info, selector) {
		  var tooltip = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
	
	
		  /*
		  This function is used to make the category breakdown graphs for tooltips on
		  dendrogram mousover and on dendrogram click modal popup.
		  */
	
		  // in case sim_mat
		  if (inst_rc === 'both') {
		    inst_rc = 'row';
		  }
	
		  var cat_breakdown = calc_cat_cluster_breakdown(params, inst_data, inst_rc);
	
		  if (cat_breakdown.length > 0) {
	
		    // put cluster information in dendro_tip
		    ///////////////////////////////////////////
		    var cluster_info_container = d3.select(selector + ' .cluster_info_container');
	
		    // loop through cat_breakdown data
		    var super_string = ': ';
		    var paragraph_string = '<p>';
		    var width = 370;
		    var bar_offset = 23;
		    var bar_height = 20;
		    var max_string_length = 25;
		    var bar_width = 180;
		    var title_height = 27;
		    var shift_tooltip_left = 177;
	
		    // these are the indexes where the number-of-nodes and the number of downsampled
		    // nodes are stored
		    var num_nodes_index = 4;
		    var num_nodes_ds_index = 5;
		    var offset_ds_count = 150;
		    var binom_pval_index = 6;
	
		    var is_downsampled = false;
		    if (cat_breakdown[0].bar_data[0][num_nodes_ds_index] != null) {
		      width = width + 100;
		      shift_tooltip_left = shift_tooltip_left + offset_ds_count - 47;
		      is_downsampled = true;
		    }
	
		    // the index that will be used to generate the bars (will be different if
		    // downsampled)
		    var cluster_total = dendro_info.all_names.length;
		    var bars_index = num_nodes_index;
		    if (is_downsampled) {
		      bars_index = num_nodes_ds_index;
	
		      // calculate the total number of nodes in downsampled case
		      var inst_bar_data = cat_breakdown[0].bar_data;
		      cluster_total = 0;
		      _.each(inst_bar_data, function (tmp_data) {
		        cluster_total = cluster_total + tmp_data[num_nodes_ds_index];
		      });
		    }
	
		    // limit on the number of category types shown
		    var max_cats = 3;
		    // limit the number of bars shown
		    var max_bars = 25;
	
		    // calculate height needed for svg based on cat_breakdown data
		    var svg_height = 20;
		    _.each(cat_breakdown.slice(0, max_cats), function (tmp_break) {
		      var num_bars = tmp_break.bar_data.length;
		      if (num_bars > max_bars) {
		        num_bars = max_bars;
		      }
		      svg_height = svg_height + title_height * (num_bars + 1);
		    });
	
		    // Cluster Information Title (for tooltip only not modal)
		    if (tooltip) {
		      cluster_info_container.append('text').text('Cluster Information');
		    }
	
		    var main_dendro_svg = cluster_info_container.append('div').style('margin-top', '5px').classed('cat_graph', true).append('svg').style('height', svg_height + 'px').style('width', width + 'px');
	
		    // make background
		    main_dendro_svg.append('rect').classed('cat_background', true).attr('height', svg_height + 'px').attr('width', width + 'px').attr('fill', 'white').attr('opacity', 1);
	
		    // the total amout to shift down the next category
		    var shift_down = title_height;
	
		    // limit the category-types
		    cat_breakdown = cat_breakdown.slice(0, max_cats);
	
		    _.each(cat_breakdown, function (cat_data) {
	
		      var max_bar_value = cat_data.bar_data[0][bars_index];
	
		      // offset the count column based on how large the counts are
		      var digit_offset_scale = d3.scale.linear().domain([0, 100000]).range([20, 30]);
	
		      // only keep the top max_bars categories
		      cat_data.bar_data = cat_data.bar_data.slice(0, max_bars);
	
		      cluster_info_container.style('margin-bottom', '5px');
	
		      var cat_graph_group = main_dendro_svg.append('g').classed('cat_graph_group', true).attr('transform', 'translate(10, ' + shift_down + ')');
	
		      // shift down based on number of bars
		      shift_down = shift_down + title_height * (cat_data.bar_data.length + 1);
	
		      var inst_title = cat_data.type_name;
		      // ensure that title is not too long
		      if (inst_title.length >= max_string_length) {
		        inst_title = inst_title.slice(0, max_string_length) + '..';
		      }
	
		      // make title
		      cat_graph_group.append('text').classed('cat_graph_title', true).text(inst_title).style('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').style('font-weight', 800);
	
		      // shift the position of the numbers based on the size of the number
		      var count_offset = digit_offset_scale(max_bar_value);
	
		      // Count Title
		      cat_graph_group.append('text').text('Count').attr('transform', function () {
		        var inst_x = bar_width + count_offset;
		        var inst_translate = 'translate(' + inst_x + ', 0)';
		        return inst_translate;
		      });
	
		      // Percentage Title
		      cat_graph_group.append('text').text('Pct').attr('transform', function () {
		        var inst_x = bar_width + count_offset + 60;
		        var inst_translate = 'translate(' + inst_x + ', 0)';
		        return inst_translate;
		      });
	
		      // Percentage Title
		      cat_graph_group.append('text').text('P-val').attr('transform', function () {
		        var inst_x = bar_width + count_offset + 115;
		        var inst_translate = 'translate(' + inst_x + ', 0)';
		        return inst_translate;
		      });
	
		      // Count Downsampled Title
		      if (is_downsampled) {
		        cat_graph_group.append('text').text('Clusters').attr('transform', function () {
		          var inst_x = bar_width + offset_ds_count;
		          var inst_translate = 'translate(' + inst_x + ', 0)';
		          return inst_translate;
		        });
		      }
	
		      var line_y = 4;
		      cat_graph_group.append('line').attr('x1', 0).attr('x2', bar_width).attr('y1', line_y).attr('y2', line_y).attr('stroke', 'blue').attr('stroke-width', 1).attr('opacity', 1.0);
	
		      var cat_bar_container = cat_graph_group.append('g').classed('cat_bar_container', true).attr('transform', 'translate(0, 10)');
	
		      // make bar groups (hold bar and text)
		      var cat_bar_groups = cat_bar_container.selectAll('g').data(cat_data.bar_data).enter().append('g').attr('transform', function (d, i) {
		        var inst_y = i * bar_offset;
		        return 'translate(0,' + inst_y + ')';
		      });
	
		      // bar length is max when all nodes in cluster are of
		      // a single cat
		      var bar_scale = d3.scale.linear().domain([0, max_bar_value]).range([0, bar_width]);
	
		      // make bars
		      cat_bar_groups.append('rect').attr('height', bar_height + 'px').attr('width', function (d) {
		        var inst_width = bar_scale(d[bars_index]);
		        return inst_width + 'px';
		      }).attr('fill', function (d) {
		        // cat color is stored in the third element
		        return d[3];
		      }).attr('opacity', params.viz.cat_colors.opacity).attr('stroke', 'grey').attr('stroke-width', '0.5px');
	
		      // make bar labels
		      cat_bar_groups.append('text').classed('bar_labels', true).text(function (d) {
		        var inst_text = d[1];
		        if (inst_text.indexOf(super_string) > 0) {
		          inst_text = inst_text.split(super_string)[1];
		        }
		        if (inst_text.indexOf(paragraph_string) > 0) {
		          // required for Enrichr category names (needs improvements)
		          inst_text = inst_text.split(paragraph_string)[0];
		        }
		        // ensure that bar name is not too long
		        if (inst_text.length >= max_string_length) {
		          inst_text = inst_text.slice(0, max_string_length) + '..';
		        }
		        return inst_text;
		      }).attr('transform', function () {
		        return 'translate(5, ' + 0.75 * bar_height + ')';
		      }).attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').attr('font-weight', 400).attr('text-anchor', 'right');
	
		      // Count/Pct Rows
		      /////////////////////////////
		      var shift_count_num = 35;
	
		      cat_bar_groups.append('text').classed('count_labels', true).text(function (d) {
		        var inst_count = d[bars_index];
		        inst_count = inst_count.toLocaleString();
		        return String(inst_count);
		      }).attr('transform', function () {
		        var inst_x = bar_width + count_offset + shift_count_num;
		        var inst_y = 0.75 * bar_height;
		        return 'translate(' + inst_x + ', ' + inst_y + ')';
		      }).attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').attr('font-weight', 400).attr('text-anchor', 'end');
	
		      cat_bar_groups.append('text').classed('count_labels', true).text(function (d) {
		        // calculate the percentage relative to the current cluster
		        var inst_count = d[bars_index] / cluster_total * 100;
		        inst_count = Math.round(inst_count * 10) / 10;
		        inst_count = inst_count.toLocaleString();
		        return String(inst_count);
		      }).attr('transform', function () {
		        var inst_x = bar_width + count_offset + shift_count_num + 47;
		        var inst_y = 0.75 * bar_height;
		        return 'translate(' + inst_x + ', ' + inst_y + ')';
		      }).attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').attr('font-weight', 400).attr('text-anchor', 'end');
	
		      // Binomial Test Pvals
		      cat_bar_groups.append('text').classed('count_labels', true).text(function (d) {
		        // calculate the percentage relative to the current cluster
		        var inst_count = d[binom_pval_index];
	
		        if (inst_count < 0.001) {
		          inst_count = parseFloat(inst_count.toPrecision(3));
		          inst_count = inst_count.toExponential();
		        } else {
		          inst_count = parseFloat(inst_count.toPrecision(2));
		        }
	
		        // inst_count = inst_count.toLocaleString();
		        return inst_count;
		      }).attr('transform', function () {
		        var inst_x = bar_width + count_offset + shift_count_num + 112;
		        var inst_y = 0.75 * bar_height;
		        return 'translate(' + inst_x + ', ' + inst_y + ')';
		      }).attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').attr('font-weight', 400).attr('text-anchor', 'end');
	
		      if (is_downsampled) {
		        cat_bar_groups.append('text').classed('count_labels', true).text(function (d) {
		          return String(d[num_nodes_index].toLocaleString());
		        }).attr('transform', function () {
		          // downsampled cluster numbers are smaller and need less flexible offsetting
		          var inst_x = bar_width + shift_count_num + offset_ds_count + 20;
		          var inst_y = 0.75 * bar_height;
		          return 'translate(' + inst_x + ', ' + inst_y + ')';
		        }).attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').attr('font-weight', 400).attr('text-anchor', 'end');
		      }
		    });
	
		    // reposition tooltip
		    /////////////////////////////////////////////////
		    if (tooltip) {
	
		      var dendro_tip = d3.select(selector);
		      var old_top = dendro_tip.style('top').split('.px')[0];
		      var old_left = dendro_tip.style('left').split('.px')[0];
		      var shift_top = 0;
		      var shift_left = 0;
	
		      // shifting
		      if (inst_rc === 'row') {
	
		        // rows
		        //////////////
		        shift_top = 0;
		        shift_left = shift_tooltip_left;
	
		        // // prevent graph from being too high
		        // if (dendro_info.pos_top < svg_height){
		        //   // do not shift position of category breakdown graph
		        //   // shift_top = -(svg_height + (dendro_info.pos_mid - dendro_info.pos_top)/2) ;
		        // }
		      } else {
	
		        // columns
		        //////////////
		        shift_top = svg_height + 32;
		        shift_left = 30;
		      }
	
		      dendro_tip.style('top', function () {
		        var new_top = String(parseInt(old_top, 10) - shift_top) + 'px';
		        return new_top;
		      }).style('left', function () {
		        var new_left = String(parseInt(old_left, 10) - shift_left) + 'px';
		        return new_left;
		      });
		    }
		  }
			};
	
	/***/ }),
	/* 116 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var binom_test = __webpack_require__(117);
	
		module.exports = function calc_cat_cluster_breakdown(params, inst_data, inst_rc) {
		  // Category-breakdown of dendrogram-clusters
		  /////////////////////////////////////////////
		  /*
		  1. get information for nodes in cluster
		  2. find category-types that are string-type
		  3. count instances of each category name for each category-type
		  */
	
		  // in case sim_mat
		  if (inst_rc === 'both') {
		    inst_rc = 'row';
		  }
	
		  // 1: get information for nodes in cluster
		  ///////////////////////////////////////////
	
		  // names of nodes in cluster
		  var clust_names = inst_data.all_names;
		  // array of nodes in the cluster
		  var clust_nodes = [];
		  var all_nodes = params.network_data[inst_rc + '_nodes'];
		  var num_in_clust_index = null;
		  var is_downsampled = false;
	
		  var inst_name;
		  _.each(all_nodes, function (inst_node) {
	
		    inst_name = inst_node.name;
	
		    if (clust_names.indexOf(inst_name) >= 0) {
		      clust_nodes.push(inst_node);
		    }
		  });
	
		  // 2: find category-types that are string-type
		  ///////////////////////////////////////////////
	
		  var cat_breakdown = [];
	
		  if (params.viz.cat_info[inst_rc] !== null) {
	
		    var inst_cat_info = params.viz.cat_info[inst_rc];
	
		    // tmp list of all categories
		    var tmp_types_index = _.keys(inst_cat_info);
		    // this will hold the indexes of string-type categories
		    var cat_types_index = [];
	
		    // get category names (only include string-type categories)
		    var cat_types_names = [];
		    var type_name;
		    var inst_index;
		    var cat_index;
		    for (var i = 0; i < tmp_types_index.length; i++) {
	
		      cat_index = 'cat-' + String(i);
	
		      if (params.viz.cat_info[inst_rc][cat_index].type === 'cat_strings') {
		        type_name = params.viz.cat_names[inst_rc][cat_index];
		        cat_types_names.push(type_name);
		        cat_types_index.push(cat_index);
		      } else {
	
		        // save number in clust category index if found
		        if (params.viz.cat_names[inst_rc][cat_index] === 'number in clust') {
		          num_in_clust_index = cat_index;
		          is_downsampled = true;
		        }
		      }
		    }
	
		    var tmp_run_count = {};
		    var inst_breakdown = {};
		    var bar_data;
		    var radix_param = 10;
	
		    // sort by actual counts (rather than cluster counts)
		    var sorting_index = 4;
		    if (is_downsampled) {
		      sorting_index = 5;
		    }
	
		    var no_title_given;
		    if (type_name === cat_index) {
		      no_title_given = true;
		    } else {
		      no_title_given = false;
		    }
	
		    if (cat_types_names.length > 0) {
	
		      // 3: count instances of each category name for each category-type
		      var cat_name;
		      var num_in_clust = clust_names.length;
	
		      // use the cat_hist to get the number of instances of this category in
		      // all rows/cols
		      // params
	
		      _.each(cat_types_index, function (cat_index) {
	
		        inst_index = cat_index.split('-')[1];
		        type_name = cat_types_names[inst_index];
	
		        if (no_title_given) {
		          if (cat_index.indexOf('-') >= 0) {
		            var tmp_num = parseInt(cat_index.split('-')[1], radix_param) + 1;
		            type_name = 'Category ' + String(tmp_num);
		          } else {
		            // backup behavior
		            type_name = 'Category';
		          }
		        }
	
		        tmp_run_count[type_name] = {};
	
		        // loop through the nodes and keep a running count of categories
		        _.each(clust_nodes, function (tmp_node) {
	
		          cat_name = tmp_node[cat_index];
	
		          if (cat_name.indexOf(': ') >= 0) {
		            cat_name = cat_name.split(': ')[1];
		          }
	
		          if (cat_name in tmp_run_count[type_name]) {
		            tmp_run_count[type_name][cat_name].num_nodes = tmp_run_count[type_name][cat_name].num_nodes + 1;
	
		            if (num_in_clust_index != null) {
		              tmp_run_count[type_name][cat_name].num_nodes_ds = tmp_run_count[type_name][cat_name].num_nodes_ds + parseInt(tmp_node[num_in_clust_index].split(': ')[1], radix_param);
		            }
		          } else {
	
		            tmp_run_count[type_name][cat_name] = {};
		            tmp_run_count[type_name][cat_name].num_nodes = 1;
		            if (num_in_clust_index != null) {
		              tmp_run_count[type_name][cat_name].num_nodes_ds = parseInt(tmp_node[num_in_clust_index].split(': ')[1], radix_param);
		            }
		          }
		        });
	
		        inst_breakdown = {};
		        inst_breakdown.type_name = type_name;
		        inst_breakdown.num_in_clust = num_in_clust;
	
		        // sort cat info in cat_breakdown
		        bar_data = [];
		        var bar_color;
		        var cat_title_and_name;
		        var inst_run_count = tmp_run_count[type_name];
	
		        for (var inst_cat in inst_run_count) {
	
		          var tot_num_cat = params.viz.cat_info[inst_rc][cat_index].cat_hist[inst_cat];
		          var total_nodes = params.network_data[inst_rc + '_nodes'].length;
		          var expect_prob = tot_num_cat / total_nodes;
	
		          // if no cat-title given
		          if (no_title_given) {
		            cat_title_and_name = inst_cat;
		          } else {
		            cat_title_and_name = type_name + ': ' + inst_cat;
		          }
	
		          // num_nodes: number of cat-nodes drawn in cluster
		          var num_nodes = inst_run_count[inst_cat].num_nodes;
	
		          var actual_k = num_nodes;
		          var pval = binom_test(actual_k, num_in_clust, expect_prob);
	
		          // working on tracking the 'real' number of nodes, which is only different
		          // if downsampling has been done
		          if (_.has(inst_run_count[inst_cat], 'num_nodes_ds')) {
		            var num_nodes_ds = inst_run_count[inst_cat].num_nodes_ds;
		          } else {
		            num_nodes_ds = null;
		          }
	
		          bar_color = params.viz.cat_colors[inst_rc][cat_index][cat_title_and_name];
	
		          bar_data.push([cat_index, cat_title_and_name, inst_run_count[inst_cat], bar_color, num_nodes, num_nodes_ds, pval]);
		        }
	
		        bar_data.sort(function (a, b) {
		          return b[sorting_index] - a[sorting_index];
		        });
	
		        inst_breakdown.bar_data = bar_data;
	
		        cat_breakdown.push(inst_breakdown);
		      });
		    }
		  }
	
		  return cat_breakdown;
		};
	
	/***/ }),
	/* 117 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		// Load the math.js core
		// Create a new, empty math.js instance
		// It will only contain methods `import` and `config`
		// math.import(require('mathjs/lib/type/fraction'));
		var p_dict = __webpack_require__(118);
		var core = __webpack_require__(12);
		var math = core.create();
	
		math.import(__webpack_require__(119));
	
		module.exports = function binom_test(actual_k, n, p) {
	
		  var fact = math.factorial;
		  var pval;
	
		  function binom_dist(k, n, p) {
		    var bin_coeff = fact(n) / (fact(k) * fact(n - k));
		    p = bin_coeff * (Math.pow(p, k) * Math.pow(1 - p, n - k));
		    return p;
		  }
	
		  function my_binom_test_2(actual_k, n, p) {
		    var cp = 0;
		    var k;
		    var dp;
		    for (var inst_k = actual_k; inst_k < n + 1; inst_k++) {
		      k = inst_k;
		      dp = binom_dist(k, n, p);
		      cp = cp + dp;
		    }
	
		    return cp;
		  }
	
		  // look up p-value from z-score using table
		  function binom_prop_table(actual_k, n, p) {
	
		    // expected average number of successes
		    var mu = n * p;
	
		    // standard deviation
		    var sigma = Math.sqrt(n * p * (1 - p));
	
		    // how many standard deviations is the actual_k away
		    // from the expected value
		    var z = (actual_k - mu) / sigma;
	
		    var z_vals = p_dict.z;
		    var p_vals = p_dict.p;
	
		    var found_index = -1;
		    var found = false;
	
		    for (var index = 0; index < z_vals.length; index++) {
		      var inst_z = z_vals[index];
	
		      // increasing inst_z until z is less than inst_z
		      if (z < inst_z && found === false) {
		        found_index = index;
		        found = true;
		      }
		    }
	
		    // give it the smallest p-val if the z-score was larger than
		    // any in the table
		    if (found_index === -1) {
		      found_index = z_vals.length - 1;
		    }
		    pval = p_vals[found_index];
	
		    return pval;
		  }
	
		  // calculate pval
		  pval = my_binom_test_2(actual_k, n, p);
		  if (isNaN(pval)) {
		    pval = binom_prop_table(actual_k, n, p);
		  }
	
		  return pval;
			};
	
	/***/ }),
	/* 118 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = {
		  "p": [0.5, 0.48006119416162751, 0.46017216272297101, 0.4403823076297575, 0.42074029056089696, 0.4012936743170763, 0.38208857781104733, 0.3631693488243809, 0.34457825838967582, 0.32635522028791997, 0.30853753872598688, 0.29115968678834636, 0.27425311775007355, 0.25784611080586473, 0.24196365222307303, 0.22662735237686821, 0.21185539858339669, 0.19766254312269238, 0.18406012534675947, 0.17105612630848183, 0.15865525393145707, 0.14685905637589591, 0.13566606094638267, 0.12507193563715024, 0.11506967022170828, 0.10564977366685535, 0.096800484585610358, 0.088507991437401956, 0.080756659233771066, 0.073529259609648304, 0.066807201268858071, 0.060570758002059008, 0.054799291699557974, 0.049471468033648075, 0.044565462758543006, 0.040059156863817086, 0.035930319112925789, 0.032156774795613713, 0.028716559816001783, 0.025588059521638611, 0.022750131948179195, 0.020182215405704383, 0.017864420562816542, 0.015777607391090499, 0.013903447513498595, 0.012224472655044696, 0.010724110021675795, 0.0093867055348385662, 0.0081975359245961138, 0.0071428107352714152, 0.0062096653257761323, 0.0053861459540666843, 0.0046611880237187467, 0.0040245885427583027, 0.0034669738030406647, 0.0029797632350545551, 0.002555130330427929, 0.0021859614549132405, 0.0018658133003840339, 0.0015888696473648667, 0.0013498980316300933, 0.0011442068310226977, 0.00096760321321835631, 0.00081635231282856037, 0.00068713793791584708, 0.00057702504239076592, 0.00048342414238377663, 0.0004040578018640207, 0.00033692926567687988, 0.00028029327681617744, 0.00023262907903552502, 0.00019261557563563279, 0.00015910859015753364, 0.00013112015442048433, 0.00010779973347738823, 8.8417285200803773e-05, 7.2348043925119787e-05, 5.9058912418922374e-05, 4.8096344017602614e-05, 3.9075596597787456e-05, 3.1671241833119863e-05, 2.5608816474041489e-05, 2.0657506912546683e-05, 1.6623763729652213e-05, 1.334574901590631e-05, 1.0688525774934402e-05, 8.5399054709917942e-06, 6.8068765993340312e-06, 5.4125439077038407e-06, 4.293514469971858e-06, 3.3976731247300535e-06, 2.6822957796388472e-06, 2.1124547025028419e-06, 1.6596751443714555e-06, 1.3008074539172771e-06, 1.0170832425687032e-06, 7.9332815197558919e-07, 6.1730737200919249e-07, 4.7918327659031855e-07, 3.7106740796333271e-07, 2.8665157187919333e-07, 2.2090503226954194e-07, 1.6982674071475937e-07, 1.3024322953320117e-07, 9.9644263169334701e-08, 7.6049605164887e-08, 5.7901340399645569e-08, 4.3977115940058689e-08, 3.3320448485428448e-08, 2.518491005446105e-08, 1.8989562465887681e-08, 1.4283479893922661e-08, 1.0717590258310852e-08, 8.0223918506634739e-09, 5.9903714010635304e-09, 4.4621724539016108e-09, 3.3157459783261365e-09, 2.4578650618080152e-09, 1.8175078630994235e-09, 1.3407124440918662e-09, 9.8658764503769458e-10, 7.2422917051376055e-10, 5.303423262948808e-10, 3.8741473466756636e-10, 2.8231580370432682e-10, 2.0522634252189396e-10, 1.4882282217622966e-10, 1.0765746385121517e-10, 7.7688475817097756e-11, 5.592507575942645e-11, 4.0160005838590881e-11, 2.8768541736043109e-11, 2.055788909399508e-11, 1.4654650977302715e-11, 1.0420976987965154e-11, 7.3922577780177942e-12, 5.2309575441445253e-12, 3.6924994272355614e-12, 2.600126965638173e-12, 1.8264310619769611e-12, 1.279812543885835e-12, 8.9458895587698439e-13, 6.23784446333152e-13, 4.3388950271780343e-13, 3.0106279811174218e-13, 2.0838581586720548e-13, 1.4388386381575764e-13, 9.9103427495475088e-14, 6.8092248906200155e-14, 4.6670115887190274e-14, 3.1908916729108844e-14, 2.1762912097085575e-14, 1.4806537490047908e-14, 1.0048965656526223e-14, 6.8033115407739012e-15, 4.5946274357785623e-15, 3.095358771958668e-15, 2.0801863521393674e-15, 1.394517146659261e-15, 9.3255757716812045e-16, 6.2209605742717405e-16, 4.1397018162731219e-16, 2.7479593923982212e-16, 1.8196213635266084e-16, 1.2019351542735647e-16, 7.9197263146424757e-17, 5.2055697448902465e-17, 3.4131483264581459e-17, 2.232393197288031e-17, 1.456514112590909e-17, 9.4795348222032499e-18, 6.1544255908503949e-18, 3.985804962848151e-18, 2.5749715380118873e-18, 1.6594208699647519e-18, 1.0667637375474856e-18, 6.840807685935497e-19, 4.3759647993090167e-19, 2.7923343749396233e-19, 1.7774117841455144e-19, 1.1285884059538324e-19, 7.1484170112696837e-20, 4.516591491435403e-20, 2.8466774084602088e-20, 1.7897488120140146e-20, 1.1224633591327901e-20, 7.0222842404415411e-21, 4.3823862990664603e-21, 2.7281535713460872e-21, 1.6941535024881097e-21, 1.0494515075362604e-21, 6.4848144530772079e-22, 3.9972212057261192e-22, 2.4577864834723153e-22, 1.5074931688101589e-22, 9.2234135249393526e-23, 5.6292823113765143e-23, 3.4271987941135974e-23, 2.0813752194932085e-23, 1.2609160670206559e-23],
		  "z": [0.0, 0.050000000000000003, 0.10000000000000001, 0.15000000000000002, 0.20000000000000001, 0.25, 0.30000000000000004, 0.35000000000000003, 0.40000000000000002, 0.45000000000000001, 0.5, 0.55000000000000004, 0.60000000000000009, 0.65000000000000002, 0.70000000000000007, 0.75, 0.80000000000000004, 0.85000000000000009, 0.90000000000000002, 0.95000000000000007, 1.0, 1.05, 1.1000000000000001, 1.1500000000000001, 1.2000000000000002, 1.25, 1.3, 1.3500000000000001, 1.4000000000000001, 1.4500000000000002, 1.5, 1.55, 1.6000000000000001, 1.6500000000000001, 1.7000000000000002, 1.75, 1.8, 1.8500000000000001, 1.9000000000000001, 1.9500000000000002, 2.0, 2.0500000000000003, 2.1000000000000001, 2.1499999999999999, 2.2000000000000002, 2.25, 2.3000000000000003, 2.3500000000000001, 2.4000000000000004, 2.4500000000000002, 2.5, 2.5500000000000003, 2.6000000000000001, 2.6500000000000004, 2.7000000000000002, 2.75, 2.8000000000000003, 2.8500000000000001, 2.9000000000000004, 2.9500000000000002, 3.0, 3.0500000000000003, 3.1000000000000001, 3.1500000000000004, 3.2000000000000002, 3.25, 3.3000000000000003, 3.3500000000000001, 3.4000000000000004, 3.4500000000000002, 3.5, 3.5500000000000003, 3.6000000000000001, 3.6500000000000004, 3.7000000000000002, 3.75, 3.8000000000000003, 3.8500000000000001, 3.9000000000000004, 3.9500000000000002, 4.0, 4.0499999999999998, 4.1000000000000005, 4.1500000000000004, 4.2000000000000002, 4.25, 4.2999999999999998, 4.3500000000000005, 4.4000000000000004, 4.4500000000000002, 4.5, 4.5499999999999998, 4.6000000000000005, 4.6500000000000004, 4.7000000000000002, 4.75, 4.8000000000000007, 4.8500000000000005, 4.9000000000000004, 4.9500000000000002, 5.0, 5.0500000000000007, 5.1000000000000005, 5.1500000000000004, 5.2000000000000002, 5.25, 5.3000000000000007, 5.3500000000000005, 5.4000000000000004, 5.4500000000000002, 5.5, 5.5500000000000007, 5.6000000000000005, 5.6500000000000004, 5.7000000000000002, 5.75, 5.8000000000000007, 5.8500000000000005, 5.9000000000000004, 5.9500000000000002, 6.0, 6.0500000000000007, 6.1000000000000005, 6.1500000000000004, 6.2000000000000002, 6.25, 6.3000000000000007, 6.3500000000000005, 6.4000000000000004, 6.4500000000000002, 6.5, 6.5500000000000007, 6.6000000000000005, 6.6500000000000004, 6.7000000000000002, 6.75, 6.8000000000000007, 6.8500000000000005, 6.9000000000000004, 6.9500000000000002, 7.0, 7.0500000000000007, 7.1000000000000005, 7.1500000000000004, 7.2000000000000002, 7.25, 7.3000000000000007, 7.3500000000000005, 7.4000000000000004, 7.4500000000000002, 7.5, 7.5500000000000007, 7.6000000000000005, 7.6500000000000004, 7.7000000000000002, 7.75, 7.8000000000000007, 7.8500000000000005, 7.9000000000000004, 7.9500000000000002, 8.0, 8.0500000000000007, 8.0999999999999996, 8.1500000000000004, 8.2000000000000011, 8.25, 8.3000000000000007, 8.3499999999999996, 8.4000000000000004, 8.4500000000000011, 8.5, 8.5500000000000007, 8.5999999999999996, 8.6500000000000004, 8.7000000000000011, 8.75, 8.8000000000000007, 8.8499999999999996, 8.9000000000000004, 8.9500000000000011, 9.0, 9.0500000000000007, 9.0999999999999996, 9.1500000000000004, 9.2000000000000011, 9.25, 9.3000000000000007, 9.3499999999999996, 9.4000000000000004, 9.4500000000000011, 9.5, 9.5500000000000007, 9.6000000000000014, 9.6500000000000004, 9.7000000000000011, 9.75, 9.8000000000000007, 9.8500000000000014, 9.9000000000000004, 9.9500000000000011]
			};
	
	/***/ }),
	/* 119 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var deepMap = __webpack_require__(120);
	
		function factory(type, config, load, typed) {
		  var gamma = load(__webpack_require__(121));
		  var latex = __webpack_require__(45);
	
		  /**
		   * Compute the factorial of a value
		   *
		   * Factorial only supports an integer value as argument.
		   * For matrices, the function is evaluated element wise.
		   *
		   * Syntax:
		   *
		   *    math.factorial(n)
		   *
		   * Examples:
		   *
		   *    math.factorial(5);    // returns 120
		   *    math.factorial(3);    // returns 6
		   *
		   * See also:
		   *
		   *    combinations, gamma, permutations
		   *
		   * @param {number | BigNumber | Array | Matrix} n   An integer number
		   * @return {number | BigNumber | Array | Matrix}    The factorial of `n`
		   */
		  var factorial = typed('factorial', {
		    'number': function number(n) {
		      if (n < 0) {
		        throw new Error('Value must be non-negative');
		      }
	
		      return gamma(n + 1);
		    },
	
		    'BigNumber': function BigNumber(n) {
		      if (n.isNegative()) {
		        throw new Error('Value must be non-negative');
		      }
	
		      return gamma(n.plus(1));
		    },
	
		    'Array | Matrix': function ArrayMatrix(n) {
		      return deepMap(n, factorial);
		    }
		  });
	
		  factorial.toTex = {
		    1: '\\left(${args[0]}\\right)' + latex.operators['factorial']
		  };
	
		  return factorial;
		}
	
		exports.name = 'factorial';
		exports.factory = factory;
	
	/***/ }),
	/* 120 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Execute the callback function element wise for each element in array and any
		 * nested array
		 * Returns an array with the results
		 * @param {Array | Matrix} array
		 * @param {Function} callback   The callback is called with two parameters:
		 *                              value1 and value2, which contain the current
		 *                              element of both arrays.
		 * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
		 *
		 * @return {Array | Matrix} res
		 */
	
		module.exports = function deepMap(array, callback, skipZeros) {
		  if (array && typeof array.map === 'function') {
		    // TODO: replace array.map with a for loop to improve performance
		    return array.map(function (x) {
		      return deepMap(x, callback, skipZeros);
		    });
		  } else {
		    return callback(array);
		  }
		};
	
	/***/ }),
	/* 121 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var deepMap = __webpack_require__(120);
		var isInteger = __webpack_require__(18).isInteger;
	
		function factory(type, config, load, typed) {
		  var multiply = load(__webpack_require__(122));
		  var pow = load(__webpack_require__(125));
	
		  /**
		   * Compute the gamma function of a value using Lanczos approximation for
		   * small values, and an extended Stirling approximation for large values.
		   *
		   * For matrices, the function is evaluated element wise.
		   *
		   * Syntax:
		   *
		   *    math.gamma(n)
		   *
		   * Examples:
		   *
		   *    math.gamma(5);       // returns 24
		   *    math.gamma(-0.5);    // returns -3.5449077018110335
		   *    math.gamma(math.i);  // returns -0.15494982830180973 - 0.49801566811835596i
		   *
		   * See also:
		   *
		   *    combinations, factorial, permutations
		   *
		   * @param {number | Array | Matrix} n   A real or complex number
		   * @return {number | Array | Matrix}    The gamma of `n`
		   */
		  var gamma = typed('gamma', {
		    'number': function number(n) {
		      var t, x;
	
		      if (isInteger(n)) {
		        if (n <= 0) {
		          return isFinite(n) ? Infinity : NaN;
		        }
	
		        if (n > 171) {
		          return Infinity; // Will overflow
		        }
	
		        var value = n - 2;
		        var res = n - 1;
		        while (value > 1) {
		          res *= value;
		          value--;
		        }
	
		        if (res == 0) {
		          res = 1; // 0! is per definition 1
		        }
	
		        return res;
		      }
	
		      if (n < 0.5) {
		        return Math.PI / (Math.sin(Math.PI * n) * gamma(1 - n));
		      }
	
		      if (n >= 171.35) {
		        return Infinity; // will overflow
		      }
	
		      if (n > 85.0) {
		        // Extended Stirling Approx
		        var twoN = n * n;
		        var threeN = twoN * n;
		        var fourN = threeN * n;
		        var fiveN = fourN * n;
		        return Math.sqrt(2 * Math.PI / n) * Math.pow(n / Math.E, n) * (1 + 1 / (12 * n) + 1 / (288 * twoN) - 139 / (51840 * threeN) - 571 / (2488320 * fourN) + 163879 / (209018880 * fiveN) + 5246819 / (75246796800 * fiveN * n));
		      }
	
		      --n;
		      x = p[0];
		      for (var i = 1; i < p.length; ++i) {
		        x += p[i] / (n + i);
		      }
	
		      t = n + g + 0.5;
		      return Math.sqrt(2 * Math.PI) * Math.pow(t, n + 0.5) * Math.exp(-t) * x;
		    },
	
		    'Complex': function Complex(n) {
		      var t, x;
	
		      if (n.im == 0) {
		        return gamma(n.re);
		      }
	
		      n = new type.Complex(n.re - 1, n.im);
		      x = new type.Complex(p[0], 0);
		      for (var i = 1; i < p.length; ++i) {
		        var real = n.re + i; // x += p[i]/(n+i)
		        var den = real * real + n.im * n.im;
		        if (den != 0) {
		          x.re += p[i] * real / den;
		          x.im += -(p[i] * n.im) / den;
		        } else {
		          x.re = p[i] < 0 ? -Infinity : Infinity;
		        }
		      }
	
		      t = new type.Complex(n.re + g + 0.5, n.im);
		      var twoPiSqrt = Math.sqrt(2 * Math.PI);
	
		      n.re += 0.5;
		      var result = pow(t, n);
		      if (result.im == 0) {
		        // sqrt(2*PI)*result
		        result.re *= twoPiSqrt;
		      } else if (result.re == 0) {
		        result.im *= twoPiSqrt;
		      } else {
		        result.re *= twoPiSqrt;
		        result.im *= twoPiSqrt;
		      }
	
		      var r = Math.exp(-t.re); // exp(-t)
		      t.re = r * Math.cos(-t.im);
		      t.im = r * Math.sin(-t.im);
	
		      return multiply(multiply(result, t), x);
		    },
	
		    'BigNumber': function BigNumber(n) {
		      if (n.isInteger()) {
		        return n.isNegative() || n.isZero() ? new type.BigNumber(Infinity) : bigFactorial(n.minus(1));
		      }
	
		      if (!n.isFinite()) {
		        return new type.BigNumber(n.isNegative() ? NaN : Infinity);
		      }
	
		      throw new Error('Integer BigNumber expected');
		    },
	
		    'Array | Matrix': function ArrayMatrix(n) {
		      return deepMap(n, gamma);
		    }
		  });
	
		  /**
		   * Calculate factorial for a BigNumber
		   * @param {BigNumber} n
		   * @returns {BigNumber} Returns the factorial of n
		   */
		  function bigFactorial(n) {
		    if (n.isZero()) {
		      return new type.BigNumber(1); // 0! is per definition 1
		    }
	
		    var precision = config.precision + (Math.log(n.toNumber()) | 0);
		    var Big = type.BigNumber.clone({ precision: precision });
	
		    var res = new Big(n);
		    var value = n.toNumber() - 1; // number
		    while (value > 1) {
		      res = res.times(value);
		      value--;
		    }
	
		    return new type.BigNumber(res.toPrecision(type.BigNumber.precision));
		  }
	
		  gamma.toTex = { 1: '\\Gamma\\left(${args[0]}\\right)' };
	
		  return gamma;
		}
	
		// TODO: comment on the variables g and p
	
		var g = 4.7421875;
	
		var p = [0.99999999999999709182, 57.156235665862923517, -59.597960355475491248, 14.136097974741747174, -0.49191381609762019978, 0.33994649984811888699e-4, 0.46523628927048575665e-4, -0.98374475304879564677e-4, 0.15808870322491248884e-3, -0.21026444172410488319e-3, 0.21743961811521264320e-3, -0.16431810653676389022e-3, 0.84418223983852743293e-4, -0.26190838401581408670e-4, 0.36899182659531622704e-5];
	
		exports.name = 'gamma';
		exports.factory = factory;
	
	/***/ }),
	/* 122 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var extend = __webpack_require__(14).extend;
		var array = __webpack_require__(28);
	
		function factory(type, config, load, typed) {
		  var latex = __webpack_require__(45);
	
		  var matrix = load(__webpack_require__(43));
		  var addScalar = load(__webpack_require__(44));
		  var multiplyScalar = load(__webpack_require__(123));
		  var equalScalar = load(__webpack_require__(39));
	
		  var algorithm11 = load(__webpack_require__(124));
		  var algorithm14 = load(__webpack_require__(50));
	
		  var DenseMatrix = type.DenseMatrix;
		  var SparseMatrix = type.SparseMatrix;
	
		  /**
		   * Multiply two or more values, `x * y`.
		   * For matrices, the matrix product is calculated.
		   *
		   * Syntax:
		   *
		   *    math.multiply(x, y)
		   *    math.multiply(x, y, z, ...)
		   *
		   * Examples:
		   *
		   *    math.multiply(4, 5.2);        // returns number 20.8
		   *    math.multiply(2, 3, 4);       // returns number 24
		   *
		   *    var a = math.complex(2, 3);
		   *    var b = math.complex(4, 1);
		   *    math.multiply(a, b);          // returns Complex 5 + 14i
		   *
		   *    var c = [[1, 2], [4, 3]];
		   *    var d = [[1, 2, 3], [3, -4, 7]];
		   *    math.multiply(c, d);          // returns Array [[7, -6, 17], [13, -4, 33]]
		   *
		   *    var e = math.unit('2.1 km');
		   *    math.multiply(3, e);          // returns Unit 6.3 km
		   *
		   * See also:
		   *
		   *    divide, prod, cross, dot
		   *
		   * @param  {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First value to multiply
		   * @param  {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second value to multiply
		   * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Multiplication of `x` and `y`
		   */
		  var multiply = typed('multiply', extend({
		    // we extend the signatures of multiplyScalar with signatures dealing with matrices
	
		    'Array, Array': function ArrayArray(x, y) {
		      // check dimensions
		      _validateMatrixDimensions(array.size(x), array.size(y));
	
		      // use dense matrix implementation
		      var m = multiply(matrix(x), matrix(y));
		      // return array or scalar
		      return type.isMatrix(m) ? m.valueOf() : m;
		    },
	
		    'Matrix, Matrix': function MatrixMatrix(x, y) {
		      // dimensions
		      var xsize = x.size();
		      var ysize = y.size();
	
		      // check dimensions
		      _validateMatrixDimensions(xsize, ysize);
	
		      // process dimensions
		      if (xsize.length === 1) {
		        // process y dimensions
		        if (ysize.length === 1) {
		          // Vector * Vector
		          return _multiplyVectorVector(x, y, xsize[0]);
		        }
		        // Vector * Matrix
		        return _multiplyVectorMatrix(x, y);
		      }
		      // process y dimensions
		      if (ysize.length === 1) {
		        // Matrix * Vector
		        return _multiplyMatrixVector(x, y);
		      }
		      // Matrix * Matrix
		      return _multiplyMatrixMatrix(x, y);
		    },
	
		    'Matrix, Array': function MatrixArray(x, y) {
		      // use Matrix * Matrix implementation
		      return multiply(x, matrix(y));
		    },
	
		    'Array, Matrix': function ArrayMatrix(x, y) {
		      // use Matrix * Matrix implementation
		      return multiply(matrix(x, y.storage()), y);
		    },
	
		    'Matrix, any': function MatrixAny(x, y) {
		      // result
		      var c;
	
		      // process storage format
		      switch (x.storage()) {
		        case 'sparse':
		          c = algorithm11(x, y, multiplyScalar, false);
		          break;
		        case 'dense':
		          c = algorithm14(x, y, multiplyScalar, false);
		          break;
		      }
		      return c;
		    },
	
		    'any, Matrix': function anyMatrix(x, y) {
		      // result
		      var c;
		      // check storage format
		      switch (y.storage()) {
		        case 'sparse':
		          c = algorithm11(y, x, multiplyScalar, true);
		          break;
		        case 'dense':
		          c = algorithm14(y, x, multiplyScalar, true);
		          break;
		      }
		      return c;
		    },
	
		    'Array, any': function ArrayAny(x, y) {
		      // use matrix implementation
		      return algorithm14(matrix(x), y, multiplyScalar, false).valueOf();
		    },
	
		    'any, Array': function anyArray(x, y) {
		      // use matrix implementation
		      return algorithm14(matrix(y), x, multiplyScalar, true).valueOf();
		    },
	
		    'any, any': multiplyScalar,
	
		    'Array | Matrix | any, Array | Matrix | any, ...any': function ArrayMatrixAnyArrayMatrixAnyAny(x, y, rest) {
		      var result = multiply(x, y);
	
		      for (var i = 0; i < rest.length; i++) {
		        result = multiply(result, rest[i]);
		      }
	
		      return result;
		    }
		  }, multiplyScalar.signatures));
	
		  var _validateMatrixDimensions = function _validateMatrixDimensions(size1, size2) {
		    // check left operand dimensions
		    switch (size1.length) {
		      case 1:
		        // check size2
		        switch (size2.length) {
		          case 1:
		            // Vector x Vector
		            if (size1[0] !== size2[0]) {
		              // throw error
		              throw new RangeError('Dimension mismatch in multiplication. Vectors must have the same length');
		            }
		            break;
		          case 2:
		            // Vector x Matrix
		            if (size1[0] !== size2[0]) {
		              // throw error
		              throw new RangeError('Dimension mismatch in multiplication. Vector length (' + size1[0] + ') must match Matrix rows (' + size2[0] + ')');
		            }
		            break;
		          default:
		            throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix B has ' + size2.length + ' dimensions)');
		        }
		        break;
		      case 2:
		        // check size2
		        switch (size2.length) {
		          case 1:
		            // Matrix x Vector
		            if (size1[1] !== size2[0]) {
		              // throw error
		              throw new RangeError('Dimension mismatch in multiplication. Matrix columns (' + size1[1] + ') must match Vector length (' + size2[0] + ')');
		            }
		            break;
		          case 2:
		            // Matrix x Matrix
		            if (size1[1] !== size2[0]) {
		              // throw error
		              throw new RangeError('Dimension mismatch in multiplication. Matrix A columns (' + size1[1] + ') must match Matrix B rows (' + size2[0] + ')');
		            }
		            break;
		          default:
		            throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix B has ' + size2.length + ' dimensions)');
		        }
		        break;
		      default:
		        throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix A has ' + size1.length + ' dimensions)');
		    }
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            Dense Vector   (N)
		   * @param {Matrix} b            Dense Vector   (N)
		   *
		   * @return {number}             Scalar value
		   */
		  var _multiplyVectorVector = function _multiplyVectorVector(a, b, n) {
		    // check empty vector
		    if (n === 0) throw new Error('Cannot multiply two empty vectors');
	
		    // a dense
		    var adata = a._data;
		    var adt = a._datatype;
		    // b dense
		    var bdata = b._data;
		    var bdt = b._datatype;
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		    }
	
		    // result (do not initialize it with zero)
		    var c = mf(adata[0], bdata[0]);
		    // loop data
		    for (var i = 1; i < n; i++) {
		      // multiply and accumulate
		      c = af(c, mf(adata[i], bdata[i]));
		    }
		    return c;
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            Dense Vector   (M)
		   * @param {Matrix} b            Matrix         (MxN)
		   *
		   * @return {Matrix}             Dense Vector   (N)
		   */
		  var _multiplyVectorMatrix = function _multiplyVectorMatrix(a, b) {
		    // process storage
		    switch (b.storage()) {
		      case 'dense':
		        return _multiplyVectorDenseMatrix(a, b);
		    }
		    throw new Error('Not implemented');
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            Dense Vector   (M)
		   * @param {Matrix} b            Dense Matrix   (MxN)
		   *
		   * @return {Matrix}             Dense Vector   (N)
		   */
		  var _multiplyVectorDenseMatrix = function _multiplyVectorDenseMatrix(a, b) {
		    // a dense
		    var adata = a._data;
		    var asize = a._size;
		    var adt = a._datatype;
		    // b dense
		    var bdata = b._data;
		    var bsize = b._size;
		    var bdt = b._datatype;
		    // rows & columns
		    var alength = asize[0];
		    var bcolumns = bsize[1];
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		    }
	
		    // result
		    var c = [];
	
		    // loop matrix columns
		    for (var j = 0; j < bcolumns; j++) {
		      // sum (do not initialize it with zero)
		      var sum = mf(adata[0], bdata[0][j]);
		      // loop vector
		      for (var i = 1; i < alength; i++) {
		        // multiply & accumulate
		        sum = af(sum, mf(adata[i], bdata[i][j]));
		      }
		      c[j] = sum;
		    }
	
		    // return matrix
		    return new DenseMatrix({
		      data: c,
		      size: [bcolumns],
		      datatype: dt
		    });
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            Matrix         (MxN)
		   * @param {Matrix} b            Dense Vector   (N)
		   *
		   * @return {Matrix}             Dense Vector   (M)
		   */
		  var _multiplyMatrixVector = function _multiplyMatrixVector(a, b) {
		    // process storage
		    switch (a.storage()) {
		      case 'dense':
		        return _multiplyDenseMatrixVector(a, b);
		      case 'sparse':
		        return _multiplySparseMatrixVector(a, b);
		    }
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            Matrix         (MxN)
		   * @param {Matrix} b            Matrix         (NxC)
		   *
		   * @return {Matrix}             Matrix         (MxC)
		   */
		  var _multiplyMatrixMatrix = function _multiplyMatrixMatrix(a, b) {
		    // process storage
		    switch (a.storage()) {
		      case 'dense':
		        // process storage
		        switch (b.storage()) {
		          case 'dense':
		            return _multiplyDenseMatrixDenseMatrix(a, b);
		          case 'sparse':
		            return _multiplyDenseMatrixSparseMatrix(a, b);
		        }
		        break;
		      case 'sparse':
		        // process storage
		        switch (b.storage()) {
		          case 'dense':
		            return _multiplySparseMatrixDenseMatrix(a, b);
		          case 'sparse':
		            return _multiplySparseMatrixSparseMatrix(a, b);
		        }
		        break;
		    }
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            DenseMatrix  (MxN)
		   * @param {Matrix} b            Dense Vector (N)
		   *
		   * @return {Matrix}             Dense Vector (M) 
		   */
		  var _multiplyDenseMatrixVector = function _multiplyDenseMatrixVector(a, b) {
		    // a dense
		    var adata = a._data;
		    var asize = a._size;
		    var adt = a._datatype;
		    // b dense
		    var bdata = b._data;
		    var bdt = b._datatype;
		    // rows & columns
		    var arows = asize[0];
		    var acolumns = asize[1];
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		    }
	
		    // result
		    var c = [];
	
		    // loop matrix a rows
		    for (var i = 0; i < arows; i++) {
		      // current row
		      var row = adata[i];
		      // sum (do not initialize it with zero)
		      var sum = mf(row[0], bdata[0]);
		      // loop matrix a columns
		      for (var j = 1; j < acolumns; j++) {
		        // multiply & accumulate
		        sum = af(sum, mf(row[j], bdata[j]));
		      }
		      c[i] = sum;
		    }
	
		    // return matrix
		    return new DenseMatrix({
		      data: c,
		      size: [arows],
		      datatype: dt
		    });
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            DenseMatrix    (MxN)
		   * @param {Matrix} b            DenseMatrix    (NxC)
		   *
		   * @return {Matrix}             DenseMatrix    (MxC)
		   */
		  var _multiplyDenseMatrixDenseMatrix = function _multiplyDenseMatrixDenseMatrix(a, b) {
		    // a dense
		    var adata = a._data;
		    var asize = a._size;
		    var adt = a._datatype;
		    // b dense
		    var bdata = b._data;
		    var bsize = b._size;
		    var bdt = b._datatype;
		    // rows & columns
		    var arows = asize[0];
		    var acolumns = asize[1];
		    var bcolumns = bsize[1];
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		    }
	
		    // result
		    var c = [];
	
		    // loop matrix a rows
		    for (var i = 0; i < arows; i++) {
		      // current row
		      var row = adata[i];
		      // initialize row array
		      c[i] = [];
		      // loop matrix b columns
		      for (var j = 0; j < bcolumns; j++) {
		        // sum (avoid initializing sum to zero)
		        var sum = mf(row[0], bdata[0][j]);
		        // loop matrix a columns
		        for (var x = 1; x < acolumns; x++) {
		          // multiply & accumulate
		          sum = af(sum, mf(row[x], bdata[x][j]));
		        }
		        c[i][j] = sum;
		      }
		    }
	
		    // return matrix
		    return new DenseMatrix({
		      data: c,
		      size: [arows, bcolumns],
		      datatype: dt
		    });
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            DenseMatrix    (MxN)
		   * @param {Matrix} b            SparseMatrix   (NxC)
		   *
		   * @return {Matrix}             SparseMatrix   (MxC)
		   */
		  var _multiplyDenseMatrixSparseMatrix = function _multiplyDenseMatrixSparseMatrix(a, b) {
		    // a dense
		    var adata = a._data;
		    var asize = a._size;
		    var adt = a._datatype;
		    // b sparse
		    var bvalues = b._values;
		    var bindex = b._index;
		    var bptr = b._ptr;
		    var bsize = b._size;
		    var bdt = b._datatype;
		    // validate b matrix
		    if (!bvalues) throw new Error('Cannot multiply Dense Matrix times Pattern only Matrix');
		    // rows & columns
		    var arows = asize[0];
		    var bcolumns = bsize[1];
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
		    // equalScalar signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		      eq = typed.find(equalScalar, [dt, dt]);
		      // convert 0 to the same datatype
		      zero = typed.convert(0, dt);
		    }
	
		    // result
		    var cvalues = [];
		    var cindex = [];
		    var cptr = [];
		    // c matrix
		    var c = new SparseMatrix({
		      values: cvalues,
		      index: cindex,
		      ptr: cptr,
		      size: [arows, bcolumns],
		      datatype: dt
		    });
	
		    // loop b columns
		    for (var jb = 0; jb < bcolumns; jb++) {
		      // update ptr
		      cptr[jb] = cindex.length;
		      // indeces in column jb
		      var kb0 = bptr[jb];
		      var kb1 = bptr[jb + 1];
		      // do not process column jb if no data exists
		      if (kb1 > kb0) {
		        // last row mark processed
		        var last = 0;
		        // loop a rows
		        for (var i = 0; i < arows; i++) {
		          // column mark
		          var mark = i + 1;
		          // C[i, jb]
		          var cij;
		          // values in b column j
		          for (var kb = kb0; kb < kb1; kb++) {
		            // row
		            var ib = bindex[kb];
		            // check value has been initialized
		            if (last !== mark) {
		              // first value in column jb
		              cij = mf(adata[i][ib], bvalues[kb]);
		              // update mark
		              last = mark;
		            } else {
		              // accumulate value
		              cij = af(cij, mf(adata[i][ib], bvalues[kb]));
		            }
		          }
		          // check column has been processed and value != 0
		          if (last === mark && !eq(cij, zero)) {
		            // push row & value
		            cindex.push(i);
		            cvalues.push(cij);
		          }
		        }
		      }
		    }
		    // update ptr
		    cptr[bcolumns] = cindex.length;
	
		    // return sparse matrix
		    return c;
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            SparseMatrix    (MxN)
		   * @param {Matrix} b            Dense Vector (N)
		   *
		   * @return {Matrix}             SparseMatrix    (M, 1) 
		   */
		  var _multiplySparseMatrixVector = function _multiplySparseMatrixVector(a, b) {
		    // a sparse
		    var avalues = a._values;
		    var aindex = a._index;
		    var aptr = a._ptr;
		    var adt = a._datatype;
		    // validate a matrix
		    if (!avalues) throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix');
		    // b dense
		    var bdata = b._data;
		    var bdt = b._datatype;
		    // rows & columns
		    var arows = a._size[0];
		    var brows = b._size[0];
		    // result
		    var cvalues = [];
		    var cindex = [];
		    var cptr = [];
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
		    // equalScalar signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		      eq = typed.find(equalScalar, [dt, dt]);
		      // convert 0 to the same datatype
		      zero = typed.convert(0, dt);
		    }
	
		    // workspace
		    var x = [];
		    // vector with marks indicating a value x[i] exists in a given column
		    var w = [];
	
		    // update ptr
		    cptr[0] = 0;
		    // rows in b
		    for (var ib = 0; ib < brows; ib++) {
		      // b[ib]
		      var vbi = bdata[ib];
		      // check b[ib] != 0, avoid loops
		      if (!eq(vbi, zero)) {
		        // A values & index in ib column
		        for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) {
		          // a row
		          var ia = aindex[ka];
		          // check value exists in current j
		          if (!w[ia]) {
		            // ia is new entry in j
		            w[ia] = true;
		            // add i to pattern of C
		            cindex.push(ia);
		            // x(ia) = A
		            x[ia] = mf(vbi, avalues[ka]);
		          } else {
		            // i exists in C already
		            x[ia] = af(x[ia], mf(vbi, avalues[ka]));
		          }
		        }
		      }
		    }
		    // copy values from x to column jb of c
		    for (var p1 = cindex.length, p = 0; p < p1; p++) {
		      // row
		      var ic = cindex[p];
		      // copy value
		      cvalues[p] = x[ic];
		    }
		    // update ptr
		    cptr[1] = cindex.length;
	
		    // return sparse matrix
		    return new SparseMatrix({
		      values: cvalues,
		      index: cindex,
		      ptr: cptr,
		      size: [arows, 1],
		      datatype: dt
		    });
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            SparseMatrix      (MxN)
		   * @param {Matrix} b            DenseMatrix       (NxC)
		   *
		   * @return {Matrix}             SparseMatrix      (MxC)
		   */
		  var _multiplySparseMatrixDenseMatrix = function _multiplySparseMatrixDenseMatrix(a, b) {
		    // a sparse
		    var avalues = a._values;
		    var aindex = a._index;
		    var aptr = a._ptr;
		    var adt = a._datatype;
		    // validate a matrix
		    if (!avalues) throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix');
		    // b dense
		    var bdata = b._data;
		    var bdt = b._datatype;
		    // rows & columns
		    var arows = a._size[0];
		    var brows = b._size[0];
		    var bcolumns = b._size[1];
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
		    // equalScalar signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		      eq = typed.find(equalScalar, [dt, dt]);
		      // convert 0 to the same datatype
		      zero = typed.convert(0, dt);
		    }
	
		    // result
		    var cvalues = [];
		    var cindex = [];
		    var cptr = [];
		    // c matrix
		    var c = new SparseMatrix({
		      values: cvalues,
		      index: cindex,
		      ptr: cptr,
		      size: [arows, bcolumns],
		      datatype: dt
		    });
	
		    // workspace
		    var x = [];
		    // vector with marks indicating a value x[i] exists in a given column
		    var w = [];
	
		    // loop b columns
		    for (var jb = 0; jb < bcolumns; jb++) {
		      // update ptr
		      cptr[jb] = cindex.length;
		      // mark in workspace for current column
		      var mark = jb + 1;
		      // rows in jb
		      for (var ib = 0; ib < brows; ib++) {
		        // b[ib, jb]
		        var vbij = bdata[ib][jb];
		        // check b[ib, jb] != 0, avoid loops
		        if (!eq(vbij, zero)) {
		          // A values & index in ib column
		          for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) {
		            // a row
		            var ia = aindex[ka];
		            // check value exists in current j
		            if (w[ia] !== mark) {
		              // ia is new entry in j
		              w[ia] = mark;
		              // add i to pattern of C
		              cindex.push(ia);
		              // x(ia) = A
		              x[ia] = mf(vbij, avalues[ka]);
		            } else {
		              // i exists in C already
		              x[ia] = af(x[ia], mf(vbij, avalues[ka]));
		            }
		          }
		        }
		      }
		      // copy values from x to column jb of c
		      for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) {
		        // row
		        var ic = cindex[p];
		        // copy value
		        cvalues[p] = x[ic];
		      }
		    }
		    // update ptr
		    cptr[bcolumns] = cindex.length;
	
		    // return sparse matrix
		    return c;
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            SparseMatrix      (MxN)
		   * @param {Matrix} b            SparseMatrix      (NxC)
		   *
		   * @return {Matrix}             SparseMatrix      (MxC)
		   */
		  var _multiplySparseMatrixSparseMatrix = function _multiplySparseMatrixSparseMatrix(a, b) {
		    // a sparse
		    var avalues = a._values;
		    var aindex = a._index;
		    var aptr = a._ptr;
		    var adt = a._datatype;
		    // b sparse
		    var bvalues = b._values;
		    var bindex = b._index;
		    var bptr = b._ptr;
		    var bdt = b._datatype;
	
		    // rows & columns
		    var arows = a._size[0];
		    var bcolumns = b._size[1];
		    // flag indicating both matrices (a & b) contain data
		    var values = avalues && bvalues;
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		    }
	
		    // result
		    var cvalues = values ? [] : undefined;
		    var cindex = [];
		    var cptr = [];
		    // c matrix
		    var c = new SparseMatrix({
		      values: cvalues,
		      index: cindex,
		      ptr: cptr,
		      size: [arows, bcolumns],
		      datatype: dt
		    });
	
		    // workspace
		    var x = values ? [] : undefined;
		    // vector with marks indicating a value x[i] exists in a given column
		    var w = [];
		    // variables
		    var ka, ka0, ka1, kb, kb0, kb1, ia, ib;
		    // loop b columns
		    for (var jb = 0; jb < bcolumns; jb++) {
		      // update ptr
		      cptr[jb] = cindex.length;
		      // mark in workspace for current column
		      var mark = jb + 1;
		      // B values & index in j
		      for (kb0 = bptr[jb], kb1 = bptr[jb + 1], kb = kb0; kb < kb1; kb++) {
		        // b row
		        ib = bindex[kb];
		        // check we need to process values
		        if (values) {
		          // loop values in a[:,ib]
		          for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) {
		            // row
		            ia = aindex[ka];
		            // check value exists in current j
		            if (w[ia] !== mark) {
		              // ia is new entry in j
		              w[ia] = mark;
		              // add i to pattern of C
		              cindex.push(ia);
		              // x(ia) = A
		              x[ia] = mf(bvalues[kb], avalues[ka]);
		            } else {
		              // i exists in C already
		              x[ia] = af(x[ia], mf(bvalues[kb], avalues[ka]));
		            }
		          }
		        } else {
		          // loop values in a[:,ib]
		          for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) {
		            // row
		            ia = aindex[ka];
		            // check value exists in current j
		            if (w[ia] !== mark) {
		              // ia is new entry in j
		              w[ia] = mark;
		              // add i to pattern of C
		              cindex.push(ia);
		            }
		          }
		        }
		      }
		      // check we need to process matrix values (pattern matrix)
		      if (values) {
		        // copy values from x to column jb of c
		        for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) {
		          // row
		          var ic = cindex[p];
		          // copy value
		          cvalues[p] = x[ic];
		        }
		      }
		    }
		    // update ptr
		    cptr[bcolumns] = cindex.length;
	
		    // return sparse matrix
		    return c;
		  };
	
		  multiply.toTex = {
		    2: '\\left(${args[0]}' + latex.operators['multiply'] + '${args[1]}\\right)'
		  };
	
		  return multiply;
		}
	
		exports.name = 'multiply';
		exports.factory = factory;
	
	/***/ }),
	/* 123 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
	
		  /**
		   * Multiply two scalar values, `x * y`.
		   * This function is meant for internal use: it is used by the public function
		   * `multiply`
		   *
		   * This function does not support collections (Array or Matrix), and does
		   * not validate the number of of inputs.
		   *
		   * @param  {number | BigNumber | Fraction | Complex | Unit} x   First value to multiply
		   * @param  {number | BigNumber | Fraction | Complex} y          Second value to multiply
		   * @return {number | BigNumber | Fraction | Complex | Unit}                      Multiplication of `x` and `y`
		   * @private
		   */
		  var multiplyScalar = typed('multiplyScalar', {
	
		    'number, number': function numberNumber(x, y) {
		      return x * y;
		    },
	
		    'Complex, Complex': function ComplexComplex(x, y) {
		      return x.mul(y);
		    },
	
		    'BigNumber, BigNumber': function BigNumberBigNumber(x, y) {
		      return x.times(y);
		    },
	
		    'Fraction, Fraction': function FractionFraction(x, y) {
		      return x.mul(y);
		    },
	
		    'number | Fraction | BigNumber | Complex, Unit': function numberFractionBigNumberComplexUnit(x, y) {
		      var res = y.clone();
		      res.value = res.value === null ? res._normalize(x) : multiplyScalar(res.value, x);
		      return res;
		    },
	
		    'Unit, number | Fraction | BigNumber | Complex': function UnitNumberFractionBigNumberComplex(x, y) {
		      var res = x.clone();
		      res.value = res.value === null ? res._normalize(y) : multiplyScalar(res.value, y);
		      return res;
		    },
	
		    'Unit, Unit': function UnitUnit(x, y) {
		      return x.multiply(y);
		    }
	
		  });
	
		  return multiplyScalar;
		}
	
		exports.factory = factory;
	
	/***/ }),
	/* 124 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
	
		  var equalScalar = load(__webpack_require__(39));
	
		  var SparseMatrix = type.SparseMatrix;
	
		  /**
		   * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). 
		   * Callback function invoked NZ times (number of nonzero items in S).
		   *
		   *
		   *          ┌  f(Sij, b)  ; S(i,j) !== 0
		   * C(i,j) = ┤  
		   *          └  0          ; otherwise
		   *
		   *
		   * @param {Matrix}   s                 The SparseMatrix instance (S)
		   * @param {Scalar}   b                 The Scalar value
		   * @param {Function} callback          The f(Aij,b) operation to invoke
		   * @param {boolean}  inverse           A true value indicates callback should be invoked f(b,Sij)
		   *
		   * @return {Matrix}                    SparseMatrix (C)
		   *
		   * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813
		   */
		  var algorithm11 = function algorithm11(s, b, callback, inverse) {
		    // sparse matrix arrays
		    var avalues = s._values;
		    var aindex = s._index;
		    var aptr = s._ptr;
		    var asize = s._size;
		    var adt = s._datatype;
	
		    // sparse matrix cannot be a Pattern matrix
		    if (!avalues) throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value');
	
		    // rows & columns
		    var rows = asize[0];
		    var columns = asize[1];
	
		    // datatype
		    var dt;
		    // equal signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
		    // callback signature to use
		    var cf = callback;
	
		    // process data types
		    if (typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signature that matches (dt, dt)
		      eq = typed.find(equalScalar, [dt, dt]);
		      // convert 0 to the same datatype
		      zero = typed.convert(0, dt);
		      // convert b to the same datatype
		      b = typed.convert(b, dt);
		      // callback
		      cf = typed.find(callback, [dt, dt]);
		    }
	
		    // result arrays
		    var cvalues = [];
		    var cindex = [];
		    var cptr = [];
		    // matrix
		    var c = new SparseMatrix({
		      values: cvalues,
		      index: cindex,
		      ptr: cptr,
		      size: [rows, columns],
		      datatype: dt
		    });
	
		    // loop columns
		    for (var j = 0; j < columns; j++) {
		      // initialize ptr
		      cptr[j] = cindex.length;
		      // values in j
		      for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) {
		        // row
		        var i = aindex[k];
		        // invoke callback
		        var v = inverse ? cf(b, avalues[k]) : cf(avalues[k], b);
		        // check value is zero
		        if (!eq(v, zero)) {
		          // push index & value
		          cindex.push(i);
		          cvalues.push(v);
		        }
		      }
		    }
		    // update ptr
		    cptr[columns] = cindex.length;
	
		    // return sparse matrix
		    return c;
		  };
	
		  return algorithm11;
		}
	
		exports.name = 'algorithm11';
		exports.factory = factory;
	
	/***/ }),
	/* 125 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var isInteger = __webpack_require__(18).isInteger;
		var size = __webpack_require__(28).size;
	
		function factory(type, config, load, typed) {
		  var latex = __webpack_require__(45);
		  var eye = load(__webpack_require__(126));
		  var multiply = load(__webpack_require__(122));
		  var matrix = load(__webpack_require__(43));
		  var fraction = load(__webpack_require__(127));
		  var number = load(__webpack_require__(128));
	
		  /**
		   * Calculates the power of x to y, `x ^ y`.
		   * Matrix exponentiation is supported for square matrices `x`, and positive
		   * integer exponents `y`.
		   *
		   * For cubic roots of negative numbers, the function returns the principal
		   * root by default. In order to let the function return the real root,
		   * math.js can be configured with `math.config({predictable: true})`.
		   * To retrieve all cubic roots of a value, use `math.cbrt(x, true)`.
		   *
		   * Syntax:
		   *
		   *    math.pow(x, y)
		   *
		   * Examples:
		   *
		   *    math.pow(2, 3);               // returns number 8
		   *
		   *    var a = math.complex(2, 3);
		   *    math.pow(a, 2)                // returns Complex -5 + 12i
		   *
		   *    var b = [[1, 2], [4, 3]];
		   *    math.pow(b, 2);               // returns Array [[9, 8], [16, 17]]
		   *
		   * See also:
		   *
		   *    multiply, sqrt, cbrt, nthRoot
		   *
		   * @param  {number | BigNumber | Complex | Array | Matrix} x  The base
		   * @param  {number | BigNumber | Complex} y                   The exponent
		   * @return {number | BigNumber | Complex | Array | Matrix} The value of `x` to the power `y`
		   */
		  var pow = typed('pow', {
		    'number, number': _pow,
	
		    'Complex, Complex': function ComplexComplex(x, y) {
		      return x.pow(y);
		    },
	
		    'BigNumber, BigNumber': function BigNumberBigNumber(x, y) {
		      if (y.isInteger() || x >= 0 || config.predictable) {
		        return x.pow(y);
		      } else {
		        return new type.Complex(x.toNumber(), 0).pow(y.toNumber(), 0);
		      }
		    },
	
		    'Fraction, Fraction': function FractionFraction(x, y) {
		      if (y.d !== 1) {
		        if (config.predictable) {
		          throw new Error('Function pow does not support non-integer exponents for fractions.');
		        } else {
		          return _pow(x.valueOf(), y.valueOf());
		        }
		      } else {
		        return x.pow(y);
		      }
		    },
	
		    'Array, number': _powArray,
	
		    'Array, BigNumber': function ArrayBigNumber(x, y) {
		      return _powArray(x, y.toNumber());
		    },
	
		    'Matrix, number': _powMatrix,
	
		    'Matrix, BigNumber': function MatrixBigNumber(x, y) {
		      return _powMatrix(x, y.toNumber());
		    },
	
		    'Unit, number': function UnitNumber(x, y) {
		      return x.pow(y);
		    }
	
		  });
	
		  /**
		   * Calculates the power of x to y, x^y, for two numbers.
		   * @param {number} x
		   * @param {number} y
		   * @return {number | Complex} res
		   * @private
		   */
		  function _pow(x, y) {
	
		    // Alternatively could define a 'realmode' config option or something, but
		    // 'predictable' will work for now
		    if (config.predictable && !isInteger(y) && x < 0) {
		      // Check to see if y can be represented as a fraction
		      try {
		        var yFrac = fraction(y);
		        var yNum = number(yFrac);
		        if (y === yNum || Math.abs((y - yNum) / y) < 1e-14) {
		          if (yFrac.d % 2 === 1) {
		            return (yFrac.n % 2 === 0 ? 1 : -1) * Math.pow(-x, y);
		          }
		        }
		      } catch (ex) {}
		      // fraction() throws an error if y is Infinity, etc.
	
	
		      // Unable to express y as a fraction, so continue on
		    }
	
		    // x^Infinity === 0 if -1 < x < 1
		    // A real number 0 is returned instead of complex(0)
		    if (x * x < 1 && y === Infinity || x * x > 1 && y === -Infinity) {
		      return 0;
		    }
	
		    // **for predictable mode** x^Infinity === NaN if x < -1
		    // N.B. this behavour is different from `Math.pow` which gives
		    // (-2)^Infinity === Infinity
		    if (config.predictable && (x < -1 && y === Infinity || x > -1 && x < 0 && y === -Infinity)) {
		      return NaN;
		    }
	
		    if (isInteger(y) || x >= 0 || config.predictable) {
		      return Math.pow(x, y);
		    } else {
		      return new type.Complex(x, 0).pow(y, 0);
		    }
		  }
	
		  /**
		   * Calculate the power of a 2d array
		   * @param {Array} x     must be a 2 dimensional, square matrix
		   * @param {number} y    a positive, integer value
		   * @returns {Array}
		   * @private
		   */
		  function _powArray(x, y) {
		    if (!isInteger(y) || y < 0) {
		      throw new TypeError('For A^b, b must be a positive integer (value is ' + y + ')');
		    }
		    // verify that A is a 2 dimensional square matrix
		    var s = size(x);
		    if (s.length != 2) {
		      throw new Error('For A^b, A must be 2 dimensional (A has ' + s.length + ' dimensions)');
		    }
		    if (s[0] != s[1]) {
		      throw new Error('For A^b, A must be square (size is ' + s[0] + 'x' + s[1] + ')');
		    }
	
		    var res = eye(s[0]).valueOf();
		    var px = x;
		    while (y >= 1) {
		      if ((y & 1) == 1) {
		        res = multiply(px, res);
		      }
		      y >>= 1;
		      px = multiply(px, px);
		    }
		    return res;
		  }
	
		  /**
		   * Calculate the power of a 2d matrix
		   * @param {Matrix} x     must be a 2 dimensional, square matrix
		   * @param {number} y    a positive, integer value
		   * @returns {Matrix}
		   * @private
		   */
		  function _powMatrix(x, y) {
		    return matrix(_powArray(x.valueOf(), y));
		  }
	
		  pow.toTex = {
		    2: '\\left(${args[0]}\\right)' + latex.operators['pow'] + '{${args[1]}}'
		  };
	
		  return pow;
		}
	
		exports.name = 'pow';
		exports.factory = factory;
	
	/***/ }),
	/* 126 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var array = __webpack_require__(28);
		var isInteger = __webpack_require__(18).isInteger;
	
		function factory(type, config, load, typed) {
	
		  var matrix = load(__webpack_require__(43));
	
		  /**
		   * Create a 2-dimensional identity matrix with size m x n or n x n.
		   * The matrix has ones on the diagonal and zeros elsewhere.
		   *
		   * Syntax:
		   *
		   *    math.eye(n)
		   *    math.eye(n, format)
		   *    math.eye(m, n)
		   *    math.eye(m, n, format)
		   *    math.eye([m, n])
		   *    math.eye([m, n], format)
		   *
		   * Examples:
		   *
		   *    math.eye(3);                    // returns [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
		   *    math.eye(3, 2);                 // returns [[1, 0], [0, 1], [0, 0]]
		   *
		   *    var A = [[1, 2, 3], [4, 5, 6]];
		   *    math.eye(math.size(A));         // returns [[1, 0, 0], [0, 1, 0]]
		   *
		   * See also:
		   *
		   *    diag, ones, zeros, size, range
		   *
		   * @param {...number | Matrix | Array} size   The size for the matrix
		   * @param {string} [format]                   The Matrix storage format
		   *
		   * @return {Matrix | Array | number} A matrix with ones on the diagonal.
		   */
		  var eye = typed('eye', {
		    '': function _() {
		      return config.matrix === 'Matrix' ? matrix([]) : [];
		    },
	
		    'string': function string(format) {
		      return matrix(format);
		    },
	
		    'number | BigNumber': function numberBigNumber(rows) {
		      return _eye(rows, rows, config.matrix === 'Matrix' ? 'default' : undefined);
		    },
	
		    'number | BigNumber, string': function numberBigNumberString(rows, format) {
		      return _eye(rows, rows, format);
		    },
	
		    'number | BigNumber, number | BigNumber': function numberBigNumberNumberBigNumber(rows, cols) {
		      return _eye(rows, cols, config.matrix === 'Matrix' ? 'default' : undefined);
		    },
	
		    'number | BigNumber, number | BigNumber, string': function numberBigNumberNumberBigNumberString(rows, cols, format) {
		      return _eye(rows, cols, format);
		    },
	
		    'Array': function Array(size) {
		      return _eyeVector(size);
		    },
	
		    'Array, string': function ArrayString(size, format) {
		      return _eyeVector(size, format);
		    },
	
		    'Matrix': function Matrix(size) {
		      return _eyeVector(size.valueOf(), size.storage());
		    },
	
		    'Matrix, string': function MatrixString(size, format) {
		      return _eyeVector(size.valueOf(), format);
		    }
		  });
	
		  eye.toTex = undefined; // use default template
	
		  return eye;
	
		  function _eyeVector(size, format) {
		    switch (size.length) {
		      case 0:
		        return format ? matrix(format) : [];
		      case 1:
		        return _eye(size[0], size[0], format);
		      case 2:
		        return _eye(size[0], size[1], format);
		      default:
		        throw new Error('Vector containing two values expected');
		    }
		  }
	
		  /**
		   * Create an identity matrix
		   * @param {number | BigNumber} rows
		   * @param {number | BigNumber} cols
		   * @param {string} [format]
		   * @returns {Matrix}
		   * @private
		   */
		  function _eye(rows, cols, format) {
		    // BigNumber constructor with the right precision
		    var Big = type.isBigNumber(rows) || type.isBigNumber(cols) ? type.BigNumber : null;
	
		    if (type.isBigNumber(rows)) rows = rows.toNumber();
		    if (type.isBigNumber(cols)) cols = cols.toNumber();
	
		    if (!isInteger(rows) || rows < 1) {
		      throw new Error('Parameters in function eye must be positive integers');
		    }
		    if (!isInteger(cols) || cols < 1) {
		      throw new Error('Parameters in function eye must be positive integers');
		    }
	
		    var one = Big ? new type.BigNumber(1) : 1;
		    var defaultValue = Big ? new Big(0) : 0;
		    var size = [rows, cols];
	
		    // check we need to return a matrix
		    if (format) {
		      // get matrix storage constructor
		      var F = type.Matrix.storage(format);
		      // create diagonal matrix (use optimized implementation for storage format)
		      return F.diagonal(size, one, 0, defaultValue);
		    }
	
		    // create and resize array
		    var res = array.resize([], size, defaultValue);
		    // fill in ones on the diagonal
		    var minimum = rows < cols ? rows : cols;
		    // fill diagonal
		    for (var d = 0; d < minimum; d++) {
		      res[d][d] = one;
		    }
		    return res;
		  }
		}
	
		exports.name = 'eye';
		exports.factory = factory;
	
	/***/ }),
	/* 127 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var deepMap = __webpack_require__(120);
	
		function factory(type, config, load, typed) {
		  /**
		   * Create a fraction convert a value to a fraction.
		   *
		   * Syntax:
		   *     math.fraction(numerator, denominator)
		   *     math.fraction({n: numerator, d: denominator})
		   *     math.fraction(matrix: Array | Matrix)         Turn all matrix entries
		   *                                                   into fractions
		   *
		   * Examples:
		   *
		   *     math.fraction(1, 3);
		   *     math.fraction('2/3');
		   *     math.fraction({n: 2, d: 3});
		   *     math.fraction([0.2, 0.25, 1.25]);
		   *
		   * See also:
		   *
		   *    bignumber, number, string, unit
		   *
		   * @param {number | string | Fraction | BigNumber | Array | Matrix} [args]
		   *            Arguments specifying the numerator and denominator of
		   *            the fraction
		   * @return {Fraction | Array | Matrix} Returns a fraction
		   */
		  var fraction = typed('fraction', {
		    'number': function number(x) {
		      if (!isFinite(x) || isNaN(x)) {
		        throw new Error(x + ' cannot be represented as a fraction');
		      }
	
		      return new type.Fraction(x);
		    },
	
		    'string': function string(x) {
		      return new type.Fraction(x);
		    },
	
		    'number, number': function numberNumber(numerator, denominator) {
		      return new type.Fraction(numerator, denominator);
		    },
	
		    'BigNumber': function BigNumber(x) {
		      return new type.Fraction(x.toString());
		    },
	
		    'Fraction': function Fraction(x) {
		      return x; // fractions are immutable
		    },
	
		    'Object': function Object(x) {
		      return new type.Fraction(x);
		    },
	
		    'Array | Matrix': function ArrayMatrix(x) {
		      return deepMap(x, fraction);
		    }
		  });
	
		  return fraction;
		}
	
		exports.name = 'fraction';
		exports.factory = factory;
	
	/***/ }),
	/* 128 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var deepMap = __webpack_require__(120);
	
		function factory(type, config, load, typed) {
		  /**
		   * Create a number or convert a string, boolean, or unit to a number.
		   * When value is a matrix, all elements will be converted to number.
		   *
		   * Syntax:
		   *
		   *    math.number(value)
		   *    math.number(unit, valuelessUnit)
		   *
		   * Examples:
		   *
		   *    math.number(2);                         // returns number 2
		   *    math.number('7.2');                     // returns number 7.2
		   *    math.number(true);                      // returns number 1
		   *    math.number([true, false, true, true]); // returns [1, 0, 1, 1]
		   *    math.number(math.unit('52cm'), 'm');    // returns 0.52
		   *
		   * See also:
		   *
		   *    bignumber, boolean, complex, index, matrix, string, unit
		   *
		   * @param {string | number | BigNumber | Fraction | boolean | Array | Matrix | Unit | null} [value]  Value to be converted
		   * @param {Unit | string} [valuelessUnit] A valueless unit, used to convert a unit to a number
		   * @return {number | Array | Matrix} The created number
		   */
		  var number = typed('number', {
		    '': function _() {
		      return 0;
		    },
	
		    'number': function number(x) {
		      return x;
		    },
	
		    'string': function string(x) {
		      var num = Number(x);
		      if (isNaN(num)) {
		        throw new SyntaxError('String "' + x + '" is no valid number');
		      }
		      return num;
		    },
	
		    'BigNumber': function BigNumber(x) {
		      return x.toNumber();
		    },
	
		    'Fraction': function Fraction(x) {
		      return x.valueOf();
		    },
	
		    'Unit': function Unit(x) {
		      throw new Error('Second argument with valueless unit expected');
		    },
	
		    'Unit, string | Unit': function UnitStringUnit(unit, valuelessUnit) {
		      return unit.toNumber(valuelessUnit);
		    },
	
		    'Array | Matrix': function ArrayMatrix(x) {
		      return deepMap(x, number);
		    }
		  });
	
		  number.toTex = {
		    0: '0',
		    1: '\\left(${args[0]}\\right)',
		    2: '\\left(\\left(${args[0]}\\right)${args[1]}\\right)'
		  };
	
		  return number;
		}
	
		exports.name = 'number';
		exports.factory = factory;
	
	/***/ }),
	/* 129 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function get_previous_zoom(params) {
		  var prev_zoom = {};
	
		  var inst_trans = d3.select(params.root + ' .clust_group').attr('transform');
	
		  if (inst_trans != null) {
	
		    // prevent from crashing if no scaling was done
		    if (inst_trans.indexOf('scale') > 0) {
		      prev_zoom.zoom_x = parseFloat(inst_trans.split('scale')[1].replace('(', '').replace(')', '').split(',')[0]);
	
		      prev_zoom.zoom_y = parseFloat(inst_trans.split('scale')[1].replace('(', '').replace(')', '').split(',')[1]);
		    } else {
		      prev_zoom.zoom_x = 1;
		      prev_zoom.zoom_y = 1;
		    }
		  } else {
		    prev_zoom.zoom_x = 1;
		    prev_zoom.zoom_y = 1;
		  }
	
		  return prev_zoom;
			};
	
	/***/ }),
	/* 130 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var d3_tip_custom = __webpack_require__(100);
	
		module.exports = function make_row_tooltips(params) {
	
		  if (params.labels.show_label_tooltips) {
	
		    // remove old tooltips
		    d3.selectAll(params.viz.root_tips + '_row_tip').remove();
	
		    var root_tip_selector = params.viz.root_tips.replace('.', '');
	
		    // d3-tooltip
		    var row_tip = d3_tip_custom().attr('class', function () {
		      var class_string = root_tip_selector + ' d3-tip ' + root_tip_selector + '_row_tip';
		      return class_string;
		    }).direction('e').offset([0, 10]).style('display', 'none').html(function (d) {
		      var inst_name = d.name.replace(/_/g, ' ').split('#')[0];
		      return "<span>" + inst_name + "</span>";
		    });
	
		    d3.select(params.viz.viz_wrapper).select(params.root + ' .row_container').call(row_tip);
	
		    d3.select(params.root + ' .row_label_zoom_container').selectAll('g').on('mouseover', function (d) {
	
		      d3.select(params.viz.root_tips + '_row_tip').classed(d.name, true);
	
		      d3.selectAll(params.viz.root_tips + '_row_tip').style('display', 'block');
	
		      d3.select(this).select('text').classed('active', true);
	
		      row_tip.show(d);
	
		      if (params.row_tip_callback != null) {
		        params.row_tip_callback(params.viz.root_tips, d);
		      }
		    }).on('mouseout', function mouseout(d) {
	
		      d3.selectAll(params.viz.root_tips + '_row_tip').style('display', 'none').classed(d.name, false);
	
		      d3.select(this).select('text').classed('active', false);
	
		      row_tip.hide(d);
		    });
		  } else {
	
		    d3.select(params.root + ' .row_label_zoom_container').selectAll('g').on('mouseover', function () {
		      d3.select(this).select('text').classed('active', true);
		    }).on('mouseout', function mouseout() {
		      d3.select(this).select('text').classed('active', false);
		    });
		  }
			};
	
	/***/ }),
	/* 131 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
		var add_col_click_hlight = __webpack_require__(132);
		var col_reorder = __webpack_require__(133);
		var row_reorder = __webpack_require__(104);
		var make_col_tooltips = __webpack_require__(137);
		var col_viz_aid_triangle = __webpack_require__(138);
	
		module.exports = function make_col_label_container(cgm) {
		  var text_delay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
	
	
		  var params = cgm.params;
		  var col_container;
	
		  var col_nodes = params.network_data.col_nodes;
	
		  // offset click group column label
		  var x_offset_click = params.viz.x_scale.rangeBand() / 2 + params.viz.border_width.x;
		  // reduce width of rotated rects
	
	
		  // make container to pre-position zoomable elements
		  if (d3.select(params.root + ' .col_container').empty()) {
	
		    col_container = d3.select(params.viz.viz_svg).append('g').attr('class', 'col_container').attr('transform', 'translate(' + params.viz.clust.margin.left + ',' + params.viz.norm_labels.margin.top + ')');
	
		    // white background rect for col labels
		    col_container.append('rect').attr('fill', params.viz.background_color) //!! prog_colors
		    .attr('width', 30 * params.viz.clust.dim.width + 'px').attr('height', params.viz.label_background.col).attr('class', 'white_bars');
	
		    // col labels
		    col_container.append('g').attr('class', 'col_label_outer_container')
		    // position the outer col label group
		    .attr('transform', 'translate(0,' + params.viz.norm_labels.width.col + ')').append('g').attr('class', 'col_zoom_container');
		  } else {
	
		    col_container = d3.select(params.root + ' .col_container').attr('transform', 'translate(' + params.viz.clust.margin.left + ',' + params.viz.norm_labels.margin.top + ')');
	
		    // white background rect for col labels
		    col_container.select('.white_bars').attr('fill', params.viz.background_color) //!! prog_colors
		    .attr('width', 30 * params.viz.clust.dim.width + 'px').attr('height', params.viz.label_background.col);
	
		    // col labels
		    col_container.select(params.root + ' .col_label_outer_container');
		  }
	
		  // add main column label group
		  var col_label_obj = d3.select(params.root + ' .col_zoom_container').selectAll('.col_label_text').data(col_nodes, function (d) {
		    return d.name;
		  }).enter().append('g').attr('class', 'col_label_text').attr('transform', function (d) {
		    var inst_index = d.col_index;
		    return 'translate(' + params.viz.x_scale(inst_index) + ', 0) rotate(-90)';
		  });
	
		  // append group for individual column label
		  var col_label_group = col_label_obj
		  // append new group for rect and label (not white lines)
		  .append('g').attr('class', 'col_label_group')
		  // rotate column labels
		  .attr('transform', 'translate(' + params.viz.x_scale.rangeBand() / 2 + ',' + x_offset_click + ') rotate(45)').on('mouseover', function () {
		    d3.select(this).select('text').classed('active', true);
		  }).on('mouseout', function () {
		    d3.select(this).select('text').classed('active', false);
		  });
	
		  // append column value bars
		  if (utils.has(params.network_data.col_nodes[0], 'value')) {
	
		    col_label_group.append('rect').attr('class', 'col_bars').attr('width', function (d) {
		      var inst_value = 0;
		      if (d.value > 0) {
		        inst_value = params.labels.bar_scale_col(d.value);
		      }
		      return inst_value;
		    })
		    // rotate labels - reduce width if rotating
		    .attr('height', params.viz.x_scale.rangeBand() * 0.66).style('fill', function (d) {
		      return d.value > 0 ? params.matrix.bar_colors[0] : params.matrix.bar_colors[1];
		    }).attr('opacity', 0.6);
		  }
	
		  // add column label
		  col_label_group.append('text').attr('x', 0)
		  // manually tuned
		  .attr('y', params.viz.x_scale.rangeBand() * 0.64).attr('dx', params.viz.border_width.x).attr('text-anchor', 'start').attr('full_name', function (d) {
		    return d.name;
		  })
		  // original font size
		  .style('font-size', params.labels.default_fs_col + 'px').style('cursor', 'default').text(function (d) {
		    return utils.normal_name(d);
		  })
		  // .attr('pointer-events','none')
		  .style('opacity', 0).transition().delay(text_delay).duration(text_delay).style('opacity', 1);
	
		  make_col_tooltips(params);
	
		  // add triangle under rotated labels
		  col_label_group.append('path').style('stroke-width', 0).attr('d', function () {
		    return col_viz_aid_triangle(params);
		  }).attr('fill', '#eee').style('opacity', 0).transition().delay(text_delay).duration(text_delay).style('opacity', params.viz.triangle_opacity);
	
		  // add col callback function
		  d3.selectAll(params.root + ' .col_label_text').on('click', function (d) {
	
		    if (typeof params.click_label == 'function') {
		      params.click_label(d.name, 'col');
		      add_col_click_hlight(params, this, d.ini);
		    } else {
	
		      if (params.tile_click_hlight) {
		        add_col_click_hlight(params, this, d.ini);
		      }
		    }
		  }).on('dblclick', function (d) {
	
		    var data_attr = '__data__';
		    var col_name = this[data_attr].name;
	
		    if (params.sim_mat) {
		      col_reorder(cgm, this, col_name);
	
		      var row_selection = d3.selectAll(params.root + ' .row_label_group').filter(function (d) {
		        return d.name == col_name;
		      })[0][0];
	
		      row_reorder(cgm, row_selection, col_name);
		    } else {
		      col_reorder(cgm, this, col_name);
		    }
	
		    if (params.tile_click_hlight) {
		      add_col_click_hlight(params, this, d.ini);
		    }
		  });
			};
	
	/***/ }),
	/* 132 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function (params, clicked_col, id_clicked_col) {
	
		  if (id_clicked_col != params.click_hlight_col) {
	
		    params.click_hlight_col = id_clicked_col;
	
		    var rel_width_hlight = 6;
		    var opacity_hlight = 0.85;
		    var hlight_width = rel_width_hlight * params.viz.border_width.x;
	
		    d3.selectAll(params.root + ' .click_hlight').remove();
	
		    // // highlight selected column
		    // ///////////////////////////////
		    // // unhilight and unbold all columns (already unbolded earlier)
		    // d3.selectAll('.col_label_text')
		    //   .select('rect')
		    //   .style('opacity', 0);
		    // // highlight column name
		    // d3.select(clicked_col)
		    //   .select('rect')
		    //   .style('opacity', 1);
	
		    d3.select(clicked_col).append('rect').classed('click_hlight', true).classed('col_top_hlight', true).attr('width', params.viz.clust.dim.height).attr('height', hlight_width).attr('fill', params.matrix.hlight_color).attr('opacity', opacity_hlight).attr('transform', function () {
		      var tmp_translate_y = 0;
		      var tmp_translate_x = -(params.viz.clust.dim.height + params.viz.cat_room.col + params.viz.uni_margin);
		      return 'translate(' + tmp_translate_x + ',' + tmp_translate_y + ')';
		    });
	
		    d3.select(clicked_col).append('rect').classed('click_hlight', true).classed('col_bottom_hlight', true).attr('width', params.viz.clust.dim.height).attr('height', hlight_width).attr('fill', params.matrix.hlight_color).attr('opacity', opacity_hlight).attr('transform', function () {
		      // reverse x and y since rotated
		      var tmp_translate_y = params.viz.x_scale.rangeBand() - hlight_width;
		      var tmp_translate_x = -(params.viz.clust.dim.height + params.viz.cat_room.col + params.viz.uni_margin);
		      return 'translate(' + tmp_translate_x + ',' + tmp_translate_y + ')';
		    });
		  } else {
		    d3.selectAll(params.root + ' .click_hlight').remove();
		    params.click_hlight_col = -666;
		  }
			};
	
	/***/ }),
	/* 133 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		// var utils = require('../Utils_clust');
		var reposition_tile_highlight = __webpack_require__(105);
		var toggle_dendro_view = __webpack_require__(106);
		var show_visible_area = __webpack_require__(134);
		var ini_zoom_info = __webpack_require__(88);
		var get_previous_zoom = __webpack_require__(129);
		var calc_downsampled_levels = __webpack_require__(79);
	
		module.exports = function col_reorder(cgm, col_selection, inst_term) {
	
		  var params = cgm.params;
		  var prev_zoom = get_previous_zoom(params);
	
		  if (prev_zoom.zoom_y === 1 && prev_zoom.zoom_x === 1) {
	
		    params.viz.inst_order.col = 'custom';
	
		    toggle_dendro_view(cgm, 'col');
	
		    d3.selectAll(params.root + ' .toggle_row_order .btn').classed('active', false);
	
		    params.viz.run_trans = true;
	
		    var mat = $.extend(true, {}, params.matrix.matrix);
		    var row_nodes = params.network_data.row_nodes;
		    var col_nodes = params.network_data.col_nodes;
	
		    // find the column number of col_selection term from col_nodes
		    // gather column node names
		    var tmp_arr = [];
		    col_nodes.forEach(function (node) {
		      tmp_arr.push(node.name);
		    });
	
		    // find index
		    var inst_col = _.indexOf(tmp_arr, inst_term);
	
		    // gather the values of the input genes
		    tmp_arr = [];
		    row_nodes.forEach(function (node, index) {
		      tmp_arr.push(mat[index].row_data[inst_col].value);
		    });
	
		    // sort the cols
		    var tmp_sort = d3.range(tmp_arr.length).sort(function (a, b) {
		      return tmp_arr[b] - tmp_arr[a];
		    });
	
		    // resort rows (rows are reorderd by double clicking a col)
		    params.viz.y_scale.domain(tmp_sort);
	
		    // save to custom row order
		    params.matrix.orders.custom_col = tmp_sort;
	
		    var t;
	
		    var row_nodes_names = params.network_data.row_nodes_names;
	
		    // reorder
		    if (params.network_data.links.length > params.matrix.def_large_matrix) {
		      t = d3.select(params.root + ' .viz_svg');
		    } else {
		      t = d3.select(params.root + ' .viz_svg').transition().duration(2500);
		    }
	
		    // reorder row_label_triangle groups
		    t.selectAll('.row_cat_group').attr('transform', function (d) {
		      var inst_index = _.indexOf(row_nodes_names, d.name);
		      return 'translate(0,' + params.viz.y_scale(inst_index) + ')';
		    });
	
		    // Move Row Labels
		    t.select('.row_label_zoom_container').selectAll('.row_label_group').attr('transform', function (d) {
		      var inst_index = _.indexOf(row_nodes_names, d.name);
		      return 'translate(0,' + params.viz.y_scale(inst_index) + ')';
		    });
	
		    // only update matri if not downsampled
		    if (params.viz.ds_level === -1) {
		      // reorder matrix rows
		      t.selectAll('.row').attr('transform', function (d) {
		        var inst_index = _.indexOf(row_nodes_names, d.name);
		        return 'translate(0,' + params.viz.y_scale(inst_index) + ')';
		      });
		    }
	
		    // highlight selected column
		    ///////////////////////////////
		    // unhilight and unbold all columns (already unbolded earlier)
		    d3.selectAll(params.root + ' .col_label_text').select('.highlight_rect').style('opacity', 0);
		    // highlight column name
		    d3.select(col_selection).select('.highlight_rect').style('opacity', 1);
	
		    // redefine x and y positions
		    params.network_data.links.forEach(function (d) {
		      d.x = params.viz.x_scale(d.target);
		      d.y = params.viz.y_scale(d.source);
		    });
	
		    reposition_tile_highlight(params);
	
		    params.zoom_info = ini_zoom_info();
	
		    setTimeout(function () {
		      params.viz.run_trans = false;
		    }, 2500);
	
		    // calculate downsmapling if necessary
		    if (params.viz.ds_num_levels > 0 && params.viz.ds_level >= 0) {
	
		      calc_downsampled_levels(params);
	
		      var zooming_stopped = true;
		      var zooming_out = true;
		      var make_all_rows = true;
		      // show_visible_area is also run with two_translate_zoom, but at that point
		      // the parameters were not updated and two_translate_zoom if only run
		      // if needed to reset zoom
		      show_visible_area(cgm, zooming_stopped, zooming_out, make_all_rows);
		    }
		  }
			};
	
	/***/ }),
	/* 134 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var find_viz_rows = __webpack_require__(135);
		var make_matrix_rows = __webpack_require__(93);
		var make_row_labels = __webpack_require__(102);
		var make_row_visual_aid_triangles = __webpack_require__(136);
		var underscore = __webpack_require__(68);
	
		module.exports = function show_visible_area(cgm) {
		  var zooming_stopped = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
		  var zooming_out = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
		  var make_all_rows = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
	
	
		  // console.log('show_visible_area stopped: ' + String(zooming_stopped));
	
		  var params = cgm.params;
		  var zoom_info = params.zoom_info;
	
		  // update ds_level if necessary
		  //////////////////////////////////////////////
		  var check_ds_level = params.viz.ds_level;
		  var old_ds_level = params.viz.ds_level;
	
		  // toggle the downsampling level (if necessary)
		  if (params.viz.ds === null) {
		    check_ds_level = -1;
		  } else {
	
		    check_ds_level = Math.floor(Math.log(zoom_info.zoom_y) / Math.log(params.viz.ds_zt));
	
		    if (check_ds_level > params.viz.ds_num_levels - 1) {
		      check_ds_level = -1;
		    }
		  }
	
		  // check if override_ds is necessary
		  //////////////////////////////////////////////
		  // force update of view if moving to more coarse view
		  var override_ds = false;
	
		  if (old_ds_level == -1) {
		    // transitioning to more coarse downsampling view (from real data)
		    if (check_ds_level >= 0) {
		      override_ds = true;
		    }
		  } else {
		    // transitioning to more coarse downsampling view
		    if (check_ds_level < old_ds_level) {
		      override_ds = true;
		    }
		  }
	
		  // update level if zooming has stopped or if transitioning to more coarse view
		  var new_ds_level;
	
		  if (zooming_stopped === true || override_ds === true) {
	
		    // update new_ds_level if necessary (if decreasing detail, zooming out)
		    new_ds_level = check_ds_level;
	
		    // set zooming_stopped to true in case of override_ds
		    zooming_stopped = true;
	
		    params.viz.ds_level = new_ds_level;
		  } else {
		    // keep the old level (zooming is still occuring and not zooming out)
		    new_ds_level = old_ds_level;
		  }
	
		  var viz_area = {};
		  var buffer_size = 5;
		  // get translation vector absolute values
		  viz_area.min_x = Math.abs(zoom_info.trans_x) / zoom_info.zoom_x - (buffer_size + 1) * params.viz.rect_width;
		  viz_area.min_y = Math.abs(zoom_info.trans_y) / zoom_info.zoom_y - (buffer_size + 1) * params.viz.rect_height;
	
		  viz_area.max_x = Math.abs(zoom_info.trans_x) / zoom_info.zoom_x + params.viz.clust.dim.width / zoom_info.zoom_x + buffer_size * params.viz.rect_width;
	
		  viz_area.max_y = Math.abs(zoom_info.trans_y) / zoom_info.zoom_y + params.viz.clust.dim.height / zoom_info.zoom_y + buffer_size * params.viz.rect_height;
	
		  // generate lists of visible rows/cols
		  find_viz_rows(params, viz_area);
	
		  var missing_rows;
		  if (make_all_rows === false) {
		    missing_rows = _.difference(params.viz.viz_nodes.row, params.viz.viz_nodes.curr_row);
		  } else {
		    // make all rows (reordering)
		    missing_rows = 'all';
	
		    // remove downsampled rows
		    d3.selectAll(params.root + ' .ds' + String(new_ds_level) + '_row').remove();
		  }
	
		  if (params.viz.ds != null) {
		    var ds_row_class = '.ds' + String(params.viz.ds_level) + '_row';
		    d3.selectAll(ds_row_class).style('display', 'block');
		  }
	
		  // if downsampling
		  if (new_ds_level >= 0) {
		    // remove old rows
		    d3.selectAll(params.root + ' .row').remove();
		    // remove tile tooltips and row tooltips
		    d3.selectAll(params.viz.root_tips + '_tile_tip').remove();
		    d3.selectAll(params.viz.root_tips + '_row_tip').remove();
		  }
	
		  // default state for downsampling
		  var inst_matrix;
	
		  if (new_ds_level < 0) {
		    // set matrix to default matrix
		    inst_matrix = params.matrix.matrix;
	
		    // make row visual-aid triangles
		    make_row_visual_aid_triangles(params);
		  } else {
		    // set matrix to downsampled matrix
		    inst_matrix = params.matrix.ds_matrix[new_ds_level];
	
		    d3.selectAll(params.root + ' .row_cat_group path').remove();
		  }
	
		  // also remove row visual aid triangles if zooming out
		  if (zooming_out === true) {
		    d3.selectAll(params.root + ' .row_cat_group path').remove();
		  }
	
		  // remove rows and labels that are not visible and change ds_level
		  /* run when zooming has stopped */
		  if (zooming_stopped === true) {
	
		    // remove not visible matrix rows
		    if (new_ds_level >= 0) {
	
		      // remove downsampled rows
		      d3.selectAll(params.root + ' .ds' + String(new_ds_level) + '_row').each(function (d) {
		        if (underscore.contains(params.viz.viz_nodes.row, d.name) === false) {
		          d3.select(this).remove();
		        }
		      });
		    } else {
		      // remove real data rows
		      d3.selectAll(params.root + ' .row').each(function (d) {
		        if (underscore.contains(params.viz.viz_nodes.row, d.name) === false) {
		          d3.select(this).remove();
		        }
		      });
		    }
	
		    // remove not visible row labels
		    d3.selectAll(params.root + ' .row_label_group').each(function (d) {
		      if (underscore.contains(params.viz.viz_nodes.row, d.name) === false) {
		        d3.select(this).remove();
		      }
		    });
	
		    // level change
		    if (new_ds_level != old_ds_level) {
	
		      // console.log('old: ' + String(old_ds_level) + ' new: '+ String(new_ds_level));
	
		      // all visible rows are missing at new downsampling level
		      missing_rows = params.viz.viz_nodes.row;
	
		      // remove old level rows
		      d3.selectAll(params.root + ' .ds' + String(old_ds_level) + '_row').remove();
		    }
		  }
	
		  // console.log('missing_rows: ' + String(missing_rows))
		  // console.log(missing_rows)
	
		  // only make new matrix_rows if there are missing rows
		  if (missing_rows.length >= 1 || missing_rows === 'all') {
		    make_matrix_rows(params, inst_matrix, missing_rows, new_ds_level);
		  }
	
		  // only make new row_labels if there are missing row_labels, downsampled, and
		  // not zooming out or zooming has stopped
		  if (new_ds_level === -1) {
	
		    if (zooming_out === false || zooming_stopped) {
	
		      // check if labels need to be made
		      ///////////////////////////////////
		      // get the names visible row_labels
		      var visible_row_labels = [];
		      d3.selectAll(params.root + ' .row_label_group').each(function (d) {
		        visible_row_labels.push(d.name);
		      });
	
		      // find missing labels
		      var missing_row_labels = _.difference(params.viz.viz_nodes.row, visible_row_labels);
	
		      // make labels
		      //////////////////////////////////
		      // only make row labels if there are any missing
		      var addback_thresh = 1;
		      if (missing_row_labels.length > addback_thresh) {
		        make_row_labels(cgm, missing_row_labels);
		      }
		    }
		  }
			};
	
	/***/ }),
	/* 135 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function find_viz_rows(params, viz_area) {
	
		  var should_be_rows = [];
		  var curr_rows = [];
	
		  // find rows that should be visible
		  var y_trans;
	
		  // default y_scale (no downsampling)
		  var y_scale = params.viz.y_scale;
		  var ds_level = params.viz.ds_level;
		  var row_names = params.network_data.row_nodes_names;
		  var row_class = '.row';
	
		  // if downsampling redefine variables
		  if (ds_level >= 0) {
		    y_scale = params.viz.ds[ds_level].y_scale;
		    row_names = d3.range(params.matrix.ds_matrix[ds_level].length).map(String);
		    row_class = '.ds' + String(ds_level) + '_row';
		  }
	
		  // find rows that should be visible
		  for (var i = 0; i < row_names.length; i++) {
		    y_trans = y_scale(i);
		    if (y_trans < viz_area.max_y && y_trans > viz_area.min_y) {
		      should_be_rows.push(row_names[i]);
		    }
		  }
	
		  // find currently visible rows
		  d3.selectAll(params.root + ' ' + row_class).each(function (d) {
		    curr_rows.push(d.name);
		  });
	
		  // nodes that should be visible
		  params.viz.viz_nodes.row = should_be_rows;
		  // nodes that are visible
		  params.viz.viz_nodes.curr_row = curr_rows;
			};
	
	/***/ }),
	/* 136 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function make_row_visual_aid_triangles(params) {
	
		  if (d3.select(params.root + ' .row_cat_group path').empty() === true) {
		    d3.selectAll(params.root + ' .row_cat_group').append('path').attr('d', function () {
		      var origin_x = params.viz.cat_room.symbol_width - 1;
		      var origin_y = 0;
		      var mid_x = 1;
		      var mid_y = params.viz.y_scale.rangeBand() / 2;
		      var final_x = params.viz.cat_room.symbol_width - 1;
		      var final_y = params.viz.y_scale.rangeBand();
		      var output_string = 'M ' + origin_x + ',' + origin_y + ' L ' + mid_x + ',' + mid_y + ', L ' + final_x + ',' + final_y + ' Z';
		      return output_string;
		    }).attr('fill', '#eee').style('opacity', params.viz.triangle_opacity);
		  }
			};
	
	/***/ }),
	/* 137 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var d3_tip_custom = __webpack_require__(100);
	
		module.exports = function make_col_tooltips(params) {
	
		  if (params.labels.show_label_tooltips) {
	
		    // remove old col tooltips
		    d3.selectAll(params.viz.root_tips + '_col_tip').remove();
	
		    // d3-tooltip
		    var col_tip = d3_tip_custom().attr('class', function () {
		      var root_tip_selector = params.viz.root_tips.replace('.', '');
		      var class_string = root_tip_selector + ' d3-tip ' + root_tip_selector + '_col_tip';
		      return class_string;
		    }).direction('w').offset([20, 0]).style('display', 'none').html(function (d) {
		      var inst_name = d.name.replace(/_/g, ' ').split('#')[0];
		      return "<span>" + inst_name + "</span>";
		    });
	
		    d3.select(params.viz.viz_wrapper).select('svg').select(params.root + ' .col_zoom_container').selectAll('.col_label_group').select('text').call(col_tip);
	
		    d3.select(params.root + ' .col_zoom_container').selectAll('.col_label_group').on('mouseover', function (d) {
	
		      d3.selectAll(params.viz.root_tips + '_col_tip').style('display', 'block');
	
		      col_tip.show(d);
		      if (params.col_tip_callback != null) {
		        params.col_tip_callback(d);
		      }
		    }).on('mouseout', function () {
		      col_tip.hide(this);
	
		      d3.selectAll(params.viz.root_tips + '_col_tip').style('display', 'none');
		    });
		  }
			};
	
	/***/ }),
	/* 138 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function col_viz_aid_triangle(params) {
	
		  // x and y are flipped since its rotated
		  var reduce_rect_width = params.viz.x_scale.rangeBand() * 0.36;
		  var origin_y = -params.viz.border_width.x;
		  var start_x = 0;
		  var final_x = params.viz.x_scale.rangeBand() - reduce_rect_width;
		  var start_y = -(params.viz.x_scale.rangeBand() - reduce_rect_width + params.viz.border_width.x);
		  var final_y = -params.viz.border_width.x;
		  var output_string = 'M ' + origin_y + ',0 L ' + start_y + ',' + start_x + ', L ' + final_y + ',' + final_x + ' Z';
		  return output_string;
		};
	
	/***/ }),
	/* 139 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function (params) {
	
		  d3.select(params.viz.viz_svg).append('rect').attr('fill', params.viz.background_color).attr('height', params.viz.super_labels.dim.width + 'px').attr('width', '3000px').classed('super_col_bkg', true).classed('white_bars', true).attr('transform', 'translate(' + params.viz.clust.margin.left + ',' + params.viz.super_labels.margin.top + ')');
	
		  d3.select(params.viz.viz_svg).append('text').attr('class', 'super_col').text(params.labels.super.col).attr('text-anchor', 'center').attr('transform', function () {
	
		    var inst_text_width = d3.select(this)[0][0].getBBox().width;
	
		    var inst_x = params.viz.clust.dim.width / 2 + params.viz.norm_labels.width.row - inst_text_width / 2;
		    var inst_y = params.viz.super_labels.dim.width;
		    return 'translate(' + inst_x + ',' + inst_y + ')';
		  }).style('font-size', function () {
		    var inst_font_size = params.labels.super_label_fs * params.labels.super_label_scale;
		    return inst_font_size + 'px';
		  }).style('font-weight', 300);
	
		  d3.select(params.viz.viz_svg).append('rect').attr('fill', params.viz.background_color).attr('width', params.viz.super_labels.dim.width + 'px').attr('height', '3000px').classed('super_row_bkg', true).classed('white_bars', true).attr('transform', 'translate(' + params.viz.super_labels.margin.left + ',0)');
	
		  // append super title row group - used to separate translation from rotation
		  d3.select(params.viz.viz_svg).append('g').classed('super_row', true).attr('transform', function () {
		    // position in the middle of the clustergram
		    var inst_x = params.viz.super_labels.dim.width;
		    var inst_y = params.viz.clust.dim.height / 2 + params.viz.norm_labels.width.col;
		    return 'translate(' + inst_x + ',' + inst_y + ')';
		  });
	
		  // super row label (rotate the already translated title )
		  d3.select(params.root + ' .super_row').append('text').text(params.labels.super.row).attr('text-anchor', 'center').attr('transform', function () {
		    var inst_text_width = d3.select(this)[0][0].getBBox().width;
		    var inst_x_offset = inst_text_width / 2 + params.viz.norm_labels.width.col;
		    var inst_offset = 'translate(0,' + inst_x_offset + '), rotate(-90)';
		    return inst_offset;
		  }).style('font-size', function () {
		    var inst_font_size = params.labels.super_label_fs * params.labels.super_label_scale;
		    return inst_font_size + 'px';
		  }).style('font-weight', 300);
			};
	
	/***/ }),
	/* 140 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var get_cat_title = __webpack_require__(141);
		var ini_cat_reorder = __webpack_require__(142);
		var make_row_cat_super_labels = __webpack_require__(150);
		var make_dendro_crop_buttons = __webpack_require__(112);
	
		module.exports = function Spillover(cgm) {
	
		  var params = cgm.params;
	
		  var viz = params.viz;
	
		  // hide spillover from slanted column labels on right side
		  d3.select(viz.root + ' .col_container').append('path').style('stroke-width', '0').attr('d', 'M 0,0 L 1000,-1000, L 1000,0 Z').attr('fill', viz.background_color) //!! prog_colors
		  .attr('class', 'right_slant_triangle').attr('transform', 'translate(' + viz.clust.dim.width + ',' + viz.norm_labels.width.col + ')');
	
		  // hide spillover from slanted column labels on left side
		  d3.select(viz.root + ' .col_container').append('path').style('stroke-width', '0').attr('d', 'M 0,0 L 500,-500, L 0,-500 Z').attr('fill', viz.background_color).attr('class', 'left_slant_triangle')
		  // shift left by 1 px to prevent cutting off labels
		  .attr('transform', 'translate(-1,' + viz.norm_labels.width.col + ')');
	
		  var rect_height = viz.clust.margin.top + viz.uni_margin / 5;
		  // white rect to cover excess labels
		  d3.select(viz.viz_svg).append('rect').attr('fill', viz.background_color) //!! prog_colors
		  .attr('width', viz.clust.margin.left).attr('height', rect_height).attr('class', 'top_left_white');
	
		  var inst_height = viz.cat_room.col + 1.5 * viz.uni_margin;
		  // white rect to cover excess labels
		  d3.select(viz.viz_svg).append('rect').attr('fill', viz.background_color).attr('width', 2 * viz.clust.dim.width).attr('height', inst_height).attr('class', 'top_right_white').attr('transform', function () {
		    var tmp_left = viz.clust.margin.left + viz.clust.dim.width;
		    var tmp_top = viz.norm_labels.width.col + viz.norm_labels.margin.top - viz.uni_margin;
		    return 'translate(' + tmp_left + ', ' + tmp_top + ')';
		  });
	
		  x_offset = viz.clust.margin.left + viz.clust.dim.width + viz.uni_margin;
		  y_offset = viz.norm_labels.margin.top + viz.norm_labels.width.col + 2.5 * viz.uni_margin;
		  var cat_text_size = 1.15 * viz.cat_room.symbol_width;
		  var cat_super_opacity = 0.65;
		  var extra_y_room = 1.25;
	
		  // col category super labels
		  if (viz.show_categories.col) {
	
		    d3.select(viz.viz_svg).selectAll().data(viz.all_cats.col).enter().append('text').classed('col_cat_super', true).style('font-size', cat_text_size + 'px').style('opacity', cat_super_opacity).style('cursor', 'default').attr('transform', function (d) {
		      var inst_cat = parseInt(d.split('-')[1], 10);
		      var inst_y = y_offset + extra_y_room * viz.cat_room.symbol_width * inst_cat;
		      return 'translate(' + x_offset + ',' + inst_y + ')';
		    }).text(function (d) {
		      return get_cat_title(viz, d, 'col');
		    });
		  }
	
		  // row category super labels
		  make_row_cat_super_labels(cgm);
	
		  // white border bottom - prevent clustergram from hitting border
		  if (viz.show_dendrogram) {
		    // quick fix to make room for crop buttons
		    y_offset = viz.clust.margin.top + viz.clust.dim.height + viz.dendro_room.col - 2 * viz.uni_margin;
		  } else {
		    y_offset = viz.clust.margin.top + viz.clust.dim.height;
		  }
	
		  var b_spill_container = d3.select(viz.viz_svg).append('g').classed('bottom_spillover_container', true).attr('transform', function () {
		    // shift up enough to show the entire border width
		    return 'translate(0,' + y_offset + ')';
		  });
	
		  b_spill_container.append('rect').attr('class', 'bottom_spillover').attr('fill', viz.background_color) //!! prog_colors
		  .attr('width', viz.svg_dim.width).attr('height', 2 * viz.svg_dim.height);
	
		  x_offset = viz.clust.margin.left;
		  y_offset = 0;
		  b_spill_container.append('g').classed('col_dendro_icons_container', true).attr('transform', 'translate(' + x_offset + ',' + y_offset + ')').append('g').classed('col_dendro_icons_group', true);
	
		  if (params.viz.show_dendrogram) {
		    make_dendro_crop_buttons(cgm, 'col');
		  }
	
		  var x_offset = viz.clust.margin.left + viz.clust.dim.width;
		  var y_offset = viz.clust.margin.top + viz.clust.dim.height;
		  var tmp_width = viz.cat_room.col + viz.clust.dim.width;
		  var tmp_height = viz.cat_room.row + 10 * viz.uni_margin;
		  d3.select(viz.viz_svg).append('rect').attr('fill', viz.background_color).attr('width', tmp_width).attr('height', tmp_height).attr('transform', function () {
		    return 'translate(' + x_offset + ',' + y_offset + ')';
		  }).classed('white_bars', true).classed('dendro_corner_spillover', true);
	
		  // hide spillover left top of col dendrogram
		  x_offset = 0;
		  y_offset = viz.clust.margin.top + viz.clust.dim.height;
		  tmp_width = viz.clust.margin.left;
		  tmp_height = viz.clust.dim.height * 10;
		  d3.select(viz.viz_svg).append('rect').attr('fill', viz.background_color).attr('width', tmp_width).attr('height', tmp_height).attr('transform', function () {
		    return 'translate(' + x_offset + ',' + y_offset + ')';
		  }).classed('white_bars', true).classed('dendro_col_spillover', true);
	
		  ini_cat_reorder(cgm);
			};
	
	/***/ }),
	/* 141 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function get_cat_title(viz, inst_cat, inst_rc) {
		  var cat_title;
	
		  // make default title if none is given
		  if (viz.cat_names[inst_rc][inst_cat] === inst_cat) {
		    var inst_num = parseInt(inst_cat.split('-')[1], 10) + 1;
		    // generate placeholder title
		    cat_title = 'Category ' + inst_num;
		  } else {
		    // make real title
		    cat_title = viz.cat_names[inst_rc][inst_cat];
		  }
	
		  return cat_title;
			};
	
	/***/ }),
	/* 142 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var all_reorder = __webpack_require__(143);
	
		module.exports = function ini_cat_reorder(cgm) {
		  /* eslint-disable */
	
		  var params = cgm.params;
	
		  _.each(['row', 'col'], function (inst_rc) {
	
		    if (params.viz.show_categories[inst_rc]) {
		      d3.selectAll(params.root + ' .' + inst_rc + '_cat_super').on('dblclick', function () {
	
		        if (params.sim_mat) {
		          inst_rc = 'both';
		        }
	
		        d3.selectAll(params.root + ' .toggle_' + inst_rc + '_order .btn').classed('active', false);
	
		        var order_id = this.__data__.replace('-', '_') + '_index';
		        if (params.viz.sim_mat) {
		          all_reorder(cgm, order_id, 'row');
		          all_reorder(cgm, order_id, 'col');
		        } else {
		          all_reorder(cgm, order_id, inst_rc);
		        }
		      });
		    }
		  });
		};
	
	/***/ }),
	/* 143 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var toggle_dendro_view = __webpack_require__(106);
		var show_visible_area = __webpack_require__(134);
		var ini_zoom_info = __webpack_require__(88);
		var calc_downsampled_levels = __webpack_require__(79);
		var two_translate_zoom = __webpack_require__(144);
		var get_previous_zoom = __webpack_require__(129);
	
		module.exports = function (cgm, inst_order, inst_rc) {
	
		  var params = cgm.params;
	
		  var prev_zoom = get_previous_zoom(params);
	
		  var delay_reorder = 0;
		  if (prev_zoom.zoom_y != 1 || prev_zoom.zoom_x != 1) {
		    // reset zoom before reordering
		    two_translate_zoom(cgm, 0, 0, 1);
		    delay_reorder = 1200;
		  }
	
		  // row/col names are swapped, will improve later
		  var other_rc;
		  if (inst_rc === 'row') {
		    other_rc = 'col';
		  } else if (inst_rc === 'col') {
		    other_rc = 'row';
		  }
	
		  params.viz.run_trans = true;
	
		  // save order state
		  if (other_rc === 'row') {
		    params.viz.inst_order.row = inst_order;
		  } else if (other_rc === 'col') {
		    params.viz.inst_order.col = inst_order;
		  }
	
		  if (params.viz.show_dendrogram) {
		    toggle_dendro_view(cgm, inst_rc);
		  }
	
		  if (other_rc === 'row') {
		    params.viz.x_scale.domain(params.matrix.orders[params.viz.inst_order.row + '_row']);
		  } else if (other_rc == 'col') {
		    params.viz.y_scale.domain(params.matrix.orders[params.viz.inst_order.col + '_col']);
		  }
	
		  // only animate transition if there are a small number of tiles
		  var t;
		  if (d3.selectAll(params.root + ' .tile')[0].length < params.matrix.def_large_matrix) {
		    t = d3.select(params.root + ' .viz_svg').transition().duration(2500).delay(delay_reorder);
		  } else {
		    t = d3.select(params.root + ' .viz_svg');
		  }
	
		  var row_nodes_names = params.network_data.row_nodes_names;
		  var col_nodes_names = params.network_data.col_nodes_names;
	
		  // only update matrix if not downsampled (otherwise rows are updated)
		  if (params.viz.ds_level === -1) {
	
		    t.selectAll('.row').attr('transform', function (d) {
		      var inst_index = _.indexOf(row_nodes_names, d.name);
		      return 'translate(0,' + params.viz.y_scale(inst_index) + ')';
		    }).selectAll('.tile').attr('transform', function (d) {
		      return 'translate(' + params.viz.x_scale(d.pos_x) + ' , 0)';
		    });
	
		    t.selectAll('.tile_up').attr('transform', function (d) {
		      return 'translate(' + params.viz.x_scale(d.pos_x) + ' , 0)';
		    });
	
		    t.selectAll('.tile_dn').attr('transform', function (d) {
		      return 'translate(' + params.viz.x_scale(d.pos_x) + ' , 0)';
		    });
		  }
	
		  // Move Row Labels
		  t.select('.row_label_zoom_container').selectAll('.row_label_group').attr('transform', function (d) {
		    var inst_index = _.indexOf(row_nodes_names, d.name);
		    return 'translate(0,' + params.viz.y_scale(inst_index) + ')';
		  });
	
		  // Move Col Labels
		  t.select('.col_zoom_container').selectAll('.col_label_text').attr('transform', function (d) {
		    var inst_index = _.indexOf(col_nodes_names, d.name);
		    return 'translate(' + params.viz.x_scale(inst_index) + ') rotate(-90)';
		  });
	
		  // reorder row categories
		  t.selectAll('.row_cat_group').attr('transform', function (d) {
		    var inst_index = _.indexOf(row_nodes_names, d.name);
		    return 'translate(0,' + params.viz.y_scale(inst_index) + ')';
		  });
	
		  // reorder col_class groups
		  t.selectAll('.col_cat_group').attr('transform', function (d) {
		    var inst_index = _.indexOf(col_nodes_names, d.name);
		    return 'translate(' + params.viz.x_scale(inst_index) + ',0)';
		  });
	
		  // redefine x and y positions
		  params.network_data.links.forEach(function (d) {
		    d.x = params.viz.x_scale(d.target);
		    d.y = params.viz.y_scale(d.source);
		  });
	
		  params.zoom_info = ini_zoom_info();
	
		  // calculate downsmapling if necessary
		  if (params.viz.ds_num_levels > 0 && params.viz.ds_level >= 0) {
	
		    calc_downsampled_levels(params);
		    var zooming_stopped = true;
		    var zooming_out = true;
		    var make_all_rows = true;
	
		    // show_visible_area is also run with two_translate_zoom, but at that point
		    // the parameters were not updated and two_translate_zoom if only run
		    // if needed to reset zoom
		    show_visible_area(cgm, zooming_stopped, zooming_out, make_all_rows);
		  }
	
		  setTimeout(function () {
		    params.viz.run_trans = false;
		  }, 2500);
			};
	
	/***/ }),
	/* 144 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
		var label_constrain_and_trim = __webpack_require__(145);
		var show_visible_area = __webpack_require__(134);
		var ini_zoom_info = __webpack_require__(88);
		var toggle_grid_lines = __webpack_require__(149);
	
		module.exports = function two_translate_zoom(cgm, pan_dx, pan_dy, fin_zoom) {
	
		  // console.log('pan_dy: ' + String(pan_dy))
	
		  var params = cgm.params;
	
		  d3.selectAll(params.viz.root_tips).style('display', 'none');
	
		  params.zoom_info = ini_zoom_info();
	
		  show_visible_area(cgm);
	
		  // do not allow while transitioning, e.g. reordering
		  if (!params.viz.run_trans) {
	
		    // define the commonly used variable half_height
		    var half_height = params.viz.clust.dim.height / 2;
	
		    // y pan room, the pan room has to be less than half_height since
		    // zooming in on a gene that is near the top of the clustergram also causes
		    // panning out of the visible region
		    var y_pan_room = half_height / fin_zoom;
	
		    // prevent visualization from panning down too much
		    // when zooming into genes near the top of the clustergram
		    if (pan_dy >= half_height - y_pan_room) {
	
		      // console.log(' prevent visualization from panning down too much')
	
		      // explanation of panning rules
		      /////////////////////////////////
		      /*
		        prevent the clustergram from panning down too much
		        if the amount of panning is equal to the half_height then it needs to be reduced
		        effectively, the the visualization needs to be moved up (negative) by some factor
		        of the half-width-of-the-visualization.
		         If there was no zooming involved, then the
		        visualization would be centered first, then panned to center the top term
		        this would require a
		        correction to re-center it. However, because of the zooming the offset is
		        reduced by the zoom factor (this is because the panning is occurring on something
		        that will be zoomed into - this is why the pan_dy value is not scaled in the two
		        translate transformations, but it has to be scaled afterwards to set the translate
		        vector)
		        pan_dy = half_height - (half_height)/fin_zoom
		         if pan_dy is greater than the pan room, then panning has to be restricted
		        start by shifting back up (negative) by half_height/fin_zoom then shift back down
		        by the difference between half_height and pan_dy (so that the top of the clustergram is
		        visible)
		      */
	
		      var shift_top_viz = half_height - pan_dy;
		      var shift_up_viz = -half_height / fin_zoom + shift_top_viz;
	
		      // reduce pan_dy so that the visualization does not get panned to far down
		      pan_dy = pan_dy + shift_up_viz;
		    }
	
		    // prevent visualization from panning up too much
		    // when zooming into genes at the bottom of the clustergram
		    if (pan_dy < -(half_height - y_pan_room)) {
	
		      shift_top_viz = half_height + pan_dy;
	
		      shift_up_viz = half_height / fin_zoom - shift_top_viz; //- move_up_one_row;
	
		      // reduce pan_dy so that the visualization does not get panned to far down
		      pan_dy = pan_dy + shift_up_viz;
		    }
	
		    // will improve this !!
		    var zoom_y = fin_zoom;
		    var zoom_x = 1;
	
		    // search duration - the duration of zooming and panning
		    var search_duration = 700;
	
		    // center_y
		    var center_y = -(zoom_y - 1) * half_height;
	
		    // transform clust group
		    ////////////////////////////
		    d3.select(params.root + ' .clust_group').transition().duration(search_duration)
		    // first apply the margin transformation
		    // then zoom, then apply the final transformation
		    .attr('transform', 'translate(' + [0, 0 + center_y] + ')' + ' scale(' + zoom_x + ',' + zoom_y + ')' + 'translate(' + [pan_dx, pan_dy] + ')');
	
		    // transform row labels
		    d3.select(params.root + ' .row_label_zoom_container').transition().duration(search_duration).attr('transform', 'translate(' + [0, center_y] + ')' + ' scale(' + zoom_y + ',' + zoom_y + ')' + 'translate(' + [0, pan_dy] + ')');
	
		    // transform row_cat_container
		    // use the offset saved in params, only zoom in the y direction
		    d3.select(params.root + ' .row_cat_container').transition().duration(search_duration).attr('transform', 'translate(' + [0, center_y] + ')' + ' scale(' + 1 + ',' + zoom_y + ')' + 'translate(' + [0, pan_dy] + ')');
	
		    d3.select(params.root + ' .row_dendro_container').transition().duration(search_duration).attr('transform', 'translate(' + [0, center_y] + ')' + ' scale(' + zoom_x + ',' + zoom_y + ')' + 'translate(' + [params.viz.uni_margin / 2, pan_dy] + ')');
	
		    // toggle crop buttons
		    var inst_button_opacity;
		    _.each(['row', 'col'], function (inst_rc) {
	
		      inst_button_opacity = d3.select(params.root + ' .' + inst_rc + '_dendro_crop_buttons').style('opacity');
		      d3.selectAll(params.root + ' .' + inst_rc + '_dendro_crop_buttons').style('opacity', 0);
		      setTimeout(show_crop_buttons, 700, inst_rc, inst_button_opacity);
		    });
	
		    // transform col labels
		    d3.select(params.root + ' .col_zoom_container').transition().duration(search_duration).attr('transform', ' scale(' + zoom_x + ',' + zoom_x + ')' + 'translate(' + [pan_dx, 0] + ')');
	
		    // transform col_class
		    d3.select(params.root + ' .col_cat_container').transition().duration(search_duration).attr('transform', ' scale(' + zoom_x + ',' + 1 + ')' + 'translate(' + [pan_dx, 0] + ')');
	
		    d3.select(params.root + ' .col_dendro_container').transition().duration(search_duration).attr('transform', ' scale(' + zoom_x + ',' + 1 + ')' + 'translate(' + [pan_dx, params.viz.uni_margin / 2] + ')');
	
		    // set y translate: center_y is positive, positive moves the visualization down
		    // the translate vector has the initial margin, the first y centering, and pan_dy
		    // times the scaling zoom_y
		    var net_y_offset = params.viz.clust.margin.top + center_y + pan_dy * zoom_y;
		    var net_x_offset = params.viz.clust.margin.left + pan_dx;
	
		    // reset the zoom and translate
		    params.zoom_behavior.scale(zoom_y).translate([net_x_offset, net_y_offset]);
	
		    label_constrain_and_trim(params);
	
		    // re-size of the highlighting rects
		    /////////////////////////////////////////
		    if (d3.select(params.root + ' .row_label_zoom_container text').empty() === false) {
		      d3.select(params.root + ' .row_label_zoom_container').each(function () {
		        // get the bounding box of the row label text
		        var bbox = d3.select(this).select('text')[0][0].getBBox();
	
		        // use the bounding box to set the size of the rect
		        d3.select(this).select('rect').attr('x', bbox.x * 0.5).attr('y', 0).attr('width', bbox.width * 0.5).attr('height', params.viz.y_scale.rangeBand()).style('fill', 'yellow');
		      });
		    }
	
		    // reset crop button zooming
		    d3.select(params.root + ' .row_dendro_icons_group').attr('transform', 'translate(' + [0, 0 + center_y] + ')' + ' scale(' + zoom_x + ',' + zoom_y + ')' + 'translate(' + [pan_dx, pan_dy] + ')');
	
		    d3.select(params.root + ' .row_dendro_icons_group').selectAll('path').attr('transform', function (d) {
		      var inst_x = params.viz.uni_margin;
		      var inst_y = d.pos_mid;
		      return 'translate(' + inst_x + ',' + inst_y + ') ' + 'scale(1, ' + 1 / zoom_y + ')';
		    });
	
		    // console.log('zooming x and y')
		    // console.log(zoom_x)
		    // console.log(zoom_y)
	
		    // need to improve behavior
		    d3.select(params.root + ' .col_dendro_icons_group').attr('transform', function () {
		      var inst_trans =
		      // 'translate(' + [0, 0 + center_y] + ')' +
		      ' scale(' + zoom_x + ',' + zoom_y + ')';
		      // + 'translate(' + [pan_dx, pan_dy ] + ')';
		      return inst_trans;
		    });
	
		    d3.select(params.root + ' .col_dendro_icons_group').selectAll('path').attr('transform', function (d) {
		      var inst_x = d.pos_mid;
		      var inst_y = params.viz.uni_margin;
		      // return 'translate('+ inst_x +',' + inst_y + ') ' + 'scale('+1/zoom_x+',1)';
		      return 'translate(' + inst_x + ',' + inst_y + ') ' + 'scale(1,1)';
		    });
	
		    // column value bars
		    ///////////////////////
		    // reduce the height of the column value bars based on the zoom applied
		    // recalculate the height and divide by the zooming scale
		    // col_label_obj.select('rect')
		    if (utils.has(params.network_data.col_nodes[0], 'value')) {
	
		      d3.selectAll(params.root + ' .col_bars').attr('width', function (d) {
		        var inst_value = 0;
		        if (d.value > 0) {
		          inst_value = params.labels.bar_scale_col(d.value) / zoom_x;
		        }
		        return inst_value;
		      });
		    }
	
		    if (utils.has(params.network_data.row_nodes[0], 'value')) {
	
		      d3.selectAll(params.root + ' .row_bars').transition().duration(search_duration).attr('width', function (d) {
		        var inst_value = 0;
		        inst_value = params.labels.bar_scale_row(Math.abs(d.value)) / zoom_y;
		        return inst_value;
		      }).attr('x', function (d) {
		        var inst_value = 0;
		        inst_value = -params.labels.bar_scale_row(Math.abs(d.value)) / zoom_y;
		        return inst_value;
		      });
		    }
	
		    toggle_grid_lines(params);
		  }
	
		  function show_crop_buttons(inst_rc, inst_button_opacity) {
		    d3.selectAll(params.root + ' .' + inst_rc + '_dendro_crop_buttons').transition().duration(search_duration).style('opacity', inst_button_opacity);
		  }
			};
	
	/***/ }),
	/* 145 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
		var trim_text = __webpack_require__(146);
		var constrain_font_size = __webpack_require__(147);
	
		module.exports = function label_constrain_and_trim(params) {
	
		  // console.log('label_constrain_and_trim');
	
		  // reset text in rows and columns
		  d3.selectAll(params.root + ' .row_label_group').select('text').text(function (d) {
		    return utils.normal_name(d);
		  });
	
		  d3.selectAll(params.root + ' .col_label_text').select('text').text(function (d) {
		    return utils.normal_name(d);
		  });
	
		  constrain_font_size(params);
	
		  d3.selectAll(params.root + ' .row_label_group').each(function () {
		    trim_text(params, this, 'row');
		  });
	
		  d3.selectAll(params.root + ' .col_label_group').each(function () {
		    trim_text(params, this, 'col');
		  });
			};
	
	/***/ }),
	/* 146 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function (params, inst_selection, inst_rc) {
		  if (d3.select(inst_selection).style('display') != 'none') {
	
		    // trim text that is longer than the container
		    var inst_zoom;
		    var inst_width;
		    var trimmed_text;
		    var current_num_char;
		    var inst_text;
		    var original_text;
		    var keep_num_char;
		    var i;
	
		    var max_width = params.viz.norm_labels.width[inst_rc];
	
		    if (inst_rc === 'row') {
		      if (params.viz.zoom_ratio.y) {
		        inst_zoom = params.zoom_behavior.scale() / params.viz.zoom_ratio.y;
		      } else {
		        inst_zoom = params.zoom_behavior.scale();
		      }
		      // num_trims = params.labels.row_max_char;
		    } else {
		      if (params.viz.zoom_ratio.x > 1) {
		        inst_zoom = params.zoom_behavior.scale() / params.viz.zoom_ratio.x;
		      } else {
		        inst_zoom = params.zoom_behavior.scale();
		      }
		      // num_trims = params.labels.col_max_char;
		    }
	
		    var num_trims;
		    d3.select(inst_selection).select('text').each(function (d) {
		      num_trims = d.name.length;
		    });
	
		    var tmp_width = d3.select(inst_selection).select('text').node().getBBox().width;
	
		    inst_width = calc_width(tmp_width, inst_zoom);
	
		    if (inst_width > max_width) {
	
		      for (i = 1; i < num_trims; i++) {
		        if (inst_width > max_width) {
	
		          d3.select(inst_selection).select('text').text(trim);
	
		          tmp_width = d3.select(inst_selection).select('text').node().getBBox().width;
	
		          inst_width = calc_width(tmp_width, inst_zoom);
		        }
		      }
		    } else if (inst_width < max_width * 0.75) {
	
		      for (i = 1; i < num_trims; i++) {
		        if (inst_width < max_width * 0.75) {
	
		          d3.select(inst_selection).select('text').text(add_back);
	
		          tmp_width = d3.select(inst_selection).select('text').node().getBBox().width;
	
		          inst_width = calc_width(tmp_width, inst_zoom);
		        }
		      }
		    }
		  }
	
		  function trim() {
		    inst_text = d3.select(this).text();
		    current_num_char = inst_text.length;
		    keep_num_char = current_num_char - 3;
		    trimmed_text = inst_text.substring(0, keep_num_char) + '..';
		    return trimmed_text;
		  }
	
		  function add_back(d) {
		    inst_text = d3.select(this).text();
		    if (inst_text.slice(-2) === '..') {
		      current_num_char = inst_text.length - 2;
		    } else {
		      current_num_char = inst_text.length;
		    }
	
		    original_text = d.name;
		    keep_num_char = current_num_char + 2;
		    trimmed_text = original_text.substring(0, keep_num_char) + '..';
	
		    // if '..' was added to original text
		    if (trimmed_text.length > original_text.length) {
		      trimmed_text = original_text;
		    }
	
		    return trimmed_text;
		  }
	
		  function calc_width(tmp_width, inst_zoom) {
		    if (inst_zoom < 1) {
		      inst_width = tmp_width;
		    } else {
		      inst_width = tmp_width * inst_zoom;
		    }
	
		    return inst_width;
		  }
			};
	
	/***/ }),
	/* 147 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var calc_real_font_size = __webpack_require__(148);
	
		module.exports = function constrain_font_size(params) {
	
		  var tmp_font_size = params.labels.default_fs_row;
		  var inst_zoom;
		  var min_font_size = 3;
	
		  var real_font_size = calc_real_font_size(params);
	
		  // rows
		  ////////////////////////////////////
		  if (real_font_size.row > min_font_size) {
	
		    if (real_font_size.row > params.labels.max_allow_fs) {
	
		      if (params.viz.zoom_ratio.y) {
		        inst_zoom = params.zoom_behavior.scale() / params.viz.zoom_ratio.y;
		      } else {
		        inst_zoom = params.zoom_behavior.scale();
		      }
	
		      if (inst_zoom < 1) {
		        inst_zoom = 1;
		      }
	
		      tmp_font_size = params.labels.max_allow_fs / inst_zoom;
	
		      d3.selectAll(params.root + ' .row_label_group').select('text').style('font-size', tmp_font_size + 'px').attr('y', params.viz.rect_height * 0.5 + tmp_font_size * 0.35);
		    } else {
		      d3.selectAll(params.root + ' .row_label_group').select('text').style('font-size', params.labels.default_fs_row + 'px').attr('y', params.viz.rect_height * 0.5 + params.labels.default_fs_row * 0.35);
		    }
		  }
	
		  // columns
		  //////////////////////////////////////
		  if (real_font_size.col > min_font_size) {
	
		    if (real_font_size.col > params.labels.max_allow_fs) {
	
		      if (params.viz.zoom_ratio.x > 1) {
		        inst_zoom = params.zoom_behavior.scale() / params.viz.zoom_ratio.x;
		      } else {
		        inst_zoom = params.zoom_behavior.scale();
		      }
	
		      if (inst_zoom < 1) {
		        inst_zoom = 1;
		      }
	
		      tmp_font_size = params.labels.max_allow_fs / inst_zoom;
	
		      if (tmp_font_size > 0.7 * params.viz.rect_width) {
		        tmp_font_size = 0.7 * params.viz.rect_width;
		      }
	
		      d3.selectAll(params.root + ' .col_label_text').select('text').style('font-size', tmp_font_size + 'px');
		    } else {
		      d3.selectAll(params.root + ' .col_label_text').select('text').style('font-size', params.labels.default_fs_col + 'px');
		    }
		  }
			};
	
	/***/ }),
	/* 148 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function calc_real_font_size(params) {
	
		  var real_font_size = {};
		  // zoom_switch behavior has to change with zoom_ratio.y
		  if (params.viz.zoom_ratio.x > 1) {
		    real_font_size.row = params.labels.default_fs_row * params.zoom_behavior.scale();
		    real_font_size.col = params.labels.default_fs_col * params.zoom_behavior.scale();
		  } else {
		    real_font_size.row = params.labels.default_fs_row * params.zoom_behavior.scale() / params.viz.zoom_ratio.y;
		    real_font_size.col = params.labels.default_fs_col * params.zoom_behavior.scale();
		  }
	
		  return real_font_size;
			};
	
	/***/ }),
	/* 149 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function toggle_grid_lines(params) {
	
		  if (params.zoom_info.zoom_x * params.viz.border_width.x > 1) {
		    d3.selectAll(params.root + ' .vert_lines').select('line').style('display', 'block').style('opacity', 0).transition().style('opacity', 1);
		  } else {
		    d3.selectAll(params.root + ' .vert_lines').select('line').style('display', 'none');
		  }
	
		  if (params.zoom_info.zoom_y * params.viz.border_width.y > 1) {
		    d3.selectAll(params.root + ' .horz_lines').select('line').style('display', 'block').style('opacity', 0).transition().style('opacity', 1);
		  } else {
		    d3.selectAll(params.root + ' .horz_lines').select('line').style('display', 'none');
		  }
		};
	
	/***/ }),
	/* 150 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var get_cat_title = __webpack_require__(141);
		var d3_tip_custom = __webpack_require__(100);
	
		module.exports = function make_row_cat_super_labels(cgm) {
	
		  var params = cgm.params;
	
		  var viz = params.viz;
		  var extra_x_room = 2.75;
	
		  if (d3.select(params.root + ' .row_cat_label_container').empty()) {
	
		    d3.select(cgm.params.viz.viz_svg).append('g').classed('row_cat_label_container', true);
	
		    // append background section for optional value-bars (e.g. enrichment pvals)
		    d3.select(cgm.params.viz.viz_svg + ' .row_cat_label_container').append('g').classed('row_cat_label_bar_container', true);
		  }
	
		  var x_offset = viz.clust.margin.left + viz.clust.dim.width + viz.uni_margin;
		  var y_offset = viz.norm_labels.margin.top + viz.norm_labels.width.col + 2.5 * viz.uni_margin;
		  var cat_text_size = 1.15 * viz.cat_room.symbol_width;
		  var cat_super_opacity = 0.65;
		  var extra_y_room = 1.25;
	
		  d3.select(params.root + ' .row_cat_label_container').attr('transform', function () {
		    x_offset = viz.norm_labels.margin.left + viz.norm_labels.width.row + viz.cat_room.symbol_width + extra_x_room * viz.uni_margin;
		    y_offset = viz.clust.margin.top - viz.uni_margin;
		    return 'translate(' + x_offset + ',' + y_offset + ') rotate(-90)';
		  });
	
		  // clear old categories
		  d3.selectAll(params.root + ' .row_cat_label_container text').remove();
		  d3.selectAll(params.root + ' .row_cat_selection_bar').remove();
		  // d3.selectAll(params.root+' .row_cat_label_bar_container rect').remove();
	
		  // remove any old row_cat_super tooltips from this visualization
		  d3.selectAll(cgm.params.viz.root_tips + '_row_cat_super').remove();
	
		  // d3-tooltip
		  var tmp_y_offset = 50; // viz.clust.margin.top - viz.uni_margin;
		  var tmp_x_offset = -75;
		  var cat_tip = d3_tip_custom().attr('class', function () {
		    var root_tip_selector = params.viz.root_tips.replace('.', '');
		    var class_string = root_tip_selector + ' d3-tip ' + root_tip_selector + '_row_cat_super';
		    return class_string;
		  }).direction('south_custom').offset([tmp_y_offset, tmp_x_offset]).style('display', 'none').style('opacity', 0).html(function (d) {
	
		    var full_string;
	
		    var tmp_string = params.network_data.row_nodes[0][d];
	
		    if (tmp_string.indexOf('<p>') > -1) {
	
		      var start_string = tmp_string.split(': ')[0];
		      var end_string = tmp_string.split('<p>')[1];
	
		      full_string = start_string + '<p>' + end_string;
		    } else {
	
		      full_string = get_cat_title(viz, d, 'row');
		    }
	
		    return full_string;
		  });
	
		  var unit_length = extra_y_room * viz.cat_room.symbol_width;
		  var bar_width = unit_length * 0.9;
	
		  // show row label categories even if viewing a simmilarity matrix
	
		  d3.select(params.root + ' .row_cat_label_container').selectAll().data(viz.all_cats.row).enter().append('text').style('width', '100px').style('height', bar_width + 'px').classed('row_cat_super', true).style('font-size', cat_text_size + 'px').style('opacity', cat_super_opacity).style('cursor', 'default').attr('transform', function (d) {
		    var inst_y = extra_y_room * viz.cat_room.symbol_width * parseInt(d.split('-')[1], 10);
		    return 'translate(0,' + inst_y + ')';
		  }).text(function (d) {
	
		    return get_cat_title(viz, d, 'row');
		  });
	
		  // selection bar
		  ///////////////////////////////
		  d3.select(params.root + ' .row_cat_label_container').selectAll().data(viz.all_cats.row).enter().append('rect').classed('row_cat_super', true).classed('row_cat_selection_bar', true).style('height', bar_width + 'px').style('fill', 'green').style('width', '120px').style('opacity', 0).attr('transform', function (d) {
		    var inst_y = unit_length * (parseInt(d.split('-')[1], 10) - 0.75);
		    return 'translate(0,' + inst_y + ')';
		  }).on('mouseover', function (d) {
	
		    d3.selectAll(params.viz.root_tips + '_row_cat_super').style('display', 'block').style('opacity', 1);
	
		    cat_tip.show(d);
		  }).on('mouseout', function () {
		    cat_tip.hide(this);
		    // might not need
		    d3.selectAll('.d3-tip').style('display', 'none');
	
		    d3.selectAll(params.viz.root_tips + '_row_cat_super').style('display', 'none').style('opacity', 0);
		  });
	
		  // row category super-label mouseover
		  //////////////////////////////////////
		  if (d3.select(params.root + ' .row_cat_selection_bar').empty() === false) {
		    d3.selectAll(params.root + ' .row_cat_selection_bar').call(cat_tip);
		  }
	
		  if (_.has(params.network_data, 'row_cat_bars')) {
	
		    // Enrichrgram title
		    /////////////////////
		    d3.select(params.root + ' .enr_title').remove();
	
		    var enr_title = d3.select(params.root + ' .viz_svg').append('g').classed('enr_title', true).attr('transform', function () {
		      var trans = d3.select(params.root + ' .row_cat_label_container').attr('transform').split('(')[1].split(')')[0];
		      var x_offset = Number(trans.split(',')[0]) - 10;
	
		      return 'translate(' + String(x_offset) + ', 0)';
		    });
	
		    enr_title.append('rect').attr('width', params.viz.cat_room.row).attr('height', 25).attr('fill', 'white');
	
		    var library_string = params.network_data.enrichrgram_lib.substring(0, 40);
	
		    enr_title.append('text').attr('transform', 'translate(0, 17)').text(library_string.replace(/_/g, ' ')).style('font-size', '15px').attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif');
	
		    // Enrichr bars
		    ////////////////////
		    d3.selectAll(params.root + ' .enrichr_bars').remove();
	
		    var bar_height = params.viz.clust.margin.top - 35;
		    var max_score = params.network_data.row_cat_bars[0];
		    var bar_scale = d3.scale.linear().domain([0, max_score]).range([0, bar_height]);
	
		    d3.select(params.root + ' .row_cat_label_bar_container').selectAll().data(params.network_data.row_cat_bars).enter().append('rect').classed('enrichr_bars', true).attr('height', bar_width + 'px').attr('fill', 'red').attr('width', function (d) {
		      var bar_length = bar_scale(d);
		      return bar_length + 'px';
		    }).attr('opacity', 0.4).attr('transform', function (d, i) {
		      var inst_y = unit_length * (i - 0.75);
		      return 'translate(0, ' + inst_y + ')';
		    });
		  }
			};
	
	/***/ }),
	/* 151 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var resize_viz = __webpack_require__(152);
	
		module.exports = function initialize_resizing(cgm) {
	
		  var params = cgm.params;
	
		  var exp_button;
	
		  // d3.select(window).on('resize', null);
	
		  // // resize window
		  // if (params.viz.resize) {
		  //   d3.select(window).on('resize', function () {
	
		  //     d3.select(params.viz.viz_svg).style('opacity', 0.5);
	
		  //     var wait_time = 500;
		  //     if (params.viz.run_trans === true) {
		  //       wait_time = 2500;
		  //     }
	
		  //     setTimeout(resize_viz, wait_time, params);
		  //   });
		  // }
	
		  // if (params.viz.expand_button) {
	
		  d3.select(params.root + ' .expand_button').on('click', null);
		  var expand_opacity = 0.4;
	
		  if (d3.select(params.root + ' .expand_button').empty()) {
		    exp_button = d3.select(params.viz.viz_svg).append('text').attr('class', 'expand_button');
		  } else {
		    exp_button = d3.select(params.root + ' .expand_button');
		  }
	
		  exp_button.attr('text-anchor', 'middle').attr('dominant-baseline', 'central').attr('font-family', 'FontAwesome').attr('font-size', '30px').text(function () {
		    if (params.viz.is_expand === false) {
		      // expand button
		      return '\uF0B2';
		    } else {
		      // menu button
		      return '\uF0C9';
		    }
		  }).attr('y', '25px').attr('x', '25px').style('cursor', 'pointer').style('opacity', expand_opacity).on('mouseover', function () {
		    d3.select(this).style('opacity', 0.75);
		  }).on('mouseout', function () {
		    d3.select(this).style('opacity', expand_opacity);
		  }).on('click', function () {
	
		    // expand view
		    if (params.viz.is_expand === false) {
	
		      d3.select(this).text(function () {
		        // menu button
		        return '\uF0C9';
		      });
		      params.viz.is_expand = true;
	
		      d3.selectAll(params.root + ' .borders').style('fill', 'white');
		      // d3.select(params.root+' .footer_section').style('display', 'none');
		      d3.select(params.root + ' .sidebar_wrapper').style('display', 'none');
	
		      // contract view
		    } else {
	
		      d3.select(this).text(function () {
		        // expand button
		        return '\uF0B2';
		      });
	
		      params.viz.is_expand = false;
	
		      d3.selectAll(params.root + ' .borders').style('fill', '#eee');
		      // d3.select(params.root+' .footer_section').style('display', 'block');
		      d3.select(params.root + ' .viz_wrapper').style('width', '100px');
		      d3.select(params.root + ' .sidebar_wrapper').style('display', 'block');
		    }
	
		    // // resize parent div
		    // set_viz_wrapper_size(params);
	
		    d3.select(params.viz.viz_svg).style('opacity', 0.5);
		    var wait_time = 500;
		    if (params.viz.run_trans == true) {
		      wait_time = 2500;
		    }
		    setTimeout(resize_viz, wait_time, cgm);
		  });
		  // }
		};
	
	/***/ }),
	/* 152 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
		var run_zoom = __webpack_require__(153);
		var ini_doubleclick = __webpack_require__(161);
		var reset_zoom = __webpack_require__(162);
		var resize_dendro = __webpack_require__(163);
		var resize_super_labels = __webpack_require__(164);
		var resize_spillover = __webpack_require__(165);
		var resize_borders = __webpack_require__(166);
		var resize_row_labels = __webpack_require__(167);
		var resize_highlights = __webpack_require__(168);
		var resize_row_viz = __webpack_require__(169);
		var resize_col_labels = __webpack_require__(170);
		var resize_col_text = __webpack_require__(171);
		var resize_col_triangle = __webpack_require__(172);
		var resize_col_hlight = __webpack_require__(173);
		var recalc_params_for_resize = __webpack_require__(174);
		var resize_row_tiles = __webpack_require__(175);
		var resize_label_bars = __webpack_require__(176);
		var label_constrain_and_trim = __webpack_require__(145);
		var make_dendro_triangles = __webpack_require__(107);
		var toggle_dendro_view = __webpack_require__(106);
		var show_visible_area = __webpack_require__(134);
		var calc_viz_dimensions = __webpack_require__(70);
		var position_play_button = __webpack_require__(177);
		var make_row_cat_super_labels = __webpack_require__(150);
		var ini_cat_reorder = __webpack_require__(142);
		var position_svg_dendro_slider = __webpack_require__(178);
		var ini_zoom_info = __webpack_require__(88);
		var grid_lines_viz = __webpack_require__(179);
	
		module.exports = function resize_viz(cgm) {
	
		  var params = cgm.params;
	
		  var cont_dim = calc_viz_dimensions(params);
	
		  d3.select(params.root + ' .play_button');
		  // .style('opacity', 0.2);
	
	
		  d3.select(params.root + ' .sidebar_wrapper').style('height', cont_dim.height + 'px');
	
		  d3.select(params.viz.viz_wrapper)
		  // .style('float', 'left')
		  .style('margin-top', cont_dim.top + 'px').style('width', cont_dim.width + 'px').style('height', cont_dim.height + 'px');
	
		  params = recalc_params_for_resize(params);
	
		  params.zoom_info = ini_zoom_info();
	
		  reset_zoom(params);
	
		  var svg_group = d3.select(params.viz.viz_svg);
	
		  // redefine x and y positions
		  _.each(params.network_data.links, function (d) {
		    d.x = params.viz.x_scale(d.target);
		    d.y = params.viz.y_scale(d.source);
		  });
	
		  // disable zoom while transitioning
		  svg_group.on('.zoom', null);
	
		  params.zoom_behavior.scaleExtent([1, params.viz.square_zoom * params.viz.zoom_ratio.x]).on('zoom', function () {
		    run_zoom(cgm);
		  });
	
		  // reenable zoom after transition
		  if (params.viz.do_zoom) {
		    svg_group.call(params.zoom_behavior);
		  }
	
		  // prevent normal double click zoom etc
		  ini_doubleclick(cgm);
	
		  svg_group.attr('width', params.viz.svg_dim.width).attr('height', params.viz.svg_dim.height);
	
		  svg_group.select('.super_background').style('width', params.viz.svg_dim.width).style('height', params.viz.svg_dim.height);
	
		  svg_group.select('.grey_background').attr('width', params.viz.clust.dim.width).attr('height', params.viz.clust.dim.height);
	
		  setTimeout(position_play_button, 100, params);
	
		  var row_nodes = params.network_data.row_nodes;
		  var row_nodes_names = utils.pluck(row_nodes, 'name');
	
		  resize_row_tiles(params, svg_group);
	
		  svg_group.selectAll('.highlighting_rect').attr('width', params.viz.x_scale.rangeBand() * 0.80).attr('height', params.viz.y_scale.rangeBand() * 0.80);
	
		  resize_highlights(params);
	
		  // resize row labels
		  ///////////////////////////
	
		  resize_row_labels(params, svg_group);
		  resize_row_viz(params, svg_group);
	
		  // change the size of the highlighting rects
		  svg_group.selectAll('.row_label_group').each(function () {
		    var bbox = d3.select(this).select('text')[0][0].getBBox();
		    d3.select(this).select('rect').attr('x', bbox.x).attr('y', 0).attr('width', bbox.width).attr('height', params.viz.rect_height).style('fill', 'yellow').style('opacity', function (d) {
		      var inst_opacity = 0;
		      // highlight target genes
		      if (d.target === 1) {
		        inst_opacity = 1;
		      }
		      return inst_opacity;
		    });
		  });
	
		  // necessary to properly position row labels vertically
		  svg_group.selectAll('.row_label_group').select('text').attr('y', params.viz.rect_height * 0.5 + params.labels.default_fs_row * 0.35);
	
		  if (utils.has(params.network_data.row_nodes[0], 'value')) {
		    resize_label_bars(cgm, svg_group);
		  }
	
		  svg_group.selectAll('.row_cat_group').attr('transform', function (d) {
		    var inst_index = _.indexOf(row_nodes_names, d.name);
		    return 'translate(0, ' + params.viz.y_scale(inst_index) + ')';
		  });
	
		  svg_group.selectAll('.row_cat_group').select('path').attr('d', function () {
		    var origin_x = params.viz.cat_room.symbol_width - 1;
		    var origin_y = 0;
		    var mid_x = 1;
		    var mid_y = params.viz.rect_height / 2;
		    var final_x = params.viz.cat_room.symbol_width - 1;
		    var final_y = params.viz.rect_height;
		    var output_string = 'M ' + origin_x + ',' + origin_y + ' L ' + mid_x + ',' + mid_y + ', L ' + final_x + ',' + final_y + ' Z';
		    return output_string;
		  });
	
		  var is_resize = true;
		  if (params.viz.show_dendrogram) {
		    make_dendro_triangles(cgm, 'row', is_resize);
		    make_dendro_triangles(cgm, 'col', is_resize);
		    resize_dendro(params, svg_group);
	
		    toggle_dendro_view(cgm, 'row', 0);
		    toggle_dendro_view(cgm, 'col', 0);
		  } else {
		    resize_dendro(params, svg_group);
		  }
	
		  resize_col_labels(params, svg_group);
		  resize_col_text(params, svg_group);
		  resize_col_triangle(params, svg_group);
		  resize_col_hlight(params, svg_group);
	
		  resize_super_labels(params, svg_group);
		  resize_spillover(params.viz, svg_group);
	
		  grid_lines_viz(params);
	
		  resize_borders(params, svg_group);
	
		  // reset zoom and translate
		  params.zoom_behavior.scale(1).translate([params.viz.clust.margin.left, params.viz.clust.margin.top]);
	
		  label_constrain_and_trim(params);
	
		  // reposition matrix
		  d3.select(params.root + ' .clust_container').attr('transform', 'translate(' + params.viz.clust.margin.left + ',' + params.viz.clust.margin.top + ')');
	
		  // removed, this was causing bugs
		  if (cgm.params.viz.ds_level === -1) {
		    show_visible_area(cgm);
		  }
	
		  make_row_cat_super_labels(cgm);
	
		  d3.select(params.viz.viz_svg).style('opacity', 1);
	
		  ini_cat_reorder(cgm);
	
		  d3.select(cgm.params.root + ' .row_slider_group').style('opacity', 0);
		  d3.select(cgm.params.root + ' .col_slider_group').style('opacity', 0);
	
		  setTimeout(position_svg_dendro_slider, 500, cgm, 'row');
		  setTimeout(position_svg_dendro_slider, 500, cgm, 'col');
			};
	
	/***/ }),
	/* 153 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var run_transformation = __webpack_require__(154);
		var zoom_rules_y = __webpack_require__(159);
		var zoom_rules_x = __webpack_require__(160);
	
		module.exports = function zoomed(cgm) {
	
		  var params = cgm.params;
	
		  var zoom_info = {};
		  zoom_info.zoom_x = d3.event.scale;
		  zoom_info.zoom_y = d3.event.scale;
	
		  // subtract away the margin to easily calculate pan_room etc.
		  zoom_info.trans_x = params.zoom_behavior.translate()[0] - params.viz.clust.margin.left;
		  zoom_info.trans_y = params.zoom_behavior.translate()[1] - params.viz.clust.margin.top;
	
		  d3.selectAll(params.viz.root_tips).style('display', 'none');
	
		  // transfer zoom_info to params
		  params.zoom_info = zoom_rules_y(params, zoom_info);
		  params.zoom_info = zoom_rules_x(params, zoom_info);
	
		  // do not run transformation if moving slider
		  if (params.is_slider_drag === false && params.is_cropping === false) {
	
		    // reset translate vector - add back margins to trans_x and trans_y
		    var new_x = params.zoom_info.trans_x + params.viz.clust.margin.left;
		    var new_y = params.zoom_info.trans_y + params.viz.clust.margin.top;
	
		    params.zoom_behavior.translate([new_x, new_y]);
		    cgm.params = params;
	
		    run_transformation(cgm);
		  }
			};
	
	/***/ }),
	/* 154 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var constrain_font_size = __webpack_require__(147);
		var show_visible_area = __webpack_require__(134);
		var resize_label_val_bars = __webpack_require__(155);
		var zoom_crop_triangles = __webpack_require__(114);
		var get_previous_zoom = __webpack_require__(129);
		var run_when_zoom_stopped = __webpack_require__(156);
		var check_zoom_stop_status = __webpack_require__(158);
	
		module.exports = function run_transformation(cgm) {
	
		  var params = cgm.params;
	
		  var zoom_info = params.zoom_info;
	
		  var prev_zoom = get_previous_zoom(params);
	
		  d3.select(params.root + ' .clust_group').attr('transform', 'translate(' + [zoom_info.trans_x, zoom_info.trans_y] + ') scale(' + zoom_info.zoom_x + ',' + zoom_info.zoom_y + ')');
	
		  d3.select(params.root + ' .row_label_zoom_container').attr('transform', 'translate(' + [0, zoom_info.trans_y] + ') scale(' + zoom_info.zoom_y + ')');
	
		  d3.select(params.root + ' .col_zoom_container').attr('transform', 'translate(' + [zoom_info.trans_x, 0] + ') scale(' + zoom_info.zoom_x + ')');
	
		  d3.select(params.root + ' .row_cat_container').attr('transform', 'translate(' + [0, zoom_info.trans_y] + ') scale( 1,' + zoom_info.zoom_y + ')');
	
		  d3.select(params.root + ' .row_dendro_container').attr('transform', 'translate(' + [params.viz.uni_margin / 2, zoom_info.trans_y] + ') ' + 'scale( 1,' + zoom_info.zoom_y + ')');
	
		  d3.select(params.root + ' .row_dendro_icons_group').attr('transform', function () {
		    var inst_y = zoom_info.trans_y;
		    var inst_translate = 'translate(' + [0, inst_y] + ') ';
		    var inst_zoom = 'scale(1, ' + zoom_info.zoom_y + ')';
		    var transform_string = inst_translate + inst_zoom;
		    return transform_string;
		  });
	
		  d3.select(params.root + ' .col_dendro_icons_group').attr('transform', function () {
		    var inst_x = zoom_info.trans_x;
		    var inst_translate = 'translate(' + [inst_x, 0] + ')';
		    var inst_zoom = 'scale(' + zoom_info.zoom_x + ', 1)';
		    var transform_string = inst_translate + inst_zoom;
		    return transform_string;
		  });
	
		  zoom_crop_triangles(params, zoom_info, 'row');
		  zoom_crop_triangles(params, zoom_info, 'col');
	
		  d3.select(params.root + ' .col_cat_container').attr('transform', 'translate(' + [zoom_info.trans_x, 0] + ') scale(' + zoom_info.zoom_x + ',1)');
	
		  d3.select(params.root + ' .col_dendro_container').attr('transform', 'translate(' + [zoom_info.trans_x, params.viz.uni_margin / 2] + ') scale(' + zoom_info.zoom_x + ',1)');
	
		  resize_label_val_bars(params, zoom_info);
	
		  d3.select(params.root + ' .viz_svg').attr('is_zoom', function () {
		    var inst_zoom = Number(d3.select(params.root + ' .viz_svg').attr('is_zoom'));
		    d3.select(params.root + ' .viz_svg').attr('stopped_zoom', 1);
		    return inst_zoom + 1;
		  });
	
		  // this function runs with a slight delay and tells the visualization that
		  // this particular zoom event is over, reducing the total number of zoom
		  // events that need to finish
		  var not_zooming = function not_zooming() {
	
		    d3.select(params.root + ' .viz_svg').attr('is_zoom', function () {
		      var inst_zoom = Number(d3.select(params.root + ' .viz_svg').attr('is_zoom'));
		      return inst_zoom - 1;
		    });
		  };
	
		  constrain_font_size(params);
	
		  if (zoom_info.zoom_y <= prev_zoom.zoom_y) {
	
		    var zooming_out = false;
		    if (zoom_info.zoom_y < prev_zoom.zoom_y) {
		      zooming_out = true;
		    }
	
		    // zooming has not stopped and zooming out is true
		    var zooming_stopped = false;
		    show_visible_area(cgm, zooming_stopped, zooming_out);
		  }
	
		  setTimeout(not_zooming, 50);
		  setTimeout(check_if_zooming_has_stopped, 100, cgm);
	
		  function check_if_zooming_has_stopped(cgm) {
		    var params = cgm.params;
	
		    var stop_attributes = check_zoom_stop_status(params);
	
		    if (stop_attributes === true) {
		      // wait and double check that zooming has stopped
		      setTimeout(run_when_zoom_stopped, 50, cgm);
		    }
		  }
			};
	
	/***/ }),
	/* 155 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
	
		module.exports = function resize_label_val_bars(params) {
	
		  var zoom_info = params.zoom_info;
	
		  // resize label bars if necessary
		  if (utils.has(params.network_data.row_nodes[0], 'value')) {
		    d3.selectAll(params.root + ' .row_bars').attr('width', function (d) {
		      var inst_value = 0;
		      inst_value = params.labels.bar_scale_row(Math.abs(d.value)) / zoom_info.zoom_y;
		      return inst_value;
		    }).attr('x', function (d) {
		      var inst_value = 0;
		      inst_value = -params.labels.bar_scale_row(Math.abs(d.value)) / zoom_info.zoom_y;
		      return inst_value;
		    });
		  }
	
		  if (utils.has(params.network_data.col_nodes[0], 'value')) {
		    d3.selectAll(params.root + ' .col_bars').attr('width', function (d) {
		      var inst_value = 0;
		      if (d.value > 0) {
		        inst_value = params.labels.bar_scale_col(d.value) / zoom_info.zoom_x;
		      }
		      return inst_value;
		    });
		  }
			};
	
	/***/ }),
	/* 156 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var constrain_font_size = __webpack_require__(147);
		var trim_text = __webpack_require__(146);
		var num_visible_labels = __webpack_require__(157);
		var toggle_grid_lines = __webpack_require__(149);
		var show_visible_area = __webpack_require__(134);
		var check_zoom_stop_status = __webpack_require__(158);
	
		module.exports = function run_when_zoom_stopped(cgm) {
	
		  var params = cgm.params;
	
		  var stop_attributes = check_zoom_stop_status(params);
	
		  if (stop_attributes === true) {
	
		    // ///////////////////////////////////////////////
		    // // zooming has stopped
		    // ///////////////////////////////////////////////
		    // console.log('\nZOOMING HAS ACTUALLY STOPPED\n============================');
		    // console.log(params.zoom_info.zoom_y)
	
		    _.each(['row', 'col'], function (inst_rc) {
	
		      d3.selectAll(params.root + ' .' + inst_rc + '_label_group').select('text').style('opacity', 1);
	
		      d3.selectAll(params.root + ' .' + inst_rc + '_cat_group').select('path').style('display', 'block');
		    });
	
		    show_visible_area(cgm, true);
	
		    d3.selectAll(params.viz.root_tips).style('display', 'block');
	
		    d3.selectAll(params.root + ' .row_label_group').select('text').style('display', 'none');
		    d3.selectAll(params.root + ' .row_label_group').select('text').style('display', 'block');
	
		    d3.select(params.root + ' .viz_svg').attr('stopped_zoom', 0);
	
		    d3.selectAll(params.root + ' .row_label_group').select('text').style('display', 'block');
		    d3.selectAll(params.root + ' .col_label_group').select('text').style('display', 'block');
	
		    toggle_grid_lines(params);
	
		    // reset x_offset
		    cgm.params.viz.x_offset = 0;
	
		    var max_labels_to_trim = 150;
		    // probably do not need
		    /////////////////////////
		    _.each(['row', 'col'], function (inst_rc) {
	
		      var inst_num_visible = num_visible_labels(params, inst_rc);
	
		      if (inst_num_visible < max_labels_to_trim) {
		        d3.selectAll(params.root + ' .' + inst_rc + '_label_group').each(function () {
		          trim_text(params, this, inst_rc);
		        });
		      }
		    });
	
		    text_patch();
	
		    constrain_font_size(params);
	
		    // this makes sure that the text is visible after zooming and trimming
		    // there is buggy behavior in chrome when zooming into large matrices
		    // I'm running it twice in quick succession
		    setTimeout(text_patch, 100);
		  }
	
		  function text_patch() {
	
		    _.each(['row', 'col'], function (inst_rc) {
	
		      d3.selectAll(params.root + ' .' + inst_rc + '_label_group').filter(function () {
		        return d3.select(this).style('display') != 'none';
		      }).select('text').style('font-size', function () {
		        var inst_fs = Number(d3.select(this).style('font-size').replace('px', ''));
		        return inst_fs;
		      });
		    });
		  }
			};
	
	/***/ }),
	/* 157 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function num_visible_labels(params, inst_rc) {
	
		  // counting the number of visible labels, probably not necessary
	
		  var num_visible;
		  if (inst_rc === 'row') {
	
		    // initialize at high number
		    num_visible = 10000;
	
		    // only count visible rows if no downsampling
		    if (params.viz.ds_level === -1) {
		      num_visible = d3.selectAll(params.root + ' .row')[0].length;
		    }
		  } else if (inst_rc === 'col') {
	
		    num_visible = d3.selectAll(params.root + ' .' + inst_rc + '_label_text').filter(function () {
		      return d3.select(this).style('display') != 'none';
		    })[0].length;
		  }
	
		  return num_visible;
		};
	
	/***/ }),
	/* 158 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function check_zoom_stop_status(params) {
	
		  var inst_zoom = Number(d3.select(params.root + ' .viz_svg').attr('is_zoom'));
	
		  var check_stop = Number(d3.select(params.root + ' .viz_svg').attr('stopped_zoom'));
	
		  var stop_attributes = false;
		  if (inst_zoom === 0 && check_stop != 0) {
		    stop_attributes = true;
		  }
	
		  return stop_attributes;
		};
	
	/***/ }),
	/* 159 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function zoom_rules_y(params, zoom_info) {
	
		  var viz = params.viz;
		  // zoom in the x direction before zooming in the y direction
		  if (viz.zoom_ratio.y > 1) {
		    if (zoom_info.zoom_y < viz.zoom_ratio.y) {
		      zoom_info.trans_y = 0;
		      zoom_info.zoom_y = 1;
		    } else {
		      zoom_info.zoom_y = zoom_info.zoom_y / viz.zoom_ratio.y;
		    }
		  }
	
		  // calculate panning room available in the y direction
		  zoom_info.pan_room_y = (zoom_info.zoom_y - 1) * viz.clust.dim.height;
	
		  // console.log( 'pan_room_y: ' +  String(zoom_info.pan_room_y) + ' ' + String(-zoom_info.trans_y))
	
		  // no positive panning or panning more than pan_room
		  if (zoom_info.trans_y >= 0) {
		    zoom_info.trans_y = 0;
		    // console.log('y no positive panning\n\n')
		  } else if (zoom_info.trans_y <= -zoom_info.pan_room_y) {
		    zoom_info.trans_y = -zoom_info.pan_room_y;
		    // console.log('y restrict pan room \n\n')
		  }
	
		  return zoom_info;
		};
	
	/***/ }),
	/* 160 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function zoom_rules_x(params, zoom_info) {
	
		  var viz = params.viz;
	
		  // zoom in the y direction before zooming in the x direction
		  if (viz.zoom_ratio.x > 1) {
	
		    if (zoom_info.zoom_x < viz.zoom_ratio.x) {
	
		      // remove this
		      // zoom_info.trans_x = - params.viz.clust.margin.left;
	
		      zoom_info.zoom_x = 1;
		    } else {
		      zoom_info.zoom_x = zoom_info.zoom_x / viz.zoom_ratio.x;
	
		      // console.log('********* zoom_x: ' + String(zoom_info.zoom_x))
	
		      // zoom_info.trans_x = zoom_info.trans_x + params.viz.x_offset;
		      // zoom_info.trans_x = zoom_info.trans_x * (params.zoom_info.zoom_x/params.zoom_info.zoom_y);
		    }
		  }
	
		  // calculate panning room available in the x direction
		  zoom_info.pan_room_x = (zoom_info.zoom_x - 1) * viz.clust.dim.width;
	
		  // console.log( 'pan_room_x: ' +  String(zoom_info.pan_room_x) + ' trans_x: ' + String(-zoom_info.trans_x))
	
		  // no positive panning or panning more than pan_room
		  if (zoom_info.trans_x > 0) {
		    zoom_info.trans_x = 0;
		    // console.log('no positive panning\n\n')
		  } else if (zoom_info.trans_x <= -zoom_info.pan_room_x) {
		    zoom_info.trans_x = -zoom_info.pan_room_x;
		    // console.log('******* restrict pan room\n\n')
		  }
	
		  return zoom_info;
		};
	
	/***/ }),
	/* 161 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var two_translate_zoom = __webpack_require__(144);
	
		module.exports = function ini_doubleclick(cgm) {
	
		  var params = cgm.params;
		  // disable double-click zoom
		  d3.selectAll(params.viz.zoom_element).on('dblclick.zoom', null);
	
		  d3.select(params.viz.zoom_element).on('dblclick', function () {
		    two_translate_zoom(cgm, 0, 0, 1);
		  });
		};
	
	/***/ }),
	/* 162 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function (params) {
	
		  // reset zoom
		  //////////////////////////////
		  var zoom_y = 1;
		  // var zoom_x = 1;
		  var pan_dx = 0;
		  var pan_dy = 0;
	
		  var half_height = params.viz.clust.dim.height / 2;
		  var center_y = -(zoom_y - 1) * half_height;
	
		  d3.select(params.root + ' .clust_group').attr('transform', 'translate(' + [0, 0 + center_y] + ')' + ' scale(' + 1 + ',' + zoom_y + ')' + 'translate(' + [pan_dx, pan_dy] + ')');
	
		  d3.select(params.root + ' .row_label_zoom_container').attr('transform', 'translate(' + [0, center_y] + ')' + ' scale(' + zoom_y + ',' + zoom_y + ')' + 'translate(' + [0, pan_dy] + ')');
	
		  d3.select(params.root + ' .row_cat_container').attr('transform', 'translate(' + [0, center_y] + ')' + ' scale(' + 1 + ',' + zoom_y + ')' + 'translate(' + [0, pan_dy] + ')');
	
		  d3.select(params.root + ' .row_dendro_container').attr('transform', 'translate(' + [0, center_y] + ')' + ' scale(' + zoom_y + ',' + zoom_y + ')' + 'translate(' + [params.viz.uni_margin / 2, pan_dy] + ')');
	
		  d3.select(params.root + ' .col_zoom_container').attr('transform', ' scale(' + 1 + ',' + 1 + ')' + 'translate(' + [pan_dx, 0] + ')');
	
		  d3.select(params.root + ' .col_cat_container').attr('transform', ' scale(' + 1 + ',' + 1 + ')' + 'translate(' + [pan_dx, 0] + ')');
	
		  d3.select(params.root + ' .col_dendro_container').attr('transform', ' scale(' + 1 + ',' + 1 + ')' + 'translate(' + [pan_dx, params.viz.uni_margin / 2] + ')');
	
		  // reset crop button zooming
		  d3.select(params.root + ' .row_dendro_icons_group').attr('transform', function () {
		    return 'translate(0,0) scale(1)';
		  });
	
		  d3.select(params.root + ' .row_dendro_icons_group').selectAll('path').attr('transform', function (d) {
		    var inst_x = 7;
		    var inst_y = d.pos_mid;
		    return 'translate(' + inst_x + ',' + inst_y + ') ' + 'scale(1, 1)';
		  });
			};
	
	/***/ }),
	/* 163 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function resize_dendro(params, svg_group) {
		  var delay_info = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
	
	
		  // resize dendrogram
		  ///////////////////
	
		  var delays = {};
	
		  if (delay_info === false) {
		    delays.run_transition = false;
		  } else {
		    delays = delay_info;
		  }
	
		  var duration = params.viz.duration;
		  var col_nodes = params.network_data.col_nodes;
		  var col_nodes_names = params.network_data.col_nodes_names;
	
		  var dendro_group;
		  if (delays.run_transition) {
	
		    dendro_group = svg_group.transition().delay(delays.update).duration(duration);
	
		    svg_group.selectAll('.col_cat_group')
		    // data binding needed for loss/gain of columns
		    .data(col_nodes, function (d) {
		      return d.name;
		    }).transition().delay(delays.update).duration(duration).attr('transform', function (d) {
		      var inst_index = _.indexOf(col_nodes_names, d.name);
		      return 'translate(' + params.viz.x_scale(inst_index) + ',0)';
		    });
	
		    svg_group.selectAll('.col_dendro_group')
		    // data binding needed for loss/gain of columns
		    .data(col_nodes, function (d) {
		      return d.name;
		    }).transition().delay(delays.update).duration(duration).attr('transform', function (d) {
		      var inst_index = _.indexOf(col_nodes_names, d.name);
		      return 'translate(' + params.viz.x_scale(inst_index) + ',0)';
		    });
		  } else {
	
		    dendro_group = svg_group;
	
		    svg_group.selectAll('.col_cat_group')
		    // data binding needed for loss/gain of columns
		    .data(col_nodes, function (d) {
		      return d.name;
		    }).attr('transform', function (d) {
		      var inst_index = _.indexOf(col_nodes_names, d.name);
		      return 'translate(' + params.viz.x_scale(inst_index) + ',0)';
		    });
	
		    d3.select(params.root).selectAll('.col_dendro_group')
		    // data binding needed for loss/gain of columns
		    .data(col_nodes, function (d) {
		      return d.name;
		    }).attr('transform', function (d) {
		      var inst_index = _.indexOf(col_nodes_names, d.name);
		      return 'translate(' + params.viz.x_scale(inst_index) + ',0)';
		    });
		  }
	
		  var i;
		  var inst_class;
	
		  _.each(['row', 'col'], function (inst_rc) {
	
		    var num_cats = params.viz.all_cats[inst_rc].length;
	
		    for (i = 0; i < num_cats; i++) {
		      inst_class = '.' + inst_rc + '_cat_rect_' + String(i);
	
		      if (inst_rc === 'row') {
		        dendro_group.selectAll(inst_class).attr('height', params.viz.y_scale.rangeBand());
		      } else {
		        dendro_group.selectAll(inst_class).attr('width', params.viz.x_scale.rangeBand());
		      }
		    }
		  });
	
		  // position row_dendro_outer_container
		  var x_offset = params.viz.clust.margin.left + params.viz.clust.dim.width;
		  var y_offset = params.viz.clust.margin.top;
		  var spillover_width = params.viz.dendro_room.row + params.viz.uni_margin;
	
		  d3.select(params.root + ' .viz_svg').select('row_dendro_outer_container').attr('transform', 'translate(' + x_offset + ',' + y_offset + ')');
	
		  d3.select(params.root + ' .row_dendro_outer_container').select('.row_dendro_spillover').attr('width', spillover_width + 'px').attr('height', params.viz.svg_dim.height);
	
		  x_offset = params.viz.clust.margin.left;
		  y_offset = params.viz.clust.margin.top + params.viz.clust.dim.height;
		  var spillover_height = params.viz.dendro_room.col + params.viz.uni_margin;
	
		  d3.select(params.root + ' .col_dendro_outer_container').select('.col_dendro_spillover').attr('width', params.viz.svg_dim.width).attr('height', spillover_height + 'px');
	
		  d3.select(params.root + ' .col_dendro_outer_container').select('.col_dendro_spillover_top').attr('width', params.viz.svg_dim.width).attr('height', params.viz.svg_dim.height).attr('transform', 'translate(0,' + params.viz.dendro_room.col + ')');
	
		  x_offset = params.viz.clust.margin.left;
		  y_offset = 0;
		  d3.select(params.root + ' .col_dendro_icons_container').attr('transform', 'translate(' + x_offset + ',' + y_offset + ')');
			};
	
	/***/ }),
	/* 164 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function resize_super_labels(params, ini_svg_group) {
		  var delay_info = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
	
	
		  var delays = {};
		  var duration = params.viz.duration;
		  var svg_group;
	
		  if (delay_info === false) {
		    delays.run_transition = false;
		  } else {
		    delays = delay_info;
		  }
	
		  if (delays.run_transition) {
		    svg_group = ini_svg_group.transition().delay(delays.update).duration(duration);
		  } else {
		    svg_group = ini_svg_group;
		  }
	
		  svg_group.select('.super_col_bkg').attr('height', params.viz.super_labels.dim.width + 'px').attr('transform', 'translate(' + params.viz.clust.margin.left + ',' + params.viz.grey_border_width + ')');
	
		  // super col title
		  svg_group.select('.super_col').attr('transform', function () {
		    var inst_x = params.viz.clust.dim.width / 2 + params.viz.norm_labels.width.row;
		    var inst_y = params.viz.super_labels.dim.width;
		    return 'translate(' + inst_x + ',' + inst_y + ')';
		  });
	
		  svg_group.select('.super_row_bkg').attr('width', params.viz.super_labels.dim.width + 'px').attr('transform', 'translate(' + params.viz.grey_border_width + ',0)');
	
		  svg_group.select('.super_row').attr('transform', function () {
		    var inst_x = params.viz.super_labels.dim.width;
		    var inst_y = params.viz.clust.dim.height / 2 + params.viz.norm_labels.width.col;
		    return 'translate(' + inst_x + ',' + inst_y + ')';
		  });
			};
	
	/***/ }),
	/* 165 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function resize_spillover(viz, ini_svg_group) {
		  var delay_info = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
	
	
		  var delays = {};
		  var duration = viz.duration;
		  var svg_group;
	
		  if (delay_info === false) {
		    delays.run_transition = false;
		  } else {
		    delays = delay_info;
		  }
	
		  if (delays.run_transition) {
		    svg_group = ini_svg_group.transition().delay(delays.update).duration(duration);
		  } else {
		    svg_group = ini_svg_group;
		  }
	
		  svg_group.select(viz.root + ' .right_slant_triangle').attr('transform', 'translate(' + viz.clust.dim.width + ',' + viz.norm_labels.width.col + ')');
	
		  svg_group.select(viz.root + ' .left_slant_triangle').attr('transform', 'translate(-1,' + viz.norm_labels.width.col + ')');
	
		  var rect_height = viz.clust.margin.top + viz.uni_margin / 5;
		  svg_group.select(viz.root + ' .top_left_white').attr('width', viz.clust.margin.left).attr('height', rect_height);
	
		  var tmp_left = viz.clust.margin.left + viz.clust.dim.width + viz.uni_margin + viz.dendro_room.row;
		  var tmp_top = viz.norm_labels.margin.top + viz.norm_labels.width.col;
	
		  svg_group.select(viz.root + ' .right_spillover_container').attr('transform', function () {
		    return 'translate(' + tmp_left + ', 0)';
		  });
	
		  tmp_top = viz.norm_labels.margin.top + viz.norm_labels.width.col;
	
		  svg_group.select(viz.root + ' .right_spillover_container rect').attr('transform', function () {
		    return 'translate( 0,' + tmp_top + ')';
		  });
	
		  svg_group.select(viz.root + ' .right_spillover').attr('height', viz.svg_dim.height + 'px');
	
		  // resize dendro spillovers
		  var x_offset = viz.clust.margin.left + viz.clust.dim.width;
		  var y_offset = tmp_top;
		  var tmp_width = viz.dendro_room.row + viz.uni_margin;
		  var tmp_height = viz.cat_room.col + viz.uni_margin;
		  d3.select(viz.root + ' .dendro_row_spillover').attr('width', tmp_width).attr('height', tmp_height).attr('transform', function () {
		    return 'translate(' + x_offset + ',' + y_offset + ')';
		  });
	
		  // hide spillover left top of col dendrogram
		  x_offset = 0;
		  y_offset = viz.clust.margin.top + viz.clust.dim.height;
		  tmp_width = viz.clust.margin.left;
		  tmp_height = viz.clust.dim.height * 10;
	
		  svg_group.select('.dendro_col_spillover').attr('width', tmp_width).attr('height', tmp_height).attr('transform', function () {
		    return 'translate(' + x_offset + ',' + y_offset + ')';
		  });
	
		  x_offset = viz.clust.margin.left + viz.clust.dim.width;
		  y_offset = viz.clust.margin.top + viz.clust.dim.height;
		  tmp_width = viz.cat_room.col + viz.clust.dim.width;
		  tmp_height = viz.cat_room.row + viz.uni_margin;
	
		  svg_group.select('.dendro_corner_spillover').attr('width', tmp_width).attr('height', tmp_height).attr('transform', function () {
		    return 'translate(' + x_offset + ',' + y_offset + ')';
		  });
	
		  x_offset = viz.clust.margin.left + viz.clust.dim.width + viz.uni_margin;
		  y_offset = viz.norm_labels.margin.top + viz.norm_labels.width.col + 2.5 * viz.uni_margin;
		  var extra_x_room = 2.75;
		  var extra_y_room = 1.2;
	
		  // reposition category superlabels
		  if (viz.show_categories.col) {
	
		    d3.selectAll(viz.root + ' .col_cat_super').attr('transform', function (d) {
		      var inst_cat = parseInt(d.split('-')[1], 10);
		      var inst_y = y_offset + extra_y_room * viz.cat_room.symbol_width * inst_cat;
		      return 'translate(' + x_offset + ',' + inst_y + ')';
		    });
		  }
	
		  if (viz.show_categories.row) {
		    d3.select(viz.root + ' .row_cat_label_container').attr('transform', function () {
		      x_offset = viz.norm_labels.margin.left + viz.norm_labels.width.row + viz.cat_room.symbol_width + extra_x_room * viz.uni_margin;
		      y_offset = viz.clust.margin.top - viz.uni_margin;
		      return 'translate(' + x_offset + ',' + y_offset + ') rotate(-90)';
		    });
		  }
	
		  // white border bottom - prevent clustergram from hitting border
		  if (viz.show_dendrogram) {
		    y_offset = viz.clust.margin.top + viz.clust.dim.height + viz.dendro_room.col - 2 * viz.uni_margin;
		  } else {
		    y_offset = viz.clust.margin.top + viz.clust.dim.height;
		  }
	
		  d3.select(viz.root + ' .bottom_spillover_container').attr('transform', function () {
		    // shift up enough to show the entire border width
		    return 'translate(0,' + y_offset + ')';
		  });
	
		  svg_group.select(viz.root + ' .bottom_spillover').attr('width', viz.svg_dim.width).attr('height', 2 * viz.svg_dim.height);
	
		  var inst_height = viz.cat_room.col + 1.5 * viz.uni_margin;
		  // white rect to cover excess labels
		  d3.select(viz.viz_svg + ' .top_right_white').attr('fill', viz.background_color).attr('width', 2 * viz.clust.dim.width).attr('height', inst_height).attr('transform', function () {
		    var tmp_left = viz.clust.margin.left + viz.clust.dim.width;
		    var tmp_top = viz.norm_labels.width.col + viz.norm_labels.margin.top - viz.uni_margin;
		    return 'translate(' + tmp_left + ', ' + tmp_top + ')';
		  });
			};
	
	/***/ }),
	/* 166 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function resize_borders(params, svg_group) {
	
		  // left border
		  svg_group.select('.left_border').attr('width', params.viz.grey_border_width).attr('height', params.viz.svg_dim.height).attr('transform', 'translate(0,0)');
	
		  // right border
		  svg_group.select('.right_border').attr('width', params.viz.grey_border_width).attr('height', params.viz.svg_dim.height).attr('transform', function () {
		    var inst_offset = params.viz.svg_dim.width - params.viz.grey_border_width;
		    return 'translate(' + inst_offset + ',0)';
		  });
	
		  // top border
		  svg_group.select('.top_border').attr('width', params.viz.svg_dim.width).attr('height', params.viz.grey_border_width).attr('transform', function () {
		    var inst_offset = 0;
		    return 'translate(' + inst_offset + ',0)';
		  });
	
		  // bottom border
		  svg_group.select('.bottom_border').attr('width', params.viz.svg_dim.width).attr('height', params.viz.grey_border_width).attr('transform', function () {
		    var inst_offset = params.viz.svg_dim.height - params.viz.grey_border_width;
		    return 'translate(0,' + inst_offset + ')';
		  });
			};
	
	/***/ }),
	/* 167 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function resize_row_labels(params, ini_svg_group) {
		  var delay_info = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
	
	
		  var delays = {};
		  var duration = params.viz.duration;
		  var svg_group;
	
		  var row_nodes = params.network_data.row_nodes;
		  var row_nodes_names = params.network_data.row_nodes_names;
	
		  if (delay_info === false) {
		    delays.run_transition = false;
		  } else {
		    delays = delay_info;
		  }
	
		  if (delays.run_transition) {
	
		    ini_svg_group.selectAll('.row_label_group')
		    // data bind necessary for loss/gain of rows
		    .data(row_nodes, function (d) {
		      return d.name;
		    }).transition().delay(delays.update).duration(duration).attr('transform', function (d) {
		      var inst_index = _.indexOf(row_nodes_names, d.name);
		      return 'translate(0,' + params.viz.y_scale(inst_index) + ')';
		    }).attr('y', params.viz.rect_height * 0.5 + params.labels.default_fs_row * 0.35);
	
		    svg_group = ini_svg_group.transition().delay(delays.update).duration(duration);
		  } else {
	
		    ini_svg_group.selectAll('.row_label_group')
		    // data bind necessary for loss/gain of rows
		    .data(row_nodes, function (d) {
		      return d.name;
		    }).attr('transform', function (d) {
		      var inst_index = _.indexOf(row_nodes_names, d.name);
		      return 'translate(0,' + params.viz.y_scale(inst_index) + ')';
		    }).attr('y', params.viz.rect_height * 0.5 + params.labels.default_fs_row * 0.35);
	
		    svg_group = ini_svg_group;
		  }
	
		  svg_group.select(params.root + ' .row_container').attr('transform', 'translate(' + params.viz.norm_labels.margin.left + ',' + params.viz.clust.margin.top + ')');
	
		  svg_group.select(params.root + ' .row_container').select('.white_bars').attr('width', params.viz.label_background.row).attr('height', 30 * params.viz.clust.dim.height + 'px');
	
		  svg_group.select(params.root + ' .row_container').select('.row_label_container').attr('transform', 'translate(' + params.viz.norm_labels.width.row + ',0)');
			};
	
	/***/ }),
	/* 168 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function resize_highlights(params) {
	
		  // reposition tile highlight
		  ////////////////////////////////
	
		  var rel_width_hlight = 6;
		  // var opacity_hlight = 0.85;
		  var hlight_width = rel_width_hlight * params.viz.border_width.x;
		  var hlight_height = rel_width_hlight * params.viz.border_width.y;
	
		  // top highlight
		  d3.select(params.root + ' .top_hlight').attr('width', params.viz.rect_width).attr('height', hlight_height).attr('transform', function () {
		    return 'translate(' + params.viz.x_scale(params.matrix.click_hlight_x) + ',0)';
		  });
	
		  // left highlight
		  d3.select(params.root + ' .left_hlight').attr('width', hlight_width).attr('height', params.viz.rect_width - hlight_height * 0.99).attr('transform', function () {
		    return 'translate(' + params.viz.x_scale(params.matrix.click_hlight_x) + ',' + hlight_height * 0.99 + ')';
		  });
	
		  // right highlight
		  d3.select(params.root + ' .right_hlight').attr('width', hlight_width).attr('height', params.viz.rect_height - hlight_height * 0.99).attr('transform', function () {
		    var tmp_translate = params.viz.x_scale(params.matrix.click_hlight_x) + params.viz.rect_width - hlight_width;
		    return 'translate(' + tmp_translate + ',' + hlight_height * 0.99 + ')';
		  });
	
		  // bottom highlight
		  d3.select(params.root + ' .bottom_hlight').attr('width', function () {
		    return params.viz.rect_width - 1.98 * hlight_width;
		  }).attr('height', hlight_height).attr('transform', function () {
		    var tmp_translate_x = params.viz.x_scale(params.matrix.click_hlight_x) + hlight_width * 0.99;
		    var tmp_translate_y = params.viz.rect_height - hlight_height;
		    return 'translate(' + tmp_translate_x + ',' + tmp_translate_y + ')';
		  });
	
		  // resize row highlight
		  /////////////////////////
		  d3.select(params.root + ' .row_top_hlight').attr('width', params.viz.svg_dim.width).attr('height', hlight_height);
	
		  d3.select(params.root + ' .row_bottom_hlight').attr('width', params.viz.svg_dim.width).attr('height', hlight_height).attr('transform', function () {
		    var tmp_translate_y = params.viz.rect_height - hlight_height;
		    return 'translate(0,' + tmp_translate_y + ')';
		  });
	
		  // resize col highlight
		  /////////////////////////
		  d3.select(params.root + ' .col_top_hlight').attr('width', params.viz.clust.dim.height).attr('height', hlight_width).attr('transform', function () {
		    var tmp_translate_y = 0;
		    var tmp_translate_x = -(params.viz.clust.dim.height + params.viz.cat_room.col + params.viz.uni_margin);
		    return 'translate(' + tmp_translate_x + ',' + tmp_translate_y + ')';
		  });
	
		  d3.select(params.root + ' .col_bottom_hlight').attr('width', params.viz.clust.dim.height).attr('height', hlight_width).attr('transform', function () {
		    var tmp_translate_y = params.viz.rect_width - hlight_width;
		    var tmp_translate_x = -(params.viz.clust.dim.height + params.viz.cat_room.col + params.viz.uni_margin);
		    return 'translate(' + tmp_translate_x + ',' + tmp_translate_y + ')';
		  });
			};
	
	/***/ }),
	/* 169 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function resize_row_viz(params, ini_svg_group) {
		  var delay_info = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
	
	
		  var delays = {};
		  var duration = params.viz.duration;
		  var svg_group;
	
		  if (delay_info === false) {
		    delays.run_transition = false;
		  } else {
		    delays = delay_info;
		  }
	
		  if (delays.run_transition) {
		    svg_group = ini_svg_group.transition().delay(delays.update).duration(duration);
		  } else {
		    svg_group = ini_svg_group;
		  }
	
		  svg_group.select('.row_cat_outer_container').attr('transform', 'translate(' + params.viz.norm_labels.width.row + ',0)').select('white_bars').attr('width', params.viz.cat_room.row + 'px').attr('height', function () {
		    var inst_height = params.viz.clust.dim.height;
		    return inst_height;
		  });
	
		  var x_offset = params.viz.clust.margin.left + params.viz.clust.dim.width;
		  var y_offset = params.viz.clust.margin.top;
		  svg_group.select('.row_dendro_outer_container').attr('transform', 'translate(' + x_offset + ',' + y_offset + ')');
	
		  // !! tmp resize col dendro
		  x_offset = params.viz.clust.margin.left;
		  y_offset = params.viz.clust.margin.top + params.viz.clust.dim.height;
	
		  svg_group.select(' .col_dendro_outer_container').attr('transform', function () {
		    return 'translate(' + x_offset + ',' + y_offset + ')';
		  });
			};
	
	/***/ }),
	/* 170 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function (params, ini_svg_group) {
		  var delay_info = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
	
	
		  var delays = {};
		  var duration = params.viz.duration;
		  var svg_group;
	
		  var col_nodes = params.network_data.col_nodes;
		  var col_nodes_names = params.network_data.col_nodes_names;
	
		  if (delay_info === false) {
		    delays.run_transition = false;
		  } else {
		    delays = delay_info;
		  }
	
		  if (delays.run_transition) {
		    svg_group = ini_svg_group.transition().delay(delays.update).duration(duration);
	
		    ini_svg_group.selectAll('.col_label_text').data(col_nodes, function (d) {
		      return d.name;
		    }).transition().delay(delays.update).duration(duration).attr('transform', function (d) {
		      var inst_index = _.indexOf(col_nodes_names, d.name);
		      return 'translate(' + params.viz.x_scale(inst_index) + ', 0) rotate(-90)';
		    });
		  } else {
		    svg_group = ini_svg_group;
	
		    ini_svg_group.selectAll('.col_label_text').data(col_nodes, function (d) {
		      return d.name;
		    }).attr('transform', function (d) {
		      var inst_index = _.indexOf(col_nodes_names, d.name);
		      return 'translate(' + params.viz.x_scale(inst_index) + ', 0) rotate(-90)';
		    });
		  }
	
		  // offset click group column label
		  var x_offset_click = params.viz.x_scale.rangeBand() / 2 + params.viz.border_width.x;
	
		  svg_group.select(params.root + ' .col_container').attr('transform', 'translate(' + params.viz.clust.margin.left + ',' + params.viz.norm_labels.margin.top + ')');
	
		  svg_group.select(params.root + ' .col_container').select('.white_bars').attr('width', 30 * params.viz.clust.dim.width + 'px').attr('height', params.viz.label_background.col);
	
		  svg_group.select(params.root + ' .col_container').select('.col_label_outer_container').attr('transform', 'translate(0,' + params.viz.norm_labels.width.col + ')');
	
		  svg_group.selectAll('.col_label_group').attr('transform', 'translate(' + params.viz.x_scale.rangeBand() / 2 + ',' + x_offset_click + ') rotate(45)');
	
		  svg_group.selectAll('.col_label_group').select('text').attr('y', params.viz.x_scale.rangeBand() * 0.60).attr('dx', 2 * params.viz.border_width.x);
			};
	
	/***/ }),
	/* 171 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
	
		module.exports = function resize_col_text(params, svg_group) {
		  svg_group.selectAll('.col_label_group').select('text').style('font-size', params.labels.default_fs_col + 'px').text(function (d) {
		    return utils.normal_name(d);
		  });
	
		  svg_group.selectAll('.col_label_group').each(function () {
		    d3.select(this).select('text')[0][0].getBBox();
		  });
		};
	
	/***/ }),
	/* 172 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var col_viz_aid_triangle = __webpack_require__(138);
	
		module.exports = function resize_col_triangle(params, ini_svg_group) {
		  var delay_info = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
	
	
		  // resize column triangle
		  var ini_triangle_group = ini_svg_group.selectAll('.col_label_group').select('path');
	
		  var delays = {};
		  var duration = params.viz.duration;
	
		  if (delay_info === false) {
		    delays.run_transition = false;
		  } else {
		    delays = delay_info;
		  }
	
		  var triangle_group;
		  if (delays.run_transition) {
		    triangle_group = ini_triangle_group.transition().delay(delays.update).duration(duration);
		  } else {
		    triangle_group = ini_triangle_group;
		  }
	
		  triangle_group.attr('d', function () {
		    return col_viz_aid_triangle(params);
		  }).attr('fill', '#eee');
			};
	
	/***/ }),
	/* 173 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
	
		module.exports = function resize_col_hlight(params, svg_group) {
		  var delay_info = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
	
	
		  var delays = {};
		  // var duration = params.viz.duration;
	
		  if (delay_info === false) {
		    delays.run_transition = false;
		  } else {
		    delays = delay_info;
		  }
	
		  if (utils.has(params.network_data.col_nodes[0], 'value')) {
	
		    svg_group.selectAll('.col_bars').data(params.network_data.col_nodes, function (d) {
		      return d.name;
		    }).attr('width', function (d) {
	
		      var inst_value = 0;
	
		      if (d.value > 0) {
		        inst_value = params.labels.bar_scale_col(d.value);
		      }
		      return inst_value;
		    })
		    // rotate labels - reduce width if rotating
		    .attr('height', params.viz.rect_width * 0.66);
		  }
			};
	
	/***/ }),
	/* 174 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var get_svg_dim = __webpack_require__(71);
		var calc_clust_height = __webpack_require__(74);
		var calc_clust_width = __webpack_require__(73);
		var calc_default_fs = __webpack_require__(83);
		var calc_zoom_switching = __webpack_require__(82);
	
		module.exports = function recalc_params_for_resize(params) {
	
		  // Resetting some visualization parameters
		  params = get_svg_dim(params);
		  params.viz = calc_clust_width(params.viz);
		  params.viz = calc_clust_height(params.viz);
	
		  if (params.sim_mat) {
		    if (params.viz.clust.dim.width <= params.viz.clust.dim.height) {
		      params.viz.clust.dim.height = params.viz.clust.dim.width;
		    } else {
		      params.viz.clust.dim.width = params.viz.clust.dim.height;
		    }
		  }
	
		  params.viz = calc_zoom_switching(params.viz);
	
		  // redefine x_scale and y_scale rangeBands
		  params.viz.x_scale.rangeBands([0, params.viz.clust.dim.width]);
		  params.viz.y_scale.rangeBands([0, params.viz.clust.dim.height]);
	
		  // redefine border width
		  params.viz.border_width.x = params.viz.x_scale.rangeBand() / params.viz.border_fraction;
		  params.viz.border_width.y = params.viz.y_scale.rangeBand() / params.viz.border_fraction;
	
		  params.viz.rect_width = params.viz.x_scale.rangeBand() - params.viz.border_width.x;
		  params.viz.rect_height = params.viz.y_scale.rangeBand() - params.viz.border_width.y;
	
		  // for downsampling
		  if (params.viz.ds != null) {
		    for (var i; i < params.viz.ds.length; i++) {
		      params.viz.ds[i].rect_height = params.viz.ds[i].y_scale.rangeBand() - params.viz.border_width.y;
		    }
		  }
	
		  // recalc downsampled y_scale if necessary
		  if (params.viz.ds_num_levels > 0) {
		    _.each(params.viz.ds, function (inst_ds) {
	
		      // y_scale
		      /////////////////////////
		      inst_ds.y_scale = d3.scale.ordinal().rangeBands([0, params.viz.clust.dim.height]);
		      inst_ds.y_scale.domain(d3.range(inst_ds.num_rows + 1));
	
		      inst_ds.rect_height = inst_ds.y_scale.rangeBand() - params.viz.border_width.y;
		    });
		  }
	
		  // redefine zoom extent
		  params.viz.square_zoom = params.viz.norm_labels.width.col / (params.viz.rect_width / 2);
	
		  // the default font sizes are set here
		  params = calc_default_fs(params);
	
		  return params;
		};
	
	/***/ }),
	/* 175 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var draw_up_tile = __webpack_require__(95);
		var draw_dn_tile = __webpack_require__(96);
		var fine_position_tile = __webpack_require__(99);
	
		module.exports = function resize_row_tiles(params, svg_group) {
	
		  var row_nodes_names = params.network_data.row_nodes_names;
	
		  if (params.viz.ds_level === -1) {
	
		    // no downsampling
		    ///////////////////////
	
		    // resize rows
		    svg_group.selectAll('.row').attr('transform', function (d) {
		      var tmp_index = _.indexOf(row_nodes_names, d.name);
		      var inst_y = params.viz.y_scale(tmp_index);
		      return 'translate(0,' + inst_y + ')';
		    });
	
		    // resize tiles
		    svg_group.selectAll('.row').selectAll('.tile').attr('transform', function (d) {
		      return fine_position_tile(params, d);
		    }).attr('width', params.viz.rect_width).attr('height', params.viz.rect_height);
	
		    // resize tile_up
		    svg_group.selectAll('.row').selectAll('.tile_up').attr('d', function () {
		      return draw_up_tile(params);
		    }).attr('transform', function (d) {
		      return fine_position_tile(params, d);
		    });
	
		    // resize tile_dn
		    svg_group.selectAll('.row').selectAll('.tile_dn').attr('d', function () {
		      return draw_dn_tile(params);
		    }).attr('transform', function (d) {
		      return fine_position_tile(params, d);
		    });
		  } else {
	
		    // downsampling
		    /////////////////////////
	
		    var ds_level = params.viz.ds_level;
		    var row_class = '.ds' + String(ds_level) + '_row';
		    var ds_rect_height = params.viz.ds[ds_level].rect_height;
	
		    svg_group.selectAll(row_class).attr('transform', function (d) {
		      var inst_y = params.viz.ds[ds_level].y_scale(d.row_index);
		      return 'translate(0,' + inst_y + ')';
		    });
	
		    // reset ds-tiles
		    svg_group.selectAll(row_class).selectAll('.tile').attr('transform', function (d) {
		      return fine_position_tile(params, d);
		    }).attr('width', params.viz.rect_width).attr('height', ds_rect_height);
		  }
			};
	
	/***/ }),
	/* 176 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var calc_val_max = __webpack_require__(75);
		// var underscore = require('underscore');
	
		module.exports = function resize_label_bars(cgm, svg_group) {
		  var params = cgm.params;
	
		  // // set bar scale
		  // var val_max = Math.abs(underscore.max( params.network_data.row_nodes, function(d) {
		  //   return Math.abs(d.value);
		  // } ).value) ;
	
		  // params.labels.bar_scale_row = d3.scale
		  //   .linear()
		  //   .domain([0, val_max])
		  //   .range([0, params.viz.norm_labels.width.row ]);
	
		  params = calc_val_max(params);
	
		  svg_group.selectAll('.row_bars')
		  // .transition().delay(delays.update).duration(duration)
		  .attr('width', function (d) {
		    var inst_value = 0;
		    inst_value = params.labels.bar_scale_row(Math.abs(d.value));
		    return inst_value;
		  }).attr('x', function (d) {
		    var inst_value = 0;
		    inst_value = -params.labels.bar_scale_row(Math.abs(d.value));
		    return inst_value;
		  }).attr('height', params.viz.y_scale.rangeBand());
			};
	
	/***/ }),
	/* 177 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function position_play_button(params) {
	
		  var clust_transform = d3.select(params.root + ' .clust_container').attr('transform');
	
		  var clust_x = Number(clust_transform.split('(')[1].split(',')[0]);
		  var clust_y = Number(clust_transform.split(',')[1].replace(')', ''));
		  var trans_x = clust_x + params.viz.clust.dim.width / 2;
		  var trans_y = clust_y + params.viz.clust.dim.height / 2;
	
		  d3.select(params.root + ' .play_button').attr('transform', function () {
		    return 'translate(' + trans_x + ',' + trans_y + ')';
		  });
			};
	
	/***/ }),
	/* 178 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function position_svg_dendro_slider(cgm, inst_rc) {
	
		  var viz = cgm.params.viz;
		  var tmp_left;
		  var tmp_top;
		  if (inst_rc === 'row') {
	
		    // row dendrogram
		    ///////////////////////
	
		    // keep slider near clustergram
		    var max_room = viz.svg_dim.width - 3 * viz.uni_margin;
	
		    // position close to row dendrogram trapezoids
		    tmp_left = viz.clust.margin.left + viz.clust.dim.width + 5.25 * viz.dendro_room.row;
	
		    if (tmp_left > max_room) {
		      tmp_left = max_room;
		    }
	
		    tmp_top = viz.clust.margin.top + 3 * viz.uni_margin - 50; // + 90 ;
		  } else {
	
		    // column dendrogram
		    ///////////////////////
		    tmp_left = 2 * viz.uni_margin;
		    // tmp_top =  viz.svg_dim.height - 2.5 * viz.uni_margin;
		    tmp_top = viz.clust.margin.top + viz.clust.dim.height + viz.dendro_room.col - 2 * viz.uni_margin;
		  }
	
		  // reposition tree icon
		  d3.select(cgm.params.root + ' .' + inst_rc + '_tree_group').attr('transform', function () {
		    var inst_translation;
		    tmp_top = tmp_top - 75;
		    inst_translation = 'translate(' + tmp_left + ',' + tmp_top + ')';
	
		    return inst_translation;
		  }).style('opacity', 1);
	
		  // reposiiton slider
		  d3.select(cgm.params.root + ' .' + inst_rc + '_slider_group').attr('transform', function () {
		    var inst_translation;
		    if (inst_rc === 'row') {
		      tmp_left = tmp_left + 0.8 * viz.dendro_room.row;
		      tmp_top = tmp_top + 65;
		      inst_translation = 'translate(' + tmp_left + ',' + tmp_top + ')';
		    } else {
		      inst_translation = 'translate(' + tmp_left + ',' + tmp_top + '), rotate(-90)';
		    }
		    return inst_translation;
		  }).style('opacity', 1);
			};
	
	/***/ }),
	/* 179 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function grid_lines_viz(params) {
		  var duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
	
	
		  var delay = 0;
		  if (duration > 0) {
		    delay = 2000;
		  }
	
		  var horz_lines = d3.selectAll(params.root + ' .horz_lines');
		  var vert_lines = d3.selectAll(params.root + ' .vert_lines');
	
		  horz_lines.style('opacity', 0).attr('transform', function (d) {
		    var inst_index = d.row_index;
		    var inst_trans = params.viz.y_scale(inst_index);
		    return 'translate(  0,' + inst_trans + ') rotate(0)';
		  }).transition().duration(duration).delay(delay).style('opacity', 1);
	
		  horz_lines.append('line').attr('x1', 0).attr('x2', params.viz.clust.dim.width).style('stroke-width', function () {
		    var inst_width = params.viz.border_width.y;
		    return inst_width + 'px';
		  });
	
		  vert_lines.style('opacity', 0).attr('transform', function (d) {
		    var inst_index = d.col_index;
		    var inst_trans = params.viz.x_scale(inst_index);
		    return 'translate(' + inst_trans + ') rotate(-90)';
		  }).transition().duration(duration).delay(delay).style('opacity', 1);
	
		  vert_lines.append('line').attr('x1', 0).attr('x2', -params.viz.clust.dim.height).style('stroke-width', function () {
		    var inst_width = params.viz.border_width.x;
		    return inst_width + 'px';
		  });
			};
	
	/***/ }),
	/* 180 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var cat_tooltip_text = __webpack_require__(181);
		var d3_tip_custom = __webpack_require__(100);
		var reset_cat_opacity = __webpack_require__(182);
		var ini_cat_opacity = __webpack_require__(183);
		// var click_filter_cats = require('./click_filter_cats');
		var get_cat_names = __webpack_require__(184);
	
		module.exports = function make_col_cat(cgm) {
	
		  var params = cgm.params;
	
		  // make or reuse outer container
		  if (d3.select(params.root + ' .col_cat_outer_container').empty()) {
		    d3.select(params.root + ' .col_container').append('g').attr('class', 'col_cat_outer_container').attr('transform', function () {
		      var inst_offset = params.viz.norm_labels.width.col + 2;
		      return 'translate(0,' + inst_offset + ')';
		    }).append('g').attr('class', 'col_cat_container');
		  } else {
		    d3.select(params.root + ' .col_container').select('col_cat_outer_container').attr('transform', function () {
		      var inst_offset = params.viz.norm_labels.width.col + 2;
		      return 'translate(0,' + inst_offset + ')';
		    });
		  }
	
		  // remove old col_cat_tips
		  d3.selectAll(params.viz.root_tips + '_col_cat_tip').remove();
	
		  // d3-tooltip
		  var cat_tip = d3_tip_custom().attr('class', function () {
		    var root_tip_selector = params.viz.root_tips.replace('.', '');
		    var class_string = root_tip_selector + ' d3-tip ' + root_tip_selector + '_col_cat_tip';
		    return class_string;
		  }).direction('s').offset([5, 0]).style('display', 'none').html(function (d) {
		    return cat_tooltip_text(params, d, this, 'col');
		  });
	
		  // append groups - each will hold classification rects
		  d3.select(params.root + ' .col_cat_container').selectAll('g').data(params.network_data.col_nodes, function (d) {
		    return d.name;
		  }).enter().append('g').attr('class', 'col_cat_group').attr('transform', function (d) {
		    var inst_index = _.indexOf(params.network_data.col_nodes_names, d.name);
		    // return 'translate(' + params.viz.x_scale(d.col_index) + ',0)';
		    return 'translate(' + params.viz.x_scale(inst_index) + ',0)';
		  });
	
		  d3.select(params.root + ' .col_cat_container').selectAll('.col_cat_group').call(cat_tip);
	
		  // add category rects
		  d3.selectAll(params.root + ' .col_cat_group').each(function () {
	
		    var inst_selection = this;
		    var cat_rect;
	
		    _.each(params.viz.all_cats.col, function (inst_cat) {
	
		      var inst_num = parseInt(inst_cat.split('-')[1], 10);
		      var cat_rect_class = 'col_cat_rect_' + String(inst_num);
	
		      if (d3.select(inst_selection).select('.' + cat_rect_class).empty()) {
		        cat_rect = d3.select(inst_selection).append('rect').attr('class', cat_rect_class).attr('cat', inst_cat).attr('transform', function () {
		          var cat_room = params.viz.cat_room.symbol_width + params.viz.cat_room.separation;
		          var inst_shift = inst_num * cat_room;
		          return 'translate(0,' + inst_shift + ')';
		        }).on('click', function (d) {
	
		          if (d3.select(this).classed('cat_strings')) {
	
		            var found_names = get_cat_names(params, d, this, 'col');
	
		            $(params.root + ' .dendro_info').modal('toggle');
		            var group_string = found_names.join(', ');
		            d3.select(params.root + ' .dendro_info input').attr('value', group_string);
		          }
		        });
		      } else {
		        cat_rect = d3.select(inst_selection).select('.' + cat_rect_class);
		      }
	
		      cat_rect.attr('width', params.viz.x_scale.rangeBand()).attr('height', params.viz.cat_room.symbol_width).style('fill', function (d) {
		        var cat_name = d[inst_cat];
		        var inst_color = params.viz.cat_colors.col[inst_cat][cat_name];
		        return inst_color;
		      }).on('mouseover', cat_tip.show).on('mouseout', function () {
		        cat_tip.hide(this);
		        reset_cat_opacity(params);
		        d3.select(this).classed('hovering', false);
	
		        d3.selectAll('.d3-tip').style('display', 'none');
		      });
	
		      ini_cat_opacity(params.viz, 'col', cat_rect, inst_cat);
		    });
		  });
			};
	
	/***/ }),
	/* 181 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var get_cat_title = __webpack_require__(141);
	
		module.exports = function cat_tooltip_text(params, inst_data, inst_selection, inst_rc) {
	
		  d3.selectAll(params.viz.root_tips + '_col_cat_tip').style('display', 'block');
	
		  d3.selectAll(params.viz.root_tips + '_row_cat_tip').style('display', 'block');
	
		  // category index
		  var inst_cat = d3.select(inst_selection).attr('cat');
		  var cat_title = get_cat_title(params.viz, inst_cat, inst_rc);
		  var cat_name = inst_data[inst_cat];
	
		  if (typeof cat_name === 'string') {
		    if (cat_name.indexOf(': ') >= 0) {
		      cat_name = cat_name.split(': ')[1];
		    }
		  }
	
		  var cat_string = cat_title + ': ' + cat_name;
	
		  d3.select(inst_selection).classed('hovering', true);
	
		  setTimeout(highlight_categories, 500);
	
		  return cat_string;
	
		  function highlight_categories() {
	
		    var run_highlighting = false;
	
		    if (d3.select(inst_selection).classed('hovering')) {
	
		      var node_types = [inst_rc];
	
		      if (params.viz.sim_mat) {
		        node_types = ['row', 'col'];
		      }
	
		      _.each(node_types, function (tmp_rc) {
	
		        // only highlight string categories that are not 'false' categories
		        if (typeof cat_name === 'string') {
		          if (cat_name.indexOf('Not ') < 0 && cat_name != 'false') {
		            run_highlighting = true;
		          }
		        }
	
		        if (run_highlighting) {
	
		          d3.selectAll(params.root + ' .' + tmp_rc + '_cat_group').selectAll('rect').style('opacity', function (d) {
	
		            var inst_opacity = d3.select(this).style('opacity');
	
		            if (d3.select(this).classed('cat_strings') && d3.select(this).classed('filtered_cat') === false) {
	
		              var tmp_name;
		              var tmp_cat = d3.select(this).attr('cat');
	
		              if (d[tmp_cat].indexOf(': ') >= 0) {
		                tmp_name = d[tmp_cat].split(': ')[1];
		              } else {
		                tmp_name = d[tmp_cat];
		              }
	
		              if (tmp_cat === inst_cat && tmp_name === cat_name) {
		                inst_opacity = params.viz.cat_colors.active_opacity;
		              } else {
		                inst_opacity = params.viz.cat_colors.opacity / 4;
		              }
		            }
	
		            return inst_opacity;
		          });
		        }
		      });
		    }
		  }
			};
	
	/***/ }),
	/* 182 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function reset_cat_opacity(params) {
	
		  _.each(['row', 'col'], function (inst_rc) {
	
		    d3.selectAll(params.root + ' .' + inst_rc + '_cat_group').selectAll('rect').style('opacity', function () {
	
		      var inst_opacity = d3.select(this).style('opacity');
	
		      if (d3.select(this).classed('cat_strings') && d3.select(this).classed('filtered_cat') === false) {
		        inst_opacity = params.viz.cat_colors.opacity;
		      }
	
		      return inst_opacity;
		    });
		  });
			};
	
	/***/ }),
	/* 183 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function ini_cat_opacity(viz, inst_rc, cat_rect, inst_cat) {
		  var updating = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
	
	
		  // debugger;
	
		  var super_string = ': ';
		  var inst_type = viz.cat_info[inst_rc][inst_cat].type;
	
		  // set opacity based on string or value cats
		  if (inst_type === 'cat_strings') {
	
		    // optionally have categories transition in
		    if (updating) {
		      cat_rect.classed('cat_strings', true).style('opacity', 0).transition().duration(1000).style('opacity', viz.cat_colors.opacity);
		    } else {
		      // opacity is fixed
		      cat_rect.classed('cat_strings', true).style('opacity', viz.cat_colors.opacity);
		    }
		  } else {
	
		    // opacity varies based on value
		    cat_rect.classed('cat_values', true).style('opacity', function (d) {
	
		      var unprocessed_val = d[inst_cat];
	
		      var cat_value = get_cat_value(unprocessed_val);
	
		      return viz.cat_info[inst_rc][inst_cat].cat_scale(Math.abs(cat_value));
		    }).style('fill', function (d) {
		      var inst_color;
	
		      var cat_value = get_cat_value(d[inst_cat]);
	
		      // get positive and negative colors
		      if (cat_value > 0) {
		        inst_color = viz.cat_value_colors[0];
		      } else {
		        inst_color = viz.cat_value_colors[1];
		      }
	
		      return inst_color;
		    });
		  }
	
		  function get_cat_value(unprocessed_value) {
		    if (typeof unprocessed_value === 'string') {
	
		      if (unprocessed_value.indexOf(super_string) > -1) {
		        unprocessed_value = unprocessed_value.split(super_string)[1];
		      }
		    }
	
		    var cat_value = parseFloat(unprocessed_value);
	
		    return cat_value;
		  }
			};
	
	/***/ }),
	/* 184 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
	
		module.exports = function get_cat_names(params, inst_data, inst_selection, inst_rc) {
	
		  // category index
		  var inst_cat = d3.select(inst_selection).attr('cat');
		  var cat_name = inst_data[inst_cat];
		  var tmp_nodes = params.network_data[inst_rc + '_nodes'];
	
		  var found_nodes = _.filter(tmp_nodes, function (d) {
		    return d[inst_cat] == cat_name;
		  });
	
		  var found_names = utils.pluck(found_nodes, 'name');
	
		  return found_names;
		};
	
	/***/ }),
	/* 185 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var cat_tooltip_text = __webpack_require__(181);
		var d3_tip_custom = __webpack_require__(100);
		var reset_cat_opacity = __webpack_require__(182);
		var ini_cat_opacity = __webpack_require__(183);
		// var click_filter_cats = require('./click_filter_cats');
		var get_cat_names = __webpack_require__(184);
	
		module.exports = function make_row_cat(cgm) {
		  var updating = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
	
	
		  // console.log('make_row_cat')
	
		  var params = cgm.params;
	
		  // make or reuse outer container
		  if (d3.select(params.root + ' .row_cat_outer_container').empty()) {
		    d3.select(params.root + ' .row_container').append('g').attr('class', 'row_cat_outer_container').attr('transform', 'translate(' + params.viz.norm_labels.width.row + ',0)').append('g').attr('class', 'row_cat_container');
		  } else {
		    d3.select(params.root + ' .row_container').select('row_cat_outer_container').attr('transform', 'translate(' + params.viz.norm_labels.width.row + ',0)');
		  }
	
		  // white background
		  if (d3.select(params.root + ' .row_cat_container').select('.white_bars').empty()) {
		    d3.select(params.root + ' .row_cat_container').append('rect').attr('class', 'white_bars').attr('fill', params.viz.background_color).attr('width', params.viz.cat_room.row + 'px').attr('height', function () {
		      var inst_height = params.viz.clust.dim.height;
		      return inst_height;
		    });
		  } else {
		    d3.select(params.root + ' .row_cat_container').select('.white_bars').attr('fill', params.viz.background_color).attr('width', params.viz.cat_room.row + 'px').attr('height', function () {
		      var inst_height = params.viz.clust.dim.height;
		      return inst_height;
		    });
		  }
	
		  // remove old col_cat_tips
		  d3.selectAll(params.viz.root_tips + '_row_cat_tip').remove();
	
		  // d3-tooltip
		  var cat_tip = d3_tip_custom().attr('class', function () {
		    var root_tip_selector = params.viz.root_tips.replace('.', '');
		    var class_string = root_tip_selector + ' d3-tip ' + root_tip_selector + '_row_cat_tip';
		    return class_string;
		  }).direction('e').offset([5, 0]).style('display', 'none').html(function (d) {
		    return cat_tooltip_text(params, d, this, 'row');
		  });
	
		  // groups that hold classification triangle and colorbar rect
		  d3.select(params.root + ' .row_cat_container').selectAll('g').data(params.network_data.row_nodes, function (d) {
		    return d.name;
		  }).enter().append('g').attr('class', 'row_cat_group').attr('transform', function (d) {
		    var inst_index = _.indexOf(params.network_data.row_nodes_names, d.name);
		    return 'translate(0, ' + params.viz.y_scale(inst_index) + ')';
		  });
	
		  d3.select(params.root + ' .row_cat_container').selectAll('.row_cat_group').call(cat_tip);
	
		  var cat_rect;
		  var inst_selection;
	
		  d3.selectAll(params.root + ' .row_cat_group rect').remove();
	
		  if (params.viz.show_categories.row) {
	
		    d3.selectAll(params.root + ' .row_cat_group').each(function () {
	
		      inst_selection = this;
	
		      _.each(params.viz.all_cats.row, function (inst_cat) {
	
		        var inst_num = parseInt(inst_cat.split('-')[1], 10);
		        var cat_rect_class = 'row_cat_rect_' + String(inst_num);
	
		        if (d3.select(inst_selection).select('.' + cat_rect_class).empty()) {
		          cat_rect = d3.select(inst_selection).append('rect').attr('class', cat_rect_class).attr('cat', inst_cat);
		        } else {
		          cat_rect = d3.select(inst_selection).select('.' + cat_rect_class);
		        }
	
		        cat_rect.attr('width', params.viz.cat_room.symbol_width).attr('height', params.viz.y_scale.rangeBand()).style('fill', function (d) {
		          var cat_name = d[inst_cat];
	
		          // if (cat_name.indexOf(': ') >= 0){
		          //   cat_name = cat_name.split(': ')[1];
		          // }
	
		          // console.log(cat_name)
	
		          var inst_color = params.viz.cat_colors.row[inst_cat][cat_name];
	
		          // console.log('inst_color: ' + String(inst_color));
		          return inst_color;
		        }).attr('x', function () {
		          var inst_offset = params.viz.cat_room.symbol_width + params.viz.uni_margin / 2;
		          return inst_offset + 'px';
		        }).attr('transform', function () {
		          var cat_room = params.viz.cat_room.symbol_width + params.viz.cat_room.separation;
		          var inst_shift = inst_num * cat_room;
		          return 'translate(' + inst_shift + ',0)';
		        }).on('click', function (d) {
	
		          if (d3.select(this).classed('cat_strings')) {
	
		            var found_names = get_cat_names(params, d, this, 'row');
	
		            $(params.root + ' .dendro_info').modal('toggle');
		            var group_string = found_names.join(', ');
		            d3.select(params.root + ' .dendro_info input').attr('value', group_string);
		          }
		        }).on('mouseover', cat_tip.show).on('mouseout', function () {
		          cat_tip.hide(this);
		          reset_cat_opacity(params);
		          d3.select(this).classed('hovering', false);
	
		          d3.selectAll('.d3-tip').style('display', 'none');
		        });
	
		        ini_cat_opacity(params.viz, 'row', cat_rect, inst_cat, updating);
		      });
		    });
		  }
			};
	
	/***/ }),
	/* 186 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_dendro_triangles = __webpack_require__(107);
	
		module.exports = function make_row_dendro(cgm) {
	
		  var params = cgm.params;
	
		  var spillover_width = params.viz.dendro_room.row + params.viz.uni_margin;
	
		  // position row_dendro_outer_container
		  var x_offset = params.viz.clust.margin.left + params.viz.clust.dim.width;
		  var y_offset = params.viz.clust.margin.top;
	
		  // make or reuse outer container
		  if (d3.select(params.root + ' .row_dendro_outer_container').empty()) {
	
		    d3.select(params.root + ' .viz_svg').append('g').attr('class', 'row_dendro_outer_container').attr('transform', 'translate(' + x_offset + ',' + y_offset + ')');
	
		    d3.select(params.root + ' .row_dendro_outer_container').append('rect').classed('row_dendro_spillover', true).attr('fill', params.viz.background_color).attr('width', spillover_width + 'px').attr('height', params.viz.svg_dim.height);
	
		    d3.select(params.root + ' .row_dendro_outer_container').append('g').attr('class', 'row_dendro_container').attr('transform', 'translate(' + params.viz.uni_margin / 2 + ',0)');
		  } else {
		    d3.select(params.root + ' .viz_svg').select('row_dendro_outer_container').attr('transform', 'translate(' + x_offset + ',' + y_offset + ')');
	
		    d3.select(params.root + ' .row_dendro_outer_container').select('.row_dendro_spillover').attr('width', spillover_width + 'px').attr('height', params.viz.svg_dim.height);
		  }
	
		  make_dendro_triangles(cgm, 'row', false);
	
		  if (params.viz.inst_order.col != 'clust') {
		    d3.selectAll(params.root + ' .row_dendro_group').remove();
		  }
			};
	
	/***/ }),
	/* 187 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_dendro_triangles = __webpack_require__(107);
	
		module.exports = function make_col_dendro(cgm) {
	
		  var params = cgm.params;
	
		  // position col_dendro_outer_container
		  var x_offset = params.viz.clust.margin.left;
		  var y_offset = params.viz.clust.margin.top + params.viz.clust.dim.height;
		  var spillover_height = params.viz.dendro_room.col + params.viz.uni_margin;
	
		  // make or reuse outer container
		  if (d3.select(params.root + ' .col_dendro_outer_container').empty()) {
	
		    d3.select(params.root + ' .viz_svg').append('g').attr('class', 'col_dendro_outer_container').attr('transform', 'translate(' + x_offset + ',' + y_offset + ')');
	
		    d3.select(params.root + ' .col_dendro_outer_container').append('rect').classed('col_dendro_spillover', true).attr('fill', params.viz.background_color).attr('width', params.viz.svg_dim.width).attr('height', spillover_height + 'px');
	
		    d3.select(params.root + ' .col_dendro_outer_container').append('g').attr('class', 'col_dendro_container').attr('transform', 'translate(0,' + params.viz.uni_margin / 2 + ')');
	
		    d3.select(params.root + ' .col_dendro_outer_container').append('rect').classed('col_dendro_spillover_top', true).attr('fill', params.viz.background_color).attr('width', params.viz.svg_dim.width).attr('height', params.viz.svg_dim.height).attr('transform', 'translate(0,' + params.viz.dendro_room.col + ')');
		  } else {
	
		    d3.select(params.root + ' .viz_svg').select('col_dendro_outer_container').attr('transform', 'translate(' + x_offset + ',' + y_offset + ')');
	
		    d3.select(params.root + ' .col_dendro_outer_container').select('.col_dendro_spillover').attr('width', params.viz.svg_dim.width).attr('height', spillover_height + 'px');
		  }
	
		  make_dendro_triangles(cgm, 'col', false);
	
		  if (params.viz.inst_order.row != 'clust') {
		    d3.selectAll(params.root + ' .col_dendro_group').remove();
		  }
			};
	
	/***/ }),
	/* 188 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var build_svg_dendro_slider = __webpack_require__(189);
		var build_svg_tree_icon = __webpack_require__(191);
	
		module.exports = function make_svg_dendro_sliders(cgm) {
	
		  build_svg_dendro_slider(cgm, 'row');
		  build_svg_dendro_slider(cgm, 'col');
	
		  // disabled
		  // build_svg_tree_icon(cgm);
			};
	
	/***/ }),
	/* 189 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var change_groups = __webpack_require__(190);
		var position_svg_dendro_slider = __webpack_require__(178);
	
		module.exports = function build_svg_dendro_slider(cgm, inst_rc) {
	
		  var slider_length = 100;
	
		  var drag = d3.behavior.drag().on("drag", dragging).on('dragend', function () {
		    cgm.params.is_slider_drag = false;
		  });
	
		  var slider_group = d3.select(cgm.params.root + ' .viz_svg').append('g').classed(inst_rc + '_slider_group', true);
	
		  position_svg_dendro_slider(cgm, inst_rc);
	
		  var rect_height = slider_length + 20;
		  var rect_width = 30;
		  slider_group.append('rect').classed(inst_rc + '_slider_background', true).attr('height', rect_height + 'px').attr('width', rect_width + 'px').attr('fill', cgm.params.viz.background_color).attr('transform', function () {
		    var translate_string = 'translate(-10, -5)';
		    return translate_string;
		  }).style('opacity', 0);
	
		  slider_group.append("line").style('stroke-width', slider_length / 7 + 'px').style('stroke', 'black').style('stroke-linecap', 'round').style('opacity', 0.0).attr("y1", 0).attr("y2", function () {
		    return slider_length - 2;
		  }).on('click', click_dendro_slider);
	
		  var offset_triangle = -slider_length / 40;
		  slider_group.append('path').style('fill', 'black').attr('transform', 'translate(' + offset_triangle + ', 0)').attr('d', function () {
	
		    // up triangle
		    var start_x = 0;
		    var start_y = 0;
	
		    var mid_x = 0;
		    var mid_y = slider_length;
	
		    var final_x = slider_length / 10;
		    var final_y = 0;
	
		    var output_string = 'M' + start_x + ',' + start_y + ', L' + mid_x + ', ' + mid_y + ', L' + final_x + ',' + final_y + ' Z';
	
		    return output_string;
		  }).style('opacity', 0.35).on('click', click_dendro_slider);
	
		  var default_opacity = 0.35;
		  var high_opacity = 0.6;
		  slider_group.append('circle').classed(inst_rc + '_group_circle', true).attr('r', slider_length * 0.08).attr('transform', function () {
		    return 'translate(0, ' + slider_length / 2 + ')';
		  }).style('fill', 'blue').style('opacity', default_opacity).on('mouseover', function () {
		    d3.select(this).style('opacity', high_opacity);
		  }).on('mouseout', function () {
		    d3.select(this).style('opacity', default_opacity);
		  }).call(drag);
	
		  function dragging() {
	
		    cgm.params.is_slider_drag = true;
	
		    // d[0] = d3.event.x;
		    var slider_pos = d3.event.y;
	
		    if (slider_pos < 0) {
		      slider_pos = 0;
		    }
	
		    if (slider_pos > slider_length) {
		      slider_pos = slider_length;
		    }
	
		    if (this.nextSibling) {
		      this.parentNode.appendChild(this);
		    }
	
		    slider_pos = d3.round(slider_pos, -1);
	
		    var slider_value = 10 - slider_pos / 10;
	
		    d3.select(this).attr("transform", "translate(0, " + slider_pos + ")");
	
		    change_groups(cgm, inst_rc, slider_value);
		  }
	
		  function click_dendro_slider() {
	
		    var clicked_line_position = d3.mouse(this);
	
		    var rel_pos = d3.round(clicked_line_position[1], -1);
	
		    d3.select(cgm.params.root + ' .' + inst_rc + '_group_circle').attr('transform', 'translate(0, ' + rel_pos + ')');
	
		    var slider_value = 10 - rel_pos / 10;
	
		    change_groups(cgm, inst_rc, slider_value);
		  }
		};
	
	/***/ }),
	/* 190 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		// var build_color_groups = require('./build_color_groups');
		var make_dendro_triangles = __webpack_require__(107);
	
		/* Changes the groupings (x- and y-axis color bars).
		 */
		module.exports = function (cgm, inst_rc, inst_index) {
	
		  var params = cgm.params;
	
		  if (inst_rc === 'row') {
		    params.group_level.row = inst_index;
		  } else if (inst_rc === 'col') {
		    params.group_level.col = inst_index;
		  }
	
		  var is_change_group = true;
	
		  make_dendro_triangles(cgm, inst_rc, is_change_group);
			};
	
	/***/ }),
	/* 191 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var position_svg_dendro_slider = __webpack_require__(178);
		var d3_tip_custom = __webpack_require__(100);
		var toggle_tree_menu = __webpack_require__(192);
	
		module.exports = function build_svg_tree_icon(cgm, inst_rc) {
	
		  inst_rc = 'row';
	
		  var slider_length = 40;
		  var params = cgm.params;
		  var default_opacity = 0.35;
		  var high_opacity = 0.6;
	
		  // d3-tooltip
		  var tree_menu_tip = d3_tip_custom().attr('class', function () {
		    var root_tip_selector = params.viz.root_tips.replace('.', '');
		    var class_string = root_tip_selector + '_tree_menu_tip d3-tip';
		    return class_string;
		  }).direction('sw').style('display', 'none').offset([-10, -5]).html(function () {
		    return 'Clustering Menu';
		  });
	
		  var tree_icon_outer_group = d3.select(params.root + ' .viz_svg').append('g').classed(inst_rc + '_tree_group', true).on('mouseover', function () {
	
		    // only if no menu is showing
		    if (d3.select(params.root + ' .tree_menu').empty()) {
	
		      d3.selectAll(params.viz.root_tips + '_tree_menu_tip').style('opacity', 1).style('display', 'block');
	
		      tree_menu_tip.show();
		    }
	
		    d3.selectAll(params.root + ' .tree_leaf_circle').style('opacity', high_opacity);
		  }).on('mouseout', function () {
		    tree_menu_tip.hide();
		    d3.selectAll(params.root + ' .tree_leaf_circle').style('opacity', default_opacity);
		  }).call(tree_menu_tip);
	
		  var tree_icon_group = tree_icon_outer_group.append('g').classed('dendro_tree_container', true).on('click', function () {
	
		    if (d3.select(params.root + ' .tree_menu').empty()) {
	
		      toggle_tree_menu(cgm, 'open');
	
		      tree_menu_tip.hide();
		    } else {
	
		      toggle_tree_menu(cgm, 'close');
		    }
		  });
	
		  d3.select(params.root + ' .dendro_tree_container').attr('transform', 'scale(0.9)');
	
		  position_svg_dendro_slider(cgm, inst_rc);
	
		  var offset_triangle = 0;
		  var tree_width = 20;
	
		  // main branch
		  tree_icon_group.append('path').style('fill', 'black').attr('transform', 'translate(' + offset_triangle + ', 0)').attr('d', function () {
	
		    // up triangle
		    var start_x = 0;
		    var start_y = slider_length;
	
		    var mid_x = tree_width / 2; //left_x + slider_length/10;
		    var mid_y = 0;
	
		    var final_x = tree_width; //left_x + slider_length/5;
		    var final_y = slider_length;
	
		    var output_string = 'M' + start_x + ',' + start_y + ', L' + mid_x + ', ' + mid_y + ', L' + final_x + ',' + final_y + ' Z';
	
		    return output_string;
		  }).style('opacity', 0.35);
	
		  // left branch
		  var branch_height = 30;
		  tree_icon_group.append('path').style('fill', 'black').attr('transform', 'translate(' + offset_triangle + ', 0)').attr('d', function () {
	
		    // up triangle
		    var start_x = 4.3;
		    var start_y = 23;
	
		    var mid_x = -5; //left_x + slider_length/10;
		    var mid_y = branch_height / 2.5;
	
		    var final_x = 5.8; //left_x + slider_length/5;
		    var final_y = branch_height / 1.8;
	
		    var output_string = 'M' + start_x + ',' + start_y + ', L' + mid_x + ', ' + mid_y + ', L' + final_x + ',' + final_y + ' Z';
	
		    return output_string;
		  }).style('opacity', 0.35);
	
		  // right branch
		  tree_icon_group.append('path').style('fill', 'black').attr('transform', 'translate(' + offset_triangle + ', 0)').attr('d', function () {
	
		    // up triangle
		    var start_x = 15.7;
		    var start_y = 23;
	
		    var mid_x = 25; //left_x + slider_length/10;
		    var mid_y = branch_height / 2.5;
	
		    var final_x = 14.2; //left_x + slider_length/5;
		    var final_y = branch_height / 1.8;
	
		    var output_string = 'M' + start_x + ',' + start_y + ', L' + mid_x + ', ' + mid_y + ', L' + final_x + ',' + final_y + ' Z';
	
		    return output_string;
		  }).style('opacity', 0.35);
	
		  var small_leaf_offset = 13;
		  var small_leaf_radius = 9.5;
	
		  tree_icon_group.selectAll().data([[-3, small_leaf_offset, small_leaf_radius], [tree_width / 2, 0, 17], [23, small_leaf_offset, small_leaf_radius]]).enter().append('circle').classed('tree_leaf_circle', true).attr('r', function (d) {
		    return d[2];
		  }).attr('transform', function (d) {
		    return 'translate(' + d[0] + ', ' + d[1] + ')';
		  }).attr('fill', 'blue').attr('opacity', default_opacity).attr('');
	
		  tree_icon_group.append('rect').attr('width', 50).attr('height', 62).attr('transform', function () {
		    return 'translate(' + -15 + ', ' + -19 + ')';
		  }).attr('opacity', 0.0);
			};
	
	/***/ }),
	/* 192 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_tree_menu = __webpack_require__(193);
	
		module.exports = function toggle_tree_menu(cgm, toggle) {
	
		  var params = cgm.params;
	
		  if (toggle === 'open') {
	
		    // console.log('open')
		    make_tree_menu(cgm);
		  } else if (toggle === 'close') {
	
		    d3.select(params.root + ' .tree_menu').transition(700).attr('opacity', 0);
	
		    setTimeout(function () {
		      d3.select(params.root + ' .tree_menu').remove();
		    }, 700);
		  }
			};
	
	/***/ }),
	/* 193 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var recluster = __webpack_require__(194);
	
		module.exports = function make_tree_menu(cgm) {
	
		  var params = cgm.params;
		  var menu_width = 475;
	
		  // make tree menu (state is in cgm, remade each time)
		  /////////////////////////////////////////////////////
		  var tree_menu = d3.select(params.root + ' .viz_svg').append('g').attr('transform', function () {
		    var shift = {};
		    shift.x = params.viz.clust.dim.width + params.viz.clust.margin.left - menu_width + 25;
		    shift.y = params.viz.clust.margin.top;
		    return 'translate(' + shift.x + ', ' + shift.y + ')';
		  }).classed('tree_menu', true);
	
		  tree_menu.attr('opacity', 0.0).transition().attr('opacity', 1.0);
	
		  tree_menu.append('rect').classed('tree_menu_background', true).attr('width', function () {
		    var inst_width = menu_width;
		    return inst_width;
		  }).attr('height', function () {
		    var inst_height = 500;
		    return inst_height;
		  }).attr('fill', 'white').attr('stroke', '#A3A3A3').attr('stroke-width', '3px').attr('opacity', 0.95);
	
		  // tree_menu
		  tree_menu.append('text').classed('tree_menu_title', true).attr('transform', 'translate(20,30)').attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').attr('font-size', '18px').attr('font-weight', 800).attr('cursor', 'default').text('Clustering Menu');
	
		  // menu options
		  var possible_distances = ['cosine', 'euclidean', 'correlation', 'jaccard'];
		  var vertical_space = 30;
		  var menu_y_offset = 110;
		  var distance_line_offset = 80;
	
		  tree_menu.append('text').attr('transform', 'translate(25, 70)').attr('font-size', '18px').attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').style('cursor', 'default').text('Distance Metric');
	
		  tree_menu.append('rect').classed('tree_menu_line', true).attr('height', '2px').attr('width', '435px').attr('stroke-width', '3px').attr('opacity', 0.3).attr('fill', 'black').attr('transform', 'translate(20,' + distance_line_offset + ')');
	
		  var distance_section = tree_menu.append('g').attr('transform', 'translate(20,' + menu_y_offset + ')').classed('distance_section', true);
	
		  var distance_groups = distance_section.selectAll('g').data(possible_distances).enter().append('g').attr('transform', function (d, i) {
		    var vert = i * vertical_space;
		    var transform_string = 'translate(0,' + vert + ')';
		    return transform_string;
		  }).on('click', function (d) {
	
		    // if (d === 'euclidean'){
		    // toggle tree menu
		    d3.select(params.root + ' .tree_menu').transition(700).attr('opacity', 0);
		    setTimeout(function () {
		      d3.select(params.root + ' .tree_menu').remove();
		    }, 700);
	
		    // update distance metric
		    cgm.params.matrix.distance_metric = d;
	
		    recluster(cgm, d);
		    // }
		  });
	
		  distance_groups.append('circle').attr('cx', 10).attr('cy', -6).attr('r', 7).style('stroke', '#A3A3A3').style('stroke-width', '2px').style('fill', function (d) {
		    var inst_color = 'white';
		    if (d === cgm.params.matrix.distance_metric) {
		      inst_color = 'red';
		    }
	
		    return inst_color;
		  });
	
		  distance_groups.append('text').attr('transform', 'translate(25,0)').style('font-size', '16px').attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').style('cursor', 'default').text(function (d) {
		    return capitalizeFirstLetter(d);
		  });
	
		  function capitalizeFirstLetter(string) {
		    return string.charAt(0).toUpperCase() + string.slice(1);
		  }
	
		  ///////////////////////////////////////////////////////
		};
	
	/***/ }),
	/* 194 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var clusterfck = __webpack_require__(195);
		var core = __webpack_require__(12);
		var math = core.create();
		var dist_fun = __webpack_require__(199);
		var get_order_and_groups_clusterfck_tree = __webpack_require__(200);
		var update_view = __webpack_require__(202);
	
		math.import(__webpack_require__(227));
		math.import(__webpack_require__(25));
	
		module.exports = function recluster(cgm, new_distance_metric) {
	
		  var new_view = {};
		  new_view.N_row_sum = 'null';
		  new_view.N_row_var = 'null';
		  new_view.dist = new_distance_metric;
	
		  // // constructing new nodes from old view (does not work when filtering)
		  // new_view.nodes = $.extend(true, [], cgm.params.network_data.views[0].nodes);
	
		  new_view.nodes = {};
		  new_view.nodes.row_nodes = $.extend(true, [], cgm.params.network_data.row_nodes);
		  new_view.nodes.col_nodes = $.extend(true, [], cgm.params.network_data.col_nodes);
	
		  _.each(['row', 'col'], function (inst_rc) {
	
		    var mat;
		    var transpose = math.transpose;
		    var names;
		    var name_nodes;
	
		    if (inst_rc === 'row') {
		      mat = $.extend(true, [], cgm.params.network_data.mat);
	
		      names = cgm.params.network_data.row_nodes_names;
		      name_nodes = 'row_nodes';
		    } else if (inst_rc === 'col') {
		      mat = $.extend(true, [], cgm.params.network_data.mat);
		      mat = transpose(mat);
	
		      names = cgm.params.network_data.col_nodes_names;
		      name_nodes = 'col_nodes';
		    }
	
		    var clusters = clusterfck.hcluster(mat, dist_fun[new_distance_metric]);
	
		    var order_info = get_order_and_groups_clusterfck_tree(clusters, names);
		    var inst_node;
		    var inst_order;
	
		    // row or column nodes
		    var rc_nodes = new_view.nodes[name_nodes];
	
		    for (var index = 0; index < rc_nodes.length; index++) {
	
		      inst_node = rc_nodes[index];
		      inst_order = order_info.info[index];
	
		      inst_node.clust = inst_order.order;
		      inst_node.group = inst_order.group;
		    }
		  });
	
		  // add new view to views
		  cgm.config.network_data.views.push(new_view);
		  update_view(cgm, 'dist', new_distance_metric);
			};
	
	/***/ }),
	/* 195 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = {
		   hcluster: __webpack_require__(196),
		   Kmeans: __webpack_require__(198),
		   kmeans: __webpack_require__(198).kmeans
			};
	
	/***/ }),
	/* 196 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var distances = __webpack_require__(197);
	
		var HierarchicalClustering = function HierarchicalClustering(distance, linkage, threshold) {
	
		   this.distance = distance || "euclidean";
		   this.linkage = linkage || "average";
		   this.threshold = threshold == undefined ? Infinity : threshold;
	
		   if (typeof this.distance == "string") {
		      this.distance = distances[this.distance];
		   }
		};
	
		HierarchicalClustering.prototype = {
		   tree: function tree(items, snapshotPeriod, snapshotCb) {
		      this.tree = [];
		      this.dists = []; // distances between each pair of clusters
		      this.mins = []; // closest cluster for each cluster
		      this.index = []; // keep a hash of all clusters by key
	
		      for (var i = 0; i < items.length; i++) {
		         var cluster = {
		            value: items[i],
		            key: i,
		            index: i,
		            size: 1
		         };
		         this.tree[i] = cluster;
		         this.index[i] = cluster;
		         this.dists[i] = [];
		         this.mins[i] = 0;
		      }
	
		      for (var i = 0; i < this.tree.length; i++) {
	
		         for (var j = 0; j <= i; j++) {
		            var dist = i == j ? Infinity : this.distance(this.tree[i].value, this.tree[j].value);
		            this.dists[i][j] = dist;
		            this.dists[j][i] = dist;
	
		            if (dist < this.dists[i][this.mins[i]]) {
		               this.mins[i] = j;
		            }
		         }
		      }
	
		      this.dists_backup = $.extend(true, [], this.dists);
	
		      var merged = this.mergeClosest();
		      var i = 0;
		      while (merged) {
		         if (snapshotCb && i++ % snapshotPeriod == 0) {
		            snapshotCb(this.tree);
		         }
		         merged = this.mergeClosest();
		      }
	
		      // do not remove index or key
		      ///////////////////////////////
		      // this.tree.forEach(function(cluster) {
		      //   // clean up metadata used for clustering
		      //   delete cluster.key;
		      //   delete cluster.index;
		      // });
	
	
		      return this.tree;
		   },
	
		   mergeClosest: function mergeClosest() {
		      // find two closest clusters from cached mins
		      var minKey = 0,
		          min = Infinity;
		      for (var i = 0; i < this.tree.length; i++) {
		         var key = this.tree[i].key,
		             dist = this.dists[key][this.mins[key]];
		         if (dist < min) {
		            minKey = key;
		            min = dist;
		         }
		      }
		      if (min >= this.threshold) {
		         return false;
		      }
	
		      var c1 = this.index[minKey],
		          c2 = this.index[this.mins[minKey]];
	
		      // merge two closest clusters
		      var merged = {
		         dist: min,
		         left: c1,
		         right: c2,
		         key: c1.key,
		         size: c1.size + c2.size
		      };
	
		      this.tree[c1.index] = merged;
		      this.tree.splice(c2.index, 1);
		      this.index[c1.key] = merged;
	
		      // update distances with new merged cluster
		      for (var i = 0; i < this.tree.length; i++) {
		         var ci = this.tree[i];
		         var dist;
		         if (c1.key == ci.key) {
		            dist = Infinity;
		         } else if (this.linkage == "single") {
		            dist = this.dists[c1.key][ci.key];
		            if (this.dists[c1.key][ci.key] > this.dists[c2.key][ci.key]) {
		               dist = this.dists[c2.key][ci.key];
		            }
		         } else if (this.linkage == "complete") {
		            dist = this.dists[c1.key][ci.key];
		            if (this.dists[c1.key][ci.key] < this.dists[c2.key][ci.key]) {
		               dist = this.dists[c2.key][ci.key];
		            }
		         } else if (this.linkage == "average") {
		            dist = (this.dists[c1.key][ci.key] * c1.size + this.dists[c2.key][ci.key] * c2.size) / (c1.size + c2.size);
		         } else {
		            dist = this.distance(ci.value, c1.value);
		         }
	
		         this.dists[c1.key][ci.key] = this.dists[ci.key][c1.key] = dist;
		      }
	
		      // update cached mins
		      for (var i = 0; i < this.tree.length; i++) {
		         var key1 = this.tree[i].key;
		         if (this.mins[key1] == c1.key || this.mins[key1] == c2.key) {
		            var min = key1;
		            for (var j = 0; j < this.tree.length; j++) {
		               var key2 = this.tree[j].key;
		               if (this.dists[key1][key2] < this.dists[key1][min]) {
		                  min = key2;
		               }
		            }
		            this.mins[key1] = min;
		         }
		         this.tree[i].index = i;
		      }
	
		      // // clean up metadata used for clustering
		      // delete c1.key; delete c2.key;
		      // delete c1.index; delete c2.index;
	
	
		      return true;
		   },
		   clusters: function clusters(num) {
		      //  Return all nodes if num is invalid
		      if (num > this.tree.size || num < 1) num = this.tree.size;
	
		      var result = [],
		          subtrees = [this.tree];
	
		      //  Get a list of root nodes for num different clusters
		      while (num > 1) {
		         var furthest = _findNextFurthest(subtrees);
		         subtrees.splice(subtrees.indexOf(furthest), 1);
		         subtrees.push(furthest.left, furthest.right);
		         num--;
		      }
	
		      //  Transform the subtrees node list into a list of the subtrees leaf values
		      subtrees.forEach(function (tree) {
		         result.push(_getValues(tree));
		      });
	
		      //  Split the next furthest distance root node
		      function _findNextFurthest(subtrees) {
		         var max = -1,
		             furthest;
		         subtrees.forEach(function (tree) {
		            if (tree.dist > max) {
		               max = tree.dist;
		               furthest = tree;
		            }
		         });
		         return furthest;
		      }
	
		      //  Traverse the tree and yield a list of the leaf node values
		      function _getValues(tree) {
		         if (tree.size === 1) return [tree.value];
		         return _getValues(tree.left).concat(_getValues(tree.right));
		      }
	
		      return result;
		   }
		};
	
		var hcluster = function hcluster(items, distance, linkage, threshold, snapshot, snapshotCallback) {
		   var hc = new HierarchicalClustering(distance, linkage, threshold);
		   var tree = hc.tree(items, snapshot, snapshotCallback);
	
		   return {
		      hc: hc,
		      tree: threshold === undefined ? tree[0] : tree,
		      clusters: hc.clusters
		   };
		};
	
		module.exports = hcluster;
	
	/***/ }),
	/* 197 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = {
		   euclidean: function euclidean(v1, v2) {
		      var total = 0;
		      for (var i = 0; i < v1.length; i++) {
		         total += Math.pow(v2[i] - v1[i], 2);
		      }
		      return Math.sqrt(total);
		   },
		   manhattan: function manhattan(v1, v2) {
		      var total = 0;
		      for (var i = 0; i < v1.length; i++) {
		         total += Math.abs(v2[i] - v1[i]);
		      }
		      return total;
		   },
		   max: function max(v1, v2) {
		      var max = 0;
		      for (var i = 0; i < v1.length; i++) {
		         max = Math.max(max, Math.abs(v2[i] - v1[i]));
		      }
		      return max;
		   }
			};
	
	/***/ }),
	/* 198 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var distances = __webpack_require__(197);
	
		function KMeans(centroids) {
		   this.centroids = centroids || [];
		}
	
		KMeans.prototype.randomCentroids = function (points, k) {
		   var centroids = points.slice(0); // copy
		   centroids.sort(function () {
		      return Math.round(Math.random()) - 0.5;
		   });
		   return centroids.slice(0, k);
		};
	
		KMeans.prototype.classify = function (point, distance) {
		   var min = Infinity,
		       index = 0;
	
		   distance = distance || "euclidean";
		   if (typeof distance == "string") {
		      distance = distances[distance];
		   }
	
		   for (var i = 0; i < this.centroids.length; i++) {
		      var dist = distance(point, this.centroids[i]);
		      if (dist < min) {
		         min = dist;
		         index = i;
		      }
		   }
	
		   return index;
		};
	
		KMeans.prototype.cluster = function (points, k, distance, snapshotPeriod, snapshotCb) {
		   k = k || Math.max(2, Math.ceil(Math.sqrt(points.length / 2)));
	
		   distance = distance || "euclidean";
		   if (typeof distance == "string") {
		      distance = distances[distance];
		   }
	
		   this.centroids = this.randomCentroids(points, k);
	
		   var assignment = new Array(points.length);
		   var clusters = new Array(k);
	
		   var iterations = 0;
		   var movement = true;
		   while (movement) {
		      // update point-to-centroid assignments
		      for (var i = 0; i < points.length; i++) {
		         assignment[i] = this.classify(points[i], distance);
		      }
	
		      // update location of each centroid
		      movement = false;
		      for (var j = 0; j < k; j++) {
		         var assigned = [];
		         for (var i = 0; i < assignment.length; i++) {
		            if (assignment[i] == j) {
		               assigned.push(points[i]);
		            }
		         }
	
		         if (!assigned.length) {
		            continue;
		         }
	
		         var centroid = this.centroids[j];
		         var newCentroid = new Array(centroid.length);
	
		         for (var g = 0; g < centroid.length; g++) {
		            var sum = 0;
		            for (var i = 0; i < assigned.length; i++) {
		               sum += assigned[i][g];
		            }
		            newCentroid[g] = sum / assigned.length;
	
		            if (newCentroid[g] != centroid[g]) {
		               movement = true;
		            }
		         }
	
		         this.centroids[j] = newCentroid;
		         clusters[j] = assigned;
		      }
	
		      if (snapshotCb && iterations++ % snapshotPeriod == 0) {
		         snapshotCb(clusters);
		      }
		   }
	
		   return clusters;
		};
	
		KMeans.prototype.toJSON = function () {
		   return JSON.stringify(this.centroids);
		};
	
		KMeans.prototype.fromJSON = function (json) {
		   this.centroids = JSON.parse(json);
		   return this;
		};
	
		module.exports = KMeans;
	
		module.exports.kmeans = function (vectors, k) {
		   return new KMeans().cluster(vectors, k);
		};
	
	/***/ }),
	/* 199 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		function vec_dot_product(vecA, vecB) {
		  var product = 0;
		  for (var i = 0; i < vecA.length; i++) {
		    product = product + vecA[i] * vecB[i];
		  }
		  return product;
		}
	
		function vec_magnitude(vec) {
		  var sum = 0;
		  for (var i = 0; i < vec.length; i++) {
		    sum = sum + vec[i] * vec[i];
		  }
		  return Math.sqrt(sum);
		}
	
		function vec_diff_value(vec, val) {
		  var vec_sub = [];
		  for (var i = 0; i < vec.length; i++) {
		    vec_sub.push(vec[i] - val);
		  }
		  return vec_sub;
		}
	
		function vec_mean(vec) {
		  var sum = 0;
		  var mean;
		  for (var i = 0; i < vec.length; i++) {
		    sum = sum + vec[i];
		  }
	
		  mean = sum / vec.length;
	
		  return mean;
		}
	
		module.exports = {
	
		  'euclidean': function euclidean(v1, v2) {
		    var total = 0;
		    for (var i = 0; i < v1.length; i++) {
		      total = total + Math.pow(v2[i] - v1[i], 2);
		    }
		    return Math.sqrt(total);
		  },
		  'cosine': function cosine(vecA, vecB) {
	
		    var cos_sim = vec_dot_product(vecA, vecB) / (vec_magnitude(vecA) * vec_magnitude(vecB));
	
		    var cos_dist = 1 - cos_sim;
	
		    return cos_dist;
		  },
		  'correlation': function correlation(vecA, vecB) {
	
		    var vecA_mean = vec_mean(vecA);
		    var vecB_mean = vec_mean(vecB);
	
		    var vecA_diff_mean = vec_diff_value(vecA, vecA_mean);
		    var vecB_diff_mean = vec_diff_value(vecB, vecB_mean);
	
		    var cor_sim = vec_dot_product(vecA_diff_mean, vecB_diff_mean) / (vec_magnitude(vecA_diff_mean) * vec_magnitude(vecB_diff_mean));
		    var cor_diff = 1 - cor_sim;
	
		    return cor_diff;
		  }
			};
	
	/***/ }),
	/* 200 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var get_max_distance_in_dm = __webpack_require__(201);
	
		module.exports = function get_order_and_groups_clusterfck_tree(clusters, names) {
	
		  // console.log('**** checking in get_order ***********************')
		  // console.log(clusters.hc.dists[0][5])
		  // console.log(clusters.hc.dists[0])
	
		  // console.log('**** checking dists_backup get_order ***********************')
		  // console.log(clusters.hc.dists_backup[0][5])
		  // console.log(clusters.hc.dists_backup[0])
	
	
		  var max_distance_in_dm = get_max_distance_in_dm(clusters.hc.dists_backup);
	
		  // get order information from clusterfck tree
		  ///////////////////////////////////////////////
		  var inst_order = 0;
		  var group = [];
		  var order_array = [];
		  var order_list = [];
		  var inst_leaf;
		  var inst_key;
	
		  // start hierarchy
		  var tree = clusters.tree;
		  var ini_level = 1;
		  var tree_height = tree.dist;
	
		  // var cutoff_fractions = [];
		  var cutoff_vals = [];
		  var cutoff_indexes = [];
		  var threshold_status = [];
		  for (var i = 0; i <= 10; i++) {
		    cutoff_vals.push(max_distance_in_dm * i / 10);
		    // cutoff_vals.push(manual_cutoff);
		    threshold_status.push('above');
		    group.push(0);
		    cutoff_indexes.push(i);
		  }
	
		  _.each(['left', 'right'], function (side) {
	
		    get_leaves(tree[side], side, ini_level, tree_height, threshold_status);
		  });
	
		  function get_leaves(limb, side, inst_level, inst_dist, threshold_status) {
	
		    // lock if distance is under resolvable distance
		    _.each(cutoff_indexes, function (index) {
		      if (inst_dist <= cutoff_vals[index]) {
	
		        // increment group if going from above to below threshold
		        if (threshold_status[index] === 'above') {
		          group[index] = group[index] + 1;
		        }
	
		        // locks[index] = true;
		        threshold_status[index] = 'below';
		      } else {
	
		        threshold_status[index] = 'above';
		      }
		    });
	
		    // if there are more branches then there is a distance
		    if (_.has(limb, 'dist')) {
	
		      inst_dist = limb.dist;
		      inst_level = inst_level + 1;
	
		      _.each(['left', 'right'], function (side2) {
		        get_leaves(limb[side2], side2, inst_level, inst_dist, threshold_status);
		      });
		    } else {
	
		      inst_key = limb.key;
	
		      // increment group if leaf is above threshold
		      _.each(cutoff_indexes, function (index) {
	
		        if (threshold_status[index] === 'above') {
		          group[index] = group[index] + 1;
		        }
		      });
	
		      inst_leaf = {};
		      inst_leaf.level = inst_level;
		      inst_leaf.order = inst_order;
	
		      // need to make copy of group not reference
		      // inst_leaf.group = group;
		      inst_leaf.group = $.extend(true, [], group);
	
		      inst_leaf.key = inst_key;
		      inst_leaf.dist = inst_dist;
	
		      inst_leaf.name = names[inst_key];
	
		      order_array.push(inst_leaf);
		      order_list.push(inst_key);
	
		      // increment order when terminal node is found
		      inst_order = inst_order + 1;
		    }
		  }
	
		  // sort on key value
		  order_array.sort(function (a, b) {
		    return a.key - b.key;
		  });
	
		  // generate ordered names
		  var inst_name;
		  var ordered_names = [];
		  _.each(order_list, function (index) {
		    inst_name = names[index];
		    ordered_names.push(inst_name);
		  });
	
		  var order_info = {};
		  order_info.info = order_array;
		  order_info.order = order_list;
		  order_info.ordered_names = ordered_names;
	
		  return order_info;
			};
	
	/***/ }),
	/* 201 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function get_max_tree_distance(dm) {
	
		  var max_distance_in_dm = 0;
	
		  _.each(dm, function (row) {
		    _.each(row, function (inst_val) {
		      if (isFinite(inst_val)) {
		        if (inst_val > max_distance_in_dm) {
		          max_distance_in_dm = inst_val;
		        }
		      }
		    });
		  });
	
		  return max_distance_in_dm;
			};
	
	/***/ }),
	/* 202 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var update_viz_with_view = __webpack_require__(203);
		var reset_other_filter_sliders = __webpack_require__(225);
	
		module.exports = function update_view(cgm, filter_type, inst_state) {
	
		  // add something to control slider position
		  /////////////////////////////////////////////
	
		  var requested_view = {};
		  requested_view[filter_type] = inst_state;
		  update_viz_with_view(cgm, requested_view);
	
		  reset_other_filter_sliders(cgm, filter_type, inst_state);
		};
	
	/***/ }),
	/* 203 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_network_using_view = __webpack_require__(10);
		var disable_sidebar = __webpack_require__(204);
		var update_viz_with_network = __webpack_require__(205);
	
		module.exports = function update_viz_with_view(cgm, requested_view) {
	
		  disable_sidebar(cgm.params);
	
		  // make new_network_data by filtering the original network data
		  var new_network_data = make_network_using_view(cgm.config, cgm.params, requested_view);
	
		  // reset crop button
		  d3.select(cgm.params.root + ' .crop_button').style('color', '#337ab7').classed('fa-crop', true).classed('fa-undo', false).classed('active_cropping', false);
	
		  // reset dendrogram filtering when updating with a new view
		  // e.g. with the row filter sliders
		  _.each(['row', 'col'], function (inst_rc) {
	
		    // set class to reflect that no filtering was ran
		    d3.select(cgm.params.root + ' .' + inst_rc + '_dendro_icons_group').classed('ran_filter', false);
	
		    // display all crop buttons when cropping has not been done
		    d3.select(cgm.params.root + ' .' + inst_rc + '_dendro_icons_container').style('display', 'block');
		  });
	
		  update_viz_with_network(cgm, new_network_data);
			};
	
	/***/ }),
	/* 204 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function disable_sidebar(params) {
	
		  d3.selectAll(params.root + ' .btn').attr('disabled', true);
		  d3.select(params.viz.viz_svg).style('opacity', 0.70);
			};
	
	/***/ }),
	/* 205 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_params = __webpack_require__(9);
		var define_enter_exit_delays = __webpack_require__(206);
		var enter_exit_update = __webpack_require__(207);
		var initialize_resizing = __webpack_require__(151);
		var make_col_cat = __webpack_require__(180);
		var make_row_cat = __webpack_require__(185);
		var make_row_dendro = __webpack_require__(186);
		var make_col_dendro = __webpack_require__(187);
		var ini_sidebar = __webpack_require__(218);
		var enable_sidebar = __webpack_require__(220);
		var ini_doubleclick = __webpack_require__(161);
		var update_reorder_buttons = __webpack_require__(221);
		var make_row_cat_super_labels = __webpack_require__(150);
		var modify_row_node_cats = __webpack_require__(222);
		var run_zoom = __webpack_require__(153);
		var ds_enter_exit_update = __webpack_require__(224);
		var make_cat_params = __webpack_require__(84);
	
		module.exports = function update_viz_with_network(cgm, new_network_data) {
	
		  // set runnning_update class, prevents multiple update from running at once
		  d3.select(cgm.params.viz.viz_svg).classed('running_update', true);
	
		  // remove downsampled rows always
		  d3.selectAll(cgm.params.root + ' .ds' + String(cgm.params.viz.ds_level) + '_row').remove();
	
		  // run optional callback function
		  if (cgm.params.matrix_update_callback != null) {
		    cgm.params.matrix_update_callback();
		  }
	
		  var inst_distance_metric = cgm.params.matrix.distance_metric;
		  var inst_group_level = cgm.params.group_level;
		  var inst_crop_fitler = cgm.params.crop_filter_nodes;
	
		  // make tmp config to make new params
		  var tmp_config = jQuery.extend(true, {}, cgm.config);
	
		  var new_row_cats = null;
	
		  // bring in 'new' category data
		  if (cgm.params.new_row_cats != null) {
		    modify_row_node_cats(cgm.params.new_row_cats, new_network_data.row_nodes);
		    new_row_cats = cgm.params.new_row_cats;
		    cgm.params.new_row_cats = new_row_cats;
		    // do not preserve the updated (row) cats
		    var predefined_cat_colors = true;
		    cgm.params.viz = make_cat_params(cgm.params, cgm.params.viz, predefined_cat_colors);
		  }
	
		  tmp_config.network_data = new_network_data;
		  tmp_config.inst_order = cgm.params.viz.inst_order;
		  tmp_config.input_domain = cgm.params.matrix.opacity_scale.domain()[1];
	
		  update_reorder_buttons(tmp_config, cgm.params);
	
		  // tmp_config.ini_expand = false;
		  tmp_config.ini_view = null;
		  tmp_config.current_col_cat = cgm.params.current_col_cat;
	
		  // disabled, causing problems when cropping
		  // always preserve category colors when updating
		  tmp_config.cat_colors = cgm.params.viz.cat_colors;
	
		  var new_params = make_params(tmp_config);
	
		  // this function is sensitive to further updates, so run here
		  var delays = define_enter_exit_delays(cgm.params, new_params);
	
		  // pass the newly calcluated params back to the cgm object
		  cgm.params = new_params;
	
		  // set up zoom
		  cgm.params.zoom_behavior = d3.behavior.zoom().scaleExtent([1, cgm.params.viz.square_zoom * cgm.params.viz.zoom_ratio.x]).on('zoom', function () {
		    run_zoom(cgm);
		  });
	
		  // Persistent Parameters
		  /////////////////////////
		  cgm.params.matrix.distance_metric = inst_distance_metric;
	
		  // have persistent group levels while updating
		  cgm.params.group_level = inst_group_level;
	
		  // have persistent crop_filter_nodes while updating
		  cgm.params.crop_filter_nodes = inst_crop_fitler;
	
		  // only run enter-exit-updates if there is no downsampling
		  if (cgm.params.viz.ds_num_levels === 0) {
		    // new_network_data is necessary
		    enter_exit_update(cgm, new_network_data, delays);
		  } else {
		    ds_enter_exit_update(cgm);
		  }
	
		  // reduce opacity during update
		  d3.select(cgm.params.viz.viz_svg).style('opacity', 0.70);
	
		  make_row_cat(cgm);
		  make_row_cat_super_labels(cgm);
	
		  if (cgm.params.viz.show_categories.col) {
		    make_col_cat(cgm);
		  }
	
		  if (cgm.params.viz.show_dendrogram) {
		    make_row_dendro(cgm);
		    make_col_dendro(cgm);
		  }
	
		  initialize_resizing(cgm);
	
		  d3.select(cgm.params.viz.viz_svg).call(cgm.params.zoom_behavior);
	
		  ini_doubleclick(cgm);
	
		  ini_sidebar(cgm);
	
		  cgm.params.viz.run_trans = true;
	
		  // d3.selectAll(cgm.params.viz.root_tips)
		  //   .style('opacity',0);
	
		  setTimeout(enable_sidebar, 2500, cgm.params);
	
		  // remove all dendro shadows
		  setTimeout(remove_shadows, 50);
		  setTimeout(remove_shadows, 100);
		  setTimeout(remove_shadows, 500);
		  setTimeout(remove_shadows, 1000);
		  setTimeout(remove_shadows, 1500);
	
		  function remove_shadows() {
		    d3.selectAll('.dendro_shadow').remove();
		  }
	
		  function finish_update() {
		    d3.select(cgm.params.viz.viz_svg).transition().duration(250).style('opacity', 1.0);
	
		    setTimeout(finish_update_class, 1000);
		  }
	
		  setTimeout(finish_update, delays.enter);
	
		  function finish_update_class() {
		    d3.select(cgm.params.viz.viz_svg).classed('running_update', false);
		  }
			};
	
	/***/ }),
	/* 206 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function (old_params, params) {
	
		  // exit, update, enter
	
		  // check if exit or enter or both are required
		  var old_row_nodes = old_params.network_data.row_nodes;
		  var old_col_nodes = old_params.network_data.col_nodes;
		  var old_row = _.map(old_row_nodes, function (d) {
		    return d.name;
		  });
		  var old_col = _.map(old_col_nodes, function (d) {
		    return d.name;
		  });
		  var all_old_nodes = old_row.concat(old_col);
	
		  var row_nodes = params.network_data.row_nodes;
		  var col_nodes = params.network_data.col_nodes;
		  var row = _.map(row_nodes, function (d) {
		    return d.name;
		  });
		  var col = _.map(col_nodes, function (d) {
		    return d.name;
		  });
		  var all_nodes = row.concat(col);
	
		  var exit_nodes = _.difference(all_old_nodes, all_nodes).length;
		  var enter_nodes = _.difference(all_nodes, all_old_nodes).length;
	
		  var delays = {};
	
		  if (exit_nodes > 0) {
		    delays.update = 1000;
		  } else {
		    delays.update = 0;
		  }
	
		  if (enter_nodes > 0) {
		    delays.enter = 1000;
		  } else {
		    delays.enter = 0;
		  }
	
		  delays.enter = delays.enter + delays.update;
	
		  delays.run_transition = true;
	
		  var old_num_links = old_params.network_data.links.length;
		  var new_num_links = params.network_data.links.length;
		  var cutoff_num_links = 0.5 * params.matrix.def_large_matrix;
	
		  if (old_num_links > cutoff_num_links || new_num_links > cutoff_num_links) {
		    delays.run_transition = false;
		    delays.update = 0;
		    delays.enter = 0;
		  }
	
		  return delays;
		};
	
	/***/ }),
	/* 207 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var reset_size_after_update = __webpack_require__(208);
		var make_row_label_container = __webpack_require__(101);
		var make_col_label_container = __webpack_require__(131);
		var eeu_existing_row = __webpack_require__(209);
		var exit_components = __webpack_require__(213);
		var draw_gridlines = __webpack_require__(91);
		var enter_row_groups = __webpack_require__(214);
		var resize_containers = __webpack_require__(217);
		var label_constrain_and_trim = __webpack_require__(145);
		var d3_tip_custom = __webpack_require__(100);
	
		module.exports = function enter_exit_update(cgm, network_data, delays) {
	
		  var params = cgm.params;
	
		  // remove old tooltips
		  d3.selectAll(params.viz.root_tips).remove();
	
		  // d3-tooltip - for tiles
		  var tip = d3_tip_custom().attr('class', function () {
		    var root_tip_selector = params.viz.root_tips.replace('.', '');
		    var class_string = root_tip_selector + ' d3-tip ' + root_tip_selector + '_tile_tip';
		    return class_string;
		  }).direction('nw').offset([0, 0]).style('display', 'none').html(function (d) {
		    var inst_value = String(d.value.toFixed(3));
		    var tooltip_string;
	
		    if (params.keep_orig) {
		      var orig_value = String(d.value_orig.toFixed(3));
		      tooltip_string = '<p>' + d.row_name + ' and ' + d.col_name + '</p>' + '<p> normalized value: ' + inst_value + '</p>' + '<div> original value: ' + orig_value + '</div>';
		    } else {
		      tooltip_string = '<p>' + d.row_name + ' and ' + d.col_name + '</p>' + '<div> value: ' + inst_value + '</div>';
		    }
	
		    return tooltip_string;
		  });
	
		  d3.select(params.root + ' .clust_group').call(tip);
	
		  // necessary for repositioning clust, col and col-cat containers
		  resize_containers(params);
	
		  var duration = 1000;
	
		  // make global so that names can be accessed
		  var row_nodes = network_data.row_nodes;
		  var col_nodes = network_data.col_nodes;
		  var links = network_data.links;
	
		  //
		  var tile_data = links;
	
		  // add name to links for object constancy
		  for (var i = 0; i < tile_data.length; i++) {
		    var d = tile_data[i];
		    tile_data[i].name = row_nodes[d.source].name + '_' + col_nodes[d.target].name;
		  }
	
		  // move rows
		  var move_rows = d3.select(params.root + ' .clust_group').selectAll('.row').data(params.matrix.matrix, function (d) {
		    return d.name;
		  });
	
		  if (delays.run_transition) {
		    move_rows.transition().delay(delays.update).duration(duration).attr('transform', function (d) {
		      var tmp_index = d.row_index;
		      return 'translate(0,' + params.viz.y_scale(tmp_index) + ')';
		    });
		  } else {
		    move_rows.attr('transform', function (d) {
		      var tmp_index = d.row_index;
		      return 'translate(0,' + params.viz.y_scale(tmp_index) + ')';
		    });
		  }
	
		  // update existing rows - enter, exit, update tiles in existing row
		  d3.select(params.root + ' .clust_group').selectAll('.row').each(function (d) {
		    // TODO add tip back to arguments
		    var inst_selection = this;
		    eeu_existing_row(params, d, delays, duration, inst_selection, tip);
		  });
	
		  d3.selectAll(params.root + ' .horz_lines').remove();
		  d3.selectAll(params.root + ' .vert_lines').remove();
	
		  // exit
		  ////////////
		  exit_components(params, delays, duration);
	
		  // resize clust components using appropriate delays
		  reset_size_after_update(cgm, duration, delays);
	
		  // enter new elements
		  //////////////////////////
		  enter_row_groups(params, delays, duration, tip);
	
		  // update existing rows
		  make_row_label_container(cgm, duration);
		  make_col_label_container(cgm, duration);
	
		  draw_gridlines(params, delays, duration);
	
		  setTimeout(label_constrain_and_trim, 2000, params);
			};
	
	/***/ }),
	/* 208 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var utils = __webpack_require__(2);
		var calc_clust_height = __webpack_require__(74);
		var get_svg_dim = __webpack_require__(71);
		var calc_clust_width = __webpack_require__(73);
		var reset_zoom = __webpack_require__(162);
		var resize_dendro = __webpack_require__(163);
		var resize_super_labels = __webpack_require__(164);
		var resize_spillover = __webpack_require__(165);
		var resize_row_labels = __webpack_require__(167);
		var resize_row_viz = __webpack_require__(169);
		var resize_col_labels = __webpack_require__(170);
		var resize_col_text = __webpack_require__(171);
		var resize_col_triangle = __webpack_require__(172);
		var resize_col_hlight = __webpack_require__(173);
		var resize_label_bars = __webpack_require__(176);
		var calc_default_fs = __webpack_require__(83);
		var calc_zoom_switching = __webpack_require__(82);
		// var show_visible_area = require('../zoom/show_visible_area');
		var ini_zoom_info = __webpack_require__(88);
	
		module.exports = function reset_size_after_update(cgm) {
		  var duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
		  var delays = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
	
	
		  if (delays === null) {
		    delays = {};
		    delays.enter = 0;
		    delays.update = 0;
		    delays.run_transition = false;
		  }
	
		  var params = cgm.params;
	
		  var row_nodes = cgm.params.network_data.row_nodes;
	
		  params.zoom_info = ini_zoom_info();
	
		  // // not sure if this is necessary
		  // ////////////////////////////
		  // show_visible_area(params);
		  // // quick fix for column filtering
		  // setTimeout(show_visible_area, 2200, cgm);
	
		  var row_nodes_names = params.network_data.row_nodes_names;
	
		  reset_zoom(params);
	
		  // Resetting some visualization parameters
		  params = get_svg_dim(params);
		  params.viz = calc_clust_width(params.viz);
		  params.viz = calc_clust_height(params.viz);
	
		  if (params.sim_mat) {
		    if (params.viz.clust.dim.width <= params.viz.clust.dim.height) {
		      params.viz.clust.dim.height = params.viz.clust.dim.width;
		    } else {
		      params.viz.clust.dim.width = params.viz.clust.dim.height;
		    }
		  }
	
		  params.viz = calc_zoom_switching(params.viz);
	
		  // redefine x_scale and y_scale rangeBands
		  params.viz.x_scale.rangeBands([0, params.viz.clust.dim.width]);
		  params.viz.y_scale.rangeBands([0, params.viz.clust.dim.height]);
	
		  // redefine zoom extent
		  params.viz.square_zoom = params.viz.norm_labels.width.col / (params.viz.x_scale.rangeBand() / 2);
		  params.zoom_behavior.scaleExtent([1, params.viz.square_zoom * params.viz.zoom_ratio.x]);
	
		  // redefine border width
		  params.viz.border_width.x = params.viz.x_scale.rangeBand() / params.viz.border_fraction;
		  params.viz.border_width.y = params.viz.y_scale.rangeBand() / params.viz.border_fraction;
	
		  params = calc_default_fs(params);
	
		  // resize the svg
		  ///////////////////////
		  var svg_group = d3.select(params.viz.viz_wrapper).select('svg');
	
		  svg_group.select(params.root + ' .grey_background').transition().delay(delays.update).duration(duration).attr('width', params.viz.clust.dim.width).attr('height', params.viz.clust.dim.height);
	
		  resize_row_labels(params, svg_group, delays);
	
		  // do not delay the font size change since this will break the bounding box calc
		  svg_group.selectAll('.row_label_group').select('text').style('font-size', params.labels.default_fs_row + 'px').text(function (d) {
		    return utils.normal_name(d);
		  });
	
		  // change the size of the highlighting rects
		  svg_group.selectAll('.row_label_group').each(function () {
		    var bbox = d3.select(this).select('text')[0][0].getBBox();
		    d3.select(this).select('rect').attr('x', bbox.x).attr('y', 0).attr('width', bbox.width).attr('height', params.viz.y_scale.rangeBand()).style('fill', 'yellow').style('opacity', function (d) {
		      var inst_opacity = 0;
		      // highlight target genes
		      if (d.target === 1) {
		        inst_opacity = 1;
		      }
		      return inst_opacity;
		    });
		  });
	
		  resize_row_viz(params, svg_group, delays);
	
		  if (delays.run_transition) {
	
		    // positioning row text after row text size may have been reduced
		    svg_group.selectAll('.row_label_group').select('text').transition().delay(delays.update).duration(duration).attr('y', params.viz.rect_height * 0.5 + params.labels.default_fs_row * 0.35);
	
		    svg_group.selectAll('.row_cat_group').data(row_nodes, function (d) {
		      return d.name;
		    }).transition().delay(delays.update).duration(duration).attr('transform', function (d) {
		      var inst_index = _.indexOf(row_nodes_names, d.name);
		      return 'translate(0, ' + params.viz.y_scale(inst_index) + ')';
		    });
	
		    svg_group.selectAll('.row_cat_group').select('path').transition().delay(delays.update).duration(duration).attr('d', function () {
		      var origin_x = params.viz.cat_room.symbol_width - 1;
		      var origin_y = 0;
		      var mid_x = 1;
		      var mid_y = params.viz.y_scale.rangeBand() / 2;
		      var final_x = params.viz.cat_room.symbol_width - 1;
		      var final_y = params.viz.y_scale.rangeBand();
		      var output_string = 'M ' + origin_x + ',' + origin_y + ' L ' + mid_x + ',' + mid_y + ', L ' + final_x + ',' + final_y + ' Z';
		      return output_string;
		    });
	
		    svg_group.selectAll('.row_dendro_group').data(row_nodes, function (d) {
		      return d.name;
		    }).transition().delay(delays.update).duration(duration).attr('transform', function (d) {
		      var inst_index = _.indexOf(row_nodes_names, d.name);
		      return 'translate(0, ' + params.viz.y_scale(inst_index) + ')';
		    });
		  } else {
	
		    // positioning row text after row text size may have been reduced
		    svg_group.selectAll('.row_label_group').select('text').attr('y', params.viz.rect_height * 0.5 + params.labels.default_fs_row * 0.35);
	
		    svg_group.selectAll('.row_cat_group').data(row_nodes, function (d) {
		      return d.name;
		    }).attr('transform', function (d) {
		      var inst_index = _.indexOf(row_nodes_names, d.name);
		      return 'translate(0, ' + params.viz.y_scale(inst_index) + ')';
		    });
	
		    svg_group.selectAll('.row_cat_group').select('path').attr('d', function () {
		      var origin_x = params.viz.cat_room.symbol_width - 1;
		      var origin_y = 0;
		      var mid_x = 1;
		      var mid_y = params.viz.y_scale.rangeBand() / 2;
		      var final_x = params.viz.cat_room.symbol_width - 1;
		      var final_y = params.viz.y_scale.rangeBand();
		      var output_string = 'M ' + origin_x + ',' + origin_y + ' L ' + mid_x + ',' + mid_y + ', L ' + final_x + ',' + final_y + ' Z';
		      return output_string;
		    });
	
		    svg_group.selectAll('.row_dendro_group').data(row_nodes, function (d) {
		      return d.name;
		    }).attr('transform', function (d) {
		      var inst_index = _.indexOf(row_nodes_names, d.name);
		      return 'translate(0, ' + params.viz.y_scale(inst_index) + ')';
		    });
		  }
	
		  if (utils.has(params.network_data.row_nodes[0], 'value')) {
	
		    resize_label_bars(cgm, svg_group);
		  }
	
		  // resize col labels
		  ///////////////////////
		  // reduce width of rotated rects
	
		  resize_col_labels(params, svg_group, delays);
		  resize_col_text(params, svg_group);
		  resize_col_triangle(params, svg_group, delays);
	
		  resize_col_hlight(params, svg_group, delays);
	
		  resize_dendro(params, svg_group, delays);
		  resize_super_labels(params, svg_group, delays);
		  resize_spillover(params.viz, svg_group, delays);
	
		  // reset zoom and translate
		  params.zoom_behavior.scale(1).translate([params.viz.clust.margin.left, params.viz.clust.margin.top]);
			};
	
	/***/ }),
	/* 209 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var exit_existing_row = __webpack_require__(210);
		var enter_existing_row = __webpack_require__(211);
		var update_split_tiles = __webpack_require__(212);
		var mouseover_tile = __webpack_require__(97);
		var mouseout_tile = __webpack_require__(98);
		var fine_position_tile = __webpack_require__(99);
		var underscore = __webpack_require__(68);
	
		// TODO add tip back to arguments
		module.exports = function eeu_existing_row(params, ini_inp_row_data, delays, duration, row_selection, tip) {
	
		  var inp_row_data = ini_inp_row_data.row_data;
	
		  // remove zero values from
		  var row_values = _.filter(inp_row_data, function (num) {
		    return num.value != 0;
		  });
	
		  // bind data to tiles
		  var cur_row_tiles = d3.select(row_selection).selectAll('.tile').data(row_values, function (d) {
		    return d.col_name;
		  });
	
		  exit_existing_row(params, delays, cur_row_tiles, inp_row_data, row_selection);
	
		  ///////////////////////////
		  // Update
		  ///////////////////////////
	
		  // update tiles in x direction
		  var update_row_tiles = cur_row_tiles.on('mouseover', function () {
		    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
		      args[_key] = arguments[_key];
		    }
	
		    mouseover_tile(params, this, tip, args);
		  }).on('mouseout', function mouseout() {
		    mouseout_tile(params, this, tip);
		  });
	
		  var col_nodes_names = params.network_data.col_nodes_names;
	
		  if (delays.run_transition) {
	
		    update_row_tiles.transition().delay(delays.update).duration(duration).attr('width', params.viz.rect_width).attr('height', params.viz.rect_height).attr('transform', function (d) {
		      // if (_.contains(col_nodes_names, d.col_name)){
		      if (underscore.contains(col_nodes_names, d.col_name)) {
		        return fine_position_tile(params, d);
		      } else {
		        return 'translate(0,0)';
		      }
		    });
		  } else {
		    update_row_tiles.attr('width', params.viz.rect_width).attr('height', params.viz.rect_height).attr('transform', function (d) {
		      if (underscore.contains(col_nodes_names, d.col_name)) {
		        return fine_position_tile(params, d);
		      } else {
		        return 'translate(0,0)';
		      }
		    });
		  }
	
		  if (params.matrix.tile_type == 'updn') {
		    update_split_tiles(params, inp_row_data, row_selection, delays, duration, cur_row_tiles, tip);
		  }
	
		  enter_existing_row(params, delays, duration, cur_row_tiles, tip);
			};
	
	/***/ }),
	/* 210 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function exit_existing_row(params, delays, cur_row_tiles, inp_row_data, row_selection) {
	
		  if (delays.run_transition) {
		    cur_row_tiles.exit().transition().duration(300).attr('fill-opacity', 0).remove();
		  } else {
		    cur_row_tiles.exit().attr('fill-opacity', 0).remove();
		  }
	
		  if (params.matrix.tile_type == 'updn') {
	
		    // value split
		    var row_split_data = _.filter(inp_row_data, function (num) {
		      return num.value_up != 0 || num.value_dn != 0;
		    });
	
		    // tile_up
		    var cur_tiles_up = d3.select(row_selection).selectAll('.tile_up').data(row_split_data, function (d) {
		      return d.col_name;
		    });
	
		    if (delays.run_transition) {
		      cur_tiles_up.exit().transition().duration(300).attr('fill', '0').remove();
		    } else {
		      cur_tiles_up.exit().attr('fill', 0).remove();
		    }
	
		    // tile_dn
		    var cur_tiles_dn = d3.select(row_selection).selectAll('.tile_dn').data(row_split_data, function (d) {
		      return d.col_name;
		    });
	
		    if (delays.run_transition) {
		      cur_tiles_dn.exit().transition().duration(300).attr('fill', 0).remove();
		    } else {
		      cur_tiles_dn.exit().attr('fill', 0).remove();
		    }
		  }
			};
	
	/***/ }),
	/* 211 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var mouseover_tile = __webpack_require__(97);
		var mouseout_tile = __webpack_require__(98);
		var fine_position_tile = __webpack_require__(99);
	
		module.exports = function enter_existing_row(params, delays, duration, cur_row_tiles, tip) {
	
		  // enter new tiles
		  var new_tiles = cur_row_tiles.enter().append('rect').attr('class', 'tile row_tile').attr('width', params.viz.rect_width).attr('height', params.viz.rect_height).on('mouseover', function () {
		    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
		      args[_key] = arguments[_key];
		    }
	
		    mouseover_tile(params, this, tip, args);
		  }).on('mouseout', function mouseout() {
		    mouseout_tile(params, this, tip);
		  }).attr('fill-opacity', 0).attr('transform', function (d) {
		    return fine_position_tile(params, d);
		  });
	
		  if (delays.run_transition) {
		    new_tiles.transition().delay(delays.enter).duration(duration).style('fill', function (d) {
		      return d.value > 0 ? params.matrix.tile_colors[0] : params.matrix.tile_colors[1];
		    }).attr('fill-opacity', function (d) {
		      var output_opacity = params.matrix.opacity_scale(Math.abs(d.value));
		      return output_opacity;
		    });
		  } else {
		    new_tiles.style('fill', function (d) {
		      return d.value > 0 ? params.matrix.tile_colors[0] : params.matrix.tile_colors[1];
		    }).attr('fill-opacity', function (d) {
		      var output_opacity = params.matrix.opacity_scale(Math.abs(d.value));
		      return output_opacity;
		    });
		  }
	
		  // remove new tiles if necessary
		  new_tiles.each(function (d) {
		    if (Math.abs(d.value_up) > 0 && Math.abs(d.value_dn) > 0) {
		      d3.select(this).remove();
		    }
		  });
		};
	
	/***/ }),
	/* 212 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var draw_up_tile = __webpack_require__(95);
		var draw_dn_tile = __webpack_require__(96);
		var mouseover_tile = __webpack_require__(97);
		var mouseout_tile = __webpack_require__(98);
		var fine_position_tile = __webpack_require__(99);
	
		module.exports = function update_split_tiles(params, inp_row_data, row_selection, delays, duration, cur_row_tiles, tip) {
	
		  // value split
		  var row_split_data = _.filter(inp_row_data, function (num) {
		    return num.value_up != 0 || num.value_dn != 0;
		  });
	
		  // tile_up
		  var cur_tiles_up = d3.select(row_selection).selectAll('.tile_up').data(row_split_data, function (d) {
		    return d.col_name;
		  });
	
		  // update split tiles_up
		  var update_tiles_up = cur_tiles_up.on('mouseover', function () {
		    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
		      args[_key] = arguments[_key];
		    }
	
		    mouseover_tile(params, this, tip, args);
		  }).on('mouseout', function mouseout() {
		    mouseout_tile(params, this, tip);
		  });
	
		  if (delays.run_transition) {
		    update_tiles_up.transition().delay(delays.update).duration(duration).attr('d', function () {
		      return draw_up_tile(params);
		    }).attr('transform', function (d) {
		      return fine_position_tile(params, d);
		    });
		  } else {
		    update_tiles_up.attr('d', function () {
		      return draw_up_tile(params);
		    }).attr('transform', function (d) {
		      return fine_position_tile(params, d);
		    });
		  }
	
		  // tile_dn
		  var cur_tiles_dn = d3.select(row_selection).selectAll('.tile_dn').data(row_split_data, function (d) {
		    return d.col_name;
		  });
	
		  // update split tiles_dn
		  var update_tiles_dn = cur_tiles_dn.on('mouseover', function () {
		    for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
		      args[_key2] = arguments[_key2];
		    }
	
		    mouseover_tile(params, this, tip, args);
		  }).on('mouseout', function mouseout() {
		    mouseout_tile(params, this, tip);
		  });
	
		  if (delays.run_transition) {
		    update_tiles_dn.transition().delay(delays.update).duration(duration).attr('d', function () {
		      return draw_dn_tile(params);
		    }).attr('transform', function (d) {
		      return fine_position_tile(params, d);
		    });
		  } else {
		    update_tiles_dn.attr('d', function () {
		      return draw_dn_tile(params);
		    }).attr('transform', function (d) {
		      return fine_position_tile(params, d);
		    });
		  }
	
		  // remove tiles when splitting is done
		  cur_row_tiles.selectAll('.tile').each(function (d) {
		    if (Math.abs(d.value_up) > 0 && Math.abs(d.value_dn) > 0) {
		      d3.select(this).remove();
		    }
		  });
		};
	
	/***/ }),
	/* 213 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function exit_components(params, delays, duration) {
	
		  var row_nodes = params.network_data.row_nodes;
		  var col_nodes = params.network_data.col_nodes;
	
		  // remove entire rows
		  var exiting_rows = d3.select(params.root + ' .clust_group').selectAll('.row').data(params.matrix.matrix, function (d) {
		    return d.name;
		  }).exit();
	
		  if (delays.run_transition) {
		    exiting_rows.transition().duration(duration).style('opacity', 0).remove();
		  } else {
		    exiting_rows.style('opacity', 0).remove();
		  }
	
		  // remove row labels
		  d3.selectAll(params.root + ' .row_label_group').data(row_nodes, function (d) {
		    return d.name;
		  }).exit().transition().duration(duration).style('opacity', 0).remove();
	
		  // remove column labels
		  d3.selectAll(params.root + ' .col_label_group').data(col_nodes, function (d) {
		    return d.name;
		  }).exit().transition().duration(duration).style('opacity', 0).remove();
	
		  // remove row triangles and colorbars
		  d3.selectAll(params.root + ' .row_cat_group').data(row_nodes, function (d) {
		    return d.name;
		  }).exit().transition().duration(duration).style('opacity', 0).remove();
	
		  // remove row triangles and colorbars
		  d3.selectAll(params.root + ' .row_dendro_group').data(row_nodes, function (d) {
		    return d.name;
		  }).exit().transition().duration(duration).style('opacity', 0).remove();
	
		  d3.selectAll(params.root + ' .col_label_text').data(col_nodes, function (d) {
		    return d.name;
		  }).exit().transition().duration(duration).style('opacity', 0).remove();
	
		  d3.selectAll(params.root + ' .horz_lines').data(row_nodes, function (d) {
		    return d.name;
		  }).exit().transition().duration(duration).style('opacity', 0).remove();
	
		  d3.selectAll(params.root + ' .vert_lines').data(col_nodes, function (d) {
		    return d.name;
		  }).exit().transition().duration(duration).style('opacity', 0).remove();
	
		  // remove dendrogram
		  d3.selectAll(params.root + ' .col_cat_group').data(col_nodes, function (d) {
		    return d.name;
		  }).exit().transition().duration(duration).style('opacity', 0).remove();
	
		  d3.selectAll(params.root + ' .col_dendro_group').data(col_nodes, function (d) {
		    return d.name;
		  }).exit().transition().duration(duration).style('opacity', 0).remove();
			};
	
	/***/ }),
	/* 214 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var enter_new_rows = __webpack_require__(215);
	
		module.exports = function enter_row_groups(params, delays, duration, tip) {
	
		  // enter new rows
		  var new_row_groups = d3.select(params.root + ' .clust_group').selectAll('.row').data(params.matrix.matrix, function (d) {
		    return d.name;
		  }).enter().append('g').classed('row', true).attr('transform', function (d) {
		    return 'translate(0,' + params.viz.y_scale(d.row_index) + ')';
		  });
	
		  new_row_groups.each(function (d) {
		    enter_new_rows(params, d, delays, duration, tip, this);
		  });
			};
	
	/***/ }),
	/* 215 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var enter_split_tiles = __webpack_require__(216);
		var mouseover_tile = __webpack_require__(97);
		var mouseout_tile = __webpack_require__(98);
		var fine_position_tile = __webpack_require__(99);
	
		// make each row in the clustergram
		module.exports = function enter_new_rows(params, ini_inp_row_data, delays, duration, tip, row_selection) {
	
		  var inp_row_data = ini_inp_row_data.row_data;
	
		  // remove zero values to make visualization faster
		  var row_data = _.filter(inp_row_data, function (num) {
		    return num.value !== 0;
		  });
	
		  // update tiles
		  ////////////////////////////////////////////
		  var tile = d3.select(row_selection).selectAll('rect').data(row_data, function (d) {
		    return d.col_name;
		  }).enter().append('rect').attr('class', 'tile row_tile').attr('width', params.viz.rect_width).attr('height', params.viz.rect_height)
		  // switch the color based on up/dn value
		  .style('fill', function (d) {
		    return d.value > 0 ? params.matrix.tile_colors[0] : params.matrix.tile_colors[1];
		  }).on('mouseover', function () {
		    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
		      args[_key] = arguments[_key];
		    }
	
		    mouseover_tile(params, this, tip, args);
		  }).on('mouseout', function mouseout() {
		    mouseout_tile(params, this, tip);
		  });
	
		  tile.style('fill-opacity', 0).transition().delay(delays.enter).duration(duration).style('fill-opacity', function (d) {
		    // calculate output opacity using the opacity scale
		    var output_opacity = params.matrix.opacity_scale(Math.abs(d.value));
		    return output_opacity;
		  });
	
		  tile.attr('transform', function (d) {
		    return fine_position_tile(params, d);
		  });
	
		  if (params.matrix.tile_type == 'updn') {
		    enter_split_tiles(params, inp_row_data, row_selection, tip, delays, duration, tile);
		  }
			};
	
	/***/ }),
	/* 216 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var draw_up_tile = __webpack_require__(95);
		var draw_dn_tile = __webpack_require__(96);
		var fine_position_tile = __webpack_require__(99);
	
		module.exports = function enter_split_tiles(params, inp_row_data, row_selection, tip, delays, duration, tile) {
	
		  // value split
		  var row_split_data = _.filter(inp_row_data, function (num) {
		    return num.value_up != 0 || num.value_dn != 0;
		  });
	
		  // tile_up
		  var new_tiles_up = d3.select(row_selection).selectAll('.tile_up').data(row_split_data, function (d) {
		    return d.col_name;
		  }).enter().append('path').attr('class', 'tile_up').attr('d', function () {
		    return draw_up_tile(params);
		  }).attr('transform', function (d) {
		    return fine_position_tile(params, d);
		  }).style('fill', function () {
		    return params.matrix.tile_colors[0];
		  }).on('mouseover', function (p) {
		    // highlight row - set text to active if
		    d3.selectAll(params.root + ' .row_label_group text').classed('active', function (d) {
		      return p.row_name === d.name;
		    });
	
		    d3.selectAll(params.root + ' .col_label_text text').classed('active', function (d) {
		      return p.col_name === d.name;
		    });
		    if (params.matrix.show_tile_tooltips) {
		      tip.show(p);
		    }
		  }).on('mouseout', function () {
		    d3.selectAll(params.root + ' text').classed('active', false);
		    if (params.matrix.show_tile_tooltips) {
		      tip.hide();
		    }
		  });
	
		  new_tiles_up.style('fill-opacity', 0).transition().delay(delays.enter).duration(duration).style('fill-opacity', function (d) {
		    var inst_opacity = 0;
		    if (Math.abs(d.value_dn) > 0) {
		      inst_opacity = params.matrix.opacity_scale(Math.abs(d.value_up));
		    }
		    return inst_opacity;
		  });
	
		  // tile_dn
		  var new_tiles_dn = d3.select(row_selection).selectAll('.tile_dn').data(row_split_data, function (d) {
		    return d.col_name;
		  }).enter().append('path').attr('class', 'tile_dn').attr('d', function () {
		    return draw_dn_tile(params);
		  }).attr('transform', function (d) {
		    return fine_position_tile(params, d);
		  }).style('fill', function () {
		    return params.matrix.tile_colors[1];
		  }).on('mouseover', function (p) {
		    // highlight row - set text to active if
		    d3.selectAll(params.root + ' .row_label_group text').classed('active', function (d) {
		      return p.row_name === d.name;
		    });
	
		    d3.selectAll(params.root + ' .col_label_text text').classed('active', function (d) {
		      return p.col_name === d.name;
		    });
		    if (params.matrix.show_tile_tooltips) {
		      tip.show(p);
		    }
		  }).on('mouseout', function () {
		    d3.selectAll(params.root + ' text').classed('active', false);
		    if (params.matrix.show_tile_tooltips) {
		      tip.hide();
		    }
		  });
	
		  new_tiles_dn.style('fill-opacity', 0).transition().delay(delays.enter).duration(duration).style('fill-opacity', function (d) {
		    var inst_opacity = 0;
		    if (Math.abs(d.value_up) > 0) {
		      inst_opacity = params.matrix.opacity_scale(Math.abs(d.value_dn));
		    }
		    return inst_opacity;
		  });
	
		  // remove tiles when splitting is done
		  tile.each(function (d) {
		    if (Math.abs(d.value_up) > 0 && Math.abs(d.value_dn) > 0) {
		      d3.select(this).remove();
		    }
		  });
			};
	
	/***/ }),
	/* 217 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function resize_containers(params) {
	
		  // reposition matrix
		  d3.select(params.root + ' .clust_container').attr('transform', 'translate(' + params.viz.clust.margin.left + ',' + params.viz.clust.margin.top + ')');
	
		  // reposition col container
		  d3.select(params.root + ' .col_label_outer_container').attr('transform', 'translate(0,' + params.viz.norm_labels.width.col + ')');
	
		  // reposition col_viz container
		  d3.select(params.root + ' .col_cat_outer_container').attr('transform', function () {
		    var inst_offset = params.viz.norm_labels.width.col + 2;
		    return 'translate(0,' + inst_offset + ')';
		  });
			};
	
	/***/ }),
	/* 218 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		/* eslint-disable */
	
		var change_groups = __webpack_require__(190);
		var all_reorder = __webpack_require__(143);
		var ini_cat_reorder = __webpack_require__(142);
		var run_row_search = __webpack_require__(219);
	
		module.exports = function ini_sidebar(cgm) {
	
		  var params = cgm.params;
	
		  var input = d3.select(params.root + ' .gene_search_box')[0][0];
		  var awesomplete = new Awesomplete(input, { minChars: 1, maxItems: 15 });
		  var entities = cgm.params.network_data.row_nodes_names;
		  awesomplete.list = entities;
	
		  // position awesomplete list elements above other elements in the page
		  d3.selectAll('.awesomplete ul').style('z-index', 99);
	
		  // submit genes button
		  $(params.root + ' .gene_search_box').keyup(function (e) {
		    if (e.keyCode === 13) {
		      var search_gene = $(params.root + ' .gene_search_box').val();
		      run_row_search(cgm, search_gene, entities);
		    }
		  });
	
		  $(params.root + ' .submit_gene_button').off().click(function () {
		    var search_gene = $(params.root + ' .gene_search_box').val();
		    run_row_search(cgm, search_gene, entities);
		  });
	
		  var reorder_types;
		  if (params.sim_mat) {
		    reorder_types = ['both'];
		  } else {
		    reorder_types = ['row', 'col'];
		  }
	
		  _.each(reorder_types, function (inst_rc) {
	
		    // reorder buttons
		    $(params.root + ' .toggle_' + inst_rc + '_order .btn').off().click(function (evt) {
	
		      var order_id = $(evt.target).attr('name').replace('_row', '').replace('_col', '');
	
		      d3.selectAll(params.root + ' .toggle_' + inst_rc + '_order .btn').classed('active', false);
	
		      d3.select(this).classed('active', true);
	
		      if (inst_rc != 'both') {
		        all_reorder(cgm, order_id, inst_rc);
		      } else {
		        all_reorder(cgm, order_id, 'row');
		        all_reorder(cgm, order_id, 'col');
		      }
		    });
		  });
	
		  ini_cat_reorder(cgm);
	
		  // Opacity Slider
		  //////////////////////////////////////////////////////////////////////
		  if (d3.select(cgm.params.root + ' .opacity_slider').select('#handle-one').empty()) {
	
		    var slider_fun = d3.slider().snap(true).value(1).min(0.1).max(1.9).step(0.1).on('slide', function (evt, value) {
		      run_on_opacity_slide(evt, value);
		    });
	
		    d3.select(cgm.params.root + ' .opacity_slider').call(slider_fun);
		  }
	
		  function run_on_dendro_slide(evt, value, inst_rc) {
		    $("#amount").val("$" + value);
		    var inst_index = value * 10;
		    // var inst_rc;
	
		    if (inst_rc != 'both') {
		      change_groups(cgm, inst_rc, inst_index);
		    } else {
		      change_groups(cgm, 'row', inst_index);
		      change_groups(cgm, 'col', inst_index);
		    }
		  }
	
		  function run_on_opacity_slide(evt, value) {
	
		    var inst_index = 2 - value;
		    var scaled_max = cgm.params.matrix.abs_max_val * inst_index;
	
		    cgm.params.matrix.opacity_scale.domain([0, scaled_max]);
	
		    d3.selectAll(cgm.params.root + ' .tile').style('fill-opacity', function (d) {
		      // calculate output opacity using the opacity scale
		      var output_opacity = cgm.params.matrix.opacity_scale(Math.abs(d.value));
		      return output_opacity;
		    });
		  }
			};
	
	/***/ }),
	/* 219 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var two_translate_zoom = __webpack_require__(144);
	
		module.exports = function run_row_search(cgm, search_term, entities) {
	
		  var prop = 'name';
	
		  if (entities.indexOf(search_term) !== -1) {
	
		    // unhighlight
		    d3.selectAll(cgm.params.root + ' .row_label_group').select('rect').style('opacity', 0);
	
		    // calc pan_dy
		    var idx = _.indexOf(entities, search_term);
		    var inst_y_pos = cgm.params.viz.y_scale(idx);
		    var pan_dy = cgm.params.viz.clust.dim.height / 2 - inst_y_pos;
	
		    var inst_zoom = cgm.params.viz.zoom_ratio.x;
	
		    // working on improving zoom behavior
		    ///////////////////////////////////////////////////
		    ///////////////////////////////////////////////////
	
		    // // increase zoom
		    // inst_zoom = 3 * inst_zoom;
	
		    // // move visualization down less
		    // pan_dy = pan_dy - 5;
	
		    two_translate_zoom(cgm, 0, pan_dy, inst_zoom);
	
		    // set y zoom to zoom_switch
		    cgm.params.zoom_info.zoom_y = inst_zoom;
	
		    // highlight
		    d3.selectAll(cgm.params.root + ' .row_label_group').filter(function (d) {
		      return d[prop] === search_term;
		    }).select('rect').style('opacity', 1);
		  }
			};
	
	/***/ }),
	/* 220 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function enable_sidebar(params) {
	
		  /* only enable dendrogram sliders if there has been no dendro_filtering */
	
		  // only enable reordering if params.dendro_filter.row === false
		  if (params.dendro_filter.row === false) {
	
		    // orders are switched!
		    if (params.viz.inst_order.col === 'clust') {
		      d3.select(params.root + ' .row_slider_group').style('opacity', 1).style('pointer-events', 'all');
		    }
		  }
	
		  d3.selectAll(params.root + ' .toggle_row_order .btn').attr('disabled', null);
	
		  if (params.dendro_filter.col === false) {
	
		    // orders are switched!
		    if (params.viz.inst_order.row === 'clust') {
		      d3.select(params.root + ' .col_slider_group').style('opacity', 1).style('pointer-events', 'all');
		    }
		  }
	
		  d3.selectAll(params.root + ' .toggle_col_order .btn').attr('disabled', null);
	
		  d3.selectAll(params.root + ' .gene_search_button .btn').attr('disabled', null);
	
		  params.viz.run_trans = false;
			};
	
	/***/ }),
	/* 221 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function update_reorder_buttons(tmp_config, params) {
		  _.each(['row', 'col'], function (inst_rc) {
	
		    var other_rc;
		    if (inst_rc === 'row') {
		      other_rc = 'col';
		    } else {
		      other_rc = 'row';
		    }
	
		    d3.selectAll(params.root + ' .toggle_' + other_rc + '_order .btn').filter(function () {
		      return d3.select(this).attr('name') === tmp_config.inst_order[inst_rc];
		    }).classed('active', true);
		  });
		};
	
	/***/ }),
	/* 222 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var remove_node_cats = __webpack_require__(223);
		var utils = __webpack_require__(2);
		var underscore = __webpack_require__(68);
	
		module.exports = function modify_row_node_cats(cat_data, inst_nodes) {
		  var strip_names = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
	
	
		  // console.log('MODIFY ROW NODE CATS')
		  // console.log('CAT_DATA')
		  // console.log(cat_data)
	
		  var cat_type_num = 0;
		  var inst_index = 0;
		  var inst_cat_title;
		  var inst_cats;
		  var inst_members;
		  var inst_name;
		  var inst_category;
		  var inst_cat_name;
		  var inst_full_cat;
		  var inst_cat_num;
	
		  // loop through row nodes
		  //////////////////////////
		  _.each(inst_nodes, function (inst_node) {
	
		    inst_name = inst_node.name;
	
		    // not sure if this is needed
		    // inst_name = inst_name.toUpperCase();
	
		    if (strip_names === true) {
		      // only consider first part of inst_name
		      ////////////////////////////////////////////
		      // may improve this
		      if (inst_name.indexOf(' ')) {
		        inst_name = inst_name.split(' ')[0];
		      } else if (inst_name.indexOf('_')) {
		        inst_name = inst_name.split('_')[0];
		      }
		    }
	
		    cat_type_num = 0;
	
		    remove_node_cats(inst_node);
	
		    // loop through each category type
		    _.each(cat_data, function (inst_cat_data) {
	
		      inst_cat_title = inst_cat_data.cat_title;
		      inst_cats = inst_cat_data.cats;
	
		      // initialize with no category
		      inst_category = 'false';
		      inst_index = -1;
	
		      inst_cat_num = 0;
	
		      // loop through each category in the category-type
		      _.each(inst_cats, function (inst_cat) {
	
		        inst_cat_name = inst_cat.cat_name;
		        inst_members = inst_cat.members;
	
		        // add category if node is a member
		        // if ( _.contains(inst_members, inst_name) ){
		        if (underscore.contains(inst_members, inst_name)) {
	
		          inst_category = inst_cat_name;
		          inst_index = inst_cat_num;
		        }
	
		        inst_cat_num = inst_cat_num + 1;
		      });
	
		      if (utils.has(inst_cat_data, 'pval')) {
	
		        var inst_pval = inst_cat_data.pval.toExponential();
		        inst_full_cat = inst_cat_title + ': ' + inst_category + '<p> Pval ' + String(inst_pval) + '</p>';
		      } else {
	
		        if (inst_cat_title.indexOf('cat-') === -1) {
		          inst_full_cat = inst_cat_title + ': ' + inst_category;
		        } else {
		          inst_full_cat = inst_category;
		        }
		      }
	
		      inst_node['cat-' + String(cat_type_num)] = inst_full_cat;
		      inst_node['cat_' + String(cat_type_num) + '_index'] = inst_index;
	
		      cat_type_num = cat_type_num + 1;
		    });
		  });
			};
	
	/***/ }),
	/* 223 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function remove_node_cats(inst_node) {
	
		  var all_props = _.keys(inst_node);
	
		  _.each(all_props, function (inst_prop) {
	
		    if (inst_prop.indexOf('cat-') > -1) {
		      delete inst_node[inst_prop];
		    }
	
		    if (inst_prop.indexOf('cat_') > -1) {
		      delete inst_node[inst_prop];
		    }
		  });
			};
	
	/***/ }),
	/* 224 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var reset_size_after_update = __webpack_require__(208);
		var make_col_label_container = __webpack_require__(131);
		var show_visible_area = __webpack_require__(134);
		var resize_containers = __webpack_require__(217);
	
		module.exports = function ds_enter_exit_update(cgm) {
	
		  // console.log('======== ds_enter_exit_update ===============');
	
		  // remove row labels, remove non-downsampled rows, and add downsampled rows
		  d3.selectAll(cgm.params.root + ' .row_cat_group').remove();
		  d3.selectAll(cgm.params.root + ' .row_label_group').remove();
		  d3.selectAll(cgm.params.root + ' .row').remove();
	
		  // no need to re-calculate the downsampled layers
		  // calc_downsampled_levels(params);
		  var zooming_stopped = true;
		  var zooming_out = true;
		  var make_all_rows = true;
	
		  // show_visible_area is also run with two_translate_zoom, but at that point
		  // the parameters were not updated and two_translate_zoom if only run
		  // if needed to reset zoom
		  show_visible_area(cgm, zooming_stopped, zooming_out, make_all_rows);
	
		  make_col_label_container(cgm);
	
		  var col_nodes = cgm.params.network_data.col_nodes;
	
		  // remove column labels
		  d3.selectAll(cgm.params.root + ' .col_label_group').data(col_nodes, function (d) {
		    return d.name;
		  }).exit().style('opacity', 0).remove();
	
		  d3.selectAll(cgm.params.root + ' .col_label_text').data(col_nodes, function (d) {
		    return d.name;
		  }).exit().style('opacity', 0).remove();
	
		  d3.selectAll(cgm.params.root + ' .col_cat_group').data(col_nodes, function (d) {
		    return d.name;
		  }).exit().style('opacity', 0).remove();
	
		  d3.selectAll(cgm.params.root + ' .col_dendro_group').data(col_nodes, function (d) {
		    return d.name;
		  }).exit().style('opacity', 0).remove();
	
		  // necessary for repositioning clust, col and col-cat containers
		  resize_containers(cgm.params);
	
		  // seeing if this fixes resizing issue
		  var delays = {};
		  delays.enter = 0;
		  delays.update = 0;
		  delays.run_transition = false;
		  var duration = 0;
		  reset_size_after_update(cgm, duration, delays);
			};
	
	/***/ }),
	/* 225 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_filter_title = __webpack_require__(226);
	
		module.exports = function reset_other_filter_sliders(cgm, filter_type, inst_state) {
	
		  var params = cgm.params;
		  var inst_rc;
		  var reset_rc;
	
		  d3.select(params.root + ' .slider_' + filter_type).attr('current_state', inst_state);
	
		  _.each(_.keys(params.viz.possible_filters), function (reset_filter) {
	
		    if (filter_type.indexOf('row') > -1) {
		      inst_rc = 'row';
		    } else if (filter_type.indexOf('col') > -1) {
		      inst_rc = 'col';
		    } else {
		      inst_rc = 'neither';
		    }
	
		    if (reset_filter.indexOf('row') > -1) {
		      reset_rc = 'row';
		    } else if (reset_filter.indexOf('col') > -1) {
		      reset_rc = 'col';
		    } else {
		      reset_rc = 'neither';
		    }
	
		    if (filter_type != reset_filter && inst_rc != 'neither') {
	
		      if (inst_rc == reset_rc) {
	
		        var tmp_title = make_filter_title(params, reset_filter);
	
		        cgm.slider_functions[reset_filter].value(0);
	
		        d3.select(params.root + ' .title_' + reset_filter).text(tmp_title.text + tmp_title.state);
	
		        d3.select(params.root + ' .slider_' + reset_filter).attr('current_state', tmp_title.state);
		      }
		    }
		  });
	
		  var filter_title = make_filter_title(params, filter_type);
	
		  d3.select(params.root + ' .title_' + filter_type).text(filter_title.text + inst_state + filter_title.suffix);
			};
	
	/***/ }),
	/* 226 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var get_filter_default_state = __webpack_require__(5);
	
		module.exports = function make_filter_title(params, filter_type) {
	
		  var filter_title = {};
		  var title = {};
		  var type = {};
	
		  filter_title.state = get_filter_default_state(params.viz.filter_data, filter_type);
	
		  type.top = filter_type.split('_')[0];
		  type.node = filter_type.split('_')[1];
		  type.measure = filter_type.split('_')[2];
	
		  if (type.node === 'row') {
		    title.node = 'rows';
		  } else {
		    title.node = 'columns';
		  }
	
		  if (type.top === 'N') {
		    // filter_title.suffix = ' '+title.node;
		    filter_title.suffix = '';
		  }
	
		  if (type.top === 'pct') {
		    filter_title.suffix = '%';
		  }
	
		  if (type.measure == 'sum') {
		    title.measure = 'sum';
		  } else if (type.measure == 'var') {
		    title.measure = 'variance';
		  }
	
		  if (type.measure === 'sum') {
		    filter_title.text = 'Top ' + title.node + ' ' + title.measure + ': ';
		  }
	
		  if (type.measure === 'var') {
		    filter_title.text = 'Top ' + title.node + ' ' + title.measure + ': ';
		  }
	
		  // Enrichr specific rules 
		  if (_.keys(params.viz.possible_filters).indexOf('enr_score_type') > -1) {
		    if (type.node === 'col') {
		      filter_title.text = 'Top Enriched Terms: ';
		      filter_title.suffix = '';
		    }
		  }
	
		  return filter_title;
		};
	
	/***/ }),
	/* 227 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var clone = __webpack_require__(14).clone;
		var format = __webpack_require__(29).format;
	
		function factory(type, config, load, typed) {
		  var latex = __webpack_require__(45);
	
		  var matrix = load(__webpack_require__(43));
	
		  var DenseMatrix = type.DenseMatrix,
		      SparseMatrix = type.SparseMatrix;
	
		  /**
		   * Transpose a matrix. All values of the matrix are reflected over its
		   * main diagonal. Only applicable to two dimensional matrices containing
		   * a vector (i.e. having size `[1,n]` or `[n,1]`). One dimensional
		   * vectors and scalars return the input unchanged.
		   *
		   * Syntax:
		   *
		   *     math.transpose(x)
		   *
		   * Examples:
		   *
		   *     var A = [[1, 2, 3], [4, 5, 6]];
		   *     math.transpose(A);               // returns [[1, 4], [2, 5], [3, 6]]
		   *
		   * See also:
		   *
		   *     diag, inv, subset, squeeze
		   *
		   * @param {Array | Matrix} x  Matrix to be transposed
		   * @return {Array | Matrix}   The transposed matrix
		   */
		  var transpose = typed('transpose', {
	
		    'Array': function Array(x) {
		      // use dense matrix implementation
		      return transpose(matrix(x)).valueOf();
		    },
	
		    'Matrix': function Matrix(x) {
		      // matrix size
		      var size = x.size();
	
		      // result
		      var c;
	
		      // process dimensions
		      switch (size.length) {
		        case 1:
		          // vector
		          c = x.clone();
		          break;
	
		        case 2:
		          // rows and columns
		          var rows = size[0];
		          var columns = size[1];
	
		          // check columns
		          if (columns === 0) {
		            // throw exception
		            throw new RangeError('Cannot transpose a 2D matrix with no columns (size: ' + format(size) + ')');
		          }
	
		          // process storage format
		          switch (x.storage()) {
		            case 'dense':
		              c = _denseTranspose(x, rows, columns);
		              break;
		            case 'sparse':
		              c = _sparseTranspose(x, rows, columns);
		              break;
		          }
		          break;
	
		        default:
		          // multi dimensional
		          throw new RangeError('Matrix must be a vector or two dimensional (size: ' + format(this._size) + ')');
		      }
		      return c;
		    },
	
		    // scalars
		    'any': function any(x) {
		      return clone(x);
		    }
		  });
	
		  var _denseTranspose = function _denseTranspose(m, rows, columns) {
		    // matrix array
		    var data = m._data;
		    // transposed matrix data
		    var transposed = [];
		    var transposedRow;
		    // loop columns
		    for (var j = 0; j < columns; j++) {
		      // initialize row
		      transposedRow = transposed[j] = [];
		      // loop rows
		      for (var i = 0; i < rows; i++) {
		        // set data
		        transposedRow[i] = clone(data[i][j]);
		      }
		    }
		    // return matrix
		    return new DenseMatrix({
		      data: transposed,
		      size: [columns, rows],
		      datatype: m._datatype
		    });
		  };
	
		  var _sparseTranspose = function _sparseTranspose(m, rows, columns) {
		    // matrix arrays
		    var values = m._values;
		    var index = m._index;
		    var ptr = m._ptr;
		    // result matrices
		    var cvalues = values ? [] : undefined;
		    var cindex = [];
		    var cptr = [];
		    // row counts
		    var w = [];
		    for (var x = 0; x < rows; x++) {
		      w[x] = 0;
		    } // vars
		    var p, l, j;
		    // loop values in matrix
		    for (p = 0, l = index.length; p < l; p++) {
		      // number of values in row
		      w[index[p]]++;
		    }
		    // cumulative sum
		    var sum = 0;
		    // initialize cptr with the cummulative sum of row counts
		    for (var i = 0; i < rows; i++) {
		      // update cptr
		      cptr.push(sum);
		      // update sum
		      sum += w[i];
		      // update w
		      w[i] = cptr[i];
		    }
		    // update cptr
		    cptr.push(sum);
		    // loop columns
		    for (j = 0; j < columns; j++) {
		      // values & index in column
		      for (var k0 = ptr[j], k1 = ptr[j + 1], k = k0; k < k1; k++) {
		        // C values & index
		        var q = w[index[k]]++;
		        // C[j, i] = A[i, j]
		        cindex[q] = j;
		        // check we need to process values (pattern matrix)
		        if (values) cvalues[q] = clone(values[k]);
		      }
		    }
		    // return matrix
		    return new SparseMatrix({
		      values: cvalues,
		      index: cindex,
		      ptr: cptr,
		      size: [columns, rows],
		      datatype: m._datatype
		    });
		  };
	
		  transpose.toTex = { 1: '\\left(${args[0]}\\right)' + latex.operators['transpose'] };
	
		  return transpose;
		}
	
		exports.name = 'transpose';
		exports.factory = factory;
	
	/***/ }),
	/* 228 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_dendro_crop_buttons = __webpack_require__(112);
	
		module.exports = function make_row_dendro_spillover(cgm) {
	
		  var viz = cgm.params.viz;
	
		  // hide spillover from right
		  var tmp_left = viz.clust.margin.left + viz.clust.dim.width + viz.uni_margin + viz.dendro_room.row;
	
		  var r_spill_container = d3.select(viz.viz_svg).append('g').classed('right_spillover_container', true).attr('transform', function () {
		    return 'translate(' + tmp_left + ', 0)';
		  });
	
		  var tmp_top = viz.norm_labels.margin.top + viz.norm_labels.width.col;
	
		  r_spill_container.append('rect').attr('fill', viz.background_color) //!! prog_colors
		  .attr('width', 10 * viz.clust.dim.width).attr('height', viz.svg_dim.height + 'px').attr('class', 'white_bars').attr('class', 'right_spillover').attr('transform', function () {
		    return 'translate( 0,' + tmp_top + ')';
		  });
	
		  var x_offset = 0;
		  var y_offset = viz.clust.margin.top;
		  r_spill_container.append('g').classed('row_dendro_icons_container', true).attr('transform', 'translate(' + x_offset + ',' + y_offset + ')').append('g').classed('row_dendro_icons_group', true);
	
		  make_dendro_crop_buttons(cgm, 'row');
	
		  // hide spillover from top of row dendrogram
		  x_offset = viz.clust.margin.left + viz.clust.dim.width;
		  y_offset = tmp_top;
	
		  var tmp_width = viz.dendro_room.row + viz.uni_margin;
		  var tmp_height = viz.cat_room.col + viz.uni_margin;
		  d3.select(viz.viz_svg).append('rect').attr('fill', viz.background_color).attr('width', tmp_width).attr('height', tmp_height).attr('transform', function () {
		    return 'translate(' + x_offset + ',' + y_offset + ')';
		  }).classed('white_bars', true).classed('dendro_row_spillover', true);
			};
	
	/***/ }),
	/* 229 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		/* eslint-disable */
	
		var run_segment = __webpack_require__(230);
		var play_intro = __webpack_require__(231);
		var play_zoom = __webpack_require__(233);
		var play_reset_zoom = __webpack_require__(234);
		var play_reorder_row = __webpack_require__(236);
		var play_reorder_buttons = __webpack_require__(237);
		var play_search = __webpack_require__(239);
		var play_filter = __webpack_require__(240);
		var quick_cluster = __webpack_require__(241);
		var play_groups = __webpack_require__(242);
		var play_categories = __webpack_require__(243);
		var play_conclusion = __webpack_require__(244);
		var toggle_play_button = __webpack_require__(245);
		var play_menu_button = __webpack_require__(246);
	
		module.exports = function play_demo() {
	
		  var cgm = this;
		  var params = cgm.params;
	
		  if (d3.select(params.root + ' .running_demo').empty()) {
	
		    // prevent more than one demo from running at once
		    d3.select(params.root + ' .play_button').classed('running_demo', true);
	
		    toggle_play_button(params, false);
	
		    // prevent user interaction while playing
		    $.blockUI({ css: {
		        border: 'none',
		        padding: '15px',
		        backgroundColor: '#000',
		        '-webkit-border-radius': '10px',
		        '-moz-border-radius': '10px',
		        opacity: 0,
		        color: '#fff',
		        cursor: 'default'
		      } });
	
		    d3.selectAll('.blockUI').style('opacity', 0);
	
		    // intro text
		    var inst_time = 750;
	
		    if (cgm.params.viz.is_expand === false) {
		      inst_time = run_segment(params, inst_time, quick_cluster);
		      inst_time = inst_time - 1500;
		    }
	
		    // clustergram interaction
		    ///////////////////////////////////
		    inst_time = run_segment(params, inst_time, play_intro);
		    inst_time = run_segment(params, inst_time, play_zoom);
		    inst_time = run_segment(cgm, inst_time, play_reset_zoom);
		    inst_time = run_segment(params, inst_time, play_categories);
		    inst_time = run_segment(params, inst_time, play_reorder_row);
	
		    // sidebar interaction
		    ///////////////////////////////////
		    inst_time = run_segment(params, inst_time, play_menu_button);
		    inst_time = run_segment(params, inst_time, play_groups);
		    inst_time = run_segment(params, inst_time, play_reorder_buttons);
		    inst_time = run_segment(params, inst_time, play_search);
		    inst_time = run_segment(cgm, inst_time, play_filter);
	
		    // conclusion
		    ///////////////////////////////////
		    inst_time = run_segment(params, inst_time, quick_cluster);
		    inst_time = run_segment(params, inst_time, play_conclusion);
		  }
			};
	
	/***/ }),
	/* 230 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function run_segment(segment_data, inst_time, inst_segment) {
		  /* eslint-disable */
	
		  var timer = setTimeout(inst_segment().run, inst_time, segment_data);
	
		  // set up kill demo that will stop setTimeouts
		  //////////////////////////////////////////////////
		  // if (clear_timer){
		  //   clearTimeout(timer);
		  // }
	
		  var inst_duration = inst_segment().get_duration();
		  inst_time = inst_time + inst_duration;
	
		  return inst_time;
			};
	
	/***/ }),
	/* 231 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var demo_text = __webpack_require__(232);
	
		module.exports = function play_intro() {
	
		  var speed_up = 1;
	
		  function run(params) {
		    var text_1 = 'Clustergrammer allows users to generate\ninteractive and ' + 'sharable visualizations\nby uploading a matrix';
		    var text_2 = "This demo will quickly overview some\nof Clustergrammer's " + "interactive features";
	
		    setTimeout(demo_text, 0, params, text_1, 4500 / speed_up);
		    setTimeout(demo_text, 4500 / speed_up, params, text_2, 4500 / speed_up);
		  }
	
		  function get_duration() {
		    return 10000 / speed_up;
		  }
	
		  return {
		    run: run,
		    get_duration: get_duration
		  };
			};
	
	/***/ }),
	/* 232 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function demo_text(params, text, read_duration) {
	
		  var split_text = text.split('\n');
	
		  if (split_text.length < 3) {
		    split_text.push('');
		  }
	
		  d3.select(params.root + ' .demo_group').style('opacity', 0).transition().duration(250).style('opacity', 1).transition().duration(250).delay(read_duration).style('opacity', 0);
	
		  for (var i = 0; i < split_text.length; i++) {
	
		    var inst_text_num = i + 1;
	
		    // make text box 
		    //////////////////
		    var inst_text_obj = d3.select(params.root + ' .demo_group').select('#text_' + inst_text_num).text(split_text[i]);
		    var bbox = inst_text_obj[0][0].getBBox();
	
		    var box_opacity = 0.9;
	
		    var tmp_fs = Number(d3.select('.demo_group').select('text').style('font-size').replace('px', ''));
		    var shift_height = tmp_fs * 1.3;
	
		    d3.select(params.root + ' .demo_group').select('.rect_' + inst_text_num).style('fill', 'white').attr('width', bbox.width + 20).attr('height', bbox.height).attr('x', -10).attr('y', bbox.y + i * shift_height).style('opacity', box_opacity);
		  }
			};
	
	/***/ }),
	/* 233 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var demo_text = __webpack_require__(232);
		var two_translate_zoom = __webpack_require__(144);
	
		module.exports = function play_zoom() {
	
		  function run(cgm) {
	
		    var params = cgm.params;
		    var text = 'Zoom and pan by\nscrolling and dragging';
		    demo_text(params, text, 4000);
	
		    setTimeout(two_translate_zoom, 1500, cgm, 0, 0, 4);
		  }
	
		  function get_duration() {
		    return 4000;
		  }
	
		  return {
		    run: run,
		    get_duration: get_duration
		  };
			};
	
	/***/ }),
	/* 234 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var demo_text = __webpack_require__(232);
		var two_translate_zoom = __webpack_require__(144);
		var sim_click = __webpack_require__(235);
	
		module.exports = function play_reset_zoom() {
	
		  function run(cgm) {
	
		    var params = cgm.params;
	
		    var text = 'Reset zoom by double-clicking\n';
		    demo_text(params, text, 4000);
	
		    setTimeout(sim_click, 2000, params, 'double', 300, 300);
		    setTimeout(two_translate_zoom, 2400, cgm, 0, 0, 1);
		  }
	
		  function get_duration() {
		    return 4500;
		  }
	
		  return {
		    run: run,
		    get_duration: get_duration
		  };
			};
	
	/***/ }),
	/* 235 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function sim_click(params, single_double, pos_x, pos_y) {
	
		  var click_duration = 200;
	
		  var click_circle = d3.select(params.root + ' .viz_svg').append('circle').attr('cx', pos_x).attr('cy', pos_y).attr('r', 25).style('stroke', 'black').style('stroke-width', '3px').style('fill', '#007f00').style('opacity', 0.5);
	
		  if (single_double === 'double') {
		    click_circle.transition().duration(click_duration).style('opacity', 0.0).transition().duration(50).style('opacity', 0.5).transition().duration(click_duration).style('opacity', 0.0).remove();
		  } else {
		    click_circle.transition().duration(click_duration).style('opacity', 0.0).transition().duration(250).remove();
		  }
			};
	
	/***/ }),
	/* 236 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var demo_text = __webpack_require__(232);
		var sim_click = __webpack_require__(235);
	
		module.exports = function play_reorder_row() {
		  /* eslint-disable */
	
		  function run(params) {
	
		    var text = 'Reorder the matrix based on a single\nrow or column by double-clicking a\nlabel';
		    demo_text(params, text, 7000);
	
		    var inst_element = get_row_element(params, 'EGFR');
	
		    var group_trans = d3.select(inst_element).attr('transform');
	
		    var container_trans = d3.select(params.root + ' .clust_container').attr('transform').split(',')[1].replace(')', '');
	
		    var x_trans = params.viz.norm_labels.width.row * 0.9;
	
		    var row_trans = group_trans.split(',')[1].replace(')', '');
		    var y_trans = String(Number(row_trans) + Number(container_trans) + params.viz.rect_height / 2);
	
		    var wait_click = 4000;
		    setTimeout(sim_click, wait_click, params, 'double', x_trans, y_trans);
		    var wait_reorder = wait_click + 300;
		    setTimeout(fire_double_click_row, wait_reorder, params, inst_element);
		  }
	
		  function get_duration() {
		    return 8000;
		  }
	
		  function get_row_element(params, inst_row) {
	
		    var inst_element = d3.selectAll(params.root + ' .row_label_group').filter(function () {
		      var inst_data = this.__data__;
		      return inst_data.name == inst_row;
		    })[0][0];
	
		    return inst_element;
		  }
	
		  function fire_double_click_row(params, inst_element) {
	
		    $(inst_element).d3DblClick();
		  }
	
		  // allows doubleclicking on d3 element
		  jQuery.fn.d3DblClick = function () {
		    this.each(function (i, e) {
		      var evt = document.createEvent("MouseEvents");
		      evt.initMouseEvent("dblclick", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
		      e.dispatchEvent(evt);
		    });
		  };
	
		  return {
		    run: run,
		    get_duration: get_duration
		  };
			};
	
	/***/ }),
	/* 237 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var demo_text = __webpack_require__(232);
		var highlight_sidebar_element = __webpack_require__(238);
	
		module.exports = function play_reorder_buttons() {
		  /* eslint-disable */
	
		  function run(params) {
	
		    var text = 'Reorder all rows and columns\nby clicking the reorder\n buttons';
		    demo_text(params, text, 9000);
	
		    setTimeout(highlight_sidebar_element, 3000, params, 'toggle_col_order');
		    setTimeout(click_reorder_button, 3500, params, 'col', 'rank');
	
		    setTimeout(highlight_sidebar_element, 7000, params, 'toggle_row_order');
		    setTimeout(click_reorder_button, 7500, params, 'row', 'rank');
		  }
	
		  function get_duration() {
		    return 11000;
		  }
	
		  function click_reorder_button(params, inst_rc, inst_order) {
		    var inst_button = d3.selectAll('.toggle_' + inst_rc + '_order .btn').filter(function () {
		      return this.__data__ == inst_order;
		    })[0];
	
		    $(inst_button).click();
		  }
	
		  return {
		    run: run,
		    get_duration: get_duration
		  };
			};
	
	/***/ }),
	/* 238 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function highlight_sidebar_element(params, highlight_class) {
		  var duration = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 4000;
	
	
		  if (highlight_class.indexOf('slider') < 0) {
		    d3.select(params.root + ' .' + highlight_class).style('background', '#007f00').style('box-shadow', '0px 0px 10px 5px #007f00').transition().duration(1).delay(duration).style('background', '#FFFFFF').style('box-shadow', 'none');
		  } else {
		    d3.select(params.root + ' .' + highlight_class).style('box-shadow', '0px 0px 10px 5px #007f00').transition().duration(1).delay(duration).style('box-shadow', 'none');
		  }
			};
	
	/***/ }),
	/* 239 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var demo_text = __webpack_require__(232);
		var highlight_sidebar_element = __webpack_require__(238);
		var two_translate_zoom = __webpack_require__(144);
	
		module.exports = function play_search() {
	
		  function run(cgm) {
	
		    var params = cgm.params;
		    var text = 'Search for rows using\nthe search box';
		    demo_text(params, text, 5000);
	
		    var ini_delay = 2500;
		    setTimeout(highlight_sidebar_element, ini_delay, params, 'gene_search_container');
	
		    // manually mimic typing and autocomplete
		    setTimeout(type_out_search, ini_delay + 1000, params, 'E');
		    setTimeout(type_out_search, ini_delay + 1500, params, 'EG');
		    setTimeout(type_out_search, ini_delay + 2000, params, 'EGF');
		    setTimeout(type_out_search, ini_delay + 2500, params, 'EGFR');
	
		    setTimeout(run_search, 5500, params);
	
		    setTimeout(two_translate_zoom, 7500, cgm, 0, 0, 1);
		  }
	
		  function get_duration() {
		    return 10000;
		  }
	
		  function type_out_search(params, inst_string) {
		    $(params.root + ' .gene_search_box').val(inst_string);
		    $(params.root + ' .gene_search_box').autocomplete("search", inst_string);
		  }
	
		  function run_search(params) {
		    $(params.root + ' .submit_gene_button').click();
		    $(params.root + ' .gene_search_box').autocomplete("search", '');
		  }
	
		  return {
		    run: run,
		    get_duration: get_duration
		  };
			};
	
	/***/ }),
	/* 240 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var demo_text = __webpack_require__(232);
		var highlight_sidebar_element = __webpack_require__(238);
		var update_viz_with_view = __webpack_require__(203);
	
		module.exports = function play_filter() {
	
		  function run(cgm) {
		    var params = cgm.params;
	
		    var text = 'Filter rows based on sum or\nvariance using the sliders';
		    demo_text(params, text, 4000);
	
		    var filter_type = 'N_row_sum';
	
		    setTimeout(highlight_sidebar_element, 5000, params, 'slider_' + filter_type, 13000);
	
		    text = 'Filter: Top 20 rows by sum';
		    setTimeout(demo_text, 5000, params, text, 4000);
		    setTimeout(run_update, 5300, cgm, filter_type, 20, 1);
	
		    text = 'Filter: Top 10 rows by sum';
		    setTimeout(demo_text, 10000, params, text, 4000);
		    setTimeout(run_update, 10300, cgm, filter_type, 10, 2);
	
		    text = 'Filter: All rows';
		    setTimeout(demo_text, 15000, params, text, 4000);
		    setTimeout(run_update, 15300, cgm, filter_type, 'all', 0);
		  }
	
		  function get_duration() {
		    return 19500;
		  }
	
		  function run_update(cgm, filter_type, filter_value, filter_index) {
	
		    var params = cgm.params;
	
		    var requested_view = {};
		    requested_view[filter_type] = filter_value;
		    update_viz_with_view(cgm, requested_view);
	
		    // quick fix for slider
		    $(params.root + ' .slider_' + filter_type).slider("value", filter_index);
	
		    var unit_name;
		    if (filter_type === 'N_row_sum') {
		      unit_name = 'sum';
		    } else {
		      unit_name = 'variance';
		    }
	
		    d3.select(params.root + ' .title_' + filter_type).text('Top rows ' + unit_name + ': ' + filter_value);
		  }
	
		  return {
		    run: run,
		    get_duration: get_duration
		  };
			};
	
	/***/ }),
	/* 241 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var sim_click = __webpack_require__(235);
	
		module.exports = function quick_cluster() {
		  /* eslint-disable */
	
		  function run(params) {
	
		    var x_trans = Number(d3.select(params.root + ' .expand_button').attr('x').replace('px', ''));
		    var y_trans = Number(d3.select(params.root + ' .expand_button').attr('y').replace('px', ''));
	
		    var wait_click = 0;
		    var wait_real_click = 400;
		    setTimeout(sim_click, wait_click, params, 'single', x_trans, y_trans);
		    setTimeout(click_menu_button, wait_real_click, params);
	
		    setTimeout(reset_cluster_order, 1500, params);
		  }
	
		  function get_duration() {
		    return 3500;
		  }
	
		  function click_menu_button(params) {
		    $(params.root + ' .expand_button').d3Click();
		  };
	
		  function reset_cluster_order(params) {
		    click_reorder_button(params, 'row', 'clust');
		    click_reorder_button(params, 'col', 'clust');
		  }
	
		  function click_reorder_button(params, inst_rc, inst_order) {
		    var inst_button = d3.selectAll('.toggle_' + inst_rc + '_order .btn').filter(function () {
		      return this.__data__ == inst_order;
		    })[0];
	
		    $(inst_button).click();
		  }
	
		  // allows doubleclicking on d3 element
		  jQuery.fn.d3Click = function () {
		    this.each(function (i, e) {
		      var evt = document.createEvent("MouseEvents");
		      evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
		      e.dispatchEvent(evt);
		    });
		  };
	
		  return {
		    run: run,
		    get_duration: get_duration
		  };
			};
	
	/***/ }),
	/* 242 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var demo_text = __webpack_require__(232);
		var highlight_sidebar_element = __webpack_require__(238);
		var change_groups = __webpack_require__(190);
	
		module.exports = function play_groups() {
		  /* eslint-disable */
	
		  function run(params) {
	
		    var text = 'Identify row and column groups\nof varying sizes using ' + ' the\nsliders and dendrogram';
		    demo_text(params, text, 10000);
	
		    setTimeout(highlight_sidebar_element, 3000, params, 'slider_col', 7000);
	
		    setTimeout(change_group_slider, 4000, params, 'row', 3);
		    setTimeout(change_group_slider, 5000, params, 'row', 4);
		    setTimeout(change_group_slider, 6000, params, 'row', 5);
		    setTimeout(change_group_slider, 7000, params, 'row', 6);
		    setTimeout(change_group_slider, 8000, params, 'row', 7);
		    setTimeout(change_group_slider, 9000, params, 'row', 5);
		  }
	
		  function get_duration() {
		    return 11000;
		  }
	
		  function change_group_slider(params, inst_rc, inst_value) {
		    $(cgm.params.root + ' .slider_col').slider("value", inst_value / 10);
		    change_groups(cgm, inst_rc, inst_value);
		  }
	
		  return {
		    run: run,
		    get_duration: get_duration
		  };
			};
	
	/***/ }),
	/* 243 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var demo_text = __webpack_require__(232);
		var sim_click = __webpack_require__(235);
	
		module.exports = function play_category() {
		  /* eslint-disable */
	
		  function run(params) {
	
		    var text = 'Row and column categories\ncan be use to reorder\nby double-clicking';
		    demo_text(params, text, 7000);
	
		    var inst_element = d3.selectAll(params.root + ' .col_cat_super').filter(function () {
		      return this.__data__ === 'cat-1';
		    })[0];
	
		    var tmp_pos = d3.select('.col_cat_super').attr('transform');
		    var x_trans = Number(tmp_pos.split('(')[1].split(',')[0].replace(')', '')) + 20;
		    var y_trans = Number(tmp_pos.split(',')[1].replace(')', ''));
	
		    var wait_click = 4000;
		    setTimeout(sim_click, wait_click, params, 'double', x_trans, y_trans);
	
		    var wait_reorder = wait_click + 300;
		    setTimeout(fire_double_click_row, wait_reorder, params, inst_element);
		  }
	
		  function get_duration() {
		    return 8000;
		  }
	
		  function fire_double_click_row(params, inst_element) {
		    $(inst_element).d3DblClick();
		  }
	
		  // allows doubleclicking on d3 element
		  jQuery.fn.d3DblClick = function () {
		    this.each(function (i, e) {
		      var evt = document.createEvent("MouseEvents");
		      evt.initMouseEvent("dblclick", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
		      e.dispatchEvent(evt);
		    });
		  };
		  return {
		    run: run,
		    get_duration: get_duration
		  };
			};
	
	/***/ }),
	/* 244 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var demo_text = __webpack_require__(232);
		var toggle_play_button = __webpack_require__(245);
	
		module.exports = function play_conclusion() {
	
		  function run(params) {
		    var text_1 = "Clustergrammer is built with gene\nexpression data in mind" + " and interfaces\nwith several Ma'ayan lab web tools";
		    var text_2 = "The example data being visualized is\ngene expression data" + " obtained from the\nCancer Cell Line Encyclopedia";
		    var text_3 = "For more information please view\nthe help documentation";
	
		    setTimeout(demo_text, 0, params, text_1, 4500);
		    setTimeout(demo_text, 4500, params, text_2, 4500);
		    setTimeout(demo_text, 9000, params, text_3, 4500);
	
		    setTimeout(reset_demo, 14000, params);
		  }
	
		  function reset_demo(params) {
	
		    // prevent more than one demo from running at once 
		    d3.select(params.root + ' .play_button').classed('running_demo', false);
	
		    toggle_play_button(params, true);
		  }
	
		  function get_duration() {
		    return 12000;
		  }
	
		  return {
		    run: run,
		    get_duration: get_duration
		  };
			};
	
	/***/ }),
	/* 245 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function toggle_play_button(params, show) {
	
		  if (show === false) {
		    d3.select(params.root + ' .play_button').transition().duration(500).style('opacity', 0);
		  } else {
		    d3.select(params.root + ' .play_button').transition().duration(500).style('opacity', 1);
	
		    $.unblockUI();
		  }
			};
	
	/***/ }),
	/* 246 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var demo_text = __webpack_require__(232);
		var sim_click = __webpack_require__(235);
	
		module.exports = function play_menu_button() {
		  /* eslint-disable */
	
		  function run(params) {
	
		    var text = 'View additional controls\nby clicking the menu button';
		    demo_text(params, text, 4000);
	
		    // var inst_element = get_row_element(params, 'EGFR');
	
		    // var group_trans = d3.select(inst_element).attr('transform');
	
		    // var container_trans = d3.select(params.root+' .clust_container')
		    //   .attr('transform')
		    //   .split(',')[1].replace(')','');
	
		    // var x_trans = params.viz.norm_labels.width.row * 0.9;
	
		    // var row_trans = group_trans.split(',')[1].replace(')','');
		    // var y_trans = String(Number(row_trans) + Number(container_trans) + 
		    //   params.viz.rect_height/2);
	
		    var x_trans = Number(d3.select(params.root + ' .expand_button').attr('x').replace('px', ''));
		    var y_trans = Number(d3.select(params.root + ' .expand_button').attr('y').replace('px', ''));
	
		    var wait_click = 3000;
		    var wait_real_click = 3400;
		    setTimeout(sim_click, wait_click, params, 'single', x_trans, y_trans);
		    setTimeout(click_menu_button, wait_real_click, params);
		  }
	
		  function get_duration() {
		    return 5000;
		  }
	
		  function click_menu_button(params) {
		    $(params.root + ' .expand_button').d3Click();
		  };
	
		  function get_row_element(params, inst_row) {
	
		    var inst_element = d3.selectAll(params.root + ' .row_label_group').filter(function () {
		      var inst_data = this.__data__;
		      return inst_data.name == inst_row;
		    })[0][0];
	
		    return inst_element;
		  }
	
		  // allows doubleclicking on d3 element
		  jQuery.fn.d3Click = function () {
		    this.each(function (i, e) {
		      var evt = document.createEvent("MouseEvents");
		      evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
		      e.dispatchEvent(evt);
		    });
		  };
	
		  // allows doubleclicking on d3 element
		  jQuery.fn.d3DblClick = function () {
		    this.each(function (i, e) {
		      var evt = document.createEvent("MouseEvents");
		      evt.initMouseEvent("dblclick", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
		      e.dispatchEvent(evt);
		    });
		  };
		  return {
		    run: run,
		    get_duration: get_duration
		  };
			};
	
	/***/ }),
	/* 247 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_play_button = __webpack_require__(248);
		var make_demo_text_containers = __webpack_require__(249);
	
		module.exports = function ini_demo() {
	
		  var cgm = this;
		  var params = cgm.params;
	
		  make_play_button(cgm);
	
		  var demo_text_size = 30;
		  make_demo_text_containers(params, demo_text_size);
			};
	
	/***/ }),
	/* 248 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var position_play_button = __webpack_require__(177);
	
		module.exports = function make_play_button(cgm) {
	
		  var params = cgm.params;
	
		  if (d3.select(params.root + ' .play_button').empty()) {
	
		    var play_button = d3.select(params.root + ' .viz_svg').append('g').classed('play_button', true).classed('running_demo', false);
	
		    position_play_button(params);
	
		    play_button.append('circle').style('r', 45).style('fill', 'white').style('stroke', 'black').style('stroke-width', '3px').style('opacity', 0.5);
	
		    play_button.append('path').attr('d', function () {
	
		      var tri_w = 40;
		      var tri_h = 22;
		      var tri_offset = 15;
	
		      return 'M-' + tri_offset + ',-' + tri_h + ' l ' + tri_w + ',' + tri_h + ' l -' + tri_w + ',' + tri_h + ' z ';
		    }).style('fill', 'black').style('opacity', 0.5);
	
		    // mouseover behavior
		    play_button.on('mouseover', function () {
		      d3.select(this).select('path').style('fill', 'red').style('opacity', 1);
	
		      d3.select(this).select('circle').style('opacity', 1);
		    }).on('mouseout', function () {
		      d3.select(this).select('path').style('fill', 'black').style('opacity', 0.5);
		      d3.select(this).select('circle').style('opacity', 0.5);
		    }).on('click', function () {
		      // running from anonymous function to keep this defined correctly 
		      cgm.play_demo();
		    });
		  }
			};
	
	/***/ }),
	/* 249 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function make_demo_text_containers(params, demo_text_size) {
	
		  if (d3.select(params.root + ' .demo_group').empty()) {
	
		    var clust_transform = d3.select(params.root + ' .clust_container').attr('transform');
		    var clust_x = Number(clust_transform.split('(')[1].split(',')[0]);
		    var clust_y = Number(clust_transform.split(',')[1].replace(')', ''));
	
		    // demo text container 
		    var demo_group = d3.select(params.root + ' .viz_svg').append('g').classed('demo_group', true).attr('transform', function () {
		      var pos_x = clust_x + 20;
		      var pos_y = clust_y + 40;
		      return 'translate(' + pos_x + ',' + pos_y + ')';
		    });
	
		    demo_group.append('rect').classed('rect_1', true);
	
		    demo_group.append('rect').classed('rect_2', true);
	
		    demo_group.append('rect').classed('rect_3', true);
	
		    var shift_height = 1.3 * demo_text_size;
	
		    demo_group.append('text').attr('id', 'text_1').attr('font-size', demo_text_size + 'px').attr('font-weight', 1000).attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif');
	
		    demo_group.append('text').attr('id', 'text_2').attr('font-size', demo_text_size + 'px').attr('font-weight', 1000).attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').attr('transform', function () {
		      return 'translate(0,' + String(shift_height) + ')';
		    });
	
		    demo_group.append('text').attr('id', 'text_3').attr('font-size', demo_text_size + 'px').attr('font-weight', 1000).attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').attr('transform', function () {
		      return 'translate(0,' + String(2 * shift_height) + ')';
		    });
		  }
			};
	
	/***/ }),
	/* 250 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var filter_network_using_new_nodes = __webpack_require__(11);
		var update_viz_with_network = __webpack_require__(205);
	
		module.exports = function filter_viz_using_nodes(new_nodes) {
	
		  var new_network_data = filter_network_using_new_nodes(this.config, new_nodes);
		  update_viz_with_network(this, new_network_data);
			};
	
	/***/ }),
	/* 251 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var filter_network_using_new_nodes = __webpack_require__(11);
		var update_viz_with_network = __webpack_require__(205);
	
		module.exports = function filter_viz_using_names(names) {
		  var external_cgm = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
	
	
		  // names is an object with row and column names that will be used to filter
		  // the matrix
	
		  var cgm;
		  if (external_cgm === false) {
		    cgm = this;
		  } else {
		    cgm = external_cgm;
		  }
	
		  var params = cgm.params;
		  var new_nodes = {};
		  var found_nodes;
	
		  _.each(['row', 'col'], function (inst_rc) {
	
		    var orig_nodes = params.inst_nodes[inst_rc + '_nodes'];
	
		    if (_.has(names, inst_rc)) {
	
		      if (names[inst_rc].length > 0) {
		        var inst_names = names[inst_rc];
		        found_nodes = $.grep(orig_nodes, function (d) {
		          return $.inArray(d.name, inst_names) > -1;
		        });
		      } else {
	
		        found_nodes = orig_nodes;
		      }
		    } else {
	
		      found_nodes = orig_nodes;
		    }
	
		    new_nodes[inst_rc + '_nodes'] = found_nodes;
		  });
	
		  // keep backup of the nodes for resetting filtering
		  var inst_row_nodes = cgm.params.network_data.row_nodes;
		  var inst_col_nodes = cgm.params.network_data.col_nodes;
	
		  var new_network_data = filter_network_using_new_nodes(cgm.config, new_nodes);
	
		  // takes entire cgm object
		  // last argument tells it to not preserve categoty colors
		  update_viz_with_network(cgm, new_network_data);
	
		  // only keep backup if previous number of nodes were larger than current number
		  // of nodes
		  if (inst_row_nodes.length > cgm.params.inst_nodes.row_nodes.length) {
		    cgm.params.inst_nodes.row_nodes = inst_row_nodes;
		  }
	
		  if (inst_col_nodes.length > cgm.params.inst_nodes.col_nodes.length) {
		    cgm.params.inst_nodes.col_nodes = inst_col_nodes;
		  }
			};
	
	/***/ }),
	/* 252 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_row_cat = __webpack_require__(185);
		var calc_viz_params = __webpack_require__(66);
		var resize_viz = __webpack_require__(152);
		var modify_row_node_cats = __webpack_require__(222);
	
		module.exports = function update_cats(cgm, cat_data) {
	
		  // Only accessible from the cgm API, cat_data is provided by externally
		  ///////////////////////////////////////////////////////////////////////////
	
		  if (cgm.params.cat_update_callback != null) {
		    cgm.params.cat_update_callback(this);
		  }
	
		  // do not change column category info
		  var col_cat_colors = cgm.params.viz.cat_colors.col;
	
		  modify_row_node_cats(cat_data, cgm.params.network_data.row_nodes, true);
		  // modify the current inst copy of nodes
		  modify_row_node_cats(cat_data, cgm.params.inst_nodes.row_nodes, true);
	
		  // recalculate the visualization parameters using the updated network_data
		  cgm.params = calc_viz_params(cgm.params, false);
	
		  make_row_cat(cgm, true);
		  resize_viz(cgm);
	
		  cgm.params.new_row_cats = cat_data;
	
		  cgm.params.viz.cat_colors.col = col_cat_colors;
			};
	
	/***/ }),
	/* 253 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_row_cat = __webpack_require__(185);
		var calc_viz_params = __webpack_require__(66);
		var resize_viz = __webpack_require__(152);
		var modify_row_node_cats = __webpack_require__(222);
		var generate_cat_data = __webpack_require__(254);
	
		module.exports = function reset_cats() {
		  var run_resize_viz = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
	
	
		  // console.log('RESET CATS')
	
		  var cgm = this;
	
		  var cat_data = generate_cat_data(cgm);
	
		  // do not change column category info
		  var col_cat_colors = cgm.params.viz.cat_colors.col;
	
		  modify_row_node_cats(cat_data, cgm.params.network_data.row_nodes);
		  // modify the current inst copy of nodes
		  modify_row_node_cats(cat_data, cgm.params.inst_nodes.row_nodes);
	
		  cgm.params.new_row_cats = cat_data;
		  cgm.params.viz.cat_colors.col = col_cat_colors;
	
		  if (run_resize_viz) {
	
		    // resize visualizatino
		    ////////////////////////////
		    // recalculate the visualization parameters using the updated network_data
		    var predefine_cat_colors = true;
		    cgm.params = calc_viz_params(cgm.params, predefine_cat_colors);
	
		    make_row_cat(cgm, true);
		    resize_viz(cgm);
		  }
			};
	
	/***/ }),
	/* 254 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function generate_cat_data(cgm) {
	
		  // only row category resetting is supported currently
	
		  // get row_nodes from config, since this is has the original network
		  var row_nodes = cgm.config.network_data.row_nodes;
		  var title_sep = ': ';
	
		  // contains all the category information stored as an array of
		  // cat_type
		  var cat_data = [];
		  var cat_type;
		  var cat_info;
		  var found_cat_title;
		  var found_cat_name;
		  var cat_name;
	
		  // console.log('generate_cat_data')
		  // console.log(cgm.params.viz.cat_names.row)
	
		  // get current list of cateories
		  var check_node = row_nodes[0];
		  var node_keys = _.keys(check_node);
		  var current_cats = {};
		  var tmp_cat;
		  var tmp_title;
		  var cat_index;
		  _.each(node_keys, function (inst_prop) {
	
		    if (inst_prop.indexOf('cat-') >= 0) {
	
		      // generate titles from cat info
		      tmp_cat = check_node[inst_prop];
	
		      cat_index = parseInt(inst_prop.split('cat-')[1], 10);
	
		      // use given title
		      if (tmp_cat.indexOf(title_sep) >= 0) {
		        tmp_title = tmp_cat.split(title_sep)[0];
		      } else {
		        tmp_title = inst_prop;
		      }
	
		      // current_cats.push(tmp_title);
	
		      current_cats[cat_index] = tmp_title;
		    }
		  });
	
		  // console.log('current_cats')
		  // console.log(current_cats)
	
		  // initialize cat_data with categories in the correct order
		  var all_index = _.keys(current_cats).sort();
	
		  var inst_data;
		  _.each(all_index, function (inst_index) {
	
		    inst_data = {};
		    inst_data.cat_title = current_cats[inst_index];
		    inst_data.cats = [];
	
		    cat_data.push(inst_data);
		  });
	
		  // // initialize cat_data (keep original order)
		  // var found_title;
		  // _.each(cgm.params.viz.cat_names.row, function(inst_title){
	
		  //   found_title = false;
	
		  //   console.log('inst_title -> ' + String(inst_title))
	
		  //   if (current_cats.indexOf(inst_title) >= 0){
		  //     found_title = true;
		  //   }
	
		  //   // only track cats that are found in the incoming nodes
		  //   if (found_title){
		  //     var inst_data = {};
		  //     inst_data.cat_title = inst_title;
		  //     inst_data.cats = [];
		  //     cat_data.push(inst_data);
		  //   }
	
		  // });
	
		  // console.log('cat_data after cross checking with current cats')
		  // console.log(cat_data)
		  // console.log('-------------------------\n')
	
		  _.each(row_nodes, function (inst_node) {
	
		    var all_props = _.keys(inst_node);
	
		    _.each(all_props, function (inst_prop) {
	
		      if (inst_prop.indexOf('cat-') > -1) {
	
		        cat_name = inst_node[inst_prop];
	
		        cat_index = parseInt(inst_prop.split('cat-')[1], 10);
	
		        // default title and name
		        var cat_title = inst_prop;
		        cat_name = inst_node[inst_prop];
		        var cat_string = inst_node[inst_prop];
		        var cat_row_name = inst_node.name;
	
		        // console.log('cat_string: '+String(cat_string))
		        // found actual title
		        if (cat_string.indexOf(title_sep) > -1) {
		          cat_title = cat_string.split(title_sep)[0];
		          cat_name = cat_string.split(title_sep)[1];
		        } else {
		          // cat_title = 'Category-'+String(parseInt(inst_prop.split('-')[1]) + 1)
		          cat_title = inst_prop;
		          cat_name = cat_string;
		        }
	
		        // console.log('cat_index -> ' + String(cat_index))
		        // console.log('cat_name '+cat_name)
		        // console.log('cat_title ' + cat_title)
		        // console.log('--------')
	
		        // cat_data is empty
		        if (cat_data.length === 0) {
	
		          add_new_cat_type(cat_title, cat_name, cat_row_name);
	
		          // cat_data is not empty
		        } else {
	
		          // look for cat_title in cat_data
		          found_cat_title = false;
		          _.each(cat_data, function (inst_cat_type) {
	
		            // console.log('inst_cat_data title ' + inst_cat_type.cat_title)
	
		            // check each cat_type object for a matching title
		            if (cat_title === inst_cat_type.cat_title) {
		              found_cat_title = true;
	
		              // check if cat_name is in cats
		              found_cat_name = false;
		              _.each(inst_cat_type.cats, function (inst_cat_obj) {
	
		                // found category name, add cat_row_name to members
		                if (cat_name === inst_cat_obj.cat_name) {
		                  found_cat_name = true;
	
		                  // add cat_row_name to members
		                  inst_cat_obj.members.push(cat_row_name);
		                }
		              });
	
		              // did not find cat name in cat_type - add cat_info for new
		              // category
		              if (found_cat_name === false) {
		                cat_info = {};
		                cat_info.cat_name = cat_name;
		                cat_info.members = [];
		                cat_info.members.push(cat_row_name);
		                inst_cat_type.cats.push(cat_info);
		              }
		            }
		          });
	
		          // did not find category type, initialize category type object
		          if (found_cat_title === false) {
	
		            // console.log('did not find cat_title: ' + String(cat_title))
		            // add_new_cat_type(cat_title, cat_name, cat_row_name);
	
		          }
		        }
		      }
		    });
		  });
	
		  function add_new_cat_type(cat_title, cat_name, cat_row_name) {
	
		    // initialize cat_type object to push to cat_data
		    cat_type = {};
		    cat_type.cat_title = cat_title;
		    cat_type.cats = [];
	
		    // initialize cat_info (e.g. 'true' category has members [...])
		    cat_info = {};
		    cat_info.cat_name = cat_name;
		    cat_info.members = [];
		    cat_info.members.push(cat_row_name);
	
		    cat_type.cats.push(cat_info);
	
		    cat_data.push(cat_type);
		  }
	
		  // console.log('RETURNING CAT DATA')
		  // console.log(cat_data)
	
		  return cat_data;
		};
	
	/***/ }),
	/* 255 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var file_saver = __webpack_require__(256);
		var make_matrix_string = __webpack_require__(257);
	
		module.exports = function save_matrix() {
	
		  var saveAs = file_saver();
	
		  var params = this.params;
	
		  var matrix_string = make_matrix_string(params);
	
		  var blob = new Blob([matrix_string], { type: 'text/plain;charset=utf-8' });
		  saveAs(blob, 'clustergrammer.txt');
			};
	
	/***/ }),
	/* 256 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function file_saver() {
		  /* eslint-disable */
		  /* FileSaver.js
		   * A saveAs() FileSaver implementation.
		   * 2013-01-23
		   * 
		   * By Eli Grey, http://eligrey.com
		   * License: X11/MIT
		   *   See LICENSE.md
		   */
	
		  /*global self */
		  /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
		    plusplus: true */
	
		  /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
	
		  var saveAs = saveAs || navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator) || function (view) {
		    "use strict";
	
		    var doc = view.document
		    // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet
		    ,
		        get_URL = function get_URL() {
		      return view.URL || view.webkitURL || view;
		    },
		        URL = view.URL || view.webkitURL || view,
		        save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"),
		        can_use_save_link = "download" in save_link,
		        click = function click(node) {
		      var event = doc.createEvent("MouseEvents");
		      event.initMouseEvent("click", true, false, view, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
		      node.dispatchEvent(event);
		    },
		        webkit_req_fs = view.webkitRequestFileSystem,
		        req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem,
		        throw_outside = function throw_outside(ex) {
		      (view.setImmediate || view.setTimeout)(function () {
		        throw ex;
		      }, 0);
		    },
		        force_saveable_type = "application/octet-stream",
		        fs_min_size = 0,
		        deletion_queue = [],
		        process_deletion_queue = function process_deletion_queue() {
		      var i = deletion_queue.length;
		      while (i--) {
		        var file = deletion_queue[i];
		        if (typeof file === "string") {
		          // file is an object URL
		          URL.revokeObjectURL(file);
		        } else {
		          // file is a File
		          file.remove();
		        }
		      }
		      deletion_queue.length = 0; // clear queue
		    },
		        dispatch = function dispatch(filesaver, event_types, event) {
		      event_types = [].concat(event_types);
		      var i = event_types.length;
		      while (i--) {
		        var listener = filesaver["on" + event_types[i]];
		        if (typeof listener === "function") {
		          try {
		            listener.call(filesaver, event || filesaver);
		          } catch (ex) {
		            throw_outside(ex);
		          }
		        }
		      }
		    },
		        FileSaver = function FileSaver(blob, name) {
		      // First try a.download, then web filesystem, then object URLs
		      var filesaver = this,
		          type = blob.type,
		          blob_changed = false,
		          object_url,
		          target_view,
		          get_object_url = function get_object_url() {
		        var object_url = get_URL().createObjectURL(blob);
		        deletion_queue.push(object_url);
		        return object_url;
		      },
		          dispatch_all = function dispatch_all() {
		        dispatch(filesaver, "writestart progress write writeend".split(" "));
		      }
		      // on any filesys errors revert to saving with object URLs
		      ,
		          fs_error = function fs_error() {
		        // don't create more object URLs than needed
		        if (blob_changed || !object_url) {
		          object_url = get_object_url(blob);
		        }
		        if (target_view) {
		          target_view.location.href = object_url;
		        }
		        filesaver.readyState = filesaver.DONE;
		        dispatch_all();
		      },
		          abortable = function abortable(func) {
		        return function () {
		          if (filesaver.readyState !== filesaver.DONE) {
		            return func.apply(this, arguments);
		          }
		        };
		      },
		          create_if_not_found = { create: true, exclusive: false },
		          slice;
		      filesaver.readyState = filesaver.INIT;
		      if (!name) {
		        name = "download";
		      }
		      if (can_use_save_link) {
		        object_url = get_object_url(blob);
		        save_link.href = object_url;
		        save_link.download = name;
		        click(save_link);
		        filesaver.readyState = filesaver.DONE;
		        dispatch_all();
		        return;
		      }
		      // Object and web filesystem URLs have a problem saving in Google Chrome when
		      // viewed in a tab, so I force save with application/octet-stream
		      // http://code.google.com/p/chromium/issues/detail?id=91158
		      if (view.chrome && type && type !== force_saveable_type) {
		        slice = blob.slice || blob.webkitSlice;
		        blob = slice.call(blob, 0, blob.size, force_saveable_type);
		        blob_changed = true;
		      }
		      // Since I can't be sure that the guessed media type will trigger a download
		      // in WebKit, I append .download to the filename.
		      // https://bugs.webkit.org/show_bug.cgi?id=65440
		      if (webkit_req_fs && name !== "download") {
		        name += ".download";
		      }
		      if (type === force_saveable_type || webkit_req_fs) {
		        target_view = view;
		      } else {
		        target_view = view.open();
		      }
		      if (!req_fs) {
		        fs_error();
		        return;
		      }
		      fs_min_size += blob.size;
		      req_fs(view.TEMPORARY, fs_min_size, abortable(function (fs) {
		        fs.root.getDirectory("saved", create_if_not_found, abortable(function (dir) {
		          var save = function save() {
		            dir.getFile(name, create_if_not_found, abortable(function (file) {
		              file.createWriter(abortable(function (writer) {
		                writer.onwriteend = function (event) {
		                  target_view.location.href = file.toURL();
		                  deletion_queue.push(file);
		                  filesaver.readyState = filesaver.DONE;
		                  dispatch(filesaver, "writeend", event);
		                };
		                writer.onerror = function () {
		                  var error = writer.error;
		                  if (error.code !== error.ABORT_ERR) {
		                    fs_error();
		                  }
		                };
		                "writestart progress write abort".split(" ").forEach(function (event) {
		                  writer["on" + event] = filesaver["on" + event];
		                });
		                writer.write(blob);
		                filesaver.abort = function () {
		                  writer.abort();
		                  filesaver.readyState = filesaver.DONE;
		                };
		                filesaver.readyState = filesaver.WRITING;
		              }), fs_error);
		            }), fs_error);
		          };
		          dir.getFile(name, { create: false }, abortable(function (file) {
		            // delete file if it already exists
		            file.remove();
		            save();
		          }), abortable(function (ex) {
		            if (ex.code === ex.NOT_FOUND_ERR) {
		              save();
		            } else {
		              fs_error();
		            }
		          }));
		        }), fs_error);
		      }), fs_error);
		    },
		        FS_proto = FileSaver.prototype,
		        saveAs = function saveAs(blob, name) {
		      return new FileSaver(blob, name);
		    };
		    FS_proto.abort = function () {
		      var filesaver = this;
		      filesaver.readyState = filesaver.DONE;
		      dispatch(filesaver, "abort");
		    };
		    FS_proto.readyState = FS_proto.INIT = 0;
		    FS_proto.WRITING = 1;
		    FS_proto.DONE = 2;
	
		    FS_proto.error = FS_proto.onwritestart = FS_proto.onprogress = FS_proto.onwrite = FS_proto.onabort = FS_proto.onerror = FS_proto.onwriteend = null;
	
		    view.addEventListener("unload", process_deletion_queue, false);
		    return saveAs;
		  }(self);
	
		  return saveAs;
			};
	
	/***/ }),
	/* 257 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_full_name = __webpack_require__(258);
	
		module.exports = function make_matrix_string(params) {
	
		  var inst_matrix = params.matrix;
	
		  // get order indexes
		  var order_indexes = {};
		  var inst_name;
		  _.each(['row', 'col'], function (tmp_rc) {
	
		    var inst_rc;
		    // row/col names are reversed in saved orders
		    if (tmp_rc === 'row') {
		      inst_rc = 'col';
		    } else {
		      inst_rc = 'row';
		    }
	
		    // use tmp_rc
		    inst_name = params.inst_order[tmp_rc];
	
		    // use tmp_rc
		    order_indexes[inst_rc] = inst_matrix.orders[inst_name + '_' + tmp_rc];
		  });
	
		  var matrix_string = '\t';
		  var row_nodes = params.network_data.row_nodes;
		  var col_nodes = params.network_data.col_nodes;
	
		  // alternate column entry
		  for (var c_i = 0; c_i < order_indexes.col.length; c_i++) {
	
		    var inst_index = order_indexes.col[c_i];
	
		    var inst_col = col_nodes[inst_index];
		    var col_name = make_full_name(params, inst_col, 'col');
	
		    if (c_i < order_indexes.col.length - 1) {
		      matrix_string = matrix_string + col_name + '\t';
		    } else {
		      matrix_string = matrix_string + col_name;
		    }
		  }
	
		  var row_data;
		  matrix_string = matrix_string + '\n';
	
		  _.each(order_indexes.row, function (inst_index) {
	
		    // row names
		    row_data = inst_matrix.matrix[inst_index].row_data;
	
		    // var row_name = inst_matrix.matrix[inst_index].name;
		    var inst_row = row_nodes[inst_index];
	
		    // var row_name = inst_row.name;
		    var row_name = make_full_name(params, inst_row, 'row');
	
		    matrix_string = matrix_string + row_name + '\t';
	
		    // alternate data entry
		    for (var r_i = 0; r_i < order_indexes.col.length; r_i++) {
	
		      // get the order
		      var col_index = order_indexes.col[r_i];
	
		      if (r_i < order_indexes.col.length - 1) {
		        matrix_string = matrix_string + String(row_data[col_index].value) + '\t';
		      } else {
		        matrix_string = matrix_string + String(row_data[col_index].value);
		      }
		    }
	
		    matrix_string = matrix_string + '\n';
		  });
	
		  return matrix_string;
			};
	
	/***/ }),
	/* 258 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function make_full_name(params, inst_node, inst_rc) {
	
		  var cat_name;
		  var inst_name = inst_node.name;
		  var num_cats = params.viz.all_cats[inst_rc].length;
	
		  // make tuple if necessary
		  if (num_cats > 0) {
	
		    inst_name = "('" + inst_name + "'";
	
		    for (var cat_index = 0; cat_index < num_cats; cat_index++) {
		      cat_name = 'cat-' + String(cat_index);
	
		      inst_name = inst_name + ", '" + String(inst_node[cat_name]) + "'";
		    }
	
		    inst_name = inst_name + ')';
		  } else {
	
		    // always make names strings
		    inst_name = String(inst_name);
		  }
	
		  return inst_name;
		};
	
	/***/ }),
	/* 259 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var deactivate_cropping = __webpack_require__(260);
	
		module.exports = function brush_crop_matrix() {
	
		  // get rows/cols from brush-extent
		  // works for differnt brushing directions (e.g. start end sites)
	
		  var cgm = this;
		  var params = cgm.params;
	
		  var clust_width = params.viz.clust.dim.width;
		  var clust_height = params.viz.clust.dim.height;
	
		  var x = d3.scale.linear().domain([0, clust_width]).range([0, clust_width]);
		  var y = d3.scale.linear().domain([0, clust_height]).range([0, clust_height]);
	
		  // make brush group
		  d3.select(params.root + ' .clust_container').append('g').classed('brush_group', true);
	
		  cgm.params.is_cropping = true;
	
		  var brush = d3.svg.brush().x(x).y(y).on("brushend", brushend);
	
		  d3.select(params.root + ' .brush_group').call(brush);
	
		  function brushend() {
	
		    // do not display dendro crop buttons when cropping with brushing
		    d3.select(cgm.params.root + ' .col_dendro_icons_container').style('display', 'none');
		    d3.select(cgm.params.root + ' .row_dendro_icons_container').style('display', 'none');
	
		    var brushing_extent = brush.extent();
		    var brush_start = brushing_extent[0];
		    var brush_end = brushing_extent[1];
	
		    var x_start = brush_start[0];
		    var x_end = brush_end[0];
	
		    var y_start = brush_start[1];
		    var y_end = brush_end[1];
	
		    if (x_start != x_end && y_start != y_end) {
	
		      setTimeout(deactivate_cropping, 500, cgm);
	
		      // find cropped nodes
		      var found_nodes = find_cropped_nodes(x_start, x_end, y_start, y_end, brush_start, brush_end);
	
		      cgm.filter_viz_using_names(found_nodes);
	
		      d3.select(params.root + ' .crop_button').style('color', '#337ab7').classed('fa-crop', false).classed('fa-undo', true);
		    }
		  }
	
		  function find_cropped_nodes(x_start, x_end, y_start, y_end, brush_start, brush_end) {
	
		    // reverse if necessary (depending on how brushing was done)
		    if (x_start > x_end) {
		      x_start = brush_end[0];
		      x_end = brush_start[0];
		    }
	
		    if (y_start > y_end) {
		      y_start = brush_end[1];
		      y_end = brush_start[1];
		    }
	
		    // add room to brushing
		    y_start = y_start - params.viz.rect_height;
		    x_start = x_start - params.viz.rect_width;
	
		    var found_nodes = {};
		    found_nodes.row = [];
		    found_nodes.col = [];
	
		    // d3.selectAll(params.root+' .row_label_group')
		    //   .each(function(inst_row){
	
		    //     // there is already bound data on the rows
		    //     var inst_trans = d3.select(this)
		    //       .attr('transform');
	
		    //     var y_trans = Number(inst_trans.split(',')[1].split(')')[0]);
	
		    //     if (y_trans > y_start && y_trans < y_end){
	
		    //       found_nodes.row.push(inst_row.name);
	
		    //     }
	
		    //   });
	
		    _.each(params.matrix.matrix, function (row_data) {
		      var y_trans = params.viz.y_scale(row_data.row_index);
	
		      if (y_trans > y_start && y_trans < y_end) {
		        found_nodes.row.push(row_data.name);
		      }
		    });
	
		    d3.selectAll(params.root + ' .col_label_text').each(function (inst_col) {
	
		      // there is already bound data on the cols
		      var inst_trans = d3.select(this).attr('transform');
	
		      var x_trans = Number(inst_trans.split(',')[0].split('(')[1]);
	
		      if (x_trans > x_start && x_trans < x_end) {
	
		        found_nodes.col.push(inst_col.name);
		      }
		    });
	
		    return found_nodes;
		  }
	
		  d3.selectAll(params.root + ' .extent').style('opacity', 0.2).style('fill', 'black');
			};
	
	/***/ }),
	/* 260 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function deactivate_cropping(cgm) {
	
		  d3.select(cgm.params.root + ' .brush_group').transition().style('opacity', 0).remove();
	
		  cgm.params.is_cropping = false;
			};
	
	/***/ }),
	/* 261 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;'use strict';
	
		var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
	
		/*
		    D3.js Slider
		    Inspired by jQuery UI Slider
		    Copyright (c) 2013, Bjorn Sandvik - http://blog.thematicmapping.org
		    BSD license: http://opensource.org/licenses/BSD-3-Clause
		*/
		(function (root, factory) {
		  if (true) {
		    // AMD. Register as an anonymous module.
		    !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(262)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
		  } else if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
		    if (process.browser) {
		      // Browserify. Import css too using cssify.
		      require('./d3.slider.css');
		    }
		    // Node. Does not work with strict CommonJS, but
		    // only CommonJS-like environments that support module.exports,
		    // like Node.
		    module.exports = factory(require('d3'));
		  } else {
		    // Browser globals (root is window)
		    root.d3.slider = factory(root.d3);
		  }
		})(undefined, function (d3) {
		  return function module() {
		    "use strict";
	
		    // Public variables width default settings
	
		    var min = 0,
		        max = 100,
		        step = 0.01,
		        animate = false,
		        orientation = "horizontal",
		        axis = false,
		        margin = 50,
		        value,
		        active = 1,
		        snap = false,
		        scale;
	
		    // Private variables
		    var axisScale,
		        dispatch = d3.dispatch("slide", "slideend"),
		        formatPercent = d3.format(".2%"),
		        tickFormat = d3.format(".0"),
		        handle1,
		        handle2 = null,
		        divRange,
		        sliderLength;
	
		    function slider(selection) {
		      selection.each(function () {
	
		        // Create scale if not defined by user
		        if (!scale) {
		          scale = d3.scale.linear().domain([min, max]);
		        }
	
		        // Start value
		        value = value || scale.domain()[0];
	
		        // DIV container
		        var div = d3.select(this).classed("d3-slider d3-slider-" + orientation, true);
	
		        var drag = d3.behavior.drag();
		        drag.on('dragend', function () {
		          dispatch.slideend(d3.event, value);
		        });
	
		        // Slider handle
		        //if range slider, create two
		        // var divRange;
	
		        if (toType(value) == "array" && value.length == 2) {
		          handle1 = div.append("a").classed("d3-slider-handle", true).attr("xlink:href", "#").attr('id', "handle-one").on("click", stopPropagation).call(drag);
		          handle2 = div.append("a").classed("d3-slider-handle", true).attr('id', "handle-two").attr("xlink:href", "#").on("click", stopPropagation).call(drag);
		        } else {
		          handle1 = div.append("a").classed("d3-slider-handle", true).attr("xlink:href", "#").attr('id', "handle-one").on("click", stopPropagation).call(drag);
		        }
	
		        // Horizontal slider
		        if (orientation === "horizontal") {
	
		          div.on("click", onClickHorizontal);
	
		          if (toType(value) == "array" && value.length == 2) {
		            divRange = d3.select(this).append('div').classed("d3-slider-range", true);
	
		            handle1.style("left", formatPercent(scale(value[0])));
		            divRange.style("left", formatPercent(scale(value[0])));
		            drag.on("drag", onDragHorizontal);
	
		            var width = 100 - parseFloat(formatPercent(scale(value[1])));
		            handle2.style("left", formatPercent(scale(value[1])));
		            divRange.style("right", width + "%");
		            drag.on("drag", onDragHorizontal);
		          } else {
		            handle1.style("left", formatPercent(scale(value)));
		            drag.on("drag", onDragHorizontal);
		          }
	
		          sliderLength = parseInt(div.style("width"), 10);
		        } else {
		          // Vertical
	
		          div.on("click", onClickVertical);
		          drag.on("drag", onDragVertical);
		          if (toType(value) == "array" && value.length == 2) {
		            divRange = d3.select(this).append('div').classed("d3-slider-range-vertical", true);
	
		            handle1.style("bottom", formatPercent(scale(value[0])));
		            divRange.style("bottom", formatPercent(scale(value[0])));
		            drag.on("drag", onDragVertical);
	
		            var top = 100 - parseFloat(formatPercent(scale(value[1])));
		            handle2.style("bottom", formatPercent(scale(value[1])));
		            divRange.style("top", top + "%");
		            drag.on("drag", onDragVertical);
		          } else {
		            handle1.style("bottom", formatPercent(scale(value)));
		            drag.on("drag", onDragVertical);
		          }
	
		          sliderLength = parseInt(div.style("height"), 10);
		        }
	
		        if (axis) {
		          createAxis(div);
		        }
	
		        function createAxis(dom) {
	
		          // Create axis if not defined by user
		          if (typeof axis === "boolean") {
	
		            axis = d3.svg.axis().ticks(Math.round(sliderLength / 100)).tickFormat(tickFormat).orient(orientation === "horizontal" ? "bottom" : "right");
		          }
	
		          // Copy slider scale to move from percentages to pixels
		          axisScale = scale.ticks ? scale.copy().range([0, sliderLength]) : scale.copy().rangePoints([0, sliderLength], 0.5);
		          axis.scale(axisScale);
	
		          // Create SVG axis container
		          var svg = dom.append("svg").classed("d3-slider-axis d3-slider-axis-" + axis.orient(), true).on("click", stopPropagation);
	
		          var g = svg.append("g");
	
		          // Horizontal axis
		          if (orientation === "horizontal") {
	
		            svg.style("margin-left", -margin + "px");
	
		            svg.attr({
		              width: sliderLength + margin * 2,
		              height: margin
		            });
	
		            if (axis.orient() === "top") {
		              svg.style("top", -margin + "px");
		              g.attr("transform", "translate(" + margin + "," + margin + ")");
		            } else {
		              // bottom
		              g.attr("transform", "translate(" + margin + ",0)");
		            }
		          } else {
		            // Vertical
	
		            svg.style("top", -margin + "px");
	
		            svg.attr({
		              width: margin,
		              height: sliderLength + margin * 2
		            });
	
		            if (axis.orient() === "left") {
		              svg.style("left", -margin + "px");
		              g.attr("transform", "translate(" + margin + "," + margin + ")");
		            } else {
		              // right
		              g.attr("transform", "translate(" + 0 + "," + margin + ")");
		            }
		          }
	
		          g.call(axis);
		        }
	
		        function onClickHorizontal() {
		          if (toType(value) != "array") {
		            var pos = Math.max(0, Math.min(sliderLength, d3.event.offsetX || d3.event.layerX));
		            moveHandle(scale.invert ? stepValue(scale.invert(pos / sliderLength)) : nearestTick(pos / sliderLength));
		          }
		        }
	
		        function onClickVertical() {
		          if (toType(value) != "array") {
		            var pos = sliderLength - Math.max(0, Math.min(sliderLength, d3.event.offsetY || d3.event.layerY));
		            moveHandle(scale.invert ? stepValue(scale.invert(pos / sliderLength)) : nearestTick(pos / sliderLength));
		          }
		        }
	
		        function onDragHorizontal() {
		          if (d3.event.sourceEvent.target.id === "handle-one") {
		            active = 1;
		          } else if (d3.event.sourceEvent.target.id == "handle-two") {
		            active = 2;
		          }
		          var pos = Math.max(0, Math.min(sliderLength, d3.event.x));
		          moveHandle(scale.invert ? stepValue(scale.invert(pos / sliderLength)) : nearestTick(pos / sliderLength));
		        }
	
		        function onDragVertical() {
		          if (d3.event.sourceEvent.target.id === "handle-one") {
		            active = 1;
		          } else if (d3.event.sourceEvent.target.id == "handle-two") {
		            active = 2;
		          }
		          var pos = sliderLength - Math.max(0, Math.min(sliderLength, d3.event.y));
		          moveHandle(scale.invert ? stepValue(scale.invert(pos / sliderLength)) : nearestTick(pos / sliderLength));
		        }
	
		        function stopPropagation() {
		          d3.event.stopPropagation();
		        }
		      });
		    }
	
		    // Move slider handle on click/drag
		    function moveHandle(newValue) {
		      var currentValue = toType(value) == "array" && value.length == 2 ? value[active - 1] : value,
		          oldPos = formatPercent(scale(stepValue(currentValue))),
		          newPos = formatPercent(scale(stepValue(newValue))),
		          position = orientation === "horizontal" ? "left" : "bottom";
		      if (oldPos !== newPos) {
	
		        if (toType(value) == "array" && value.length == 2) {
		          value[active - 1] = newValue;
		          if (d3.event) {
		            dispatch.slide(d3.event, value);
		          };
		        } else {
		          if (d3.event) {
		            dispatch.slide(d3.event.sourceEvent || d3.event, value = newValue);
		          };
		        }
	
		        if (value[0] >= value[1]) return;
		        if (active === 1) {
		          if (toType(value) == "array" && value.length == 2) {
		            position === "left" ? divRange.style("left", newPos) : divRange.style("bottom", newPos);
		          }
	
		          if (animate) {
		            handle1.transition().styleTween(position, function () {
		              return d3.interpolate(oldPos, newPos);
		            }).duration(typeof animate === "number" ? animate : 250);
		          } else {
		            handle1.style(position, newPos);
		          }
		        } else {
	
		          var width = 100 - parseFloat(newPos);
		          var top = 100 - parseFloat(newPos);
	
		          position === "left" ? divRange.style("right", width + "%") : divRange.style("top", top + "%");
	
		          if (animate) {
		            handle2.transition().styleTween(position, function () {
		              return d3.interpolate(oldPos, newPos);
		            }).duration(typeof animate === "number" ? animate : 250);
		          } else {
		            handle2.style(position, newPos);
		          }
		        }
		      }
		    }
	
		    // Calculate nearest step value
		    function stepValue(val) {
	
		      if (val === scale.domain()[0] || val === scale.domain()[1]) {
		        return val;
		      }
	
		      var alignValue = val;
		      if (snap) {
		        alignValue = nearestTick(scale(val));
		      } else {
		        var valModStep = (val - scale.domain()[0]) % step;
		        alignValue = val - valModStep;
	
		        if (Math.abs(valModStep) * 2 >= step) {
		          alignValue += valModStep > 0 ? step : -step;
		        }
		      };
	
		      return alignValue;
		    }
	
		    // Find the nearest tick
		    function nearestTick(pos) {
		      var ticks = scale.ticks ? scale.ticks() : scale.domain();
		      var dist = ticks.map(function (d) {
		        return pos - scale(d);
		      });
		      var i = -1,
		          index = 0,
		          r = scale.ticks ? scale.range()[1] : scale.rangeExtent()[1];
		      do {
		        i++;
		        if (Math.abs(dist[i]) < r) {
		          r = Math.abs(dist[i]);
		          index = i;
		        };
		      } while (dist[i] > 0 && i < dist.length - 1);
	
		      return ticks[index];
		    };
	
		    // Return the type of an object
		    function toType(v) {
		      return {}.toString.call(v).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
		    };
	
		    // Getter/setter functions
		    slider.min = function (_) {
		      if (!arguments.length) return min;
		      min = _;
		      return slider;
		    };
	
		    slider.max = function (_) {
		      if (!arguments.length) return max;
		      max = _;
		      return slider;
		    };
	
		    slider.step = function (_) {
		      if (!arguments.length) return step;
		      step = _;
		      return slider;
		    };
	
		    slider.animate = function (_) {
		      if (!arguments.length) return animate;
		      animate = _;
		      return slider;
		    };
	
		    slider.orientation = function (_) {
		      if (!arguments.length) return orientation;
		      orientation = _;
		      return slider;
		    };
	
		    slider.axis = function (_) {
		      if (!arguments.length) return axis;
		      axis = _;
		      return slider;
		    };
	
		    slider.margin = function (_) {
		      if (!arguments.length) return margin;
		      margin = _;
		      return slider;
		    };
	
		    slider.value = function (_) {
		      if (!arguments.length) return value;
		      if (value) {
		        moveHandle(stepValue(_));
		      };
		      value = _;
		      return slider;
		    };
	
		    slider.snap = function (_) {
		      if (!arguments.length) return snap;
		      snap = _;
		      return slider;
		    };
	
		    slider.scale = function (_) {
		      if (!arguments.length) return scale;
		      scale = _;
		      return slider;
		    };
	
		    d3.rebind(slider, dispatch, "on");
	
		    return slider;
		  };
		});
	
	/***/ }),
	/* 262 */
	/***/ (function(module, exports) {
	
		module.exports = __webpack_require__(4);
	
	/***/ }),
	/* 263 */
	/***/ (function(module, exports, __webpack_require__) {
	
		/* WEBPACK VAR INJECTION */(function(module) {"use strict";
	
		var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
	
		/**
		 * Simple, lightweight, usable local autocomplete library for modern browsers
		 * Because there weren’t enough autocomplete scripts in the world? Because I’m completely insane and have NIH syndrome? Probably both. :P
		 * @author Lea Verou http://leaverou.github.io/awesomplete
		 * MIT license
		 */
	
		(function () {
	
			var _ = function _(input, o) {
				var me = this;
	
				// Setup
	
				this.input = $(input);
				this.input.setAttribute("autocomplete", "off");
				this.input.setAttribute("aria-autocomplete", "list");
	
				o = o || {};
	
				configure(this, {
					minChars: 2,
					maxItems: 10,
					autoFirst: false,
					data: _.DATA,
					filter: _.FILTER_CONTAINS,
					sort: _.SORT_BYLENGTH,
					item: _.ITEM,
					replace: _.REPLACE
				}, o);
	
				this.index = -1;
	
				// Create necessary elements
	
				this.container = $.create("div", {
					className: "awesomplete",
					around: input
				});
	
				this.ul = $.create("ul", {
					hidden: "hidden",
					inside: this.container
				});
	
				this.status = $.create("span", {
					className: "visually-hidden",
					role: "status",
					"aria-live": "assertive",
					"aria-relevant": "additions",
					inside: this.container
				});
	
				// Bind events
	
				$.bind(this.input, {
					"input": this.evaluate.bind(this),
					"blur": this.close.bind(this, { reason: "blur" }),
					"keydown": function keydown(evt) {
						var c = evt.keyCode;
	
						// If the dropdown `ul` is in view, then act on keydown for the following keys:
						// Enter / Esc / Up / Down
						if (me.opened) {
							if (c === 13 && me.selected) {
								// Enter
								evt.preventDefault();
								me.select();
							} else if (c === 27) {
								// Esc
								me.close({ reason: "esc" });
							} else if (c === 38 || c === 40) {
								// Down/Up arrow
								evt.preventDefault();
								me[c === 38 ? "previous" : "next"]();
							}
						}
					}
				});
	
				$.bind(this.input.form, { "submit": this.close.bind(this, { reason: "submit" }) });
	
				$.bind(this.ul, { "mousedown": function mousedown(evt) {
						var li = evt.target;
	
						if (li !== this) {
	
							while (li && !/li/i.test(li.nodeName)) {
								li = li.parentNode;
							}
	
							if (li && evt.button === 0) {
								// Only select on left click
								evt.preventDefault();
								me.select(li, evt.target);
							}
						}
					} });
	
				if (this.input.hasAttribute("list")) {
					this.list = "#" + this.input.getAttribute("list");
					this.input.removeAttribute("list");
				} else {
					this.list = this.input.getAttribute("data-list") || o.list || [];
				}
	
				_.all.push(this);
			};
	
			_.prototype = {
				set list(list) {
					if (Array.isArray(list)) {
						this._list = list;
					} else if (typeof list === "string" && list.indexOf(",") > -1) {
						this._list = list.split(/\s*,\s*/);
					} else {
						// Element or CSS selector
						list = $(list);
	
						if (list && list.children) {
							var items = [];
							slice.apply(list.children).forEach(function (el) {
								if (!el.disabled) {
									var text = el.textContent.trim();
									var value = el.value || text;
									var label = el.label || text;
									if (value !== "") {
										items.push({ label: label, value: value });
									}
								}
							});
							this._list = items;
						}
					}
	
					if (document.activeElement === this.input) {
						this.evaluate();
					}
				},
	
				get selected() {
					return this.index > -1;
				},
	
				get opened() {
					return !this.ul.hasAttribute("hidden");
				},
	
				close: function close(o) {
					if (!this.opened) {
						return;
					}
	
					this.ul.setAttribute("hidden", "");
					this.index = -1;
	
					$.fire(this.input, "awesomplete-close", o || {});
				},
	
				open: function open() {
					this.ul.removeAttribute("hidden");
	
					if (this.autoFirst && this.index === -1) {
						this.goto(0);
					}
	
					$.fire(this.input, "awesomplete-open");
				},
	
				next: function next() {
					var count = this.ul.children.length;
	
					this.goto(this.index < count - 1 ? this.index + 1 : -1);
				},
	
				previous: function previous() {
					var count = this.ul.children.length;
	
					this.goto(this.selected ? this.index - 1 : count - 1);
				},
	
				// Should not be used, highlights specific item without any checks!
				goto: function goto(i) {
					var lis = this.ul.children;
	
					if (this.selected) {
						lis[this.index].setAttribute("aria-selected", "false");
					}
	
					this.index = i;
	
					if (i > -1 && lis.length > 0) {
						lis[i].setAttribute("aria-selected", "true");
						this.status.textContent = lis[i].textContent;
	
						$.fire(this.input, "awesomplete-highlight", {
							text: this.suggestions[this.index]
						});
					}
				},
	
				select: function select(selected, origin) {
					if (selected) {
						this.index = $.siblingIndex(selected);
					} else {
						selected = this.ul.children[this.index];
					}
	
					if (selected) {
						var suggestion = this.suggestions[this.index];
	
						var allowed = $.fire(this.input, "awesomplete-select", {
							text: suggestion,
							origin: origin || selected
						});
	
						if (allowed) {
							this.replace(suggestion);
							this.close({ reason: "select" });
							$.fire(this.input, "awesomplete-selectcomplete", {
								text: suggestion
							});
						}
					}
				},
	
				evaluate: function evaluate() {
					var me = this;
					var value = this.input.value;
	
					if (value.length >= this.minChars && this._list.length > 0) {
						this.index = -1;
						// Populate list with options that match
						this.ul.innerHTML = "";
	
						this.suggestions = this._list.map(function (item) {
							return new Suggestion(me.data(item, value));
						}).filter(function (item) {
							return me.filter(item, value);
						}).sort(this.sort).slice(0, this.maxItems);
	
						this.suggestions.forEach(function (text) {
							me.ul.appendChild(me.item(text, value));
						});
	
						if (this.ul.children.length === 0) {
							this.close({ reason: "nomatches" });
						} else {
							this.open();
						}
					} else {
						this.close({ reason: "nomatches" });
					}
				}
			};
	
			// Static methods/properties
	
			_.all = [];
	
			_.FILTER_CONTAINS = function (text, input) {
				return RegExp($.regExpEscape(input.trim()), "i").test(text);
			};
	
			_.FILTER_STARTSWITH = function (text, input) {
				return RegExp("^" + $.regExpEscape(input.trim()), "i").test(text);
			};
	
			_.SORT_BYLENGTH = function (a, b) {
				if (a.length !== b.length) {
					return a.length - b.length;
				}
	
				return a < b ? -1 : 1;
			};
	
			_.ITEM = function (text, input) {
				var html = input === '' ? text : text.replace(RegExp($.regExpEscape(input.trim()), "gi"), "<mark>$&</mark>");
				return $.create("li", {
					innerHTML: html,
					"aria-selected": "false"
				});
			};
	
			_.REPLACE = function (text) {
				this.input.value = text.value;
			};
	
			_.DATA = function (item /*, input*/) {
				return item;
			};
	
			// Private functions
	
			function Suggestion(data) {
				var o = Array.isArray(data) ? { label: data[0], value: data[1] } : (typeof data === "undefined" ? "undefined" : _typeof(data)) === "object" && "label" in data && "value" in data ? data : { label: data, value: data };
	
				this.label = o.label || o.value;
				this.value = o.value;
			}
			Object.defineProperty(Suggestion.prototype = Object.create(String.prototype), "length", {
				get: function get() {
					return this.label.length;
				}
			});
			Suggestion.prototype.toString = Suggestion.prototype.valueOf = function () {
				return "" + this.label;
			};
	
			function configure(instance, properties, o) {
				for (var i in properties) {
					var initial = properties[i],
					    attrValue = instance.input.getAttribute("data-" + i.toLowerCase());
	
					if (typeof initial === "number") {
						instance[i] = parseInt(attrValue);
					} else if (initial === false) {
						// Boolean options must be false by default anyway
						instance[i] = attrValue !== null;
					} else if (initial instanceof Function) {
						instance[i] = null;
					} else {
						instance[i] = attrValue;
					}
	
					if (!instance[i] && instance[i] !== 0) {
						instance[i] = i in o ? o[i] : initial;
					}
				}
			}
	
			// Helpers
	
			var slice = Array.prototype.slice;
	
			function $(expr, con) {
				return typeof expr === "string" ? (con || document).querySelector(expr) : expr || null;
			}
	
			function $$(expr, con) {
				return slice.call((con || document).querySelectorAll(expr));
			}
	
			$.create = function (tag, o) {
				var element = document.createElement(tag);
	
				for (var i in o) {
					var val = o[i];
	
					if (i === "inside") {
						$(val).appendChild(element);
					} else if (i === "around") {
						var ref = $(val);
						ref.parentNode.insertBefore(element, ref);
						element.appendChild(ref);
					} else if (i in element) {
						element[i] = val;
					} else {
						element.setAttribute(i, val);
					}
				}
	
				return element;
			};
	
			$.bind = function (element, o) {
				if (element) {
					for (var event in o) {
						var callback = o[event];
	
						event.split(/\s+/).forEach(function (event) {
							element.addEventListener(event, callback);
						});
					}
				}
			};
	
			$.fire = function (target, type, properties) {
				var evt = document.createEvent("HTMLEvents");
	
				evt.initEvent(type, true, true);
	
				for (var j in properties) {
					evt[j] = properties[j];
				}
	
				return target.dispatchEvent(evt);
			};
	
			$.regExpEscape = function (s) {
				return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
			};
	
			$.siblingIndex = function (el) {
				/* eslint-disable no-cond-assign */
				for (var i = 0; el = el.previousElementSibling; i++) {}
				return i;
			};
	
			// Initialization
	
			function init() {
				$$("input.awesomplete").forEach(function (input) {
					new _(input);
				});
			}
	
			// Are we in a browser? Check for Document constructor
			if (typeof Document !== "undefined") {
				// DOM already loaded?
				if (document.readyState !== "loading") {
					init();
				} else {
					// Wait for it
					document.addEventListener("DOMContentLoaded", init);
				}
			}
	
			_.$ = $;
			_.$$ = $$;
	
			// Make sure to export Awesomplete on self when in a browser
			if (typeof self !== "undefined") {
				self.Awesomplete = _;
			}
	
			// Expose Awesomplete as a CJS module
			if (( false ? "undefined" : _typeof(module)) === "object" && module.exports) {
				module.exports = _;
			}
	
			return _;
			})();
		/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(264)(module)))
	
	/***/ }),
	/* 264 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function (module) {
			if (!module.webpackPolyfill) {
				module.deprecate = function () {};
				module.paths = [];
				// module.parent = undefined by default
				module.children = [];
				module.webpackPolyfill = 1;
			}
			return module;
		};
	
	/***/ }),
	/* 265 */
	/***/ (function(module, exports, __webpack_require__) {
	
		// style-loader: Adds some css to the DOM by adding a <style> tag
	
		// load the styles
		var content = __webpack_require__(266);
		if(typeof content === 'string') content = [[module.id, content, '']];
		// add the styles to the DOM
		var update = __webpack_require__(268)(content, {});
		if(content.locals) module.exports = content.locals;
		// Hot Module Replacement
		if(false) {
			// When the styles change, update the <style> tags
			if(!content.locals) {
				module.hot.accept("!!../../node_modules/css-loader/index.js!./d3.slider.css", function() {
					var newContent = require("!!../../node_modules/css-loader/index.js!./d3.slider.css");
					if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
					update(newContent);
				});
			}
			// When the module is disposed, remove the <style> tags
			module.hot.dispose(function() { update(); });
		}
	
	/***/ }),
	/* 266 */
	/***/ (function(module, exports, __webpack_require__) {
	
		exports = module.exports = __webpack_require__(267)();
		// imports
	
	
		// module
		exports.push([module.id, ".d3-slider {\n    position: relative;\n    font-family: Verdana,Arial,sans-serif;\n    font-size: 1.1em;\n    border: 1px solid #aaaaaa;\n    z-index: 2;\n}\n\n.d3-slider-horizontal {\n    height: .8em;\n}  \n\n.d3-slider-range {\n  background:#2980b9;\n  left:0px;\n  right:0px;\n  height: 0.8em;\n  position: absolute;\n}\n\n.d3-slider-range-vertical {\n  background:#2980b9;\n  left:0px;\n  right:0px;\n  position: absolute;\n  top:0;\n}\n\n.d3-slider-vertical {\n    width: .8em;\n    height: 100px;\n}      \n\n.d3-slider-handle {\n    position: absolute;\n    width: 1.2em;\n    height: 1.2em;\n    border: 1px solid #d3d3d3;\n    border-radius: 4px;\n    background: #eee;\n    background: linear-gradient(to bottom, #eee 0%, #ddd 100%);\n    z-index: 3;\n}\n\n.d3-slider-handle:hover {\n    border: 1px solid #999999;\n}\n\n.d3-slider-horizontal .d3-slider-handle {\n    top: -.3em;\n    margin-left: -.6em;\n}\n\n.d3-slider-axis {\n    position: relative;\n    z-index: 1;    \n}\n\n.d3-slider-axis-bottom {\n    top: .8em;\n}\n\n.d3-slider-axis-right {\n    left: .8em;\n}\n\n.d3-slider-axis path {\n    stroke-width: 0;\n    fill: none;\n}\n\n.d3-slider-axis line {\n    fill: none;\n    stroke: #aaa;\n    shape-rendering: crispEdges;\n}\n\n.d3-slider-axis text {\n    font-size: 11px;\n}\n\n.d3-slider-vertical .d3-slider-handle {\n    left: -.25em;\n    margin-left: 0;\n    margin-bottom: -.6em;      \n}", ""]);
	
		// exports
	
	
	/***/ }),
	/* 267 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		/*
			MIT License http://www.opensource.org/licenses/mit-license.php
			Author Tobias Koppers @sokra
		*/
		// css base code, injected by the css-loader
		module.exports = function () {
			var list = [];
	
			// return the list of modules as css string
			list.toString = function toString() {
				var result = [];
				for (var i = 0; i < this.length; i++) {
					var item = this[i];
					if (item[2]) {
						result.push("@media " + item[2] + "{" + item[1] + "}");
					} else {
						result.push(item[1]);
					}
				}
				return result.join("");
			};
	
			// import a list of modules into the list
			list.i = function (modules, mediaQuery) {
				if (typeof modules === "string") modules = [[null, modules, ""]];
				var alreadyImportedModules = {};
				for (var i = 0; i < this.length; i++) {
					var id = this[i][0];
					if (typeof id === "number") alreadyImportedModules[id] = true;
				}
				for (i = 0; i < modules.length; i++) {
					var item = modules[i];
					// skip already imported module
					// this implementation is not 100% perfect for weird media query combinations
					//  when a module is imported multiple times with different media queries.
					//  I hope this will never occur (Hey this way we have smaller bundles)
					if (typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) {
						if (mediaQuery && !item[2]) {
							item[2] = mediaQuery;
						} else if (mediaQuery) {
							item[2] = "(" + item[2] + ") and (" + mediaQuery + ")";
						}
						list.push(item);
					}
				}
			};
			return list;
		};
	
	/***/ }),
	/* 268 */
	/***/ (function(module, exports, __webpack_require__) {
	
		/*
			MIT License http://www.opensource.org/licenses/mit-license.php
			Author Tobias Koppers @sokra
		*/
		var stylesInDom = {},
			memoize = function(fn) {
				var memo;
				return function () {
					if (typeof memo === "undefined") memo = fn.apply(this, arguments);
					return memo;
				};
			},
			isOldIE = memoize(function() {
				return /msie [6-9]\b/.test(self.navigator.userAgent.toLowerCase());
			}),
			getHeadElement = memoize(function () {
				return document.head || document.getElementsByTagName("head")[0];
			}),
			singletonElement = null,
			singletonCounter = 0,
			styleElementsInsertedAtTop = [];
	
		module.exports = function(list, options) {
			if(false) {
				if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
			}
	
			options = options || {};
			// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
			// tags it will allow on a page
			if (typeof options.singleton === "undefined") options.singleton = isOldIE();
	
			// By default, add <style> tags to the bottom of <head>.
			if (typeof options.insertAt === "undefined") options.insertAt = "bottom";
	
			var styles = listToStyles(list);
			addStylesToDom(styles, options);
	
			return function update(newList) {
				var mayRemove = [];
				for(var i = 0; i < styles.length; i++) {
					var item = styles[i];
					var domStyle = stylesInDom[item.id];
					domStyle.refs--;
					mayRemove.push(domStyle);
				}
				if(newList) {
					var newStyles = listToStyles(newList);
					addStylesToDom(newStyles, options);
				}
				for(var i = 0; i < mayRemove.length; i++) {
					var domStyle = mayRemove[i];
					if(domStyle.refs === 0) {
						for(var j = 0; j < domStyle.parts.length; j++)
							domStyle.parts[j]();
						delete stylesInDom[domStyle.id];
					}
				}
			};
		}
	
		function addStylesToDom(styles, options) {
			for(var i = 0; i < styles.length; i++) {
				var item = styles[i];
				var domStyle = stylesInDom[item.id];
				if(domStyle) {
					domStyle.refs++;
					for(var j = 0; j < domStyle.parts.length; j++) {
						domStyle.parts[j](item.parts[j]);
					}
					for(; j < item.parts.length; j++) {
						domStyle.parts.push(addStyle(item.parts[j], options));
					}
				} else {
					var parts = [];
					for(var j = 0; j < item.parts.length; j++) {
						parts.push(addStyle(item.parts[j], options));
					}
					stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts};
				}
			}
		}
	
		function listToStyles(list) {
			var styles = [];
			var newStyles = {};
			for(var i = 0; i < list.length; i++) {
				var item = list[i];
				var id = item[0];
				var css = item[1];
				var media = item[2];
				var sourceMap = item[3];
				var part = {css: css, media: media, sourceMap: sourceMap};
				if(!newStyles[id])
					styles.push(newStyles[id] = {id: id, parts: [part]});
				else
					newStyles[id].parts.push(part);
			}
			return styles;
		}
	
		function insertStyleElement(options, styleElement) {
			var head = getHeadElement();
			var lastStyleElementInsertedAtTop = styleElementsInsertedAtTop[styleElementsInsertedAtTop.length - 1];
			if (options.insertAt === "top") {
				if(!lastStyleElementInsertedAtTop) {
					head.insertBefore(styleElement, head.firstChild);
				} else if(lastStyleElementInsertedAtTop.nextSibling) {
					head.insertBefore(styleElement, lastStyleElementInsertedAtTop.nextSibling);
				} else {
					head.appendChild(styleElement);
				}
				styleElementsInsertedAtTop.push(styleElement);
			} else if (options.insertAt === "bottom") {
				head.appendChild(styleElement);
			} else {
				throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'.");
			}
		}
	
		function removeStyleElement(styleElement) {
			styleElement.parentNode.removeChild(styleElement);
			var idx = styleElementsInsertedAtTop.indexOf(styleElement);
			if(idx >= 0) {
				styleElementsInsertedAtTop.splice(idx, 1);
			}
		}
	
		function createStyleElement(options) {
			var styleElement = document.createElement("style");
			styleElement.type = "text/css";
			insertStyleElement(options, styleElement);
			return styleElement;
		}
	
		function createLinkElement(options) {
			var linkElement = document.createElement("link");
			linkElement.rel = "stylesheet";
			insertStyleElement(options, linkElement);
			return linkElement;
		}
	
		function addStyle(obj, options) {
			var styleElement, update, remove;
	
			if (options.singleton) {
				var styleIndex = singletonCounter++;
				styleElement = singletonElement || (singletonElement = createStyleElement(options));
				update = applyToSingletonTag.bind(null, styleElement, styleIndex, false);
				remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true);
			} else if(obj.sourceMap &&
				typeof URL === "function" &&
				typeof URL.createObjectURL === "function" &&
				typeof URL.revokeObjectURL === "function" &&
				typeof Blob === "function" &&
				typeof btoa === "function") {
				styleElement = createLinkElement(options);
				update = updateLink.bind(null, styleElement);
				remove = function() {
					removeStyleElement(styleElement);
					if(styleElement.href)
						URL.revokeObjectURL(styleElement.href);
				};
			} else {
				styleElement = createStyleElement(options);
				update = applyToTag.bind(null, styleElement);
				remove = function() {
					removeStyleElement(styleElement);
				};
			}
	
			update(obj);
	
			return function updateStyle(newObj) {
				if(newObj) {
					if(newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap)
						return;
					update(obj = newObj);
				} else {
					remove();
				}
			};
		}
	
		var replaceText = (function () {
			var textStore = [];
	
			return function (index, replacement) {
				textStore[index] = replacement;
				return textStore.filter(Boolean).join('\n');
			};
		})();
	
		function applyToSingletonTag(styleElement, index, remove, obj) {
			var css = remove ? "" : obj.css;
	
			if (styleElement.styleSheet) {
				styleElement.styleSheet.cssText = replaceText(index, css);
			} else {
				var cssNode = document.createTextNode(css);
				var childNodes = styleElement.childNodes;
				if (childNodes[index]) styleElement.removeChild(childNodes[index]);
				if (childNodes.length) {
					styleElement.insertBefore(cssNode, childNodes[index]);
				} else {
					styleElement.appendChild(cssNode);
				}
			}
		}
	
		function applyToTag(styleElement, obj) {
			var css = obj.css;
			var media = obj.media;
	
			if(media) {
				styleElement.setAttribute("media", media)
			}
	
			if(styleElement.styleSheet) {
				styleElement.styleSheet.cssText = css;
			} else {
				while(styleElement.firstChild) {
					styleElement.removeChild(styleElement.firstChild);
				}
				styleElement.appendChild(document.createTextNode(css));
			}
		}
	
		function updateLink(linkElement, obj) {
			var css = obj.css;
			var sourceMap = obj.sourceMap;
	
			if(sourceMap) {
				// http://stackoverflow.com/a/26603875
				css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */";
			}
	
			var blob = new Blob([css], { type: "text/css" });
	
			var oldSrc = linkElement.href;
	
			linkElement.href = URL.createObjectURL(blob);
	
			if(oldSrc)
				URL.revokeObjectURL(oldSrc);
		}
	
	
	/***/ }),
	/* 269 */
	/***/ (function(module, exports, __webpack_require__) {
	
		// style-loader: Adds some css to the DOM by adding a <style> tag
	
		// load the styles
		var content = __webpack_require__(270);
		if(typeof content === 'string') content = [[module.id, content, '']];
		// add the styles to the DOM
		var update = __webpack_require__(268)(content, {});
		if(content.locals) module.exports = content.locals;
		// Hot Module Replacement
		if(false) {
			// When the styles change, update the <style> tags
			if(!content.locals) {
				module.hot.accept("!!../css-loader/index.js!./awesomplete.css", function() {
					var newContent = require("!!../css-loader/index.js!./awesomplete.css");
					if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
					update(newContent);
				});
			}
			// When the module is disposed, remove the <style> tags
			module.hot.dispose(function() { update(); });
		}
	
	/***/ }),
	/* 270 */
	/***/ (function(module, exports, __webpack_require__) {
	
		exports = module.exports = __webpack_require__(267)();
		// imports
	
	
		// module
		exports.push([module.id, "[hidden] { display: none; }\n\n.visually-hidden {\n\tposition: absolute;\n\tclip: rect(0, 0, 0, 0);\n}\n\ndiv.awesomplete {\n\tdisplay: inline-block;\n\tposition: relative;\n}\n\ndiv.awesomplete > input {\n\tdisplay: block;\n}\n\ndiv.awesomplete > ul {\n\tposition: absolute;\n\tleft: 0;\n\tz-index: 1;\n\tmin-width: 100%;\n\tbox-sizing: border-box;\n\tlist-style: none;\n\tpadding: 0;\n\tborder-radius: .3em;\n\tmargin: .2em 0 0;\n\tbackground: hsla(0,0%,100%,.9);\n\tbackground: linear-gradient(to bottom right, white, hsla(0,0%,100%,.8));\n\tborder: 1px solid rgba(0,0,0,.3);\n\tbox-shadow: .05em .2em .6em rgba(0,0,0,.2);\n\ttext-shadow: none;\n}\n\ndiv.awesomplete > ul[hidden],\ndiv.awesomplete > ul:empty {\n\tdisplay: none;\n}\n\n@supports (transform: scale(0)) {\n\tdiv.awesomplete > ul {\n\t\ttransition: .3s cubic-bezier(.4,.2,.5,1.4);\n\t\ttransform-origin: 1.43em -.43em;\n\t}\n\t\n\tdiv.awesomplete > ul[hidden],\n\tdiv.awesomplete > ul:empty {\n\t\topacity: 0;\n\t\ttransform: scale(0);\n\t\tdisplay: block;\n\t\ttransition-timing-function: ease;\n\t}\n}\n\n\t/* Pointer */\n\tdiv.awesomplete > ul:before {\n\t\tcontent: \"\";\n\t\tposition: absolute;\n\t\ttop: -.43em;\n\t\tleft: 1em;\n\t\twidth: 0; height: 0;\n\t\tpadding: .4em;\n\t\tbackground: white;\n\t\tborder: inherit;\n\t\tborder-right: 0;\n\t\tborder-bottom: 0;\n\t\t-webkit-transform: rotate(45deg);\n\t\ttransform: rotate(45deg);\n\t}\n\n\tdiv.awesomplete > ul > li {\n\t\tposition: relative;\n\t\tpadding: .2em .5em;\n\t\tcursor: pointer;\n\t}\n\t\n\tdiv.awesomplete > ul > li:hover {\n\t\tbackground: hsl(200, 40%, 80%);\n\t\tcolor: black;\n\t}\n\t\n\tdiv.awesomplete > ul > li[aria-selected=\"true\"] {\n\t\tbackground: hsl(205, 40%, 40%);\n\t\tcolor: white;\n\t}\n\t\n\t\tdiv.awesomplete mark {\n\t\t\tbackground: hsl(65, 100%, 50%);\n\t\t}\n\t\t\n\t\tdiv.awesomplete li:hover mark {\n\t\t\tbackground: hsl(68, 100%, 41%);\n\t\t}\n\t\t\n\t\tdiv.awesomplete li[aria-selected=\"true\"] mark {\n\t\t\tbackground: hsl(86, 100%, 21%);\n\t\t\tcolor: inherit;\n\t\t}", ""]);
	
		// exports
	
	
	/***/ }),
	/* 271 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var ini_sidebar = __webpack_require__(218);
		var set_up_filters = __webpack_require__(272);
		var set_up_search = __webpack_require__(277);
		var set_up_reorder = __webpack_require__(278);
		var set_sidebar_ini_view = __webpack_require__(279);
		var make_icons = __webpack_require__(280);
		var make_modals = __webpack_require__(282);
		var set_up_opacity_slider = __webpack_require__(284);
		var make_colorbar = __webpack_require__(285);
	
		/* Represents sidebar with controls.
		 */
		module.exports = function sidebar(cgm) {
	
		  var params = cgm.params;
	
		  var sidebar = d3.select(params.root + ' .sidebar_wrapper');
	
		  // console.log('is_expand ',params.viz.is_expand)
	
		  if (params.viz.is_expand) {
		    sidebar.style('display', 'none');
		  }
	
		  sidebar.append('div').classed('title_section', true);
	
		  if (params.sidebar.title != null) {
		    sidebar.select('.title_section').append('h4')
		    // .style('margin-left', params.sidebar.title_margin_left+'px')
		    .style('margin-left', '20px').style('margin-top', '5px').style('margin-bottom', '0px').text(params.sidebar.title);
		  }
	
		  sidebar.append('div').style('padding-right', '2px').classed('about_section', true);
	
		  if (params.sidebar.about != null) {
	
		    sidebar.select('.about_section').append('h5').classed('sidebar_text', true).style('margin-left', '7px').style('margin-top', '5px').style('margin-bottom', '2px').style('text-align', 'justify').html(params.sidebar.about);
		  }
	
		  sidebar.append('div').classed('icons_section', true).style('text-align', 'center');
	
		  if (cgm.params.make_modals) {
		    make_modals(params);
		  }
	
		  if (params.sidebar.icons) {
		    make_icons(cgm, sidebar);
		  }
	
		  set_up_reorder(params, sidebar);
	
		  set_up_search(sidebar, params);
	
		  set_up_opacity_slider(sidebar);
	
		  var possible_filter_names = _.keys(params.viz.possible_filters);
	
		  if (possible_filter_names.indexOf('enr_score_type') > -1) {
		    possible_filter_names.sort(function (a, b) {
		      return a.toLowerCase().localeCompare(b.toLowerCase());
		    });
		  }
	
		  cgm.slider_functions = {};
	
		  _.each(possible_filter_names, function (inst_filter) {
		    set_up_filters(cgm, inst_filter);
		  });
	
		  ini_sidebar(cgm);
	
		  // when initializing the visualization using a view
		  if (params.ini_view !== null) {
	
		    set_sidebar_ini_view(params);
	
		    params.ini_view = null;
		  }
	
		  make_colorbar(cgm);
			};
	
	/***/ }),
	/* 272 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_slider_filter = __webpack_require__(273);
		var make_button_filter = __webpack_require__(276);
	
		module.exports = function set_up_filters(cgm, filter_type) {
	
		  var params = cgm.params;
	
		  var div_filters = d3.select(params.root + ' .sidebar_wrapper').append('div').classed('div_filters', true).style('padding-left', '10px').style('padding-right', '10px');
	
		  if (params.viz.possible_filters[filter_type] == 'numerical') {
		    make_slider_filter(cgm, filter_type, div_filters);
		  } else if (params.viz.possible_filters[filter_type] == 'categorical') {
		    make_button_filter(cgm, filter_type, div_filters);
		  }
			};
	
	/***/ }),
	/* 273 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_filter_title = __webpack_require__(226);
		var run_filter_slider = __webpack_require__(274);
		var get_filter_default_state = __webpack_require__(5);
		var get_subset_views = __webpack_require__(63);
	
		d3.slider = __webpack_require__(261);
	
		module.exports = function make_slider_filter(cgm, filter_type, div_filters) {
	
		  var params = cgm.params;
		  var inst_view = {};
	
		  var possible_filters = _.keys(params.viz.possible_filters);
	
		  _.each(possible_filters, function (tmp_filter) {
		    if (tmp_filter != filter_type) {
		      var default_state = get_filter_default_state(params.viz.filter_data, tmp_filter);
		      inst_view[tmp_filter] = default_state;
		    }
		  });
	
		  var filter_title = make_filter_title(params, filter_type);
	
		  div_filters.append('div').classed('title_' + filter_type, true).classed('sidebar_text', true).classed('slider_description', true).style('margin-top', '5px').style('margin-bottom', '3px').text(filter_title.text + filter_title.state + filter_title.suffix);
	
		  div_filters.append('div').classed('slider_' + filter_type, true).classed('slider', true).attr('current_state', filter_title.state);
	
		  var views = params.network_data.views;
	
		  var available_views = get_subset_views(params, views, inst_view);
	
		  // sort available views by filter_type value
		  available_views = available_views.sort(function (a, b) {
		    return b[filter_type] - a[filter_type];
		  });
	
		  var inst_max = available_views.length - 1;
	
		  var ini_value = 0;
		  // change the starting position of the slider if necessary
		  if (params.requested_view !== null && filter_type in params.requested_view) {
	
		    var inst_filter_value = params.requested_view[filter_type];
	
		    if (inst_filter_value != 'all') {
	
		      var found_value = available_views.map(function (e) {
		        return e[filter_type];
		      }).indexOf(inst_filter_value);
	
		      if (found_value > 0) {
		        ini_value = found_value;
		      }
		    }
		  }
	
		  // Filter Slider
		  //////////////////////////////////////////////////////////////////////
		  var slide_filter_fun = d3.slider().value(ini_value).min(0).max(inst_max).step(1).on('slide', function (evt, value) {
		    run_filter_slider_db(cgm, filter_type, available_views, value);
		  }).on('slideend', function (evt, value) {
		    run_filter_slider_db(cgm, filter_type, available_views, value);
		  });
	
		  // save slider function in order to reset value later
		  cgm.slider_functions[filter_type] = slide_filter_fun;
	
		  d3.select(cgm.params.root + ' .slider_' + filter_type).call(slide_filter_fun);
	
		  //////////////////////////////////////////////////////////////////////
	
		  var run_filter_slider_db = _.debounce(run_filter_slider, 800);
			};
	
	/***/ }),
	/* 274 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var update_viz_with_view = __webpack_require__(203);
		var reset_other_filter_sliders = __webpack_require__(225);
		var get_current_orders = __webpack_require__(275);
		var make_requested_view = __webpack_require__(65);
	
		module.exports = function run_filter_slider(cgm, filter_type, available_views, inst_index) {
	
		  // only update if not running update
		  if (d3.select(cgm.params.viz.viz_svg).classed('running_update') === false) {
	
		    var params = cgm.params;
	
		    // get value
		    var inst_state = available_views[inst_index][filter_type];
	
		    reset_other_filter_sliders(cgm, filter_type, inst_state);
	
		    params = get_current_orders(params);
	
		    var requested_view = {};
		    requested_view[filter_type] = inst_state;
	
		    requested_view = make_requested_view(params, requested_view);
	
		    if (_.has(available_views[0], 'enr_score_type')) {
		      var enr_state = d3.select(params.root + ' .toggle_enr_score_type').attr('current_state');
	
		      requested_view.enr_score_type = enr_state;
		    }
	
		    update_viz_with_view(cgm, requested_view);
		  }
			};
	
	/***/ }),
	/* 275 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function get_current_orders(params) {
	
		  // get current orders 
		  var other_rc;
		  _.each(['row', 'col'], function (inst_rc) {
	
		    if (inst_rc === 'row') {
		      other_rc = 'col';
		    } else {
		      other_rc = 'row';
		    }
	
		    if (d3.select(params.root + ' .toggle_' + other_rc + '_order .active').empty() === false) {
	
		      params.viz.inst_order[inst_rc] = d3.select(params.root + ' .toggle_' + other_rc + '_order').select('.active').attr('name');
		    } else {
	
		      // default to cluster ordering 
		      params.viz.inst_order[inst_rc] = 'clust';
		    }
		  });
	
		  return params;
		};
	
	/***/ }),
	/* 276 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		// var update_network = require('../network/update_network');
		var make_requested_view = __webpack_require__(65);
	
		module.exports = function make_button_filter(config, params, filter_type, div_filters) {
	
		  /*
		  Enrichr specific code
		  */
	
		  var buttons = div_filters.append('div').classed('categorical_filter', true).classed('toggle_' + filter_type, true).classed('btn-group-vertical', true).style('width', '100%').style('margin-top', '10px').attr('current_state', 'combined_score');
	
		  var filter_options = params.viz.filter_data[filter_type];
	
		  var button_dict = {
		    'combined_score': 'Combined Score',
		    'pval': 'P-Value',
		    'zscore': 'Z-score'
		  };
	
		  buttons.selectAll('button').data(filter_options).enter().append('button').attr('type', 'button').classed('btn', true).classed('btn-primary', true).classed('.filter_button', true).classed('active', function (d) {
		    var is_active = false;
		    if (d == 'combined_score') {
		      is_active = true;
		    }
		    return is_active;
		  }).attr('name', function (d) {
		    return d;
		  }).html(function (d) {
		    return button_dict[d];
		  });
	
		  $(params.root + ' .categorical_filter .btn').off().click(function () {
	
		    d3.selectAll(params.root + ' .categorical_filter .btn').classed('active', false);
	
		    d3.select(this).classed('active', true);
	
		    var inst_state = d3.select(this).attr('name');
	
		    var requested_view = { 'enr_score_type': inst_state };
	
		    make_requested_view(params, requested_view);
	
		    d3.select(params.root + ' .toggle_enr_score_type').attr('current_state', inst_state);
		  });
			};
	
	/***/ }),
	/* 277 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function set_up_search(sidebar, params) {
	
		  var search_container = sidebar.append('div')
		  // .classed('row',true)
		  .classed('gene_search_container', true).style('padding-left', '10px').style('padding-right', '10px').style('margin-top', '10px');
	
		  search_container.append('input').classed('form-control', true).classed('gene_search_box', true).classed('sidebar_text', true).attr('type', 'text').attr('placeholder', params.sidebar.row_search.placeholder).style('height', params.sidebar.row_search.box.height + 'px').style('margin-top', '10px');
	
		  search_container.append('div').classed('gene_search_button', true).style('margin-top', '5px').attr('data-toggle', 'buttons').append('button').classed('sidebar_text', true).html('Search').attr('type', 'button').classed('btn', true).classed('btn-primary', true).classed('submit_gene_button', true).style('width', '100%').style('font-size', '14px');
			};
	
	/***/ }),
	/* 278 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		// var get_cat_title = require('../categories/get_cat_title');
	
		module.exports = function set_up_reorder(params, sidebar) {
	
		  var button_dict;
		  var tmp_orders;
		  var rc_dict = { 'row': 'Row', 'col': 'Column', 'both': '' };
		  var is_active;
		  var inst_reorder;
		  // var all_cats;
		  // var inst_order_label;
	
		  var reorder_section = sidebar.append('div').style('padding-left', '10px').style('padding-right', '10px').classed('reorder_section', true);
	
		  var reorder_types;
		  if (params.sim_mat) {
		    reorder_types = ['both'];
		  } else {
		    reorder_types = ['row', 'col'];
		  }
	
		  _.each(reorder_types, function (inst_rc) {
	
		    button_dict = {
		      'clust': 'Cluster',
		      'rank': 'Rank by Sum',
		      'rankvar': 'Rank by Variance',
		      'ini': 'Initial Order',
		      'alpha': 'Alphabetically'
		    };
	
		    var other_rc;
		    if (inst_rc === 'row') {
		      other_rc = 'col';
		    } else {
		      other_rc = 'row';
		    }
	
		    tmp_orders = Object.keys(params.matrix.orders);
	
		    var possible_orders = [];
	
		    _.each(tmp_orders, function (inst_name) {
	
		      if (inst_name.indexOf(other_rc) > -1) {
		        inst_name = inst_name.replace('_row', '').replace('_col', '');
	
		        if (inst_name.indexOf('cat_') < 0) {
		          possible_orders.push(inst_name);
		        }
		      }
		    });
	
		    // specific to Enrichr
		    if (_.keys(params.viz.filter_data).indexOf('enr_score_type') > -1) {
		      possible_orders = ['clust', 'rank'];
		    }
	
		    possible_orders = _.uniq(possible_orders);
	
		    possible_orders = possible_orders.sort();
	
		    var reorder_text;
		    if (inst_rc != 'both') {
		      reorder_text = ' Order';
		    } else {
		      reorder_text = 'Reorder Matrix';
		    }
	
		    reorder_section.append('div').classed('sidebar_button_text', true).style('clear', 'both').style('margin-top', '10px').html(rc_dict[inst_rc] + reorder_text);
	
		    inst_reorder = reorder_section.append('div').classed('btn-group-vertical', true).style('width', '100%').classed('toggle_' + inst_rc + '_order', true).attr('role', 'group');
	
		    inst_reorder.selectAll('.button').data(possible_orders).enter().append('button').attr('type', 'button').classed('btn', true).classed('btn-primary', true).classed('sidebar_button_text', true).classed('active', function (d) {
		      is_active = false;
		      if (d == params.viz.inst_order[other_rc]) {
		        is_active = true;
		      }
		      return is_active;
		    }).attr('name', function (d) {
		      return d;
		    }).html(function (d) {
		      return button_dict[d];
		    });
		  });
			};
	
	/***/ }),
	/* 279 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_filter_title = __webpack_require__(226);
	
		module.exports = function set_sidebar_ini_view(params) {
	
		  _.each(_.keys(params.ini_view), function (inst_filter) {
	
		    // initialize filter slider using ini_view
		    var inst_value = params.ini_view[inst_filter];
	
		    var filter_type = params.viz.possible_filters[inst_filter];
	
		    if (filter_type === 'numerical') {
	
		      if (inst_value != 'all') {
		        inst_value = parseInt(inst_value, 10);
		      }
	
		      if (params.viz.filter_data[inst_filter].indexOf(inst_value) <= -1) {
		        inst_value = 'all';
		      }
	
		      var filter_title = make_filter_title(params, inst_filter);
	
		      d3.select(params.root + ' .title_' + inst_filter).text(filter_title.text + inst_value + filter_title.suffix);
	
		      d3.select(params.root + ' .slider_' + inst_filter).attr('current_state', inst_value);
		    } else {
	
		      // set up button initialization
	
		    }
		  });
			};
	
	/***/ }),
	/* 280 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var file_saver = __webpack_require__(256);
		var two_translate_zoom = __webpack_require__(144);
		var deactivate_cropping = __webpack_require__(260);
		var save_svg_png = __webpack_require__(281);
	
		module.exports = function make_icons(cgm, sidebar) {
	
		  var params = cgm.params;
		  // var saveSvgAsPng = save_svg_png();
		  var saveAs = file_saver();
	
		  var row = sidebar.select('.icons_section').style('margin-top', '7px').style('margin-left', '5%');
	
		  var width_pct = '22%';
		  var padding_left = '0px';
		  var padding_right = '0px';
	
		  row.append('div').classed('clust_icon', true).style('float', 'left').style('width', width_pct).style('padding-left', padding_left).style('padding-right', padding_right).append('i').classed('fa', true).classed('fa-share-alt', true).classed('icon_buttons', true).style('font-size', '25px').on('click', function () {
		    $(params.root + ' .share_info').modal('toggle');
		    $('.share_url').val(window.location.href);
		  }).classed('sidebar_tooltip', true).append('span').classed('sidebar_tooltip_text', true).html('Share').style('left', '0%');
	
		  row.append('div').classed('clust_icon', true).style('float', 'left').style('width', width_pct).style('padding-left', padding_left).style('padding-right', padding_right).append('i').classed('fa', true).classed('fa-camera', true).classed('icon_buttons', true).style('font-size', '25px').on('click', function () {
	
		    $(params.root + ' .picture_info').modal('toggle');
		  }).classed('sidebar_tooltip', true).append('span').classed('sidebar_tooltip_text', true).html('Take snapshot').style('left', '-100%');
	
		  row.append('div').classed('clust_icon', true).style('float', 'left').style('width', width_pct).style('padding-left', padding_left).style('padding-right', padding_right).append('i').classed('fa', true).classed('fa fa-cloud-download', true).classed('icon_buttons', true).style('font-size', '25px').on('click', function () {
	
		    cgm.save_matrix();
		  }).classed('sidebar_tooltip', true).append('span').classed('sidebar_tooltip_text', true).html('Download matrix').style('left', '-200%');
	
		  row.append('div').classed('clust_icon', true).style('float', 'left').style('width', width_pct).style('padding-left', padding_left).style('padding-right', '-5px').append('i').classed('fa', true).classed('fa-crop', true).classed('crop_button', true).classed('icon_buttons', true).style('font-size', '25px').on('click', function () {
	
		    // do nothing if dendro filtering has been done
		    if (cgm.params.dendro_filter.row === false && cgm.params.dendro_filter.col === false) {
	
		      var is_crop = d3.select(this).classed('fa-crop');
	
		      var is_undo = d3.select(this).classed('fa-undo');
	
		      // press crop button (can be active/incative)
		      if (is_crop) {
	
		        // keep list of names to return to state
		        cgm.params.crop_filter_nodes = {};
		        cgm.params.crop_filter_nodes.row_nodes = cgm.params.network_data.row_nodes;
		        cgm.params.crop_filter_nodes.col_nodes = cgm.params.network_data.col_nodes;
	
		        cgm.brush_crop_matrix();
	
		        if (d3.select(this).classed('active_cropping') === false) {
	
		          // set active_cropping (button turns red)
		          d3.select(this).classed('active_cropping', true).style('color', 'red');
		        } else {
		          // deactivate cropping (button turns blue)
		          d3.select(this).classed('active_cropping', false).style('color', '#337ab7');
	
		          deactivate_cropping(cgm);
		        }
		      }
	
		      // press undo button
		      if (is_undo) {
	
		        d3.select(params.root + ' .crop_button').style('color', '#337ab7').classed('fa-crop', true).classed('fa-undo', false);
	
		        // cgm.filter_viz_using_names(cgm.params.crop_filter_nodes);
		        cgm.filter_viz_using_nodes(cgm.params.crop_filter_nodes);
	
		        // show dendro crop buttons after brush-cropping has been undone
		        d3.select(cgm.params.root + ' .col_dendro_icons_container').style('display', 'block');
		        d3.select(cgm.params.root + ' .row_dendro_icons_container').style('display', 'block');
		      }
	
		      two_translate_zoom(cgm, 0, 0, 1);
		    }
		  }).classed('sidebar_tooltip', true).append('span').classed('sidebar_tooltip_text', true).html('Crop matrix').style('left', '-400%');
	
		  // save svg: example from: http://bl.ocks.org/pgiraud/8955139#profile.json
		  ////////////////////////////////////////////////////////////////////////////
		  function save_clust_svg() {
	
		    d3.select(params.root + ' .expand_button').style('opacity', 0);
	
		    var html = d3.select(params.root + " .viz_svg").attr("title", "test2").attr("version", 1.1).attr("xmlns", "http://www.w3.org/2000/svg").node().parentNode.innerHTML;
	
		    var blob = new Blob([html], { type: "image/svg+xml" });
	
		    saveAs(blob, "clustergrammer.svg");
	
		    d3.select(params.root + ' .expand_button').style('opacity', 0.4);
		  }
	
		  d3.select(params.root + ' .download_buttons').append('p').append('a').html('Download SVG').on('click', function () {
		    save_clust_svg();
		  });
	
		  var svg_id = 'svg_' + params.root.replace('#', '');
	
		  // save as PNG
		  /////////////////////////////////////////
		  d3.select(params.root + ' .download_buttons').append('p').append('a').html('Download PNG').on('click', function () {
		    d3.select(params.root + ' .expand_button').style('opacity', 0);
		    // saveSvgAsPng(document.getElementById(svg_id), "clustergrammer.png");
		    save_svg_png.saveSvgAsPng(document.getElementById(svg_id), "clustergrammer.png");
		    d3.select(params.root + ' .expand_button').style('opacity', 0.4);
		  });
			};
	
	/***/ }),
	/* 281 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var __WEBPACK_AMD_DEFINE_RESULT__;'use strict';
	
		(function () {
		  var out$ = typeof exports != 'undefined' && exports || "function" != 'undefined' && {} || this;
	
		  var doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [<!ENTITY nbsp "&#160;">]>';
	
		  function isElement(obj) {
		    return obj instanceof HTMLElement || obj instanceof SVGElement;
		  }
	
		  function requireDomNode(el) {
		    if (!isElement(el)) {
		      throw new Error('an HTMLElement or SVGElement is required; got ' + el);
		    }
		  }
	
		  function isExternal(url) {
		    return url && url.lastIndexOf('http', 0) == 0 && url.lastIndexOf(window.location.host) == -1;
		  }
	
		  function inlineImages(el, callback) {
		    requireDomNode(el);
	
		    var images = el.querySelectorAll('image'),
		        left = images.length,
		        checkDone = function checkDone() {
		      if (left === 0) {
		        callback();
		      }
		    };
	
		    checkDone();
		    for (var i = 0; i < images.length; i++) {
		      (function (image) {
		        var href = image.getAttributeNS("http://www.w3.org/1999/xlink", "href");
		        if (href) {
		          if (isExternal(href.value)) {
		            console.warn("Cannot render embedded images linking to external hosts: " + href.value);
		            return;
		          }
		        }
		        var canvas = document.createElement('canvas');
		        var ctx = canvas.getContext('2d');
		        var img = new Image();
		        img.crossOrigin = "anonymous";
		        href = href || image.getAttribute('href');
		        if (href) {
		          img.src = href;
		          img.onload = function () {
		            canvas.width = img.width;
		            canvas.height = img.height;
		            ctx.drawImage(img, 0, 0);
		            image.setAttributeNS("http://www.w3.org/1999/xlink", "href", canvas.toDataURL('image/png'));
		            left--;
		            checkDone();
		          };
		          img.onerror = function () {
		            console.log("Could not load " + href);
		            left--;
		            checkDone();
		          };
		        } else {
		          left--;
		          checkDone();
		        }
		      })(images[i]);
		    }
		  }
	
		  function styles(el, options, cssLoadedCallback) {
		    var selectorRemap = options.selectorRemap;
		    var modifyStyle = options.modifyStyle;
		    var css = "";
		    // each font that has extranl link is saved into queue, and processed
		    // asynchronously
		    var fontsQueue = [];
		    var sheets = document.styleSheets;
		    for (var i = 0; i < sheets.length; i++) {
		      try {
		        var rules = sheets[i].cssRules;
		      } catch (e) {
		        console.warn("Stylesheet could not be loaded: " + sheets[i].href);
		        continue;
		      }
	
		      if (rules != null) {
		        for (var j = 0, match; j < rules.length; j++, match = null) {
		          var rule = rules[j];
		          if (typeof rule.style != "undefined") {
		            var selectorText;
	
		            try {
		              selectorText = rule.selectorText;
		            } catch (err) {
		              console.warn('The following CSS rule has an invalid selector: "' + rule + '"', err);
		            }
	
		            try {
		              if (selectorText) {
		                match = el.querySelector(selectorText) || el.parentNode.querySelector(selectorText);
		              }
		            } catch (err) {
		              console.warn('Invalid CSS selector "' + selectorText + '"', err);
		            }
	
		            if (match) {
		              var selector = selectorRemap ? selectorRemap(rule.selectorText) : rule.selectorText;
		              var cssText = modifyStyle ? modifyStyle(rule.style.cssText) : rule.style.cssText;
		              css += selector + " { " + cssText + " }\n";
		            } else if (rule.cssText.match(/^@font-face/)) {
		              // below we are trying to find matches to external link. E.g.
		              // @font-face {
		              //   // ...
		              //   src: local('Abel'), url(https://fonts.gstatic.com/s/abel/v6/UzN-iejR1VoXU2Oc-7LsbvesZW2xOQ-xsNqO47m55DA.woff2);
		              // }
		              //
		              // This regex will save extrnal link into first capture group
		              var fontUrlRegexp = /url\(["']?(.+?)["']?\)/;
		              // TODO: This needs to be changed to support multiple url declarations per font.
		              var fontUrlMatch = rule.cssText.match(fontUrlRegexp);
	
		              var externalFontUrl = fontUrlMatch && fontUrlMatch[1] || '';
		              var fontUrlIsDataURI = externalFontUrl.match(/^data:/);
		              if (fontUrlIsDataURI) {
		                // We should ignore data uri - they are already embedded
		                externalFontUrl = '';
		              }
	
		              if (externalFontUrl) {
		                // okay, we are lucky. We can fetch this font later
	
		                //handle url if relative
		                if (externalFontUrl.startsWith('../')) {
		                  externalFontUrl = sheets[i].href + '/../' + externalFontUrl;
		                } else if (externalFontUrl.startsWith('./')) {
		                  externalFontUrl = sheets[i].href + '/.' + externalFontUrl;
		                }
	
		                fontsQueue.push({
		                  text: rule.cssText,
		                  // Pass url regex, so that once font is downladed, we can run `replace()` on it
		                  fontUrlRegexp: fontUrlRegexp,
		                  format: getFontMimeTypeFromUrl(externalFontUrl),
		                  url: externalFontUrl
		                });
		              } else {
		                // otherwise, use previous logic
		                css += rule.cssText + '\n';
		              }
		            }
		          }
		        }
		      }
		    }
	
		    // Now all css is processed, it's time to handle scheduled fonts
		    processFontQueue(fontsQueue);
	
		    function getFontMimeTypeFromUrl(fontUrl) {
		      var supportedFormats = {
		        'woff2': 'font/woff2',
		        'woff': 'font/woff',
		        'otf': 'application/x-font-opentype',
		        'ttf': 'application/x-font-ttf',
		        'eot': 'application/vnd.ms-fontobject',
		        'sfnt': 'application/font-sfnt',
		        'svg': 'image/svg+xml'
		      };
		      var extensions = Object.keys(supportedFormats);
		      for (var i = 0; i < extensions.length; ++i) {
		        var extension = extensions[i];
		        // TODO: This is not bullet proof, it needs to handle edge cases...
		        if (fontUrl.indexOf('.' + extension) > 0) {
		          return supportedFormats[extension];
		        }
		      }
	
		      // If you see this error message, you probably need to update code above.
		      console.error('Unknown font format for ' + fontUrl + '; Fonts may not be working correctly');
		      return 'application/octet-stream';
		    }
	
		    function processFontQueue(queue) {
		      if (queue.length > 0) {
		        // load fonts one by one until we have anything in the queue:
		        var font = queue.pop();
		        processNext(font);
		      } else {
		        // no more fonts to load.
		        cssLoadedCallback(css);
		      }
	
		      function processNext(font) {
		        // TODO: This could benefit from caching.
		        var oReq = new XMLHttpRequest();
		        oReq.addEventListener('load', fontLoaded);
		        oReq.addEventListener('error', transferFailed);
		        oReq.addEventListener('abort', transferFailed);
		        oReq.open('GET', font.url);
		        oReq.responseType = 'arraybuffer';
		        oReq.send();
	
		        function fontLoaded() {
		          // TODO: it may be also worth to wait until fonts are fully loaded before
		          // attempting to rasterize them. (e.g. use https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet )
		          var fontBits = oReq.response;
		          var fontInBase64 = arrayBufferToBase64(fontBits);
		          updateFontStyle(font, fontInBase64);
		        }
	
		        function transferFailed(e) {
		          console.warn('Failed to load font from: ' + font.url);
		          console.warn(e);
		          css += font.text + '\n';
		          processFontQueue();
		        }
	
		        function updateFontStyle(font, fontInBase64) {
		          var dataUrl = 'url("data:' + font.format + ';base64,' + fontInBase64 + '")';
		          css += font.text.replace(font.fontUrlRegexp, dataUrl) + '\n';
	
		          // schedule next font download on next tick.
		          setTimeout(function () {
		            processFontQueue(queue);
		          }, 0);
		        }
		      }
		    }
	
		    function arrayBufferToBase64(buffer) {
		      var binary = '';
		      var bytes = new Uint8Array(buffer);
		      var len = bytes.byteLength;
	
		      for (var i = 0; i < len; i++) {
		        binary += String.fromCharCode(bytes[i]);
		      }
	
		      return window.btoa(binary);
		    }
		  }
	
		  function getDimension(el, clone, dim) {
		    var v = el.viewBox && el.viewBox.baseVal && el.viewBox.baseVal[dim] || clone.getAttribute(dim) !== null && !clone.getAttribute(dim).match(/%$/) && parseInt(clone.getAttribute(dim)) || el.getBoundingClientRect()[dim] || parseInt(clone.style[dim]) || parseInt(window.getComputedStyle(el).getPropertyValue(dim));
		    return typeof v === 'undefined' || v === null || isNaN(parseFloat(v)) ? 0 : v;
		  }
	
		  function reEncode(data) {
		    data = encodeURIComponent(data);
		    data = data.replace(/%([0-9A-F]{2})/g, function (match, p1) {
		      var c = String.fromCharCode('0x' + p1);
		      return c === '%' ? '%25' : c;
		    });
		    return decodeURIComponent(data);
		  }
	
		  out$.prepareSvg = function (el, options, cb) {
		    requireDomNode(el);
	
		    options = options || {};
		    options.scale = options.scale || 1;
		    options.responsive = options.responsive || false;
		    var xmlns = "http://www.w3.org/2000/xmlns/";
	
		    inlineImages(el, function () {
		      var outer = document.createElement("div");
		      var clone = el.cloneNode(true);
		      var width, height;
		      if (el.tagName == 'svg') {
		        width = options.width || getDimension(el, clone, 'width');
		        height = options.height || getDimension(el, clone, 'height');
		      } else if (el.getBBox) {
		        var box = el.getBBox();
		        width = box.x + box.width;
		        height = box.y + box.height;
		        clone.setAttribute('transform', clone.getAttribute('transform').replace(/translate\(.*?\)/, ''));
	
		        var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
		        svg.appendChild(clone);
		        clone = svg;
		      } else {
		        console.error('Attempted to render non-SVG element', el);
		        return;
		      }
	
		      clone.setAttribute("version", "1.1");
		      if (!clone.getAttribute('xmlns')) {
		        clone.setAttributeNS(xmlns, "xmlns", "http://www.w3.org/2000/svg");
		      }
		      if (!clone.getAttribute('xmlns:xlink')) {
		        clone.setAttributeNS(xmlns, "xmlns:xlink", "http://www.w3.org/1999/xlink");
		      }
	
		      if (options.responsive) {
		        clone.removeAttribute('width');
		        clone.removeAttribute('height');
		        clone.setAttribute('preserveAspectRatio', 'xMinYMin meet');
		      } else {
		        clone.setAttribute("width", width * options.scale);
		        clone.setAttribute("height", height * options.scale);
		      }
	
		      clone.setAttribute("viewBox", [options.left || 0, options.top || 0, width, height].join(" "));
	
		      var fos = clone.querySelectorAll('foreignObject > *');
		      for (var i = 0; i < fos.length; i++) {
		        if (!fos[i].getAttribute('xmlns')) {
		          fos[i].setAttributeNS(xmlns, "xmlns", "http://www.w3.org/1999/xhtml");
		        }
		      }
	
		      outer.appendChild(clone);
	
		      // In case of custom fonts we need to fetch font first, and then inline
		      // its url into data-uri format (encode as base64). That's why style
		      // processing is done asynchonously. Once all inlining is finshed
		      // cssLoadedCallback() is called.
		      styles(el, options, cssLoadedCallback);
	
		      function cssLoadedCallback(css) {
		        // here all fonts are inlined, so that we can render them properly.
		        var s = document.createElement('style');
		        s.setAttribute('type', 'text/css');
		        s.innerHTML = "<![CDATA[\n" + css + "\n]]>";
		        var defs = document.createElement('defs');
		        defs.appendChild(s);
		        clone.insertBefore(defs, clone.firstChild);
	
		        if (cb) {
		          var outHtml = outer.innerHTML;
		          outHtml = outHtml.replace(/NS\d+:href/gi, 'xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href');
		          cb(outHtml, width, height);
		        }
		      }
		    });
		  };
	
		  out$.svgAsDataUri = function (el, options, cb) {
		    out$.prepareSvg(el, options, function (svg) {
		      var uri = 'data:image/svg+xml;base64,' + window.btoa(reEncode(doctype + svg));
		      if (cb) {
		        cb(uri);
		      }
		    });
		  };
	
		  out$.svgAsPngUri = function (el, options, cb) {
		    requireDomNode(el);
	
		    options = options || {};
		    options.encoderType = options.encoderType || 'image/png';
		    options.encoderOptions = options.encoderOptions || 0.8;
	
		    var convertToPng = function convertToPng(src, w, h) {
		      var canvas = document.createElement('canvas');
		      var context = canvas.getContext('2d');
		      canvas.width = w;
		      canvas.height = h;
	
		      if (options.canvg) {
		        options.canvg(canvas, src);
		      } else {
		        context.drawImage(src, 0, 0);
		      }
	
		      if (options.backgroundColor) {
		        context.globalCompositeOperation = 'destination-over';
		        context.fillStyle = options.backgroundColor;
		        context.fillRect(0, 0, canvas.width, canvas.height);
		      }
	
		      var png;
		      try {
		        png = canvas.toDataURL(options.encoderType, options.encoderOptions);
		      } catch (e) {
		        if (typeof SecurityError !== 'undefined' && e instanceof SecurityError || e.name == "SecurityError") {
		          console.error("Rendered SVG images cannot be downloaded in this browser.");
		          return;
		        } else {
		          throw e;
		        }
		      }
		      cb(png);
		    };
	
		    if (options.canvg) {
		      out$.prepareSvg(el, options, convertToPng);
		    } else {
		      out$.svgAsDataUri(el, options, function (uri) {
		        var image = new Image();
	
		        image.onload = function () {
		          convertToPng(image, image.width, image.height);
		        };
	
		        image.onerror = function () {
		          console.error('There was an error loading the data URI as an image on the following SVG\n', window.atob(uri.slice(26)), '\n', "Open the following link to see browser's diagnosis\n", uri);
		        };
	
		        image.src = uri;
		      });
		    }
		  };
	
		  out$.download = function (name, uri) {
		    if (navigator.msSaveOrOpenBlob) {
		      navigator.msSaveOrOpenBlob(uriToBlob(uri), name);
		    } else {
		      var saveLink = document.createElement('a');
		      var downloadSupported = 'download' in saveLink;
		      if (downloadSupported) {
		        saveLink.download = name;
		        saveLink.style.display = 'none';
		        document.body.appendChild(saveLink);
		        try {
		          var blob = uriToBlob(uri);
		          var url = URL.createObjectURL(blob);
		          saveLink.href = url;
		          saveLink.onclick = function () {
		            requestAnimationFrame(function () {
		              URL.revokeObjectURL(url);
		            });
		          };
		        } catch (e) {
		          console.warn('This browser does not support object URLs. Falling back to string URL.');
		          saveLink.href = uri;
		        }
		        saveLink.click();
		        document.body.removeChild(saveLink);
		      } else {
		        window.open(uri, '_temp', 'menubar=no,toolbar=no,status=no');
		      }
		    }
		  };
	
		  function uriToBlob(uri) {
		    var byteString = window.atob(uri.split(',')[1]);
		    var mimeString = uri.split(',')[0].split(':')[1].split(';')[0];
		    var buffer = new ArrayBuffer(byteString.length);
		    var intArray = new Uint8Array(buffer);
		    for (var i = 0; i < byteString.length; i++) {
		      intArray[i] = byteString.charCodeAt(i);
		    }
		    return new Blob([buffer], { type: mimeString });
		  }
	
		  out$.saveSvg = function (el, name, options) {
		    requireDomNode(el);
	
		    options = options || {};
		    out$.svgAsDataUri(el, options, function (uri) {
		      out$.download(name, uri);
		    });
		  };
	
		  out$.saveSvgAsPng = function (el, name, options) {
		    requireDomNode(el);
	
		    options = options || {};
		    out$.svgAsPngUri(el, options, function (uri) {
		      out$.download(name, uri);
		    });
		  };
	
		  // if define is defined create as an AMD module
		  if (true) {
		    !(__WEBPACK_AMD_DEFINE_RESULT__ = function () {
		      return out$;
		    }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
		  }
			})();
	
	/***/ }),
	/* 282 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var make_modal_skeleton = __webpack_require__(283);
	
		module.exports = function ini_modals(params) {
	
		  // share modal
		  ///////////////////////////////////////
		  var share_modal = make_modal_skeleton(params, 'share_info');
	
		  share_modal.header.append('a').attr('target', '_blank').attr('href', '/clustergrammer/');
	
		  share_modal.header.append('h4').classed('modal-title', true).html('Share the visualization using the current URL:');
	
		  share_modal.body.append('input').classed('bootstrap_highlight', true).classed('share_url', true);
	
		  // picture modal
		  ///////////////////////////////////////
		  var screenshot_modal = make_modal_skeleton(params, 'picture_info');
	
		  screenshot_modal.header.append('h4').classed('modal-title', true).html('Save a snapshot of the visualization');
	
		  screenshot_modal.body.append('div').classed('download_buttons', true);
	
		  // dendro modal
		  ///////////////////////////////////////
		  var dendro_modal = make_modal_skeleton(params, 'dendro_info');
	
		  dendro_modal.header.append('h4').classed('modal-title', true).html('Cluster Information');
	
		  dendro_modal.body.append('g').classed('cluster_info_container', true);
	
		  dendro_modal.body.append('div').classed('dendro_text', true).append('input').classed('bootstrap_highlight', true).classed('current_names', true).style('width', '100%');
			};
	
	/***/ }),
	/* 283 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function make_modal_skeleton(params, modal_class) {
	
		  var modal_skeleton = {};
	
		  var modal = d3.select(params.root).append('div').classed('modal', true).classed('fade', true).classed(modal_class, true).attr('role', 'dialog');
	
		  var modal_dialog = modal.append('div').classed('modal-dialog', true);
	
		  var modal_content = modal_dialog.append('div').classed('modal-content', true);
	
		  modal_skeleton.header = modal_content.append('div').classed('modal-header', true);
	
		  modal_skeleton.header.append('button').attr('type', 'button').classed('close', true).attr('data-dismiss', 'modal').html('&times;');
	
		  modal_skeleton.body = modal_content.append('div').classed('modal-body', true);
	
		  return modal_skeleton;
			};
	
	/***/ }),
	/* 284 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = function set_up_opacity_slider(sidebar) {
	
		  var slider_container = sidebar.append('div').classed('opacity_slider_container', true).style('margin-top', '5px').style('padding-left', '10px').style('padding-right', '10px');
	
		  slider_container.append('div').classed('sidebar_text', true).classed('opacity_slider_text', true).style('margin-bottom', '3px').text('Opacity Slider');
	
		  slider_container.append('div').classed('slider', true).classed('opacity_slider', true);
			};
	
	/***/ }),
	/* 285 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var underscore = __webpack_require__(68);
	
		module.exports = function make_colorbar(cgm) {
	
		  var params = cgm.params;
	
		  d3.select(params.root + ' .sidebar_wrapper').append('div').classed('sidebar_text', true).style('padding-left', '10px').style('padding-top', '5px').text('Matrix Values');
	
		  var colorbar_width = params.sidebar.width - 20;
		  var colorbar_height = 13;
		  var svg_height = 3 * colorbar_height;
		  var svg_width = 1.2 * colorbar_width;
		  var low_left_margin = 10;
		  var top_margin = 33;
		  var high_left_margin = colorbar_width + 10;
		  var bar_margin_left = 10;
		  var bar_margin_top = 3;
	
		  var network_data = params.network_data;
	
		  var max_link = underscore.max(network_data.links, function (d) {
		    return d.value;
		  }).value;
	
		  var min_link = _.min(network_data.links, function (d) {
		    return d.value;
		  }).value;
	
		  var main_svg = d3.select(params.root + ' .sidebar_wrapper').append('svg').attr('height', svg_height + 'px').attr('width', svg_width + 'px');
	
		  //Append a defs (for definition) element to your SVG
		  var defs = main_svg.append("defs");
	
		  //Append a linearGradient element to the defs and give it a unique id
		  var linearGradient = defs.append("linearGradient").attr("id", "linear-gradient");
	
		  var special_case = 'none';
	
		  // no negative numbers
		  if (min_link >= 0) {
	
		    //Set the color for the start (0%)
		    linearGradient.append("stop").attr("offset", "0%").attr("stop-color", "white");
	
		    //Set the color for the end (100%)
		    linearGradient.append("stop").attr("offset", "100%").attr("stop-color", "red");
	
		    special_case = 'all_postiive';
	
		    // no positive numbers
		  } else if (max_link <= 0) {
	
		    //Set the color for the start (0%)
		    linearGradient.append("stop").attr("offset", "0%").attr("stop-color", "blue");
	
		    //Set the color for the end (100%)
		    linearGradient.append("stop").attr("offset", "100%").attr("stop-color", "white");
	
		    special_case = 'all_negative';
		  }
	
		  // both postive and negative numbers
		  else {
		      //Set the color for the start (0%)
		      linearGradient.append("stop").attr("offset", "0%").attr("stop-color", "blue");
	
		      //Set the color for the end (100%)
		      linearGradient.append("stop").attr("offset", "50%").attr("stop-color", "white");
	
		      //Set the color for the end (100%)
		      linearGradient.append("stop").attr("offset", "100%").attr("stop-color", "red");
		    }
	
		  // make colorbar
		  main_svg.append('rect').classed('background', true).attr('height', colorbar_height + 'px').attr('width', colorbar_width + 'px').attr('fill', 'url(#linear-gradient)').attr('transform', 'translate(' + bar_margin_left + ', ' + bar_margin_top + ')').attr('stroke', 'grey').attr('stroke-width', '0.25px');
	
		  // make title
		  ///////////////
	
		  var max_abs_val = Math.abs(Math.round(params.matrix.max_link * 10) / 10);
		  var font_size = 13;
	
		  main_svg.append('text').text(function () {
		    var inst_string;
		    if (special_case === 'all_postiive') {
		      inst_string = 0;
		    } else {
		      inst_string = '-' + max_abs_val.toLocaleString();
		    }
		    return inst_string;
		  }).style('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').style('font-weight', 300).style('font-size', font_size).attr('transform', 'translate(' + low_left_margin + ',' + top_margin + ')').attr('text-anchor', 'start');
	
		  main_svg.append('text').text(max_abs_val.toLocaleString()).text(function () {
		    var inst_string;
		    if (special_case === 'all_negative') {
		      inst_string = 0;
		    } else {
		      inst_string = max_abs_val.toLocaleString();
		    }
		    return inst_string;
		  }).style('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif').style('font-weight', 300).style('font-size', font_size).attr('transform', 'translate(' + high_left_margin + ',' + top_margin + ')').attr('text-anchor', 'end');
			};
	
	/***/ })
	/******/ ]);
	//# sourceMappingURL=clustergrammer.node.js.map

/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {

	/* WEBPACK VAR INJECTION */(function(Buffer) {module.exports =
	/******/ (function(modules) { // webpackBootstrap
	/******/ 	// The module cache
	/******/ 	var installedModules = {};
	
	/******/ 	// The require function
	/******/ 	function __webpack_require__(moduleId) {
	
	/******/ 		// Check if module is in cache
	/******/ 		if(installedModules[moduleId])
	/******/ 			return installedModules[moduleId].exports;
	
	/******/ 		// Create a new module (and put it into the cache)
	/******/ 		var module = installedModules[moduleId] = {
	/******/ 			exports: {},
	/******/ 			id: moduleId,
	/******/ 			loaded: false
	/******/ 		};
	
	/******/ 		// Execute the module function
	/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
	
	/******/ 		// Flag the module as loaded
	/******/ 		module.loaded = true;
	
	/******/ 		// Return the exports of the module
	/******/ 		return module.exports;
	/******/ 	}
	
	
	/******/ 	// expose the modules object (__webpack_modules__)
	/******/ 	__webpack_require__.m = modules;
	
	/******/ 	// expose the module cache
	/******/ 	__webpack_require__.c = installedModules;
	
	/******/ 	// __webpack_public_path__
	/******/ 	__webpack_require__.p = "";
	
	/******/ 	// Load entry module and return exports
	/******/ 	return __webpack_require__(0);
	/******/ })
	/************************************************************************/
	/******/ ([
	/* 0 */
	/***/ (function(module, exports, __webpack_require__) {
	
		/*
	
		  Version 0.1.2
	
		 */
	
		// var filename = 'data/mult_view.json';
	
		// const
		var run_viz = __webpack_require__(1);
	
		// global variables
		// d3 = require('d3');
	
		function Clustergrammer2(args) {
	
		  var network = args.network;
		  var container = args.container;
	
		  run_viz(container, network);
		}
	
		// necessary for exporting function
		module.exports = Clustergrammer2;
	
	/***/ }),
	/* 1 */
	/***/ (function(module, exports, __webpack_require__) {
	
		/* eslint-disable */
	
		var initialize_params = __webpack_require__(2);
		var draw_commands = __webpack_require__(229);
		_ = __webpack_require__(236);
	
		module.exports = function run_viz(container, network) {
	
		  var regl = __webpack_require__(237)({
		    extensions: ['angle_instanced_arrays'],
		    container: container
		  });
	
		  console.log('run_viz loading regl');
		  console.log(network);
	
		  // console.log('****************');
		  // console.log('** initialize **');
		  // console.log('****************');
	
		  // var network = JSON.parse(assets.viz);
	
		  // var tick = 0;
		  // var has_been_both = false;
		  var initialize_viz = true;
	
		  // global params
		  params = initialize_params(regl, network);
	
		  var first_frame = true;
	
		  regl.frame(function () {
	
		    if (params.still_interacting == true || initialize_viz == true) {
	
		      // console.log('frame-animation');
	
		      params.zoom_data.x.total_int = params.zoom_data.x.total_int + 1;
	
		      draw_commands(regl, params);
	
		      setTimeout(function () {
		        params.zoom_data.x.total_int = params.zoom_data.x.total_int - 1;
	
		        // console.log('total_int: ', params.zoom_data.x.total_int);
	
		        if (params.zoom_data.x.total_int == 0 && initialize_viz == false) {
	
		          // preventing from running on first frame
		          if (first_frame == false) {
	
		            console.log('\n------------------\nFINAL INTERACTION');
	
		            // run draw commands
		            draw_commands(regl, params, slow_draw = true);
	
		            // console.log(params.kept_row_y);
		          } else {
		            first_frame = false;
		          }
		        }
		      }, 100);
	
		      // console.log('draw');
		      initialize_viz = false;
		    } else {
	
		      /*
		        Consider setting up something to run background calculations if
		        necessary when the visualization is not being updated. For instance,
		        we could calculate the text triangles of all rows a little at a time
		        in the background.
		      */
	
		    }
		  });
			};
	
	/***/ }),
	/* 2 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var calc_row_and_col_canvas_positions = __webpack_require__(3);
		var calc_row_text_triangles = __webpack_require__(4);
		var calc_col_text_triangles = __webpack_require__(98);
		var calc_viz_dim = __webpack_require__(99);
		var ini_zoom_data = __webpack_require__(101);
		var ini_zoom_restrict = __webpack_require__(102);
		var zoom_rules_high_mat = __webpack_require__(103);
		var make_cameras = __webpack_require__(128);
		var calc_spillover_triangles = __webpack_require__(180);
		var make_matrix_args = __webpack_require__(181);
		var make_viz_aid_tri_args = __webpack_require__(188);
		var make_dendro_args = __webpack_require__(190);
		var make_spillover_args = __webpack_require__(191);
		var calc_viz_area = __webpack_require__(192);
		var calc_row_downsampled_mat = __webpack_require__(193);
	
		/*
		  Working on using subset of math.js for matrix splicing
		*/
		var core = __webpack_require__(194);
		var math = core.create();
	
		math.import(__webpack_require__(207));
	
		// console.log(math)
	
		module.exports = function initialize_params(regl, network) {
	
		  var params = {};
	
		  // use data from network
		  //////////////////////////
		  params.network = network;
	
		  var zoom_function = function (context) {
		    return context.view;
		  };
	
		  params.zoom_function = zoom_function;
		  params.still_interacting = false;
		  params.mat_data = network.mat;
	
		  params.num_row = params.mat_data.length;
		  params.num_col = params.mat_data[0].length;
	
		  // calculate row/col canvas positions
		  params.canvas_pos = calc_row_and_col_canvas_positions(params);
	
		  // calc row-downsampled matrix
		  var run_downsampling = false;
		  params.is_downsampled = false;
		  calc_row_downsampled_mat(params, run_downsampling);
	
		  params.viz_aid_tri_args = {};
		  params.viz_aid_tri_args.row = make_viz_aid_tri_args(regl, params, 'row');
		  params.viz_aid_tri_args.col = make_viz_aid_tri_args(regl, params, 'col');
	
		  params.dendro_args = {};
		  params.dendro_args.row = make_dendro_args(regl, params.num_row, 'row');
		  params.dendro_args.col = make_dendro_args(regl, params.num_col, 'col');
	
		  var spillover_args = {};
	
		  // inst_depth is passed to spillover rects
		  spillover_args.mat_sides = make_spillover_args(regl, zoom_function, 0.5);
		  spillover_args.mat_corners = make_spillover_args(regl, zoom_function, 0.4);
		  spillover_args.label_corners = make_spillover_args(regl, zoom_function, 0.0);
	
		  params.spillover_args = spillover_args;
	
		  params.viz_dim = calc_viz_dim(regl);
	
		  params.zoom_data = ini_zoom_data();
	
		  params.text_zoom = {};
	
		  // text zooming info
		  params.text_zoom.row = {};
		  params.text_zoom.row.scaled_num = params.num_row;
		  params.text_zoom.row.reference = params.text_zoom.row.scaled_num;
		  params.text_zoom.row.factor = 1;
	
		  params.text_zoom.col = {};
		  params.text_zoom.col.scaled_num = params.num_col;
		  params.text_zoom.col.reference = params.text_zoom.col.scaled_num;
		  params.text_zoom.col.factor = 1;
	
		  // font_detail range: min ~12 max ~200
		  ////////////////////////////////////////
		  // usable range: 14-30 (was using 25)
		  params.font_detail = 15;
	
		  calc_viz_area(params);
	
		  params.max_num_text = 75;
	
		  // calculate the text_triangles for all rows
		  // initialize with no row_text_triangles
		  if (params.num_row > params.max_num_text) {
		    params.row_text_triangles = false;
		  } else {
		    params.row_text_triangles = calc_row_text_triangles(params);
		  }
	
		  if (params.num_col > params.max_num_text) {
		    params.col_text_triangles = false;
		  } else {
		    params.col_text_triangles = calc_col_text_triangles(params);
		  }
	
		  // console.log('row_text_triangles in initialize_params')
		  // console.log(params.row_text_triangles)
	
		  params.zoom_restrict = ini_zoom_restrict(params);
	
		  // update zoom_data
		  zoom_rules_high_mat(regl, params);
	
		  params.cameras = make_cameras(regl, params);
	
		  params.spillover_triangles = calc_spillover_triangles(params);
	
		  window.addEventListener('resize', params.cameras.mat.resize);
		  window.addEventListener('resize', params.cameras['row-labels'].resize);
	
		  // generate matrix_args using buffers
		  params.matrix_args = make_matrix_args(regl, params);
	
		  // 1 no zooming allowed, 3 is good value, 10 allows zooming
		  // rc_two_cats: 3
		  // mnist: 7
		  var allow_factor = d3.scale.linear().domain([10, 1000]).range([2, 10]);
	
		  params.allowable_zoom_factor = allow_factor(params.num_col);
	
		  params.text_scale = {};
	
		  return params;
			};
	
	/***/ }),
	/* 3 */
	/***/ (function(module, exports) {
	
		module.exports = function calc_row_and_col_canvas_positions(params) {
	
		  var num_col = params.num_col;
		  var num_row = params.num_row;
	
		  // draw matrix cells
		  /////////////////////////////////////////
		  // set up offset array for buffer
		  var offset = {};
		  offset.x = 0.5;
		  offset.y = 0.5;
	
		  // generate x position array
		  var x_arr = Array(num_col).fill().map(function (_, i) {
		    return i / num_col - offset.x;
		  });
	
		  var y_arr = Array(num_row).fill().map(function (_, i) {
		    return -i / num_row + offset.y - 1 / num_row;
		  });
	
		  var canvas_pos = {};
		  canvas_pos.x_arr = x_arr;
		  canvas_pos.y_arr = y_arr;
	
		  return canvas_pos;
			};
	
	/***/ }),
	/* 4 */
	/***/ (function(module, exports, __webpack_require__) {
	
		const vectorizeText = __webpack_require__(5);
	
		module.exports = function calc_row_text_triangles(params) {
	
		  var inst_nodes = params.network.row_nodes;
		  var num_row = params.num_row;
	
		  var row_height = 1 / num_row;
		  var y_offset_array = [];
		  for (var i = 0; i < num_row; i++) {
		    y_offset_array[i] = 0.5 - row_height / 2 - i * row_height;
		  }
	
		  var vect_text_attrs = {
		    textAlign: 'right',
		    textBaseline: 'middle',
		    triangles: true,
		    size: params.font_detail,
		    font: '"Open Sans", verdana, arial, sans-serif'
		  };
	
		  // draw matrix cells
		  /////////////////////////////////////////
		  var y_arr = params.canvas_pos.y_arr;
	
		  // generating array with row text triangles and y-offsets
		  var row_text_triangles = [];
	
		  var inst_order = 'clust';
	
		  var viz_area = params.viz_area;
		  var kept_row_y = [];
	
		  _.each(inst_nodes, function (inst_node, row_id) {
	
		    var row_order_id = num_row - 1 - params.network.row_nodes[row_id][inst_order];
		    var inst_y = y_arr[row_order_id] + 0.5 / num_row;
	
		    if (inst_y > viz_area.y_min && inst_y < viz_area.y_max) {
		      var inst_name = inst_node.name;
	
		      if (inst_name.indexOf(': ') >= 0) {
		        inst_name = inst_node.name.split(': ')[1];
		      }
	
		      var tmp_text_vect = vectorizeText(inst_name, vect_text_attrs);
		      tmp_text_vect.offset = [0, inst_y];
		      row_text_triangles.push(tmp_text_vect);
		      var inst_data = {};
		      inst_data.y = inst_y;
		      inst_data.name = inst_name;
		      kept_row_y.push(inst_data);
		    }
		  });
	
		  // using to improve row filtering behavior
		  params.kept_row_y = kept_row_y;
	
		  return row_text_triangles;
			};
	
	/***/ }),
	/* 5 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = createText;
	
		var vectorizeText = __webpack_require__(6);
		var defaultCanvas = null;
		var defaultContext = null;
	
		if (typeof document !== 'undefined') {
		  defaultCanvas = document.createElement('canvas');
		  defaultCanvas.width = 8192;
		  defaultCanvas.height = 1024;
		  defaultContext = defaultCanvas.getContext("2d");
		}
	
		function createText(str, options) {
		  if (typeof options !== "object" || options === null) {
		    options = {};
		  }
		  return vectorizeText(str, options.canvas || defaultCanvas, options.context || defaultContext, options);
			}
	
	/***/ }),
	/* 6 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = vectorizeText;
		module.exports.processPixels = processPixels;
	
		var surfaceNets = __webpack_require__(7);
		var ndarray = __webpack_require__(27);
		var simplify = __webpack_require__(30);
		var cleanPSLG = __webpack_require__(40);
		var cdt2d = __webpack_require__(76);
		var toPolygonCrappy = __webpack_require__(83);
	
		function transformPositions(positions, options, size) {
		  var align = options.textAlign || "start";
		  var baseline = options.textBaseline || "alphabetic";
	
		  var lo = [1 << 30, 1 << 30];
		  var hi = [0, 0];
		  var n = positions.length;
		  for (var i = 0; i < n; ++i) {
		    var p = positions[i];
		    for (var j = 0; j < 2; ++j) {
		      lo[j] = Math.min(lo[j], p[j]) | 0;
		      hi[j] = Math.max(hi[j], p[j]) | 0;
		    }
		  }
	
		  var xShift = 0;
		  switch (align) {
		    case "center":
		      xShift = -0.5 * (lo[0] + hi[0]);
		      break;
	
		    case "right":
		    case "end":
		      xShift = -hi[0];
		      break;
	
		    case "left":
		    case "start":
		      xShift = -lo[0];
		      break;
	
		    default:
		      throw new Error("vectorize-text: Unrecognized textAlign: '" + align + "'");
		  }
	
		  var yShift = 0;
		  switch (baseline) {
		    case "hanging":
		    case "top":
		      yShift = -lo[1];
		      break;
	
		    case "middle":
		      yShift = -0.5 * (lo[1] + hi[1]);
		      break;
	
		    case "alphabetic":
		    case "ideographic":
		      yShift = -3 * size;
		      break;
	
		    case "bottom":
		      yShift = -hi[1];
		      break;
	
		    default:
		      throw new Error("vectorize-text: Unrecoginized textBaseline: '" + baseline + "'");
		  }
	
		  var scale = 1.0 / size;
		  if ("lineHeight" in options) {
		    scale *= +options.lineHeight;
		  } else if ("width" in options) {
		    scale = options.width / (hi[0] - lo[0]);
		  } else if ("height" in options) {
		    scale = options.height / (hi[1] - lo[1]);
		  }
	
		  return positions.map(function (p) {
		    return [scale * (p[0] + xShift), scale * (p[1] + yShift)];
		  });
		}
	
		function getPixels(canvas, context, str, size) {
		  var width = Math.ceil(context.measureText(str).width + 2 * size) | 0;
		  if (width > 8192) {
		    throw new Error("vectorize-text: String too long (sorry, this will get fixed later)");
		  }
		  var height = 3 * size;
		  if (canvas.height < height) {
		    canvas.height = height;
		  }
	
		  context.fillStyle = "#000";
		  context.fillRect(0, 0, canvas.width, canvas.height);
	
		  context.fillStyle = "#fff";
		  context.fillText(str, size, 2 * size);
	
		  //Cut pixels from image
		  var pixelData = context.getImageData(0, 0, width, height);
		  var pixels = ndarray(pixelData.data, [height, width, 4]);
	
		  return pixels.pick(-1, -1, 0).transpose(1, 0);
		}
	
		function getContour(pixels, doSimplify) {
		  var contour = surfaceNets(pixels, 128);
		  if (doSimplify) {
		    return simplify(contour.cells, contour.positions, 0.25);
		  }
		  return {
		    edges: contour.cells,
		    positions: contour.positions
		  };
		}
	
		function processPixelsImpl(pixels, options, size, simplify) {
		  //Extract contour
		  var contour = getContour(pixels, simplify);
	
		  //Apply warp to positions
		  var positions = transformPositions(contour.positions, options, size);
		  var edges = contour.edges;
		  var flip = "ccw" === options.orientation;
	
		  //Clean up the PSLG, resolve self intersections, etc.
		  cleanPSLG(positions, edges);
	
		  //If triangulate flag passed, triangulate the result
		  if (options.polygons || options.polygon || options.polyline) {
		    var result = toPolygonCrappy(edges, positions);
		    var nresult = new Array(result.length);
		    for (var i = 0; i < result.length; ++i) {
		      var loops = result[i];
		      var nloops = new Array(loops.length);
		      for (var j = 0; j < loops.length; ++j) {
		        var loop = loops[j];
		        var nloop = new Array(loop.length);
		        for (var k = 0; k < loop.length; ++k) {
		          nloop[k] = positions[loop[k]].slice();
		        }
		        if (flip) {
		          nloop.reverse();
		        }
		        nloops[j] = nloop;
		      }
		      nresult[i] = nloops;
		    }
		    return nresult;
		  } else if (options.triangles || options.triangulate || options.triangle) {
		    return {
		      cells: cdt2d(positions, edges, {
		        delaunay: false,
		        exterior: false,
		        interior: true
		      }),
		      positions: positions
		    };
		  } else {
		    return {
		      edges: edges,
		      positions: positions
		    };
		  }
		}
	
		function processPixels(pixels, options, size) {
		  try {
		    return processPixelsImpl(pixels, options, size, true);
		  } catch (e) {}
		  try {
		    return processPixelsImpl(pixels, options, size, false);
		  } catch (e) {}
		  if (options.polygons || options.polyline || options.polygon) {
		    return [];
		  }
		  if (options.triangles || options.triangulate || options.triangle) {
		    return {
		      cells: [],
		      positions: []
		    };
		  }
		  return {
		    edges: [],
		    positions: []
		  };
		}
	
		function vectorizeText(str, canvas, context, options) {
		  var size = options.size || 64;
		  var family = options.font || "normal";
	
		  context.font = size + "px " + family;
		  context.textAlign = "start";
		  context.textBaseline = "alphabetic";
		  context.direction = "ltr";
	
		  var pixels = getPixels(canvas, context, str, size);
	
		  return processPixels(pixels, options, size);
		}
	
	/***/ }),
	/* 7 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = surfaceNets;
	
		var generateContourExtractor = __webpack_require__(8);
		var triangulateCube = __webpack_require__(16);
		var zeroCrossings = __webpack_require__(21);
	
		function buildSurfaceNets(order, dtype) {
		  var dimension = order.length;
		  var code = ["'use strict';"];
		  var funcName = "surfaceNets" + order.join("_") + "d" + dtype;
	
		  //Contour extraction function
		  code.push("var contour=genContour({", "order:[", order.join(), "],", "scalarArguments: 3,", "phase:function phaseFunc(p,a,b,c) { return (p > c)|0 },");
		  if (dtype === "generic") {
		    code.push("getters:[0],");
		  }
	
		  //Generate vertex function
		  var cubeArgs = [];
		  var extraArgs = [];
		  for (var i = 0; i < dimension; ++i) {
		    cubeArgs.push("d" + i);
		    extraArgs.push("d" + i);
		  }
		  for (var i = 0; i < 1 << dimension; ++i) {
		    cubeArgs.push("v" + i);
		    extraArgs.push("v" + i);
		  }
		  for (var i = 0; i < 1 << dimension; ++i) {
		    cubeArgs.push("p" + i);
		    extraArgs.push("p" + i);
		  }
		  cubeArgs.push("a", "b", "c");
		  extraArgs.push("a", "c");
		  code.push("vertex:function vertexFunc(", cubeArgs.join(), "){");
		  //Mask args together
		  var maskStr = [];
		  for (var i = 0; i < 1 << dimension; ++i) {
		    maskStr.push("(p" + i + "<<" + i + ")");
		  }
		  //Generate variables and giganto switch statement
		  code.push("var m=(", maskStr.join("+"), ")|0;if(m===0||m===", (1 << (1 << dimension)) - 1, "){return}");
		  var extraFuncs = [];
		  var currentFunc = [];
		  if (1 << (1 << dimension) <= 128) {
		    code.push("switch(m){");
		    currentFunc = code;
		  } else {
		    code.push("switch(m>>>7){");
		  }
		  for (var i = 0; i < 1 << (1 << dimension); ++i) {
		    if (1 << (1 << dimension) > 128) {
		      if (i % 128 === 0) {
		        if (extraFuncs.length > 0) {
		          currentFunc.push("}}");
		        }
		        var efName = "vExtra" + extraFuncs.length;
		        code.push("case ", i >>> 7, ":", efName, "(m&0x7f,", extraArgs.join(), ");break;");
		        currentFunc = ["function ", efName, "(m,", extraArgs.join(), "){switch(m){"];
		        extraFuncs.push(currentFunc);
		      }
		    }
		    currentFunc.push("case ", i & 0x7f, ":");
		    var crossings = new Array(dimension);
		    var denoms = new Array(dimension);
		    var crossingCount = new Array(dimension);
		    var bias = new Array(dimension);
		    var totalCrossings = 0;
		    for (var j = 0; j < dimension; ++j) {
		      crossings[j] = [];
		      denoms[j] = [];
		      crossingCount[j] = 0;
		      bias[j] = 0;
		    }
		    for (var j = 0; j < 1 << dimension; ++j) {
		      for (var k = 0; k < dimension; ++k) {
		        var u = j ^ 1 << k;
		        if (u > j) {
		          continue;
		        }
		        if (!(i & 1 << u) !== !(i & 1 << j)) {
		          var sign = 1;
		          if (i & 1 << u) {
		            denoms[k].push("v" + u + "-v" + j);
		          } else {
		            denoms[k].push("v" + j + "-v" + u);
		            sign = -sign;
		          }
		          if (sign < 0) {
		            crossings[k].push("-v" + j + "-v" + u);
		            crossingCount[k] += 2;
		          } else {
		            crossings[k].push("v" + j + "+v" + u);
		            crossingCount[k] -= 2;
		          }
		          totalCrossings += 1;
		          for (var l = 0; l < dimension; ++l) {
		            if (l === k) {
		              continue;
		            }
		            if (u & 1 << l) {
		              bias[l] += 1;
		            } else {
		              bias[l] -= 1;
		            }
		          }
		        }
		      }
		    }
		    var vertexStr = [];
		    for (var k = 0; k < dimension; ++k) {
		      if (crossings[k].length === 0) {
		        vertexStr.push("d" + k + "-0.5");
		      } else {
		        var cStr = "";
		        if (crossingCount[k] < 0) {
		          cStr = crossingCount[k] + "*c";
		        } else if (crossingCount[k] > 0) {
		          cStr = "+" + crossingCount[k] + "*c";
		        }
		        var weight = 0.5 * (crossings[k].length / totalCrossings);
		        var shift = 0.5 + 0.5 * (bias[k] / totalCrossings);
		        vertexStr.push("d" + k + "-" + shift + "-" + weight + "*(" + crossings[k].join("+") + cStr + ")/(" + denoms[k].join("+") + ")");
		      }
		    }
		    currentFunc.push("a.push([", vertexStr.join(), "]);", "break;");
		  }
		  code.push("}},");
		  if (extraFuncs.length > 0) {
		    currentFunc.push("}}");
		  }
	
		  //Create face function
		  var faceArgs = [];
		  for (var i = 0; i < 1 << dimension - 1; ++i) {
		    faceArgs.push("v" + i);
		  }
		  faceArgs.push("c0", "c1", "p0", "p1", "a", "b", "c");
		  code.push("cell:function cellFunc(", faceArgs.join(), "){");
	
		  var facets = triangulateCube(dimension - 1);
		  code.push("if(p0){b.push(", facets.map(function (f) {
		    return "[" + f.map(function (v) {
		      return "v" + v;
		    }) + "]";
		  }).join(), ")}else{b.push(", facets.map(function (f) {
		    var e = f.slice();
		    e.reverse();
		    return "[" + e.map(function (v) {
		      return "v" + v;
		    }) + "]";
		  }).join(), ")}}});function ", funcName, "(array,level){var verts=[],cells=[];contour(array,verts,cells,level);return {positions:verts,cells:cells};} return ", funcName, ";");
	
		  for (var i = 0; i < extraFuncs.length; ++i) {
		    code.push(extraFuncs[i].join(""));
		  }
	
		  //Compile and link
		  var proc = new Function("genContour", code.join(""));
		  return proc(generateContourExtractor);
		}
	
		//1D case: Need to handle specially
		function mesh1D(array, level) {
		  var zc = zeroCrossings(array, level);
		  var n = zc.length;
		  var npos = new Array(n);
		  var ncel = new Array(n);
		  for (var i = 0; i < n; ++i) {
		    npos[i] = [zc[i]];
		    ncel[i] = [i];
		  }
		  return {
		    positions: npos,
		    cells: ncel
		  };
		}
	
		var CACHE = {};
	
		function surfaceNets(array, level) {
		  if (array.dimension <= 0) {
		    return { positions: [], cells: [] };
		  } else if (array.dimension === 1) {
		    return mesh1D(array, level);
		  }
		  var typesig = array.order.join() + "-" + array.dtype;
		  var proc = CACHE[typesig];
		  var level = +level || 0.0;
		  if (!proc) {
		    proc = CACHE[typesig] = buildSurfaceNets(array.order, array.dtype);
		  }
		  return proc(array, level);
		}
	
	/***/ }),
	/* 8 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var pool = __webpack_require__(9);
	
		module.exports = createSurfaceExtractor;
	
		//Helper macros
		function array(i) {
		  return "a" + i;
		}
		function data(i) {
		  return "d" + i;
		}
		function cube(i, bitmask) {
		  return "c" + i + "_" + bitmask;
		}
		function shape(i) {
		  return "s" + i;
		}
		function stride(i, j) {
		  return "t" + i + "_" + j;
		}
		function offset(i) {
		  return "o" + i;
		}
		function scalar(i) {
		  return "x" + i;
		}
		function pointer(i) {
		  return "p" + i;
		}
		function delta(i, bitmask) {
		  return "d" + i + "_" + bitmask;
		}
		function index(i) {
		  return "i" + i;
		}
		function step(i, j) {
		  return "u" + i + "_" + j;
		}
		function pcube(bitmask) {
		  return "b" + bitmask;
		}
		function qcube(bitmask) {
		  return "y" + bitmask;
		}
		function pdelta(bitmask) {
		  return "e" + bitmask;
		}
		function vert(i) {
		  return "v" + i;
		}
		var VERTEX_IDS = "V";
		var PHASES = "P";
		var VERTEX_COUNT = "N";
		var POOL_SIZE = "Q";
		var POINTER = "X";
		var TEMPORARY = "T";
	
		function permBitmask(dimension, mask, order) {
		  var r = 0;
		  for (var i = 0; i < dimension; ++i) {
		    if (mask & 1 << i) {
		      r |= 1 << order[i];
		    }
		  }
		  return r;
		}
	
		//Generates the surface procedure
		function compileSurfaceProcedure(vertexFunc, faceFunc, phaseFunc, scalarArgs, order, typesig) {
		  var arrayArgs = typesig.length;
		  var dimension = order.length;
	
		  if (dimension < 2) {
		    throw new Error("ndarray-extract-contour: Dimension must be at least 2");
		  }
	
		  var funcName = "extractContour" + order.join("_");
		  var code = [];
		  var vars = [];
		  var args = [];
	
		  //Assemble arguments
		  for (var i = 0; i < arrayArgs; ++i) {
		    args.push(array(i));
		  }
		  for (var i = 0; i < scalarArgs; ++i) {
		    args.push(scalar(i));
		  }
	
		  //Shape
		  for (var i = 0; i < dimension; ++i) {
		    vars.push(shape(i) + "=" + array(0) + ".shape[" + i + "]|0");
		  }
		  //Data, stride, offset pointers
		  for (var i = 0; i < arrayArgs; ++i) {
		    vars.push(data(i) + "=" + array(i) + ".data", offset(i) + "=" + array(i) + ".offset|0");
		    for (var j = 0; j < dimension; ++j) {
		      vars.push(stride(i, j) + "=" + array(i) + ".stride[" + j + "]|0");
		    }
		  }
		  //Pointer, delta and cube variables
		  for (var i = 0; i < arrayArgs; ++i) {
		    vars.push(pointer(i) + "=" + offset(i));
		    vars.push(cube(i, 0));
		    for (var j = 1; j < 1 << dimension; ++j) {
		      var ptrStr = [];
		      for (var k = 0; k < dimension; ++k) {
		        if (j & 1 << k) {
		          ptrStr.push("-" + stride(i, k));
		        }
		      }
		      vars.push(delta(i, j) + "=(" + ptrStr.join("") + ")|0");
		      vars.push(cube(i, j) + "=0");
		    }
		  }
		  //Create step variables
		  for (var i = 0; i < arrayArgs; ++i) {
		    for (var j = 0; j < dimension; ++j) {
		      var stepVal = [stride(i, order[j])];
		      if (j > 0) {
		        stepVal.push(stride(i, order[j - 1]) + "*" + shape(order[j - 1]));
		      }
		      vars.push(step(i, order[j]) + "=(" + stepVal.join("-") + ")|0");
		    }
		  }
		  //Create index variables
		  for (var i = 0; i < dimension; ++i) {
		    vars.push(index(i) + "=0");
		  }
		  //Vertex count
		  vars.push(VERTEX_COUNT + "=0");
		  //Compute pool size, initialize pool step
		  var sizeVariable = ["2"];
		  for (var i = dimension - 2; i >= 0; --i) {
		    sizeVariable.push(shape(order[i]));
		  }
		  //Previous phases and vertex_ids
		  vars.push(POOL_SIZE + "=(" + sizeVariable.join("*") + ")|0", PHASES + "=mallocUint32(" + POOL_SIZE + ")", VERTEX_IDS + "=mallocUint32(" + POOL_SIZE + ")", POINTER + "=0");
		  //Create cube variables for phases
		  vars.push(pcube(0) + "=0");
		  for (var j = 1; j < 1 << dimension; ++j) {
		    var cubeDelta = [];
		    var cubeStep = [];
		    for (var k = 0; k < dimension; ++k) {
		      if (j & 1 << k) {
		        if (cubeStep.length === 0) {
		          cubeDelta.push("1");
		        } else {
		          cubeDelta.unshift(cubeStep.join("*"));
		        }
		      }
		      cubeStep.push(shape(order[k]));
		    }
		    var signFlag = "";
		    if (cubeDelta[0].indexOf(shape(order[dimension - 2])) < 0) {
		      signFlag = "-";
		    }
		    var jperm = permBitmask(dimension, j, order);
		    vars.push(pdelta(jperm) + "=(-" + cubeDelta.join("-") + ")|0", qcube(jperm) + "=(" + signFlag + cubeDelta.join("-") + ")|0", pcube(jperm) + "=0");
		  }
		  vars.push(vert(0) + "=0", TEMPORARY + "=0");
	
		  function forLoopBegin(i, start) {
		    code.push("for(", index(order[i]), "=", start, ";", index(order[i]), "<", shape(order[i]), ";", "++", index(order[i]), "){");
		  }
	
		  function forLoopEnd(i) {
		    for (var j = 0; j < arrayArgs; ++j) {
		      code.push(pointer(j), "+=", step(j, order[i]), ";");
		    }
		    code.push("}");
		  }
	
		  function fillEmptySlice(k) {
		    for (var i = k - 1; i >= 0; --i) {
		      forLoopBegin(i, 0);
		    }
		    var phaseFuncArgs = [];
		    for (var i = 0; i < arrayArgs; ++i) {
		      if (typesig[i]) {
		        phaseFuncArgs.push(data(i) + ".get(" + pointer(i) + ")");
		      } else {
		        phaseFuncArgs.push(data(i) + "[" + pointer(i) + "]");
		      }
		    }
		    for (var i = 0; i < scalarArgs; ++i) {
		      phaseFuncArgs.push(scalar(i));
		    }
		    code.push(PHASES, "[", POINTER, "++]=phase(", phaseFuncArgs.join(), ");");
		    for (var i = 0; i < k; ++i) {
		      forLoopEnd(i);
		    }
		    for (var j = 0; j < arrayArgs; ++j) {
		      code.push(pointer(j), "+=", step(j, order[k]), ";");
		    }
		  }
	
		  function processGridCell(mask) {
		    //Read in local data
		    for (var i = 0; i < arrayArgs; ++i) {
		      if (typesig[i]) {
		        code.push(cube(i, 0), "=", data(i), ".get(", pointer(i), ");");
		      } else {
		        code.push(cube(i, 0), "=", data(i), "[", pointer(i), "];");
		      }
		    }
	
		    //Read in phase
		    var phaseFuncArgs = [];
		    for (var i = 0; i < arrayArgs; ++i) {
		      phaseFuncArgs.push(cube(i, 0));
		    }
		    for (var i = 0; i < scalarArgs; ++i) {
		      phaseFuncArgs.push(scalar(i));
		    }
	
		    code.push(pcube(0), "=", PHASES, "[", POINTER, "]=phase(", phaseFuncArgs.join(), ");");
	
		    //Read in other cube data
		    for (var j = 1; j < 1 << dimension; ++j) {
		      code.push(pcube(j), "=", PHASES, "[", POINTER, "+", pdelta(j), "];");
		    }
	
		    //Check for boundary crossing
		    var vertexPredicate = [];
		    for (var j = 1; j < 1 << dimension; ++j) {
		      vertexPredicate.push("(" + pcube(0) + "!==" + pcube(j) + ")");
		    }
		    code.push("if(", vertexPredicate.join("||"), "){");
	
		    //Read in boundary data
		    var vertexArgs = [];
		    for (var i = 0; i < dimension; ++i) {
		      vertexArgs.push(index(i));
		    }
		    for (var i = 0; i < arrayArgs; ++i) {
		      vertexArgs.push(cube(i, 0));
		      for (var j = 1; j < 1 << dimension; ++j) {
		        if (typesig[i]) {
		          code.push(cube(i, j), "=", data(i), ".get(", pointer(i), "+", delta(i, j), ");");
		        } else {
		          code.push(cube(i, j), "=", data(i), "[", pointer(i), "+", delta(i, j), "];");
		        }
		        vertexArgs.push(cube(i, j));
		      }
		    }
		    for (var i = 0; i < 1 << dimension; ++i) {
		      vertexArgs.push(pcube(i));
		    }
		    for (var i = 0; i < scalarArgs; ++i) {
		      vertexArgs.push(scalar(i));
		    }
	
		    //Generate vertex
		    code.push("vertex(", vertexArgs.join(), ");", vert(0), "=", VERTEX_IDS, "[", POINTER, "]=", VERTEX_COUNT, "++;");
	
		    //Check for face crossings
		    var base = (1 << dimension) - 1;
		    var corner = pcube(base);
		    for (var j = 0; j < dimension; ++j) {
		      if ((mask & ~(1 << j)) === 0) {
		        //Check face
		        var subset = base ^ 1 << j;
		        var edge = pcube(subset);
		        var faceArgs = [];
		        for (var k = subset; k > 0; k = k - 1 & subset) {
		          faceArgs.push(VERTEX_IDS + "[" + POINTER + "+" + pdelta(k) + "]");
		        }
		        faceArgs.push(vert(0));
		        for (var k = 0; k < arrayArgs; ++k) {
		          if (j & 1) {
		            faceArgs.push(cube(k, base), cube(k, subset));
		          } else {
		            faceArgs.push(cube(k, subset), cube(k, base));
		          }
		        }
		        if (j & 1) {
		          faceArgs.push(corner, edge);
		        } else {
		          faceArgs.push(edge, corner);
		        }
		        for (var k = 0; k < scalarArgs; ++k) {
		          faceArgs.push(scalar(k));
		        }
		        code.push("if(", corner, "!==", edge, "){", "face(", faceArgs.join(), ")}");
		      }
		    }
	
		    //Increment pointer, close off if statement
		    code.push("}", POINTER, "+=1;");
		  }
	
		  function flip() {
		    for (var j = 1; j < 1 << dimension; ++j) {
		      code.push(TEMPORARY, "=", pdelta(j), ";", pdelta(j), "=", qcube(j), ";", qcube(j), "=", TEMPORARY, ";");
		    }
		  }
	
		  function createLoop(i, mask) {
		    if (i < 0) {
		      processGridCell(mask);
		      return;
		    }
		    fillEmptySlice(i);
		    code.push("if(", shape(order[i]), ">0){", index(order[i]), "=1;");
		    createLoop(i - 1, mask | 1 << order[i]);
	
		    for (var j = 0; j < arrayArgs; ++j) {
		      code.push(pointer(j), "+=", step(j, order[i]), ";");
		    }
		    if (i === dimension - 1) {
		      code.push(POINTER, "=0;");
		      flip();
		    }
		    forLoopBegin(i, 2);
		    createLoop(i - 1, mask);
		    if (i === dimension - 1) {
		      code.push("if(", index(order[dimension - 1]), "&1){", POINTER, "=0;}");
		      flip();
		    }
		    forLoopEnd(i);
		    code.push("}");
		  }
	
		  createLoop(dimension - 1, 0);
	
		  //Release scratch memory
		  code.push("freeUint32(", VERTEX_IDS, ");freeUint32(", PHASES, ");");
	
		  //Compile and link procedure
		  var procedureCode = ["'use strict';", "function ", funcName, "(", args.join(), "){", "var ", vars.join(), ";", code.join(""), "}", "return ", funcName].join("");
	
		  var proc = new Function("vertex", "face", "phase", "mallocUint32", "freeUint32", procedureCode);
		  return proc(vertexFunc, faceFunc, phaseFunc, pool.mallocUint32, pool.freeUint32);
		}
	
		function createSurfaceExtractor(args) {
		  function error(msg) {
		    throw new Error("ndarray-extract-contour: " + msg);
		  }
		  if (typeof args !== "object") {
		    error("Must specify arguments");
		  }
		  var order = args.order;
		  if (!Array.isArray(order)) {
		    error("Must specify order");
		  }
		  var arrays = args.arrayArguments || 1;
		  if (arrays < 1) {
		    error("Must have at least one array argument");
		  }
		  var scalars = args.scalarArguments || 0;
		  if (scalars < 0) {
		    error("Scalar arg count must be > 0");
		  }
		  if (typeof args.vertex !== "function") {
		    error("Must specify vertex creation function");
		  }
		  if (typeof args.cell !== "function") {
		    error("Must specify cell creation function");
		  }
		  if (typeof args.phase !== "function") {
		    error("Must specify phase function");
		  }
		  var getters = args.getters || [];
		  var typesig = new Array(arrays);
		  for (var i = 0; i < arrays; ++i) {
		    if (getters.indexOf(i) >= 0) {
		      typesig[i] = true;
		    } else {
		      typesig[i] = false;
		    }
		  }
		  return compileSurfaceProcedure(args.vertex, args.cell, args.phase, scalars, order, typesig);
			}
	
	/***/ }),
	/* 9 */
	/***/ (function(module, exports, __webpack_require__) {
	
		/* WEBPACK VAR INJECTION */(function(global, Buffer) {'use strict';
	
		var bits = __webpack_require__(14);
		var dup = __webpack_require__(15);
	
		//Legacy pool support
		if (!global.__TYPEDARRAY_POOL) {
		  global.__TYPEDARRAY_POOL = {
		    UINT8: dup([32, 0]),
		    UINT16: dup([32, 0]),
		    UINT32: dup([32, 0]),
		    INT8: dup([32, 0]),
		    INT16: dup([32, 0]),
		    INT32: dup([32, 0]),
		    FLOAT: dup([32, 0]),
		    DOUBLE: dup([32, 0]),
		    DATA: dup([32, 0]),
		    UINT8C: dup([32, 0]),
		    BUFFER: dup([32, 0])
		  };
		}
	
		var hasUint8C = typeof Uint8ClampedArray !== 'undefined';
		var POOL = global.__TYPEDARRAY_POOL;
	
		//Upgrade pool
		if (!POOL.UINT8C) {
		  POOL.UINT8C = dup([32, 0]);
		}
		if (!POOL.BUFFER) {
		  POOL.BUFFER = dup([32, 0]);
		}
	
		//New technique: Only allocate from ArrayBufferView and Buffer
		var DATA = POOL.DATA,
		    BUFFER = POOL.BUFFER;
	
		exports.free = function free(array) {
		  if (Buffer.isBuffer(array)) {
		    BUFFER[bits.log2(array.length)].push(array);
		  } else {
		    if (Object.prototype.toString.call(array) !== '[object ArrayBuffer]') {
		      array = array.buffer;
		    }
		    if (!array) {
		      return;
		    }
		    var n = array.length || array.byteLength;
		    var log_n = bits.log2(n) | 0;
		    DATA[log_n].push(array);
		  }
		};
	
		function freeArrayBuffer(buffer) {
		  if (!buffer) {
		    return;
		  }
		  var n = buffer.length || buffer.byteLength;
		  var log_n = bits.log2(n);
		  DATA[log_n].push(buffer);
		}
	
		function freeTypedArray(array) {
		  freeArrayBuffer(array.buffer);
		}
	
		exports.freeUint8 = exports.freeUint16 = exports.freeUint32 = exports.freeInt8 = exports.freeInt16 = exports.freeInt32 = exports.freeFloat32 = exports.freeFloat = exports.freeFloat64 = exports.freeDouble = exports.freeUint8Clamped = exports.freeDataView = freeTypedArray;
	
		exports.freeArrayBuffer = freeArrayBuffer;
	
		exports.freeBuffer = function freeBuffer(array) {
		  BUFFER[bits.log2(array.length)].push(array);
		};
	
		exports.malloc = function malloc(n, dtype) {
		  if (dtype === undefined || dtype === 'arraybuffer') {
		    return mallocArrayBuffer(n);
		  } else {
		    switch (dtype) {
		      case 'uint8':
		        return mallocUint8(n);
		      case 'uint16':
		        return mallocUint16(n);
		      case 'uint32':
		        return mallocUint32(n);
		      case 'int8':
		        return mallocInt8(n);
		      case 'int16':
		        return mallocInt16(n);
		      case 'int32':
		        return mallocInt32(n);
		      case 'float':
		      case 'float32':
		        return mallocFloat(n);
		      case 'double':
		      case 'float64':
		        return mallocDouble(n);
		      case 'uint8_clamped':
		        return mallocUint8Clamped(n);
		      case 'buffer':
		        return mallocBuffer(n);
		      case 'data':
		      case 'dataview':
		        return mallocDataView(n);
	
		      default:
		        return null;
		    }
		  }
		  return null;
		};
	
		function mallocArrayBuffer(n) {
		  var n = bits.nextPow2(n);
		  var log_n = bits.log2(n);
		  var d = DATA[log_n];
		  if (d.length > 0) {
		    return d.pop();
		  }
		  return new ArrayBuffer(n);
		}
		exports.mallocArrayBuffer = mallocArrayBuffer;
	
		function mallocUint8(n) {
		  return new Uint8Array(mallocArrayBuffer(n), 0, n);
		}
		exports.mallocUint8 = mallocUint8;
	
		function mallocUint16(n) {
		  return new Uint16Array(mallocArrayBuffer(2 * n), 0, n);
		}
		exports.mallocUint16 = mallocUint16;
	
		function mallocUint32(n) {
		  return new Uint32Array(mallocArrayBuffer(4 * n), 0, n);
		}
		exports.mallocUint32 = mallocUint32;
	
		function mallocInt8(n) {
		  return new Int8Array(mallocArrayBuffer(n), 0, n);
		}
		exports.mallocInt8 = mallocInt8;
	
		function mallocInt16(n) {
		  return new Int16Array(mallocArrayBuffer(2 * n), 0, n);
		}
		exports.mallocInt16 = mallocInt16;
	
		function mallocInt32(n) {
		  return new Int32Array(mallocArrayBuffer(4 * n), 0, n);
		}
		exports.mallocInt32 = mallocInt32;
	
		function mallocFloat(n) {
		  return new Float32Array(mallocArrayBuffer(4 * n), 0, n);
		}
		exports.mallocFloat32 = exports.mallocFloat = mallocFloat;
	
		function mallocDouble(n) {
		  return new Float64Array(mallocArrayBuffer(8 * n), 0, n);
		}
		exports.mallocFloat64 = exports.mallocDouble = mallocDouble;
	
		function mallocUint8Clamped(n) {
		  if (hasUint8C) {
		    return new Uint8ClampedArray(mallocArrayBuffer(n), 0, n);
		  } else {
		    return mallocUint8(n);
		  }
		}
		exports.mallocUint8Clamped = mallocUint8Clamped;
	
		function mallocDataView(n) {
		  return new DataView(mallocArrayBuffer(n), 0, n);
		}
		exports.mallocDataView = mallocDataView;
	
		function mallocBuffer(n) {
		  n = bits.nextPow2(n);
		  var log_n = bits.log2(n);
		  var cache = BUFFER[log_n];
		  if (cache.length > 0) {
		    return cache.pop();
		  }
		  return new Buffer(n);
		}
		exports.mallocBuffer = mallocBuffer;
	
		exports.clearCache = function clearCache() {
		  for (var i = 0; i < 32; ++i) {
		    POOL.UINT8[i].length = 0;
		    POOL.UINT16[i].length = 0;
		    POOL.UINT32[i].length = 0;
		    POOL.INT8[i].length = 0;
		    POOL.INT16[i].length = 0;
		    POOL.INT32[i].length = 0;
		    POOL.FLOAT[i].length = 0;
		    POOL.DOUBLE[i].length = 0;
		    POOL.UINT8C[i].length = 0;
		    DATA[i].length = 0;
		    BUFFER[i].length = 0;
		  }
		};
		/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(10).Buffer))
	
	/***/ }),
	/* 10 */
	/***/ (function(module, exports, __webpack_require__) {
	
		/* WEBPACK VAR INJECTION */(function(global) {/*!
		 * The buffer module from node.js, for the browser.
		 *
		 * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
		 * @license  MIT
		 */
		/* eslint-disable no-proto */
	
		'use strict';
	
		var base64 = __webpack_require__(11);
		var ieee754 = __webpack_require__(12);
		var isArray = __webpack_require__(13);
	
		exports.Buffer = Buffer;
		exports.SlowBuffer = SlowBuffer;
		exports.INSPECT_MAX_BYTES = 50;
	
		/**
		 * If `Buffer.TYPED_ARRAY_SUPPORT`:
		 *   === true    Use Uint8Array implementation (fastest)
		 *   === false   Use Object implementation (most compatible, even IE6)
		 *
		 * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
		 * Opera 11.6+, iOS 4.2+.
		 *
		 * Due to various browser bugs, sometimes the Object implementation will be used even
		 * when the browser supports typed arrays.
		 *
		 * Note:
		 *
		 *   - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
		 *     See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
		 *
		 *   - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
		 *
		 *   - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
		 *     incorrect length in some situations.
	
		 * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they
		 * get the Object implementation, which is slower but behaves correctly.
		 */
		Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined ? global.TYPED_ARRAY_SUPPORT : typedArraySupport();
	
		/*
		 * Export kMaxLength after typed array support is determined.
		 */
		exports.kMaxLength = kMaxLength();
	
		function typedArraySupport() {
		  try {
		    var arr = new Uint8Array(1);
		    arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () {
		        return 42;
		      } };
		    return arr.foo() === 42 && // typed array instances can be augmented
		    typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
		    arr.subarray(1, 1).byteLength === 0; // ie10 has broken `subarray`
		  } catch (e) {
		    return false;
		  }
		}
	
		function kMaxLength() {
		  return Buffer.TYPED_ARRAY_SUPPORT ? 0x7fffffff : 0x3fffffff;
		}
	
		function createBuffer(that, length) {
		  if (kMaxLength() < length) {
		    throw new RangeError('Invalid typed array length');
		  }
		  if (Buffer.TYPED_ARRAY_SUPPORT) {
		    // Return an augmented `Uint8Array` instance, for best performance
		    that = new Uint8Array(length);
		    that.__proto__ = Buffer.prototype;
		  } else {
		    // Fallback: Return an object instance of the Buffer class
		    if (that === null) {
		      that = new Buffer(length);
		    }
		    that.length = length;
		  }
	
		  return that;
		}
	
		/**
		 * The Buffer constructor returns instances of `Uint8Array` that have their
		 * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
		 * `Uint8Array`, so the returned instances will have all the node `Buffer` methods
		 * and the `Uint8Array` methods. Square bracket notation works as expected -- it
		 * returns a single octet.
		 *
		 * The `Uint8Array` prototype remains unmodified.
		 */
	
		function Buffer(arg, encodingOrOffset, length) {
		  if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {
		    return new Buffer(arg, encodingOrOffset, length);
		  }
	
		  // Common case.
		  if (typeof arg === 'number') {
		    if (typeof encodingOrOffset === 'string') {
		      throw new Error('If encoding is specified then the first argument must be a string');
		    }
		    return allocUnsafe(this, arg);
		  }
		  return from(this, arg, encodingOrOffset, length);
		}
	
		Buffer.poolSize = 8192; // not used by this implementation
	
		// TODO: Legacy, not needed anymore. Remove in next major version.
		Buffer._augment = function (arr) {
		  arr.__proto__ = Buffer.prototype;
		  return arr;
		};
	
		function from(that, value, encodingOrOffset, length) {
		  if (typeof value === 'number') {
		    throw new TypeError('"value" argument must not be a number');
		  }
	
		  if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
		    return fromArrayBuffer(that, value, encodingOrOffset, length);
		  }
	
		  if (typeof value === 'string') {
		    return fromString(that, value, encodingOrOffset);
		  }
	
		  return fromObject(that, value);
		}
	
		/**
		 * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
		 * if value is a number.
		 * Buffer.from(str[, encoding])
		 * Buffer.from(array)
		 * Buffer.from(buffer)
		 * Buffer.from(arrayBuffer[, byteOffset[, length]])
		 **/
		Buffer.from = function (value, encodingOrOffset, length) {
		  return from(null, value, encodingOrOffset, length);
		};
	
		if (Buffer.TYPED_ARRAY_SUPPORT) {
		  Buffer.prototype.__proto__ = Uint8Array.prototype;
		  Buffer.__proto__ = Uint8Array;
		  if (typeof Symbol !== 'undefined' && Symbol.species && Buffer[Symbol.species] === Buffer) {
		    // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
		    Object.defineProperty(Buffer, Symbol.species, {
		      value: null,
		      configurable: true
		    });
		  }
		}
	
		function assertSize(size) {
		  if (typeof size !== 'number') {
		    throw new TypeError('"size" argument must be a number');
		  } else if (size < 0) {
		    throw new RangeError('"size" argument must not be negative');
		  }
		}
	
		function alloc(that, size, fill, encoding) {
		  assertSize(size);
		  if (size <= 0) {
		    return createBuffer(that, size);
		  }
		  if (fill !== undefined) {
		    // Only pay attention to encoding if it's a string. This
		    // prevents accidentally sending in a number that would
		    // be interpretted as a start offset.
		    return typeof encoding === 'string' ? createBuffer(that, size).fill(fill, encoding) : createBuffer(that, size).fill(fill);
		  }
		  return createBuffer(that, size);
		}
	
		/**
		 * Creates a new filled Buffer instance.
		 * alloc(size[, fill[, encoding]])
		 **/
		Buffer.alloc = function (size, fill, encoding) {
		  return alloc(null, size, fill, encoding);
		};
	
		function allocUnsafe(that, size) {
		  assertSize(size);
		  that = createBuffer(that, size < 0 ? 0 : checked(size) | 0);
		  if (!Buffer.TYPED_ARRAY_SUPPORT) {
		    for (var i = 0; i < size; ++i) {
		      that[i] = 0;
		    }
		  }
		  return that;
		}
	
		/**
		 * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
		 * */
		Buffer.allocUnsafe = function (size) {
		  return allocUnsafe(null, size);
		};
		/**
		 * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
		 */
		Buffer.allocUnsafeSlow = function (size) {
		  return allocUnsafe(null, size);
		};
	
		function fromString(that, string, encoding) {
		  if (typeof encoding !== 'string' || encoding === '') {
		    encoding = 'utf8';
		  }
	
		  if (!Buffer.isEncoding(encoding)) {
		    throw new TypeError('"encoding" must be a valid string encoding');
		  }
	
		  var length = byteLength(string, encoding) | 0;
		  that = createBuffer(that, length);
	
		  var actual = that.write(string, encoding);
	
		  if (actual !== length) {
		    // Writing a hex string, for example, that contains invalid characters will
		    // cause everything after the first invalid character to be ignored. (e.g.
		    // 'abxxcd' will be treated as 'ab')
		    that = that.slice(0, actual);
		  }
	
		  return that;
		}
	
		function fromArrayLike(that, array) {
		  var length = array.length < 0 ? 0 : checked(array.length) | 0;
		  that = createBuffer(that, length);
		  for (var i = 0; i < length; i += 1) {
		    that[i] = array[i] & 255;
		  }
		  return that;
		}
	
		function fromArrayBuffer(that, array, byteOffset, length) {
		  array.byteLength; // this throws if `array` is not a valid ArrayBuffer
	
		  if (byteOffset < 0 || array.byteLength < byteOffset) {
		    throw new RangeError('\'offset\' is out of bounds');
		  }
	
		  if (array.byteLength < byteOffset + (length || 0)) {
		    throw new RangeError('\'length\' is out of bounds');
		  }
	
		  if (byteOffset === undefined && length === undefined) {
		    array = new Uint8Array(array);
		  } else if (length === undefined) {
		    array = new Uint8Array(array, byteOffset);
		  } else {
		    array = new Uint8Array(array, byteOffset, length);
		  }
	
		  if (Buffer.TYPED_ARRAY_SUPPORT) {
		    // Return an augmented `Uint8Array` instance, for best performance
		    that = array;
		    that.__proto__ = Buffer.prototype;
		  } else {
		    // Fallback: Return an object instance of the Buffer class
		    that = fromArrayLike(that, array);
		  }
		  return that;
		}
	
		function fromObject(that, obj) {
		  if (Buffer.isBuffer(obj)) {
		    var len = checked(obj.length) | 0;
		    that = createBuffer(that, len);
	
		    if (that.length === 0) {
		      return that;
		    }
	
		    obj.copy(that, 0, 0, len);
		    return that;
		  }
	
		  if (obj) {
		    if (typeof ArrayBuffer !== 'undefined' && obj.buffer instanceof ArrayBuffer || 'length' in obj) {
		      if (typeof obj.length !== 'number' || isnan(obj.length)) {
		        return createBuffer(that, 0);
		      }
		      return fromArrayLike(that, obj);
		    }
	
		    if (obj.type === 'Buffer' && isArray(obj.data)) {
		      return fromArrayLike(that, obj.data);
		    }
		  }
	
		  throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.');
		}
	
		function checked(length) {
		  // Note: cannot use `length < kMaxLength()` here because that fails when
		  // length is NaN (which is otherwise coerced to zero.)
		  if (length >= kMaxLength()) {
		    throw new RangeError('Attempt to allocate Buffer larger than maximum ' + 'size: 0x' + kMaxLength().toString(16) + ' bytes');
		  }
		  return length | 0;
		}
	
		function SlowBuffer(length) {
		  if (+length != length) {
		    // eslint-disable-line eqeqeq
		    length = 0;
		  }
		  return Buffer.alloc(+length);
		}
	
		Buffer.isBuffer = function isBuffer(b) {
		  return !!(b != null && b._isBuffer);
		};
	
		Buffer.compare = function compare(a, b) {
		  if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
		    throw new TypeError('Arguments must be Buffers');
		  }
	
		  if (a === b) return 0;
	
		  var x = a.length;
		  var y = b.length;
	
		  for (var i = 0, len = Math.min(x, y); i < len; ++i) {
		    if (a[i] !== b[i]) {
		      x = a[i];
		      y = b[i];
		      break;
		    }
		  }
	
		  if (x < y) return -1;
		  if (y < x) return 1;
		  return 0;
		};
	
		Buffer.isEncoding = function isEncoding(encoding) {
		  switch (String(encoding).toLowerCase()) {
		    case 'hex':
		    case 'utf8':
		    case 'utf-8':
		    case 'ascii':
		    case 'latin1':
		    case 'binary':
		    case 'base64':
		    case 'ucs2':
		    case 'ucs-2':
		    case 'utf16le':
		    case 'utf-16le':
		      return true;
		    default:
		      return false;
		  }
		};
	
		Buffer.concat = function concat(list, length) {
		  if (!isArray(list)) {
		    throw new TypeError('"list" argument must be an Array of Buffers');
		  }
	
		  if (list.length === 0) {
		    return Buffer.alloc(0);
		  }
	
		  var i;
		  if (length === undefined) {
		    length = 0;
		    for (i = 0; i < list.length; ++i) {
		      length += list[i].length;
		    }
		  }
	
		  var buffer = Buffer.allocUnsafe(length);
		  var pos = 0;
		  for (i = 0; i < list.length; ++i) {
		    var buf = list[i];
		    if (!Buffer.isBuffer(buf)) {
		      throw new TypeError('"list" argument must be an Array of Buffers');
		    }
		    buf.copy(buffer, pos);
		    pos += buf.length;
		  }
		  return buffer;
		};
	
		function byteLength(string, encoding) {
		  if (Buffer.isBuffer(string)) {
		    return string.length;
		  }
		  if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {
		    return string.byteLength;
		  }
		  if (typeof string !== 'string') {
		    string = '' + string;
		  }
	
		  var len = string.length;
		  if (len === 0) return 0;
	
		  // Use a for loop to avoid recursion
		  var loweredCase = false;
		  for (;;) {
		    switch (encoding) {
		      case 'ascii':
		      case 'latin1':
		      case 'binary':
		        return len;
		      case 'utf8':
		      case 'utf-8':
		      case undefined:
		        return utf8ToBytes(string).length;
		      case 'ucs2':
		      case 'ucs-2':
		      case 'utf16le':
		      case 'utf-16le':
		        return len * 2;
		      case 'hex':
		        return len >>> 1;
		      case 'base64':
		        return base64ToBytes(string).length;
		      default:
		        if (loweredCase) return utf8ToBytes(string).length; // assume utf8
		        encoding = ('' + encoding).toLowerCase();
		        loweredCase = true;
		    }
		  }
		}
		Buffer.byteLength = byteLength;
	
		function slowToString(encoding, start, end) {
		  var loweredCase = false;
	
		  // No need to verify that "this.length <= MAX_UINT32" since it's a read-only
		  // property of a typed array.
	
		  // This behaves neither like String nor Uint8Array in that we set start/end
		  // to their upper/lower bounds if the value passed is out of range.
		  // undefined is handled specially as per ECMA-262 6th Edition,
		  // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
		  if (start === undefined || start < 0) {
		    start = 0;
		  }
		  // Return early if start > this.length. Done here to prevent potential uint32
		  // coercion fail below.
		  if (start > this.length) {
		    return '';
		  }
	
		  if (end === undefined || end > this.length) {
		    end = this.length;
		  }
	
		  if (end <= 0) {
		    return '';
		  }
	
		  // Force coersion to uint32. This will also coerce falsey/NaN values to 0.
		  end >>>= 0;
		  start >>>= 0;
	
		  if (end <= start) {
		    return '';
		  }
	
		  if (!encoding) encoding = 'utf8';
	
		  while (true) {
		    switch (encoding) {
		      case 'hex':
		        return hexSlice(this, start, end);
	
		      case 'utf8':
		      case 'utf-8':
		        return utf8Slice(this, start, end);
	
		      case 'ascii':
		        return asciiSlice(this, start, end);
	
		      case 'latin1':
		      case 'binary':
		        return latin1Slice(this, start, end);
	
		      case 'base64':
		        return base64Slice(this, start, end);
	
		      case 'ucs2':
		      case 'ucs-2':
		      case 'utf16le':
		      case 'utf-16le':
		        return utf16leSlice(this, start, end);
	
		      default:
		        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding);
		        encoding = (encoding + '').toLowerCase();
		        loweredCase = true;
		    }
		  }
		}
	
		// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect
		// Buffer instances.
		Buffer.prototype._isBuffer = true;
	
		function swap(b, n, m) {
		  var i = b[n];
		  b[n] = b[m];
		  b[m] = i;
		}
	
		Buffer.prototype.swap16 = function swap16() {
		  var len = this.length;
		  if (len % 2 !== 0) {
		    throw new RangeError('Buffer size must be a multiple of 16-bits');
		  }
		  for (var i = 0; i < len; i += 2) {
		    swap(this, i, i + 1);
		  }
		  return this;
		};
	
		Buffer.prototype.swap32 = function swap32() {
		  var len = this.length;
		  if (len % 4 !== 0) {
		    throw new RangeError('Buffer size must be a multiple of 32-bits');
		  }
		  for (var i = 0; i < len; i += 4) {
		    swap(this, i, i + 3);
		    swap(this, i + 1, i + 2);
		  }
		  return this;
		};
	
		Buffer.prototype.swap64 = function swap64() {
		  var len = this.length;
		  if (len % 8 !== 0) {
		    throw new RangeError('Buffer size must be a multiple of 64-bits');
		  }
		  for (var i = 0; i < len; i += 8) {
		    swap(this, i, i + 7);
		    swap(this, i + 1, i + 6);
		    swap(this, i + 2, i + 5);
		    swap(this, i + 3, i + 4);
		  }
		  return this;
		};
	
		Buffer.prototype.toString = function toString() {
		  var length = this.length | 0;
		  if (length === 0) return '';
		  if (arguments.length === 0) return utf8Slice(this, 0, length);
		  return slowToString.apply(this, arguments);
		};
	
		Buffer.prototype.equals = function equals(b) {
		  if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer');
		  if (this === b) return true;
		  return Buffer.compare(this, b) === 0;
		};
	
		Buffer.prototype.inspect = function inspect() {
		  var str = '';
		  var max = exports.INSPECT_MAX_BYTES;
		  if (this.length > 0) {
		    str = this.toString('hex', 0, max).match(/.{2}/g).join(' ');
		    if (this.length > max) str += ' ... ';
		  }
		  return '<Buffer ' + str + '>';
		};
	
		Buffer.prototype.compare = function compare(target, start, end, thisStart, thisEnd) {
		  if (!Buffer.isBuffer(target)) {
		    throw new TypeError('Argument must be a Buffer');
		  }
	
		  if (start === undefined) {
		    start = 0;
		  }
		  if (end === undefined) {
		    end = target ? target.length : 0;
		  }
		  if (thisStart === undefined) {
		    thisStart = 0;
		  }
		  if (thisEnd === undefined) {
		    thisEnd = this.length;
		  }
	
		  if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
		    throw new RangeError('out of range index');
		  }
	
		  if (thisStart >= thisEnd && start >= end) {
		    return 0;
		  }
		  if (thisStart >= thisEnd) {
		    return -1;
		  }
		  if (start >= end) {
		    return 1;
		  }
	
		  start >>>= 0;
		  end >>>= 0;
		  thisStart >>>= 0;
		  thisEnd >>>= 0;
	
		  if (this === target) return 0;
	
		  var x = thisEnd - thisStart;
		  var y = end - start;
		  var len = Math.min(x, y);
	
		  var thisCopy = this.slice(thisStart, thisEnd);
		  var targetCopy = target.slice(start, end);
	
		  for (var i = 0; i < len; ++i) {
		    if (thisCopy[i] !== targetCopy[i]) {
		      x = thisCopy[i];
		      y = targetCopy[i];
		      break;
		    }
		  }
	
		  if (x < y) return -1;
		  if (y < x) return 1;
		  return 0;
		};
	
		// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
		// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
		//
		// Arguments:
		// - buffer - a Buffer to search
		// - val - a string, Buffer, or number
		// - byteOffset - an index into `buffer`; will be clamped to an int32
		// - encoding - an optional encoding, relevant is val is a string
		// - dir - true for indexOf, false for lastIndexOf
		function bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) {
		  // Empty buffer means no match
		  if (buffer.length === 0) return -1;
	
		  // Normalize byteOffset
		  if (typeof byteOffset === 'string') {
		    encoding = byteOffset;
		    byteOffset = 0;
		  } else if (byteOffset > 0x7fffffff) {
		    byteOffset = 0x7fffffff;
		  } else if (byteOffset < -0x80000000) {
		    byteOffset = -0x80000000;
		  }
		  byteOffset = +byteOffset; // Coerce to Number.
		  if (isNaN(byteOffset)) {
		    // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
		    byteOffset = dir ? 0 : buffer.length - 1;
		  }
	
		  // Normalize byteOffset: negative offsets start from the end of the buffer
		  if (byteOffset < 0) byteOffset = buffer.length + byteOffset;
		  if (byteOffset >= buffer.length) {
		    if (dir) return -1;else byteOffset = buffer.length - 1;
		  } else if (byteOffset < 0) {
		    if (dir) byteOffset = 0;else return -1;
		  }
	
		  // Normalize val
		  if (typeof val === 'string') {
		    val = Buffer.from(val, encoding);
		  }
	
		  // Finally, search either indexOf (if dir is true) or lastIndexOf
		  if (Buffer.isBuffer(val)) {
		    // Special case: looking for empty string/buffer always fails
		    if (val.length === 0) {
		      return -1;
		    }
		    return arrayIndexOf(buffer, val, byteOffset, encoding, dir);
		  } else if (typeof val === 'number') {
		    val = val & 0xFF; // Search for a byte value [0-255]
		    if (Buffer.TYPED_ARRAY_SUPPORT && typeof Uint8Array.prototype.indexOf === 'function') {
		      if (dir) {
		        return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset);
		      } else {
		        return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset);
		      }
		    }
		    return arrayIndexOf(buffer, [val], byteOffset, encoding, dir);
		  }
	
		  throw new TypeError('val must be string, number or Buffer');
		}
	
		function arrayIndexOf(arr, val, byteOffset, encoding, dir) {
		  var indexSize = 1;
		  var arrLength = arr.length;
		  var valLength = val.length;
	
		  if (encoding !== undefined) {
		    encoding = String(encoding).toLowerCase();
		    if (encoding === 'ucs2' || encoding === 'ucs-2' || encoding === 'utf16le' || encoding === 'utf-16le') {
		      if (arr.length < 2 || val.length < 2) {
		        return -1;
		      }
		      indexSize = 2;
		      arrLength /= 2;
		      valLength /= 2;
		      byteOffset /= 2;
		    }
		  }
	
		  function read(buf, i) {
		    if (indexSize === 1) {
		      return buf[i];
		    } else {
		      return buf.readUInt16BE(i * indexSize);
		    }
		  }
	
		  var i;
		  if (dir) {
		    var foundIndex = -1;
		    for (i = byteOffset; i < arrLength; i++) {
		      if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
		        if (foundIndex === -1) foundIndex = i;
		        if (i - foundIndex + 1 === valLength) return foundIndex * indexSize;
		      } else {
		        if (foundIndex !== -1) i -= i - foundIndex;
		        foundIndex = -1;
		      }
		    }
		  } else {
		    if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength;
		    for (i = byteOffset; i >= 0; i--) {
		      var found = true;
		      for (var j = 0; j < valLength; j++) {
		        if (read(arr, i + j) !== read(val, j)) {
		          found = false;
		          break;
		        }
		      }
		      if (found) return i;
		    }
		  }
	
		  return -1;
		}
	
		Buffer.prototype.includes = function includes(val, byteOffset, encoding) {
		  return this.indexOf(val, byteOffset, encoding) !== -1;
		};
	
		Buffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) {
		  return bidirectionalIndexOf(this, val, byteOffset, encoding, true);
		};
	
		Buffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) {
		  return bidirectionalIndexOf(this, val, byteOffset, encoding, false);
		};
	
		function hexWrite(buf, string, offset, length) {
		  offset = Number(offset) || 0;
		  var remaining = buf.length - offset;
		  if (!length) {
		    length = remaining;
		  } else {
		    length = Number(length);
		    if (length > remaining) {
		      length = remaining;
		    }
		  }
	
		  // must be an even number of digits
		  var strLen = string.length;
		  if (strLen % 2 !== 0) throw new TypeError('Invalid hex string');
	
		  if (length > strLen / 2) {
		    length = strLen / 2;
		  }
		  for (var i = 0; i < length; ++i) {
		    var parsed = parseInt(string.substr(i * 2, 2), 16);
		    if (isNaN(parsed)) return i;
		    buf[offset + i] = parsed;
		  }
		  return i;
		}
	
		function utf8Write(buf, string, offset, length) {
		  return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length);
		}
	
		function asciiWrite(buf, string, offset, length) {
		  return blitBuffer(asciiToBytes(string), buf, offset, length);
		}
	
		function latin1Write(buf, string, offset, length) {
		  return asciiWrite(buf, string, offset, length);
		}
	
		function base64Write(buf, string, offset, length) {
		  return blitBuffer(base64ToBytes(string), buf, offset, length);
		}
	
		function ucs2Write(buf, string, offset, length) {
		  return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length);
		}
	
		Buffer.prototype.write = function write(string, offset, length, encoding) {
		  // Buffer#write(string)
		  if (offset === undefined) {
		    encoding = 'utf8';
		    length = this.length;
		    offset = 0;
		    // Buffer#write(string, encoding)
		  } else if (length === undefined && typeof offset === 'string') {
		    encoding = offset;
		    length = this.length;
		    offset = 0;
		    // Buffer#write(string, offset[, length][, encoding])
		  } else if (isFinite(offset)) {
		    offset = offset | 0;
		    if (isFinite(length)) {
		      length = length | 0;
		      if (encoding === undefined) encoding = 'utf8';
		    } else {
		      encoding = length;
		      length = undefined;
		    }
		    // legacy write(string, encoding, offset, length) - remove in v0.13
		  } else {
		    throw new Error('Buffer.write(string, encoding, offset[, length]) is no longer supported');
		  }
	
		  var remaining = this.length - offset;
		  if (length === undefined || length > remaining) length = remaining;
	
		  if (string.length > 0 && (length < 0 || offset < 0) || offset > this.length) {
		    throw new RangeError('Attempt to write outside buffer bounds');
		  }
	
		  if (!encoding) encoding = 'utf8';
	
		  var loweredCase = false;
		  for (;;) {
		    switch (encoding) {
		      case 'hex':
		        return hexWrite(this, string, offset, length);
	
		      case 'utf8':
		      case 'utf-8':
		        return utf8Write(this, string, offset, length);
	
		      case 'ascii':
		        return asciiWrite(this, string, offset, length);
	
		      case 'latin1':
		      case 'binary':
		        return latin1Write(this, string, offset, length);
	
		      case 'base64':
		        // Warning: maxLength not taken into account in base64Write
		        return base64Write(this, string, offset, length);
	
		      case 'ucs2':
		      case 'ucs-2':
		      case 'utf16le':
		      case 'utf-16le':
		        return ucs2Write(this, string, offset, length);
	
		      default:
		        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding);
		        encoding = ('' + encoding).toLowerCase();
		        loweredCase = true;
		    }
		  }
		};
	
		Buffer.prototype.toJSON = function toJSON() {
		  return {
		    type: 'Buffer',
		    data: Array.prototype.slice.call(this._arr || this, 0)
		  };
		};
	
		function base64Slice(buf, start, end) {
		  if (start === 0 && end === buf.length) {
		    return base64.fromByteArray(buf);
		  } else {
		    return base64.fromByteArray(buf.slice(start, end));
		  }
		}
	
		function utf8Slice(buf, start, end) {
		  end = Math.min(buf.length, end);
		  var res = [];
	
		  var i = start;
		  while (i < end) {
		    var firstByte = buf[i];
		    var codePoint = null;
		    var bytesPerSequence = firstByte > 0xEF ? 4 : firstByte > 0xDF ? 3 : firstByte > 0xBF ? 2 : 1;
	
		    if (i + bytesPerSequence <= end) {
		      var secondByte, thirdByte, fourthByte, tempCodePoint;
	
		      switch (bytesPerSequence) {
		        case 1:
		          if (firstByte < 0x80) {
		            codePoint = firstByte;
		          }
		          break;
		        case 2:
		          secondByte = buf[i + 1];
		          if ((secondByte & 0xC0) === 0x80) {
		            tempCodePoint = (firstByte & 0x1F) << 0x6 | secondByte & 0x3F;
		            if (tempCodePoint > 0x7F) {
		              codePoint = tempCodePoint;
		            }
		          }
		          break;
		        case 3:
		          secondByte = buf[i + 1];
		          thirdByte = buf[i + 2];
		          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
		            tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | thirdByte & 0x3F;
		            if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
		              codePoint = tempCodePoint;
		            }
		          }
		          break;
		        case 4:
		          secondByte = buf[i + 1];
		          thirdByte = buf[i + 2];
		          fourthByte = buf[i + 3];
		          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
		            tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | fourthByte & 0x3F;
		            if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
		              codePoint = tempCodePoint;
		            }
		          }
		      }
		    }
	
		    if (codePoint === null) {
		      // we did not generate a valid codePoint so insert a
		      // replacement char (U+FFFD) and advance only 1 byte
		      codePoint = 0xFFFD;
		      bytesPerSequence = 1;
		    } else if (codePoint > 0xFFFF) {
		      // encode to utf16 (surrogate pair dance)
		      codePoint -= 0x10000;
		      res.push(codePoint >>> 10 & 0x3FF | 0xD800);
		      codePoint = 0xDC00 | codePoint & 0x3FF;
		    }
	
		    res.push(codePoint);
		    i += bytesPerSequence;
		  }
	
		  return decodeCodePointsArray(res);
		}
	
		// Based on http://stackoverflow.com/a/22747272/680742, the browser with
		// the lowest limit is Chrome, with 0x10000 args.
		// We go 1 magnitude less, for safety
		var MAX_ARGUMENTS_LENGTH = 0x1000;
	
		function decodeCodePointsArray(codePoints) {
		  var len = codePoints.length;
		  if (len <= MAX_ARGUMENTS_LENGTH) {
		    return String.fromCharCode.apply(String, codePoints); // avoid extra slice()
		  }
	
		  // Decode in chunks to avoid "call stack size exceeded".
		  var res = '';
		  var i = 0;
		  while (i < len) {
		    res += String.fromCharCode.apply(String, codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH));
		  }
		  return res;
		}
	
		function asciiSlice(buf, start, end) {
		  var ret = '';
		  end = Math.min(buf.length, end);
	
		  for (var i = start; i < end; ++i) {
		    ret += String.fromCharCode(buf[i] & 0x7F);
		  }
		  return ret;
		}
	
		function latin1Slice(buf, start, end) {
		  var ret = '';
		  end = Math.min(buf.length, end);
	
		  for (var i = start; i < end; ++i) {
		    ret += String.fromCharCode(buf[i]);
		  }
		  return ret;
		}
	
		function hexSlice(buf, start, end) {
		  var len = buf.length;
	
		  if (!start || start < 0) start = 0;
		  if (!end || end < 0 || end > len) end = len;
	
		  var out = '';
		  for (var i = start; i < end; ++i) {
		    out += toHex(buf[i]);
		  }
		  return out;
		}
	
		function utf16leSlice(buf, start, end) {
		  var bytes = buf.slice(start, end);
		  var res = '';
		  for (var i = 0; i < bytes.length; i += 2) {
		    res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256);
		  }
		  return res;
		}
	
		Buffer.prototype.slice = function slice(start, end) {
		  var len = this.length;
		  start = ~~start;
		  end = end === undefined ? len : ~~end;
	
		  if (start < 0) {
		    start += len;
		    if (start < 0) start = 0;
		  } else if (start > len) {
		    start = len;
		  }
	
		  if (end < 0) {
		    end += len;
		    if (end < 0) end = 0;
		  } else if (end > len) {
		    end = len;
		  }
	
		  if (end < start) end = start;
	
		  var newBuf;
		  if (Buffer.TYPED_ARRAY_SUPPORT) {
		    newBuf = this.subarray(start, end);
		    newBuf.__proto__ = Buffer.prototype;
		  } else {
		    var sliceLen = end - start;
		    newBuf = new Buffer(sliceLen, undefined);
		    for (var i = 0; i < sliceLen; ++i) {
		      newBuf[i] = this[i + start];
		    }
		  }
	
		  return newBuf;
		};
	
		/*
		 * Need to make sure that buffer isn't trying to write out of bounds.
		 */
		function checkOffset(offset, ext, length) {
		  if (offset % 1 !== 0 || offset < 0) throw new RangeError('offset is not uint');
		  if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length');
		}
	
		Buffer.prototype.readUIntLE = function readUIntLE(offset, byteLength, noAssert) {
		  offset = offset | 0;
		  byteLength = byteLength | 0;
		  if (!noAssert) checkOffset(offset, byteLength, this.length);
	
		  var val = this[offset];
		  var mul = 1;
		  var i = 0;
		  while (++i < byteLength && (mul *= 0x100)) {
		    val += this[offset + i] * mul;
		  }
	
		  return val;
		};
	
		Buffer.prototype.readUIntBE = function readUIntBE(offset, byteLength, noAssert) {
		  offset = offset | 0;
		  byteLength = byteLength | 0;
		  if (!noAssert) {
		    checkOffset(offset, byteLength, this.length);
		  }
	
		  var val = this[offset + --byteLength];
		  var mul = 1;
		  while (byteLength > 0 && (mul *= 0x100)) {
		    val += this[offset + --byteLength] * mul;
		  }
	
		  return val;
		};
	
		Buffer.prototype.readUInt8 = function readUInt8(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 1, this.length);
		  return this[offset];
		};
	
		Buffer.prototype.readUInt16LE = function readUInt16LE(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 2, this.length);
		  return this[offset] | this[offset + 1] << 8;
		};
	
		Buffer.prototype.readUInt16BE = function readUInt16BE(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 2, this.length);
		  return this[offset] << 8 | this[offset + 1];
		};
	
		Buffer.prototype.readUInt32LE = function readUInt32LE(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 4, this.length);
	
		  return (this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16) + this[offset + 3] * 0x1000000;
		};
	
		Buffer.prototype.readUInt32BE = function readUInt32BE(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 4, this.length);
	
		  return this[offset] * 0x1000000 + (this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3]);
		};
	
		Buffer.prototype.readIntLE = function readIntLE(offset, byteLength, noAssert) {
		  offset = offset | 0;
		  byteLength = byteLength | 0;
		  if (!noAssert) checkOffset(offset, byteLength, this.length);
	
		  var val = this[offset];
		  var mul = 1;
		  var i = 0;
		  while (++i < byteLength && (mul *= 0x100)) {
		    val += this[offset + i] * mul;
		  }
		  mul *= 0x80;
	
		  if (val >= mul) val -= Math.pow(2, 8 * byteLength);
	
		  return val;
		};
	
		Buffer.prototype.readIntBE = function readIntBE(offset, byteLength, noAssert) {
		  offset = offset | 0;
		  byteLength = byteLength | 0;
		  if (!noAssert) checkOffset(offset, byteLength, this.length);
	
		  var i = byteLength;
		  var mul = 1;
		  var val = this[offset + --i];
		  while (i > 0 && (mul *= 0x100)) {
		    val += this[offset + --i] * mul;
		  }
		  mul *= 0x80;
	
		  if (val >= mul) val -= Math.pow(2, 8 * byteLength);
	
		  return val;
		};
	
		Buffer.prototype.readInt8 = function readInt8(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 1, this.length);
		  if (!(this[offset] & 0x80)) return this[offset];
		  return (0xff - this[offset] + 1) * -1;
		};
	
		Buffer.prototype.readInt16LE = function readInt16LE(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 2, this.length);
		  var val = this[offset] | this[offset + 1] << 8;
		  return val & 0x8000 ? val | 0xFFFF0000 : val;
		};
	
		Buffer.prototype.readInt16BE = function readInt16BE(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 2, this.length);
		  var val = this[offset + 1] | this[offset] << 8;
		  return val & 0x8000 ? val | 0xFFFF0000 : val;
		};
	
		Buffer.prototype.readInt32LE = function readInt32LE(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 4, this.length);
	
		  return this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16 | this[offset + 3] << 24;
		};
	
		Buffer.prototype.readInt32BE = function readInt32BE(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 4, this.length);
	
		  return this[offset] << 24 | this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3];
		};
	
		Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 4, this.length);
		  return ieee754.read(this, offset, true, 23, 4);
		};
	
		Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 4, this.length);
		  return ieee754.read(this, offset, false, 23, 4);
		};
	
		Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 8, this.length);
		  return ieee754.read(this, offset, true, 52, 8);
		};
	
		Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) {
		  if (!noAssert) checkOffset(offset, 8, this.length);
		  return ieee754.read(this, offset, false, 52, 8);
		};
	
		function checkInt(buf, value, offset, ext, max, min) {
		  if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance');
		  if (value > max || value < min) throw new RangeError('"value" argument is out of bounds');
		  if (offset + ext > buf.length) throw new RangeError('Index out of range');
		}
	
		Buffer.prototype.writeUIntLE = function writeUIntLE(value, offset, byteLength, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  byteLength = byteLength | 0;
		  if (!noAssert) {
		    var maxBytes = Math.pow(2, 8 * byteLength) - 1;
		    checkInt(this, value, offset, byteLength, maxBytes, 0);
		  }
	
		  var mul = 1;
		  var i = 0;
		  this[offset] = value & 0xFF;
		  while (++i < byteLength && (mul *= 0x100)) {
		    this[offset + i] = value / mul & 0xFF;
		  }
	
		  return offset + byteLength;
		};
	
		Buffer.prototype.writeUIntBE = function writeUIntBE(value, offset, byteLength, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  byteLength = byteLength | 0;
		  if (!noAssert) {
		    var maxBytes = Math.pow(2, 8 * byteLength) - 1;
		    checkInt(this, value, offset, byteLength, maxBytes, 0);
		  }
	
		  var i = byteLength - 1;
		  var mul = 1;
		  this[offset + i] = value & 0xFF;
		  while (--i >= 0 && (mul *= 0x100)) {
		    this[offset + i] = value / mul & 0xFF;
		  }
	
		  return offset + byteLength;
		};
	
		Buffer.prototype.writeUInt8 = function writeUInt8(value, offset, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0);
		  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value);
		  this[offset] = value & 0xff;
		  return offset + 1;
		};
	
		function objectWriteUInt16(buf, value, offset, littleEndian) {
		  if (value < 0) value = 0xffff + value + 1;
		  for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {
		    buf[offset + i] = (value & 0xff << 8 * (littleEndian ? i : 1 - i)) >>> (littleEndian ? i : 1 - i) * 8;
		  }
		}
	
		Buffer.prototype.writeUInt16LE = function writeUInt16LE(value, offset, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0);
		  if (Buffer.TYPED_ARRAY_SUPPORT) {
		    this[offset] = value & 0xff;
		    this[offset + 1] = value >>> 8;
		  } else {
		    objectWriteUInt16(this, value, offset, true);
		  }
		  return offset + 2;
		};
	
		Buffer.prototype.writeUInt16BE = function writeUInt16BE(value, offset, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0);
		  if (Buffer.TYPED_ARRAY_SUPPORT) {
		    this[offset] = value >>> 8;
		    this[offset + 1] = value & 0xff;
		  } else {
		    objectWriteUInt16(this, value, offset, false);
		  }
		  return offset + 2;
		};
	
		function objectWriteUInt32(buf, value, offset, littleEndian) {
		  if (value < 0) value = 0xffffffff + value + 1;
		  for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {
		    buf[offset + i] = value >>> (littleEndian ? i : 3 - i) * 8 & 0xff;
		  }
		}
	
		Buffer.prototype.writeUInt32LE = function writeUInt32LE(value, offset, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0);
		  if (Buffer.TYPED_ARRAY_SUPPORT) {
		    this[offset + 3] = value >>> 24;
		    this[offset + 2] = value >>> 16;
		    this[offset + 1] = value >>> 8;
		    this[offset] = value & 0xff;
		  } else {
		    objectWriteUInt32(this, value, offset, true);
		  }
		  return offset + 4;
		};
	
		Buffer.prototype.writeUInt32BE = function writeUInt32BE(value, offset, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0);
		  if (Buffer.TYPED_ARRAY_SUPPORT) {
		    this[offset] = value >>> 24;
		    this[offset + 1] = value >>> 16;
		    this[offset + 2] = value >>> 8;
		    this[offset + 3] = value & 0xff;
		  } else {
		    objectWriteUInt32(this, value, offset, false);
		  }
		  return offset + 4;
		};
	
		Buffer.prototype.writeIntLE = function writeIntLE(value, offset, byteLength, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  if (!noAssert) {
		    var limit = Math.pow(2, 8 * byteLength - 1);
	
		    checkInt(this, value, offset, byteLength, limit - 1, -limit);
		  }
	
		  var i = 0;
		  var mul = 1;
		  var sub = 0;
		  this[offset] = value & 0xFF;
		  while (++i < byteLength && (mul *= 0x100)) {
		    if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
		      sub = 1;
		    }
		    this[offset + i] = (value / mul >> 0) - sub & 0xFF;
		  }
	
		  return offset + byteLength;
		};
	
		Buffer.prototype.writeIntBE = function writeIntBE(value, offset, byteLength, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  if (!noAssert) {
		    var limit = Math.pow(2, 8 * byteLength - 1);
	
		    checkInt(this, value, offset, byteLength, limit - 1, -limit);
		  }
	
		  var i = byteLength - 1;
		  var mul = 1;
		  var sub = 0;
		  this[offset + i] = value & 0xFF;
		  while (--i >= 0 && (mul *= 0x100)) {
		    if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
		      sub = 1;
		    }
		    this[offset + i] = (value / mul >> 0) - sub & 0xFF;
		  }
	
		  return offset + byteLength;
		};
	
		Buffer.prototype.writeInt8 = function writeInt8(value, offset, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80);
		  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value);
		  if (value < 0) value = 0xff + value + 1;
		  this[offset] = value & 0xff;
		  return offset + 1;
		};
	
		Buffer.prototype.writeInt16LE = function writeInt16LE(value, offset, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);
		  if (Buffer.TYPED_ARRAY_SUPPORT) {
		    this[offset] = value & 0xff;
		    this[offset + 1] = value >>> 8;
		  } else {
		    objectWriteUInt16(this, value, offset, true);
		  }
		  return offset + 2;
		};
	
		Buffer.prototype.writeInt16BE = function writeInt16BE(value, offset, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);
		  if (Buffer.TYPED_ARRAY_SUPPORT) {
		    this[offset] = value >>> 8;
		    this[offset + 1] = value & 0xff;
		  } else {
		    objectWriteUInt16(this, value, offset, false);
		  }
		  return offset + 2;
		};
	
		Buffer.prototype.writeInt32LE = function writeInt32LE(value, offset, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
		  if (Buffer.TYPED_ARRAY_SUPPORT) {
		    this[offset] = value & 0xff;
		    this[offset + 1] = value >>> 8;
		    this[offset + 2] = value >>> 16;
		    this[offset + 3] = value >>> 24;
		  } else {
		    objectWriteUInt32(this, value, offset, true);
		  }
		  return offset + 4;
		};
	
		Buffer.prototype.writeInt32BE = function writeInt32BE(value, offset, noAssert) {
		  value = +value;
		  offset = offset | 0;
		  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
		  if (value < 0) value = 0xffffffff + value + 1;
		  if (Buffer.TYPED_ARRAY_SUPPORT) {
		    this[offset] = value >>> 24;
		    this[offset + 1] = value >>> 16;
		    this[offset + 2] = value >>> 8;
		    this[offset + 3] = value & 0xff;
		  } else {
		    objectWriteUInt32(this, value, offset, false);
		  }
		  return offset + 4;
		};
	
		function checkIEEE754(buf, value, offset, ext, max, min) {
		  if (offset + ext > buf.length) throw new RangeError('Index out of range');
		  if (offset < 0) throw new RangeError('Index out of range');
		}
	
		function writeFloat(buf, value, offset, littleEndian, noAssert) {
		  if (!noAssert) {
		    checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38);
		  }
		  ieee754.write(buf, value, offset, littleEndian, 23, 4);
		  return offset + 4;
		}
	
		Buffer.prototype.writeFloatLE = function writeFloatLE(value, offset, noAssert) {
		  return writeFloat(this, value, offset, true, noAssert);
		};
	
		Buffer.prototype.writeFloatBE = function writeFloatBE(value, offset, noAssert) {
		  return writeFloat(this, value, offset, false, noAssert);
		};
	
		function writeDouble(buf, value, offset, littleEndian, noAssert) {
		  if (!noAssert) {
		    checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308);
		  }
		  ieee754.write(buf, value, offset, littleEndian, 52, 8);
		  return offset + 8;
		}
	
		Buffer.prototype.writeDoubleLE = function writeDoubleLE(value, offset, noAssert) {
		  return writeDouble(this, value, offset, true, noAssert);
		};
	
		Buffer.prototype.writeDoubleBE = function writeDoubleBE(value, offset, noAssert) {
		  return writeDouble(this, value, offset, false, noAssert);
		};
	
		// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
		Buffer.prototype.copy = function copy(target, targetStart, start, end) {
		  if (!start) start = 0;
		  if (!end && end !== 0) end = this.length;
		  if (targetStart >= target.length) targetStart = target.length;
		  if (!targetStart) targetStart = 0;
		  if (end > 0 && end < start) end = start;
	
		  // Copy 0 bytes; we're done
		  if (end === start) return 0;
		  if (target.length === 0 || this.length === 0) return 0;
	
		  // Fatal error conditions
		  if (targetStart < 0) {
		    throw new RangeError('targetStart out of bounds');
		  }
		  if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds');
		  if (end < 0) throw new RangeError('sourceEnd out of bounds');
	
		  // Are we oob?
		  if (end > this.length) end = this.length;
		  if (target.length - targetStart < end - start) {
		    end = target.length - targetStart + start;
		  }
	
		  var len = end - start;
		  var i;
	
		  if (this === target && start < targetStart && targetStart < end) {
		    // descending copy from end
		    for (i = len - 1; i >= 0; --i) {
		      target[i + targetStart] = this[i + start];
		    }
		  } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
		    // ascending copy from start
		    for (i = 0; i < len; ++i) {
		      target[i + targetStart] = this[i + start];
		    }
		  } else {
		    Uint8Array.prototype.set.call(target, this.subarray(start, start + len), targetStart);
		  }
	
		  return len;
		};
	
		// Usage:
		//    buffer.fill(number[, offset[, end]])
		//    buffer.fill(buffer[, offset[, end]])
		//    buffer.fill(string[, offset[, end]][, encoding])
		Buffer.prototype.fill = function fill(val, start, end, encoding) {
		  // Handle string cases:
		  if (typeof val === 'string') {
		    if (typeof start === 'string') {
		      encoding = start;
		      start = 0;
		      end = this.length;
		    } else if (typeof end === 'string') {
		      encoding = end;
		      end = this.length;
		    }
		    if (val.length === 1) {
		      var code = val.charCodeAt(0);
		      if (code < 256) {
		        val = code;
		      }
		    }
		    if (encoding !== undefined && typeof encoding !== 'string') {
		      throw new TypeError('encoding must be a string');
		    }
		    if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
		      throw new TypeError('Unknown encoding: ' + encoding);
		    }
		  } else if (typeof val === 'number') {
		    val = val & 255;
		  }
	
		  // Invalid ranges are not set to a default, so can range check early.
		  if (start < 0 || this.length < start || this.length < end) {
		    throw new RangeError('Out of range index');
		  }
	
		  if (end <= start) {
		    return this;
		  }
	
		  start = start >>> 0;
		  end = end === undefined ? this.length : end >>> 0;
	
		  if (!val) val = 0;
	
		  var i;
		  if (typeof val === 'number') {
		    for (i = start; i < end; ++i) {
		      this[i] = val;
		    }
		  } else {
		    var bytes = Buffer.isBuffer(val) ? val : utf8ToBytes(new Buffer(val, encoding).toString());
		    var len = bytes.length;
		    for (i = 0; i < end - start; ++i) {
		      this[i + start] = bytes[i % len];
		    }
		  }
	
		  return this;
		};
	
		// HELPER FUNCTIONS
		// ================
	
		var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g;
	
		function base64clean(str) {
		  // Node strips out invalid characters like \n and \t from the string, base64-js does not
		  str = stringtrim(str).replace(INVALID_BASE64_RE, '');
		  // Node converts strings with length < 2 to ''
		  if (str.length < 2) return '';
		  // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
		  while (str.length % 4 !== 0) {
		    str = str + '=';
		  }
		  return str;
		}
	
		function stringtrim(str) {
		  if (str.trim) return str.trim();
		  return str.replace(/^\s+|\s+$/g, '');
		}
	
		function toHex(n) {
		  if (n < 16) return '0' + n.toString(16);
		  return n.toString(16);
		}
	
		function utf8ToBytes(string, units) {
		  units = units || Infinity;
		  var codePoint;
		  var length = string.length;
		  var leadSurrogate = null;
		  var bytes = [];
	
		  for (var i = 0; i < length; ++i) {
		    codePoint = string.charCodeAt(i);
	
		    // is surrogate component
		    if (codePoint > 0xD7FF && codePoint < 0xE000) {
		      // last char was a lead
		      if (!leadSurrogate) {
		        // no lead yet
		        if (codePoint > 0xDBFF) {
		          // unexpected trail
		          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
		          continue;
		        } else if (i + 1 === length) {
		          // unpaired lead
		          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
		          continue;
		        }
	
		        // valid lead
		        leadSurrogate = codePoint;
	
		        continue;
		      }
	
		      // 2 leads in a row
		      if (codePoint < 0xDC00) {
		        if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
		        leadSurrogate = codePoint;
		        continue;
		      }
	
		      // valid surrogate pair
		      codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000;
		    } else if (leadSurrogate) {
		      // valid bmp char, but last char was a lead
		      if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
		    }
	
		    leadSurrogate = null;
	
		    // encode utf8
		    if (codePoint < 0x80) {
		      if ((units -= 1) < 0) break;
		      bytes.push(codePoint);
		    } else if (codePoint < 0x800) {
		      if ((units -= 2) < 0) break;
		      bytes.push(codePoint >> 0x6 | 0xC0, codePoint & 0x3F | 0x80);
		    } else if (codePoint < 0x10000) {
		      if ((units -= 3) < 0) break;
		      bytes.push(codePoint >> 0xC | 0xE0, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80);
		    } else if (codePoint < 0x110000) {
		      if ((units -= 4) < 0) break;
		      bytes.push(codePoint >> 0x12 | 0xF0, codePoint >> 0xC & 0x3F | 0x80, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80);
		    } else {
		      throw new Error('Invalid code point');
		    }
		  }
	
		  return bytes;
		}
	
		function asciiToBytes(str) {
		  var byteArray = [];
		  for (var i = 0; i < str.length; ++i) {
		    // Node's code seems to be doing this and not & 0x7F..
		    byteArray.push(str.charCodeAt(i) & 0xFF);
		  }
		  return byteArray;
		}
	
		function utf16leToBytes(str, units) {
		  var c, hi, lo;
		  var byteArray = [];
		  for (var i = 0; i < str.length; ++i) {
		    if ((units -= 2) < 0) break;
	
		    c = str.charCodeAt(i);
		    hi = c >> 8;
		    lo = c % 256;
		    byteArray.push(lo);
		    byteArray.push(hi);
		  }
	
		  return byteArray;
		}
	
		function base64ToBytes(str) {
		  return base64.toByteArray(base64clean(str));
		}
	
		function blitBuffer(src, dst, offset, length) {
		  for (var i = 0; i < length; ++i) {
		    if (i + offset >= dst.length || i >= src.length) break;
		    dst[i + offset] = src[i];
		  }
		  return i;
		}
	
		function isnan(val) {
		  return val !== val; // eslint-disable-line no-self-compare
		}
		/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
	
	/***/ }),
	/* 11 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		exports.byteLength = byteLength;
		exports.toByteArray = toByteArray;
		exports.fromByteArray = fromByteArray;
	
		var lookup = [];
		var revLookup = [];
		var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array;
	
		var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
		for (var i = 0, len = code.length; i < len; ++i) {
		  lookup[i] = code[i];
		  revLookup[code.charCodeAt(i)] = i;
		}
	
		revLookup['-'.charCodeAt(0)] = 62;
		revLookup['_'.charCodeAt(0)] = 63;
	
		function placeHoldersCount(b64) {
		  var len = b64.length;
		  if (len % 4 > 0) {
		    throw new Error('Invalid string. Length must be a multiple of 4');
		  }
	
		  // the number of equal signs (place holders)
		  // if there are two placeholders, than the two characters before it
		  // represent one byte
		  // if there is only one, then the three characters before it represent 2 bytes
		  // this is just a cheap hack to not do indexOf twice
		  return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0;
		}
	
		function byteLength(b64) {
		  // base64 is 4/3 + up to two characters of the original data
		  return b64.length * 3 / 4 - placeHoldersCount(b64);
		}
	
		function toByteArray(b64) {
		  var i, l, tmp, placeHolders, arr;
		  var len = b64.length;
		  placeHolders = placeHoldersCount(b64);
	
		  arr = new Arr(len * 3 / 4 - placeHolders);
	
		  // if there are placeholders, only get up to the last complete 4 chars
		  l = placeHolders > 0 ? len - 4 : len;
	
		  var L = 0;
	
		  for (i = 0; i < l; i += 4) {
		    tmp = revLookup[b64.charCodeAt(i)] << 18 | revLookup[b64.charCodeAt(i + 1)] << 12 | revLookup[b64.charCodeAt(i + 2)] << 6 | revLookup[b64.charCodeAt(i + 3)];
		    arr[L++] = tmp >> 16 & 0xFF;
		    arr[L++] = tmp >> 8 & 0xFF;
		    arr[L++] = tmp & 0xFF;
		  }
	
		  if (placeHolders === 2) {
		    tmp = revLookup[b64.charCodeAt(i)] << 2 | revLookup[b64.charCodeAt(i + 1)] >> 4;
		    arr[L++] = tmp & 0xFF;
		  } else if (placeHolders === 1) {
		    tmp = revLookup[b64.charCodeAt(i)] << 10 | revLookup[b64.charCodeAt(i + 1)] << 4 | revLookup[b64.charCodeAt(i + 2)] >> 2;
		    arr[L++] = tmp >> 8 & 0xFF;
		    arr[L++] = tmp & 0xFF;
		  }
	
		  return arr;
		}
	
		function tripletToBase64(num) {
		  return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];
		}
	
		function encodeChunk(uint8, start, end) {
		  var tmp;
		  var output = [];
		  for (var i = start; i < end; i += 3) {
		    tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + uint8[i + 2];
		    output.push(tripletToBase64(tmp));
		  }
		  return output.join('');
		}
	
		function fromByteArray(uint8) {
		  var tmp;
		  var len = uint8.length;
		  var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
		  var output = '';
		  var parts = [];
		  var maxChunkLength = 16383; // must be multiple of 3
	
		  // go through the array every three bytes, we'll deal with trailing stuff later
		  for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
		    parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength));
		  }
	
		  // pad the end with zeros, but make sure to not forget the extra bytes
		  if (extraBytes === 1) {
		    tmp = uint8[len - 1];
		    output += lookup[tmp >> 2];
		    output += lookup[tmp << 4 & 0x3F];
		    output += '==';
		  } else if (extraBytes === 2) {
		    tmp = (uint8[len - 2] << 8) + uint8[len - 1];
		    output += lookup[tmp >> 10];
		    output += lookup[tmp >> 4 & 0x3F];
		    output += lookup[tmp << 2 & 0x3F];
		    output += '=';
		  }
	
		  parts.push(output);
	
		  return parts.join('');
		}
	
	/***/ }),
	/* 12 */
	/***/ (function(module, exports) {
	
		exports.read = function (buffer, offset, isLE, mLen, nBytes) {
		  var e, m;
		  var eLen = nBytes * 8 - mLen - 1;
		  var eMax = (1 << eLen) - 1;
		  var eBias = eMax >> 1;
		  var nBits = -7;
		  var i = isLE ? nBytes - 1 : 0;
		  var d = isLE ? -1 : 1;
		  var s = buffer[offset + i];
	
		  i += d;
	
		  e = s & (1 << -nBits) - 1;
		  s >>= -nBits;
		  nBits += eLen;
		  for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
	
		  m = e & (1 << -nBits) - 1;
		  e >>= -nBits;
		  nBits += mLen;
		  for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
	
		  if (e === 0) {
		    e = 1 - eBias;
		  } else if (e === eMax) {
		    return m ? NaN : (s ? -1 : 1) * Infinity;
		  } else {
		    m = m + Math.pow(2, mLen);
		    e = e - eBias;
		  }
		  return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
		};
	
		exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
		  var e, m, c;
		  var eLen = nBytes * 8 - mLen - 1;
		  var eMax = (1 << eLen) - 1;
		  var eBias = eMax >> 1;
		  var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
		  var i = isLE ? 0 : nBytes - 1;
		  var d = isLE ? 1 : -1;
		  var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;
	
		  value = Math.abs(value);
	
		  if (isNaN(value) || value === Infinity) {
		    m = isNaN(value) ? 1 : 0;
		    e = eMax;
		  } else {
		    e = Math.floor(Math.log(value) / Math.LN2);
		    if (value * (c = Math.pow(2, -e)) < 1) {
		      e--;
		      c *= 2;
		    }
		    if (e + eBias >= 1) {
		      value += rt / c;
		    } else {
		      value += rt * Math.pow(2, 1 - eBias);
		    }
		    if (value * c >= 2) {
		      e++;
		      c /= 2;
		    }
	
		    if (e + eBias >= eMax) {
		      m = 0;
		      e = eMax;
		    } else if (e + eBias >= 1) {
		      m = (value * c - 1) * Math.pow(2, mLen);
		      e = e + eBias;
		    } else {
		      m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
		      e = 0;
		    }
		  }
	
		  for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
	
		  e = e << mLen | m;
		  eLen += mLen;
		  for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
	
		  buffer[offset + i - d] |= s * 128;
		};
	
	/***/ }),
	/* 13 */
	/***/ (function(module, exports) {
	
		var toString = {}.toString;
	
		module.exports = Array.isArray || function (arr) {
		  return toString.call(arr) == '[object Array]';
		};
	
	/***/ }),
	/* 14 */
	/***/ (function(module, exports) {
	
		/**
		 * Bit twiddling hacks for JavaScript.
		 *
		 * Author: Mikola Lysenko
		 *
		 * Ported from Stanford bit twiddling hack library:
		 *    http://graphics.stanford.edu/~seander/bithacks.html
		 */
	
		"use strict";"use restrict";
	
		//Number of bits in an integer
	
		var INT_BITS = 32;
	
		//Constants
		exports.INT_BITS = INT_BITS;
		exports.INT_MAX = 0x7fffffff;
		exports.INT_MIN = -1 << INT_BITS - 1;
	
		//Returns -1, 0, +1 depending on sign of x
		exports.sign = function (v) {
		  return (v > 0) - (v < 0);
		};
	
		//Computes absolute value of integer
		exports.abs = function (v) {
		  var mask = v >> INT_BITS - 1;
		  return (v ^ mask) - mask;
		};
	
		//Computes minimum of integers x and y
		exports.min = function (x, y) {
		  return y ^ (x ^ y) & -(x < y);
		};
	
		//Computes maximum of integers x and y
		exports.max = function (x, y) {
		  return x ^ (x ^ y) & -(x < y);
		};
	
		//Checks if a number is a power of two
		exports.isPow2 = function (v) {
		  return !(v & v - 1) && !!v;
		};
	
		//Computes log base 2 of v
		exports.log2 = function (v) {
		  var r, shift;
		  r = (v > 0xFFFF) << 4;v >>>= r;
		  shift = (v > 0xFF) << 3;v >>>= shift;r |= shift;
		  shift = (v > 0xF) << 2;v >>>= shift;r |= shift;
		  shift = (v > 0x3) << 1;v >>>= shift;r |= shift;
		  return r | v >> 1;
		};
	
		//Computes log base 10 of v
		exports.log10 = function (v) {
		  return v >= 1000000000 ? 9 : v >= 100000000 ? 8 : v >= 10000000 ? 7 : v >= 1000000 ? 6 : v >= 100000 ? 5 : v >= 10000 ? 4 : v >= 1000 ? 3 : v >= 100 ? 2 : v >= 10 ? 1 : 0;
		};
	
		//Counts number of bits
		exports.popCount = function (v) {
		  v = v - (v >>> 1 & 0x55555555);
		  v = (v & 0x33333333) + (v >>> 2 & 0x33333333);
		  return (v + (v >>> 4) & 0xF0F0F0F) * 0x1010101 >>> 24;
		};
	
		//Counts number of trailing zeros
		function countTrailingZeros(v) {
		  var c = 32;
		  v &= -v;
		  if (v) c--;
		  if (v & 0x0000FFFF) c -= 16;
		  if (v & 0x00FF00FF) c -= 8;
		  if (v & 0x0F0F0F0F) c -= 4;
		  if (v & 0x33333333) c -= 2;
		  if (v & 0x55555555) c -= 1;
		  return c;
		}
		exports.countTrailingZeros = countTrailingZeros;
	
		//Rounds to next power of 2
		exports.nextPow2 = function (v) {
		  v += v === 0;
		  --v;
		  v |= v >>> 1;
		  v |= v >>> 2;
		  v |= v >>> 4;
		  v |= v >>> 8;
		  v |= v >>> 16;
		  return v + 1;
		};
	
		//Rounds down to previous power of 2
		exports.prevPow2 = function (v) {
		  v |= v >>> 1;
		  v |= v >>> 2;
		  v |= v >>> 4;
		  v |= v >>> 8;
		  v |= v >>> 16;
		  return v - (v >>> 1);
		};
	
		//Computes parity of word
		exports.parity = function (v) {
		  v ^= v >>> 16;
		  v ^= v >>> 8;
		  v ^= v >>> 4;
		  v &= 0xf;
		  return 0x6996 >>> v & 1;
		};
	
		var REVERSE_TABLE = new Array(256);
	
		(function (tab) {
		  for (var i = 0; i < 256; ++i) {
		    var v = i,
		        r = i,
		        s = 7;
		    for (v >>>= 1; v; v >>>= 1) {
		      r <<= 1;
		      r |= v & 1;
		      --s;
		    }
		    tab[i] = r << s & 0xff;
		  }
		})(REVERSE_TABLE);
	
		//Reverse bits in a 32 bit word
		exports.reverse = function (v) {
		  return REVERSE_TABLE[v & 0xff] << 24 | REVERSE_TABLE[v >>> 8 & 0xff] << 16 | REVERSE_TABLE[v >>> 16 & 0xff] << 8 | REVERSE_TABLE[v >>> 24 & 0xff];
		};
	
		//Interleave bits of 2 coordinates with 16 bits.  Useful for fast quadtree codes
		exports.interleave2 = function (x, y) {
		  x &= 0xFFFF;
		  x = (x | x << 8) & 0x00FF00FF;
		  x = (x | x << 4) & 0x0F0F0F0F;
		  x = (x | x << 2) & 0x33333333;
		  x = (x | x << 1) & 0x55555555;
	
		  y &= 0xFFFF;
		  y = (y | y << 8) & 0x00FF00FF;
		  y = (y | y << 4) & 0x0F0F0F0F;
		  y = (y | y << 2) & 0x33333333;
		  y = (y | y << 1) & 0x55555555;
	
		  return x | y << 1;
		};
	
		//Extracts the nth interleaved component
		exports.deinterleave2 = function (v, n) {
		  v = v >>> n & 0x55555555;
		  v = (v | v >>> 1) & 0x33333333;
		  v = (v | v >>> 2) & 0x0F0F0F0F;
		  v = (v | v >>> 4) & 0x00FF00FF;
		  v = (v | v >>> 16) & 0x000FFFF;
		  return v << 16 >> 16;
		};
	
		//Interleave bits of 3 coordinates, each with 10 bits.  Useful for fast octree codes
		exports.interleave3 = function (x, y, z) {
		  x &= 0x3FF;
		  x = (x | x << 16) & 4278190335;
		  x = (x | x << 8) & 251719695;
		  x = (x | x << 4) & 3272356035;
		  x = (x | x << 2) & 1227133513;
	
		  y &= 0x3FF;
		  y = (y | y << 16) & 4278190335;
		  y = (y | y << 8) & 251719695;
		  y = (y | y << 4) & 3272356035;
		  y = (y | y << 2) & 1227133513;
		  x |= y << 1;
	
		  z &= 0x3FF;
		  z = (z | z << 16) & 4278190335;
		  z = (z | z << 8) & 251719695;
		  z = (z | z << 4) & 3272356035;
		  z = (z | z << 2) & 1227133513;
	
		  return x | z << 2;
		};
	
		//Extracts nth interleaved component of a 3-tuple
		exports.deinterleave3 = function (v, n) {
		  v = v >>> n & 1227133513;
		  v = (v | v >>> 2) & 3272356035;
		  v = (v | v >>> 4) & 251719695;
		  v = (v | v >>> 8) & 4278190335;
		  v = (v | v >>> 16) & 0x3FF;
		  return v << 22 >> 22;
		};
	
		//Computes next combination in colexicographic order (this is mistakenly called nextPermutation on the bit twiddling hacks page)
		exports.nextCombination = function (v) {
		  var t = v | v - 1;
		  return t + 1 | (~t & -~t) - 1 >>> countTrailingZeros(v) + 1;
		};
	
	/***/ }),
	/* 15 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		function dupe_array(count, value, i) {
		  var c = count[i] | 0;
		  if (c <= 0) {
		    return [];
		  }
		  var result = new Array(c),
		      j;
		  if (i === count.length - 1) {
		    for (j = 0; j < c; ++j) {
		      result[j] = value;
		    }
		  } else {
		    for (j = 0; j < c; ++j) {
		      result[j] = dupe_array(count, value, i + 1);
		    }
		  }
		  return result;
		}
	
		function dupe_number(count, value) {
		  var result, i;
		  result = new Array(count);
		  for (i = 0; i < count; ++i) {
		    result[i] = value;
		  }
		  return result;
		}
	
		function dupe(count, value) {
		  if (typeof value === "undefined") {
		    value = 0;
		  }
		  switch (typeof count) {
		    case "number":
		      if (count > 0) {
		        return dupe_number(count | 0, value);
		      }
		      break;
		    case "object":
		      if (typeof count.length === "number") {
		        return dupe_array(count, value, 0);
		      }
		      break;
		  }
		  return [];
		}
	
		module.exports = dupe;
	
	/***/ }),
	/* 16 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = triangulateCube;
	
		var perm = __webpack_require__(17);
		var sgn = __webpack_require__(19);
		var gamma = __webpack_require__(20);
	
		function triangulateCube(dimension) {
		  if (dimension < 0) {
		    return [];
		  }
		  if (dimension === 0) {
		    return [[0]];
		  }
		  var dfactorial = Math.round(gamma(dimension + 1)) | 0;
		  var result = [];
		  for (var i = 0; i < dfactorial; ++i) {
		    var p = perm.unrank(dimension, i);
		    var cell = [0];
		    var v = 0;
		    for (var j = 0; j < p.length; ++j) {
		      v += 1 << p[j];
		      cell.push(v);
		    }
		    if (sgn(p) < 1) {
		      cell[0] = v;
		      cell[dimension] = 0;
		    }
		    result.push(cell);
		  }
		  return result;
		}
	
	/***/ }),
	/* 17 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var pool = __webpack_require__(9);
		var inverse = __webpack_require__(18);
	
		function rank(permutation) {
		  var n = permutation.length;
		  switch (n) {
		    case 0:
		    case 1:
		      return 0;
		    case 2:
		      return permutation[1];
		    default:
		      break;
		  }
		  var p = pool.mallocUint32(n);
		  var pinv = pool.mallocUint32(n);
		  var r = 0,
		      s,
		      t,
		      i;
		  inverse(permutation, pinv);
		  for (i = 0; i < n; ++i) {
		    p[i] = permutation[i];
		  }
		  for (i = n - 1; i > 0; --i) {
		    t = pinv[i];
		    s = p[i];
		    p[i] = p[t];
		    p[t] = s;
		    pinv[i] = pinv[s];
		    pinv[s] = t;
		    r = (r + s) * i;
		  }
		  pool.freeUint32(pinv);
		  pool.freeUint32(p);
		  return r;
		}
	
		function unrank(n, r, p) {
		  switch (n) {
		    case 0:
		      if (p) {
		        return p;
		      }
		      return [];
		    case 1:
		      if (p) {
		        p[0] = 0;
		        return p;
		      } else {
		        return [0];
		      }
		    case 2:
		      if (p) {
		        if (r) {
		          p[0] = 0;
		          p[1] = 1;
		        } else {
		          p[0] = 1;
		          p[1] = 0;
		        }
		        return p;
		      } else {
		        return r ? [0, 1] : [1, 0];
		      }
		    default:
		      break;
		  }
		  p = p || new Array(n);
		  var s,
		      t,
		      i,
		      nf = 1;
		  p[0] = 0;
		  for (i = 1; i < n; ++i) {
		    p[i] = i;
		    nf = nf * i | 0;
		  }
		  for (i = n - 1; i > 0; --i) {
		    s = r / nf | 0;
		    r = r - s * nf | 0;
		    nf = nf / i | 0;
		    t = p[i] | 0;
		    p[i] = p[s] | 0;
		    p[s] = t | 0;
		  }
		  return p;
		}
	
		exports.rank = rank;
		exports.unrank = unrank;
	
	/***/ }),
	/* 18 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		function invertPermutation(pi, result) {
		  result = result || new Array(pi.length);
		  for (var i = 0; i < pi.length; ++i) {
		    result[pi[i]] = i;
		  }
		  return result;
		}
	
		module.exports = invertPermutation;
	
	/***/ }),
	/* 19 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = permutationSign;
	
		var BRUTE_FORCE_CUTOFF = 32;
	
		var pool = __webpack_require__(9);
	
		function permutationSign(p) {
		  var n = p.length;
		  if (n < BRUTE_FORCE_CUTOFF) {
		    //Use quadratic algorithm for small n
		    var sgn = 1;
		    for (var i = 0; i < n; ++i) {
		      for (var j = 0; j < i; ++j) {
		        if (p[i] < p[j]) {
		          sgn = -sgn;
		        } else if (p[i] === p[j]) {
		          return 0;
		        }
		      }
		    }
		    return sgn;
		  } else {
		    //Otherwise use linear time algorithm
		    var visited = pool.mallocUint8(n);
		    for (var i = 0; i < n; ++i) {
		      visited[i] = 0;
		    }
		    var sgn = 1;
		    for (var i = 0; i < n; ++i) {
		      if (!visited[i]) {
		        var count = 1;
		        visited[i] = 1;
		        for (var j = p[i]; j !== i; j = p[j]) {
		          if (visited[j]) {
		            pool.freeUint8(visited);
		            return 0;
		          }
		          count += 1;
		          visited[j] = 1;
		        }
		        if (!(count & 1)) {
		          sgn = -sgn;
		        }
		      }
		    }
		    pool.freeUint8(visited);
		    return sgn;
		  }
		}
	
	/***/ }),
	/* 20 */
	/***/ (function(module, exports) {
	
		// transliterated from the python snippet here:
		// http://en.wikipedia.org/wiki/Lanczos_approximation
	
		var g = 7;
		var p = [0.99999999999980993, 676.5203681218851, -1259.1392167224028, 771.32342877765313, -176.61502916214059, 12.507343278686905, -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7];
	
		var g_ln = 607 / 128;
		var p_ln = [0.99999999999999709182, 57.156235665862923517, -59.597960355475491248, 14.136097974741747174, -0.49191381609762019978, 0.33994649984811888699e-4, 0.46523628927048575665e-4, -0.98374475304879564677e-4, 0.15808870322491248884e-3, -0.21026444172410488319e-3, 0.21743961811521264320e-3, -0.16431810653676389022e-3, 0.84418223983852743293e-4, -0.26190838401581408670e-4, 0.36899182659531622704e-5];
	
		// Spouge approximation (suitable for large arguments)
		function lngamma(z) {
	
		    if (z < 0) return Number('0/0');
		    var x = p_ln[0];
		    for (var i = p_ln.length - 1; i > 0; --i) x += p_ln[i] / (z + i);
		    var t = z + g_ln + 0.5;
		    return .5 * Math.log(2 * Math.PI) + (z + .5) * Math.log(t) - t + Math.log(x) - Math.log(z);
		}
	
		module.exports = function gamma(z) {
		    if (z < 0.5) {
		        return Math.PI / (Math.sin(Math.PI * z) * gamma(1 - z));
		    } else if (z > 100) return Math.exp(lngamma(z));else {
		        z -= 1;
		        var x = p[0];
		        for (var i = 1; i < g + 2; i++) {
		            x += p[i] / (z + i);
		        }
		        var t = z + g + 0.5;
	
		        return Math.sqrt(2 * Math.PI) * Math.pow(t, z + 0.5) * Math.exp(-t) * x;
		    }
		};
	
		module.exports.log = lngamma;
	
	/***/ }),
	/* 21 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = findZeroCrossings;
	
		var core = __webpack_require__(22);
	
		function findZeroCrossings(array, level) {
		  var cross = [];
		  level = +level || 0.0;
		  core(array.hi(array.shape[0] - 1), cross, level);
		  return cross;
		}
	
	/***/ }),
	/* 22 */
	/***/ (function(module, exports, __webpack_require__) {
	
		module.exports = __webpack_require__(23)({
		    args: ['array', {
		        offset: [1],
		        array: 0
		    }, 'scalar', 'scalar', 'index'],
		    pre: {
		        "body": "{}",
		        "args": [],
		        "thisVars": [],
		        "localVars": []
		    },
		    post: {
		        "body": "{}",
		        "args": [],
		        "thisVars": [],
		        "localVars": []
		    },
		    body: {
		        "body": "{\n        var _inline_1_da = _inline_1_arg0_ - _inline_1_arg3_\n        var _inline_1_db = _inline_1_arg1_ - _inline_1_arg3_\n        if((_inline_1_da >= 0) !== (_inline_1_db >= 0)) {\n          _inline_1_arg2_.push(_inline_1_arg4_[0] + 0.5 + 0.5 * (_inline_1_da + _inline_1_db) / (_inline_1_da - _inline_1_db))\n        }\n      }",
		        "args": [{
		            "name": "_inline_1_arg0_",
		            "lvalue": false,
		            "rvalue": true,
		            "count": 1
		        }, {
		            "name": "_inline_1_arg1_",
		            "lvalue": false,
		            "rvalue": true,
		            "count": 1
		        }, {
		            "name": "_inline_1_arg2_",
		            "lvalue": false,
		            "rvalue": true,
		            "count": 1
		        }, {
		            "name": "_inline_1_arg3_",
		            "lvalue": false,
		            "rvalue": true,
		            "count": 2
		        }, {
		            "name": "_inline_1_arg4_",
		            "lvalue": false,
		            "rvalue": true,
		            "count": 1
		        }],
		        "thisVars": [],
		        "localVars": ["_inline_1_da", "_inline_1_db"]
		    },
		    funcName: 'zeroCrossings'
			});
	
	/***/ }),
	/* 23 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var createThunk = __webpack_require__(24);
	
		function Procedure() {
		  this.argTypes = [];
		  this.shimArgs = [];
		  this.arrayArgs = [];
		  this.arrayBlockIndices = [];
		  this.scalarArgs = [];
		  this.offsetArgs = [];
		  this.offsetArgIndex = [];
		  this.indexArgs = [];
		  this.shapeArgs = [];
		  this.funcName = "";
		  this.pre = null;
		  this.body = null;
		  this.post = null;
		  this.debug = false;
		}
	
		function compileCwise(user_args) {
		  //Create procedure
		  var proc = new Procedure();
	
		  //Parse blocks
		  proc.pre = user_args.pre;
		  proc.body = user_args.body;
		  proc.post = user_args.post;
	
		  //Parse arguments
		  var proc_args = user_args.args.slice(0);
		  proc.argTypes = proc_args;
		  for (var i = 0; i < proc_args.length; ++i) {
		    var arg_type = proc_args[i];
		    if (arg_type === "array" || typeof arg_type === "object" && arg_type.blockIndices) {
		      proc.argTypes[i] = "array";
		      proc.arrayArgs.push(i);
		      proc.arrayBlockIndices.push(arg_type.blockIndices ? arg_type.blockIndices : 0);
		      proc.shimArgs.push("array" + i);
		      if (i < proc.pre.args.length && proc.pre.args[i].count > 0) {
		        throw new Error("cwise: pre() block may not reference array args");
		      }
		      if (i < proc.post.args.length && proc.post.args[i].count > 0) {
		        throw new Error("cwise: post() block may not reference array args");
		      }
		    } else if (arg_type === "scalar") {
		      proc.scalarArgs.push(i);
		      proc.shimArgs.push("scalar" + i);
		    } else if (arg_type === "index") {
		      proc.indexArgs.push(i);
		      if (i < proc.pre.args.length && proc.pre.args[i].count > 0) {
		        throw new Error("cwise: pre() block may not reference array index");
		      }
		      if (i < proc.body.args.length && proc.body.args[i].lvalue) {
		        throw new Error("cwise: body() block may not write to array index");
		      }
		      if (i < proc.post.args.length && proc.post.args[i].count > 0) {
		        throw new Error("cwise: post() block may not reference array index");
		      }
		    } else if (arg_type === "shape") {
		      proc.shapeArgs.push(i);
		      if (i < proc.pre.args.length && proc.pre.args[i].lvalue) {
		        throw new Error("cwise: pre() block may not write to array shape");
		      }
		      if (i < proc.body.args.length && proc.body.args[i].lvalue) {
		        throw new Error("cwise: body() block may not write to array shape");
		      }
		      if (i < proc.post.args.length && proc.post.args[i].lvalue) {
		        throw new Error("cwise: post() block may not write to array shape");
		      }
		    } else if (typeof arg_type === "object" && arg_type.offset) {
		      proc.argTypes[i] = "offset";
		      proc.offsetArgs.push({ array: arg_type.array, offset: arg_type.offset });
		      proc.offsetArgIndex.push(i);
		    } else {
		      throw new Error("cwise: Unknown argument type " + proc_args[i]);
		    }
		  }
	
		  //Make sure at least one array argument was specified
		  if (proc.arrayArgs.length <= 0) {
		    throw new Error("cwise: No array arguments specified");
		  }
	
		  //Make sure arguments are correct
		  if (proc.pre.args.length > proc_args.length) {
		    throw new Error("cwise: Too many arguments in pre() block");
		  }
		  if (proc.body.args.length > proc_args.length) {
		    throw new Error("cwise: Too many arguments in body() block");
		  }
		  if (proc.post.args.length > proc_args.length) {
		    throw new Error("cwise: Too many arguments in post() block");
		  }
	
		  //Check debug flag
		  proc.debug = !!user_args.printCode || !!user_args.debug;
	
		  //Retrieve name
		  proc.funcName = user_args.funcName || "cwise";
	
		  //Read in block size
		  proc.blockSize = user_args.blockSize || 64;
	
		  return createThunk(proc);
		}
	
		module.exports = compileCwise;
	
	/***/ }),
	/* 24 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		// The function below is called when constructing a cwise function object, and does the following:
		// A function object is constructed which accepts as argument a compilation function and returns another function.
		// It is this other function that is eventually returned by createThunk, and this function is the one that actually
		// checks whether a certain pattern of arguments has already been used before and compiles new loops as needed.
		// The compilation passed to the first function object is used for compiling new functions.
		// Once this function object is created, it is called with compile as argument, where the first argument of compile
		// is bound to "proc" (essentially containing a preprocessed version of the user arguments to cwise).
		// So createThunk roughly works like this:
		// function createThunk(proc) {
		//   var thunk = function(compileBound) {
		//     var CACHED = {}
		//     return function(arrays and scalars) {
		//       if (dtype and order of arrays in CACHED) {
		//         var func = CACHED[dtype and order of arrays]
		//       } else {
		//         var func = CACHED[dtype and order of arrays] = compileBound(dtype and order of arrays)
		//       }
		//       return func(arrays and scalars)
		//     }
		//   }
		//   return thunk(compile.bind1(proc))
		// }
	
		var compile = __webpack_require__(25);
	
		function createThunk(proc) {
		  var code = ["'use strict'", "var CACHED={}"];
		  var vars = [];
		  var thunkName = proc.funcName + "_cwise_thunk";
	
		  //Build thunk
		  code.push(["return function ", thunkName, "(", proc.shimArgs.join(","), "){"].join(""));
		  var typesig = [];
		  var string_typesig = [];
		  var proc_args = [["array", proc.arrayArgs[0], ".shape.slice(", // Slice shape so that we only retain the shape over which we iterate (which gets passed to the cwise operator as SS).
		  Math.max(0, proc.arrayBlockIndices[0]), proc.arrayBlockIndices[0] < 0 ? "," + proc.arrayBlockIndices[0] + ")" : ")"].join("")];
		  var shapeLengthConditions = [],
		      shapeConditions = [];
		  // Process array arguments
		  for (var i = 0; i < proc.arrayArgs.length; ++i) {
		    var j = proc.arrayArgs[i];
		    vars.push(["t", j, "=array", j, ".dtype,", "r", j, "=array", j, ".order"].join(""));
		    typesig.push("t" + j);
		    typesig.push("r" + j);
		    string_typesig.push("t" + j);
		    string_typesig.push("r" + j + ".join()");
		    proc_args.push("array" + j + ".data");
		    proc_args.push("array" + j + ".stride");
		    proc_args.push("array" + j + ".offset|0");
		    if (i > 0) {
		      // Gather conditions to check for shape equality (ignoring block indices)
		      shapeLengthConditions.push("array" + proc.arrayArgs[0] + ".shape.length===array" + j + ".shape.length+" + (Math.abs(proc.arrayBlockIndices[0]) - Math.abs(proc.arrayBlockIndices[i])));
		      shapeConditions.push("array" + proc.arrayArgs[0] + ".shape[shapeIndex+" + Math.max(0, proc.arrayBlockIndices[0]) + "]===array" + j + ".shape[shapeIndex+" + Math.max(0, proc.arrayBlockIndices[i]) + "]");
		    }
		  }
		  // Check for shape equality
		  if (proc.arrayArgs.length > 1) {
		    code.push("if (!(" + shapeLengthConditions.join(" && ") + ")) throw new Error('cwise: Arrays do not all have the same dimensionality!')");
		    code.push("for(var shapeIndex=array" + proc.arrayArgs[0] + ".shape.length-" + Math.abs(proc.arrayBlockIndices[0]) + "; shapeIndex-->0;) {");
		    code.push("if (!(" + shapeConditions.join(" && ") + ")) throw new Error('cwise: Arrays do not all have the same shape!')");
		    code.push("}");
		  }
		  // Process scalar arguments
		  for (var i = 0; i < proc.scalarArgs.length; ++i) {
		    proc_args.push("scalar" + proc.scalarArgs[i]);
		  }
		  // Check for cached function (and if not present, generate it)
		  vars.push(["type=[", string_typesig.join(","), "].join()"].join(""));
		  vars.push("proc=CACHED[type]");
		  code.push("var " + vars.join(","));
	
		  code.push(["if(!proc){", "CACHED[type]=proc=compile([", typesig.join(","), "])}", "return proc(", proc_args.join(","), ")}"].join(""));
	
		  if (proc.debug) {
		    console.log("-----Generated thunk:\n" + code.join("\n") + "\n----------");
		  }
	
		  //Compile thunk
		  var thunk = new Function("compile", code.join("\n"));
		  return thunk(compile.bind(undefined, proc));
		}
	
		module.exports = createThunk;
	
	/***/ }),
	/* 25 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var uniq = __webpack_require__(26);
	
		// This function generates very simple loops analogous to how you typically traverse arrays (the outermost loop corresponds to the slowest changing index, the innermost loop to the fastest changing index)
		// TODO: If two arrays have the same strides (and offsets) there is potential for decreasing the number of "pointers" and related variables. The drawback is that the type signature would become more specific and that there would thus be less potential for caching, but it might still be worth it, especially when dealing with large numbers of arguments.
		function innerFill(order, proc, body) {
		  var dimension = order.length,
		      nargs = proc.arrayArgs.length,
		      has_index = proc.indexArgs.length > 0,
		      code = [],
		      vars = [],
		      idx = 0,
		      pidx = 0,
		      i,
		      j;
		  for (i = 0; i < dimension; ++i) {
		    // Iteration variables
		    vars.push(["i", i, "=0"].join(""));
		  }
		  //Compute scan deltas
		  for (j = 0; j < nargs; ++j) {
		    for (i = 0; i < dimension; ++i) {
		      pidx = idx;
		      idx = order[i];
		      if (i === 0) {
		        // The innermost/fastest dimension's delta is simply its stride
		        vars.push(["d", j, "s", i, "=t", j, "p", idx].join(""));
		      } else {
		        // For other dimensions the delta is basically the stride minus something which essentially "rewinds" the previous (more inner) dimension
		        vars.push(["d", j, "s", i, "=(t", j, "p", idx, "-s", pidx, "*t", j, "p", pidx, ")"].join(""));
		      }
		    }
		  }
		  if (vars.length > 0) {
		    code.push("var " + vars.join(","));
		  }
		  //Scan loop
		  for (i = dimension - 1; i >= 0; --i) {
		    // Start at largest stride and work your way inwards
		    idx = order[i];
		    code.push(["for(i", i, "=0;i", i, "<s", idx, ";++i", i, "){"].join(""));
		  }
		  //Push body of inner loop
		  code.push(body);
		  //Advance scan pointers
		  for (i = 0; i < dimension; ++i) {
		    pidx = idx;
		    idx = order[i];
		    for (j = 0; j < nargs; ++j) {
		      code.push(["p", j, "+=d", j, "s", i].join(""));
		    }
		    if (has_index) {
		      if (i > 0) {
		        code.push(["index[", pidx, "]-=s", pidx].join(""));
		      }
		      code.push(["++index[", idx, "]"].join(""));
		    }
		    code.push("}");
		  }
		  return code.join("\n");
		}
	
		// Generate "outer" loops that loop over blocks of data, applying "inner" loops to the blocks by manipulating the local variables in such a way that the inner loop only "sees" the current block.
		// TODO: If this is used, then the previous declaration (done by generateCwiseOp) of s* is essentially unnecessary.
		//       I believe the s* are not used elsewhere (in particular, I don't think they're used in the pre/post parts and "shape" is defined independently), so it would be possible to make defining the s* dependent on what loop method is being used.
		function outerFill(matched, order, proc, body) {
		  var dimension = order.length,
		      nargs = proc.arrayArgs.length,
		      blockSize = proc.blockSize,
		      has_index = proc.indexArgs.length > 0,
		      code = [];
		  for (var i = 0; i < nargs; ++i) {
		    code.push(["var offset", i, "=p", i].join(""));
		  }
		  //Generate loops for unmatched dimensions
		  // The order in which these dimensions are traversed is fairly arbitrary (from small stride to large stride, for the first argument)
		  // TODO: It would be nice if the order in which these loops are placed would also be somehow "optimal" (at the very least we should check that it really doesn't hurt us if they're not).
		  for (var i = matched; i < dimension; ++i) {
		    code.push(["for(var j" + i + "=SS[", order[i], "]|0;j", i, ">0;){"].join("")); // Iterate back to front
		    code.push(["if(j", i, "<", blockSize, "){"].join("")); // Either decrease j by blockSize (s = blockSize), or set it to zero (after setting s = j).
		    code.push(["s", order[i], "=j", i].join(""));
		    code.push(["j", i, "=0"].join(""));
		    code.push(["}else{s", order[i], "=", blockSize].join(""));
		    code.push(["j", i, "-=", blockSize, "}"].join(""));
		    if (has_index) {
		      code.push(["index[", order[i], "]=j", i].join(""));
		    }
		  }
		  for (var i = 0; i < nargs; ++i) {
		    var indexStr = ["offset" + i];
		    for (var j = matched; j < dimension; ++j) {
		      indexStr.push(["j", j, "*t", i, "p", order[j]].join(""));
		    }
		    code.push(["p", i, "=(", indexStr.join("+"), ")"].join(""));
		  }
		  code.push(innerFill(order, proc, body));
		  for (var i = matched; i < dimension; ++i) {
		    code.push("}");
		  }
		  return code.join("\n");
		}
	
		//Count the number of compatible inner orders
		// This is the length of the longest common prefix of the arrays in orders.
		// Each array in orders lists the dimensions of the correspond ndarray in order of increasing stride.
		// This is thus the maximum number of dimensions that can be efficiently traversed by simple nested loops for all arrays.
		function countMatches(orders) {
		  var matched = 0,
		      dimension = orders[0].length;
		  while (matched < dimension) {
		    for (var j = 1; j < orders.length; ++j) {
		      if (orders[j][matched] !== orders[0][matched]) {
		        return matched;
		      }
		    }
		    ++matched;
		  }
		  return matched;
		}
	
		//Processes a block according to the given data types
		// Replaces variable names by different ones, either "local" ones (that are then ferried in and out of the given array) or ones matching the arguments that the function performing the ultimate loop will accept.
		function processBlock(block, proc, dtypes) {
		  var code = block.body;
		  var pre = [];
		  var post = [];
		  for (var i = 0; i < block.args.length; ++i) {
		    var carg = block.args[i];
		    if (carg.count <= 0) {
		      continue;
		    }
		    var re = new RegExp(carg.name, "g");
		    var ptrStr = "";
		    var arrNum = proc.arrayArgs.indexOf(i);
		    switch (proc.argTypes[i]) {
		      case "offset":
		        var offArgIndex = proc.offsetArgIndex.indexOf(i);
		        var offArg = proc.offsetArgs[offArgIndex];
		        arrNum = offArg.array;
		        ptrStr = "+q" + offArgIndex; // Adds offset to the "pointer" in the array
		      case "array":
		        ptrStr = "p" + arrNum + ptrStr;
		        var localStr = "l" + i;
		        var arrStr = "a" + arrNum;
		        if (proc.arrayBlockIndices[arrNum] === 0) {
		          // Argument to body is just a single value from this array
		          if (carg.count === 1) {
		            // Argument/array used only once(?)
		            if (dtypes[arrNum] === "generic") {
		              if (carg.lvalue) {
		                pre.push(["var ", localStr, "=", arrStr, ".get(", ptrStr, ")"].join("")); // Is this necessary if the argument is ONLY used as an lvalue? (keep in mind that we can have a += something, so we would actually need to check carg.rvalue)
		                code = code.replace(re, localStr);
		                post.push([arrStr, ".set(", ptrStr, ",", localStr, ")"].join(""));
		              } else {
		                code = code.replace(re, [arrStr, ".get(", ptrStr, ")"].join(""));
		              }
		            } else {
		              code = code.replace(re, [arrStr, "[", ptrStr, "]"].join(""));
		            }
		          } else if (dtypes[arrNum] === "generic") {
		            pre.push(["var ", localStr, "=", arrStr, ".get(", ptrStr, ")"].join("")); // TODO: Could we optimize by checking for carg.rvalue?
		            code = code.replace(re, localStr);
		            if (carg.lvalue) {
		              post.push([arrStr, ".set(", ptrStr, ",", localStr, ")"].join(""));
		            }
		          } else {
		            pre.push(["var ", localStr, "=", arrStr, "[", ptrStr, "]"].join("")); // TODO: Could we optimize by checking for carg.rvalue?
		            code = code.replace(re, localStr);
		            if (carg.lvalue) {
		              post.push([arrStr, "[", ptrStr, "]=", localStr].join(""));
		            }
		          }
		        } else {
		          // Argument to body is a "block"
		          var reStrArr = [carg.name],
		              ptrStrArr = [ptrStr];
		          for (var j = 0; j < Math.abs(proc.arrayBlockIndices[arrNum]); j++) {
		            reStrArr.push("\\s*\\[([^\\]]+)\\]");
		            ptrStrArr.push("$" + (j + 1) + "*t" + arrNum + "b" + j); // Matched index times stride
		          }
		          re = new RegExp(reStrArr.join(""), "g");
		          ptrStr = ptrStrArr.join("+");
		          if (dtypes[arrNum] === "generic") {
		            /*if(carg.lvalue) {
		              pre.push(["var ", localStr, "=", arrStr, ".get(", ptrStr, ")"].join("")) // Is this necessary if the argument is ONLY used as an lvalue? (keep in mind that we can have a += something, so we would actually need to check carg.rvalue)
		              code = code.replace(re, localStr)
		              post.push([arrStr, ".set(", ptrStr, ",", localStr,")"].join(""))
		            } else {
		              code = code.replace(re, [arrStr, ".get(", ptrStr, ")"].join(""))
		            }*/
		            throw new Error("cwise: Generic arrays not supported in combination with blocks!");
		          } else {
		            // This does not produce any local variables, even if variables are used multiple times. It would be possible to do so, but it would complicate things quite a bit.
		            code = code.replace(re, [arrStr, "[", ptrStr, "]"].join(""));
		          }
		        }
		        break;
		      case "scalar":
		        code = code.replace(re, "Y" + proc.scalarArgs.indexOf(i));
		        break;
		      case "index":
		        code = code.replace(re, "index");
		        break;
		      case "shape":
		        code = code.replace(re, "shape");
		        break;
		    }
		  }
		  return [pre.join("\n"), code, post.join("\n")].join("\n").trim();
		}
	
		function typeSummary(dtypes) {
		  var summary = new Array(dtypes.length);
		  var allEqual = true;
		  for (var i = 0; i < dtypes.length; ++i) {
		    var t = dtypes[i];
		    var digits = t.match(/\d+/);
		    if (!digits) {
		      digits = "";
		    } else {
		      digits = digits[0];
		    }
		    if (t.charAt(0) === 0) {
		      summary[i] = "u" + t.charAt(1) + digits;
		    } else {
		      summary[i] = t.charAt(0) + digits;
		    }
		    if (i > 0) {
		      allEqual = allEqual && summary[i] === summary[i - 1];
		    }
		  }
		  if (allEqual) {
		    return summary[0];
		  }
		  return summary.join("");
		}
	
		//Generates a cwise operator
		function generateCWiseOp(proc, typesig) {
	
		  //Compute dimension
		  // Arrays get put first in typesig, and there are two entries per array (dtype and order), so this gets the number of dimensions in the first array arg.
		  var dimension = typesig[1].length - Math.abs(proc.arrayBlockIndices[0]) | 0;
		  var orders = new Array(proc.arrayArgs.length);
		  var dtypes = new Array(proc.arrayArgs.length);
		  for (var i = 0; i < proc.arrayArgs.length; ++i) {
		    dtypes[i] = typesig[2 * i];
		    orders[i] = typesig[2 * i + 1];
		  }
	
		  //Determine where block and loop indices start and end
		  var blockBegin = [],
		      blockEnd = []; // These indices are exposed as blocks
		  var loopBegin = [],
		      loopEnd = []; // These indices are iterated over
		  var loopOrders = []; // orders restricted to the loop indices
		  for (var i = 0; i < proc.arrayArgs.length; ++i) {
		    if (proc.arrayBlockIndices[i] < 0) {
		      loopBegin.push(0);
		      loopEnd.push(dimension);
		      blockBegin.push(dimension);
		      blockEnd.push(dimension + proc.arrayBlockIndices[i]);
		    } else {
		      loopBegin.push(proc.arrayBlockIndices[i]); // Non-negative
		      loopEnd.push(proc.arrayBlockIndices[i] + dimension);
		      blockBegin.push(0);
		      blockEnd.push(proc.arrayBlockIndices[i]);
		    }
		    var newOrder = [];
		    for (var j = 0; j < orders[i].length; j++) {
		      if (loopBegin[i] <= orders[i][j] && orders[i][j] < loopEnd[i]) {
		        newOrder.push(orders[i][j] - loopBegin[i]); // If this is a loop index, put it in newOrder, subtracting loopBegin, to make sure that all loopOrders are using a common set of indices.
		      }
		    }
		    loopOrders.push(newOrder);
		  }
	
		  //First create arguments for procedure
		  var arglist = ["SS"]; // SS is the overall shape over which we iterate
		  var code = ["'use strict'"];
		  var vars = [];
	
		  for (var j = 0; j < dimension; ++j) {
		    vars.push(["s", j, "=SS[", j, "]"].join("")); // The limits for each dimension.
		  }
		  for (var i = 0; i < proc.arrayArgs.length; ++i) {
		    arglist.push("a" + i); // Actual data array
		    arglist.push("t" + i); // Strides
		    arglist.push("p" + i); // Offset in the array at which the data starts (also used for iterating over the data)
	
		    for (var j = 0; j < dimension; ++j) {
		      // Unpack the strides into vars for looping
		      vars.push(["t", i, "p", j, "=t", i, "[", loopBegin[i] + j, "]"].join(""));
		    }
	
		    for (var j = 0; j < Math.abs(proc.arrayBlockIndices[i]); ++j) {
		      // Unpack the strides into vars for block iteration
		      vars.push(["t", i, "b", j, "=t", i, "[", blockBegin[i] + j, "]"].join(""));
		    }
		  }
		  for (var i = 0; i < proc.scalarArgs.length; ++i) {
		    arglist.push("Y" + i);
		  }
		  if (proc.shapeArgs.length > 0) {
		    vars.push("shape=SS.slice(0)"); // Makes the shape over which we iterate available to the user defined functions (so you can use width/height for example)
		  }
		  if (proc.indexArgs.length > 0) {
		    // Prepare an array to keep track of the (logical) indices, initialized to dimension zeroes.
		    var zeros = new Array(dimension);
		    for (var i = 0; i < dimension; ++i) {
		      zeros[i] = "0";
		    }
		    vars.push(["index=[", zeros.join(","), "]"].join(""));
		  }
		  for (var i = 0; i < proc.offsetArgs.length; ++i) {
		    // Offset arguments used for stencil operations
		    var off_arg = proc.offsetArgs[i];
		    var init_string = [];
		    for (var j = 0; j < off_arg.offset.length; ++j) {
		      if (off_arg.offset[j] === 0) {
		        continue;
		      } else if (off_arg.offset[j] === 1) {
		        init_string.push(["t", off_arg.array, "p", j].join(""));
		      } else {
		        init_string.push([off_arg.offset[j], "*t", off_arg.array, "p", j].join(""));
		      }
		    }
		    if (init_string.length === 0) {
		      vars.push("q" + i + "=0");
		    } else {
		      vars.push(["q", i, "=", init_string.join("+")].join(""));
		    }
		  }
	
		  //Prepare this variables
		  var thisVars = uniq([].concat(proc.pre.thisVars).concat(proc.body.thisVars).concat(proc.post.thisVars));
		  vars = vars.concat(thisVars);
		  if (vars.length > 0) {
		    code.push("var " + vars.join(","));
		  }
		  for (var i = 0; i < proc.arrayArgs.length; ++i) {
		    code.push("p" + i + "|=0");
		  }
	
		  //Inline prelude
		  if (proc.pre.body.length > 3) {
		    code.push(processBlock(proc.pre, proc, dtypes));
		  }
	
		  //Process body
		  var body = processBlock(proc.body, proc, dtypes);
		  var matched = countMatches(loopOrders);
		  if (matched < dimension) {
		    code.push(outerFill(matched, loopOrders[0], proc, body)); // TODO: Rather than passing loopOrders[0], it might be interesting to look at passing an order that represents the majority of the arguments for example.
		  } else {
		    code.push(innerFill(loopOrders[0], proc, body));
		  }
	
		  //Inline epilog
		  if (proc.post.body.length > 3) {
		    code.push(processBlock(proc.post, proc, dtypes));
		  }
	
		  if (proc.debug) {
		    console.log("-----Generated cwise routine for ", typesig, ":\n" + code.join("\n") + "\n----------");
		  }
	
		  var loopName = [proc.funcName || "unnamed", "_cwise_loop_", orders[0].join("s"), "m", matched, typeSummary(dtypes)].join("");
		  var f = new Function(["function ", loopName, "(", arglist.join(","), "){", code.join("\n"), "} return ", loopName].join(""));
		  return f();
		}
		module.exports = generateCWiseOp;
	
	/***/ }),
	/* 26 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		function unique_pred(list, compare) {
		  var ptr = 1,
		      len = list.length,
		      a = list[0],
		      b = list[0];
		  for (var i = 1; i < len; ++i) {
		    b = a;
		    a = list[i];
		    if (compare(a, b)) {
		      if (i === ptr) {
		        ptr++;
		        continue;
		      }
		      list[ptr++] = a;
		    }
		  }
		  list.length = ptr;
		  return list;
		}
	
		function unique_eq(list) {
		  var ptr = 1,
		      len = list.length,
		      a = list[0],
		      b = list[0];
		  for (var i = 1; i < len; ++i, b = a) {
		    b = a;
		    a = list[i];
		    if (a !== b) {
		      if (i === ptr) {
		        ptr++;
		        continue;
		      }
		      list[ptr++] = a;
		    }
		  }
		  list.length = ptr;
		  return list;
		}
	
		function unique(list, compare, sorted) {
		  if (list.length === 0) {
		    return list;
		  }
		  if (compare) {
		    if (!sorted) {
		      list.sort(compare);
		    }
		    return unique_pred(list, compare);
		  }
		  if (!sorted) {
		    list.sort();
		  }
		  return unique_eq(list);
		}
	
		module.exports = unique;
	
	/***/ }),
	/* 27 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var iota = __webpack_require__(28);
		var isBuffer = __webpack_require__(29);
	
		var hasTypedArrays = typeof Float64Array !== "undefined";
	
		function compare1st(a, b) {
		  return a[0] - b[0];
		}
	
		function order() {
		  var stride = this.stride;
		  var terms = new Array(stride.length);
		  var i;
		  for (i = 0; i < terms.length; ++i) {
		    terms[i] = [Math.abs(stride[i]), i];
		  }
		  terms.sort(compare1st);
		  var result = new Array(terms.length);
		  for (i = 0; i < result.length; ++i) {
		    result[i] = terms[i][1];
		  }
		  return result;
		}
	
		function compileConstructor(dtype, dimension) {
		  var className = ["View", dimension, "d", dtype].join("");
		  if (dimension < 0) {
		    className = "View_Nil" + dtype;
		  }
		  var useGetters = dtype === "generic";
	
		  if (dimension === -1) {
		    //Special case for trivial arrays
		    var code = "function " + className + "(a){this.data=a;};\
		var proto=" + className + ".prototype;\
		proto.dtype='" + dtype + "';\
		proto.index=function(){return -1};\
		proto.size=0;\
		proto.dimension=-1;\
		proto.shape=proto.stride=proto.order=[];\
		proto.lo=proto.hi=proto.transpose=proto.step=\
		function(){return new " + className + "(this.data);};\
		proto.get=proto.set=function(){};\
		proto.pick=function(){return null};\
		return function construct_" + className + "(a){return new " + className + "(a);}";
		    var procedure = new Function(code);
		    return procedure();
		  } else if (dimension === 0) {
		    //Special case for 0d arrays
		    var code = "function " + className + "(a,d) {\
		this.data = a;\
		this.offset = d\
		};\
		var proto=" + className + ".prototype;\
		proto.dtype='" + dtype + "';\
		proto.index=function(){return this.offset};\
		proto.dimension=0;\
		proto.size=1;\
		proto.shape=\
		proto.stride=\
		proto.order=[];\
		proto.lo=\
		proto.hi=\
		proto.transpose=\
		proto.step=function " + className + "_copy() {\
		return new " + className + "(this.data,this.offset)\
		};\
		proto.pick=function " + className + "_pick(){\
		return TrivialArray(this.data);\
		};\
		proto.valueOf=proto.get=function " + className + "_get(){\
		return " + (useGetters ? "this.data.get(this.offset)" : "this.data[this.offset]") + "};\
		proto.set=function " + className + "_set(v){\
		return " + (useGetters ? "this.data.set(this.offset,v)" : "this.data[this.offset]=v") + "\
		};\
		return function construct_" + className + "(a,b,c,d){return new " + className + "(a,d)}";
		    var procedure = new Function("TrivialArray", code);
		    return procedure(CACHED_CONSTRUCTORS[dtype][0]);
		  }
	
		  var code = ["'use strict'"];
	
		  //Create constructor for view
		  var indices = iota(dimension);
		  var args = indices.map(function (i) {
		    return "i" + i;
		  });
		  var index_str = "this.offset+" + indices.map(function (i) {
		    return "this.stride[" + i + "]*i" + i;
		  }).join("+");
		  var shapeArg = indices.map(function (i) {
		    return "b" + i;
		  }).join(",");
		  var strideArg = indices.map(function (i) {
		    return "c" + i;
		  }).join(",");
		  code.push("function " + className + "(a," + shapeArg + "," + strideArg + ",d){this.data=a", "this.shape=[" + shapeArg + "]", "this.stride=[" + strideArg + "]", "this.offset=d|0}", "var proto=" + className + ".prototype", "proto.dtype='" + dtype + "'", "proto.dimension=" + dimension);
	
		  //view.size:
		  code.push("Object.defineProperty(proto,'size',{get:function " + className + "_size(){\
		return " + indices.map(function (i) {
		    return "this.shape[" + i + "]";
		  }).join("*"), "}})");
	
		  //view.order:
		  if (dimension === 1) {
		    code.push("proto.order=[0]");
		  } else {
		    code.push("Object.defineProperty(proto,'order',{get:");
		    if (dimension < 4) {
		      code.push("function " + className + "_order(){");
		      if (dimension === 2) {
		        code.push("return (Math.abs(this.stride[0])>Math.abs(this.stride[1]))?[1,0]:[0,1]}})");
		      } else if (dimension === 3) {
		        code.push("var s0=Math.abs(this.stride[0]),s1=Math.abs(this.stride[1]),s2=Math.abs(this.stride[2]);\
		if(s0>s1){\
		if(s1>s2){\
		return [2,1,0];\
		}else if(s0>s2){\
		return [1,2,0];\
		}else{\
		return [1,0,2];\
		}\
		}else if(s0>s2){\
		return [2,0,1];\
		}else if(s2>s1){\
		return [0,1,2];\
		}else{\
		return [0,2,1];\
		}}})");
		      }
		    } else {
		      code.push("ORDER})");
		    }
		  }
	
		  //view.set(i0, ..., v):
		  code.push("proto.set=function " + className + "_set(" + args.join(",") + ",v){");
		  if (useGetters) {
		    code.push("return this.data.set(" + index_str + ",v)}");
		  } else {
		    code.push("return this.data[" + index_str + "]=v}");
		  }
	
		  //view.get(i0, ...):
		  code.push("proto.get=function " + className + "_get(" + args.join(",") + "){");
		  if (useGetters) {
		    code.push("return this.data.get(" + index_str + ")}");
		  } else {
		    code.push("return this.data[" + index_str + "]}");
		  }
	
		  //view.index:
		  code.push("proto.index=function " + className + "_index(", args.join(), "){return " + index_str + "}");
	
		  //view.hi():
		  code.push("proto.hi=function " + className + "_hi(" + args.join(",") + "){return new " + className + "(this.data," + indices.map(function (i) {
		    return ["(typeof i", i, "!=='number'||i", i, "<0)?this.shape[", i, "]:i", i, "|0"].join("");
		  }).join(",") + "," + indices.map(function (i) {
		    return "this.stride[" + i + "]";
		  }).join(",") + ",this.offset)}");
	
		  //view.lo():
		  var a_vars = indices.map(function (i) {
		    return "a" + i + "=this.shape[" + i + "]";
		  });
		  var c_vars = indices.map(function (i) {
		    return "c" + i + "=this.stride[" + i + "]";
		  });
		  code.push("proto.lo=function " + className + "_lo(" + args.join(",") + "){var b=this.offset,d=0," + a_vars.join(",") + "," + c_vars.join(","));
		  for (var i = 0; i < dimension; ++i) {
		    code.push("if(typeof i" + i + "==='number'&&i" + i + ">=0){\
		d=i" + i + "|0;\
		b+=c" + i + "*d;\
		a" + i + "-=d}");
		  }
		  code.push("return new " + className + "(this.data," + indices.map(function (i) {
		    return "a" + i;
		  }).join(",") + "," + indices.map(function (i) {
		    return "c" + i;
		  }).join(",") + ",b)}");
	
		  //view.step():
		  code.push("proto.step=function " + className + "_step(" + args.join(",") + "){var " + indices.map(function (i) {
		    return "a" + i + "=this.shape[" + i + "]";
		  }).join(",") + "," + indices.map(function (i) {
		    return "b" + i + "=this.stride[" + i + "]";
		  }).join(",") + ",c=this.offset,d=0,ceil=Math.ceil");
		  for (var i = 0; i < dimension; ++i) {
		    code.push("if(typeof i" + i + "==='number'){\
		d=i" + i + "|0;\
		if(d<0){\
		c+=b" + i + "*(a" + i + "-1);\
		a" + i + "=ceil(-a" + i + "/d)\
		}else{\
		a" + i + "=ceil(a" + i + "/d)\
		}\
		b" + i + "*=d\
		}");
		  }
		  code.push("return new " + className + "(this.data," + indices.map(function (i) {
		    return "a" + i;
		  }).join(",") + "," + indices.map(function (i) {
		    return "b" + i;
		  }).join(",") + ",c)}");
	
		  //view.transpose():
		  var tShape = new Array(dimension);
		  var tStride = new Array(dimension);
		  for (var i = 0; i < dimension; ++i) {
		    tShape[i] = "a[i" + i + "]";
		    tStride[i] = "b[i" + i + "]";
		  }
		  code.push("proto.transpose=function " + className + "_transpose(" + args + "){" + args.map(function (n, idx) {
		    return n + "=(" + n + "===undefined?" + idx + ":" + n + "|0)";
		  }).join(";"), "var a=this.shape,b=this.stride;return new " + className + "(this.data," + tShape.join(",") + "," + tStride.join(",") + ",this.offset)}");
	
		  //view.pick():
		  code.push("proto.pick=function " + className + "_pick(" + args + "){var a=[],b=[],c=this.offset");
		  for (var i = 0; i < dimension; ++i) {
		    code.push("if(typeof i" + i + "==='number'&&i" + i + ">=0){c=(c+this.stride[" + i + "]*i" + i + ")|0}else{a.push(this.shape[" + i + "]);b.push(this.stride[" + i + "])}");
		  }
		  code.push("var ctor=CTOR_LIST[a.length+1];return ctor(this.data,a,b,c)}");
	
		  //Add return statement
		  code.push("return function construct_" + className + "(data,shape,stride,offset){return new " + className + "(data," + indices.map(function (i) {
		    return "shape[" + i + "]";
		  }).join(",") + "," + indices.map(function (i) {
		    return "stride[" + i + "]";
		  }).join(",") + ",offset)}");
	
		  //Compile procedure
		  var procedure = new Function("CTOR_LIST", "ORDER", code.join("\n"));
		  return procedure(CACHED_CONSTRUCTORS[dtype], order);
		}
	
		function arrayDType(data) {
		  if (isBuffer(data)) {
		    return "buffer";
		  }
		  if (hasTypedArrays) {
		    switch (Object.prototype.toString.call(data)) {
		      case "[object Float64Array]":
		        return "float64";
		      case "[object Float32Array]":
		        return "float32";
		      case "[object Int8Array]":
		        return "int8";
		      case "[object Int16Array]":
		        return "int16";
		      case "[object Int32Array]":
		        return "int32";
		      case "[object Uint8Array]":
		        return "uint8";
		      case "[object Uint16Array]":
		        return "uint16";
		      case "[object Uint32Array]":
		        return "uint32";
		      case "[object Uint8ClampedArray]":
		        return "uint8_clamped";
		    }
		  }
		  if (Array.isArray(data)) {
		    return "array";
		  }
		  return "generic";
		}
	
		var CACHED_CONSTRUCTORS = {
		  "float32": [],
		  "float64": [],
		  "int8": [],
		  "int16": [],
		  "int32": [],
		  "uint8": [],
		  "uint16": [],
		  "uint32": [],
		  "array": [],
		  "uint8_clamped": [],
		  "buffer": [],
		  "generic": []
		};(function () {
		  for (var id in CACHED_CONSTRUCTORS) {
		    CACHED_CONSTRUCTORS[id].push(compileConstructor(id, -1));
		  }
		});
	
		function wrappedNDArrayCtor(data, shape, stride, offset) {
		  if (data === undefined) {
		    var ctor = CACHED_CONSTRUCTORS.array[0];
		    return ctor([]);
		  } else if (typeof data === "number") {
		    data = [data];
		  }
		  if (shape === undefined) {
		    shape = [data.length];
		  }
		  var d = shape.length;
		  if (stride === undefined) {
		    stride = new Array(d);
		    for (var i = d - 1, sz = 1; i >= 0; --i) {
		      stride[i] = sz;
		      sz *= shape[i];
		    }
		  }
		  if (offset === undefined) {
		    offset = 0;
		    for (var i = 0; i < d; ++i) {
		      if (stride[i] < 0) {
		        offset -= (shape[i] - 1) * stride[i];
		      }
		    }
		  }
		  var dtype = arrayDType(data);
		  var ctor_list = CACHED_CONSTRUCTORS[dtype];
		  while (ctor_list.length <= d + 1) {
		    ctor_list.push(compileConstructor(dtype, ctor_list.length - 1));
		  }
		  var ctor = ctor_list[d + 1];
		  return ctor(data, shape, stride, offset);
		}
	
		module.exports = wrappedNDArrayCtor;
	
	/***/ }),
	/* 28 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		function iota(n) {
		  var result = new Array(n);
		  for (var i = 0; i < n; ++i) {
		    result[i] = i;
		  }
		  return result;
		}
	
		module.exports = iota;
	
	/***/ }),
	/* 29 */
	/***/ (function(module, exports) {
	
		/*!
		 * Determine if an object is a Buffer
		 *
		 * @author   Feross Aboukhadijeh <https://feross.org>
		 * @license  MIT
		 */
	
		// The _isBuffer check is for Safari 5-7 support, because it's missing
		// Object.prototype.constructor. Remove this eventually
		module.exports = function (obj) {
		  return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer);
		};
	
		function isBuffer(obj) {
		  return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj);
		}
	
		// For Node v0.10 support. Remove this eventually.
		function isSlowBuffer(obj) {
		  return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0));
		}
	
	/***/ }),
	/* 30 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = simplifyPolygon;
	
		var orient = __webpack_require__(31);
		var sc = __webpack_require__(37);
	
		function errorWeight(base, a, b) {
		  var area = Math.abs(orient(base, a, b));
		  var perim = Math.sqrt(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2));
		  return area / perim;
		}
	
		function simplifyPolygon(cells, positions, minArea) {
	
		  var n = positions.length;
		  var nc = cells.length;
		  var inv = new Array(n);
		  var outv = new Array(n);
		  var weights = new Array(n);
		  var dead = new Array(n);
	
		  //Initialize tables
		  for (var i = 0; i < n; ++i) {
		    inv[i] = outv[i] = -1;
		    weights[i] = Infinity;
		    dead[i] = false;
		  }
	
		  //Compute neighbors
		  for (var i = 0; i < nc; ++i) {
		    var c = cells[i];
		    if (c.length !== 2) {
		      throw new Error("Input must be a graph");
		    }
		    var s = c[1];
		    var t = c[0];
		    if (outv[t] !== -1) {
		      outv[t] = -2;
		    } else {
		      outv[t] = s;
		    }
		    if (inv[s] !== -1) {
		      inv[s] = -2;
		    } else {
		      inv[s] = t;
		    }
		  }
	
		  //Updates the weight for vertex i
		  function computeWeight(i) {
		    if (dead[i]) {
		      return Infinity;
		    }
		    //TODO: Check that the line segment doesn't cross once simplified
		    var s = inv[i];
		    var t = outv[i];
		    if (s < 0 || t < 0) {
		      return Infinity;
		    } else {
		      return errorWeight(positions[i], positions[s], positions[t]);
		    }
		  }
	
		  //Swaps two nodes on the heap (i,j) are the index of the nodes
		  function heapSwap(i, j) {
		    var a = heap[i];
		    var b = heap[j];
		    heap[i] = b;
		    heap[j] = a;
		    index[a] = j;
		    index[b] = i;
		  }
	
		  //Returns the weight of node i on the heap
		  function heapWeight(i) {
		    return weights[heap[i]];
		  }
	
		  function heapParent(i) {
		    if (i & 1) {
		      return i - 1 >> 1;
		    }
		    return (i >> 1) - 1;
		  }
	
		  //Bubble element i down the heap
		  function heapDown(i) {
		    var w = heapWeight(i);
		    while (true) {
		      var tw = w;
		      var left = 2 * i + 1;
		      var right = 2 * (i + 1);
		      var next = i;
		      if (left < heapCount) {
		        var lw = heapWeight(left);
		        if (lw < tw) {
		          next = left;
		          tw = lw;
		        }
		      }
		      if (right < heapCount) {
		        var rw = heapWeight(right);
		        if (rw < tw) {
		          next = right;
		        }
		      }
		      if (next === i) {
		        return i;
		      }
		      heapSwap(i, next);
		      i = next;
		    }
		  }
	
		  //Bubbles element i up the heap
		  function heapUp(i) {
		    var w = heapWeight(i);
		    while (i > 0) {
		      var parent = heapParent(i);
		      if (parent >= 0) {
		        var pw = heapWeight(parent);
		        if (w < pw) {
		          heapSwap(i, parent);
		          i = parent;
		          continue;
		        }
		      }
		      return i;
		    }
		  }
	
		  //Pop minimum element
		  function heapPop() {
		    if (heapCount > 0) {
		      var head = heap[0];
		      heapSwap(0, heapCount - 1);
		      heapCount -= 1;
		      heapDown(0);
		      return head;
		    }
		    return -1;
		  }
	
		  //Update heap item i
		  function heapUpdate(i, w) {
		    var a = heap[i];
		    if (weights[a] === w) {
		      return i;
		    }
		    weights[a] = -Infinity;
		    heapUp(i);
		    heapPop();
		    weights[a] = w;
		    heapCount += 1;
		    return heapUp(heapCount - 1);
		  }
	
		  //Kills a vertex (assume vertex already removed from heap)
		  function kill(i) {
		    if (dead[i]) {
		      return;
		    }
		    //Kill vertex
		    dead[i] = true;
		    //Fixup topology
		    var s = inv[i];
		    var t = outv[i];
		    if (inv[t] >= 0) {
		      inv[t] = s;
		    }
		    if (outv[s] >= 0) {
		      outv[s] = t;
		    }
	
		    //Update weights on s and t
		    if (index[s] >= 0) {
		      heapUpdate(index[s], computeWeight(s));
		    }
		    if (index[t] >= 0) {
		      heapUpdate(index[t], computeWeight(t));
		    }
		  }
	
		  //Initialize weights and heap
		  var heap = [];
		  var index = new Array(n);
		  for (var i = 0; i < n; ++i) {
		    var w = weights[i] = computeWeight(i);
		    if (w < Infinity) {
		      index[i] = heap.length;
		      heap.push(i);
		    } else {
		      index[i] = -1;
		    }
		  }
		  var heapCount = heap.length;
		  for (var i = heapCount >> 1; i >= 0; --i) {
		    heapDown(i);
		  }
	
		  //Kill vertices
		  while (true) {
		    var hmin = heapPop();
		    if (hmin < 0 || weights[hmin] > minArea) {
		      break;
		    }
		    kill(hmin);
		  }
	
		  //Build collapsed vertex table
		  var npositions = [];
		  for (var i = 0; i < n; ++i) {
		    if (!dead[i]) {
		      index[i] = npositions.length;
		      npositions.push(positions[i].slice());
		    }
		  }
		  var nv = npositions.length;
	
		  function tortoiseHare(seq, start) {
		    if (seq[start] < 0) {
		      return start;
		    }
		    var t = start;
		    var h = start;
		    do {
		      //Walk two steps with h
		      var nh = seq[h];
		      if (!dead[h] || nh < 0 || nh === h) {
		        break;
		      }
		      h = nh;
		      nh = seq[h];
		      if (!dead[h] || nh < 0 || nh === h) {
		        break;
		      }
		      h = nh;
	
		      //Walk one step with t
		      t = seq[t];
		    } while (t !== h);
		    //Compress cycles
		    for (var v = start; v !== h; v = seq[v]) {
		      seq[v] = h;
		    }
		    return h;
		  }
	
		  var ncells = [];
		  cells.forEach(function (c) {
		    var tin = tortoiseHare(inv, c[0]);
		    var tout = tortoiseHare(outv, c[1]);
		    if (tin >= 0 && tout >= 0 && tin !== tout) {
		      var cin = index[tin];
		      var cout = index[tout];
		      if (cin !== cout) {
		        ncells.push([cin, cout]);
		      }
		    }
		  });
	
		  //Normalize result
		  sc.unique(sc.normalize(ncells));
	
		  //Return final list of cells
		  return {
		    positions: npositions,
		    edges: ncells
		  };
			}
	
	/***/ }),
	/* 31 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var twoProduct = __webpack_require__(32);
		var robustSum = __webpack_require__(33);
		var robustScale = __webpack_require__(34);
		var robustSubtract = __webpack_require__(36);
	
		var NUM_EXPAND = 5;
	
		var EPSILON = 1.1102230246251565e-16;
		var ERRBOUND3 = (3.0 + 16.0 * EPSILON) * EPSILON;
		var ERRBOUND4 = (7.0 + 56.0 * EPSILON) * EPSILON;
	
		function cofactor(m, c) {
		  var result = new Array(m.length - 1);
		  for (var i = 1; i < m.length; ++i) {
		    var r = result[i - 1] = new Array(m.length - 1);
		    for (var j = 0, k = 0; j < m.length; ++j) {
		      if (j === c) {
		        continue;
		      }
		      r[k++] = m[i][j];
		    }
		  }
		  return result;
		}
	
		function matrix(n) {
		  var result = new Array(n);
		  for (var i = 0; i < n; ++i) {
		    result[i] = new Array(n);
		    for (var j = 0; j < n; ++j) {
		      result[i][j] = ["m", j, "[", n - i - 1, "]"].join("");
		    }
		  }
		  return result;
		}
	
		function sign(n) {
		  if (n & 1) {
		    return "-";
		  }
		  return "";
		}
	
		function generateSum(expr) {
		  if (expr.length === 1) {
		    return expr[0];
		  } else if (expr.length === 2) {
		    return ["sum(", expr[0], ",", expr[1], ")"].join("");
		  } else {
		    var m = expr.length >> 1;
		    return ["sum(", generateSum(expr.slice(0, m)), ",", generateSum(expr.slice(m)), ")"].join("");
		  }
		}
	
		function determinant(m) {
		  if (m.length === 2) {
		    return [["sum(prod(", m[0][0], ",", m[1][1], "),prod(-", m[0][1], ",", m[1][0], "))"].join("")];
		  } else {
		    var expr = [];
		    for (var i = 0; i < m.length; ++i) {
		      expr.push(["scale(", generateSum(determinant(cofactor(m, i))), ",", sign(i), m[0][i], ")"].join(""));
		    }
		    return expr;
		  }
		}
	
		function orientation(n) {
		  var pos = [];
		  var neg = [];
		  var m = matrix(n);
		  var args = [];
		  for (var i = 0; i < n; ++i) {
		    if ((i & 1) === 0) {
		      pos.push.apply(pos, determinant(cofactor(m, i)));
		    } else {
		      neg.push.apply(neg, determinant(cofactor(m, i)));
		    }
		    args.push("m" + i);
		  }
		  var posExpr = generateSum(pos);
		  var negExpr = generateSum(neg);
		  var funcName = "orientation" + n + "Exact";
		  var code = ["function ", funcName, "(", args.join(), "){var p=", posExpr, ",n=", negExpr, ",d=sub(p,n);\
		return d[d.length-1];};return ", funcName].join("");
		  var proc = new Function("sum", "prod", "scale", "sub", code);
		  return proc(robustSum, twoProduct, robustScale, robustSubtract);
		}
	
		var orientation3Exact = orientation(3);
		var orientation4Exact = orientation(4);
	
		var CACHED = [function orientation0() {
		  return 0;
		}, function orientation1() {
		  return 0;
		}, function orientation2(a, b) {
		  return b[0] - a[0];
		}, function orientation3(a, b, c) {
		  var l = (a[1] - c[1]) * (b[0] - c[0]);
		  var r = (a[0] - c[0]) * (b[1] - c[1]);
		  var det = l - r;
		  var s;
		  if (l > 0) {
		    if (r <= 0) {
		      return det;
		    } else {
		      s = l + r;
		    }
		  } else if (l < 0) {
		    if (r >= 0) {
		      return det;
		    } else {
		      s = -(l + r);
		    }
		  } else {
		    return det;
		  }
		  var tol = ERRBOUND3 * s;
		  if (det >= tol || det <= -tol) {
		    return det;
		  }
		  return orientation3Exact(a, b, c);
		}, function orientation4(a, b, c, d) {
		  var adx = a[0] - d[0];
		  var bdx = b[0] - d[0];
		  var cdx = c[0] - d[0];
		  var ady = a[1] - d[1];
		  var bdy = b[1] - d[1];
		  var cdy = c[1] - d[1];
		  var adz = a[2] - d[2];
		  var bdz = b[2] - d[2];
		  var cdz = c[2] - d[2];
		  var bdxcdy = bdx * cdy;
		  var cdxbdy = cdx * bdy;
		  var cdxady = cdx * ady;
		  var adxcdy = adx * cdy;
		  var adxbdy = adx * bdy;
		  var bdxady = bdx * ady;
		  var det = adz * (bdxcdy - cdxbdy) + bdz * (cdxady - adxcdy) + cdz * (adxbdy - bdxady);
		  var permanent = (Math.abs(bdxcdy) + Math.abs(cdxbdy)) * Math.abs(adz) + (Math.abs(cdxady) + Math.abs(adxcdy)) * Math.abs(bdz) + (Math.abs(adxbdy) + Math.abs(bdxady)) * Math.abs(cdz);
		  var tol = ERRBOUND4 * permanent;
		  if (det > tol || -det > tol) {
		    return det;
		  }
		  return orientation4Exact(a, b, c, d);
		}];
	
		function slowOrient(args) {
		  var proc = CACHED[args.length];
		  if (!proc) {
		    proc = CACHED[args.length] = orientation(args.length);
		  }
		  return proc.apply(undefined, args);
		}
	
		function generateOrientationProc() {
		  while (CACHED.length <= NUM_EXPAND) {
		    CACHED.push(orientation(CACHED.length));
		  }
		  var args = [];
		  var procArgs = ["slow"];
		  for (var i = 0; i <= NUM_EXPAND; ++i) {
		    args.push("a" + i);
		    procArgs.push("o" + i);
		  }
		  var code = ["function getOrientation(", args.join(), "){switch(arguments.length){case 0:case 1:return 0;"];
		  for (var i = 2; i <= NUM_EXPAND; ++i) {
		    code.push("case ", i, ":return o", i, "(", args.slice(0, i).join(), ");");
		  }
		  code.push("}var s=new Array(arguments.length);for(var i=0;i<arguments.length;++i){s[i]=arguments[i]};return slow(s);}return getOrientation");
		  procArgs.push(code.join(""));
	
		  var proc = Function.apply(undefined, procArgs);
		  module.exports = proc.apply(undefined, [slowOrient].concat(CACHED));
		  for (var i = 0; i <= NUM_EXPAND; ++i) {
		    module.exports[i] = CACHED[i];
		  }
		}
	
		generateOrientationProc();
	
	/***/ }),
	/* 32 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = twoProduct;
	
		var SPLITTER = +(Math.pow(2, 27) + 1.0);
	
		function twoProduct(a, b, result) {
		  var x = a * b;
	
		  var c = SPLITTER * a;
		  var abig = c - a;
		  var ahi = c - abig;
		  var alo = a - ahi;
	
		  var d = SPLITTER * b;
		  var bbig = d - b;
		  var bhi = d - bbig;
		  var blo = b - bhi;
	
		  var err1 = x - ahi * bhi;
		  var err2 = err1 - alo * bhi;
		  var err3 = err2 - ahi * blo;
	
		  var y = alo * blo - err3;
	
		  if (result) {
		    result[0] = y;
		    result[1] = x;
		    return result;
		  }
	
		  return [y, x];
		}
	
	/***/ }),
	/* 33 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = linearExpansionSum;
	
		//Easy case: Add two scalars
		function scalarScalar(a, b) {
		  var x = a + b;
		  var bv = x - a;
		  var av = x - bv;
		  var br = b - bv;
		  var ar = a - av;
		  var y = ar + br;
		  if (y) {
		    return [y, x];
		  }
		  return [x];
		}
	
		function linearExpansionSum(e, f) {
		  var ne = e.length | 0;
		  var nf = f.length | 0;
		  if (ne === 1 && nf === 1) {
		    return scalarScalar(e[0], f[0]);
		  }
		  var n = ne + nf;
		  var g = new Array(n);
		  var count = 0;
		  var eptr = 0;
		  var fptr = 0;
		  var abs = Math.abs;
		  var ei = e[eptr];
		  var ea = abs(ei);
		  var fi = f[fptr];
		  var fa = abs(fi);
		  var a, b;
		  if (ea < fa) {
		    b = ei;
		    eptr += 1;
		    if (eptr < ne) {
		      ei = e[eptr];
		      ea = abs(ei);
		    }
		  } else {
		    b = fi;
		    fptr += 1;
		    if (fptr < nf) {
		      fi = f[fptr];
		      fa = abs(fi);
		    }
		  }
		  if (eptr < ne && ea < fa || fptr >= nf) {
		    a = ei;
		    eptr += 1;
		    if (eptr < ne) {
		      ei = e[eptr];
		      ea = abs(ei);
		    }
		  } else {
		    a = fi;
		    fptr += 1;
		    if (fptr < nf) {
		      fi = f[fptr];
		      fa = abs(fi);
		    }
		  }
		  var x = a + b;
		  var bv = x - a;
		  var y = b - bv;
		  var q0 = y;
		  var q1 = x;
		  var _x, _bv, _av, _br, _ar;
		  while (eptr < ne && fptr < nf) {
		    if (ea < fa) {
		      a = ei;
		      eptr += 1;
		      if (eptr < ne) {
		        ei = e[eptr];
		        ea = abs(ei);
		      }
		    } else {
		      a = fi;
		      fptr += 1;
		      if (fptr < nf) {
		        fi = f[fptr];
		        fa = abs(fi);
		      }
		    }
		    b = q0;
		    x = a + b;
		    bv = x - a;
		    y = b - bv;
		    if (y) {
		      g[count++] = y;
		    }
		    _x = q1 + x;
		    _bv = _x - q1;
		    _av = _x - _bv;
		    _br = x - _bv;
		    _ar = q1 - _av;
		    q0 = _ar + _br;
		    q1 = _x;
		  }
		  while (eptr < ne) {
		    a = ei;
		    b = q0;
		    x = a + b;
		    bv = x - a;
		    y = b - bv;
		    if (y) {
		      g[count++] = y;
		    }
		    _x = q1 + x;
		    _bv = _x - q1;
		    _av = _x - _bv;
		    _br = x - _bv;
		    _ar = q1 - _av;
		    q0 = _ar + _br;
		    q1 = _x;
		    eptr += 1;
		    if (eptr < ne) {
		      ei = e[eptr];
		    }
		  }
		  while (fptr < nf) {
		    a = fi;
		    b = q0;
		    x = a + b;
		    bv = x - a;
		    y = b - bv;
		    if (y) {
		      g[count++] = y;
		    }
		    _x = q1 + x;
		    _bv = _x - q1;
		    _av = _x - _bv;
		    _br = x - _bv;
		    _ar = q1 - _av;
		    q0 = _ar + _br;
		    q1 = _x;
		    fptr += 1;
		    if (fptr < nf) {
		      fi = f[fptr];
		    }
		  }
		  if (q0) {
		    g[count++] = q0;
		  }
		  if (q1) {
		    g[count++] = q1;
		  }
		  if (!count) {
		    g[count++] = 0.0;
		  }
		  g.length = count;
		  return g;
		}
	
	/***/ }),
	/* 34 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var twoProduct = __webpack_require__(32);
		var twoSum = __webpack_require__(35);
	
		module.exports = scaleLinearExpansion;
	
		function scaleLinearExpansion(e, scale) {
		  var n = e.length;
		  if (n === 1) {
		    var ts = twoProduct(e[0], scale);
		    if (ts[0]) {
		      return ts;
		    }
		    return [ts[1]];
		  }
		  var g = new Array(2 * n);
		  var q = [0.1, 0.1];
		  var t = [0.1, 0.1];
		  var count = 0;
		  twoProduct(e[0], scale, q);
		  if (q[0]) {
		    g[count++] = q[0];
		  }
		  for (var i = 1; i < n; ++i) {
		    twoProduct(e[i], scale, t);
		    var pq = q[1];
		    twoSum(pq, t[0], q);
		    if (q[0]) {
		      g[count++] = q[0];
		    }
		    var a = t[1];
		    var b = q[1];
		    var x = a + b;
		    var bv = x - a;
		    var y = b - bv;
		    q[1] = x;
		    if (y) {
		      g[count++] = y;
		    }
		  }
		  if (q[1]) {
		    g[count++] = q[1];
		  }
		  if (count === 0) {
		    g[count++] = 0.0;
		  }
		  g.length = count;
		  return g;
		}
	
	/***/ }),
	/* 35 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = fastTwoSum;
	
		function fastTwoSum(a, b, result) {
			var x = a + b;
			var bv = x - a;
			var av = x - bv;
			var br = b - bv;
			var ar = a - av;
			if (result) {
				result[0] = ar + br;
				result[1] = x;
				return result;
			}
			return [ar + br, x];
		}
	
	/***/ }),
	/* 36 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = robustSubtract;
	
		//Easy case: Add two scalars
		function scalarScalar(a, b) {
		  var x = a + b;
		  var bv = x - a;
		  var av = x - bv;
		  var br = b - bv;
		  var ar = a - av;
		  var y = ar + br;
		  if (y) {
		    return [y, x];
		  }
		  return [x];
		}
	
		function robustSubtract(e, f) {
		  var ne = e.length | 0;
		  var nf = f.length | 0;
		  if (ne === 1 && nf === 1) {
		    return scalarScalar(e[0], -f[0]);
		  }
		  var n = ne + nf;
		  var g = new Array(n);
		  var count = 0;
		  var eptr = 0;
		  var fptr = 0;
		  var abs = Math.abs;
		  var ei = e[eptr];
		  var ea = abs(ei);
		  var fi = -f[fptr];
		  var fa = abs(fi);
		  var a, b;
		  if (ea < fa) {
		    b = ei;
		    eptr += 1;
		    if (eptr < ne) {
		      ei = e[eptr];
		      ea = abs(ei);
		    }
		  } else {
		    b = fi;
		    fptr += 1;
		    if (fptr < nf) {
		      fi = -f[fptr];
		      fa = abs(fi);
		    }
		  }
		  if (eptr < ne && ea < fa || fptr >= nf) {
		    a = ei;
		    eptr += 1;
		    if (eptr < ne) {
		      ei = e[eptr];
		      ea = abs(ei);
		    }
		  } else {
		    a = fi;
		    fptr += 1;
		    if (fptr < nf) {
		      fi = -f[fptr];
		      fa = abs(fi);
		    }
		  }
		  var x = a + b;
		  var bv = x - a;
		  var y = b - bv;
		  var q0 = y;
		  var q1 = x;
		  var _x, _bv, _av, _br, _ar;
		  while (eptr < ne && fptr < nf) {
		    if (ea < fa) {
		      a = ei;
		      eptr += 1;
		      if (eptr < ne) {
		        ei = e[eptr];
		        ea = abs(ei);
		      }
		    } else {
		      a = fi;
		      fptr += 1;
		      if (fptr < nf) {
		        fi = -f[fptr];
		        fa = abs(fi);
		      }
		    }
		    b = q0;
		    x = a + b;
		    bv = x - a;
		    y = b - bv;
		    if (y) {
		      g[count++] = y;
		    }
		    _x = q1 + x;
		    _bv = _x - q1;
		    _av = _x - _bv;
		    _br = x - _bv;
		    _ar = q1 - _av;
		    q0 = _ar + _br;
		    q1 = _x;
		  }
		  while (eptr < ne) {
		    a = ei;
		    b = q0;
		    x = a + b;
		    bv = x - a;
		    y = b - bv;
		    if (y) {
		      g[count++] = y;
		    }
		    _x = q1 + x;
		    _bv = _x - q1;
		    _av = _x - _bv;
		    _br = x - _bv;
		    _ar = q1 - _av;
		    q0 = _ar + _br;
		    q1 = _x;
		    eptr += 1;
		    if (eptr < ne) {
		      ei = e[eptr];
		    }
		  }
		  while (fptr < nf) {
		    a = fi;
		    b = q0;
		    x = a + b;
		    bv = x - a;
		    y = b - bv;
		    if (y) {
		      g[count++] = y;
		    }
		    _x = q1 + x;
		    _bv = _x - q1;
		    _av = _x - _bv;
		    _br = x - _bv;
		    _ar = q1 - _av;
		    q0 = _ar + _br;
		    q1 = _x;
		    fptr += 1;
		    if (fptr < nf) {
		      fi = -f[fptr];
		    }
		  }
		  if (q0) {
		    g[count++] = q0;
		  }
		  if (q1) {
		    g[count++] = q1;
		  }
		  if (!count) {
		    g[count++] = 0.0;
		  }
		  g.length = count;
		  return g;
		}
	
	/***/ }),
	/* 37 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";"use restrict";
	
		var bits = __webpack_require__(38),
		    UnionFind = __webpack_require__(39);
	
		//Returns the dimension of a cell complex
		function dimension(cells) {
		  var d = 0,
		      max = Math.max;
		  for (var i = 0, il = cells.length; i < il; ++i) {
		    d = max(d, cells[i].length);
		  }
		  return d - 1;
		}
		exports.dimension = dimension;
	
		//Counts the number of vertices in faces
		function countVertices(cells) {
		  var vc = -1,
		      max = Math.max;
		  for (var i = 0, il = cells.length; i < il; ++i) {
		    var c = cells[i];
		    for (var j = 0, jl = c.length; j < jl; ++j) {
		      vc = max(vc, c[j]);
		    }
		  }
		  return vc + 1;
		}
		exports.countVertices = countVertices;
	
		//Returns a deep copy of cells
		function cloneCells(cells) {
		  var ncells = new Array(cells.length);
		  for (var i = 0, il = cells.length; i < il; ++i) {
		    ncells[i] = cells[i].slice(0);
		  }
		  return ncells;
		}
		exports.cloneCells = cloneCells;
	
		//Ranks a pair of cells up to permutation
		function compareCells(a, b) {
		  var n = a.length,
		      t = a.length - b.length,
		      min = Math.min;
		  if (t) {
		    return t;
		  }
		  switch (n) {
		    case 0:
		      return 0;
		    case 1:
		      return a[0] - b[0];
		    case 2:
		      var d = a[0] + a[1] - b[0] - b[1];
		      if (d) {
		        return d;
		      }
		      return min(a[0], a[1]) - min(b[0], b[1]);
		    case 3:
		      var l1 = a[0] + a[1],
		          m1 = b[0] + b[1];
		      d = l1 + a[2] - (m1 + b[2]);
		      if (d) {
		        return d;
		      }
		      var l0 = min(a[0], a[1]),
		          m0 = min(b[0], b[1]),
		          d = min(l0, a[2]) - min(m0, b[2]);
		      if (d) {
		        return d;
		      }
		      return min(l0 + a[2], l1) - min(m0 + b[2], m1);
	
		    //TODO: Maybe optimize n=4 as well?
	
		    default:
		      var as = a.slice(0);
		      as.sort();
		      var bs = b.slice(0);
		      bs.sort();
		      for (var i = 0; i < n; ++i) {
		        t = as[i] - bs[i];
		        if (t) {
		          return t;
		        }
		      }
		      return 0;
		  }
		}
		exports.compareCells = compareCells;
	
		function compareZipped(a, b) {
		  return compareCells(a[0], b[0]);
		}
	
		//Puts a cell complex into normal order for the purposes of findCell queries
		function normalize(cells, attr) {
		  if (attr) {
		    var len = cells.length;
		    var zipped = new Array(len);
		    for (var i = 0; i < len; ++i) {
		      zipped[i] = [cells[i], attr[i]];
		    }
		    zipped.sort(compareZipped);
		    for (var i = 0; i < len; ++i) {
		      cells[i] = zipped[i][0];
		      attr[i] = zipped[i][1];
		    }
		    return cells;
		  } else {
		    cells.sort(compareCells);
		    return cells;
		  }
		}
		exports.normalize = normalize;
	
		//Removes all duplicate cells in the complex
		function unique(cells) {
		  if (cells.length === 0) {
		    return [];
		  }
		  var ptr = 1,
		      len = cells.length;
		  for (var i = 1; i < len; ++i) {
		    var a = cells[i];
		    if (compareCells(a, cells[i - 1])) {
		      if (i === ptr) {
		        ptr++;
		        continue;
		      }
		      cells[ptr++] = a;
		    }
		  }
		  cells.length = ptr;
		  return cells;
		}
		exports.unique = unique;
	
		//Finds a cell in a normalized cell complex
		function findCell(cells, c) {
		  var lo = 0,
		      hi = cells.length - 1,
		      r = -1;
		  while (lo <= hi) {
		    var mid = lo + hi >> 1,
		        s = compareCells(cells[mid], c);
		    if (s <= 0) {
		      if (s === 0) {
		        r = mid;
		      }
		      lo = mid + 1;
		    } else if (s > 0) {
		      hi = mid - 1;
		    }
		  }
		  return r;
		}
		exports.findCell = findCell;
	
		//Builds an index for an n-cell.  This is more general than dual, but less efficient
		function incidence(from_cells, to_cells) {
		  var index = new Array(from_cells.length);
		  for (var i = 0, il = index.length; i < il; ++i) {
		    index[i] = [];
		  }
		  var b = [];
		  for (var i = 0, n = to_cells.length; i < n; ++i) {
		    var c = to_cells[i];
		    var cl = c.length;
		    for (var k = 1, kn = 1 << cl; k < kn; ++k) {
		      b.length = bits.popCount(k);
		      var l = 0;
		      for (var j = 0; j < cl; ++j) {
		        if (k & 1 << j) {
		          b[l++] = c[j];
		        }
		      }
		      var idx = findCell(from_cells, b);
		      if (idx < 0) {
		        continue;
		      }
		      while (true) {
		        index[idx++].push(i);
		        if (idx >= from_cells.length || compareCells(from_cells[idx], b) !== 0) {
		          break;
		        }
		      }
		    }
		  }
		  return index;
		}
		exports.incidence = incidence;
	
		//Computes the dual of the mesh.  This is basically an optimized version of buildIndex for the situation where from_cells is just the list of vertices
		function dual(cells, vertex_count) {
		  if (!vertex_count) {
		    return incidence(unique(skeleton(cells, 0)), cells, 0);
		  }
		  var res = new Array(vertex_count);
		  for (var i = 0; i < vertex_count; ++i) {
		    res[i] = [];
		  }
		  for (var i = 0, len = cells.length; i < len; ++i) {
		    var c = cells[i];
		    for (var j = 0, cl = c.length; j < cl; ++j) {
		      res[c[j]].push(i);
		    }
		  }
		  return res;
		}
		exports.dual = dual;
	
		//Enumerates all cells in the complex
		function explode(cells) {
		  var result = [];
		  for (var i = 0, il = cells.length; i < il; ++i) {
		    var c = cells[i],
		        cl = c.length | 0;
		    for (var j = 1, jl = 1 << cl; j < jl; ++j) {
		      var b = [];
		      for (var k = 0; k < cl; ++k) {
		        if (j >>> k & 1) {
		          b.push(c[k]);
		        }
		      }
		      result.push(b);
		    }
		  }
		  return normalize(result);
		}
		exports.explode = explode;
	
		//Enumerates all of the n-cells of a cell complex
		function skeleton(cells, n) {
		  if (n < 0) {
		    return [];
		  }
		  var result = [],
		      k0 = (1 << n + 1) - 1;
		  for (var i = 0; i < cells.length; ++i) {
		    var c = cells[i];
		    for (var k = k0; k < 1 << c.length; k = bits.nextCombination(k)) {
		      var b = new Array(n + 1),
		          l = 0;
		      for (var j = 0; j < c.length; ++j) {
		        if (k & 1 << j) {
		          b[l++] = c[j];
		        }
		      }
		      result.push(b);
		    }
		  }
		  return normalize(result);
		}
		exports.skeleton = skeleton;
	
		//Computes the boundary of all cells, does not remove duplicates
		function boundary(cells) {
		  var res = [];
		  for (var i = 0, il = cells.length; i < il; ++i) {
		    var c = cells[i];
		    for (var j = 0, cl = c.length; j < cl; ++j) {
		      var b = new Array(c.length - 1);
		      for (var k = 0, l = 0; k < cl; ++k) {
		        if (k !== j) {
		          b[l++] = c[k];
		        }
		      }
		      res.push(b);
		    }
		  }
		  return normalize(res);
		}
		exports.boundary = boundary;
	
		//Computes connected components for a dense cell complex
		function connectedComponents_dense(cells, vertex_count) {
		  var labels = new UnionFind(vertex_count);
		  for (var i = 0; i < cells.length; ++i) {
		    var c = cells[i];
		    for (var j = 0; j < c.length; ++j) {
		      for (var k = j + 1; k < c.length; ++k) {
		        labels.link(c[j], c[k]);
		      }
		    }
		  }
		  var components = [],
		      component_labels = labels.ranks;
		  for (var i = 0; i < component_labels.length; ++i) {
		    component_labels[i] = -1;
		  }
		  for (var i = 0; i < cells.length; ++i) {
		    var l = labels.find(cells[i][0]);
		    if (component_labels[l] < 0) {
		      component_labels[l] = components.length;
		      components.push([cells[i].slice(0)]);
		    } else {
		      components[component_labels[l]].push(cells[i].slice(0));
		    }
		  }
		  return components;
		}
	
		//Computes connected components for a sparse graph
		function connectedComponents_sparse(cells) {
		  var vertices = unique(normalize(skeleton(cells, 0))),
		      labels = new UnionFind(vertices.length);
		  for (var i = 0; i < cells.length; ++i) {
		    var c = cells[i];
		    for (var j = 0; j < c.length; ++j) {
		      var vj = findCell(vertices, [c[j]]);
		      for (var k = j + 1; k < c.length; ++k) {
		        labels.link(vj, findCell(vertices, [c[k]]));
		      }
		    }
		  }
		  var components = [],
		      component_labels = labels.ranks;
		  for (var i = 0; i < component_labels.length; ++i) {
		    component_labels[i] = -1;
		  }
		  for (var i = 0; i < cells.length; ++i) {
		    var l = labels.find(findCell(vertices, [cells[i][0]]));
		    if (component_labels[l] < 0) {
		      component_labels[l] = components.length;
		      components.push([cells[i].slice(0)]);
		    } else {
		      components[component_labels[l]].push(cells[i].slice(0));
		    }
		  }
		  return components;
		}
	
		//Computes connected components for a cell complex
		function connectedComponents(cells, vertex_count) {
		  if (vertex_count) {
		    return connectedComponents_dense(cells, vertex_count);
		  }
		  return connectedComponents_sparse(cells);
		}
		exports.connectedComponents = connectedComponents;
	
	/***/ }),
	/* 38 */
	/***/ (function(module, exports) {
	
		/**
		 * Bit twiddling hacks for JavaScript.
		 *
		 * Author: Mikola Lysenko
		 *
		 * Ported from Stanford bit twiddling hack library:
		 *    http://graphics.stanford.edu/~seander/bithacks.html
		 */
	
		"use strict";"use restrict";
	
		//Number of bits in an integer
	
		var INT_BITS = 32;
	
		//Constants
		exports.INT_BITS = INT_BITS;
		exports.INT_MAX = 0x7fffffff;
		exports.INT_MIN = -1 << INT_BITS - 1;
	
		//Returns -1, 0, +1 depending on sign of x
		exports.sign = function (v) {
		  return (v > 0) - (v < 0);
		};
	
		//Computes absolute value of integer
		exports.abs = function (v) {
		  var mask = v >> INT_BITS - 1;
		  return (v ^ mask) - mask;
		};
	
		//Computes minimum of integers x and y
		exports.min = function (x, y) {
		  return y ^ (x ^ y) & -(x < y);
		};
	
		//Computes maximum of integers x and y
		exports.max = function (x, y) {
		  return x ^ (x ^ y) & -(x < y);
		};
	
		//Checks if a number is a power of two
		exports.isPow2 = function (v) {
		  return !(v & v - 1) && !!v;
		};
	
		//Computes log base 2 of v
		exports.log2 = function (v) {
		  var r, shift;
		  r = (v > 0xFFFF) << 4;v >>>= r;
		  shift = (v > 0xFF) << 3;v >>>= shift;r |= shift;
		  shift = (v > 0xF) << 2;v >>>= shift;r |= shift;
		  shift = (v > 0x3) << 1;v >>>= shift;r |= shift;
		  return r | v >> 1;
		};
	
		//Computes log base 10 of v
		exports.log10 = function (v) {
		  return v >= 1000000000 ? 9 : v >= 100000000 ? 8 : v >= 10000000 ? 7 : v >= 1000000 ? 6 : v >= 100000 ? 5 : v >= 10000 ? 4 : v >= 1000 ? 3 : v >= 100 ? 2 : v >= 10 ? 1 : 0;
		};
	
		//Counts number of bits
		exports.popCount = function (v) {
		  v = v - (v >>> 1 & 0x55555555);
		  v = (v & 0x33333333) + (v >>> 2 & 0x33333333);
		  return (v + (v >>> 4) & 0xF0F0F0F) * 0x1010101 >>> 24;
		};
	
		//Counts number of trailing zeros
		function countTrailingZeros(v) {
		  var c = 32;
		  v &= -v;
		  if (v) c--;
		  if (v & 0x0000FFFF) c -= 16;
		  if (v & 0x00FF00FF) c -= 8;
		  if (v & 0x0F0F0F0F) c -= 4;
		  if (v & 0x33333333) c -= 2;
		  if (v & 0x55555555) c -= 1;
		  return c;
		}
		exports.countTrailingZeros = countTrailingZeros;
	
		//Rounds to next power of 2
		exports.nextPow2 = function (v) {
		  v += v === 0;
		  --v;
		  v |= v >>> 1;
		  v |= v >>> 2;
		  v |= v >>> 4;
		  v |= v >>> 8;
		  v |= v >>> 16;
		  return v + 1;
		};
	
		//Rounds down to previous power of 2
		exports.prevPow2 = function (v) {
		  v |= v >>> 1;
		  v |= v >>> 2;
		  v |= v >>> 4;
		  v |= v >>> 8;
		  v |= v >>> 16;
		  return v - (v >>> 1);
		};
	
		//Computes parity of word
		exports.parity = function (v) {
		  v ^= v >>> 16;
		  v ^= v >>> 8;
		  v ^= v >>> 4;
		  v &= 0xf;
		  return 0x6996 >>> v & 1;
		};
	
		var REVERSE_TABLE = new Array(256);
	
		(function (tab) {
		  for (var i = 0; i < 256; ++i) {
		    var v = i,
		        r = i,
		        s = 7;
		    for (v >>>= 1; v; v >>>= 1) {
		      r <<= 1;
		      r |= v & 1;
		      --s;
		    }
		    tab[i] = r << s & 0xff;
		  }
		})(REVERSE_TABLE);
	
		//Reverse bits in a 32 bit word
		exports.reverse = function (v) {
		  return REVERSE_TABLE[v & 0xff] << 24 | REVERSE_TABLE[v >>> 8 & 0xff] << 16 | REVERSE_TABLE[v >>> 16 & 0xff] << 8 | REVERSE_TABLE[v >>> 24 & 0xff];
		};
	
		//Interleave bits of 2 coordinates with 16 bits.  Useful for fast quadtree codes
		exports.interleave2 = function (x, y) {
		  x &= 0xFFFF;
		  x = (x | x << 8) & 0x00FF00FF;
		  x = (x | x << 4) & 0x0F0F0F0F;
		  x = (x | x << 2) & 0x33333333;
		  x = (x | x << 1) & 0x55555555;
	
		  y &= 0xFFFF;
		  y = (y | y << 8) & 0x00FF00FF;
		  y = (y | y << 4) & 0x0F0F0F0F;
		  y = (y | y << 2) & 0x33333333;
		  y = (y | y << 1) & 0x55555555;
	
		  return x | y << 1;
		};
	
		//Extracts the nth interleaved component
		exports.deinterleave2 = function (v, n) {
		  v = v >>> n & 0x55555555;
		  v = (v | v >>> 1) & 0x33333333;
		  v = (v | v >>> 2) & 0x0F0F0F0F;
		  v = (v | v >>> 4) & 0x00FF00FF;
		  v = (v | v >>> 16) & 0x000FFFF;
		  return v << 16 >> 16;
		};
	
		//Interleave bits of 3 coordinates, each with 10 bits.  Useful for fast octree codes
		exports.interleave3 = function (x, y, z) {
		  x &= 0x3FF;
		  x = (x | x << 16) & 4278190335;
		  x = (x | x << 8) & 251719695;
		  x = (x | x << 4) & 3272356035;
		  x = (x | x << 2) & 1227133513;
	
		  y &= 0x3FF;
		  y = (y | y << 16) & 4278190335;
		  y = (y | y << 8) & 251719695;
		  y = (y | y << 4) & 3272356035;
		  y = (y | y << 2) & 1227133513;
		  x |= y << 1;
	
		  z &= 0x3FF;
		  z = (z | z << 16) & 4278190335;
		  z = (z | z << 8) & 251719695;
		  z = (z | z << 4) & 3272356035;
		  z = (z | z << 2) & 1227133513;
	
		  return x | z << 2;
		};
	
		//Extracts nth interleaved component of a 3-tuple
		exports.deinterleave3 = function (v, n) {
		  v = v >>> n & 1227133513;
		  v = (v | v >>> 2) & 3272356035;
		  v = (v | v >>> 4) & 251719695;
		  v = (v | v >>> 8) & 4278190335;
		  v = (v | v >>> 16) & 0x3FF;
		  return v << 22 >> 22;
		};
	
		//Computes next combination in colexicographic order (this is mistakenly called nextPermutation on the bit twiddling hacks page)
		exports.nextCombination = function (v) {
		  var t = v | v - 1;
		  return t + 1 | (~t & -~t) - 1 >>> countTrailingZeros(v) + 1;
		};
	
	/***/ }),
	/* 39 */
	/***/ (function(module, exports) {
	
		"use strict";"use restrict";
	
		module.exports = UnionFind;
	
		function UnionFind(count) {
		  this.roots = new Array(count);
		  this.ranks = new Array(count);
	
		  for (var i = 0; i < count; ++i) {
		    this.roots[i] = i;
		    this.ranks[i] = 0;
		  }
		}
	
		UnionFind.prototype.length = function () {
		  return this.roots.length;
		};
	
		UnionFind.prototype.makeSet = function () {
		  var n = this.roots.length;
		  this.roots.push(n);
		  this.ranks.push(0);
		  return n;
		};
	
		UnionFind.prototype.find = function (x) {
		  var roots = this.roots;
		  while (roots[x] !== x) {
		    var y = roots[x];
		    roots[x] = roots[y];
		    x = y;
		  }
		  return x;
		};
	
		UnionFind.prototype.link = function (x, y) {
		  var xr = this.find(x),
		      yr = this.find(y);
		  if (xr === yr) {
		    return;
		  }
		  var ranks = this.ranks,
		      roots = this.roots,
		      xd = ranks[xr],
		      yd = ranks[yr];
		  if (xd < yd) {
		    roots[xr] = yr;
		  } else if (yd < xd) {
		    roots[yr] = xr;
		  } else {
		    roots[yr] = xr;
		    ++ranks[xr];
		  }
		};
	
	/***/ }),
	/* 40 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		module.exports = cleanPSLG;
	
		var UnionFind = __webpack_require__(41);
		var boxIntersect = __webpack_require__(42);
		var segseg = __webpack_require__(49);
		var rat = __webpack_require__(50);
		var ratCmp = __webpack_require__(62);
		var ratToFloat = __webpack_require__(63);
		var ratVec = __webpack_require__(66);
		var nextafter = __webpack_require__(67);
	
		var solveIntersection = __webpack_require__(68);
	
		// Bounds on a rational number when rounded to a float
		function boundRat(r) {
		  var f = ratToFloat(r);
		  return [nextafter(f, -Infinity), nextafter(f, Infinity)];
		}
	
		// Convert a list of edges in a pslg to bounding boxes
		function boundEdges(points, edges) {
		  var bounds = new Array(edges.length);
		  for (var i = 0; i < edges.length; ++i) {
		    var e = edges[i];
		    var a = points[e[0]];
		    var b = points[e[1]];
		    bounds[i] = [nextafter(Math.min(a[0], b[0]), -Infinity), nextafter(Math.min(a[1], b[1]), -Infinity), nextafter(Math.max(a[0], b[0]), Infinity), nextafter(Math.max(a[1], b[1]), Infinity)];
		  }
		  return bounds;
		}
	
		// Convert a list of points into bounding boxes by duplicating coords
		function boundPoints(points) {
		  var bounds = new Array(points.length);
		  for (var i = 0; i < points.length; ++i) {
		    var p = points[i];
		    bounds[i] = [nextafter(p[0], -Infinity), nextafter(p[1], -Infinity), nextafter(p[0], Infinity), nextafter(p[1], Infinity)];
		  }
		  return bounds;
		}
	
		// Find all pairs of crossing edges in a pslg (given edge bounds)
		function getCrossings(points, edges, edgeBounds) {
		  var result = [];
		  boxIntersect(edgeBounds, function (i, j) {
		    var e = edges[i];
		    var f = edges[j];
		    if (e[0] === f[0] || e[0] === f[1] || e[1] === f[0] || e[1] === f[1]) {
		      return;
		    }
		    var a = points[e[0]];
		    var b = points[e[1]];
		    var c = points[f[0]];
		    var d = points[f[1]];
		    if (segseg(a, b, c, d)) {
		      result.push([i, j]);
		    }
		  });
		  return result;
		}
	
		// Find all pairs of crossing vertices in a pslg (given edge/vert bounds)
		function getTJunctions(points, edges, edgeBounds, vertBounds) {
		  var result = [];
		  boxIntersect(edgeBounds, vertBounds, function (i, v) {
		    var e = edges[i];
		    if (e[0] === v || e[1] === v) {
		      return;
		    }
		    var p = points[v];
		    var a = points[e[0]];
		    var b = points[e[1]];
		    if (segseg(a, b, p, p)) {
		      result.push([i, v]);
		    }
		  });
		  return result;
		}
	
		// Cut edges along crossings/tjunctions
		function cutEdges(floatPoints, edges, crossings, junctions, useColor) {
		  var i, e;
	
		  // Convert crossings into tjunctions by constructing rational points
		  var ratPoints = floatPoints.map(function (p) {
		    return [rat(p[0]), rat(p[1])];
		  });
		  for (i = 0; i < crossings.length; ++i) {
		    var crossing = crossings[i];
		    e = crossing[0];
		    var f = crossing[1];
		    var ee = edges[e];
		    var ef = edges[f];
		    var x = solveIntersection(ratVec(floatPoints[ee[0]]), ratVec(floatPoints[ee[1]]), ratVec(floatPoints[ef[0]]), ratVec(floatPoints[ef[1]]));
		    if (!x) {
		      // Segments are parallel, should already be handled by t-junctions
		      continue;
		    }
		    var idx = floatPoints.length;
		    floatPoints.push([ratToFloat(x[0]), ratToFloat(x[1])]);
		    ratPoints.push(x);
		    junctions.push([e, idx], [f, idx]);
		  }
	
		  // Sort tjunctions
		  junctions.sort(function (a, b) {
		    if (a[0] !== b[0]) {
		      return a[0] - b[0];
		    }
		    var u = ratPoints[a[1]];
		    var v = ratPoints[b[1]];
		    return ratCmp(u[0], v[0]) || ratCmp(u[1], v[1]);
		  });
	
		  // Split edges along junctions
		  for (i = junctions.length - 1; i >= 0; --i) {
		    var junction = junctions[i];
		    e = junction[0];
	
		    var edge = edges[e];
		    var s = edge[0];
		    var t = edge[1];
	
		    // Check if edge is not lexicographically sorted
		    var a = floatPoints[s];
		    var b = floatPoints[t];
		    if ((a[0] - b[0] || a[1] - b[1]) < 0) {
		      var tmp = s;
		      s = t;
		      t = tmp;
		    }
	
		    // Split leading edge
		    edge[0] = s;
		    var last = edge[1] = junction[1];
	
		    // If we are grouping edges by color, remember to track data
		    var color;
		    if (useColor) {
		      color = edge[2];
		    }
	
		    // Split other edges
		    while (i > 0 && junctions[i - 1][0] === e) {
		      var junction = junctions[--i];
		      var next = junction[1];
		      if (useColor) {
		        edges.push([last, next, color]);
		      } else {
		        edges.push([last, next]);
		      }
		      last = next;
		    }
	
		    // Add final edge
		    if (useColor) {
		      edges.push([last, t, color]);
		    } else {
		      edges.push([last, t]);
		    }
		  }
	
		  // Return constructed rational points
		  return ratPoints;
		}
	
		// Merge overlapping points
		function dedupPoints(floatPoints, ratPoints, floatBounds) {
		  var numPoints = ratPoints.length;
		  var uf = new UnionFind(numPoints);
	
		  // Compute rational bounds
		  var bounds = [];
		  for (var i = 0; i < ratPoints.length; ++i) {
		    var p = ratPoints[i];
		    var xb = boundRat(p[0]);
		    var yb = boundRat(p[1]);
		    bounds.push([nextafter(xb[0], -Infinity), nextafter(yb[0], -Infinity), nextafter(xb[1], Infinity), nextafter(yb[1], Infinity)]);
		  }
	
		  // Link all points with over lapping boxes
		  boxIntersect(bounds, function (i, j) {
		    uf.link(i, j);
		  });
	
		  // Do 1 pass over points to combine points in label sets
		  var noDupes = true;
		  var labels = new Array(numPoints);
		  for (var i = 0; i < numPoints; ++i) {
		    var j = uf.find(i);
		    if (j !== i) {
		      // Clear no-dupes flag, zero out label
		      noDupes = false;
		      // Make each point the top-left point from its cell
		      floatPoints[j] = [Math.min(floatPoints[i][0], floatPoints[j][0]), Math.min(floatPoints[i][1], floatPoints[j][1])];
		    }
		  }
	
		  // If no duplicates, return null to signal termination
		  if (noDupes) {
		    return null;
		  }
	
		  var ptr = 0;
		  for (var i = 0; i < numPoints; ++i) {
		    var j = uf.find(i);
		    if (j === i) {
		      labels[i] = ptr;
		      floatPoints[ptr++] = floatPoints[i];
		    } else {
		      labels[i] = -1;
		    }
		  }
	
		  floatPoints.length = ptr;
	
		  // Do a second pass to fix up missing labels
		  for (var i = 0; i < numPoints; ++i) {
		    if (labels[i] < 0) {
		      labels[i] = labels[uf.find(i)];
		    }
		  }
	
		  // Return resulting union-find data structure
		  return labels;
		}
	
		function compareLex2(a, b) {
		  return a[0] - b[0] || a[1] - b[1];
		}
		function compareLex3(a, b) {
		  var d = a[0] - b[0] || a[1] - b[1];
		  if (d) {
		    return d;
		  }
		  if (a[2] < b[2]) {
		    return -1;
		  } else if (a[2] > b[2]) {
		    return 1;
		  }
		  return 0;
		}
	
		// Remove duplicate edge labels
		function dedupEdges(edges, labels, useColor) {
		  if (edges.length === 0) {
		    return;
		  }
		  if (labels) {
		    for (var i = 0; i < edges.length; ++i) {
		      var e = edges[i];
		      var a = labels[e[0]];
		      var b = labels[e[1]];
		      e[0] = Math.min(a, b);
		      e[1] = Math.max(a, b);
		    }
		  } else {
		    for (var i = 0; i < edges.length; ++i) {
		      var e = edges[i];
		      var a = e[0];
		      var b = e[1];
		      e[0] = Math.min(a, b);
		      e[1] = Math.max(a, b);
		    }
		  }
		  if (useColor) {
		    edges.sort(compareLex3);
		  } else {
		    edges.sort(compareLex2);
		  }
		  var ptr = 1;
		  for (var i = 1; i < edges.length; ++i) {
		    var prev = edges[i - 1];
		    var next = edges[i];
		    if (next[0] === prev[0] && next[1] === prev[1] && (!useColor || next[2] === prev[2])) {
		      continue;
		    }
		    edges[ptr++] = next;
		  }
		  edges.length = ptr;
		}
	
		function preRound(points, edges, useColor) {
		  var labels = dedupPoints(points, [], boundPoints(points));
		  dedupEdges(edges, labels, useColor);
		  return !!labels;
		}
	
		// Repeat until convergence
		function snapRound(points, edges, useColor) {
		  // 1. find edge crossings
		  var edgeBounds = boundEdges(points, edges);
		  var crossings = getCrossings(points, edges, edgeBounds);
	
		  // 2. find t-junctions
		  var vertBounds = boundPoints(points);
		  var tjunctions = getTJunctions(points, edges, edgeBounds, vertBounds);
	
		  // 3. cut edges, construct rational points
		  var ratPoints = cutEdges(points, edges, crossings, tjunctions, useColor);
	
		  // 4. dedupe verts
		  var labels = dedupPoints(points, ratPoints, vertBounds);
	
		  // 5. dedupe edges
		  dedupEdges(edges, labels, useColor);
	
		  // 6. check termination
		  if (!labels) {
		    return crossings.length > 0 || tjunctions.length > 0;
		  }
	
		  // More iterations necessary
		  return true;
		}
	
		// Main loop, runs PSLG clean up until completion
		function cleanPSLG(points, edges, colors) {
		  // If using colors, augment edges with color data
		  var prevEdges;
		  if (colors) {
		    prevEdges = edges;
		    var augEdges = new Array(edges.length);
		    for (var i = 0; i < edges.length; ++i) {
		      var e = edges[i];
		      augEdges[i] = [e[0], e[1], colors[i]];
		    }
		    edges = augEdges;
		  }
	
		  // First round: remove duplicate edges and points
		  var modified = preRound(points, edges, !!colors);
	
		  // Run snap rounding until convergence
		  while (snapRound(points, edges, !!colors)) {
		    modified = true;
		  }
	
		  // Strip color tags
		  if (!!colors && modified) {
		    prevEdges.length = 0;
		    colors.length = 0;
		    for (var i = 0; i < edges.length; ++i) {
		      var e = edges[i];
		      prevEdges.push([e[0], e[1]]);
		      colors.push(e[2]);
		    }
		  }
	
		  return modified;
		}
	
	/***/ }),
	/* 41 */
	/***/ (function(module, exports) {
	
		"use strict";"use restrict";
	
		module.exports = UnionFind;
	
		function UnionFind(count) {
		  this.roots = new Array(count);
		  this.ranks = new Array(count);
	
		  for (var i = 0; i < count; ++i) {
		    this.roots[i] = i;
		    this.ranks[i] = 0;
		  }
		}
	
		var proto = UnionFind.prototype;
	
		Object.defineProperty(proto, "length", {
		  "get": function () {
		    return this.roots.length;
		  }
		});
	
		proto.makeSet = function () {
		  var n = this.roots.length;
		  this.roots.push(n);
		  this.ranks.push(0);
		  return n;
		};
	
		proto.find = function (x) {
		  var x0 = x;
		  var roots = this.roots;
		  while (roots[x] !== x) {
		    x = roots[x];
		  }
		  while (roots[x0] !== x) {
		    var y = roots[x0];
		    roots[x0] = x;
		    x0 = y;
		  }
		  return x;
		};
	
		proto.link = function (x, y) {
		  var xr = this.find(x),
		      yr = this.find(y);
		  if (xr === yr) {
		    return;
		  }
		  var ranks = this.ranks,
		      roots = this.roots,
		      xd = ranks[xr],
		      yd = ranks[yr];
		  if (xd < yd) {
		    roots[xr] = yr;
		  } else if (yd < xd) {
		    roots[yr] = xr;
		  } else {
		    roots[yr] = xr;
		    ++ranks[xr];
		  }
		};
	
	/***/ }),
	/* 42 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		module.exports = boxIntersectWrapper;
	
		var pool = __webpack_require__(9);
		var sweep = __webpack_require__(43);
		var boxIntersectIter = __webpack_require__(45);
	
		function boxEmpty(d, box) {
		  for (var j = 0; j < d; ++j) {
		    if (!(box[j] <= box[j + d])) {
		      return true;
		    }
		  }
		  return false;
		}
	
		//Unpack boxes into a flat typed array, remove empty boxes
		function convertBoxes(boxes, d, data, ids) {
		  var ptr = 0;
		  var count = 0;
		  for (var i = 0, n = boxes.length; i < n; ++i) {
		    var b = boxes[i];
		    if (boxEmpty(d, b)) {
		      continue;
		    }
		    for (var j = 0; j < 2 * d; ++j) {
		      data[ptr++] = b[j];
		    }
		    ids[count++] = i;
		  }
		  return count;
		}
	
		//Perform type conversions, check bounds
		function boxIntersect(red, blue, visit, full) {
		  var n = red.length;
		  var m = blue.length;
	
		  //If either array is empty, then we can skip this whole thing
		  if (n <= 0 || m <= 0) {
		    return;
		  }
	
		  //Compute dimension, if it is 0 then we skip
		  var d = red[0].length >>> 1;
		  if (d <= 0) {
		    return;
		  }
	
		  var retval;
	
		  //Convert red boxes
		  var redList = pool.mallocDouble(2 * d * n);
		  var redIds = pool.mallocInt32(n);
		  n = convertBoxes(red, d, redList, redIds);
	
		  if (n > 0) {
		    if (d === 1 && full) {
		      //Special case: 1d complete
		      sweep.init(n);
		      retval = sweep.sweepComplete(d, visit, 0, n, redList, redIds, 0, n, redList, redIds);
		    } else {
	
		      //Convert blue boxes
		      var blueList = pool.mallocDouble(2 * d * m);
		      var blueIds = pool.mallocInt32(m);
		      m = convertBoxes(blue, d, blueList, blueIds);
	
		      if (m > 0) {
		        sweep.init(n + m);
	
		        if (d === 1) {
		          //Special case: 1d bipartite
		          retval = sweep.sweepBipartite(d, visit, 0, n, redList, redIds, 0, m, blueList, blueIds);
		        } else {
		          //General case:  d>1
		          retval = boxIntersectIter(d, visit, full, n, redList, redIds, m, blueList, blueIds);
		        }
	
		        pool.free(blueList);
		        pool.free(blueIds);
		      }
		    }
	
		    pool.free(redList);
		    pool.free(redIds);
		  }
	
		  return retval;
		}
	
		var RESULT;
	
		function appendItem(i, j) {
		  RESULT.push([i, j]);
		}
	
		function intersectFullArray(x) {
		  RESULT = [];
		  boxIntersect(x, x, appendItem, true);
		  return RESULT;
		}
	
		function intersectBipartiteArray(x, y) {
		  RESULT = [];
		  boxIntersect(x, y, appendItem, false);
		  return RESULT;
		}
	
		//User-friendly wrapper, handle full input and no-visitor cases
		function boxIntersectWrapper(arg0, arg1, arg2) {
		  var result;
		  switch (arguments.length) {
		    case 1:
		      return intersectFullArray(arg0);
		    case 2:
		      if (typeof arg1 === 'function') {
		        return boxIntersect(arg0, arg0, arg1, true);
		      } else {
		        return intersectBipartiteArray(arg0, arg1);
		      }
		    case 3:
		      return boxIntersect(arg0, arg1, arg2, false);
		    default:
		      throw new Error('box-intersect: Invalid arguments');
		  }
			}
	
	/***/ }),
	/* 43 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		module.exports = {
		  init: sqInit,
		  sweepBipartite: sweepBipartite,
		  sweepComplete: sweepComplete,
		  scanBipartite: scanBipartite,
		  scanComplete: scanComplete
		};
	
		var pool = __webpack_require__(9);
		var bits = __webpack_require__(14);
		var isort = __webpack_require__(44);
	
		//Flag for blue
		var BLUE_FLAG = 1 << 28;
	
		//1D sweep event queue stuff (use pool to save space)
		var INIT_CAPACITY = 1024;
		var RED_SWEEP_QUEUE = pool.mallocInt32(INIT_CAPACITY);
		var RED_SWEEP_INDEX = pool.mallocInt32(INIT_CAPACITY);
		var BLUE_SWEEP_QUEUE = pool.mallocInt32(INIT_CAPACITY);
		var BLUE_SWEEP_INDEX = pool.mallocInt32(INIT_CAPACITY);
		var COMMON_SWEEP_QUEUE = pool.mallocInt32(INIT_CAPACITY);
		var COMMON_SWEEP_INDEX = pool.mallocInt32(INIT_CAPACITY);
		var SWEEP_EVENTS = pool.mallocDouble(INIT_CAPACITY * 8);
	
		//Reserves memory for the 1D sweep data structures
		function sqInit(count) {
		  var rcount = bits.nextPow2(count);
		  if (RED_SWEEP_QUEUE.length < rcount) {
		    pool.free(RED_SWEEP_QUEUE);
		    RED_SWEEP_QUEUE = pool.mallocInt32(rcount);
		  }
		  if (RED_SWEEP_INDEX.length < rcount) {
		    pool.free(RED_SWEEP_INDEX);
		    RED_SWEEP_INDEX = pool.mallocInt32(rcount);
		  }
		  if (BLUE_SWEEP_QUEUE.length < rcount) {
		    pool.free(BLUE_SWEEP_QUEUE);
		    BLUE_SWEEP_QUEUE = pool.mallocInt32(rcount);
		  }
		  if (BLUE_SWEEP_INDEX.length < rcount) {
		    pool.free(BLUE_SWEEP_INDEX);
		    BLUE_SWEEP_INDEX = pool.mallocInt32(rcount);
		  }
		  if (COMMON_SWEEP_QUEUE.length < rcount) {
		    pool.free(COMMON_SWEEP_QUEUE);
		    COMMON_SWEEP_QUEUE = pool.mallocInt32(rcount);
		  }
		  if (COMMON_SWEEP_INDEX.length < rcount) {
		    pool.free(COMMON_SWEEP_INDEX);
		    COMMON_SWEEP_INDEX = pool.mallocInt32(rcount);
		  }
		  var eventLength = 8 * rcount;
		  if (SWEEP_EVENTS.length < eventLength) {
		    pool.free(SWEEP_EVENTS);
		    SWEEP_EVENTS = pool.mallocDouble(eventLength);
		  }
		}
	
		//Remove an item from the active queue in O(1)
		function sqPop(queue, index, count, item) {
		  var idx = index[item];
		  var top = queue[count - 1];
		  queue[idx] = top;
		  index[top] = idx;
		}
	
		//Insert an item into the active queue in O(1)
		function sqPush(queue, index, count, item) {
		  queue[count] = item;
		  index[item] = count;
		}
	
		//Recursion base case: use 1D sweep algorithm
		function sweepBipartite(d, visit, redStart, redEnd, red, redIndex, blueStart, blueEnd, blue, blueIndex) {
	
		  //store events as pairs [coordinate, idx]
		  //
		  //  red create:  -(idx+1)
		  //  red destroy: idx
		  //  blue create: -(idx+BLUE_FLAG)
		  //  blue destroy: idx+BLUE_FLAG
		  //
		  var ptr = 0;
		  var elemSize = 2 * d;
		  var istart = d - 1;
		  var iend = elemSize - 1;
	
		  for (var i = redStart; i < redEnd; ++i) {
		    var idx = redIndex[i];
		    var redOffset = elemSize * i;
		    SWEEP_EVENTS[ptr++] = red[redOffset + istart];
		    SWEEP_EVENTS[ptr++] = -(idx + 1);
		    SWEEP_EVENTS[ptr++] = red[redOffset + iend];
		    SWEEP_EVENTS[ptr++] = idx;
		  }
	
		  for (var i = blueStart; i < blueEnd; ++i) {
		    var idx = blueIndex[i] + BLUE_FLAG;
		    var blueOffset = elemSize * i;
		    SWEEP_EVENTS[ptr++] = blue[blueOffset + istart];
		    SWEEP_EVENTS[ptr++] = -idx;
		    SWEEP_EVENTS[ptr++] = blue[blueOffset + iend];
		    SWEEP_EVENTS[ptr++] = idx;
		  }
	
		  //process events from left->right
		  var n = ptr >>> 1;
		  isort(SWEEP_EVENTS, n);
	
		  var redActive = 0;
		  var blueActive = 0;
		  for (var i = 0; i < n; ++i) {
		    var e = SWEEP_EVENTS[2 * i + 1] | 0;
		    if (e >= BLUE_FLAG) {
		      //blue destroy event
		      e = e - BLUE_FLAG | 0;
		      sqPop(BLUE_SWEEP_QUEUE, BLUE_SWEEP_INDEX, blueActive--, e);
		    } else if (e >= 0) {
		      //red destroy event
		      sqPop(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive--, e);
		    } else if (e <= -BLUE_FLAG) {
		      //blue create event
		      e = -e - BLUE_FLAG | 0;
		      for (var j = 0; j < redActive; ++j) {
		        var retval = visit(RED_SWEEP_QUEUE[j], e);
		        if (retval !== void 0) {
		          return retval;
		        }
		      }
		      sqPush(BLUE_SWEEP_QUEUE, BLUE_SWEEP_INDEX, blueActive++, e);
		    } else {
		      //red create event
		      e = -e - 1 | 0;
		      for (var j = 0; j < blueActive; ++j) {
		        var retval = visit(e, BLUE_SWEEP_QUEUE[j]);
		        if (retval !== void 0) {
		          return retval;
		        }
		      }
		      sqPush(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive++, e);
		    }
		  }
		}
	
		//Complete sweep
		function sweepComplete(d, visit, redStart, redEnd, red, redIndex, blueStart, blueEnd, blue, blueIndex) {
	
		  var ptr = 0;
		  var elemSize = 2 * d;
		  var istart = d - 1;
		  var iend = elemSize - 1;
	
		  for (var i = redStart; i < redEnd; ++i) {
		    var idx = redIndex[i] + 1 << 1;
		    var redOffset = elemSize * i;
		    SWEEP_EVENTS[ptr++] = red[redOffset + istart];
		    SWEEP_EVENTS[ptr++] = -idx;
		    SWEEP_EVENTS[ptr++] = red[redOffset + iend];
		    SWEEP_EVENTS[ptr++] = idx;
		  }
	
		  for (var i = blueStart; i < blueEnd; ++i) {
		    var idx = blueIndex[i] + 1 << 1;
		    var blueOffset = elemSize * i;
		    SWEEP_EVENTS[ptr++] = blue[blueOffset + istart];
		    SWEEP_EVENTS[ptr++] = -idx | 1;
		    SWEEP_EVENTS[ptr++] = blue[blueOffset + iend];
		    SWEEP_EVENTS[ptr++] = idx | 1;
		  }
	
		  //process events from left->right
		  var n = ptr >>> 1;
		  isort(SWEEP_EVENTS, n);
	
		  var redActive = 0;
		  var blueActive = 0;
		  var commonActive = 0;
		  for (var i = 0; i < n; ++i) {
		    var e = SWEEP_EVENTS[2 * i + 1] | 0;
		    var color = e & 1;
		    if (i < n - 1 && e >> 1 === SWEEP_EVENTS[2 * i + 3] >> 1) {
		      color = 2;
		      i += 1;
		    }
	
		    if (e < 0) {
		      //Create event
		      var id = -(e >> 1) - 1;
	
		      //Intersect with common
		      for (var j = 0; j < commonActive; ++j) {
		        var retval = visit(COMMON_SWEEP_QUEUE[j], id);
		        if (retval !== void 0) {
		          return retval;
		        }
		      }
	
		      if (color !== 0) {
		        //Intersect with red
		        for (var j = 0; j < redActive; ++j) {
		          var retval = visit(RED_SWEEP_QUEUE[j], id);
		          if (retval !== void 0) {
		            return retval;
		          }
		        }
		      }
	
		      if (color !== 1) {
		        //Intersect with blue
		        for (var j = 0; j < blueActive; ++j) {
		          var retval = visit(BLUE_SWEEP_QUEUE[j], id);
		          if (retval !== void 0) {
		            return retval;
		          }
		        }
		      }
	
		      if (color === 0) {
		        //Red
		        sqPush(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive++, id);
		      } else if (color === 1) {
		        //Blue
		        sqPush(BLUE_SWEEP_QUEUE, BLUE_SWEEP_INDEX, blueActive++, id);
		      } else if (color === 2) {
		        //Both
		        sqPush(COMMON_SWEEP_QUEUE, COMMON_SWEEP_INDEX, commonActive++, id);
		      }
		    } else {
		      //Destroy event
		      var id = (e >> 1) - 1;
		      if (color === 0) {
		        //Red
		        sqPop(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive--, id);
		      } else if (color === 1) {
		        //Blue
		        sqPop(BLUE_SWEEP_QUEUE, BLUE_SWEEP_INDEX, blueActive--, id);
		      } else if (color === 2) {
		        //Both
		        sqPop(COMMON_SWEEP_QUEUE, COMMON_SWEEP_INDEX, commonActive--, id);
		      }
		    }
		  }
		}
	
		//Sweep and prune/scanline algorithm:
		//  Scan along axis, detect intersections
		//  Brute force all boxes along axis
		function scanBipartite(d, axis, visit, flip, redStart, redEnd, red, redIndex, blueStart, blueEnd, blue, blueIndex) {
	
		  var ptr = 0;
		  var elemSize = 2 * d;
		  var istart = axis;
		  var iend = axis + d;
	
		  var redShift = 1;
		  var blueShift = 1;
		  if (flip) {
		    blueShift = BLUE_FLAG;
		  } else {
		    redShift = BLUE_FLAG;
		  }
	
		  for (var i = redStart; i < redEnd; ++i) {
		    var idx = i + redShift;
		    var redOffset = elemSize * i;
		    SWEEP_EVENTS[ptr++] = red[redOffset + istart];
		    SWEEP_EVENTS[ptr++] = -idx;
		    SWEEP_EVENTS[ptr++] = red[redOffset + iend];
		    SWEEP_EVENTS[ptr++] = idx;
		  }
		  for (var i = blueStart; i < blueEnd; ++i) {
		    var idx = i + blueShift;
		    var blueOffset = elemSize * i;
		    SWEEP_EVENTS[ptr++] = blue[blueOffset + istart];
		    SWEEP_EVENTS[ptr++] = -idx;
		  }
	
		  //process events from left->right
		  var n = ptr >>> 1;
		  isort(SWEEP_EVENTS, n);
	
		  var redActive = 0;
		  for (var i = 0; i < n; ++i) {
		    var e = SWEEP_EVENTS[2 * i + 1] | 0;
		    if (e < 0) {
		      var idx = -e;
		      var isRed = false;
		      if (idx >= BLUE_FLAG) {
		        isRed = !flip;
		        idx -= BLUE_FLAG;
		      } else {
		        isRed = !!flip;
		        idx -= 1;
		      }
		      if (isRed) {
		        sqPush(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive++, idx);
		      } else {
		        var blueId = blueIndex[idx];
		        var bluePtr = elemSize * idx;
	
		        var b0 = blue[bluePtr + axis + 1];
		        var b1 = blue[bluePtr + axis + 1 + d];
	
		        red_loop: for (var j = 0; j < redActive; ++j) {
		          var oidx = RED_SWEEP_QUEUE[j];
		          var redPtr = elemSize * oidx;
	
		          if (b1 < red[redPtr + axis + 1] || red[redPtr + axis + 1 + d] < b0) {
		            continue;
		          }
	
		          for (var k = axis + 2; k < d; ++k) {
		            if (blue[bluePtr + k + d] < red[redPtr + k] || red[redPtr + k + d] < blue[bluePtr + k]) {
		              continue red_loop;
		            }
		          }
	
		          var redId = redIndex[oidx];
		          var retval;
		          if (flip) {
		            retval = visit(blueId, redId);
		          } else {
		            retval = visit(redId, blueId);
		          }
		          if (retval !== void 0) {
		            return retval;
		          }
		        }
		      }
		    } else {
		      sqPop(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive--, e - redShift);
		    }
		  }
		}
	
		function scanComplete(d, axis, visit, redStart, redEnd, red, redIndex, blueStart, blueEnd, blue, blueIndex) {
	
		  var ptr = 0;
		  var elemSize = 2 * d;
		  var istart = axis;
		  var iend = axis + d;
	
		  for (var i = redStart; i < redEnd; ++i) {
		    var idx = i + BLUE_FLAG;
		    var redOffset = elemSize * i;
		    SWEEP_EVENTS[ptr++] = red[redOffset + istart];
		    SWEEP_EVENTS[ptr++] = -idx;
		    SWEEP_EVENTS[ptr++] = red[redOffset + iend];
		    SWEEP_EVENTS[ptr++] = idx;
		  }
		  for (var i = blueStart; i < blueEnd; ++i) {
		    var idx = i + 1;
		    var blueOffset = elemSize * i;
		    SWEEP_EVENTS[ptr++] = blue[blueOffset + istart];
		    SWEEP_EVENTS[ptr++] = -idx;
		  }
	
		  //process events from left->right
		  var n = ptr >>> 1;
		  isort(SWEEP_EVENTS, n);
	
		  var redActive = 0;
		  for (var i = 0; i < n; ++i) {
		    var e = SWEEP_EVENTS[2 * i + 1] | 0;
		    if (e < 0) {
		      var idx = -e;
		      if (idx >= BLUE_FLAG) {
		        RED_SWEEP_QUEUE[redActive++] = idx - BLUE_FLAG;
		      } else {
		        idx -= 1;
		        var blueId = blueIndex[idx];
		        var bluePtr = elemSize * idx;
	
		        var b0 = blue[bluePtr + axis + 1];
		        var b1 = blue[bluePtr + axis + 1 + d];
	
		        red_loop: for (var j = 0; j < redActive; ++j) {
		          var oidx = RED_SWEEP_QUEUE[j];
		          var redId = redIndex[oidx];
	
		          if (redId === blueId) {
		            break;
		          }
	
		          var redPtr = elemSize * oidx;
		          if (b1 < red[redPtr + axis + 1] || red[redPtr + axis + 1 + d] < b0) {
		            continue;
		          }
		          for (var k = axis + 2; k < d; ++k) {
		            if (blue[bluePtr + k + d] < red[redPtr + k] || red[redPtr + k + d] < blue[bluePtr + k]) {
		              continue red_loop;
		            }
		          }
	
		          var retval = visit(redId, blueId);
		          if (retval !== void 0) {
		            return retval;
		          }
		        }
		      }
		    } else {
		      var idx = e - BLUE_FLAG;
		      for (var j = redActive - 1; j >= 0; --j) {
		        if (RED_SWEEP_QUEUE[j] === idx) {
		          for (var k = j + 1; k < redActive; ++k) {
		            RED_SWEEP_QUEUE[k - 1] = RED_SWEEP_QUEUE[k];
		          }
		          break;
		        }
		      }
		      --redActive;
		    }
		  }
		}
	
	/***/ }),
	/* 44 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		//This code is extracted from ndarray-sort
		//It is inlined here as a temporary workaround
	
		module.exports = wrapper;
	
		var INSERT_SORT_CUTOFF = 32;
	
		function wrapper(data, n0) {
		  if (n0 <= 4 * INSERT_SORT_CUTOFF) {
		    insertionSort(0, n0 - 1, data);
		  } else {
		    quickSort(0, n0 - 1, data);
		  }
		}
	
		function insertionSort(left, right, data) {
		  var ptr = 2 * (left + 1);
		  for (var i = left + 1; i <= right; ++i) {
		    var a = data[ptr++];
		    var b = data[ptr++];
		    var j = i;
		    var jptr = ptr - 2;
		    while (j-- > left) {
		      var x = data[jptr - 2];
		      var y = data[jptr - 1];
		      if (x < a) {
		        break;
		      } else if (x === a && y < b) {
		        break;
		      }
		      data[jptr] = x;
		      data[jptr + 1] = y;
		      jptr -= 2;
		    }
		    data[jptr] = a;
		    data[jptr + 1] = b;
		  }
		}
	
		function swap(i, j, data) {
		  i *= 2;
		  j *= 2;
		  var x = data[i];
		  var y = data[i + 1];
		  data[i] = data[j];
		  data[i + 1] = data[j + 1];
		  data[j] = x;
		  data[j + 1] = y;
		}
	
		function move(i, j, data) {
		  i *= 2;
		  j *= 2;
		  data[i] = data[j];
		  data[i + 1] = data[j + 1];
		}
	
		function rotate(i, j, k, data) {
		  i *= 2;
		  j *= 2;
		  k *= 2;
		  var x = data[i];
		  var y = data[i + 1];
		  data[i] = data[j];
		  data[i + 1] = data[j + 1];
		  data[j] = data[k];
		  data[j + 1] = data[k + 1];
		  data[k] = x;
		  data[k + 1] = y;
		}
	
		function shufflePivot(i, j, px, py, data) {
		  i *= 2;
		  j *= 2;
		  data[i] = data[j];
		  data[j] = px;
		  data[i + 1] = data[j + 1];
		  data[j + 1] = py;
		}
	
		function compare(i, j, data) {
		  i *= 2;
		  j *= 2;
		  var x = data[i],
		      y = data[j];
		  if (x < y) {
		    return false;
		  } else if (x === y) {
		    return data[i + 1] > data[j + 1];
		  }
		  return true;
		}
	
		function comparePivot(i, y, b, data) {
		  i *= 2;
		  var x = data[i];
		  if (x < y) {
		    return true;
		  } else if (x === y) {
		    return data[i + 1] < b;
		  }
		  return false;
		}
	
		function quickSort(left, right, data) {
		  var sixth = (right - left + 1) / 6 | 0,
		      index1 = left + sixth,
		      index5 = right - sixth,
		      index3 = left + right >> 1,
		      index2 = index3 - sixth,
		      index4 = index3 + sixth,
		      el1 = index1,
		      el2 = index2,
		      el3 = index3,
		      el4 = index4,
		      el5 = index5,
		      less = left + 1,
		      great = right - 1,
		      tmp = 0;
		  if (compare(el1, el2, data)) {
		    tmp = el1;
		    el1 = el2;
		    el2 = tmp;
		  }
		  if (compare(el4, el5, data)) {
		    tmp = el4;
		    el4 = el5;
		    el5 = tmp;
		  }
		  if (compare(el1, el3, data)) {
		    tmp = el1;
		    el1 = el3;
		    el3 = tmp;
		  }
		  if (compare(el2, el3, data)) {
		    tmp = el2;
		    el2 = el3;
		    el3 = tmp;
		  }
		  if (compare(el1, el4, data)) {
		    tmp = el1;
		    el1 = el4;
		    el4 = tmp;
		  }
		  if (compare(el3, el4, data)) {
		    tmp = el3;
		    el3 = el4;
		    el4 = tmp;
		  }
		  if (compare(el2, el5, data)) {
		    tmp = el2;
		    el2 = el5;
		    el5 = tmp;
		  }
		  if (compare(el2, el3, data)) {
		    tmp = el2;
		    el2 = el3;
		    el3 = tmp;
		  }
		  if (compare(el4, el5, data)) {
		    tmp = el4;
		    el4 = el5;
		    el5 = tmp;
		  }
	
		  var pivot1X = data[2 * el2];
		  var pivot1Y = data[2 * el2 + 1];
		  var pivot2X = data[2 * el4];
		  var pivot2Y = data[2 * el4 + 1];
	
		  var ptr0 = 2 * el1;
		  var ptr2 = 2 * el3;
		  var ptr4 = 2 * el5;
		  var ptr5 = 2 * index1;
		  var ptr6 = 2 * index3;
		  var ptr7 = 2 * index5;
		  for (var i1 = 0; i1 < 2; ++i1) {
		    var x = data[ptr0 + i1];
		    var y = data[ptr2 + i1];
		    var z = data[ptr4 + i1];
		    data[ptr5 + i1] = x;
		    data[ptr6 + i1] = y;
		    data[ptr7 + i1] = z;
		  }
	
		  move(index2, left, data);
		  move(index4, right, data);
		  for (var k = less; k <= great; ++k) {
		    if (comparePivot(k, pivot1X, pivot1Y, data)) {
		      if (k !== less) {
		        swap(k, less, data);
		      }
		      ++less;
		    } else {
		      if (!comparePivot(k, pivot2X, pivot2Y, data)) {
		        while (true) {
		          if (!comparePivot(great, pivot2X, pivot2Y, data)) {
		            if (--great < k) {
		              break;
		            }
		            continue;
		          } else {
		            if (comparePivot(great, pivot1X, pivot1Y, data)) {
		              rotate(k, less, great, data);
		              ++less;
		              --great;
		            } else {
		              swap(k, great, data);
		              --great;
		            }
		            break;
		          }
		        }
		      }
		    }
		  }
		  shufflePivot(left, less - 1, pivot1X, pivot1Y, data);
		  shufflePivot(right, great + 1, pivot2X, pivot2Y, data);
		  if (less - 2 - left <= INSERT_SORT_CUTOFF) {
		    insertionSort(left, less - 2, data);
		  } else {
		    quickSort(left, less - 2, data);
		  }
		  if (right - (great + 2) <= INSERT_SORT_CUTOFF) {
		    insertionSort(great + 2, right, data);
		  } else {
		    quickSort(great + 2, right, data);
		  }
		  if (great - less <= INSERT_SORT_CUTOFF) {
		    insertionSort(less, great, data);
		  } else {
		    quickSort(less, great, data);
		  }
		}
	
	/***/ }),
	/* 45 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		module.exports = boxIntersectIter;
	
		var pool = __webpack_require__(9);
		var bits = __webpack_require__(14);
		var bruteForce = __webpack_require__(46);
		var bruteForcePartial = bruteForce.partial;
		var bruteForceFull = bruteForce.full;
		var sweep = __webpack_require__(43);
		var findMedian = __webpack_require__(47);
		var genPartition = __webpack_require__(48);
	
		//Twiddle parameters
		var BRUTE_FORCE_CUTOFF = 128; //Cut off for brute force search
		var SCAN_CUTOFF = 1 << 22; //Cut off for two way scan
		var SCAN_COMPLETE_CUTOFF = 1 << 22;
	
		//Partition functions
		var partitionInteriorContainsInterval = genPartition('!(lo>=p0)&&!(p1>=hi)', ['p0', 'p1']);
	
		var partitionStartEqual = genPartition('lo===p0', ['p0']);
	
		var partitionStartLessThan = genPartition('lo<p0', ['p0']);
	
		var partitionEndLessThanEqual = genPartition('hi<=p0', ['p0']);
	
		var partitionContainsPoint = genPartition('lo<=p0&&p0<=hi', ['p0']);
	
		var partitionContainsPointProper = genPartition('lo<p0&&p0<=hi', ['p0']);
	
		//Frame size for iterative loop
		var IFRAME_SIZE = 6;
		var DFRAME_SIZE = 2;
	
		//Data for box statck
		var INIT_CAPACITY = 1024;
		var BOX_ISTACK = pool.mallocInt32(INIT_CAPACITY);
		var BOX_DSTACK = pool.mallocDouble(INIT_CAPACITY);
	
		//Initialize iterative loop queue
		function iterInit(d, count) {
		  var levels = 8 * bits.log2(count + 1) * (d + 1) | 0;
		  var maxInts = bits.nextPow2(IFRAME_SIZE * levels);
		  if (BOX_ISTACK.length < maxInts) {
		    pool.free(BOX_ISTACK);
		    BOX_ISTACK = pool.mallocInt32(maxInts);
		  }
		  var maxDoubles = bits.nextPow2(DFRAME_SIZE * levels);
		  if (BOX_DSTACK < maxDoubles) {
		    pool.free(BOX_DSTACK);
		    BOX_DSTACK = pool.mallocDouble(maxDoubles);
		  }
		}
	
		//Append item to queue
		function iterPush(ptr, axis, redStart, redEnd, blueStart, blueEnd, state, lo, hi) {
	
		  var iptr = IFRAME_SIZE * ptr;
		  BOX_ISTACK[iptr] = axis;
		  BOX_ISTACK[iptr + 1] = redStart;
		  BOX_ISTACK[iptr + 2] = redEnd;
		  BOX_ISTACK[iptr + 3] = blueStart;
		  BOX_ISTACK[iptr + 4] = blueEnd;
		  BOX_ISTACK[iptr + 5] = state;
	
		  var dptr = DFRAME_SIZE * ptr;
		  BOX_DSTACK[dptr] = lo;
		  BOX_DSTACK[dptr + 1] = hi;
		}
	
		//Special case:  Intersect single point with list of intervals
		function onePointPartial(d, axis, visit, flip, redStart, redEnd, red, redIndex, blueOffset, blue, blueId) {
	
		  var elemSize = 2 * d;
		  var bluePtr = blueOffset * elemSize;
		  var blueX = blue[bluePtr + axis];
	
		  red_loop: for (var i = redStart, redPtr = redStart * elemSize; i < redEnd; ++i, redPtr += elemSize) {
		    var r0 = red[redPtr + axis];
		    var r1 = red[redPtr + axis + d];
		    if (blueX < r0 || r1 < blueX) {
		      continue;
		    }
		    if (flip && blueX === r0) {
		      continue;
		    }
		    var redId = redIndex[i];
		    for (var j = axis + 1; j < d; ++j) {
		      var r0 = red[redPtr + j];
		      var r1 = red[redPtr + j + d];
		      var b0 = blue[bluePtr + j];
		      var b1 = blue[bluePtr + j + d];
		      if (r1 < b0 || b1 < r0) {
		        continue red_loop;
		      }
		    }
		    var retval;
		    if (flip) {
		      retval = visit(blueId, redId);
		    } else {
		      retval = visit(redId, blueId);
		    }
		    if (retval !== void 0) {
		      return retval;
		    }
		  }
		}
	
		//Special case:  Intersect one point with list of intervals
		function onePointFull(d, axis, visit, redStart, redEnd, red, redIndex, blueOffset, blue, blueId) {
	
		  var elemSize = 2 * d;
		  var bluePtr = blueOffset * elemSize;
		  var blueX = blue[bluePtr + axis];
	
		  red_loop: for (var i = redStart, redPtr = redStart * elemSize; i < redEnd; ++i, redPtr += elemSize) {
		    var redId = redIndex[i];
		    if (redId === blueId) {
		      continue;
		    }
		    var r0 = red[redPtr + axis];
		    var r1 = red[redPtr + axis + d];
		    if (blueX < r0 || r1 < blueX) {
		      continue;
		    }
		    for (var j = axis + 1; j < d; ++j) {
		      var r0 = red[redPtr + j];
		      var r1 = red[redPtr + j + d];
		      var b0 = blue[bluePtr + j];
		      var b1 = blue[bluePtr + j + d];
		      if (r1 < b0 || b1 < r0) {
		        continue red_loop;
		      }
		    }
		    var retval = visit(redId, blueId);
		    if (retval !== void 0) {
		      return retval;
		    }
		  }
		}
	
		//The main box intersection routine
		function boxIntersectIter(d, visit, initFull, xSize, xBoxes, xIndex, ySize, yBoxes, yIndex) {
	
		  //Reserve memory for stack
		  iterInit(d, xSize + ySize);
	
		  var top = 0;
		  var elemSize = 2 * d;
		  var retval;
	
		  iterPush(top++, 0, 0, xSize, 0, ySize, initFull ? 16 : 0, -Infinity, Infinity);
		  if (!initFull) {
		    iterPush(top++, 0, 0, ySize, 0, xSize, 1, -Infinity, Infinity);
		  }
	
		  while (top > 0) {
		    top -= 1;
	
		    var iptr = top * IFRAME_SIZE;
		    var axis = BOX_ISTACK[iptr];
		    var redStart = BOX_ISTACK[iptr + 1];
		    var redEnd = BOX_ISTACK[iptr + 2];
		    var blueStart = BOX_ISTACK[iptr + 3];
		    var blueEnd = BOX_ISTACK[iptr + 4];
		    var state = BOX_ISTACK[iptr + 5];
	
		    var dptr = top * DFRAME_SIZE;
		    var lo = BOX_DSTACK[dptr];
		    var hi = BOX_DSTACK[dptr + 1];
	
		    //Unpack state info
		    var flip = state & 1;
		    var full = !!(state & 16);
	
		    //Unpack indices
		    var red = xBoxes;
		    var redIndex = xIndex;
		    var blue = yBoxes;
		    var blueIndex = yIndex;
		    if (flip) {
		      red = yBoxes;
		      redIndex = yIndex;
		      blue = xBoxes;
		      blueIndex = xIndex;
		    }
	
		    if (state & 2) {
		      redEnd = partitionStartLessThan(d, axis, redStart, redEnd, red, redIndex, hi);
		      if (redStart >= redEnd) {
		        continue;
		      }
		    }
		    if (state & 4) {
		      redStart = partitionEndLessThanEqual(d, axis, redStart, redEnd, red, redIndex, lo);
		      if (redStart >= redEnd) {
		        continue;
		      }
		    }
	
		    var redCount = redEnd - redStart;
		    var blueCount = blueEnd - blueStart;
	
		    if (full) {
		      if (d * redCount * (redCount + blueCount) < SCAN_COMPLETE_CUTOFF) {
		        retval = sweep.scanComplete(d, axis, visit, redStart, redEnd, red, redIndex, blueStart, blueEnd, blue, blueIndex);
		        if (retval !== void 0) {
		          return retval;
		        }
		        continue;
		      }
		    } else {
		      if (d * Math.min(redCount, blueCount) < BRUTE_FORCE_CUTOFF) {
		        //If input small, then use brute force
		        retval = bruteForcePartial(d, axis, visit, flip, redStart, redEnd, red, redIndex, blueStart, blueEnd, blue, blueIndex);
		        if (retval !== void 0) {
		          return retval;
		        }
		        continue;
		      } else if (d * redCount * blueCount < SCAN_CUTOFF) {
		        //If input medium sized, then use sweep and prune
		        retval = sweep.scanBipartite(d, axis, visit, flip, redStart, redEnd, red, redIndex, blueStart, blueEnd, blue, blueIndex);
		        if (retval !== void 0) {
		          return retval;
		        }
		        continue;
		      }
		    }
	
		    //First, find all red intervals whose interior contains (lo,hi)
		    var red0 = partitionInteriorContainsInterval(d, axis, redStart, redEnd, red, redIndex, lo, hi);
	
		    //Lower dimensional case
		    if (redStart < red0) {
	
		      if (d * (red0 - redStart) < BRUTE_FORCE_CUTOFF) {
		        //Special case for small inputs: use brute force
		        retval = bruteForceFull(d, axis + 1, visit, redStart, red0, red, redIndex, blueStart, blueEnd, blue, blueIndex);
		        if (retval !== void 0) {
		          return retval;
		        }
		      } else if (axis === d - 2) {
		        if (flip) {
		          retval = sweep.sweepBipartite(d, visit, blueStart, blueEnd, blue, blueIndex, redStart, red0, red, redIndex);
		        } else {
		          retval = sweep.sweepBipartite(d, visit, redStart, red0, red, redIndex, blueStart, blueEnd, blue, blueIndex);
		        }
		        if (retval !== void 0) {
		          return retval;
		        }
		      } else {
		        iterPush(top++, axis + 1, redStart, red0, blueStart, blueEnd, flip, -Infinity, Infinity);
		        iterPush(top++, axis + 1, blueStart, blueEnd, redStart, red0, flip ^ 1, -Infinity, Infinity);
		      }
		    }
	
		    //Divide and conquer phase
		    if (red0 < redEnd) {
	
		      //Cut blue into 3 parts:
		      //
		      //  Points < mid point
		      //  Points = mid point
		      //  Points > mid point
		      //
		      var blue0 = findMedian(d, axis, blueStart, blueEnd, blue, blueIndex);
		      var mid = blue[elemSize * blue0 + axis];
		      var blue1 = partitionStartEqual(d, axis, blue0, blueEnd, blue, blueIndex, mid);
	
		      //Right case
		      if (blue1 < blueEnd) {
		        iterPush(top++, axis, red0, redEnd, blue1, blueEnd, (flip | 4) + (full ? 16 : 0), mid, hi);
		      }
	
		      //Left case
		      if (blueStart < blue0) {
		        iterPush(top++, axis, red0, redEnd, blueStart, blue0, (flip | 2) + (full ? 16 : 0), lo, mid);
		      }
	
		      //Center case (the hard part)
		      if (blue0 + 1 === blue1) {
		        //Optimization: Range with exactly 1 point, use a brute force scan
		        if (full) {
		          retval = onePointFull(d, axis, visit, red0, redEnd, red, redIndex, blue0, blue, blueIndex[blue0]);
		        } else {
		          retval = onePointPartial(d, axis, visit, flip, red0, redEnd, red, redIndex, blue0, blue, blueIndex[blue0]);
		        }
		        if (retval !== void 0) {
		          return retval;
		        }
		      } else if (blue0 < blue1) {
		        var red1;
		        if (full) {
		          //If full intersection, need to handle special case
		          red1 = partitionContainsPoint(d, axis, red0, redEnd, red, redIndex, mid);
		          if (red0 < red1) {
		            var redX = partitionStartEqual(d, axis, red0, red1, red, redIndex, mid);
		            if (axis === d - 2) {
		              //Degenerate sweep intersection:
		              //  [red0, redX] with [blue0, blue1]
		              if (red0 < redX) {
		                retval = sweep.sweepComplete(d, visit, red0, redX, red, redIndex, blue0, blue1, blue, blueIndex);
		                if (retval !== void 0) {
		                  return retval;
		                }
		              }
	
		              //Normal sweep intersection:
		              //  [redX, red1] with [blue0, blue1]
		              if (redX < red1) {
		                retval = sweep.sweepBipartite(d, visit, redX, red1, red, redIndex, blue0, blue1, blue, blueIndex);
		                if (retval !== void 0) {
		                  return retval;
		                }
		              }
		            } else {
		              if (red0 < redX) {
		                iterPush(top++, axis + 1, red0, redX, blue0, blue1, 16, -Infinity, Infinity);
		              }
		              if (redX < red1) {
		                iterPush(top++, axis + 1, redX, red1, blue0, blue1, 0, -Infinity, Infinity);
		                iterPush(top++, axis + 1, blue0, blue1, redX, red1, 1, -Infinity, Infinity);
		              }
		            }
		          }
		        } else {
		          if (flip) {
		            red1 = partitionContainsPointProper(d, axis, red0, redEnd, red, redIndex, mid);
		          } else {
		            red1 = partitionContainsPoint(d, axis, red0, redEnd, red, redIndex, mid);
		          }
		          if (red0 < red1) {
		            if (axis === d - 2) {
		              if (flip) {
		                retval = sweep.sweepBipartite(d, visit, blue0, blue1, blue, blueIndex, red0, red1, red, redIndex);
		              } else {
		                retval = sweep.sweepBipartite(d, visit, red0, red1, red, redIndex, blue0, blue1, blue, blueIndex);
		              }
		            } else {
		              iterPush(top++, axis + 1, red0, red1, blue0, blue1, flip, -Infinity, Infinity);
		              iterPush(top++, axis + 1, blue0, blue1, red0, red1, flip ^ 1, -Infinity, Infinity);
		            }
		          }
		        }
		      }
		    }
		  }
		}
	
	/***/ }),
	/* 46 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		var DIMENSION = 'd';
		var AXIS = 'ax';
		var VISIT = 'vv';
		var FLIP = 'fp';
	
		var ELEM_SIZE = 'es';
	
		var RED_START = 'rs';
		var RED_END = 're';
		var RED_BOXES = 'rb';
		var RED_INDEX = 'ri';
		var RED_PTR = 'rp';
	
		var BLUE_START = 'bs';
		var BLUE_END = 'be';
		var BLUE_BOXES = 'bb';
		var BLUE_INDEX = 'bi';
		var BLUE_PTR = 'bp';
	
		var RETVAL = 'rv';
	
		var INNER_LABEL = 'Q';
	
		var ARGS = [DIMENSION, AXIS, VISIT, RED_START, RED_END, RED_BOXES, RED_INDEX, BLUE_START, BLUE_END, BLUE_BOXES, BLUE_INDEX];
	
		function generateBruteForce(redMajor, flip, full) {
		  var funcName = 'bruteForce' + (redMajor ? 'Red' : 'Blue') + (flip ? 'Flip' : '') + (full ? 'Full' : '');
	
		  var code = ['function ', funcName, '(', ARGS.join(), '){', 'var ', ELEM_SIZE, '=2*', DIMENSION, ';'];
	
		  var redLoop = 'for(var i=' + RED_START + ',' + RED_PTR + '=' + ELEM_SIZE + '*' + RED_START + ';' + 'i<' + RED_END + ';' + '++i,' + RED_PTR + '+=' + ELEM_SIZE + '){' + 'var x0=' + RED_BOXES + '[' + AXIS + '+' + RED_PTR + '],' + 'x1=' + RED_BOXES + '[' + AXIS + '+' + RED_PTR + '+' + DIMENSION + '],' + 'xi=' + RED_INDEX + '[i];';
	
		  var blueLoop = 'for(var j=' + BLUE_START + ',' + BLUE_PTR + '=' + ELEM_SIZE + '*' + BLUE_START + ';' + 'j<' + BLUE_END + ';' + '++j,' + BLUE_PTR + '+=' + ELEM_SIZE + '){' + 'var y0=' + BLUE_BOXES + '[' + AXIS + '+' + BLUE_PTR + '],' + (full ? 'y1=' + BLUE_BOXES + '[' + AXIS + '+' + BLUE_PTR + '+' + DIMENSION + '],' : '') + 'yi=' + BLUE_INDEX + '[j];';
	
		  if (redMajor) {
		    code.push(redLoop, INNER_LABEL, ':', blueLoop);
		  } else {
		    code.push(blueLoop, INNER_LABEL, ':', redLoop);
		  }
	
		  if (full) {
		    code.push('if(y1<x0||x1<y0)continue;');
		  } else if (flip) {
		    code.push('if(y0<=x0||x1<y0)continue;');
		  } else {
		    code.push('if(y0<x0||x1<y0)continue;');
		  }
	
		  code.push('for(var k=' + AXIS + '+1;k<' + DIMENSION + ';++k){' + 'var r0=' + RED_BOXES + '[k+' + RED_PTR + '],' + 'r1=' + RED_BOXES + '[k+' + DIMENSION + '+' + RED_PTR + '],' + 'b0=' + BLUE_BOXES + '[k+' + BLUE_PTR + '],' + 'b1=' + BLUE_BOXES + '[k+' + DIMENSION + '+' + BLUE_PTR + '];' + 'if(r1<b0||b1<r0)continue ' + INNER_LABEL + ';}' + 'var ' + RETVAL + '=' + VISIT + '(');
	
		  if (flip) {
		    code.push('yi,xi');
		  } else {
		    code.push('xi,yi');
		  }
	
		  code.push(');if(' + RETVAL + '!==void 0)return ' + RETVAL + ';}}}');
	
		  return {
		    name: funcName,
		    code: code.join('')
		  };
		}
	
		function bruteForcePlanner(full) {
		  var funcName = 'bruteForce' + (full ? 'Full' : 'Partial');
		  var prefix = [];
		  var fargs = ARGS.slice();
		  if (!full) {
		    fargs.splice(3, 0, FLIP);
		  }
	
		  var code = ['function ' + funcName + '(' + fargs.join() + '){'];
	
		  function invoke(redMajor, flip) {
		    var res = generateBruteForce(redMajor, flip, full);
		    prefix.push(res.code);
		    code.push('return ' + res.name + '(' + ARGS.join() + ');');
		  }
	
		  code.push('if(' + RED_END + '-' + RED_START + '>' + BLUE_END + '-' + BLUE_START + '){');
	
		  if (full) {
		    invoke(true, false);
		    code.push('}else{');
		    invoke(false, false);
		  } else {
		    code.push('if(' + FLIP + '){');
		    invoke(true, true);
		    code.push('}else{');
		    invoke(true, false);
		    code.push('}}else{if(' + FLIP + '){');
		    invoke(false, true);
		    code.push('}else{');
		    invoke(false, false);
		    code.push('}');
		  }
		  code.push('}}return ' + funcName);
	
		  var codeStr = prefix.join('') + code.join('');
		  var proc = new Function(codeStr);
		  return proc();
		}
	
		exports.partial = bruteForcePlanner(false);
		exports.full = bruteForcePlanner(true);
	
	/***/ }),
	/* 47 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		module.exports = findMedian;
	
		var genPartition = __webpack_require__(48);
	
		var partitionStartLessThan = genPartition('lo<p0', ['p0']);
	
		var PARTITION_THRESHOLD = 8; //Cut off for using insertion sort in findMedian
	
		//Base case for median finding:  Use insertion sort
		function insertionSort(d, axis, start, end, boxes, ids) {
		  var elemSize = 2 * d;
		  var boxPtr = elemSize * (start + 1) + axis;
		  for (var i = start + 1; i < end; ++i, boxPtr += elemSize) {
		    var x = boxes[boxPtr];
		    for (var j = i, ptr = elemSize * (i - 1); j > start && boxes[ptr + axis] > x; --j, ptr -= elemSize) {
		      //Swap
		      var aPtr = ptr;
		      var bPtr = ptr + elemSize;
		      for (var k = 0; k < elemSize; ++k, ++aPtr, ++bPtr) {
		        var y = boxes[aPtr];
		        boxes[aPtr] = boxes[bPtr];
		        boxes[bPtr] = y;
		      }
		      var tmp = ids[j];
		      ids[j] = ids[j - 1];
		      ids[j - 1] = tmp;
		    }
		  }
		}
	
		//Find median using quick select algorithm
		//  takes O(n) time with high probability
		function findMedian(d, axis, start, end, boxes, ids) {
		  if (end <= start + 1) {
		    return start;
		  }
	
		  var lo = start;
		  var hi = end;
		  var mid = end + start >>> 1;
		  var elemSize = 2 * d;
		  var pivot = mid;
		  var value = boxes[elemSize * mid + axis];
	
		  while (lo < hi) {
		    if (hi - lo < PARTITION_THRESHOLD) {
		      insertionSort(d, axis, lo, hi, boxes, ids);
		      value = boxes[elemSize * mid + axis];
		      break;
		    }
	
		    //Select pivot using median-of-3
		    var count = hi - lo;
		    var pivot0 = Math.random() * count + lo | 0;
		    var value0 = boxes[elemSize * pivot0 + axis];
		    var pivot1 = Math.random() * count + lo | 0;
		    var value1 = boxes[elemSize * pivot1 + axis];
		    var pivot2 = Math.random() * count + lo | 0;
		    var value2 = boxes[elemSize * pivot2 + axis];
		    if (value0 <= value1) {
		      if (value2 >= value1) {
		        pivot = pivot1;
		        value = value1;
		      } else if (value0 >= value2) {
		        pivot = pivot0;
		        value = value0;
		      } else {
		        pivot = pivot2;
		        value = value2;
		      }
		    } else {
		      if (value1 >= value2) {
		        pivot = pivot1;
		        value = value1;
		      } else if (value2 >= value0) {
		        pivot = pivot0;
		        value = value0;
		      } else {
		        pivot = pivot2;
		        value = value2;
		      }
		    }
	
		    //Swap pivot to end of array
		    var aPtr = elemSize * (hi - 1);
		    var bPtr = elemSize * pivot;
		    for (var i = 0; i < elemSize; ++i, ++aPtr, ++bPtr) {
		      var x = boxes[aPtr];
		      boxes[aPtr] = boxes[bPtr];
		      boxes[bPtr] = x;
		    }
		    var y = ids[hi - 1];
		    ids[hi - 1] = ids[pivot];
		    ids[pivot] = y;
	
		    //Partition using pivot
		    pivot = partitionStartLessThan(d, axis, lo, hi - 1, boxes, ids, value);
	
		    //Swap pivot back
		    var aPtr = elemSize * (hi - 1);
		    var bPtr = elemSize * pivot;
		    for (var i = 0; i < elemSize; ++i, ++aPtr, ++bPtr) {
		      var x = boxes[aPtr];
		      boxes[aPtr] = boxes[bPtr];
		      boxes[bPtr] = x;
		    }
		    var y = ids[hi - 1];
		    ids[hi - 1] = ids[pivot];
		    ids[pivot] = y;
	
		    //Swap pivot to last pivot
		    if (mid < pivot) {
		      hi = pivot - 1;
		      while (lo < hi && boxes[elemSize * (hi - 1) + axis] === value) {
		        hi -= 1;
		      }
		      hi += 1;
		    } else if (pivot < mid) {
		      lo = pivot + 1;
		      while (lo < hi && boxes[elemSize * lo + axis] === value) {
		        lo += 1;
		      }
		    } else {
		      break;
		    }
		  }
	
		  //Make sure pivot is at start
		  return partitionStartLessThan(d, axis, start, mid, boxes, ids, boxes[elemSize * mid + axis]);
			}
	
	/***/ }),
	/* 48 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = genPartition;
	
		var code = 'for(var j=2*a,k=j*c,l=k,m=c,n=b,o=a+b,p=c;d>p;++p,k+=j){var _;if($)if(m===p)m+=1,l+=j;else{for(var s=0;j>s;++s){var t=e[k+s];e[k+s]=e[l],e[l++]=t}var u=f[p];f[p]=f[m],f[m++]=u}}return m';
	
		function genPartition(predicate, args) {
		  var fargs = 'abcdef'.split('').concat(args);
		  var reads = [];
		  if (predicate.indexOf('lo') >= 0) {
		    reads.push('lo=e[k+n]');
		  }
		  if (predicate.indexOf('hi') >= 0) {
		    reads.push('hi=e[k+o]');
		  }
		  fargs.push(code.replace('_', reads.join()).replace('$', predicate));
		  return Function.apply(void 0, fargs);
		}
	
	/***/ }),
	/* 49 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = segmentsIntersect;
	
		var orient = __webpack_require__(31)[3];
	
		function checkCollinear(a0, a1, b0, b1) {
	
		  for (var d = 0; d < 2; ++d) {
		    var x0 = a0[d];
		    var y0 = a1[d];
		    var l0 = Math.min(x0, y0);
		    var h0 = Math.max(x0, y0);
	
		    var x1 = b0[d];
		    var y1 = b1[d];
		    var l1 = Math.min(x1, y1);
		    var h1 = Math.max(x1, y1);
	
		    if (h1 < l0 || h0 < l1) {
		      return false;
		    }
		  }
	
		  return true;
		}
	
		function segmentsIntersect(a0, a1, b0, b1) {
		  var x0 = orient(a0, b0, b1);
		  var y0 = orient(a1, b0, b1);
		  if (x0 > 0 && y0 > 0 || x0 < 0 && y0 < 0) {
		    return false;
		  }
	
		  var x1 = orient(b0, a0, a1);
		  var y1 = orient(b1, a0, a1);
		  if (x1 > 0 && y1 > 0 || x1 < 0 && y1 < 0) {
		    return false;
		  }
	
		  //Check for degenerate collinear case
		  if (x0 === 0 && y0 === 0 && x1 === 0 && y1 === 0) {
		    return checkCollinear(a0, a1, b0, b1);
		  }
	
		  return true;
		}
	
	/***/ }),
	/* 50 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var isRat = __webpack_require__(51);
		var isBN = __webpack_require__(52);
		var num2bn = __webpack_require__(56);
		var str2bn = __webpack_require__(58);
		var rationalize = __webpack_require__(59);
		var div = __webpack_require__(61);
	
		module.exports = makeRational;
	
		function makeRational(numer, denom) {
		  if (isRat(numer)) {
		    if (denom) {
		      return div(numer, makeRational(denom));
		    }
		    return [numer[0].clone(), numer[1].clone()];
		  }
		  var shift = 0;
		  var a, b;
		  if (isBN(numer)) {
		    a = numer.clone();
		  } else if (typeof numer === 'string') {
		    a = str2bn(numer);
		  } else if (numer === 0) {
		    return [num2bn(0), num2bn(1)];
		  } else if (numer === Math.floor(numer)) {
		    a = num2bn(numer);
		  } else {
		    while (numer !== Math.floor(numer)) {
		      numer = numer * Math.pow(2, 256);
		      shift -= 256;
		    }
		    a = num2bn(numer);
		  }
		  if (isRat(denom)) {
		    a.mul(denom[1]);
		    b = denom[0].clone();
		  } else if (isBN(denom)) {
		    b = denom.clone();
		  } else if (typeof denom === 'string') {
		    b = str2bn(denom);
		  } else if (!denom) {
		    b = num2bn(1);
		  } else if (denom === Math.floor(denom)) {
		    b = num2bn(denom);
		  } else {
		    while (denom !== Math.floor(denom)) {
		      denom = denom * Math.pow(2, 256);
		      shift += 256;
		    }
		    b = num2bn(denom);
		  }
		  if (shift > 0) {
		    a = a.ushln(shift);
		  } else if (shift < 0) {
		    b = b.ushln(-shift);
		  }
		  return rationalize(a, b);
		}
	
	/***/ }),
	/* 51 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var isBN = __webpack_require__(52);
	
		module.exports = isRat;
	
		function isRat(x) {
		  return Array.isArray(x) && x.length === 2 && isBN(x[0]) && isBN(x[1]);
		}
	
	/***/ }),
	/* 52 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var BN = __webpack_require__(53);
	
		module.exports = isBN;
	
		//Test if x is a bignumber
		//FIXME: obviously this is the wrong way to do it
		function isBN(x) {
		  return x && typeof x === 'object' && Boolean(x.words);
		}
	
	/***/ }),
	/* 53 */
	/***/ (function(module, exports, __webpack_require__) {
	
		/* WEBPACK VAR INJECTION */(function(module) {(function (module, exports) {
		  'use strict';
	
		  // Utils
	
		  function assert(val, msg) {
		    if (!val) throw new Error(msg || 'Assertion failed');
		  }
	
		  // Could use `inherits` module, but don't want to move from single file
		  // architecture yet.
		  function inherits(ctor, superCtor) {
		    ctor.super_ = superCtor;
		    var TempCtor = function () {};
		    TempCtor.prototype = superCtor.prototype;
		    ctor.prototype = new TempCtor();
		    ctor.prototype.constructor = ctor;
		  }
	
		  // BN
	
		  function BN(number, base, endian) {
		    if (BN.isBN(number)) {
		      return number;
		    }
	
		    this.negative = 0;
		    this.words = null;
		    this.length = 0;
	
		    // Reduction context
		    this.red = null;
	
		    if (number !== null) {
		      if (base === 'le' || base === 'be') {
		        endian = base;
		        base = 10;
		      }
	
		      this._init(number || 0, base || 10, endian || 'be');
		    }
		  }
		  if (typeof module === 'object') {
		    module.exports = BN;
		  } else {
		    exports.BN = BN;
		  }
	
		  BN.BN = BN;
		  BN.wordSize = 26;
	
		  var Buffer;
		  try {
		    Buffer = __webpack_require__(55).Buffer;
		  } catch (e) {}
	
		  BN.isBN = function isBN(num) {
		    if (num instanceof BN) {
		      return true;
		    }
	
		    return num !== null && typeof num === 'object' && num.constructor.wordSize === BN.wordSize && Array.isArray(num.words);
		  };
	
		  BN.max = function max(left, right) {
		    if (left.cmp(right) > 0) return left;
		    return right;
		  };
	
		  BN.min = function min(left, right) {
		    if (left.cmp(right) < 0) return left;
		    return right;
		  };
	
		  BN.prototype._init = function init(number, base, endian) {
		    if (typeof number === 'number') {
		      return this._initNumber(number, base, endian);
		    }
	
		    if (typeof number === 'object') {
		      return this._initArray(number, base, endian);
		    }
	
		    if (base === 'hex') {
		      base = 16;
		    }
		    assert(base === (base | 0) && base >= 2 && base <= 36);
	
		    number = number.toString().replace(/\s+/g, '');
		    var start = 0;
		    if (number[0] === '-') {
		      start++;
		    }
	
		    if (base === 16) {
		      this._parseHex(number, start);
		    } else {
		      this._parseBase(number, base, start);
		    }
	
		    if (number[0] === '-') {
		      this.negative = 1;
		    }
	
		    this.strip();
	
		    if (endian !== 'le') return;
	
		    this._initArray(this.toArray(), base, endian);
		  };
	
		  BN.prototype._initNumber = function _initNumber(number, base, endian) {
		    if (number < 0) {
		      this.negative = 1;
		      number = -number;
		    }
		    if (number < 0x4000000) {
		      this.words = [number & 0x3ffffff];
		      this.length = 1;
		    } else if (number < 0x10000000000000) {
		      this.words = [number & 0x3ffffff, number / 0x4000000 & 0x3ffffff];
		      this.length = 2;
		    } else {
		      assert(number < 0x20000000000000); // 2 ^ 53 (unsafe)
		      this.words = [number & 0x3ffffff, number / 0x4000000 & 0x3ffffff, 1];
		      this.length = 3;
		    }
	
		    if (endian !== 'le') return;
	
		    // Reverse the bytes
		    this._initArray(this.toArray(), base, endian);
		  };
	
		  BN.prototype._initArray = function _initArray(number, base, endian) {
		    // Perhaps a Uint8Array
		    assert(typeof number.length === 'number');
		    if (number.length <= 0) {
		      this.words = [0];
		      this.length = 1;
		      return this;
		    }
	
		    this.length = Math.ceil(number.length / 3);
		    this.words = new Array(this.length);
		    for (var i = 0; i < this.length; i++) {
		      this.words[i] = 0;
		    }
	
		    var j, w;
		    var off = 0;
		    if (endian === 'be') {
		      for (i = number.length - 1, j = 0; i >= 0; i -= 3) {
		        w = number[i] | number[i - 1] << 8 | number[i - 2] << 16;
		        this.words[j] |= w << off & 0x3ffffff;
		        this.words[j + 1] = w >>> 26 - off & 0x3ffffff;
		        off += 24;
		        if (off >= 26) {
		          off -= 26;
		          j++;
		        }
		      }
		    } else if (endian === 'le') {
		      for (i = 0, j = 0; i < number.length; i += 3) {
		        w = number[i] | number[i + 1] << 8 | number[i + 2] << 16;
		        this.words[j] |= w << off & 0x3ffffff;
		        this.words[j + 1] = w >>> 26 - off & 0x3ffffff;
		        off += 24;
		        if (off >= 26) {
		          off -= 26;
		          j++;
		        }
		      }
		    }
		    return this.strip();
		  };
	
		  function parseHex(str, start, end) {
		    var r = 0;
		    var len = Math.min(str.length, end);
		    for (var i = start; i < len; i++) {
		      var c = str.charCodeAt(i) - 48;
	
		      r <<= 4;
	
		      // 'a' - 'f'
		      if (c >= 49 && c <= 54) {
		        r |= c - 49 + 0xa;
	
		        // 'A' - 'F'
		      } else if (c >= 17 && c <= 22) {
		        r |= c - 17 + 0xa;
	
		        // '0' - '9'
		      } else {
		        r |= c & 0xf;
		      }
		    }
		    return r;
		  }
	
		  BN.prototype._parseHex = function _parseHex(number, start) {
		    // Create possibly bigger array to ensure that it fits the number
		    this.length = Math.ceil((number.length - start) / 6);
		    this.words = new Array(this.length);
		    for (var i = 0; i < this.length; i++) {
		      this.words[i] = 0;
		    }
	
		    var j, w;
		    // Scan 24-bit chunks and add them to the number
		    var off = 0;
		    for (i = number.length - 6, j = 0; i >= start; i -= 6) {
		      w = parseHex(number, i, i + 6);
		      this.words[j] |= w << off & 0x3ffffff;
		      // NOTE: `0x3fffff` is intentional here, 26bits max shift + 24bit hex limb
		      this.words[j + 1] |= w >>> 26 - off & 0x3fffff;
		      off += 24;
		      if (off >= 26) {
		        off -= 26;
		        j++;
		      }
		    }
		    if (i + 6 !== start) {
		      w = parseHex(number, start, i + 6);
		      this.words[j] |= w << off & 0x3ffffff;
		      this.words[j + 1] |= w >>> 26 - off & 0x3fffff;
		    }
		    this.strip();
		  };
	
		  function parseBase(str, start, end, mul) {
		    var r = 0;
		    var len = Math.min(str.length, end);
		    for (var i = start; i < len; i++) {
		      var c = str.charCodeAt(i) - 48;
	
		      r *= mul;
	
		      // 'a'
		      if (c >= 49) {
		        r += c - 49 + 0xa;
	
		        // 'A'
		      } else if (c >= 17) {
		        r += c - 17 + 0xa;
	
		        // '0' - '9'
		      } else {
		        r += c;
		      }
		    }
		    return r;
		  }
	
		  BN.prototype._parseBase = function _parseBase(number, base, start) {
		    // Initialize as zero
		    this.words = [0];
		    this.length = 1;
	
		    // Find length of limb in base
		    for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) {
		      limbLen++;
		    }
		    limbLen--;
		    limbPow = limbPow / base | 0;
	
		    var total = number.length - start;
		    var mod = total % limbLen;
		    var end = Math.min(total, total - mod) + start;
	
		    var word = 0;
		    for (var i = start; i < end; i += limbLen) {
		      word = parseBase(number, i, i + limbLen, base);
	
		      this.imuln(limbPow);
		      if (this.words[0] + word < 0x4000000) {
		        this.words[0] += word;
		      } else {
		        this._iaddn(word);
		      }
		    }
	
		    if (mod !== 0) {
		      var pow = 1;
		      word = parseBase(number, i, number.length, base);
	
		      for (i = 0; i < mod; i++) {
		        pow *= base;
		      }
	
		      this.imuln(pow);
		      if (this.words[0] + word < 0x4000000) {
		        this.words[0] += word;
		      } else {
		        this._iaddn(word);
		      }
		    }
		  };
	
		  BN.prototype.copy = function copy(dest) {
		    dest.words = new Array(this.length);
		    for (var i = 0; i < this.length; i++) {
		      dest.words[i] = this.words[i];
		    }
		    dest.length = this.length;
		    dest.negative = this.negative;
		    dest.red = this.red;
		  };
	
		  BN.prototype.clone = function clone() {
		    var r = new BN(null);
		    this.copy(r);
		    return r;
		  };
	
		  BN.prototype._expand = function _expand(size) {
		    while (this.length < size) {
		      this.words[this.length++] = 0;
		    }
		    return this;
		  };
	
		  // Remove leading `0` from `this`
		  BN.prototype.strip = function strip() {
		    while (this.length > 1 && this.words[this.length - 1] === 0) {
		      this.length--;
		    }
		    return this._normSign();
		  };
	
		  BN.prototype._normSign = function _normSign() {
		    // -0 = 0
		    if (this.length === 1 && this.words[0] === 0) {
		      this.negative = 0;
		    }
		    return this;
		  };
	
		  BN.prototype.inspect = function inspect() {
		    return (this.red ? '<BN-R: ' : '<BN: ') + this.toString(16) + '>';
		  };
	
		  /*
		   var zeros = [];
		  var groupSizes = [];
		  var groupBases = [];
		   var s = '';
		  var i = -1;
		  while (++i < BN.wordSize) {
		    zeros[i] = s;
		    s += '0';
		  }
		  groupSizes[0] = 0;
		  groupSizes[1] = 0;
		  groupBases[0] = 0;
		  groupBases[1] = 0;
		  var base = 2 - 1;
		  while (++base < 36 + 1) {
		    var groupSize = 0;
		    var groupBase = 1;
		    while (groupBase < (1 << BN.wordSize) / base) {
		      groupBase *= base;
		      groupSize += 1;
		    }
		    groupSizes[base] = groupSize;
		    groupBases[base] = groupBase;
		  }
		   */
	
		  var zeros = ['', '0', '00', '000', '0000', '00000', '000000', '0000000', '00000000', '000000000', '0000000000', '00000000000', '000000000000', '0000000000000', '00000000000000', '000000000000000', '0000000000000000', '00000000000000000', '000000000000000000', '0000000000000000000', '00000000000000000000', '000000000000000000000', '0000000000000000000000', '00000000000000000000000', '000000000000000000000000', '0000000000000000000000000'];
	
		  var groupSizes = [0, 0, 25, 16, 12, 11, 10, 9, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5];
	
		  var groupBases = [0, 0, 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216, 43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625, 16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632, 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149, 24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176];
	
		  BN.prototype.toString = function toString(base, padding) {
		    base = base || 10;
		    padding = padding | 0 || 1;
	
		    var out;
		    if (base === 16 || base === 'hex') {
		      out = '';
		      var off = 0;
		      var carry = 0;
		      for (var i = 0; i < this.length; i++) {
		        var w = this.words[i];
		        var word = ((w << off | carry) & 0xffffff).toString(16);
		        carry = w >>> 24 - off & 0xffffff;
		        if (carry !== 0 || i !== this.length - 1) {
		          out = zeros[6 - word.length] + word + out;
		        } else {
		          out = word + out;
		        }
		        off += 2;
		        if (off >= 26) {
		          off -= 26;
		          i--;
		        }
		      }
		      if (carry !== 0) {
		        out = carry.toString(16) + out;
		      }
		      while (out.length % padding !== 0) {
		        out = '0' + out;
		      }
		      if (this.negative !== 0) {
		        out = '-' + out;
		      }
		      return out;
		    }
	
		    if (base === (base | 0) && base >= 2 && base <= 36) {
		      // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base));
		      var groupSize = groupSizes[base];
		      // var groupBase = Math.pow(base, groupSize);
		      var groupBase = groupBases[base];
		      out = '';
		      var c = this.clone();
		      c.negative = 0;
		      while (!c.isZero()) {
		        var r = c.modn(groupBase).toString(base);
		        c = c.idivn(groupBase);
	
		        if (!c.isZero()) {
		          out = zeros[groupSize - r.length] + r + out;
		        } else {
		          out = r + out;
		        }
		      }
		      if (this.isZero()) {
		        out = '0' + out;
		      }
		      while (out.length % padding !== 0) {
		        out = '0' + out;
		      }
		      if (this.negative !== 0) {
		        out = '-' + out;
		      }
		      return out;
		    }
	
		    assert(false, 'Base should be between 2 and 36');
		  };
	
		  BN.prototype.toNumber = function toNumber() {
		    var ret = this.words[0];
		    if (this.length === 2) {
		      ret += this.words[1] * 0x4000000;
		    } else if (this.length === 3 && this.words[2] === 0x01) {
		      // NOTE: at this stage it is known that the top bit is set
		      ret += 0x10000000000000 + this.words[1] * 0x4000000;
		    } else if (this.length > 2) {
		      assert(false, 'Number can only safely store up to 53 bits');
		    }
		    return this.negative !== 0 ? -ret : ret;
		  };
	
		  BN.prototype.toJSON = function toJSON() {
		    return this.toString(16);
		  };
	
		  BN.prototype.toBuffer = function toBuffer(endian, length) {
		    assert(typeof Buffer !== 'undefined');
		    return this.toArrayLike(Buffer, endian, length);
		  };
	
		  BN.prototype.toArray = function toArray(endian, length) {
		    return this.toArrayLike(Array, endian, length);
		  };
	
		  BN.prototype.toArrayLike = function toArrayLike(ArrayType, endian, length) {
		    var byteLength = this.byteLength();
		    var reqLength = length || Math.max(1, byteLength);
		    assert(byteLength <= reqLength, 'byte array longer than desired length');
		    assert(reqLength > 0, 'Requested array length <= 0');
	
		    this.strip();
		    var littleEndian = endian === 'le';
		    var res = new ArrayType(reqLength);
	
		    var b, i;
		    var q = this.clone();
		    if (!littleEndian) {
		      // Assume big-endian
		      for (i = 0; i < reqLength - byteLength; i++) {
		        res[i] = 0;
		      }
	
		      for (i = 0; !q.isZero(); i++) {
		        b = q.andln(0xff);
		        q.iushrn(8);
	
		        res[reqLength - i - 1] = b;
		      }
		    } else {
		      for (i = 0; !q.isZero(); i++) {
		        b = q.andln(0xff);
		        q.iushrn(8);
	
		        res[i] = b;
		      }
	
		      for (; i < reqLength; i++) {
		        res[i] = 0;
		      }
		    }
	
		    return res;
		  };
	
		  if (Math.clz32) {
		    BN.prototype._countBits = function _countBits(w) {
		      return 32 - Math.clz32(w);
		    };
		  } else {
		    BN.prototype._countBits = function _countBits(w) {
		      var t = w;
		      var r = 0;
		      if (t >= 0x1000) {
		        r += 13;
		        t >>>= 13;
		      }
		      if (t >= 0x40) {
		        r += 7;
		        t >>>= 7;
		      }
		      if (t >= 0x8) {
		        r += 4;
		        t >>>= 4;
		      }
		      if (t >= 0x02) {
		        r += 2;
		        t >>>= 2;
		      }
		      return r + t;
		    };
		  }
	
		  BN.prototype._zeroBits = function _zeroBits(w) {
		    // Short-cut
		    if (w === 0) return 26;
	
		    var t = w;
		    var r = 0;
		    if ((t & 0x1fff) === 0) {
		      r += 13;
		      t >>>= 13;
		    }
		    if ((t & 0x7f) === 0) {
		      r += 7;
		      t >>>= 7;
		    }
		    if ((t & 0xf) === 0) {
		      r += 4;
		      t >>>= 4;
		    }
		    if ((t & 0x3) === 0) {
		      r += 2;
		      t >>>= 2;
		    }
		    if ((t & 0x1) === 0) {
		      r++;
		    }
		    return r;
		  };
	
		  // Return number of used bits in a BN
		  BN.prototype.bitLength = function bitLength() {
		    var w = this.words[this.length - 1];
		    var hi = this._countBits(w);
		    return (this.length - 1) * 26 + hi;
		  };
	
		  function toBitArray(num) {
		    var w = new Array(num.bitLength());
	
		    for (var bit = 0; bit < w.length; bit++) {
		      var off = bit / 26 | 0;
		      var wbit = bit % 26;
	
		      w[bit] = (num.words[off] & 1 << wbit) >>> wbit;
		    }
	
		    return w;
		  }
	
		  // Number of trailing zero bits
		  BN.prototype.zeroBits = function zeroBits() {
		    if (this.isZero()) return 0;
	
		    var r = 0;
		    for (var i = 0; i < this.length; i++) {
		      var b = this._zeroBits(this.words[i]);
		      r += b;
		      if (b !== 26) break;
		    }
		    return r;
		  };
	
		  BN.prototype.byteLength = function byteLength() {
		    return Math.ceil(this.bitLength() / 8);
		  };
	
		  BN.prototype.toTwos = function toTwos(width) {
		    if (this.negative !== 0) {
		      return this.abs().inotn(width).iaddn(1);
		    }
		    return this.clone();
		  };
	
		  BN.prototype.fromTwos = function fromTwos(width) {
		    if (this.testn(width - 1)) {
		      return this.notn(width).iaddn(1).ineg();
		    }
		    return this.clone();
		  };
	
		  BN.prototype.isNeg = function isNeg() {
		    return this.negative !== 0;
		  };
	
		  // Return negative clone of `this`
		  BN.prototype.neg = function neg() {
		    return this.clone().ineg();
		  };
	
		  BN.prototype.ineg = function ineg() {
		    if (!this.isZero()) {
		      this.negative ^= 1;
		    }
	
		    return this;
		  };
	
		  // Or `num` with `this` in-place
		  BN.prototype.iuor = function iuor(num) {
		    while (this.length < num.length) {
		      this.words[this.length++] = 0;
		    }
	
		    for (var i = 0; i < num.length; i++) {
		      this.words[i] = this.words[i] | num.words[i];
		    }
	
		    return this.strip();
		  };
	
		  BN.prototype.ior = function ior(num) {
		    assert((this.negative | num.negative) === 0);
		    return this.iuor(num);
		  };
	
		  // Or `num` with `this`
		  BN.prototype.or = function or(num) {
		    if (this.length > num.length) return this.clone().ior(num);
		    return num.clone().ior(this);
		  };
	
		  BN.prototype.uor = function uor(num) {
		    if (this.length > num.length) return this.clone().iuor(num);
		    return num.clone().iuor(this);
		  };
	
		  // And `num` with `this` in-place
		  BN.prototype.iuand = function iuand(num) {
		    // b = min-length(num, this)
		    var b;
		    if (this.length > num.length) {
		      b = num;
		    } else {
		      b = this;
		    }
	
		    for (var i = 0; i < b.length; i++) {
		      this.words[i] = this.words[i] & num.words[i];
		    }
	
		    this.length = b.length;
	
		    return this.strip();
		  };
	
		  BN.prototype.iand = function iand(num) {
		    assert((this.negative | num.negative) === 0);
		    return this.iuand(num);
		  };
	
		  // And `num` with `this`
		  BN.prototype.and = function and(num) {
		    if (this.length > num.length) return this.clone().iand(num);
		    return num.clone().iand(this);
		  };
	
		  BN.prototype.uand = function uand(num) {
		    if (this.length > num.length) return this.clone().iuand(num);
		    return num.clone().iuand(this);
		  };
	
		  // Xor `num` with `this` in-place
		  BN.prototype.iuxor = function iuxor(num) {
		    // a.length > b.length
		    var a;
		    var b;
		    if (this.length > num.length) {
		      a = this;
		      b = num;
		    } else {
		      a = num;
		      b = this;
		    }
	
		    for (var i = 0; i < b.length; i++) {
		      this.words[i] = a.words[i] ^ b.words[i];
		    }
	
		    if (this !== a) {
		      for (; i < a.length; i++) {
		        this.words[i] = a.words[i];
		      }
		    }
	
		    this.length = a.length;
	
		    return this.strip();
		  };
	
		  BN.prototype.ixor = function ixor(num) {
		    assert((this.negative | num.negative) === 0);
		    return this.iuxor(num);
		  };
	
		  // Xor `num` with `this`
		  BN.prototype.xor = function xor(num) {
		    if (this.length > num.length) return this.clone().ixor(num);
		    return num.clone().ixor(this);
		  };
	
		  BN.prototype.uxor = function uxor(num) {
		    if (this.length > num.length) return this.clone().iuxor(num);
		    return num.clone().iuxor(this);
		  };
	
		  // Not ``this`` with ``width`` bitwidth
		  BN.prototype.inotn = function inotn(width) {
		    assert(typeof width === 'number' && width >= 0);
	
		    var bytesNeeded = Math.ceil(width / 26) | 0;
		    var bitsLeft = width % 26;
	
		    // Extend the buffer with leading zeroes
		    this._expand(bytesNeeded);
	
		    if (bitsLeft > 0) {
		      bytesNeeded--;
		    }
	
		    // Handle complete words
		    for (var i = 0; i < bytesNeeded; i++) {
		      this.words[i] = ~this.words[i] & 0x3ffffff;
		    }
	
		    // Handle the residue
		    if (bitsLeft > 0) {
		      this.words[i] = ~this.words[i] & 0x3ffffff >> 26 - bitsLeft;
		    }
	
		    // And remove leading zeroes
		    return this.strip();
		  };
	
		  BN.prototype.notn = function notn(width) {
		    return this.clone().inotn(width);
		  };
	
		  // Set `bit` of `this`
		  BN.prototype.setn = function setn(bit, val) {
		    assert(typeof bit === 'number' && bit >= 0);
	
		    var off = bit / 26 | 0;
		    var wbit = bit % 26;
	
		    this._expand(off + 1);
	
		    if (val) {
		      this.words[off] = this.words[off] | 1 << wbit;
		    } else {
		      this.words[off] = this.words[off] & ~(1 << wbit);
		    }
	
		    return this.strip();
		  };
	
		  // Add `num` to `this` in-place
		  BN.prototype.iadd = function iadd(num) {
		    var r;
	
		    // negative + positive
		    if (this.negative !== 0 && num.negative === 0) {
		      this.negative = 0;
		      r = this.isub(num);
		      this.negative ^= 1;
		      return this._normSign();
	
		      // positive + negative
		    } else if (this.negative === 0 && num.negative !== 0) {
		      num.negative = 0;
		      r = this.isub(num);
		      num.negative = 1;
		      return r._normSign();
		    }
	
		    // a.length > b.length
		    var a, b;
		    if (this.length > num.length) {
		      a = this;
		      b = num;
		    } else {
		      a = num;
		      b = this;
		    }
	
		    var carry = 0;
		    for (var i = 0; i < b.length; i++) {
		      r = (a.words[i] | 0) + (b.words[i] | 0) + carry;
		      this.words[i] = r & 0x3ffffff;
		      carry = r >>> 26;
		    }
		    for (; carry !== 0 && i < a.length; i++) {
		      r = (a.words[i] | 0) + carry;
		      this.words[i] = r & 0x3ffffff;
		      carry = r >>> 26;
		    }
	
		    this.length = a.length;
		    if (carry !== 0) {
		      this.words[this.length] = carry;
		      this.length++;
		      // Copy the rest of the words
		    } else if (a !== this) {
		      for (; i < a.length; i++) {
		        this.words[i] = a.words[i];
		      }
		    }
	
		    return this;
		  };
	
		  // Add `num` to `this`
		  BN.prototype.add = function add(num) {
		    var res;
		    if (num.negative !== 0 && this.negative === 0) {
		      num.negative = 0;
		      res = this.sub(num);
		      num.negative ^= 1;
		      return res;
		    } else if (num.negative === 0 && this.negative !== 0) {
		      this.negative = 0;
		      res = num.sub(this);
		      this.negative = 1;
		      return res;
		    }
	
		    if (this.length > num.length) return this.clone().iadd(num);
	
		    return num.clone().iadd(this);
		  };
	
		  // Subtract `num` from `this` in-place
		  BN.prototype.isub = function isub(num) {
		    // this - (-num) = this + num
		    if (num.negative !== 0) {
		      num.negative = 0;
		      var r = this.iadd(num);
		      num.negative = 1;
		      return r._normSign();
	
		      // -this - num = -(this + num)
		    } else if (this.negative !== 0) {
		      this.negative = 0;
		      this.iadd(num);
		      this.negative = 1;
		      return this._normSign();
		    }
	
		    // At this point both numbers are positive
		    var cmp = this.cmp(num);
	
		    // Optimization - zeroify
		    if (cmp === 0) {
		      this.negative = 0;
		      this.length = 1;
		      this.words[0] = 0;
		      return this;
		    }
	
		    // a > b
		    var a, b;
		    if (cmp > 0) {
		      a = this;
		      b = num;
		    } else {
		      a = num;
		      b = this;
		    }
	
		    var carry = 0;
		    for (var i = 0; i < b.length; i++) {
		      r = (a.words[i] | 0) - (b.words[i] | 0) + carry;
		      carry = r >> 26;
		      this.words[i] = r & 0x3ffffff;
		    }
		    for (; carry !== 0 && i < a.length; i++) {
		      r = (a.words[i] | 0) + carry;
		      carry = r >> 26;
		      this.words[i] = r & 0x3ffffff;
		    }
	
		    // Copy rest of the words
		    if (carry === 0 && i < a.length && a !== this) {
		      for (; i < a.length; i++) {
		        this.words[i] = a.words[i];
		      }
		    }
	
		    this.length = Math.max(this.length, i);
	
		    if (a !== this) {
		      this.negative = 1;
		    }
	
		    return this.strip();
		  };
	
		  // Subtract `num` from `this`
		  BN.prototype.sub = function sub(num) {
		    return this.clone().isub(num);
		  };
	
		  function smallMulTo(self, num, out) {
		    out.negative = num.negative ^ self.negative;
		    var len = self.length + num.length | 0;
		    out.length = len;
		    len = len - 1 | 0;
	
		    // Peel one iteration (compiler can't do it, because of code complexity)
		    var a = self.words[0] | 0;
		    var b = num.words[0] | 0;
		    var r = a * b;
	
		    var lo = r & 0x3ffffff;
		    var carry = r / 0x4000000 | 0;
		    out.words[0] = lo;
	
		    for (var k = 1; k < len; k++) {
		      // Sum all words with the same `i + j = k` and accumulate `ncarry`,
		      // note that ncarry could be >= 0x3ffffff
		      var ncarry = carry >>> 26;
		      var rword = carry & 0x3ffffff;
		      var maxJ = Math.min(k, num.length - 1);
		      for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {
		        var i = k - j | 0;
		        a = self.words[i] | 0;
		        b = num.words[j] | 0;
		        r = a * b + rword;
		        ncarry += r / 0x4000000 | 0;
		        rword = r & 0x3ffffff;
		      }
		      out.words[k] = rword | 0;
		      carry = ncarry | 0;
		    }
		    if (carry !== 0) {
		      out.words[k] = carry | 0;
		    } else {
		      out.length--;
		    }
	
		    return out.strip();
		  }
	
		  // TODO(indutny): it may be reasonable to omit it for users who don't need
		  // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit
		  // multiplication (like elliptic secp256k1).
		  var comb10MulTo = function comb10MulTo(self, num, out) {
		    var a = self.words;
		    var b = num.words;
		    var o = out.words;
		    var c = 0;
		    var lo;
		    var mid;
		    var hi;
		    var a0 = a[0] | 0;
		    var al0 = a0 & 0x1fff;
		    var ah0 = a0 >>> 13;
		    var a1 = a[1] | 0;
		    var al1 = a1 & 0x1fff;
		    var ah1 = a1 >>> 13;
		    var a2 = a[2] | 0;
		    var al2 = a2 & 0x1fff;
		    var ah2 = a2 >>> 13;
		    var a3 = a[3] | 0;
		    var al3 = a3 & 0x1fff;
		    var ah3 = a3 >>> 13;
		    var a4 = a[4] | 0;
		    var al4 = a4 & 0x1fff;
		    var ah4 = a4 >>> 13;
		    var a5 = a[5] | 0;
		    var al5 = a5 & 0x1fff;
		    var ah5 = a5 >>> 13;
		    var a6 = a[6] | 0;
		    var al6 = a6 & 0x1fff;
		    var ah6 = a6 >>> 13;
		    var a7 = a[7] | 0;
		    var al7 = a7 & 0x1fff;
		    var ah7 = a7 >>> 13;
		    var a8 = a[8] | 0;
		    var al8 = a8 & 0x1fff;
		    var ah8 = a8 >>> 13;
		    var a9 = a[9] | 0;
		    var al9 = a9 & 0x1fff;
		    var ah9 = a9 >>> 13;
		    var b0 = b[0] | 0;
		    var bl0 = b0 & 0x1fff;
		    var bh0 = b0 >>> 13;
		    var b1 = b[1] | 0;
		    var bl1 = b1 & 0x1fff;
		    var bh1 = b1 >>> 13;
		    var b2 = b[2] | 0;
		    var bl2 = b2 & 0x1fff;
		    var bh2 = b2 >>> 13;
		    var b3 = b[3] | 0;
		    var bl3 = b3 & 0x1fff;
		    var bh3 = b3 >>> 13;
		    var b4 = b[4] | 0;
		    var bl4 = b4 & 0x1fff;
		    var bh4 = b4 >>> 13;
		    var b5 = b[5] | 0;
		    var bl5 = b5 & 0x1fff;
		    var bh5 = b5 >>> 13;
		    var b6 = b[6] | 0;
		    var bl6 = b6 & 0x1fff;
		    var bh6 = b6 >>> 13;
		    var b7 = b[7] | 0;
		    var bl7 = b7 & 0x1fff;
		    var bh7 = b7 >>> 13;
		    var b8 = b[8] | 0;
		    var bl8 = b8 & 0x1fff;
		    var bh8 = b8 >>> 13;
		    var b9 = b[9] | 0;
		    var bl9 = b9 & 0x1fff;
		    var bh9 = b9 >>> 13;
	
		    out.negative = self.negative ^ num.negative;
		    out.length = 19;
		    /* k = 0 */
		    lo = Math.imul(al0, bl0);
		    mid = Math.imul(al0, bh0);
		    mid = mid + Math.imul(ah0, bl0) | 0;
		    hi = Math.imul(ah0, bh0);
		    var w0 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w0 >>> 26) | 0;
		    w0 &= 0x3ffffff;
		    /* k = 1 */
		    lo = Math.imul(al1, bl0);
		    mid = Math.imul(al1, bh0);
		    mid = mid + Math.imul(ah1, bl0) | 0;
		    hi = Math.imul(ah1, bh0);
		    lo = lo + Math.imul(al0, bl1) | 0;
		    mid = mid + Math.imul(al0, bh1) | 0;
		    mid = mid + Math.imul(ah0, bl1) | 0;
		    hi = hi + Math.imul(ah0, bh1) | 0;
		    var w1 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w1 >>> 26) | 0;
		    w1 &= 0x3ffffff;
		    /* k = 2 */
		    lo = Math.imul(al2, bl0);
		    mid = Math.imul(al2, bh0);
		    mid = mid + Math.imul(ah2, bl0) | 0;
		    hi = Math.imul(ah2, bh0);
		    lo = lo + Math.imul(al1, bl1) | 0;
		    mid = mid + Math.imul(al1, bh1) | 0;
		    mid = mid + Math.imul(ah1, bl1) | 0;
		    hi = hi + Math.imul(ah1, bh1) | 0;
		    lo = lo + Math.imul(al0, bl2) | 0;
		    mid = mid + Math.imul(al0, bh2) | 0;
		    mid = mid + Math.imul(ah0, bl2) | 0;
		    hi = hi + Math.imul(ah0, bh2) | 0;
		    var w2 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w2 >>> 26) | 0;
		    w2 &= 0x3ffffff;
		    /* k = 3 */
		    lo = Math.imul(al3, bl0);
		    mid = Math.imul(al3, bh0);
		    mid = mid + Math.imul(ah3, bl0) | 0;
		    hi = Math.imul(ah3, bh0);
		    lo = lo + Math.imul(al2, bl1) | 0;
		    mid = mid + Math.imul(al2, bh1) | 0;
		    mid = mid + Math.imul(ah2, bl1) | 0;
		    hi = hi + Math.imul(ah2, bh1) | 0;
		    lo = lo + Math.imul(al1, bl2) | 0;
		    mid = mid + Math.imul(al1, bh2) | 0;
		    mid = mid + Math.imul(ah1, bl2) | 0;
		    hi = hi + Math.imul(ah1, bh2) | 0;
		    lo = lo + Math.imul(al0, bl3) | 0;
		    mid = mid + Math.imul(al0, bh3) | 0;
		    mid = mid + Math.imul(ah0, bl3) | 0;
		    hi = hi + Math.imul(ah0, bh3) | 0;
		    var w3 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w3 >>> 26) | 0;
		    w3 &= 0x3ffffff;
		    /* k = 4 */
		    lo = Math.imul(al4, bl0);
		    mid = Math.imul(al4, bh0);
		    mid = mid + Math.imul(ah4, bl0) | 0;
		    hi = Math.imul(ah4, bh0);
		    lo = lo + Math.imul(al3, bl1) | 0;
		    mid = mid + Math.imul(al3, bh1) | 0;
		    mid = mid + Math.imul(ah3, bl1) | 0;
		    hi = hi + Math.imul(ah3, bh1) | 0;
		    lo = lo + Math.imul(al2, bl2) | 0;
		    mid = mid + Math.imul(al2, bh2) | 0;
		    mid = mid + Math.imul(ah2, bl2) | 0;
		    hi = hi + Math.imul(ah2, bh2) | 0;
		    lo = lo + Math.imul(al1, bl3) | 0;
		    mid = mid + Math.imul(al1, bh3) | 0;
		    mid = mid + Math.imul(ah1, bl3) | 0;
		    hi = hi + Math.imul(ah1, bh3) | 0;
		    lo = lo + Math.imul(al0, bl4) | 0;
		    mid = mid + Math.imul(al0, bh4) | 0;
		    mid = mid + Math.imul(ah0, bl4) | 0;
		    hi = hi + Math.imul(ah0, bh4) | 0;
		    var w4 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w4 >>> 26) | 0;
		    w4 &= 0x3ffffff;
		    /* k = 5 */
		    lo = Math.imul(al5, bl0);
		    mid = Math.imul(al5, bh0);
		    mid = mid + Math.imul(ah5, bl0) | 0;
		    hi = Math.imul(ah5, bh0);
		    lo = lo + Math.imul(al4, bl1) | 0;
		    mid = mid + Math.imul(al4, bh1) | 0;
		    mid = mid + Math.imul(ah4, bl1) | 0;
		    hi = hi + Math.imul(ah4, bh1) | 0;
		    lo = lo + Math.imul(al3, bl2) | 0;
		    mid = mid + Math.imul(al3, bh2) | 0;
		    mid = mid + Math.imul(ah3, bl2) | 0;
		    hi = hi + Math.imul(ah3, bh2) | 0;
		    lo = lo + Math.imul(al2, bl3) | 0;
		    mid = mid + Math.imul(al2, bh3) | 0;
		    mid = mid + Math.imul(ah2, bl3) | 0;
		    hi = hi + Math.imul(ah2, bh3) | 0;
		    lo = lo + Math.imul(al1, bl4) | 0;
		    mid = mid + Math.imul(al1, bh4) | 0;
		    mid = mid + Math.imul(ah1, bl4) | 0;
		    hi = hi + Math.imul(ah1, bh4) | 0;
		    lo = lo + Math.imul(al0, bl5) | 0;
		    mid = mid + Math.imul(al0, bh5) | 0;
		    mid = mid + Math.imul(ah0, bl5) | 0;
		    hi = hi + Math.imul(ah0, bh5) | 0;
		    var w5 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w5 >>> 26) | 0;
		    w5 &= 0x3ffffff;
		    /* k = 6 */
		    lo = Math.imul(al6, bl0);
		    mid = Math.imul(al6, bh0);
		    mid = mid + Math.imul(ah6, bl0) | 0;
		    hi = Math.imul(ah6, bh0);
		    lo = lo + Math.imul(al5, bl1) | 0;
		    mid = mid + Math.imul(al5, bh1) | 0;
		    mid = mid + Math.imul(ah5, bl1) | 0;
		    hi = hi + Math.imul(ah5, bh1) | 0;
		    lo = lo + Math.imul(al4, bl2) | 0;
		    mid = mid + Math.imul(al4, bh2) | 0;
		    mid = mid + Math.imul(ah4, bl2) | 0;
		    hi = hi + Math.imul(ah4, bh2) | 0;
		    lo = lo + Math.imul(al3, bl3) | 0;
		    mid = mid + Math.imul(al3, bh3) | 0;
		    mid = mid + Math.imul(ah3, bl3) | 0;
		    hi = hi + Math.imul(ah3, bh3) | 0;
		    lo = lo + Math.imul(al2, bl4) | 0;
		    mid = mid + Math.imul(al2, bh4) | 0;
		    mid = mid + Math.imul(ah2, bl4) | 0;
		    hi = hi + Math.imul(ah2, bh4) | 0;
		    lo = lo + Math.imul(al1, bl5) | 0;
		    mid = mid + Math.imul(al1, bh5) | 0;
		    mid = mid + Math.imul(ah1, bl5) | 0;
		    hi = hi + Math.imul(ah1, bh5) | 0;
		    lo = lo + Math.imul(al0, bl6) | 0;
		    mid = mid + Math.imul(al0, bh6) | 0;
		    mid = mid + Math.imul(ah0, bl6) | 0;
		    hi = hi + Math.imul(ah0, bh6) | 0;
		    var w6 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w6 >>> 26) | 0;
		    w6 &= 0x3ffffff;
		    /* k = 7 */
		    lo = Math.imul(al7, bl0);
		    mid = Math.imul(al7, bh0);
		    mid = mid + Math.imul(ah7, bl0) | 0;
		    hi = Math.imul(ah7, bh0);
		    lo = lo + Math.imul(al6, bl1) | 0;
		    mid = mid + Math.imul(al6, bh1) | 0;
		    mid = mid + Math.imul(ah6, bl1) | 0;
		    hi = hi + Math.imul(ah6, bh1) | 0;
		    lo = lo + Math.imul(al5, bl2) | 0;
		    mid = mid + Math.imul(al5, bh2) | 0;
		    mid = mid + Math.imul(ah5, bl2) | 0;
		    hi = hi + Math.imul(ah5, bh2) | 0;
		    lo = lo + Math.imul(al4, bl3) | 0;
		    mid = mid + Math.imul(al4, bh3) | 0;
		    mid = mid + Math.imul(ah4, bl3) | 0;
		    hi = hi + Math.imul(ah4, bh3) | 0;
		    lo = lo + Math.imul(al3, bl4) | 0;
		    mid = mid + Math.imul(al3, bh4) | 0;
		    mid = mid + Math.imul(ah3, bl4) | 0;
		    hi = hi + Math.imul(ah3, bh4) | 0;
		    lo = lo + Math.imul(al2, bl5) | 0;
		    mid = mid + Math.imul(al2, bh5) | 0;
		    mid = mid + Math.imul(ah2, bl5) | 0;
		    hi = hi + Math.imul(ah2, bh5) | 0;
		    lo = lo + Math.imul(al1, bl6) | 0;
		    mid = mid + Math.imul(al1, bh6) | 0;
		    mid = mid + Math.imul(ah1, bl6) | 0;
		    hi = hi + Math.imul(ah1, bh6) | 0;
		    lo = lo + Math.imul(al0, bl7) | 0;
		    mid = mid + Math.imul(al0, bh7) | 0;
		    mid = mid + Math.imul(ah0, bl7) | 0;
		    hi = hi + Math.imul(ah0, bh7) | 0;
		    var w7 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w7 >>> 26) | 0;
		    w7 &= 0x3ffffff;
		    /* k = 8 */
		    lo = Math.imul(al8, bl0);
		    mid = Math.imul(al8, bh0);
		    mid = mid + Math.imul(ah8, bl0) | 0;
		    hi = Math.imul(ah8, bh0);
		    lo = lo + Math.imul(al7, bl1) | 0;
		    mid = mid + Math.imul(al7, bh1) | 0;
		    mid = mid + Math.imul(ah7, bl1) | 0;
		    hi = hi + Math.imul(ah7, bh1) | 0;
		    lo = lo + Math.imul(al6, bl2) | 0;
		    mid = mid + Math.imul(al6, bh2) | 0;
		    mid = mid + Math.imul(ah6, bl2) | 0;
		    hi = hi + Math.imul(ah6, bh2) | 0;
		    lo = lo + Math.imul(al5, bl3) | 0;
		    mid = mid + Math.imul(al5, bh3) | 0;
		    mid = mid + Math.imul(ah5, bl3) | 0;
		    hi = hi + Math.imul(ah5, bh3) | 0;
		    lo = lo + Math.imul(al4, bl4) | 0;
		    mid = mid + Math.imul(al4, bh4) | 0;
		    mid = mid + Math.imul(ah4, bl4) | 0;
		    hi = hi + Math.imul(ah4, bh4) | 0;
		    lo = lo + Math.imul(al3, bl5) | 0;
		    mid = mid + Math.imul(al3, bh5) | 0;
		    mid = mid + Math.imul(ah3, bl5) | 0;
		    hi = hi + Math.imul(ah3, bh5) | 0;
		    lo = lo + Math.imul(al2, bl6) | 0;
		    mid = mid + Math.imul(al2, bh6) | 0;
		    mid = mid + Math.imul(ah2, bl6) | 0;
		    hi = hi + Math.imul(ah2, bh6) | 0;
		    lo = lo + Math.imul(al1, bl7) | 0;
		    mid = mid + Math.imul(al1, bh7) | 0;
		    mid = mid + Math.imul(ah1, bl7) | 0;
		    hi = hi + Math.imul(ah1, bh7) | 0;
		    lo = lo + Math.imul(al0, bl8) | 0;
		    mid = mid + Math.imul(al0, bh8) | 0;
		    mid = mid + Math.imul(ah0, bl8) | 0;
		    hi = hi + Math.imul(ah0, bh8) | 0;
		    var w8 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w8 >>> 26) | 0;
		    w8 &= 0x3ffffff;
		    /* k = 9 */
		    lo = Math.imul(al9, bl0);
		    mid = Math.imul(al9, bh0);
		    mid = mid + Math.imul(ah9, bl0) | 0;
		    hi = Math.imul(ah9, bh0);
		    lo = lo + Math.imul(al8, bl1) | 0;
		    mid = mid + Math.imul(al8, bh1) | 0;
		    mid = mid + Math.imul(ah8, bl1) | 0;
		    hi = hi + Math.imul(ah8, bh1) | 0;
		    lo = lo + Math.imul(al7, bl2) | 0;
		    mid = mid + Math.imul(al7, bh2) | 0;
		    mid = mid + Math.imul(ah7, bl2) | 0;
		    hi = hi + Math.imul(ah7, bh2) | 0;
		    lo = lo + Math.imul(al6, bl3) | 0;
		    mid = mid + Math.imul(al6, bh3) | 0;
		    mid = mid + Math.imul(ah6, bl3) | 0;
		    hi = hi + Math.imul(ah6, bh3) | 0;
		    lo = lo + Math.imul(al5, bl4) | 0;
		    mid = mid + Math.imul(al5, bh4) | 0;
		    mid = mid + Math.imul(ah5, bl4) | 0;
		    hi = hi + Math.imul(ah5, bh4) | 0;
		    lo = lo + Math.imul(al4, bl5) | 0;
		    mid = mid + Math.imul(al4, bh5) | 0;
		    mid = mid + Math.imul(ah4, bl5) | 0;
		    hi = hi + Math.imul(ah4, bh5) | 0;
		    lo = lo + Math.imul(al3, bl6) | 0;
		    mid = mid + Math.imul(al3, bh6) | 0;
		    mid = mid + Math.imul(ah3, bl6) | 0;
		    hi = hi + Math.imul(ah3, bh6) | 0;
		    lo = lo + Math.imul(al2, bl7) | 0;
		    mid = mid + Math.imul(al2, bh7) | 0;
		    mid = mid + Math.imul(ah2, bl7) | 0;
		    hi = hi + Math.imul(ah2, bh7) | 0;
		    lo = lo + Math.imul(al1, bl8) | 0;
		    mid = mid + Math.imul(al1, bh8) | 0;
		    mid = mid + Math.imul(ah1, bl8) | 0;
		    hi = hi + Math.imul(ah1, bh8) | 0;
		    lo = lo + Math.imul(al0, bl9) | 0;
		    mid = mid + Math.imul(al0, bh9) | 0;
		    mid = mid + Math.imul(ah0, bl9) | 0;
		    hi = hi + Math.imul(ah0, bh9) | 0;
		    var w9 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w9 >>> 26) | 0;
		    w9 &= 0x3ffffff;
		    /* k = 10 */
		    lo = Math.imul(al9, bl1);
		    mid = Math.imul(al9, bh1);
		    mid = mid + Math.imul(ah9, bl1) | 0;
		    hi = Math.imul(ah9, bh1);
		    lo = lo + Math.imul(al8, bl2) | 0;
		    mid = mid + Math.imul(al8, bh2) | 0;
		    mid = mid + Math.imul(ah8, bl2) | 0;
		    hi = hi + Math.imul(ah8, bh2) | 0;
		    lo = lo + Math.imul(al7, bl3) | 0;
		    mid = mid + Math.imul(al7, bh3) | 0;
		    mid = mid + Math.imul(ah7, bl3) | 0;
		    hi = hi + Math.imul(ah7, bh3) | 0;
		    lo = lo + Math.imul(al6, bl4) | 0;
		    mid = mid + Math.imul(al6, bh4) | 0;
		    mid = mid + Math.imul(ah6, bl4) | 0;
		    hi = hi + Math.imul(ah6, bh4) | 0;
		    lo = lo + Math.imul(al5, bl5) | 0;
		    mid = mid + Math.imul(al5, bh5) | 0;
		    mid = mid + Math.imul(ah5, bl5) | 0;
		    hi = hi + Math.imul(ah5, bh5) | 0;
		    lo = lo + Math.imul(al4, bl6) | 0;
		    mid = mid + Math.imul(al4, bh6) | 0;
		    mid = mid + Math.imul(ah4, bl6) | 0;
		    hi = hi + Math.imul(ah4, bh6) | 0;
		    lo = lo + Math.imul(al3, bl7) | 0;
		    mid = mid + Math.imul(al3, bh7) | 0;
		    mid = mid + Math.imul(ah3, bl7) | 0;
		    hi = hi + Math.imul(ah3, bh7) | 0;
		    lo = lo + Math.imul(al2, bl8) | 0;
		    mid = mid + Math.imul(al2, bh8) | 0;
		    mid = mid + Math.imul(ah2, bl8) | 0;
		    hi = hi + Math.imul(ah2, bh8) | 0;
		    lo = lo + Math.imul(al1, bl9) | 0;
		    mid = mid + Math.imul(al1, bh9) | 0;
		    mid = mid + Math.imul(ah1, bl9) | 0;
		    hi = hi + Math.imul(ah1, bh9) | 0;
		    var w10 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w10 >>> 26) | 0;
		    w10 &= 0x3ffffff;
		    /* k = 11 */
		    lo = Math.imul(al9, bl2);
		    mid = Math.imul(al9, bh2);
		    mid = mid + Math.imul(ah9, bl2) | 0;
		    hi = Math.imul(ah9, bh2);
		    lo = lo + Math.imul(al8, bl3) | 0;
		    mid = mid + Math.imul(al8, bh3) | 0;
		    mid = mid + Math.imul(ah8, bl3) | 0;
		    hi = hi + Math.imul(ah8, bh3) | 0;
		    lo = lo + Math.imul(al7, bl4) | 0;
		    mid = mid + Math.imul(al7, bh4) | 0;
		    mid = mid + Math.imul(ah7, bl4) | 0;
		    hi = hi + Math.imul(ah7, bh4) | 0;
		    lo = lo + Math.imul(al6, bl5) | 0;
		    mid = mid + Math.imul(al6, bh5) | 0;
		    mid = mid + Math.imul(ah6, bl5) | 0;
		    hi = hi + Math.imul(ah6, bh5) | 0;
		    lo = lo + Math.imul(al5, bl6) | 0;
		    mid = mid + Math.imul(al5, bh6) | 0;
		    mid = mid + Math.imul(ah5, bl6) | 0;
		    hi = hi + Math.imul(ah5, bh6) | 0;
		    lo = lo + Math.imul(al4, bl7) | 0;
		    mid = mid + Math.imul(al4, bh7) | 0;
		    mid = mid + Math.imul(ah4, bl7) | 0;
		    hi = hi + Math.imul(ah4, bh7) | 0;
		    lo = lo + Math.imul(al3, bl8) | 0;
		    mid = mid + Math.imul(al3, bh8) | 0;
		    mid = mid + Math.imul(ah3, bl8) | 0;
		    hi = hi + Math.imul(ah3, bh8) | 0;
		    lo = lo + Math.imul(al2, bl9) | 0;
		    mid = mid + Math.imul(al2, bh9) | 0;
		    mid = mid + Math.imul(ah2, bl9) | 0;
		    hi = hi + Math.imul(ah2, bh9) | 0;
		    var w11 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w11 >>> 26) | 0;
		    w11 &= 0x3ffffff;
		    /* k = 12 */
		    lo = Math.imul(al9, bl3);
		    mid = Math.imul(al9, bh3);
		    mid = mid + Math.imul(ah9, bl3) | 0;
		    hi = Math.imul(ah9, bh3);
		    lo = lo + Math.imul(al8, bl4) | 0;
		    mid = mid + Math.imul(al8, bh4) | 0;
		    mid = mid + Math.imul(ah8, bl4) | 0;
		    hi = hi + Math.imul(ah8, bh4) | 0;
		    lo = lo + Math.imul(al7, bl5) | 0;
		    mid = mid + Math.imul(al7, bh5) | 0;
		    mid = mid + Math.imul(ah7, bl5) | 0;
		    hi = hi + Math.imul(ah7, bh5) | 0;
		    lo = lo + Math.imul(al6, bl6) | 0;
		    mid = mid + Math.imul(al6, bh6) | 0;
		    mid = mid + Math.imul(ah6, bl6) | 0;
		    hi = hi + Math.imul(ah6, bh6) | 0;
		    lo = lo + Math.imul(al5, bl7) | 0;
		    mid = mid + Math.imul(al5, bh7) | 0;
		    mid = mid + Math.imul(ah5, bl7) | 0;
		    hi = hi + Math.imul(ah5, bh7) | 0;
		    lo = lo + Math.imul(al4, bl8) | 0;
		    mid = mid + Math.imul(al4, bh8) | 0;
		    mid = mid + Math.imul(ah4, bl8) | 0;
		    hi = hi + Math.imul(ah4, bh8) | 0;
		    lo = lo + Math.imul(al3, bl9) | 0;
		    mid = mid + Math.imul(al3, bh9) | 0;
		    mid = mid + Math.imul(ah3, bl9) | 0;
		    hi = hi + Math.imul(ah3, bh9) | 0;
		    var w12 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w12 >>> 26) | 0;
		    w12 &= 0x3ffffff;
		    /* k = 13 */
		    lo = Math.imul(al9, bl4);
		    mid = Math.imul(al9, bh4);
		    mid = mid + Math.imul(ah9, bl4) | 0;
		    hi = Math.imul(ah9, bh4);
		    lo = lo + Math.imul(al8, bl5) | 0;
		    mid = mid + Math.imul(al8, bh5) | 0;
		    mid = mid + Math.imul(ah8, bl5) | 0;
		    hi = hi + Math.imul(ah8, bh5) | 0;
		    lo = lo + Math.imul(al7, bl6) | 0;
		    mid = mid + Math.imul(al7, bh6) | 0;
		    mid = mid + Math.imul(ah7, bl6) | 0;
		    hi = hi + Math.imul(ah7, bh6) | 0;
		    lo = lo + Math.imul(al6, bl7) | 0;
		    mid = mid + Math.imul(al6, bh7) | 0;
		    mid = mid + Math.imul(ah6, bl7) | 0;
		    hi = hi + Math.imul(ah6, bh7) | 0;
		    lo = lo + Math.imul(al5, bl8) | 0;
		    mid = mid + Math.imul(al5, bh8) | 0;
		    mid = mid + Math.imul(ah5, bl8) | 0;
		    hi = hi + Math.imul(ah5, bh8) | 0;
		    lo = lo + Math.imul(al4, bl9) | 0;
		    mid = mid + Math.imul(al4, bh9) | 0;
		    mid = mid + Math.imul(ah4, bl9) | 0;
		    hi = hi + Math.imul(ah4, bh9) | 0;
		    var w13 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w13 >>> 26) | 0;
		    w13 &= 0x3ffffff;
		    /* k = 14 */
		    lo = Math.imul(al9, bl5);
		    mid = Math.imul(al9, bh5);
		    mid = mid + Math.imul(ah9, bl5) | 0;
		    hi = Math.imul(ah9, bh5);
		    lo = lo + Math.imul(al8, bl6) | 0;
		    mid = mid + Math.imul(al8, bh6) | 0;
		    mid = mid + Math.imul(ah8, bl6) | 0;
		    hi = hi + Math.imul(ah8, bh6) | 0;
		    lo = lo + Math.imul(al7, bl7) | 0;
		    mid = mid + Math.imul(al7, bh7) | 0;
		    mid = mid + Math.imul(ah7, bl7) | 0;
		    hi = hi + Math.imul(ah7, bh7) | 0;
		    lo = lo + Math.imul(al6, bl8) | 0;
		    mid = mid + Math.imul(al6, bh8) | 0;
		    mid = mid + Math.imul(ah6, bl8) | 0;
		    hi = hi + Math.imul(ah6, bh8) | 0;
		    lo = lo + Math.imul(al5, bl9) | 0;
		    mid = mid + Math.imul(al5, bh9) | 0;
		    mid = mid + Math.imul(ah5, bl9) | 0;
		    hi = hi + Math.imul(ah5, bh9) | 0;
		    var w14 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w14 >>> 26) | 0;
		    w14 &= 0x3ffffff;
		    /* k = 15 */
		    lo = Math.imul(al9, bl6);
		    mid = Math.imul(al9, bh6);
		    mid = mid + Math.imul(ah9, bl6) | 0;
		    hi = Math.imul(ah9, bh6);
		    lo = lo + Math.imul(al8, bl7) | 0;
		    mid = mid + Math.imul(al8, bh7) | 0;
		    mid = mid + Math.imul(ah8, bl7) | 0;
		    hi = hi + Math.imul(ah8, bh7) | 0;
		    lo = lo + Math.imul(al7, bl8) | 0;
		    mid = mid + Math.imul(al7, bh8) | 0;
		    mid = mid + Math.imul(ah7, bl8) | 0;
		    hi = hi + Math.imul(ah7, bh8) | 0;
		    lo = lo + Math.imul(al6, bl9) | 0;
		    mid = mid + Math.imul(al6, bh9) | 0;
		    mid = mid + Math.imul(ah6, bl9) | 0;
		    hi = hi + Math.imul(ah6, bh9) | 0;
		    var w15 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w15 >>> 26) | 0;
		    w15 &= 0x3ffffff;
		    /* k = 16 */
		    lo = Math.imul(al9, bl7);
		    mid = Math.imul(al9, bh7);
		    mid = mid + Math.imul(ah9, bl7) | 0;
		    hi = Math.imul(ah9, bh7);
		    lo = lo + Math.imul(al8, bl8) | 0;
		    mid = mid + Math.imul(al8, bh8) | 0;
		    mid = mid + Math.imul(ah8, bl8) | 0;
		    hi = hi + Math.imul(ah8, bh8) | 0;
		    lo = lo + Math.imul(al7, bl9) | 0;
		    mid = mid + Math.imul(al7, bh9) | 0;
		    mid = mid + Math.imul(ah7, bl9) | 0;
		    hi = hi + Math.imul(ah7, bh9) | 0;
		    var w16 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w16 >>> 26) | 0;
		    w16 &= 0x3ffffff;
		    /* k = 17 */
		    lo = Math.imul(al9, bl8);
		    mid = Math.imul(al9, bh8);
		    mid = mid + Math.imul(ah9, bl8) | 0;
		    hi = Math.imul(ah9, bh8);
		    lo = lo + Math.imul(al8, bl9) | 0;
		    mid = mid + Math.imul(al8, bh9) | 0;
		    mid = mid + Math.imul(ah8, bl9) | 0;
		    hi = hi + Math.imul(ah8, bh9) | 0;
		    var w17 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w17 >>> 26) | 0;
		    w17 &= 0x3ffffff;
		    /* k = 18 */
		    lo = Math.imul(al9, bl9);
		    mid = Math.imul(al9, bh9);
		    mid = mid + Math.imul(ah9, bl9) | 0;
		    hi = Math.imul(ah9, bh9);
		    var w18 = (c + lo | 0) + ((mid & 0x1fff) << 13) | 0;
		    c = (hi + (mid >>> 13) | 0) + (w18 >>> 26) | 0;
		    w18 &= 0x3ffffff;
		    o[0] = w0;
		    o[1] = w1;
		    o[2] = w2;
		    o[3] = w3;
		    o[4] = w4;
		    o[5] = w5;
		    o[6] = w6;
		    o[7] = w7;
		    o[8] = w8;
		    o[9] = w9;
		    o[10] = w10;
		    o[11] = w11;
		    o[12] = w12;
		    o[13] = w13;
		    o[14] = w14;
		    o[15] = w15;
		    o[16] = w16;
		    o[17] = w17;
		    o[18] = w18;
		    if (c !== 0) {
		      o[19] = c;
		      out.length++;
		    }
		    return out;
		  };
	
		  // Polyfill comb
		  if (!Math.imul) {
		    comb10MulTo = smallMulTo;
		  }
	
		  function bigMulTo(self, num, out) {
		    out.negative = num.negative ^ self.negative;
		    out.length = self.length + num.length;
	
		    var carry = 0;
		    var hncarry = 0;
		    for (var k = 0; k < out.length - 1; k++) {
		      // Sum all words with the same `i + j = k` and accumulate `ncarry`,
		      // note that ncarry could be >= 0x3ffffff
		      var ncarry = hncarry;
		      hncarry = 0;
		      var rword = carry & 0x3ffffff;
		      var maxJ = Math.min(k, num.length - 1);
		      for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {
		        var i = k - j;
		        var a = self.words[i] | 0;
		        var b = num.words[j] | 0;
		        var r = a * b;
	
		        var lo = r & 0x3ffffff;
		        ncarry = ncarry + (r / 0x4000000 | 0) | 0;
		        lo = lo + rword | 0;
		        rword = lo & 0x3ffffff;
		        ncarry = ncarry + (lo >>> 26) | 0;
	
		        hncarry += ncarry >>> 26;
		        ncarry &= 0x3ffffff;
		      }
		      out.words[k] = rword;
		      carry = ncarry;
		      ncarry = hncarry;
		    }
		    if (carry !== 0) {
		      out.words[k] = carry;
		    } else {
		      out.length--;
		    }
	
		    return out.strip();
		  }
	
		  function jumboMulTo(self, num, out) {
		    var fftm = new FFTM();
		    return fftm.mulp(self, num, out);
		  }
	
		  BN.prototype.mulTo = function mulTo(num, out) {
		    var res;
		    var len = this.length + num.length;
		    if (this.length === 10 && num.length === 10) {
		      res = comb10MulTo(this, num, out);
		    } else if (len < 63) {
		      res = smallMulTo(this, num, out);
		    } else if (len < 1024) {
		      res = bigMulTo(this, num, out);
		    } else {
		      res = jumboMulTo(this, num, out);
		    }
	
		    return res;
		  };
	
		  // Cooley-Tukey algorithm for FFT
		  // slightly revisited to rely on looping instead of recursion
	
		  function FFTM(x, y) {
		    this.x = x;
		    this.y = y;
		  }
	
		  FFTM.prototype.makeRBT = function makeRBT(N) {
		    var t = new Array(N);
		    var l = BN.prototype._countBits(N) - 1;
		    for (var i = 0; i < N; i++) {
		      t[i] = this.revBin(i, l, N);
		    }
	
		    return t;
		  };
	
		  // Returns binary-reversed representation of `x`
		  FFTM.prototype.revBin = function revBin(x, l, N) {
		    if (x === 0 || x === N - 1) return x;
	
		    var rb = 0;
		    for (var i = 0; i < l; i++) {
		      rb |= (x & 1) << l - i - 1;
		      x >>= 1;
		    }
	
		    return rb;
		  };
	
		  // Performs "tweedling" phase, therefore 'emulating'
		  // behaviour of the recursive algorithm
		  FFTM.prototype.permute = function permute(rbt, rws, iws, rtws, itws, N) {
		    for (var i = 0; i < N; i++) {
		      rtws[i] = rws[rbt[i]];
		      itws[i] = iws[rbt[i]];
		    }
		  };
	
		  FFTM.prototype.transform = function transform(rws, iws, rtws, itws, N, rbt) {
		    this.permute(rbt, rws, iws, rtws, itws, N);
	
		    for (var s = 1; s < N; s <<= 1) {
		      var l = s << 1;
	
		      var rtwdf = Math.cos(2 * Math.PI / l);
		      var itwdf = Math.sin(2 * Math.PI / l);
	
		      for (var p = 0; p < N; p += l) {
		        var rtwdf_ = rtwdf;
		        var itwdf_ = itwdf;
	
		        for (var j = 0; j < s; j++) {
		          var re = rtws[p + j];
		          var ie = itws[p + j];
	
		          var ro = rtws[p + j + s];
		          var io = itws[p + j + s];
	
		          var rx = rtwdf_ * ro - itwdf_ * io;
	
		          io = rtwdf_ * io + itwdf_ * ro;
		          ro = rx;
	
		          rtws[p + j] = re + ro;
		          itws[p + j] = ie + io;
	
		          rtws[p + j + s] = re - ro;
		          itws[p + j + s] = ie - io;
	
		          /* jshint maxdepth : false */
		          if (j !== l) {
		            rx = rtwdf * rtwdf_ - itwdf * itwdf_;
	
		            itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_;
		            rtwdf_ = rx;
		          }
		        }
		      }
		    }
		  };
	
		  FFTM.prototype.guessLen13b = function guessLen13b(n, m) {
		    var N = Math.max(m, n) | 1;
		    var odd = N & 1;
		    var i = 0;
		    for (N = N / 2 | 0; N; N = N >>> 1) {
		      i++;
		    }
	
		    return 1 << i + 1 + odd;
		  };
	
		  FFTM.prototype.conjugate = function conjugate(rws, iws, N) {
		    if (N <= 1) return;
	
		    for (var i = 0; i < N / 2; i++) {
		      var t = rws[i];
	
		      rws[i] = rws[N - i - 1];
		      rws[N - i - 1] = t;
	
		      t = iws[i];
	
		      iws[i] = -iws[N - i - 1];
		      iws[N - i - 1] = -t;
		    }
		  };
	
		  FFTM.prototype.normalize13b = function normalize13b(ws, N) {
		    var carry = 0;
		    for (var i = 0; i < N / 2; i++) {
		      var w = Math.round(ws[2 * i + 1] / N) * 0x2000 + Math.round(ws[2 * i] / N) + carry;
	
		      ws[i] = w & 0x3ffffff;
	
		      if (w < 0x4000000) {
		        carry = 0;
		      } else {
		        carry = w / 0x4000000 | 0;
		      }
		    }
	
		    return ws;
		  };
	
		  FFTM.prototype.convert13b = function convert13b(ws, len, rws, N) {
		    var carry = 0;
		    for (var i = 0; i < len; i++) {
		      carry = carry + (ws[i] | 0);
	
		      rws[2 * i] = carry & 0x1fff;carry = carry >>> 13;
		      rws[2 * i + 1] = carry & 0x1fff;carry = carry >>> 13;
		    }
	
		    // Pad with zeroes
		    for (i = 2 * len; i < N; ++i) {
		      rws[i] = 0;
		    }
	
		    assert(carry === 0);
		    assert((carry & ~0x1fff) === 0);
		  };
	
		  FFTM.prototype.stub = function stub(N) {
		    var ph = new Array(N);
		    for (var i = 0; i < N; i++) {
		      ph[i] = 0;
		    }
	
		    return ph;
		  };
	
		  FFTM.prototype.mulp = function mulp(x, y, out) {
		    var N = 2 * this.guessLen13b(x.length, y.length);
	
		    var rbt = this.makeRBT(N);
	
		    var _ = this.stub(N);
	
		    var rws = new Array(N);
		    var rwst = new Array(N);
		    var iwst = new Array(N);
	
		    var nrws = new Array(N);
		    var nrwst = new Array(N);
		    var niwst = new Array(N);
	
		    var rmws = out.words;
		    rmws.length = N;
	
		    this.convert13b(x.words, x.length, rws, N);
		    this.convert13b(y.words, y.length, nrws, N);
	
		    this.transform(rws, _, rwst, iwst, N, rbt);
		    this.transform(nrws, _, nrwst, niwst, N, rbt);
	
		    for (var i = 0; i < N; i++) {
		      var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i];
		      iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i];
		      rwst[i] = rx;
		    }
	
		    this.conjugate(rwst, iwst, N);
		    this.transform(rwst, iwst, rmws, _, N, rbt);
		    this.conjugate(rmws, _, N);
		    this.normalize13b(rmws, N);
	
		    out.negative = x.negative ^ y.negative;
		    out.length = x.length + y.length;
		    return out.strip();
		  };
	
		  // Multiply `this` by `num`
		  BN.prototype.mul = function mul(num) {
		    var out = new BN(null);
		    out.words = new Array(this.length + num.length);
		    return this.mulTo(num, out);
		  };
	
		  // Multiply employing FFT
		  BN.prototype.mulf = function mulf(num) {
		    var out = new BN(null);
		    out.words = new Array(this.length + num.length);
		    return jumboMulTo(this, num, out);
		  };
	
		  // In-place Multiplication
		  BN.prototype.imul = function imul(num) {
		    return this.clone().mulTo(num, this);
		  };
	
		  BN.prototype.imuln = function imuln(num) {
		    assert(typeof num === 'number');
		    assert(num < 0x4000000);
	
		    // Carry
		    var carry = 0;
		    for (var i = 0; i < this.length; i++) {
		      var w = (this.words[i] | 0) * num;
		      var lo = (w & 0x3ffffff) + (carry & 0x3ffffff);
		      carry >>= 26;
		      carry += w / 0x4000000 | 0;
		      // NOTE: lo is 27bit maximum
		      carry += lo >>> 26;
		      this.words[i] = lo & 0x3ffffff;
		    }
	
		    if (carry !== 0) {
		      this.words[i] = carry;
		      this.length++;
		    }
	
		    return this;
		  };
	
		  BN.prototype.muln = function muln(num) {
		    return this.clone().imuln(num);
		  };
	
		  // `this` * `this`
		  BN.prototype.sqr = function sqr() {
		    return this.mul(this);
		  };
	
		  // `this` * `this` in-place
		  BN.prototype.isqr = function isqr() {
		    return this.imul(this.clone());
		  };
	
		  // Math.pow(`this`, `num`)
		  BN.prototype.pow = function pow(num) {
		    var w = toBitArray(num);
		    if (w.length === 0) return new BN(1);
	
		    // Skip leading zeroes
		    var res = this;
		    for (var i = 0; i < w.length; i++, res = res.sqr()) {
		      if (w[i] !== 0) break;
		    }
	
		    if (++i < w.length) {
		      for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) {
		        if (w[i] === 0) continue;
	
		        res = res.mul(q);
		      }
		    }
	
		    return res;
		  };
	
		  // Shift-left in-place
		  BN.prototype.iushln = function iushln(bits) {
		    assert(typeof bits === 'number' && bits >= 0);
		    var r = bits % 26;
		    var s = (bits - r) / 26;
		    var carryMask = 0x3ffffff >>> 26 - r << 26 - r;
		    var i;
	
		    if (r !== 0) {
		      var carry = 0;
	
		      for (i = 0; i < this.length; i++) {
		        var newCarry = this.words[i] & carryMask;
		        var c = (this.words[i] | 0) - newCarry << r;
		        this.words[i] = c | carry;
		        carry = newCarry >>> 26 - r;
		      }
	
		      if (carry) {
		        this.words[i] = carry;
		        this.length++;
		      }
		    }
	
		    if (s !== 0) {
		      for (i = this.length - 1; i >= 0; i--) {
		        this.words[i + s] = this.words[i];
		      }
	
		      for (i = 0; i < s; i++) {
		        this.words[i] = 0;
		      }
	
		      this.length += s;
		    }
	
		    return this.strip();
		  };
	
		  BN.prototype.ishln = function ishln(bits) {
		    // TODO(indutny): implement me
		    assert(this.negative === 0);
		    return this.iushln(bits);
		  };
	
		  // Shift-right in-place
		  // NOTE: `hint` is a lowest bit before trailing zeroes
		  // NOTE: if `extended` is present - it will be filled with destroyed bits
		  BN.prototype.iushrn = function iushrn(bits, hint, extended) {
		    assert(typeof bits === 'number' && bits >= 0);
		    var h;
		    if (hint) {
		      h = (hint - hint % 26) / 26;
		    } else {
		      h = 0;
		    }
	
		    var r = bits % 26;
		    var s = Math.min((bits - r) / 26, this.length);
		    var mask = 0x3ffffff ^ 0x3ffffff >>> r << r;
		    var maskedWords = extended;
	
		    h -= s;
		    h = Math.max(0, h);
	
		    // Extended mode, copy masked part
		    if (maskedWords) {
		      for (var i = 0; i < s; i++) {
		        maskedWords.words[i] = this.words[i];
		      }
		      maskedWords.length = s;
		    }
	
		    if (s === 0) {
		      // No-op, we should not move anything at all
		    } else if (this.length > s) {
		      this.length -= s;
		      for (i = 0; i < this.length; i++) {
		        this.words[i] = this.words[i + s];
		      }
		    } else {
		      this.words[0] = 0;
		      this.length = 1;
		    }
	
		    var carry = 0;
		    for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) {
		      var word = this.words[i] | 0;
		      this.words[i] = carry << 26 - r | word >>> r;
		      carry = word & mask;
		    }
	
		    // Push carried bits as a mask
		    if (maskedWords && carry !== 0) {
		      maskedWords.words[maskedWords.length++] = carry;
		    }
	
		    if (this.length === 0) {
		      this.words[0] = 0;
		      this.length = 1;
		    }
	
		    return this.strip();
		  };
	
		  BN.prototype.ishrn = function ishrn(bits, hint, extended) {
		    // TODO(indutny): implement me
		    assert(this.negative === 0);
		    return this.iushrn(bits, hint, extended);
		  };
	
		  // Shift-left
		  BN.prototype.shln = function shln(bits) {
		    return this.clone().ishln(bits);
		  };
	
		  BN.prototype.ushln = function ushln(bits) {
		    return this.clone().iushln(bits);
		  };
	
		  // Shift-right
		  BN.prototype.shrn = function shrn(bits) {
		    return this.clone().ishrn(bits);
		  };
	
		  BN.prototype.ushrn = function ushrn(bits) {
		    return this.clone().iushrn(bits);
		  };
	
		  // Test if n bit is set
		  BN.prototype.testn = function testn(bit) {
		    assert(typeof bit === 'number' && bit >= 0);
		    var r = bit % 26;
		    var s = (bit - r) / 26;
		    var q = 1 << r;
	
		    // Fast case: bit is much higher than all existing words
		    if (this.length <= s) return false;
	
		    // Check bit and return
		    var w = this.words[s];
	
		    return !!(w & q);
		  };
	
		  // Return only lowers bits of number (in-place)
		  BN.prototype.imaskn = function imaskn(bits) {
		    assert(typeof bits === 'number' && bits >= 0);
		    var r = bits % 26;
		    var s = (bits - r) / 26;
	
		    assert(this.negative === 0, 'imaskn works only with positive numbers');
	
		    if (this.length <= s) {
		      return this;
		    }
	
		    if (r !== 0) {
		      s++;
		    }
		    this.length = Math.min(s, this.length);
	
		    if (r !== 0) {
		      var mask = 0x3ffffff ^ 0x3ffffff >>> r << r;
		      this.words[this.length - 1] &= mask;
		    }
	
		    return this.strip();
		  };
	
		  // Return only lowers bits of number
		  BN.prototype.maskn = function maskn(bits) {
		    return this.clone().imaskn(bits);
		  };
	
		  // Add plain number `num` to `this`
		  BN.prototype.iaddn = function iaddn(num) {
		    assert(typeof num === 'number');
		    assert(num < 0x4000000);
		    if (num < 0) return this.isubn(-num);
	
		    // Possible sign change
		    if (this.negative !== 0) {
		      if (this.length === 1 && (this.words[0] | 0) < num) {
		        this.words[0] = num - (this.words[0] | 0);
		        this.negative = 0;
		        return this;
		      }
	
		      this.negative = 0;
		      this.isubn(num);
		      this.negative = 1;
		      return this;
		    }
	
		    // Add without checks
		    return this._iaddn(num);
		  };
	
		  BN.prototype._iaddn = function _iaddn(num) {
		    this.words[0] += num;
	
		    // Carry
		    for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) {
		      this.words[i] -= 0x4000000;
		      if (i === this.length - 1) {
		        this.words[i + 1] = 1;
		      } else {
		        this.words[i + 1]++;
		      }
		    }
		    this.length = Math.max(this.length, i + 1);
	
		    return this;
		  };
	
		  // Subtract plain number `num` from `this`
		  BN.prototype.isubn = function isubn(num) {
		    assert(typeof num === 'number');
		    assert(num < 0x4000000);
		    if (num < 0) return this.iaddn(-num);
	
		    if (this.negative !== 0) {
		      this.negative = 0;
		      this.iaddn(num);
		      this.negative = 1;
		      return this;
		    }
	
		    this.words[0] -= num;
	
		    if (this.length === 1 && this.words[0] < 0) {
		      this.words[0] = -this.words[0];
		      this.negative = 1;
		    } else {
		      // Carry
		      for (var i = 0; i < this.length && this.words[i] < 0; i++) {
		        this.words[i] += 0x4000000;
		        this.words[i + 1] -= 1;
		      }
		    }
	
		    return this.strip();
		  };
	
		  BN.prototype.addn = function addn(num) {
		    return this.clone().iaddn(num);
		  };
	
		  BN.prototype.subn = function subn(num) {
		    return this.clone().isubn(num);
		  };
	
		  BN.prototype.iabs = function iabs() {
		    this.negative = 0;
	
		    return this;
		  };
	
		  BN.prototype.abs = function abs() {
		    return this.clone().iabs();
		  };
	
		  BN.prototype._ishlnsubmul = function _ishlnsubmul(num, mul, shift) {
		    var len = num.length + shift;
		    var i;
	
		    this._expand(len);
	
		    var w;
		    var carry = 0;
		    for (i = 0; i < num.length; i++) {
		      w = (this.words[i + shift] | 0) + carry;
		      var right = (num.words[i] | 0) * mul;
		      w -= right & 0x3ffffff;
		      carry = (w >> 26) - (right / 0x4000000 | 0);
		      this.words[i + shift] = w & 0x3ffffff;
		    }
		    for (; i < this.length - shift; i++) {
		      w = (this.words[i + shift] | 0) + carry;
		      carry = w >> 26;
		      this.words[i + shift] = w & 0x3ffffff;
		    }
	
		    if (carry === 0) return this.strip();
	
		    // Subtraction overflow
		    assert(carry === -1);
		    carry = 0;
		    for (i = 0; i < this.length; i++) {
		      w = -(this.words[i] | 0) + carry;
		      carry = w >> 26;
		      this.words[i] = w & 0x3ffffff;
		    }
		    this.negative = 1;
	
		    return this.strip();
		  };
	
		  BN.prototype._wordDiv = function _wordDiv(num, mode) {
		    var shift = this.length - num.length;
	
		    var a = this.clone();
		    var b = num;
	
		    // Normalize
		    var bhi = b.words[b.length - 1] | 0;
		    var bhiBits = this._countBits(bhi);
		    shift = 26 - bhiBits;
		    if (shift !== 0) {
		      b = b.ushln(shift);
		      a.iushln(shift);
		      bhi = b.words[b.length - 1] | 0;
		    }
	
		    // Initialize quotient
		    var m = a.length - b.length;
		    var q;
	
		    if (mode !== 'mod') {
		      q = new BN(null);
		      q.length = m + 1;
		      q.words = new Array(q.length);
		      for (var i = 0; i < q.length; i++) {
		        q.words[i] = 0;
		      }
		    }
	
		    var diff = a.clone()._ishlnsubmul(b, 1, m);
		    if (diff.negative === 0) {
		      a = diff;
		      if (q) {
		        q.words[m] = 1;
		      }
		    }
	
		    for (var j = m - 1; j >= 0; j--) {
		      var qj = (a.words[b.length + j] | 0) * 0x4000000 + (a.words[b.length + j - 1] | 0);
	
		      // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max
		      // (0x7ffffff)
		      qj = Math.min(qj / bhi | 0, 0x3ffffff);
	
		      a._ishlnsubmul(b, qj, j);
		      while (a.negative !== 0) {
		        qj--;
		        a.negative = 0;
		        a._ishlnsubmul(b, 1, j);
		        if (!a.isZero()) {
		          a.negative ^= 1;
		        }
		      }
		      if (q) {
		        q.words[j] = qj;
		      }
		    }
		    if (q) {
		      q.strip();
		    }
		    a.strip();
	
		    // Denormalize
		    if (mode !== 'div' && shift !== 0) {
		      a.iushrn(shift);
		    }
	
		    return {
		      div: q || null,
		      mod: a
		    };
		  };
	
		  // NOTE: 1) `mode` can be set to `mod` to request mod only,
		  //       to `div` to request div only, or be absent to
		  //       request both div & mod
		  //       2) `positive` is true if unsigned mod is requested
		  BN.prototype.divmod = function divmod(num, mode, positive) {
		    assert(!num.isZero());
	
		    if (this.isZero()) {
		      return {
		        div: new BN(0),
		        mod: new BN(0)
		      };
		    }
	
		    var div, mod, res;
		    if (this.negative !== 0 && num.negative === 0) {
		      res = this.neg().divmod(num, mode);
	
		      if (mode !== 'mod') {
		        div = res.div.neg();
		      }
	
		      if (mode !== 'div') {
		        mod = res.mod.neg();
		        if (positive && mod.negative !== 0) {
		          mod.iadd(num);
		        }
		      }
	
		      return {
		        div: div,
		        mod: mod
		      };
		    }
	
		    if (this.negative === 0 && num.negative !== 0) {
		      res = this.divmod(num.neg(), mode);
	
		      if (mode !== 'mod') {
		        div = res.div.neg();
		      }
	
		      return {
		        div: div,
		        mod: res.mod
		      };
		    }
	
		    if ((this.negative & num.negative) !== 0) {
		      res = this.neg().divmod(num.neg(), mode);
	
		      if (mode !== 'div') {
		        mod = res.mod.neg();
		        if (positive && mod.negative !== 0) {
		          mod.isub(num);
		        }
		      }
	
		      return {
		        div: res.div,
		        mod: mod
		      };
		    }
	
		    // Both numbers are positive at this point
	
		    // Strip both numbers to approximate shift value
		    if (num.length > this.length || this.cmp(num) < 0) {
		      return {
		        div: new BN(0),
		        mod: this
		      };
		    }
	
		    // Very short reduction
		    if (num.length === 1) {
		      if (mode === 'div') {
		        return {
		          div: this.divn(num.words[0]),
		          mod: null
		        };
		      }
	
		      if (mode === 'mod') {
		        return {
		          div: null,
		          mod: new BN(this.modn(num.words[0]))
		        };
		      }
	
		      return {
		        div: this.divn(num.words[0]),
		        mod: new BN(this.modn(num.words[0]))
		      };
		    }
	
		    return this._wordDiv(num, mode);
		  };
	
		  // Find `this` / `num`
		  BN.prototype.div = function div(num) {
		    return this.divmod(num, 'div', false).div;
		  };
	
		  // Find `this` % `num`
		  BN.prototype.mod = function mod(num) {
		    return this.divmod(num, 'mod', false).mod;
		  };
	
		  BN.prototype.umod = function umod(num) {
		    return this.divmod(num, 'mod', true).mod;
		  };
	
		  // Find Round(`this` / `num`)
		  BN.prototype.divRound = function divRound(num) {
		    var dm = this.divmod(num);
	
		    // Fast case - exact division
		    if (dm.mod.isZero()) return dm.div;
	
		    var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod;
	
		    var half = num.ushrn(1);
		    var r2 = num.andln(1);
		    var cmp = mod.cmp(half);
	
		    // Round down
		    if (cmp < 0 || r2 === 1 && cmp === 0) return dm.div;
	
		    // Round up
		    return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1);
		  };
	
		  BN.prototype.modn = function modn(num) {
		    assert(num <= 0x3ffffff);
		    var p = (1 << 26) % num;
	
		    var acc = 0;
		    for (var i = this.length - 1; i >= 0; i--) {
		      acc = (p * acc + (this.words[i] | 0)) % num;
		    }
	
		    return acc;
		  };
	
		  // In-place division by number
		  BN.prototype.idivn = function idivn(num) {
		    assert(num <= 0x3ffffff);
	
		    var carry = 0;
		    for (var i = this.length - 1; i >= 0; i--) {
		      var w = (this.words[i] | 0) + carry * 0x4000000;
		      this.words[i] = w / num | 0;
		      carry = w % num;
		    }
	
		    return this.strip();
		  };
	
		  BN.prototype.divn = function divn(num) {
		    return this.clone().idivn(num);
		  };
	
		  BN.prototype.egcd = function egcd(p) {
		    assert(p.negative === 0);
		    assert(!p.isZero());
	
		    var x = this;
		    var y = p.clone();
	
		    if (x.negative !== 0) {
		      x = x.umod(p);
		    } else {
		      x = x.clone();
		    }
	
		    // A * x + B * y = x
		    var A = new BN(1);
		    var B = new BN(0);
	
		    // C * x + D * y = y
		    var C = new BN(0);
		    var D = new BN(1);
	
		    var g = 0;
	
		    while (x.isEven() && y.isEven()) {
		      x.iushrn(1);
		      y.iushrn(1);
		      ++g;
		    }
	
		    var yp = y.clone();
		    var xp = x.clone();
	
		    while (!x.isZero()) {
		      for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1);
		      if (i > 0) {
		        x.iushrn(i);
		        while (i-- > 0) {
		          if (A.isOdd() || B.isOdd()) {
		            A.iadd(yp);
		            B.isub(xp);
		          }
	
		          A.iushrn(1);
		          B.iushrn(1);
		        }
		      }
	
		      for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);
		      if (j > 0) {
		        y.iushrn(j);
		        while (j-- > 0) {
		          if (C.isOdd() || D.isOdd()) {
		            C.iadd(yp);
		            D.isub(xp);
		          }
	
		          C.iushrn(1);
		          D.iushrn(1);
		        }
		      }
	
		      if (x.cmp(y) >= 0) {
		        x.isub(y);
		        A.isub(C);
		        B.isub(D);
		      } else {
		        y.isub(x);
		        C.isub(A);
		        D.isub(B);
		      }
		    }
	
		    return {
		      a: C,
		      b: D,
		      gcd: y.iushln(g)
		    };
		  };
	
		  // This is reduced incarnation of the binary EEA
		  // above, designated to invert members of the
		  // _prime_ fields F(p) at a maximal speed
		  BN.prototype._invmp = function _invmp(p) {
		    assert(p.negative === 0);
		    assert(!p.isZero());
	
		    var a = this;
		    var b = p.clone();
	
		    if (a.negative !== 0) {
		      a = a.umod(p);
		    } else {
		      a = a.clone();
		    }
	
		    var x1 = new BN(1);
		    var x2 = new BN(0);
	
		    var delta = b.clone();
	
		    while (a.cmpn(1) > 0 && b.cmpn(1) > 0) {
		      for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1);
		      if (i > 0) {
		        a.iushrn(i);
		        while (i-- > 0) {
		          if (x1.isOdd()) {
		            x1.iadd(delta);
		          }
	
		          x1.iushrn(1);
		        }
		      }
	
		      for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);
		      if (j > 0) {
		        b.iushrn(j);
		        while (j-- > 0) {
		          if (x2.isOdd()) {
		            x2.iadd(delta);
		          }
	
		          x2.iushrn(1);
		        }
		      }
	
		      if (a.cmp(b) >= 0) {
		        a.isub(b);
		        x1.isub(x2);
		      } else {
		        b.isub(a);
		        x2.isub(x1);
		      }
		    }
	
		    var res;
		    if (a.cmpn(1) === 0) {
		      res = x1;
		    } else {
		      res = x2;
		    }
	
		    if (res.cmpn(0) < 0) {
		      res.iadd(p);
		    }
	
		    return res;
		  };
	
		  BN.prototype.gcd = function gcd(num) {
		    if (this.isZero()) return num.abs();
		    if (num.isZero()) return this.abs();
	
		    var a = this.clone();
		    var b = num.clone();
		    a.negative = 0;
		    b.negative = 0;
	
		    // Remove common factor of two
		    for (var shift = 0; a.isEven() && b.isEven(); shift++) {
		      a.iushrn(1);
		      b.iushrn(1);
		    }
	
		    do {
		      while (a.isEven()) {
		        a.iushrn(1);
		      }
		      while (b.isEven()) {
		        b.iushrn(1);
		      }
	
		      var r = a.cmp(b);
		      if (r < 0) {
		        // Swap `a` and `b` to make `a` always bigger than `b`
		        var t = a;
		        a = b;
		        b = t;
		      } else if (r === 0 || b.cmpn(1) === 0) {
		        break;
		      }
	
		      a.isub(b);
		    } while (true);
	
		    return b.iushln(shift);
		  };
	
		  // Invert number in the field F(num)
		  BN.prototype.invm = function invm(num) {
		    return this.egcd(num).a.umod(num);
		  };
	
		  BN.prototype.isEven = function isEven() {
		    return (this.words[0] & 1) === 0;
		  };
	
		  BN.prototype.isOdd = function isOdd() {
		    return (this.words[0] & 1) === 1;
		  };
	
		  // And first word and num
		  BN.prototype.andln = function andln(num) {
		    return this.words[0] & num;
		  };
	
		  // Increment at the bit position in-line
		  BN.prototype.bincn = function bincn(bit) {
		    assert(typeof bit === 'number');
		    var r = bit % 26;
		    var s = (bit - r) / 26;
		    var q = 1 << r;
	
		    // Fast case: bit is much higher than all existing words
		    if (this.length <= s) {
		      this._expand(s + 1);
		      this.words[s] |= q;
		      return this;
		    }
	
		    // Add bit and propagate, if needed
		    var carry = q;
		    for (var i = s; carry !== 0 && i < this.length; i++) {
		      var w = this.words[i] | 0;
		      w += carry;
		      carry = w >>> 26;
		      w &= 0x3ffffff;
		      this.words[i] = w;
		    }
		    if (carry !== 0) {
		      this.words[i] = carry;
		      this.length++;
		    }
		    return this;
		  };
	
		  BN.prototype.isZero = function isZero() {
		    return this.length === 1 && this.words[0] === 0;
		  };
	
		  BN.prototype.cmpn = function cmpn(num) {
		    var negative = num < 0;
	
		    if (this.negative !== 0 && !negative) return -1;
		    if (this.negative === 0 && negative) return 1;
	
		    this.strip();
	
		    var res;
		    if (this.length > 1) {
		      res = 1;
		    } else {
		      if (negative) {
		        num = -num;
		      }
	
		      assert(num <= 0x3ffffff, 'Number is too big');
	
		      var w = this.words[0] | 0;
		      res = w === num ? 0 : w < num ? -1 : 1;
		    }
		    if (this.negative !== 0) return -res | 0;
		    return res;
		  };
	
		  // Compare two numbers and return:
		  // 1 - if `this` > `num`
		  // 0 - if `this` == `num`
		  // -1 - if `this` < `num`
		  BN.prototype.cmp = function cmp(num) {
		    if (this.negative !== 0 && num.negative === 0) return -1;
		    if (this.negative === 0 && num.negative !== 0) return 1;
	
		    var res = this.ucmp(num);
		    if (this.negative !== 0) return -res | 0;
		    return res;
		  };
	
		  // Unsigned comparison
		  BN.prototype.ucmp = function ucmp(num) {
		    // At this point both numbers have the same sign
		    if (this.length > num.length) return 1;
		    if (this.length < num.length) return -1;
	
		    var res = 0;
		    for (var i = this.length - 1; i >= 0; i--) {
		      var a = this.words[i] | 0;
		      var b = num.words[i] | 0;
	
		      if (a === b) continue;
		      if (a < b) {
		        res = -1;
		      } else if (a > b) {
		        res = 1;
		      }
		      break;
		    }
		    return res;
		  };
	
		  BN.prototype.gtn = function gtn(num) {
		    return this.cmpn(num) === 1;
		  };
	
		  BN.prototype.gt = function gt(num) {
		    return this.cmp(num) === 1;
		  };
	
		  BN.prototype.gten = function gten(num) {
		    return this.cmpn(num) >= 0;
		  };
	
		  BN.prototype.gte = function gte(num) {
		    return this.cmp(num) >= 0;
		  };
	
		  BN.prototype.ltn = function ltn(num) {
		    return this.cmpn(num) === -1;
		  };
	
		  BN.prototype.lt = function lt(num) {
		    return this.cmp(num) === -1;
		  };
	
		  BN.prototype.lten = function lten(num) {
		    return this.cmpn(num) <= 0;
		  };
	
		  BN.prototype.lte = function lte(num) {
		    return this.cmp(num) <= 0;
		  };
	
		  BN.prototype.eqn = function eqn(num) {
		    return this.cmpn(num) === 0;
		  };
	
		  BN.prototype.eq = function eq(num) {
		    return this.cmp(num) === 0;
		  };
	
		  //
		  // A reduce context, could be using montgomery or something better, depending
		  // on the `m` itself.
		  //
		  BN.red = function red(num) {
		    return new Red(num);
		  };
	
		  BN.prototype.toRed = function toRed(ctx) {
		    assert(!this.red, 'Already a number in reduction context');
		    assert(this.negative === 0, 'red works only with positives');
		    return ctx.convertTo(this)._forceRed(ctx);
		  };
	
		  BN.prototype.fromRed = function fromRed() {
		    assert(this.red, 'fromRed works only with numbers in reduction context');
		    return this.red.convertFrom(this);
		  };
	
		  BN.prototype._forceRed = function _forceRed(ctx) {
		    this.red = ctx;
		    return this;
		  };
	
		  BN.prototype.forceRed = function forceRed(ctx) {
		    assert(!this.red, 'Already a number in reduction context');
		    return this._forceRed(ctx);
		  };
	
		  BN.prototype.redAdd = function redAdd(num) {
		    assert(this.red, 'redAdd works only with red numbers');
		    return this.red.add(this, num);
		  };
	
		  BN.prototype.redIAdd = function redIAdd(num) {
		    assert(this.red, 'redIAdd works only with red numbers');
		    return this.red.iadd(this, num);
		  };
	
		  BN.prototype.redSub = function redSub(num) {
		    assert(this.red, 'redSub works only with red numbers');
		    return this.red.sub(this, num);
		  };
	
		  BN.prototype.redISub = function redISub(num) {
		    assert(this.red, 'redISub works only with red numbers');
		    return this.red.isub(this, num);
		  };
	
		  BN.prototype.redShl = function redShl(num) {
		    assert(this.red, 'redShl works only with red numbers');
		    return this.red.shl(this, num);
		  };
	
		  BN.prototype.redMul = function redMul(num) {
		    assert(this.red, 'redMul works only with red numbers');
		    this.red._verify2(this, num);
		    return this.red.mul(this, num);
		  };
	
		  BN.prototype.redIMul = function redIMul(num) {
		    assert(this.red, 'redMul works only with red numbers');
		    this.red._verify2(this, num);
		    return this.red.imul(this, num);
		  };
	
		  BN.prototype.redSqr = function redSqr() {
		    assert(this.red, 'redSqr works only with red numbers');
		    this.red._verify1(this);
		    return this.red.sqr(this);
		  };
	
		  BN.prototype.redISqr = function redISqr() {
		    assert(this.red, 'redISqr works only with red numbers');
		    this.red._verify1(this);
		    return this.red.isqr(this);
		  };
	
		  // Square root over p
		  BN.prototype.redSqrt = function redSqrt() {
		    assert(this.red, 'redSqrt works only with red numbers');
		    this.red._verify1(this);
		    return this.red.sqrt(this);
		  };
	
		  BN.prototype.redInvm = function redInvm() {
		    assert(this.red, 'redInvm works only with red numbers');
		    this.red._verify1(this);
		    return this.red.invm(this);
		  };
	
		  // Return negative clone of `this` % `red modulo`
		  BN.prototype.redNeg = function redNeg() {
		    assert(this.red, 'redNeg works only with red numbers');
		    this.red._verify1(this);
		    return this.red.neg(this);
		  };
	
		  BN.prototype.redPow = function redPow(num) {
		    assert(this.red && !num.red, 'redPow(normalNum)');
		    this.red._verify1(this);
		    return this.red.pow(this, num);
		  };
	
		  // Prime numbers with efficient reduction
		  var primes = {
		    k256: null,
		    p224: null,
		    p192: null,
		    p25519: null
		  };
	
		  // Pseudo-Mersenne prime
		  function MPrime(name, p) {
		    // P = 2 ^ N - K
		    this.name = name;
		    this.p = new BN(p, 16);
		    this.n = this.p.bitLength();
		    this.k = new BN(1).iushln(this.n).isub(this.p);
	
		    this.tmp = this._tmp();
		  }
	
		  MPrime.prototype._tmp = function _tmp() {
		    var tmp = new BN(null);
		    tmp.words = new Array(Math.ceil(this.n / 13));
		    return tmp;
		  };
	
		  MPrime.prototype.ireduce = function ireduce(num) {
		    // Assumes that `num` is less than `P^2`
		    // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P)
		    var r = num;
		    var rlen;
	
		    do {
		      this.split(r, this.tmp);
		      r = this.imulK(r);
		      r = r.iadd(this.tmp);
		      rlen = r.bitLength();
		    } while (rlen > this.n);
	
		    var cmp = rlen < this.n ? -1 : r.ucmp(this.p);
		    if (cmp === 0) {
		      r.words[0] = 0;
		      r.length = 1;
		    } else if (cmp > 0) {
		      r.isub(this.p);
		    } else {
		      r.strip();
		    }
	
		    return r;
		  };
	
		  MPrime.prototype.split = function split(input, out) {
		    input.iushrn(this.n, 0, out);
		  };
	
		  MPrime.prototype.imulK = function imulK(num) {
		    return num.imul(this.k);
		  };
	
		  function K256() {
		    MPrime.call(this, 'k256', 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f');
		  }
		  inherits(K256, MPrime);
	
		  K256.prototype.split = function split(input, output) {
		    // 256 = 9 * 26 + 22
		    var mask = 0x3fffff;
	
		    var outLen = Math.min(input.length, 9);
		    for (var i = 0; i < outLen; i++) {
		      output.words[i] = input.words[i];
		    }
		    output.length = outLen;
	
		    if (input.length <= 9) {
		      input.words[0] = 0;
		      input.length = 1;
		      return;
		    }
	
		    // Shift by 9 limbs
		    var prev = input.words[9];
		    output.words[output.length++] = prev & mask;
	
		    for (i = 10; i < input.length; i++) {
		      var next = input.words[i] | 0;
		      input.words[i - 10] = (next & mask) << 4 | prev >>> 22;
		      prev = next;
		    }
		    prev >>>= 22;
		    input.words[i - 10] = prev;
		    if (prev === 0 && input.length > 10) {
		      input.length -= 10;
		    } else {
		      input.length -= 9;
		    }
		  };
	
		  K256.prototype.imulK = function imulK(num) {
		    // K = 0x1000003d1 = [ 0x40, 0x3d1 ]
		    num.words[num.length] = 0;
		    num.words[num.length + 1] = 0;
		    num.length += 2;
	
		    // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390
		    var lo = 0;
		    for (var i = 0; i < num.length; i++) {
		      var w = num.words[i] | 0;
		      lo += w * 0x3d1;
		      num.words[i] = lo & 0x3ffffff;
		      lo = w * 0x40 + (lo / 0x4000000 | 0);
		    }
	
		    // Fast length reduction
		    if (num.words[num.length - 1] === 0) {
		      num.length--;
		      if (num.words[num.length - 1] === 0) {
		        num.length--;
		      }
		    }
		    return num;
		  };
	
		  function P224() {
		    MPrime.call(this, 'p224', 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001');
		  }
		  inherits(P224, MPrime);
	
		  function P192() {
		    MPrime.call(this, 'p192', 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff');
		  }
		  inherits(P192, MPrime);
	
		  function P25519() {
		    // 2 ^ 255 - 19
		    MPrime.call(this, '25519', '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed');
		  }
		  inherits(P25519, MPrime);
	
		  P25519.prototype.imulK = function imulK(num) {
		    // K = 0x13
		    var carry = 0;
		    for (var i = 0; i < num.length; i++) {
		      var hi = (num.words[i] | 0) * 0x13 + carry;
		      var lo = hi & 0x3ffffff;
		      hi >>>= 26;
	
		      num.words[i] = lo;
		      carry = hi;
		    }
		    if (carry !== 0) {
		      num.words[num.length++] = carry;
		    }
		    return num;
		  };
	
		  // Exported mostly for testing purposes, use plain name instead
		  BN._prime = function prime(name) {
		    // Cached version of prime
		    if (primes[name]) return primes[name];
	
		    var prime;
		    if (name === 'k256') {
		      prime = new K256();
		    } else if (name === 'p224') {
		      prime = new P224();
		    } else if (name === 'p192') {
		      prime = new P192();
		    } else if (name === 'p25519') {
		      prime = new P25519();
		    } else {
		      throw new Error('Unknown prime ' + name);
		    }
		    primes[name] = prime;
	
		    return prime;
		  };
	
		  //
		  // Base reduction engine
		  //
		  function Red(m) {
		    if (typeof m === 'string') {
		      var prime = BN._prime(m);
		      this.m = prime.p;
		      this.prime = prime;
		    } else {
		      assert(m.gtn(1), 'modulus must be greater than 1');
		      this.m = m;
		      this.prime = null;
		    }
		  }
	
		  Red.prototype._verify1 = function _verify1(a) {
		    assert(a.negative === 0, 'red works only with positives');
		    assert(a.red, 'red works only with red numbers');
		  };
	
		  Red.prototype._verify2 = function _verify2(a, b) {
		    assert((a.negative | b.negative) === 0, 'red works only with positives');
		    assert(a.red && a.red === b.red, 'red works only with red numbers');
		  };
	
		  Red.prototype.imod = function imod(a) {
		    if (this.prime) return this.prime.ireduce(a)._forceRed(this);
		    return a.umod(this.m)._forceRed(this);
		  };
	
		  Red.prototype.neg = function neg(a) {
		    if (a.isZero()) {
		      return a.clone();
		    }
	
		    return this.m.sub(a)._forceRed(this);
		  };
	
		  Red.prototype.add = function add(a, b) {
		    this._verify2(a, b);
	
		    var res = a.add(b);
		    if (res.cmp(this.m) >= 0) {
		      res.isub(this.m);
		    }
		    return res._forceRed(this);
		  };
	
		  Red.prototype.iadd = function iadd(a, b) {
		    this._verify2(a, b);
	
		    var res = a.iadd(b);
		    if (res.cmp(this.m) >= 0) {
		      res.isub(this.m);
		    }
		    return res;
		  };
	
		  Red.prototype.sub = function sub(a, b) {
		    this._verify2(a, b);
	
		    var res = a.sub(b);
		    if (res.cmpn(0) < 0) {
		      res.iadd(this.m);
		    }
		    return res._forceRed(this);
		  };
	
		  Red.prototype.isub = function isub(a, b) {
		    this._verify2(a, b);
	
		    var res = a.isub(b);
		    if (res.cmpn(0) < 0) {
		      res.iadd(this.m);
		    }
		    return res;
		  };
	
		  Red.prototype.shl = function shl(a, num) {
		    this._verify1(a);
		    return this.imod(a.ushln(num));
		  };
	
		  Red.prototype.imul = function imul(a, b) {
		    this._verify2(a, b);
		    return this.imod(a.imul(b));
		  };
	
		  Red.prototype.mul = function mul(a, b) {
		    this._verify2(a, b);
		    return this.imod(a.mul(b));
		  };
	
		  Red.prototype.isqr = function isqr(a) {
		    return this.imul(a, a.clone());
		  };
	
		  Red.prototype.sqr = function sqr(a) {
		    return this.mul(a, a);
		  };
	
		  Red.prototype.sqrt = function sqrt(a) {
		    if (a.isZero()) return a.clone();
	
		    var mod3 = this.m.andln(3);
		    assert(mod3 % 2 === 1);
	
		    // Fast case
		    if (mod3 === 3) {
		      var pow = this.m.add(new BN(1)).iushrn(2);
		      return this.pow(a, pow);
		    }
	
		    // Tonelli-Shanks algorithm (Totally unoptimized and slow)
		    //
		    // Find Q and S, that Q * 2 ^ S = (P - 1)
		    var q = this.m.subn(1);
		    var s = 0;
		    while (!q.isZero() && q.andln(1) === 0) {
		      s++;
		      q.iushrn(1);
		    }
		    assert(!q.isZero());
	
		    var one = new BN(1).toRed(this);
		    var nOne = one.redNeg();
	
		    // Find quadratic non-residue
		    // NOTE: Max is such because of generalized Riemann hypothesis.
		    var lpow = this.m.subn(1).iushrn(1);
		    var z = this.m.bitLength();
		    z = new BN(2 * z * z).toRed(this);
	
		    while (this.pow(z, lpow).cmp(nOne) !== 0) {
		      z.redIAdd(nOne);
		    }
	
		    var c = this.pow(z, q);
		    var r = this.pow(a, q.addn(1).iushrn(1));
		    var t = this.pow(a, q);
		    var m = s;
		    while (t.cmp(one) !== 0) {
		      var tmp = t;
		      for (var i = 0; tmp.cmp(one) !== 0; i++) {
		        tmp = tmp.redSqr();
		      }
		      assert(i < m);
		      var b = this.pow(c, new BN(1).iushln(m - i - 1));
	
		      r = r.redMul(b);
		      c = b.redSqr();
		      t = t.redMul(c);
		      m = i;
		    }
	
		    return r;
		  };
	
		  Red.prototype.invm = function invm(a) {
		    var inv = a._invmp(this.m);
		    if (inv.negative !== 0) {
		      inv.negative = 0;
		      return this.imod(inv).redNeg();
		    } else {
		      return this.imod(inv);
		    }
		  };
	
		  Red.prototype.pow = function pow(a, num) {
		    if (num.isZero()) return new BN(1).toRed(this);
		    if (num.cmpn(1) === 0) return a.clone();
	
		    var windowSize = 4;
		    var wnd = new Array(1 << windowSize);
		    wnd[0] = new BN(1).toRed(this);
		    wnd[1] = a;
		    for (var i = 2; i < wnd.length; i++) {
		      wnd[i] = this.mul(wnd[i - 1], a);
		    }
	
		    var res = wnd[0];
		    var current = 0;
		    var currentLen = 0;
		    var start = num.bitLength() % 26;
		    if (start === 0) {
		      start = 26;
		    }
	
		    for (i = num.length - 1; i >= 0; i--) {
		      var word = num.words[i];
		      for (var j = start - 1; j >= 0; j--) {
		        var bit = word >> j & 1;
		        if (res !== wnd[0]) {
		          res = this.sqr(res);
		        }
	
		        if (bit === 0 && current === 0) {
		          currentLen = 0;
		          continue;
		        }
	
		        current <<= 1;
		        current |= bit;
		        currentLen++;
		        if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue;
	
		        res = this.mul(res, wnd[current]);
		        currentLen = 0;
		        current = 0;
		      }
		      start = 26;
		    }
	
		    return res;
		  };
	
		  Red.prototype.convertTo = function convertTo(num) {
		    var r = num.umod(this.m);
	
		    return r === num ? r.clone() : r;
		  };
	
		  Red.prototype.convertFrom = function convertFrom(num) {
		    var res = num.clone();
		    res.red = null;
		    return res;
		  };
	
		  //
		  // Montgomery method engine
		  //
	
		  BN.mont = function mont(num) {
		    return new Mont(num);
		  };
	
		  function Mont(m) {
		    Red.call(this, m);
	
		    this.shift = this.m.bitLength();
		    if (this.shift % 26 !== 0) {
		      this.shift += 26 - this.shift % 26;
		    }
	
		    this.r = new BN(1).iushln(this.shift);
		    this.r2 = this.imod(this.r.sqr());
		    this.rinv = this.r._invmp(this.m);
	
		    this.minv = this.rinv.mul(this.r).isubn(1).div(this.m);
		    this.minv = this.minv.umod(this.r);
		    this.minv = this.r.sub(this.minv);
		  }
		  inherits(Mont, Red);
	
		  Mont.prototype.convertTo = function convertTo(num) {
		    return this.imod(num.ushln(this.shift));
		  };
	
		  Mont.prototype.convertFrom = function convertFrom(num) {
		    var r = this.imod(num.mul(this.rinv));
		    r.red = null;
		    return r;
		  };
	
		  Mont.prototype.imul = function imul(a, b) {
		    if (a.isZero() || b.isZero()) {
		      a.words[0] = 0;
		      a.length = 1;
		      return a;
		    }
	
		    var t = a.imul(b);
		    var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);
		    var u = t.isub(c).iushrn(this.shift);
		    var res = u;
	
		    if (u.cmp(this.m) >= 0) {
		      res = u.isub(this.m);
		    } else if (u.cmpn(0) < 0) {
		      res = u.iadd(this.m);
		    }
	
		    return res._forceRed(this);
		  };
	
		  Mont.prototype.mul = function mul(a, b) {
		    if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this);
	
		    var t = a.mul(b);
		    var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);
		    var u = t.isub(c).iushrn(this.shift);
		    var res = u;
		    if (u.cmp(this.m) >= 0) {
		      res = u.isub(this.m);
		    } else if (u.cmpn(0) < 0) {
		      res = u.iadd(this.m);
		    }
	
		    return res._forceRed(this);
		  };
	
		  Mont.prototype.invm = function invm(a) {
		    // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R
		    var res = this.imod(a._invmp(this.m).mul(this.r2));
		    return res._forceRed(this);
		  };
		})(typeof module === 'undefined' || module, this);
		/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(54)(module)))
	
	/***/ }),
	/* 54 */
	/***/ (function(module, exports) {
	
		module.exports = function (module) {
			if (!module.webpackPolyfill) {
				module.deprecate = function () {};
				module.paths = [];
				// module.parent = undefined by default
				module.children = [];
				module.webpackPolyfill = 1;
			}
			return module;
		};
	
	/***/ }),
	/* 55 */
	/***/ (function(module, exports) {
	
		/* (ignored) */
	
	/***/ }),
	/* 56 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var BN = __webpack_require__(53);
		var db = __webpack_require__(57);
	
		module.exports = num2bn;
	
		function num2bn(x) {
		  var e = db.exponent(x);
		  if (e < 52) {
		    return new BN(x);
		  } else {
		    return new BN(x * Math.pow(2, 52 - e)).ushln(e - 52);
		  }
		}
	
	/***/ }),
	/* 57 */
	/***/ (function(module, exports, __webpack_require__) {
	
		/* WEBPACK VAR INJECTION */(function(Buffer) {var hasTypedArrays = false;
		if (typeof Float64Array !== "undefined") {
		  var DOUBLE_VIEW = new Float64Array(1),
		      UINT_VIEW = new Uint32Array(DOUBLE_VIEW.buffer);
		  DOUBLE_VIEW[0] = 1.0;
		  hasTypedArrays = true;
		  if (UINT_VIEW[1] === 0x3ff00000) {
		    //Use little endian
		    module.exports = function doubleBitsLE(n) {
		      DOUBLE_VIEW[0] = n;
		      return [UINT_VIEW[0], UINT_VIEW[1]];
		    };
		    function toDoubleLE(lo, hi) {
		      UINT_VIEW[0] = lo;
		      UINT_VIEW[1] = hi;
		      return DOUBLE_VIEW[0];
		    }
		    module.exports.pack = toDoubleLE;
		    function lowUintLE(n) {
		      DOUBLE_VIEW[0] = n;
		      return UINT_VIEW[0];
		    }
		    module.exports.lo = lowUintLE;
		    function highUintLE(n) {
		      DOUBLE_VIEW[0] = n;
		      return UINT_VIEW[1];
		    }
		    module.exports.hi = highUintLE;
		  } else if (UINT_VIEW[0] === 0x3ff00000) {
		    //Use big endian
		    module.exports = function doubleBitsBE(n) {
		      DOUBLE_VIEW[0] = n;
		      return [UINT_VIEW[1], UINT_VIEW[0]];
		    };
		    function toDoubleBE(lo, hi) {
		      UINT_VIEW[1] = lo;
		      UINT_VIEW[0] = hi;
		      return DOUBLE_VIEW[0];
		    }
		    module.exports.pack = toDoubleBE;
		    function lowUintBE(n) {
		      DOUBLE_VIEW[0] = n;
		      return UINT_VIEW[1];
		    }
		    module.exports.lo = lowUintBE;
		    function highUintBE(n) {
		      DOUBLE_VIEW[0] = n;
		      return UINT_VIEW[0];
		    }
		    module.exports.hi = highUintBE;
		  } else {
		    hasTypedArrays = false;
		  }
		}
		if (!hasTypedArrays) {
		  var buffer = new Buffer(8);
		  module.exports = function doubleBits(n) {
		    buffer.writeDoubleLE(n, 0, true);
		    return [buffer.readUInt32LE(0, true), buffer.readUInt32LE(4, true)];
		  };
		  function toDouble(lo, hi) {
		    buffer.writeUInt32LE(lo, 0, true);
		    buffer.writeUInt32LE(hi, 4, true);
		    return buffer.readDoubleLE(0, true);
		  }
		  module.exports.pack = toDouble;
		  function lowUint(n) {
		    buffer.writeDoubleLE(n, 0, true);
		    return buffer.readUInt32LE(0, true);
		  }
		  module.exports.lo = lowUint;
		  function highUint(n) {
		    buffer.writeDoubleLE(n, 0, true);
		    return buffer.readUInt32LE(4, true);
		  }
		  module.exports.hi = highUint;
		}
	
		module.exports.sign = function (n) {
		  return module.exports.hi(n) >>> 31;
		};
	
		module.exports.exponent = function (n) {
		  var b = module.exports.hi(n);
		  return (b << 1 >>> 21) - 1023;
		};
	
		module.exports.fraction = function (n) {
		  var lo = module.exports.lo(n);
		  var hi = module.exports.hi(n);
		  var b = hi & (1 << 20) - 1;
		  if (hi & 0x7ff00000) {
		    b += 1 << 20;
		  }
		  return [lo, b];
		};
	
		module.exports.denormalized = function (n) {
		  var hi = module.exports.hi(n);
		  return !(hi & 0x7ff00000);
		};
		/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(10).Buffer))
	
	/***/ }),
	/* 58 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var BN = __webpack_require__(53);
	
		module.exports = str2BN;
	
		function str2BN(x) {
		  return new BN(x);
		}
	
	/***/ }),
	/* 59 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var num2bn = __webpack_require__(56);
		var sign = __webpack_require__(60);
	
		module.exports = rationalize;
	
		function rationalize(numer, denom) {
		  var snumer = sign(numer);
		  var sdenom = sign(denom);
		  if (snumer === 0) {
		    return [num2bn(0), num2bn(1)];
		  }
		  if (sdenom === 0) {
		    return [num2bn(0), num2bn(0)];
		  }
		  if (sdenom < 0) {
		    numer = numer.neg();
		    denom = denom.neg();
		  }
		  var d = numer.gcd(denom);
		  if (d.cmpn(1)) {
		    return [numer.div(d), denom.div(d)];
		  }
		  return [numer, denom];
		}
	
	/***/ }),
	/* 60 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var BN = __webpack_require__(53);
	
		module.exports = sign;
	
		function sign(x) {
		  return x.cmp(new BN(0));
		}
	
	/***/ }),
	/* 61 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var rationalize = __webpack_require__(59);
	
		module.exports = div;
	
		function div(a, b) {
		  return rationalize(a[0].mul(b[1]), a[1].mul(b[0]));
		}
	
	/***/ }),
	/* 62 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		module.exports = cmp;
	
		function cmp(a, b) {
		    return a[0].mul(b[1]).cmp(b[0].mul(a[1]));
		}
	
	/***/ }),
	/* 63 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var bn2num = __webpack_require__(64);
		var ctz = __webpack_require__(65);
	
		module.exports = roundRat;
	
		// Round a rational to the closest float
		function roundRat(f) {
		  var a = f[0];
		  var b = f[1];
		  if (a.cmpn(0) === 0) {
		    return 0;
		  }
		  var h = a.abs().divmod(b.abs());
		  var iv = h.div;
		  var x = bn2num(iv);
		  var ir = h.mod;
		  var sgn = a.negative !== b.negative ? -1 : 1;
		  if (ir.cmpn(0) === 0) {
		    return sgn * x;
		  }
		  if (x) {
		    var s = ctz(x) + 4;
		    var y = bn2num(ir.ushln(s).divRound(b));
		    return sgn * (x + y * Math.pow(2, -s));
		  } else {
		    var ybits = b.bitLength() - ir.bitLength() + 53;
		    var y = bn2num(ir.ushln(ybits).divRound(b));
		    if (ybits < 1023) {
		      return sgn * y * Math.pow(2, -ybits);
		    }
		    y *= Math.pow(2, -1023);
		    return sgn * y * Math.pow(2, 1023 - ybits);
		  }
		}
	
	/***/ }),
	/* 64 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var sign = __webpack_require__(60);
	
		module.exports = bn2num;
	
		//TODO: Make this better
		function bn2num(b) {
		  var l = b.length;
		  var words = b.words;
		  var out = 0;
		  if (l === 1) {
		    out = words[0];
		  } else if (l === 2) {
		    out = words[0] + words[1] * 0x4000000;
		  } else {
		    for (var i = 0; i < l; i++) {
		      var w = words[i];
		      out += w * Math.pow(0x4000000, i);
		    }
		  }
		  return sign(b) * out;
		}
	
	/***/ }),
	/* 65 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var db = __webpack_require__(57);
		var ctz = __webpack_require__(14).countTrailingZeros;
	
		module.exports = ctzNumber;
	
		//Counts the number of trailing zeros
		function ctzNumber(x) {
		  var l = ctz(db.lo(x));
		  if (l < 32) {
		    return l;
		  }
		  var h = ctz(db.hi(x));
		  if (h > 20) {
		    return 52;
		  }
		  return h + 32;
		}
	
	/***/ }),
	/* 66 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		module.exports = float2rat;
	
		var rat = __webpack_require__(50);
	
		function float2rat(v) {
		  var result = new Array(v.length);
		  for (var i = 0; i < v.length; ++i) {
		    result[i] = rat(v[i]);
		  }
		  return result;
		}
	
	/***/ }),
	/* 67 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var doubleBits = __webpack_require__(57);
	
		var SMALLEST_DENORM = Math.pow(2, -1074);
		var UINT_MAX = -1 >>> 0;
	
		module.exports = nextafter;
	
		function nextafter(x, y) {
		  if (isNaN(x) || isNaN(y)) {
		    return NaN;
		  }
		  if (x === y) {
		    return x;
		  }
		  if (x === 0) {
		    if (y < 0) {
		      return -SMALLEST_DENORM;
		    } else {
		      return SMALLEST_DENORM;
		    }
		  }
		  var hi = doubleBits.hi(x);
		  var lo = doubleBits.lo(x);
		  if (y > x === x > 0) {
		    if (lo === UINT_MAX) {
		      hi += 1;
		      lo = 0;
		    } else {
		      lo += 1;
		    }
		  } else {
		    if (lo === 0) {
		      lo = UINT_MAX;
		      hi -= 1;
		    } else {
		      lo -= 1;
		    }
		  }
		  return doubleBits.pack(lo, hi);
		}
	
	/***/ }),
	/* 68 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		module.exports = solveIntersection;
	
		var ratMul = __webpack_require__(69);
		var ratDiv = __webpack_require__(61);
		var ratSub = __webpack_require__(70);
		var ratSign = __webpack_require__(71);
		var rvSub = __webpack_require__(72);
		var rvAdd = __webpack_require__(73);
		var rvMuls = __webpack_require__(75);
	
		function ratPerp(a, b) {
		  return ratSub(ratMul(a[0], b[1]), ratMul(a[1], b[0]));
		}
	
		// Solve for intersection
		//  x = a + t (b-a)
		//  (x - c) ^ (d-c) = 0
		//  (t * (b-a) + (a-c) ) ^ (d-c) = 0
		//  t * (b-a)^(d-c) = (d-c)^(a-c)
		//  t = (d-c)^(a-c) / (b-a)^(d-c)
	
		function solveIntersection(a, b, c, d) {
		  var ba = rvSub(b, a);
		  var dc = rvSub(d, c);
	
		  var baXdc = ratPerp(ba, dc);
	
		  if (ratSign(baXdc) === 0) {
		    return null;
		  }
	
		  var ac = rvSub(a, c);
		  var dcXac = ratPerp(dc, ac);
	
		  var t = ratDiv(dcXac, baXdc);
		  var s = rvMuls(ba, t);
		  var r = rvAdd(a, s);
	
		  return r;
		}
	
	/***/ }),
	/* 69 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var rationalize = __webpack_require__(59);
	
		module.exports = mul;
	
		function mul(a, b) {
		  return rationalize(a[0].mul(b[0]), a[1].mul(b[1]));
		}
	
	/***/ }),
	/* 70 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var rationalize = __webpack_require__(59);
	
		module.exports = sub;
	
		function sub(a, b) {
		  return rationalize(a[0].mul(b[1]).sub(a[1].mul(b[0])), a[1].mul(b[1]));
		}
	
	/***/ }),
	/* 71 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var bnsign = __webpack_require__(60);
	
		module.exports = sign;
	
		function sign(x) {
		  return bnsign(x[0]) * bnsign(x[1]);
		}
	
	/***/ }),
	/* 72 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var bnsub = __webpack_require__(70);
	
		module.exports = sub;
	
		function sub(a, b) {
		  var n = a.length;
		  var r = new Array(n);
		  for (var i = 0; i < n; ++i) {
		    r[i] = bnsub(a[i], b[i]);
		  }
		  return r;
		}
	
	/***/ }),
	/* 73 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var bnadd = __webpack_require__(74);
	
		module.exports = add;
	
		function add(a, b) {
		  var n = a.length;
		  var r = new Array(n);
		  for (var i = 0; i < n; ++i) {
		    r[i] = bnadd(a[i], b[i]);
		  }
		  return r;
		}
	
	/***/ }),
	/* 74 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var rationalize = __webpack_require__(59);
	
		module.exports = add;
	
		function add(a, b) {
		  return rationalize(a[0].mul(b[1]).add(b[0].mul(a[1])), a[1].mul(b[1]));
			}
	
	/***/ }),
	/* 75 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var rat = __webpack_require__(50);
		var mul = __webpack_require__(69);
	
		module.exports = muls;
	
		function muls(a, x) {
		  var s = rat(x);
		  var n = a.length;
		  var r = new Array(n);
		  for (var i = 0; i < n; ++i) {
		    r[i] = mul(a[i], s);
		  }
		  return r;
		}
	
	/***/ }),
	/* 76 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var monotoneTriangulate = __webpack_require__(77);
		var makeIndex = __webpack_require__(79);
		var delaunayFlip = __webpack_require__(80);
		var filterTriangulation = __webpack_require__(82);
	
		module.exports = cdt2d;
	
		function canonicalizeEdge(e) {
		  return [Math.min(e[0], e[1]), Math.max(e[0], e[1])];
		}
	
		function compareEdge(a, b) {
		  return a[0] - b[0] || a[1] - b[1];
		}
	
		function canonicalizeEdges(edges) {
		  return edges.map(canonicalizeEdge).sort(compareEdge);
		}
	
		function getDefault(options, property, dflt) {
		  if (property in options) {
		    return options[property];
		  }
		  return dflt;
		}
	
		function cdt2d(points, edges, options) {
	
		  if (!Array.isArray(edges)) {
		    options = edges || {};
		    edges = [];
		  } else {
		    options = options || {};
		    edges = edges || [];
		  }
	
		  //Parse out options
		  var delaunay = !!getDefault(options, 'delaunay', true);
		  var interior = !!getDefault(options, 'interior', true);
		  var exterior = !!getDefault(options, 'exterior', true);
		  var infinity = !!getDefault(options, 'infinity', false);
	
		  //Handle trivial case
		  if (!interior && !exterior || points.length === 0) {
		    return [];
		  }
	
		  //Construct initial triangulation
		  var cells = monotoneTriangulate(points, edges);
	
		  //If delaunay refinement needed, then improve quality by edge flipping
		  if (delaunay || interior !== exterior || infinity) {
	
		    //Index all of the cells to support fast neighborhood queries
		    var triangulation = makeIndex(points.length, canonicalizeEdges(edges));
		    for (var i = 0; i < cells.length; ++i) {
		      var f = cells[i];
		      triangulation.addTriangle(f[0], f[1], f[2]);
		    }
	
		    //Run edge flipping
		    if (delaunay) {
		      delaunayFlip(points, triangulation);
		    }
	
		    //Filter points
		    if (!exterior) {
		      return filterTriangulation(triangulation, -1);
		    } else if (!interior) {
		      return filterTriangulation(triangulation, 1, infinity);
		    } else if (infinity) {
		      return filterTriangulation(triangulation, 0, infinity);
		    } else {
		      return triangulation.cells();
		    }
		  } else {
		    return cells;
		  }
		}
	
	/***/ }),
	/* 77 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var bsearch = __webpack_require__(78);
		var orient = __webpack_require__(31)[3];
	
		var EVENT_POINT = 0;
		var EVENT_END = 1;
		var EVENT_START = 2;
	
		module.exports = monotoneTriangulate;
	
		//A partial convex hull fragment, made of two unimonotone polygons
		function PartialHull(a, b, idx, lowerIds, upperIds) {
		  this.a = a;
		  this.b = b;
		  this.idx = idx;
		  this.lowerIds = lowerIds;
		  this.upperIds = upperIds;
		}
	
		//An event in the sweep line procedure
		function Event(a, b, type, idx) {
		  this.a = a;
		  this.b = b;
		  this.type = type;
		  this.idx = idx;
		}
	
		//This is used to compare events for the sweep line procedure
		// Points are:
		//  1. sorted lexicographically
		//  2. sorted by type  (point < end < start)
		//  3. segments sorted by winding order
		//  4. sorted by index
		function compareEvent(a, b) {
		  var d = a.a[0] - b.a[0] || a.a[1] - b.a[1] || a.type - b.type;
		  if (d) {
		    return d;
		  }
		  if (a.type !== EVENT_POINT) {
		    d = orient(a.a, a.b, b.b);
		    if (d) {
		      return d;
		    }
		  }
		  return a.idx - b.idx;
		}
	
		function testPoint(hull, p) {
		  return orient(hull.a, hull.b, p);
		}
	
		function addPoint(cells, hulls, points, p, idx) {
		  var lo = bsearch.lt(hulls, p, testPoint);
		  var hi = bsearch.gt(hulls, p, testPoint);
		  for (var i = lo; i < hi; ++i) {
		    var hull = hulls[i];
	
		    //Insert p into lower hull
		    var lowerIds = hull.lowerIds;
		    var m = lowerIds.length;
		    while (m > 1 && orient(points[lowerIds[m - 2]], points[lowerIds[m - 1]], p) > 0) {
		      cells.push([lowerIds[m - 1], lowerIds[m - 2], idx]);
		      m -= 1;
		    }
		    lowerIds.length = m;
		    lowerIds.push(idx);
	
		    //Insert p into upper hull
		    var upperIds = hull.upperIds;
		    var m = upperIds.length;
		    while (m > 1 && orient(points[upperIds[m - 2]], points[upperIds[m - 1]], p) < 0) {
		      cells.push([upperIds[m - 2], upperIds[m - 1], idx]);
		      m -= 1;
		    }
		    upperIds.length = m;
		    upperIds.push(idx);
		  }
		}
	
		function findSplit(hull, edge) {
		  var d;
		  if (hull.a[0] < edge.a[0]) {
		    d = orient(hull.a, hull.b, edge.a);
		  } else {
		    d = orient(edge.b, edge.a, hull.a);
		  }
		  if (d) {
		    return d;
		  }
		  if (edge.b[0] < hull.b[0]) {
		    d = orient(hull.a, hull.b, edge.b);
		  } else {
		    d = orient(edge.b, edge.a, hull.b);
		  }
		  return d || hull.idx - edge.idx;
		}
	
		function splitHulls(hulls, points, event) {
		  var splitIdx = bsearch.le(hulls, event, findSplit);
		  var hull = hulls[splitIdx];
		  var upperIds = hull.upperIds;
		  var x = upperIds[upperIds.length - 1];
		  hull.upperIds = [x];
		  hulls.splice(splitIdx + 1, 0, new PartialHull(event.a, event.b, event.idx, [x], upperIds));
		}
	
		function mergeHulls(hulls, points, event) {
		  //Swap pointers for merge search
		  var tmp = event.a;
		  event.a = event.b;
		  event.b = tmp;
		  var mergeIdx = bsearch.eq(hulls, event, findSplit);
		  var upper = hulls[mergeIdx];
		  var lower = hulls[mergeIdx - 1];
		  lower.upperIds = upper.upperIds;
		  hulls.splice(mergeIdx, 1);
		}
	
		function monotoneTriangulate(points, edges) {
	
		  var numPoints = points.length;
		  var numEdges = edges.length;
	
		  var events = [];
	
		  //Create point events
		  for (var i = 0; i < numPoints; ++i) {
		    events.push(new Event(points[i], null, EVENT_POINT, i));
		  }
	
		  //Create edge events
		  for (var i = 0; i < numEdges; ++i) {
		    var e = edges[i];
		    var a = points[e[0]];
		    var b = points[e[1]];
		    if (a[0] < b[0]) {
		      events.push(new Event(a, b, EVENT_START, i), new Event(b, a, EVENT_END, i));
		    } else if (a[0] > b[0]) {
		      events.push(new Event(b, a, EVENT_START, i), new Event(a, b, EVENT_END, i));
		    }
		  }
	
		  //Sort events
		  events.sort(compareEvent);
	
		  //Initialize hull
		  var minX = events[0].a[0] - (1 + Math.abs(events[0].a[0])) * Math.pow(2, -52);
		  var hull = [new PartialHull([minX, 1], [minX, 0], -1, [], [], [], [])];
	
		  //Process events in order
		  var cells = [];
		  for (var i = 0, numEvents = events.length; i < numEvents; ++i) {
		    var event = events[i];
		    var type = event.type;
		    if (type === EVENT_POINT) {
		      addPoint(cells, hull, points, event.a, event.idx);
		    } else if (type === EVENT_START) {
		      splitHulls(hull, points, event);
		    } else {
		      mergeHulls(hull, points, event);
		    }
		  }
	
		  //Return triangulation
		  return cells;
		}
	
	/***/ }),
	/* 78 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		function compileSearch(funcName, predicate, reversed, extraArgs, earlyOut) {
		  var code = ["function ", funcName, "(a,l,h,", extraArgs.join(","), "){", earlyOut ? "" : "var i=", reversed ? "l-1" : "h+1", ";while(l<=h){\
		var m=(l+h)>>>1,x=a[m]"];
		  if (earlyOut) {
		    if (predicate.indexOf("c") < 0) {
		      code.push(";if(x===y){return m}else if(x<=y){");
		    } else {
		      code.push(";var p=c(x,y);if(p===0){return m}else if(p<=0){");
		    }
		  } else {
		    code.push(";if(", predicate, "){i=m;");
		  }
		  if (reversed) {
		    code.push("l=m+1}else{h=m-1}");
		  } else {
		    code.push("h=m-1}else{l=m+1}");
		  }
		  code.push("}");
		  if (earlyOut) {
		    code.push("return -1};");
		  } else {
		    code.push("return i};");
		  }
		  return code.join("");
		}
	
		function compileBoundsSearch(predicate, reversed, suffix, earlyOut) {
		  var result = new Function([compileSearch("A", "x" + predicate + "y", reversed, ["y"], earlyOut), compileSearch("P", "c(x,y)" + predicate + "0", reversed, ["y", "c"], earlyOut), "function dispatchBsearch", suffix, "(a,y,c,l,h){\
		if(typeof(c)==='function'){\
		return P(a,(l===void 0)?0:l|0,(h===void 0)?a.length-1:h|0,y,c)\
		}else{\
		return A(a,(c===void 0)?0:c|0,(l===void 0)?a.length-1:l|0,y)\
		}}\
		return dispatchBsearch", suffix].join(""));
		  return result();
		}
	
		module.exports = {
		  ge: compileBoundsSearch(">=", false, "GE"),
		  gt: compileBoundsSearch(">", false, "GT"),
		  lt: compileBoundsSearch("<", true, "LT"),
		  le: compileBoundsSearch("<=", true, "LE"),
		  eq: compileBoundsSearch("-", true, "EQ", true)
			};
	
	/***/ }),
	/* 79 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var bsearch = __webpack_require__(78);
	
		module.exports = createTriangulation;
	
		function Triangulation(stars, edges) {
		  this.stars = stars;
		  this.edges = edges;
		}
	
		var proto = Triangulation.prototype;
	
		function removePair(list, j, k) {
		  for (var i = 1, n = list.length; i < n; i += 2) {
		    if (list[i - 1] === j && list[i] === k) {
		      list[i - 1] = list[n - 2];
		      list[i] = list[n - 1];
		      list.length = n - 2;
		      return;
		    }
		  }
		}
	
		proto.isConstraint = function () {
		  var e = [0, 0];
		  function compareLex(a, b) {
		    return a[0] - b[0] || a[1] - b[1];
		  }
		  return function (i, j) {
		    e[0] = Math.min(i, j);
		    e[1] = Math.max(i, j);
		    return bsearch.eq(this.edges, e, compareLex) >= 0;
		  };
		}();
	
		proto.removeTriangle = function (i, j, k) {
		  var stars = this.stars;
		  removePair(stars[i], j, k);
		  removePair(stars[j], k, i);
		  removePair(stars[k], i, j);
		};
	
		proto.addTriangle = function (i, j, k) {
		  var stars = this.stars;
		  stars[i].push(j, k);
		  stars[j].push(k, i);
		  stars[k].push(i, j);
		};
	
		proto.opposite = function (j, i) {
		  var list = this.stars[i];
		  for (var k = 1, n = list.length; k < n; k += 2) {
		    if (list[k] === j) {
		      return list[k - 1];
		    }
		  }
		  return -1;
		};
	
		proto.flip = function (i, j) {
		  var a = this.opposite(i, j);
		  var b = this.opposite(j, i);
		  this.removeTriangle(i, j, a);
		  this.removeTriangle(j, i, b);
		  this.addTriangle(i, b, a);
		  this.addTriangle(j, a, b);
		};
	
		proto.edges = function () {
		  var stars = this.stars;
		  var result = [];
		  for (var i = 0, n = stars.length; i < n; ++i) {
		    var list = stars[i];
		    for (var j = 0, m = list.length; j < m; j += 2) {
		      result.push([list[j], list[j + 1]]);
		    }
		  }
		  return result;
		};
	
		proto.cells = function () {
		  var stars = this.stars;
		  var result = [];
		  for (var i = 0, n = stars.length; i < n; ++i) {
		    var list = stars[i];
		    for (var j = 0, m = list.length; j < m; j += 2) {
		      var s = list[j];
		      var t = list[j + 1];
		      if (i < Math.min(s, t)) {
		        result.push([i, s, t]);
		      }
		    }
		  }
		  return result;
		};
	
		function createTriangulation(numVerts, edges) {
		  var stars = new Array(numVerts);
		  for (var i = 0; i < numVerts; ++i) {
		    stars[i] = [];
		  }
		  return new Triangulation(stars, edges);
		}
	
	/***/ }),
	/* 80 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var inCircle = __webpack_require__(81)[4];
		var bsearch = __webpack_require__(78);
	
		module.exports = delaunayRefine;
	
		function testFlip(points, triangulation, stack, a, b, x) {
		  var y = triangulation.opposite(a, b);
	
		  //Test boundary edge
		  if (y < 0) {
		    return;
		  }
	
		  //Swap edge if order flipped
		  if (b < a) {
		    var tmp = a;
		    a = b;
		    b = tmp;
		    tmp = x;
		    x = y;
		    y = tmp;
		  }
	
		  //Test if edge is constrained
		  if (triangulation.isConstraint(a, b)) {
		    return;
		  }
	
		  //Test if edge is delaunay
		  if (inCircle(points[a], points[b], points[x], points[y]) < 0) {
		    stack.push(a, b);
		  }
		}
	
		//Assume edges are sorted lexicographically
		function delaunayRefine(points, triangulation) {
		  var stack = [];
	
		  var numPoints = points.length;
		  var stars = triangulation.stars;
		  for (var a = 0; a < numPoints; ++a) {
		    var star = stars[a];
		    for (var j = 1; j < star.length; j += 2) {
		      var b = star[j];
	
		      //If order is not consistent, then skip edge
		      if (b < a) {
		        continue;
		      }
	
		      //Check if edge is constrained
		      if (triangulation.isConstraint(a, b)) {
		        continue;
		      }
	
		      //Find opposite edge
		      var x = star[j - 1],
		          y = -1;
		      for (var k = 1; k < star.length; k += 2) {
		        if (star[k - 1] === b) {
		          y = star[k];
		          break;
		        }
		      }
	
		      //If this is a boundary edge, don't flip it
		      if (y < 0) {
		        continue;
		      }
	
		      //If edge is in circle, flip it
		      if (inCircle(points[a], points[b], points[x], points[y]) < 0) {
		        stack.push(a, b);
		      }
		    }
		  }
	
		  while (stack.length > 0) {
		    var b = stack.pop();
		    var a = stack.pop();
	
		    //Find opposite pairs
		    var x = -1,
		        y = -1;
		    var star = stars[a];
		    for (var i = 1; i < star.length; i += 2) {
		      var s = star[i - 1];
		      var t = star[i];
		      if (s === b) {
		        y = t;
		      } else if (t === b) {
		        x = s;
		      }
		    }
	
		    //If x/y are both valid then skip edge
		    if (x < 0 || y < 0) {
		      continue;
		    }
	
		    //If edge is now delaunay, then don't flip it
		    if (inCircle(points[a], points[b], points[x], points[y]) >= 0) {
		      continue;
		    }
	
		    //Flip the edge
		    triangulation.flip(a, b);
	
		    //Test flipping neighboring edges
		    testFlip(points, triangulation, stack, x, a, y);
		    testFlip(points, triangulation, stack, a, y, x);
		    testFlip(points, triangulation, stack, y, b, x);
		    testFlip(points, triangulation, stack, b, x, y);
		  }
		}
	
	/***/ }),
	/* 81 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var twoProduct = __webpack_require__(32);
		var robustSum = __webpack_require__(33);
		var robustDiff = __webpack_require__(36);
		var robustScale = __webpack_require__(34);
	
		var NUM_EXPAND = 6;
	
		function cofactor(m, c) {
		  var result = new Array(m.length - 1);
		  for (var i = 1; i < m.length; ++i) {
		    var r = result[i - 1] = new Array(m.length - 1);
		    for (var j = 0, k = 0; j < m.length; ++j) {
		      if (j === c) {
		        continue;
		      }
		      r[k++] = m[i][j];
		    }
		  }
		  return result;
		}
	
		function matrix(n) {
		  var result = new Array(n);
		  for (var i = 0; i < n; ++i) {
		    result[i] = new Array(n);
		    for (var j = 0; j < n; ++j) {
		      result[i][j] = ["m", j, "[", n - i - 2, "]"].join("");
		    }
		  }
		  return result;
		}
	
		function generateSum(expr) {
		  if (expr.length === 1) {
		    return expr[0];
		  } else if (expr.length === 2) {
		    return ["sum(", expr[0], ",", expr[1], ")"].join("");
		  } else {
		    var m = expr.length >> 1;
		    return ["sum(", generateSum(expr.slice(0, m)), ",", generateSum(expr.slice(m)), ")"].join("");
		  }
		}
	
		function makeProduct(a, b) {
		  if (a.charAt(0) === "m") {
		    if (b.charAt(0) === "w") {
		      var toks = a.split("[");
		      return ["w", b.substr(1), "m", toks[0].substr(1)].join("");
		    } else {
		      return ["prod(", a, ",", b, ")"].join("");
		    }
		  } else {
		    return makeProduct(b, a);
		  }
		}
	
		function sign(s) {
		  if (s & 1 !== 0) {
		    return "-";
		  }
		  return "";
		}
	
		function determinant(m) {
		  if (m.length === 2) {
		    return [["diff(", makeProduct(m[0][0], m[1][1]), ",", makeProduct(m[1][0], m[0][1]), ")"].join("")];
		  } else {
		    var expr = [];
		    for (var i = 0; i < m.length; ++i) {
		      expr.push(["scale(", generateSum(determinant(cofactor(m, i))), ",", sign(i), m[0][i], ")"].join(""));
		    }
		    return expr;
		  }
		}
	
		function makeSquare(d, n) {
		  var terms = [];
		  for (var i = 0; i < n - 2; ++i) {
		    terms.push(["prod(m", d, "[", i, "],m", d, "[", i, "])"].join(""));
		  }
		  return generateSum(terms);
		}
	
		function orientation(n) {
		  var pos = [];
		  var neg = [];
		  var m = matrix(n);
		  for (var i = 0; i < n; ++i) {
		    m[0][i] = "1";
		    m[n - 1][i] = "w" + i;
		  }
		  for (var i = 0; i < n; ++i) {
		    if ((i & 1) === 0) {
		      pos.push.apply(pos, determinant(cofactor(m, i)));
		    } else {
		      neg.push.apply(neg, determinant(cofactor(m, i)));
		    }
		  }
		  var posExpr = generateSum(pos);
		  var negExpr = generateSum(neg);
		  var funcName = "exactInSphere" + n;
		  var funcArgs = [];
		  for (var i = 0; i < n; ++i) {
		    funcArgs.push("m" + i);
		  }
		  var code = ["function ", funcName, "(", funcArgs.join(), "){"];
		  for (var i = 0; i < n; ++i) {
		    code.push("var w", i, "=", makeSquare(i, n), ";");
		    for (var j = 0; j < n; ++j) {
		      if (j !== i) {
		        code.push("var w", i, "m", j, "=scale(w", i, ",m", j, "[0]);");
		      }
		    }
		  }
		  code.push("var p=", posExpr, ",n=", negExpr, ",d=diff(p,n);return d[d.length-1];}return ", funcName);
		  var proc = new Function("sum", "diff", "prod", "scale", code.join(""));
		  return proc(robustSum, robustDiff, twoProduct, robustScale);
		}
	
		function inSphere0() {
		  return 0;
		}
		function inSphere1() {
		  return 0;
		}
		function inSphere2() {
		  return 0;
		}
	
		var CACHED = [inSphere0, inSphere1, inSphere2];
	
		function slowInSphere(args) {
		  var proc = CACHED[args.length];
		  if (!proc) {
		    proc = CACHED[args.length] = orientation(args.length);
		  }
		  return proc.apply(undefined, args);
		}
	
		function generateInSphereTest() {
		  while (CACHED.length <= NUM_EXPAND) {
		    CACHED.push(orientation(CACHED.length));
		  }
		  var args = [];
		  var procArgs = ["slow"];
		  for (var i = 0; i <= NUM_EXPAND; ++i) {
		    args.push("a" + i);
		    procArgs.push("o" + i);
		  }
		  var code = ["function testInSphere(", args.join(), "){switch(arguments.length){case 0:case 1:return 0;"];
		  for (var i = 2; i <= NUM_EXPAND; ++i) {
		    code.push("case ", i, ":return o", i, "(", args.slice(0, i).join(), ");");
		  }
		  code.push("}var s=new Array(arguments.length);for(var i=0;i<arguments.length;++i){s[i]=arguments[i]};return slow(s);}return testInSphere");
		  procArgs.push(code.join(""));
	
		  var proc = Function.apply(undefined, procArgs);
	
		  module.exports = proc.apply(undefined, [slowInSphere].concat(CACHED));
		  for (var i = 0; i <= NUM_EXPAND; ++i) {
		    module.exports[i] = CACHED[i];
		  }
		}
	
		generateInSphereTest();
	
	/***/ }),
	/* 82 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var bsearch = __webpack_require__(78);
	
		module.exports = classifyFaces;
	
		function FaceIndex(cells, neighbor, constraint, flags, active, next, boundary) {
		  this.cells = cells;
		  this.neighbor = neighbor;
		  this.flags = flags;
		  this.constraint = constraint;
		  this.active = active;
		  this.next = next;
		  this.boundary = boundary;
		}
	
		var proto = FaceIndex.prototype;
	
		function compareCell(a, b) {
		  return a[0] - b[0] || a[1] - b[1] || a[2] - b[2];
		}
	
		proto.locate = function () {
		  var key = [0, 0, 0];
		  return function (a, b, c) {
		    var x = a,
		        y = b,
		        z = c;
		    if (b < c) {
		      if (b < a) {
		        x = b;
		        y = c;
		        z = a;
		      }
		    } else if (c < a) {
		      x = c;
		      y = a;
		      z = b;
		    }
		    if (x < 0) {
		      return -1;
		    }
		    key[0] = x;
		    key[1] = y;
		    key[2] = z;
		    return bsearch.eq(this.cells, key, compareCell);
		  };
		}();
	
		function indexCells(triangulation, infinity) {
		  //First get cells and canonicalize
		  var cells = triangulation.cells();
		  var nc = cells.length;
		  for (var i = 0; i < nc; ++i) {
		    var c = cells[i];
		    var x = c[0],
		        y = c[1],
		        z = c[2];
		    if (y < z) {
		      if (y < x) {
		        c[0] = y;
		        c[1] = z;
		        c[2] = x;
		      }
		    } else if (z < x) {
		      c[0] = z;
		      c[1] = x;
		      c[2] = y;
		    }
		  }
		  cells.sort(compareCell);
	
		  //Initialize flag array
		  var flags = new Array(nc);
		  for (var i = 0; i < flags.length; ++i) {
		    flags[i] = 0;
		  }
	
		  //Build neighbor index, initialize queues
		  var active = [];
		  var next = [];
		  var neighbor = new Array(3 * nc);
		  var constraint = new Array(3 * nc);
		  var boundary = null;
		  if (infinity) {
		    boundary = [];
		  }
		  var index = new FaceIndex(cells, neighbor, constraint, flags, active, next, boundary);
		  for (var i = 0; i < nc; ++i) {
		    var c = cells[i];
		    for (var j = 0; j < 3; ++j) {
		      var x = c[j],
		          y = c[(j + 1) % 3];
		      var a = neighbor[3 * i + j] = index.locate(y, x, triangulation.opposite(y, x));
		      var b = constraint[3 * i + j] = triangulation.isConstraint(x, y);
		      if (a < 0) {
		        if (b) {
		          next.push(i);
		        } else {
		          active.push(i);
		          flags[i] = 1;
		        }
		        if (infinity) {
		          boundary.push([y, x, -1]);
		        }
		      }
		    }
		  }
		  return index;
		}
	
		function filterCells(cells, flags, target) {
		  var ptr = 0;
		  for (var i = 0; i < cells.length; ++i) {
		    if (flags[i] === target) {
		      cells[ptr++] = cells[i];
		    }
		  }
		  cells.length = ptr;
		  return cells;
		}
	
		function classifyFaces(triangulation, target, infinity) {
		  var index = indexCells(triangulation, infinity);
	
		  if (target === 0) {
		    if (infinity) {
		      return index.cells.concat(index.boundary);
		    } else {
		      return index.cells;
		    }
		  }
	
		  var side = 1;
		  var active = index.active;
		  var next = index.next;
		  var flags = index.flags;
		  var cells = index.cells;
		  var constraint = index.constraint;
		  var neighbor = index.neighbor;
	
		  while (active.length > 0 || next.length > 0) {
		    while (active.length > 0) {
		      var t = active.pop();
		      if (flags[t] === -side) {
		        continue;
		      }
		      flags[t] = side;
		      var c = cells[t];
		      for (var j = 0; j < 3; ++j) {
		        var f = neighbor[3 * t + j];
		        if (f >= 0 && flags[f] === 0) {
		          if (constraint[3 * t + j]) {
		            next.push(f);
		          } else {
		            active.push(f);
		            flags[f] = side;
		          }
		        }
		      }
		    }
	
		    //Swap arrays and loop
		    var tmp = next;
		    next = active;
		    active = tmp;
		    next.length = 0;
		    side = -side;
		  }
	
		  var result = filterCells(cells, flags, target);
		  if (infinity) {
		    return result.concat(index.boundary);
		  }
		  return result;
		}
	
	/***/ }),
	/* 83 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		module.exports = planarGraphToPolyline;
	
		var e2a = __webpack_require__(84);
		var planarDual = __webpack_require__(85);
		var preprocessPolygon = __webpack_require__(89);
		var twoProduct = __webpack_require__(32);
		var robustSum = __webpack_require__(33);
		var uniq = __webpack_require__(26);
		var trimLeaves = __webpack_require__(97);
	
		function makeArray(length, fill) {
		  var result = new Array(length);
		  for (var i = 0; i < length; ++i) {
		    result[i] = fill;
		  }
		  return result;
		}
	
		function makeArrayOfArrays(length) {
		  var result = new Array(length);
		  for (var i = 0; i < length; ++i) {
		    result[i] = [];
		  }
		  return result;
		}
	
		function planarGraphToPolyline(edges, positions) {
	
		  //Trim leaves
		  var result = trimLeaves(edges, positions);
		  edges = result[0];
		  positions = result[1];
	
		  var numVertices = positions.length;
		  var numEdges = edges.length;
	
		  //Calculate adjacency list, check manifold
		  var adj = e2a(edges, positions.length);
		  for (var i = 0; i < numVertices; ++i) {
		    if (adj[i].length % 2 === 1) {
		      throw new Error('planar-graph-to-polyline: graph must be manifold');
		    }
		  }
	
		  //Get faces
		  var faces = planarDual(edges, positions);
	
		  //Check orientation of a polygon using exact arithmetic
		  function ccw(c) {
		    var n = c.length;
		    var area = [0];
		    for (var j = 0; j < n; ++j) {
		      var a = positions[c[j]];
		      var b = positions[c[(j + 1) % n]];
		      var t00 = twoProduct(-a[0], a[1]);
		      var t01 = twoProduct(-a[0], b[1]);
		      var t10 = twoProduct(b[0], a[1]);
		      var t11 = twoProduct(b[0], b[1]);
		      area = robustSum(area, robustSum(robustSum(t00, t01), robustSum(t10, t11)));
		    }
		    return area[area.length - 1] > 0;
		  }
	
		  //Extract all clockwise faces
		  faces = faces.filter(ccw);
	
		  //Detect which loops are contained in one another to handle parent-of relation
		  var numFaces = faces.length;
		  var parent = new Array(numFaces);
		  var containment = new Array(numFaces);
		  for (var i = 0; i < numFaces; ++i) {
		    parent[i] = i;
		    var row = new Array(numFaces);
		    var loopVertices = faces[i].map(function (v) {
		      return positions[v];
		    });
		    var pmc = preprocessPolygon([loopVertices]);
		    var count = 0;
		    outer: for (var j = 0; j < numFaces; ++j) {
		      row[j] = 0;
		      if (i === j) {
		        continue;
		      }
		      var c = faces[j];
		      var n = c.length;
		      for (var k = 0; k < n; ++k) {
		        var d = pmc(positions[c[k]]);
		        if (d !== 0) {
		          if (d < 0) {
		            row[j] = 1;
		            count += 1;
		          }
		          continue outer;
		        }
		      }
		      row[j] = 1;
		      count += 1;
		    }
		    containment[i] = [count, i, row];
		  }
		  containment.sort(function (a, b) {
		    return b[0] - a[0];
		  });
		  for (var i = 0; i < numFaces; ++i) {
		    var row = containment[i];
		    var idx = row[1];
		    var children = row[2];
		    for (var j = 0; j < numFaces; ++j) {
		      if (children[j]) {
		        parent[j] = idx;
		      }
		    }
		  }
	
		  //Initialize face adjacency list
		  var fadj = makeArrayOfArrays(numFaces);
		  for (var i = 0; i < numFaces; ++i) {
		    fadj[i].push(parent[i]);
		    fadj[parent[i]].push(i);
		  }
	
		  //Build adjacency matrix for edges
		  var edgeAdjacency = {};
		  var internalVertices = makeArray(numVertices, false);
		  for (var i = 0; i < numFaces; ++i) {
		    var c = faces[i];
		    var n = c.length;
		    for (var j = 0; j < n; ++j) {
		      var a = c[j];
		      var b = c[(j + 1) % n];
		      var key = Math.min(a, b) + ":" + Math.max(a, b);
		      if (key in edgeAdjacency) {
		        var neighbor = edgeAdjacency[key];
		        fadj[neighbor].push(i);
		        fadj[i].push(neighbor);
		        internalVertices[a] = internalVertices[b] = true;
		      } else {
		        edgeAdjacency[key] = i;
		      }
		    }
		  }
	
		  function sharedBoundary(c) {
		    var n = c.length;
		    for (var i = 0; i < n; ++i) {
		      if (!internalVertices[c[i]]) {
		        return false;
		      }
		    }
		    return true;
		  }
	
		  var toVisit = [];
		  var parity = makeArray(numFaces, -1);
		  for (var i = 0; i < numFaces; ++i) {
		    if (parent[i] === i && !sharedBoundary(faces[i])) {
		      toVisit.push(i);
		      parity[i] = 0;
		    } else {
		      parity[i] = -1;
		    }
		  }
	
		  //Using face adjacency, classify faces as in/out
		  var result = [];
		  while (toVisit.length > 0) {
		    var top = toVisit.pop();
		    var nbhd = fadj[top];
		    uniq(nbhd, function (a, b) {
		      return a - b;
		    });
		    var nnbhr = nbhd.length;
		    var p = parity[top];
		    var polyline;
		    if (p === 0) {
		      var c = faces[top];
		      polyline = [c];
		    }
		    for (var i = 0; i < nnbhr; ++i) {
		      var f = nbhd[i];
		      if (parity[f] >= 0) {
		        continue;
		      }
		      parity[f] = p ^ 1;
		      toVisit.push(f);
		      if (p === 0) {
		        var c = faces[f];
		        if (!sharedBoundary(c)) {
		          c.reverse();
		          polyline.push(c);
		        }
		      }
		    }
		    if (p === 0) {
		      result.push(polyline);
		    }
		  }
	
		  return result;
		}
	
	/***/ }),
	/* 84 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = edgeToAdjacency;
	
		var uniq = __webpack_require__(26);
	
		function edgeToAdjacency(edges, numVertices) {
		  var numEdges = edges.length;
		  if (typeof numVertices !== "number") {
		    numVertices = 0;
		    for (var i = 0; i < numEdges; ++i) {
		      var e = edges[i];
		      numVertices = Math.max(numVertices, e[0], e[1]);
		    }
		    numVertices = (numVertices | 0) + 1;
		  }
		  numVertices = numVertices | 0;
		  var adj = new Array(numVertices);
		  for (var i = 0; i < numVertices; ++i) {
		    adj[i] = [];
		  }
		  for (var i = 0; i < numEdges; ++i) {
		    var e = edges[i];
		    adj[e[0]].push(e[1]);
		    adj[e[1]].push(e[0]);
		  }
		  for (var j = 0; j < numVertices; ++j) {
		    uniq(adj[j], function (a, b) {
		      return a - b;
		    });
		  }
		  return adj;
		}
	
	/***/ }),
	/* 85 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = planarDual;
	
		var compareAngle = __webpack_require__(86);
	
		function planarDual(cells, positions) {
	
		  var numVertices = positions.length | 0;
		  var numEdges = cells.length;
		  var adj = [new Array(numVertices), new Array(numVertices)];
		  for (var i = 0; i < numVertices; ++i) {
		    adj[0][i] = [];
		    adj[1][i] = [];
		  }
		  for (var i = 0; i < numEdges; ++i) {
		    var c = cells[i];
		    adj[0][c[0]].push(c);
		    adj[1][c[1]].push(c);
		  }
	
		  var cycles = [];
	
		  //Add isolated vertices as trivial case
		  for (var i = 0; i < numVertices; ++i) {
		    if (adj[0][i].length + adj[1][i].length === 0) {
		      cycles.push([i]);
		    }
		  }
	
		  //Remove a half edge
		  function cut(c, i) {
		    var a = adj[i][c[i]];
		    a.splice(a.indexOf(c), 1);
		  }
	
		  //Find next vertex and cut edge
		  function next(a, b, noCut) {
		    var nextCell, nextVertex, nextDir;
		    for (var i = 0; i < 2; ++i) {
		      if (adj[i][b].length > 0) {
		        nextCell = adj[i][b][0];
		        nextDir = i;
		        break;
		      }
		    }
		    nextVertex = nextCell[nextDir ^ 1];
	
		    for (var dir = 0; dir < 2; ++dir) {
		      var nbhd = adj[dir][b];
		      for (var k = 0; k < nbhd.length; ++k) {
		        var e = nbhd[k];
		        var p = e[dir ^ 1];
		        var cmp = compareAngle(positions[a], positions[b], positions[nextVertex], positions[p]);
		        if (cmp > 0) {
		          nextCell = e;
		          nextVertex = p;
		          nextDir = dir;
		        }
		      }
		    }
		    if (noCut) {
		      return nextVertex;
		    }
		    if (nextCell) {
		      cut(nextCell, nextDir);
		    }
		    return nextVertex;
		  }
	
		  function extractCycle(v, dir) {
		    var e0 = adj[dir][v][0];
		    var cycle = [v];
		    cut(e0, dir);
		    var u = e0[dir ^ 1];
		    var d0 = dir;
		    while (true) {
		      while (u !== v) {
		        cycle.push(u);
		        u = next(cycle[cycle.length - 2], u, false);
		      }
		      if (adj[0][v].length + adj[1][v].length === 0) {
		        break;
		      }
		      var a = cycle[cycle.length - 1];
		      var b = v;
		      var c = cycle[1];
		      var d = next(a, b, true);
		      if (compareAngle(positions[a], positions[b], positions[c], positions[d]) < 0) {
		        break;
		      }
		      cycle.push(v);
		      u = next(a, b);
		    }
		    return cycle;
		  }
	
		  function shouldGlue(pcycle, ncycle) {
		    return ncycle[1] === ncycle[ncycle.length - 1];
		  }
	
		  for (var i = 0; i < numVertices; ++i) {
		    for (var j = 0; j < 2; ++j) {
		      var pcycle = [];
		      while (adj[j][i].length > 0) {
		        var ni = adj[0][i].length;
		        var ncycle = extractCycle(i, j);
		        if (shouldGlue(pcycle, ncycle)) {
		          //Glue together trivial cycles
		          pcycle.push.apply(pcycle, ncycle);
		        } else {
		          if (pcycle.length > 0) {
		            cycles.push(pcycle);
		          }
		          pcycle = ncycle;
		        }
		      }
		      if (pcycle.length > 0) {
		        cycles.push(pcycle);
		      }
		    }
		  }
	
		  //Combine paths and loops together
		  return cycles;
		}
	
	/***/ }),
	/* 86 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = compareAngle;
	
		var orient = __webpack_require__(31);
		var sgn = __webpack_require__(87);
		var twoSum = __webpack_require__(35);
		var robustProduct = __webpack_require__(88);
		var robustSum = __webpack_require__(33);
	
		function testInterior(a, b, c) {
		  var x0 = twoSum(a[0], -b[0]);
		  var y0 = twoSum(a[1], -b[1]);
		  var x1 = twoSum(c[0], -b[0]);
		  var y1 = twoSum(c[1], -b[1]);
	
		  var d = robustSum(robustProduct(x0, x1), robustProduct(y0, y1));
	
		  return d[d.length - 1] >= 0;
		}
	
		function compareAngle(a, b, c, d) {
		  var bcd = orient(b, c, d);
		  if (bcd === 0) {
		    //Handle degenerate cases
		    var sabc = sgn(orient(a, b, c));
		    var sabd = sgn(orient(a, b, d));
		    if (sabc === sabd) {
		      if (sabc === 0) {
		        var ic = testInterior(a, b, c);
		        var id = testInterior(a, b, d);
		        if (ic === id) {
		          return 0;
		        } else if (ic) {
		          return 1;
		        } else {
		          return -1;
		        }
		      }
		      return 0;
		    } else if (sabd === 0) {
		      if (sabc > 0) {
		        return -1;
		      } else if (testInterior(a, b, d)) {
		        return -1;
		      } else {
		        return 1;
		      }
		    } else if (sabc === 0) {
		      if (sabd > 0) {
		        return 1;
		      } else if (testInterior(a, b, c)) {
		        return 1;
		      } else {
		        return -1;
		      }
		    }
		    return sgn(sabd - sabc);
		  }
		  var abc = orient(a, b, c);
		  if (abc > 0) {
		    if (bcd > 0 && orient(a, b, d) > 0) {
		      return 1;
		    }
		    return -1;
		  } else if (abc < 0) {
		    if (bcd > 0 || orient(a, b, d) > 0) {
		      return 1;
		    }
		    return -1;
		  } else {
		    var abd = orient(a, b, d);
		    if (abd > 0) {
		      return 1;
		    } else {
		      if (testInterior(a, b, c)) {
		        return 1;
		      } else {
		        return -1;
		      }
		    }
		  }
		}
	
	/***/ }),
	/* 87 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function signum(x) {
		  if (x < 0) {
		    return -1;
		  }
		  if (x > 0) {
		    return 1;
		  }
		  return 0.0;
		};
	
	/***/ }),
	/* 88 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var robustSum = __webpack_require__(33);
		var robustScale = __webpack_require__(34);
	
		module.exports = robustProduct;
	
		function robustProduct(a, b) {
		  if (a.length === 1) {
		    return robustScale(b, a[0]);
		  }
		  if (b.length === 1) {
		    return robustScale(a, b[0]);
		  }
		  if (a.length === 0 || b.length === 0) {
		    return [0];
		  }
		  var r = [0];
		  if (a.length < b.length) {
		    for (var i = 0; i < a.length; ++i) {
		      r = robustSum(r, robustScale(b, a[i]));
		    }
		  } else {
		    for (var i = 0; i < b.length; ++i) {
		      r = robustSum(r, robustScale(a, b[i]));
		    }
		  }
		  return r;
		}
	
	/***/ }),
	/* 89 */
	/***/ (function(module, exports, __webpack_require__) {
	
		module.exports = preprocessPolygon;
	
		var orient = __webpack_require__(31)[3];
		var makeSlabs = __webpack_require__(90);
		var makeIntervalTree = __webpack_require__(94);
		var bsearch = __webpack_require__(96);
	
		function visitInterval() {
		  return true;
		}
	
		function intervalSearch(table) {
		  return function (x, y) {
		    var tree = table[x];
		    if (tree) {
		      return !!tree.queryPoint(y, visitInterval);
		    }
		    return false;
		  };
		}
	
		function buildVerticalIndex(segments) {
		  var table = {};
		  for (var i = 0; i < segments.length; ++i) {
		    var s = segments[i];
		    var x = s[0][0];
		    var y0 = s[0][1];
		    var y1 = s[1][1];
		    var p = [Math.min(y0, y1), Math.max(y0, y1)];
		    if (x in table) {
		      table[x].push(p);
		    } else {
		      table[x] = [p];
		    }
		  }
		  var intervalTable = {};
		  var keys = Object.keys(table);
		  for (var i = 0; i < keys.length; ++i) {
		    var segs = table[keys[i]];
		    intervalTable[keys[i]] = makeIntervalTree(segs);
		  }
		  return intervalSearch(intervalTable);
		}
	
		function buildSlabSearch(slabs, coordinates) {
		  return function (p) {
		    var bucket = bsearch.le(coordinates, p[0]);
		    if (bucket < 0) {
		      return 1;
		    }
		    var root = slabs[bucket];
		    if (!root) {
		      if (bucket > 0 && coordinates[bucket] === p[0]) {
		        root = slabs[bucket - 1];
		      } else {
		        return 1;
		      }
		    }
		    var lastOrientation = 1;
		    while (root) {
		      var s = root.key;
		      var o = orient(p, s[0], s[1]);
		      if (s[0][0] < s[1][0]) {
		        if (o < 0) {
		          root = root.left;
		        } else if (o > 0) {
		          lastOrientation = -1;
		          root = root.right;
		        } else {
		          return 0;
		        }
		      } else {
		        if (o > 0) {
		          root = root.left;
		        } else if (o < 0) {
		          lastOrientation = 1;
		          root = root.right;
		        } else {
		          return 0;
		        }
		      }
		    }
		    return lastOrientation;
		  };
		}
	
		function classifyEmpty(p) {
		  return 1;
		}
	
		function createClassifyVertical(testVertical) {
		  return function classify(p) {
		    if (testVertical(p[0], p[1])) {
		      return 0;
		    }
		    return 1;
		  };
		}
	
		function createClassifyPointDegen(testVertical, testNormal) {
		  return function classify(p) {
		    if (testVertical(p[0], p[1])) {
		      return 0;
		    }
		    return testNormal(p);
		  };
		}
	
		function preprocessPolygon(loops) {
		  //Compute number of loops
		  var numLoops = loops.length;
	
		  //Unpack segments
		  var segments = [];
		  var vsegments = [];
		  var ptr = 0;
		  for (var i = 0; i < numLoops; ++i) {
		    var loop = loops[i];
		    var numVertices = loop.length;
		    for (var s = numVertices - 1, t = 0; t < numVertices; s = t++) {
		      var a = loop[s];
		      var b = loop[t];
		      if (a[0] === b[0]) {
		        vsegments.push([a, b]);
		      } else {
		        segments.push([a, b]);
		      }
		    }
		  }
	
		  //Degenerate case: All loops are empty
		  if (segments.length === 0) {
		    if (vsegments.length === 0) {
		      return classifyEmpty;
		    } else {
		      return createClassifyVertical(buildVerticalIndex(vsegments));
		    }
		  }
	
		  //Build slab decomposition
		  var slabs = makeSlabs(segments);
		  var testSlab = buildSlabSearch(slabs.slabs, slabs.coordinates);
	
		  if (vsegments.length === 0) {
		    return testSlab;
		  } else {
		    return createClassifyPointDegen(buildVerticalIndex(vsegments), testSlab);
		  }
		}
	
	/***/ }),
	/* 90 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = createSlabDecomposition;
	
		var bounds = __webpack_require__(91);
		var createRBTree = __webpack_require__(92);
		var orient = __webpack_require__(31);
		var orderSegments = __webpack_require__(93);
	
		function SlabDecomposition(slabs, coordinates, horizontal) {
		  this.slabs = slabs;
		  this.coordinates = coordinates;
		  this.horizontal = horizontal;
		}
	
		var proto = SlabDecomposition.prototype;
	
		function compareHorizontal(e, y) {
		  return e.y - y;
		}
	
		function searchBucket(root, p) {
		  var lastNode = null;
		  while (root) {
		    var seg = root.key;
		    var l, r;
		    if (seg[0][0] < seg[1][0]) {
		      l = seg[0];
		      r = seg[1];
		    } else {
		      l = seg[1];
		      r = seg[0];
		    }
		    var o = orient(l, r, p);
		    if (o < 0) {
		      root = root.left;
		    } else if (o > 0) {
		      if (p[0] !== seg[1][0]) {
		        lastNode = root;
		        root = root.right;
		      } else {
		        var val = searchBucket(root.right, p);
		        if (val) {
		          return val;
		        }
		        root = root.left;
		      }
		    } else {
		      if (p[0] !== seg[1][0]) {
		        return root;
		      } else {
		        var val = searchBucket(root.right, p);
		        if (val) {
		          return val;
		        }
		        root = root.left;
		      }
		    }
		  }
		  return lastNode;
		}
	
		proto.castUp = function (p) {
		  var bucket = bounds.le(this.coordinates, p[0]);
		  if (bucket < 0) {
		    return -1;
		  }
		  var root = this.slabs[bucket];
		  var hitNode = searchBucket(this.slabs[bucket], p);
		  var lastHit = -1;
		  if (hitNode) {
		    lastHit = hitNode.value;
		  }
		  //Edge case: need to handle horizontal segments (sucks)
		  if (this.coordinates[bucket] === p[0]) {
		    var lastSegment = null;
		    if (hitNode) {
		      lastSegment = hitNode.key;
		    }
		    if (bucket > 0) {
		      var otherHitNode = searchBucket(this.slabs[bucket - 1], p);
		      if (otherHitNode) {
		        if (lastSegment) {
		          if (orderSegments(otherHitNode.key, lastSegment) > 0) {
		            lastSegment = otherHitNode.key;
		            lastHit = otherHitNode.value;
		          }
		        } else {
		          lastHit = otherHitNode.value;
		          lastSegment = otherHitNode.key;
		        }
		      }
		    }
		    var horiz = this.horizontal[bucket];
		    if (horiz.length > 0) {
		      var hbucket = bounds.ge(horiz, p[1], compareHorizontal);
		      if (hbucket < horiz.length) {
		        var e = horiz[hbucket];
		        if (p[1] === e.y) {
		          if (e.closed) {
		            return e.index;
		          } else {
		            while (hbucket < horiz.length - 1 && horiz[hbucket + 1].y === p[1]) {
		              hbucket = hbucket + 1;
		              e = horiz[hbucket];
		              if (e.closed) {
		                return e.index;
		              }
		            }
		            if (e.y === p[1] && !e.start) {
		              hbucket = hbucket + 1;
		              if (hbucket >= horiz.length) {
		                return lastHit;
		              }
		              e = horiz[hbucket];
		            }
		          }
		        }
		        //Check if e is above/below last segment
		        if (e.start) {
		          if (lastSegment) {
		            var o = orient(lastSegment[0], lastSegment[1], [p[0], e.y]);
		            if (lastSegment[0][0] > lastSegment[1][0]) {
		              o = -o;
		            }
		            if (o > 0) {
		              lastHit = e.index;
		            }
		          } else {
		            lastHit = e.index;
		          }
		        } else if (e.y !== p[1]) {
		          lastHit = e.index;
		        }
		      }
		    }
		  }
		  return lastHit;
		};
	
		function IntervalSegment(y, index, start, closed) {
		  this.y = y;
		  this.index = index;
		  this.start = start;
		  this.closed = closed;
		}
	
		function Event(x, segment, create, index) {
		  this.x = x;
		  this.segment = segment;
		  this.create = create;
		  this.index = index;
		}
	
		function createSlabDecomposition(segments) {
		  var numSegments = segments.length;
		  var numEvents = 2 * numSegments;
		  var events = new Array(numEvents);
		  for (var i = 0; i < numSegments; ++i) {
		    var s = segments[i];
		    var f = s[0][0] < s[1][0];
		    events[2 * i] = new Event(s[0][0], s, f, i);
		    events[2 * i + 1] = new Event(s[1][0], s, !f, i);
		  }
		  events.sort(function (a, b) {
		    var d = a.x - b.x;
		    if (d) {
		      return d;
		    }
		    d = a.create - b.create;
		    if (d) {
		      return d;
		    }
		    return Math.min(a.segment[0][1], a.segment[1][1]) - Math.min(b.segment[0][1], b.segment[1][1]);
		  });
		  var tree = createRBTree(orderSegments);
		  var slabs = [];
		  var lines = [];
		  var horizontal = [];
		  var lastX = -Infinity;
		  for (var i = 0; i < numEvents;) {
		    var x = events[i].x;
		    var horiz = [];
		    while (i < numEvents) {
		      var e = events[i];
		      if (e.x !== x) {
		        break;
		      }
		      i += 1;
		      if (e.segment[0][0] === e.x && e.segment[1][0] === e.x) {
		        if (e.create) {
		          if (e.segment[0][1] < e.segment[1][1]) {
		            horiz.push(new IntervalSegment(e.segment[0][1], e.index, true, true));
		            horiz.push(new IntervalSegment(e.segment[1][1], e.index, false, false));
		          } else {
		            horiz.push(new IntervalSegment(e.segment[1][1], e.index, true, false));
		            horiz.push(new IntervalSegment(e.segment[0][1], e.index, false, true));
		          }
		        }
		      } else {
		        if (e.create) {
		          tree = tree.insert(e.segment, e.index);
		        } else {
		          tree = tree.remove(e.segment);
		        }
		      }
		    }
		    slabs.push(tree.root);
		    lines.push(x);
		    horizontal.push(horiz);
		  }
		  return new SlabDecomposition(slabs, lines, horizontal);
		}
	
	/***/ }),
	/* 91 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		function compileSearch(funcName, predicate, reversed, extraArgs, useNdarray, earlyOut) {
		  var code = ["function ", funcName, "(a,l,h,", extraArgs.join(","), "){", earlyOut ? "" : "var i=", reversed ? "l-1" : "h+1", ";while(l<=h){\
		var m=(l+h)>>>1,x=a", useNdarray ? ".get(m)" : "[m]"];
		  if (earlyOut) {
		    if (predicate.indexOf("c") < 0) {
		      code.push(";if(x===y){return m}else if(x<=y){");
		    } else {
		      code.push(";var p=c(x,y);if(p===0){return m}else if(p<=0){");
		    }
		  } else {
		    code.push(";if(", predicate, "){i=m;");
		  }
		  if (reversed) {
		    code.push("l=m+1}else{h=m-1}");
		  } else {
		    code.push("h=m-1}else{l=m+1}");
		  }
		  code.push("}");
		  if (earlyOut) {
		    code.push("return -1};");
		  } else {
		    code.push("return i};");
		  }
		  return code.join("");
		}
	
		function compileBoundsSearch(predicate, reversed, suffix, earlyOut) {
		  var result = new Function([compileSearch("A", "x" + predicate + "y", reversed, ["y"], false, earlyOut), compileSearch("B", "x" + predicate + "y", reversed, ["y"], true, earlyOut), compileSearch("P", "c(x,y)" + predicate + "0", reversed, ["y", "c"], false, earlyOut), compileSearch("Q", "c(x,y)" + predicate + "0", reversed, ["y", "c"], true, earlyOut), "function dispatchBsearch", suffix, "(a,y,c,l,h){\
		if(a.shape){\
		if(typeof(c)==='function'){\
		return Q(a,(l===undefined)?0:l|0,(h===undefined)?a.shape[0]-1:h|0,y,c)\
		}else{\
		return B(a,(c===undefined)?0:c|0,(l===undefined)?a.shape[0]-1:l|0,y)\
		}}else{\
		if(typeof(c)==='function'){\
		return P(a,(l===undefined)?0:l|0,(h===undefined)?a.length-1:h|0,y,c)\
		}else{\
		return A(a,(c===undefined)?0:c|0,(l===undefined)?a.length-1:l|0,y)\
		}}}\
		return dispatchBsearch", suffix].join(""));
		  return result();
		}
	
		module.exports = {
		  ge: compileBoundsSearch(">=", false, "GE"),
		  gt: compileBoundsSearch(">", false, "GT"),
		  lt: compileBoundsSearch("<", true, "LT"),
		  le: compileBoundsSearch("<=", true, "LE"),
		  eq: compileBoundsSearch("-", true, "EQ", true)
			};
	
	/***/ }),
	/* 92 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = createRBTree;
	
		var RED = 0;
		var BLACK = 1;
	
		function RBNode(color, key, value, left, right, count) {
		  this._color = color;
		  this.key = key;
		  this.value = value;
		  this.left = left;
		  this.right = right;
		  this._count = count;
		}
	
		function cloneNode(node) {
		  return new RBNode(node._color, node.key, node.value, node.left, node.right, node._count);
		}
	
		function repaint(color, node) {
		  return new RBNode(color, node.key, node.value, node.left, node.right, node._count);
		}
	
		function recount(node) {
		  node._count = 1 + (node.left ? node.left._count : 0) + (node.right ? node.right._count : 0);
		}
	
		function RedBlackTree(compare, root) {
		  this._compare = compare;
		  this.root = root;
		}
	
		var proto = RedBlackTree.prototype;
	
		Object.defineProperty(proto, "keys", {
		  get: function () {
		    var result = [];
		    this.forEach(function (k, v) {
		      result.push(k);
		    });
		    return result;
		  }
		});
	
		Object.defineProperty(proto, "values", {
		  get: function () {
		    var result = [];
		    this.forEach(function (k, v) {
		      result.push(v);
		    });
		    return result;
		  }
		});
	
		//Returns the number of nodes in the tree
		Object.defineProperty(proto, "length", {
		  get: function () {
		    if (this.root) {
		      return this.root._count;
		    }
		    return 0;
		  }
		});
	
		//Insert a new item into the tree
		proto.insert = function (key, value) {
		  var cmp = this._compare;
		  //Find point to insert new node at
		  var n = this.root;
		  var n_stack = [];
		  var d_stack = [];
		  while (n) {
		    var d = cmp(key, n.key);
		    n_stack.push(n);
		    d_stack.push(d);
		    if (d <= 0) {
		      n = n.left;
		    } else {
		      n = n.right;
		    }
		  }
		  //Rebuild path to leaf node
		  n_stack.push(new RBNode(RED, key, value, null, null, 1));
		  for (var s = n_stack.length - 2; s >= 0; --s) {
		    var n = n_stack[s];
		    if (d_stack[s] <= 0) {
		      n_stack[s] = new RBNode(n._color, n.key, n.value, n_stack[s + 1], n.right, n._count + 1);
		    } else {
		      n_stack[s] = new RBNode(n._color, n.key, n.value, n.left, n_stack[s + 1], n._count + 1);
		    }
		  }
		  //Rebalance tree using rotations
		  //console.log("start insert", key, d_stack)
		  for (var s = n_stack.length - 1; s > 1; --s) {
		    var p = n_stack[s - 1];
		    var n = n_stack[s];
		    if (p._color === BLACK || n._color === BLACK) {
		      break;
		    }
		    var pp = n_stack[s - 2];
		    if (pp.left === p) {
		      if (p.left === n) {
		        var y = pp.right;
		        if (y && y._color === RED) {
		          //console.log("LLr")
		          p._color = BLACK;
		          pp.right = repaint(BLACK, y);
		          pp._color = RED;
		          s -= 1;
		        } else {
		          //console.log("LLb")
		          pp._color = RED;
		          pp.left = p.right;
		          p._color = BLACK;
		          p.right = pp;
		          n_stack[s - 2] = p;
		          n_stack[s - 1] = n;
		          recount(pp);
		          recount(p);
		          if (s >= 3) {
		            var ppp = n_stack[s - 3];
		            if (ppp.left === pp) {
		              ppp.left = p;
		            } else {
		              ppp.right = p;
		            }
		          }
		          break;
		        }
		      } else {
		        var y = pp.right;
		        if (y && y._color === RED) {
		          //console.log("LRr")
		          p._color = BLACK;
		          pp.right = repaint(BLACK, y);
		          pp._color = RED;
		          s -= 1;
		        } else {
		          //console.log("LRb")
		          p.right = n.left;
		          pp._color = RED;
		          pp.left = n.right;
		          n._color = BLACK;
		          n.left = p;
		          n.right = pp;
		          n_stack[s - 2] = n;
		          n_stack[s - 1] = p;
		          recount(pp);
		          recount(p);
		          recount(n);
		          if (s >= 3) {
		            var ppp = n_stack[s - 3];
		            if (ppp.left === pp) {
		              ppp.left = n;
		            } else {
		              ppp.right = n;
		            }
		          }
		          break;
		        }
		      }
		    } else {
		      if (p.right === n) {
		        var y = pp.left;
		        if (y && y._color === RED) {
		          //console.log("RRr", y.key)
		          p._color = BLACK;
		          pp.left = repaint(BLACK, y);
		          pp._color = RED;
		          s -= 1;
		        } else {
		          //console.log("RRb")
		          pp._color = RED;
		          pp.right = p.left;
		          p._color = BLACK;
		          p.left = pp;
		          n_stack[s - 2] = p;
		          n_stack[s - 1] = n;
		          recount(pp);
		          recount(p);
		          if (s >= 3) {
		            var ppp = n_stack[s - 3];
		            if (ppp.right === pp) {
		              ppp.right = p;
		            } else {
		              ppp.left = p;
		            }
		          }
		          break;
		        }
		      } else {
		        var y = pp.left;
		        if (y && y._color === RED) {
		          //console.log("RLr")
		          p._color = BLACK;
		          pp.left = repaint(BLACK, y);
		          pp._color = RED;
		          s -= 1;
		        } else {
		          //console.log("RLb")
		          p.left = n.right;
		          pp._color = RED;
		          pp.right = n.left;
		          n._color = BLACK;
		          n.right = p;
		          n.left = pp;
		          n_stack[s - 2] = n;
		          n_stack[s - 1] = p;
		          recount(pp);
		          recount(p);
		          recount(n);
		          if (s >= 3) {
		            var ppp = n_stack[s - 3];
		            if (ppp.right === pp) {
		              ppp.right = n;
		            } else {
		              ppp.left = n;
		            }
		          }
		          break;
		        }
		      }
		    }
		  }
		  //Return new tree
		  n_stack[0]._color = BLACK;
		  return new RedBlackTree(cmp, n_stack[0]);
		};
	
		//Visit all nodes inorder
		function doVisitFull(visit, node) {
		  if (node.left) {
		    var v = doVisitFull(visit, node.left);
		    if (v) {
		      return v;
		    }
		  }
		  var v = visit(node.key, node.value);
		  if (v) {
		    return v;
		  }
		  if (node.right) {
		    return doVisitFull(visit, node.right);
		  }
		}
	
		//Visit half nodes in order
		function doVisitHalf(lo, compare, visit, node) {
		  var l = compare(lo, node.key);
		  if (l <= 0) {
		    if (node.left) {
		      var v = doVisitHalf(lo, compare, visit, node.left);
		      if (v) {
		        return v;
		      }
		    }
		    var v = visit(node.key, node.value);
		    if (v) {
		      return v;
		    }
		  }
		  if (node.right) {
		    return doVisitHalf(lo, compare, visit, node.right);
		  }
		}
	
		//Visit all nodes within a range
		function doVisit(lo, hi, compare, visit, node) {
		  var l = compare(lo, node.key);
		  var h = compare(hi, node.key);
		  var v;
		  if (l <= 0) {
		    if (node.left) {
		      v = doVisit(lo, hi, compare, visit, node.left);
		      if (v) {
		        return v;
		      }
		    }
		    if (h > 0) {
		      v = visit(node.key, node.value);
		      if (v) {
		        return v;
		      }
		    }
		  }
		  if (h > 0 && node.right) {
		    return doVisit(lo, hi, compare, visit, node.right);
		  }
		}
	
		proto.forEach = function rbTreeForEach(visit, lo, hi) {
		  if (!this.root) {
		    return;
		  }
		  switch (arguments.length) {
		    case 1:
		      return doVisitFull(visit, this.root);
		      break;
	
		    case 2:
		      return doVisitHalf(lo, this._compare, visit, this.root);
		      break;
	
		    case 3:
		      if (this._compare(lo, hi) >= 0) {
		        return;
		      }
		      return doVisit(lo, hi, this._compare, visit, this.root);
		      break;
		  }
		};
	
		//First item in list
		Object.defineProperty(proto, "begin", {
		  get: function () {
		    var stack = [];
		    var n = this.root;
		    while (n) {
		      stack.push(n);
		      n = n.left;
		    }
		    return new RedBlackTreeIterator(this, stack);
		  }
		});
	
		//Last item in list
		Object.defineProperty(proto, "end", {
		  get: function () {
		    var stack = [];
		    var n = this.root;
		    while (n) {
		      stack.push(n);
		      n = n.right;
		    }
		    return new RedBlackTreeIterator(this, stack);
		  }
		});
	
		//Find the ith item in the tree
		proto.at = function (idx) {
		  if (idx < 0) {
		    return new RedBlackTreeIterator(this, []);
		  }
		  var n = this.root;
		  var stack = [];
		  while (true) {
		    stack.push(n);
		    if (n.left) {
		      if (idx < n.left._count) {
		        n = n.left;
		        continue;
		      }
		      idx -= n.left._count;
		    }
		    if (!idx) {
		      return new RedBlackTreeIterator(this, stack);
		    }
		    idx -= 1;
		    if (n.right) {
		      if (idx >= n.right._count) {
		        break;
		      }
		      n = n.right;
		    } else {
		      break;
		    }
		  }
		  return new RedBlackTreeIterator(this, []);
		};
	
		proto.ge = function (key) {
		  var cmp = this._compare;
		  var n = this.root;
		  var stack = [];
		  var last_ptr = 0;
		  while (n) {
		    var d = cmp(key, n.key);
		    stack.push(n);
		    if (d <= 0) {
		      last_ptr = stack.length;
		    }
		    if (d <= 0) {
		      n = n.left;
		    } else {
		      n = n.right;
		    }
		  }
		  stack.length = last_ptr;
		  return new RedBlackTreeIterator(this, stack);
		};
	
		proto.gt = function (key) {
		  var cmp = this._compare;
		  var n = this.root;
		  var stack = [];
		  var last_ptr = 0;
		  while (n) {
		    var d = cmp(key, n.key);
		    stack.push(n);
		    if (d < 0) {
		      last_ptr = stack.length;
		    }
		    if (d < 0) {
		      n = n.left;
		    } else {
		      n = n.right;
		    }
		  }
		  stack.length = last_ptr;
		  return new RedBlackTreeIterator(this, stack);
		};
	
		proto.lt = function (key) {
		  var cmp = this._compare;
		  var n = this.root;
		  var stack = [];
		  var last_ptr = 0;
		  while (n) {
		    var d = cmp(key, n.key);
		    stack.push(n);
		    if (d > 0) {
		      last_ptr = stack.length;
		    }
		    if (d <= 0) {
		      n = n.left;
		    } else {
		      n = n.right;
		    }
		  }
		  stack.length = last_ptr;
		  return new RedBlackTreeIterator(this, stack);
		};
	
		proto.le = function (key) {
		  var cmp = this._compare;
		  var n = this.root;
		  var stack = [];
		  var last_ptr = 0;
		  while (n) {
		    var d = cmp(key, n.key);
		    stack.push(n);
		    if (d >= 0) {
		      last_ptr = stack.length;
		    }
		    if (d < 0) {
		      n = n.left;
		    } else {
		      n = n.right;
		    }
		  }
		  stack.length = last_ptr;
		  return new RedBlackTreeIterator(this, stack);
		};
	
		//Finds the item with key if it exists
		proto.find = function (key) {
		  var cmp = this._compare;
		  var n = this.root;
		  var stack = [];
		  while (n) {
		    var d = cmp(key, n.key);
		    stack.push(n);
		    if (d === 0) {
		      return new RedBlackTreeIterator(this, stack);
		    }
		    if (d <= 0) {
		      n = n.left;
		    } else {
		      n = n.right;
		    }
		  }
		  return new RedBlackTreeIterator(this, []);
		};
	
		//Removes item with key from tree
		proto.remove = function (key) {
		  var iter = this.find(key);
		  if (iter) {
		    return iter.remove();
		  }
		  return this;
		};
	
		//Returns the item at `key`
		proto.get = function (key) {
		  var cmp = this._compare;
		  var n = this.root;
		  while (n) {
		    var d = cmp(key, n.key);
		    if (d === 0) {
		      return n.value;
		    }
		    if (d <= 0) {
		      n = n.left;
		    } else {
		      n = n.right;
		    }
		  }
		  return;
		};
	
		//Iterator for red black tree
		function RedBlackTreeIterator(tree, stack) {
		  this.tree = tree;
		  this._stack = stack;
		}
	
		var iproto = RedBlackTreeIterator.prototype;
	
		//Test if iterator is valid
		Object.defineProperty(iproto, "valid", {
		  get: function () {
		    return this._stack.length > 0;
		  }
		});
	
		//Node of the iterator
		Object.defineProperty(iproto, "node", {
		  get: function () {
		    if (this._stack.length > 0) {
		      return this._stack[this._stack.length - 1];
		    }
		    return null;
		  },
		  enumerable: true
		});
	
		//Makes a copy of an iterator
		iproto.clone = function () {
		  return new RedBlackTreeIterator(this.tree, this._stack.slice());
		};
	
		//Swaps two nodes
		function swapNode(n, v) {
		  n.key = v.key;
		  n.value = v.value;
		  n.left = v.left;
		  n.right = v.right;
		  n._color = v._color;
		  n._count = v._count;
		}
	
		//Fix up a double black node in a tree
		function fixDoubleBlack(stack) {
		  var n, p, s, z;
		  for (var i = stack.length - 1; i >= 0; --i) {
		    n = stack[i];
		    if (i === 0) {
		      n._color = BLACK;
		      return;
		    }
		    //console.log("visit node:", n.key, i, stack[i].key, stack[i-1].key)
		    p = stack[i - 1];
		    if (p.left === n) {
		      //console.log("left child")
		      s = p.right;
		      if (s.right && s.right._color === RED) {
		        //console.log("case 1: right sibling child red")
		        s = p.right = cloneNode(s);
		        z = s.right = cloneNode(s.right);
		        p.right = s.left;
		        s.left = p;
		        s.right = z;
		        s._color = p._color;
		        n._color = BLACK;
		        p._color = BLACK;
		        z._color = BLACK;
		        recount(p);
		        recount(s);
		        if (i > 1) {
		          var pp = stack[i - 2];
		          if (pp.left === p) {
		            pp.left = s;
		          } else {
		            pp.right = s;
		          }
		        }
		        stack[i - 1] = s;
		        return;
		      } else if (s.left && s.left._color === RED) {
		        //console.log("case 1: left sibling child red")
		        s = p.right = cloneNode(s);
		        z = s.left = cloneNode(s.left);
		        p.right = z.left;
		        s.left = z.right;
		        z.left = p;
		        z.right = s;
		        z._color = p._color;
		        p._color = BLACK;
		        s._color = BLACK;
		        n._color = BLACK;
		        recount(p);
		        recount(s);
		        recount(z);
		        if (i > 1) {
		          var pp = stack[i - 2];
		          if (pp.left === p) {
		            pp.left = z;
		          } else {
		            pp.right = z;
		          }
		        }
		        stack[i - 1] = z;
		        return;
		      }
		      if (s._color === BLACK) {
		        if (p._color === RED) {
		          //console.log("case 2: black sibling, red parent", p.right.value)
		          p._color = BLACK;
		          p.right = repaint(RED, s);
		          return;
		        } else {
		          //console.log("case 2: black sibling, black parent", p.right.value)
		          p.right = repaint(RED, s);
		          continue;
		        }
		      } else {
		        //console.log("case 3: red sibling")
		        s = cloneNode(s);
		        p.right = s.left;
		        s.left = p;
		        s._color = p._color;
		        p._color = RED;
		        recount(p);
		        recount(s);
		        if (i > 1) {
		          var pp = stack[i - 2];
		          if (pp.left === p) {
		            pp.left = s;
		          } else {
		            pp.right = s;
		          }
		        }
		        stack[i - 1] = s;
		        stack[i] = p;
		        if (i + 1 < stack.length) {
		          stack[i + 1] = n;
		        } else {
		          stack.push(n);
		        }
		        i = i + 2;
		      }
		    } else {
		      //console.log("right child")
		      s = p.left;
		      if (s.left && s.left._color === RED) {
		        //console.log("case 1: left sibling child red", p.value, p._color)
		        s = p.left = cloneNode(s);
		        z = s.left = cloneNode(s.left);
		        p.left = s.right;
		        s.right = p;
		        s.left = z;
		        s._color = p._color;
		        n._color = BLACK;
		        p._color = BLACK;
		        z._color = BLACK;
		        recount(p);
		        recount(s);
		        if (i > 1) {
		          var pp = stack[i - 2];
		          if (pp.right === p) {
		            pp.right = s;
		          } else {
		            pp.left = s;
		          }
		        }
		        stack[i - 1] = s;
		        return;
		      } else if (s.right && s.right._color === RED) {
		        //console.log("case 1: right sibling child red")
		        s = p.left = cloneNode(s);
		        z = s.right = cloneNode(s.right);
		        p.left = z.right;
		        s.right = z.left;
		        z.right = p;
		        z.left = s;
		        z._color = p._color;
		        p._color = BLACK;
		        s._color = BLACK;
		        n._color = BLACK;
		        recount(p);
		        recount(s);
		        recount(z);
		        if (i > 1) {
		          var pp = stack[i - 2];
		          if (pp.right === p) {
		            pp.right = z;
		          } else {
		            pp.left = z;
		          }
		        }
		        stack[i - 1] = z;
		        return;
		      }
		      if (s._color === BLACK) {
		        if (p._color === RED) {
		          //console.log("case 2: black sibling, red parent")
		          p._color = BLACK;
		          p.left = repaint(RED, s);
		          return;
		        } else {
		          //console.log("case 2: black sibling, black parent")
		          p.left = repaint(RED, s);
		          continue;
		        }
		      } else {
		        //console.log("case 3: red sibling")
		        s = cloneNode(s);
		        p.left = s.right;
		        s.right = p;
		        s._color = p._color;
		        p._color = RED;
		        recount(p);
		        recount(s);
		        if (i > 1) {
		          var pp = stack[i - 2];
		          if (pp.right === p) {
		            pp.right = s;
		          } else {
		            pp.left = s;
		          }
		        }
		        stack[i - 1] = s;
		        stack[i] = p;
		        if (i + 1 < stack.length) {
		          stack[i + 1] = n;
		        } else {
		          stack.push(n);
		        }
		        i = i + 2;
		      }
		    }
		  }
		}
	
		//Removes item at iterator from tree
		iproto.remove = function () {
		  var stack = this._stack;
		  if (stack.length === 0) {
		    return this.tree;
		  }
		  //First copy path to node
		  var cstack = new Array(stack.length);
		  var n = stack[stack.length - 1];
		  cstack[cstack.length - 1] = new RBNode(n._color, n.key, n.value, n.left, n.right, n._count);
		  for (var i = stack.length - 2; i >= 0; --i) {
		    var n = stack[i];
		    if (n.left === stack[i + 1]) {
		      cstack[i] = new RBNode(n._color, n.key, n.value, cstack[i + 1], n.right, n._count);
		    } else {
		      cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i + 1], n._count);
		    }
		  }
	
		  //Get node
		  n = cstack[cstack.length - 1];
		  //console.log("start remove: ", n.value)
	
		  //If not leaf, then swap with previous node
		  if (n.left && n.right) {
		    //console.log("moving to leaf")
	
		    //First walk to previous leaf
		    var split = cstack.length;
		    n = n.left;
		    while (n.right) {
		      cstack.push(n);
		      n = n.right;
		    }
		    //Copy path to leaf
		    var v = cstack[split - 1];
		    cstack.push(new RBNode(n._color, v.key, v.value, n.left, n.right, n._count));
		    cstack[split - 1].key = n.key;
		    cstack[split - 1].value = n.value;
	
		    //Fix up stack
		    for (var i = cstack.length - 2; i >= split; --i) {
		      n = cstack[i];
		      cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i + 1], n._count);
		    }
		    cstack[split - 1].left = cstack[split];
		  }
		  //console.log("stack=", cstack.map(function(v) { return v.value }))
	
		  //Remove leaf node
		  n = cstack[cstack.length - 1];
		  if (n._color === RED) {
		    //Easy case: removing red leaf
		    //console.log("RED leaf")
		    var p = cstack[cstack.length - 2];
		    if (p.left === n) {
		      p.left = null;
		    } else if (p.right === n) {
		      p.right = null;
		    }
		    cstack.pop();
		    for (var i = 0; i < cstack.length; ++i) {
		      cstack[i]._count--;
		    }
		    return new RedBlackTree(this.tree._compare, cstack[0]);
		  } else {
		    if (n.left || n.right) {
		      //Second easy case:  Single child black parent
		      //console.log("BLACK single child")
		      if (n.left) {
		        swapNode(n, n.left);
		      } else if (n.right) {
		        swapNode(n, n.right);
		      }
		      //Child must be red, so repaint it black to balance color
		      n._color = BLACK;
		      for (var i = 0; i < cstack.length - 1; ++i) {
		        cstack[i]._count--;
		      }
		      return new RedBlackTree(this.tree._compare, cstack[0]);
		    } else if (cstack.length === 1) {
		      //Third easy case: root
		      //console.log("ROOT")
		      return new RedBlackTree(this.tree._compare, null);
		    } else {
		      //Hard case: Repaint n, and then do some nasty stuff
		      //console.log("BLACK leaf no children")
		      for (var i = 0; i < cstack.length; ++i) {
		        cstack[i]._count--;
		      }
		      var parent = cstack[cstack.length - 2];
		      fixDoubleBlack(cstack);
		      //Fix up links
		      if (parent.left === n) {
		        parent.left = null;
		      } else {
		        parent.right = null;
		      }
		    }
		  }
		  return new RedBlackTree(this.tree._compare, cstack[0]);
		};
	
		//Returns key
		Object.defineProperty(iproto, "key", {
		  get: function () {
		    if (this._stack.length > 0) {
		      return this._stack[this._stack.length - 1].key;
		    }
		    return;
		  },
		  enumerable: true
		});
	
		//Returns value
		Object.defineProperty(iproto, "value", {
		  get: function () {
		    if (this._stack.length > 0) {
		      return this._stack[this._stack.length - 1].value;
		    }
		    return;
		  },
		  enumerable: true
		});
	
		//Returns the position of this iterator in the sorted list
		Object.defineProperty(iproto, "index", {
		  get: function () {
		    var idx = 0;
		    var stack = this._stack;
		    if (stack.length === 0) {
		      var r = this.tree.root;
		      if (r) {
		        return r._count;
		      }
		      return 0;
		    } else if (stack[stack.length - 1].left) {
		      idx = stack[stack.length - 1].left._count;
		    }
		    for (var s = stack.length - 2; s >= 0; --s) {
		      if (stack[s + 1] === stack[s].right) {
		        ++idx;
		        if (stack[s].left) {
		          idx += stack[s].left._count;
		        }
		      }
		    }
		    return idx;
		  },
		  enumerable: true
		});
	
		//Advances iterator to next element in list
		iproto.next = function () {
		  var stack = this._stack;
		  if (stack.length === 0) {
		    return;
		  }
		  var n = stack[stack.length - 1];
		  if (n.right) {
		    n = n.right;
		    while (n) {
		      stack.push(n);
		      n = n.left;
		    }
		  } else {
		    stack.pop();
		    while (stack.length > 0 && stack[stack.length - 1].right === n) {
		      n = stack[stack.length - 1];
		      stack.pop();
		    }
		  }
		};
	
		//Checks if iterator is at end of tree
		Object.defineProperty(iproto, "hasNext", {
		  get: function () {
		    var stack = this._stack;
		    if (stack.length === 0) {
		      return false;
		    }
		    if (stack[stack.length - 1].right) {
		      return true;
		    }
		    for (var s = stack.length - 1; s > 0; --s) {
		      if (stack[s - 1].left === stack[s]) {
		        return true;
		      }
		    }
		    return false;
		  }
		});
	
		//Update value
		iproto.update = function (value) {
		  var stack = this._stack;
		  if (stack.length === 0) {
		    throw new Error("Can't update empty node!");
		  }
		  var cstack = new Array(stack.length);
		  var n = stack[stack.length - 1];
		  cstack[cstack.length - 1] = new RBNode(n._color, n.key, value, n.left, n.right, n._count);
		  for (var i = stack.length - 2; i >= 0; --i) {
		    n = stack[i];
		    if (n.left === stack[i + 1]) {
		      cstack[i] = new RBNode(n._color, n.key, n.value, cstack[i + 1], n.right, n._count);
		    } else {
		      cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i + 1], n._count);
		    }
		  }
		  return new RedBlackTree(this.tree._compare, cstack[0]);
		};
	
		//Moves iterator backward one element
		iproto.prev = function () {
		  var stack = this._stack;
		  if (stack.length === 0) {
		    return;
		  }
		  var n = stack[stack.length - 1];
		  if (n.left) {
		    n = n.left;
		    while (n) {
		      stack.push(n);
		      n = n.right;
		    }
		  } else {
		    stack.pop();
		    while (stack.length > 0 && stack[stack.length - 1].left === n) {
		      n = stack[stack.length - 1];
		      stack.pop();
		    }
		  }
		};
	
		//Checks if iterator is at start of tree
		Object.defineProperty(iproto, "hasPrev", {
		  get: function () {
		    var stack = this._stack;
		    if (stack.length === 0) {
		      return false;
		    }
		    if (stack[stack.length - 1].left) {
		      return true;
		    }
		    for (var s = stack.length - 1; s > 0; --s) {
		      if (stack[s - 1].right === stack[s]) {
		        return true;
		      }
		    }
		    return false;
		  }
		});
	
		//Default comparison function
		function defaultCompare(a, b) {
		  if (a < b) {
		    return -1;
		  }
		  if (a > b) {
		    return 1;
		  }
		  return 0;
		}
	
		//Build a tree
		function createRBTree(compare) {
		  return new RedBlackTree(compare || defaultCompare, null);
		}
	
	/***/ }),
	/* 93 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = orderSegments;
	
		var orient = __webpack_require__(31);
	
		function horizontalOrder(a, b) {
		  var bl, br;
		  if (b[0][0] < b[1][0]) {
		    bl = b[0];
		    br = b[1];
		  } else if (b[0][0] > b[1][0]) {
		    bl = b[1];
		    br = b[0];
		  } else {
		    var alo = Math.min(a[0][1], a[1][1]);
		    var ahi = Math.max(a[0][1], a[1][1]);
		    var blo = Math.min(b[0][1], b[1][1]);
		    var bhi = Math.max(b[0][1], b[1][1]);
		    if (ahi < blo) {
		      return ahi - blo;
		    }
		    if (alo > bhi) {
		      return alo - bhi;
		    }
		    return ahi - bhi;
		  }
		  var al, ar;
		  if (a[0][1] < a[1][1]) {
		    al = a[0];
		    ar = a[1];
		  } else {
		    al = a[1];
		    ar = a[0];
		  }
		  var d = orient(br, bl, al);
		  if (d) {
		    return d;
		  }
		  d = orient(br, bl, ar);
		  if (d) {
		    return d;
		  }
		  return ar - br;
		}
	
		function orderSegments(b, a) {
		  var al, ar;
		  if (a[0][0] < a[1][0]) {
		    al = a[0];
		    ar = a[1];
		  } else if (a[0][0] > a[1][0]) {
		    al = a[1];
		    ar = a[0];
		  } else {
		    return horizontalOrder(a, b);
		  }
		  var bl, br;
		  if (b[0][0] < b[1][0]) {
		    bl = b[0];
		    br = b[1];
		  } else if (b[0][0] > b[1][0]) {
		    bl = b[1];
		    br = b[0];
		  } else {
		    return -horizontalOrder(b, a);
		  }
		  var d1 = orient(al, ar, br);
		  var d2 = orient(al, ar, bl);
		  if (d1 < 0) {
		    if (d2 <= 0) {
		      return d1;
		    }
		  } else if (d1 > 0) {
		    if (d2 >= 0) {
		      return d1;
		    }
		  } else if (d2) {
		    return d2;
		  }
		  d1 = orient(br, bl, ar);
		  d2 = orient(br, bl, al);
		  if (d1 < 0) {
		    if (d2 <= 0) {
		      return d1;
		    }
		  } else if (d1 > 0) {
		    if (d2 >= 0) {
		      return d1;
		    }
		  } else if (d2) {
		    return d2;
		  }
		  return ar[0] - br[0];
		}
	
	/***/ }),
	/* 94 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var bounds = __webpack_require__(95);
	
		var NOT_FOUND = 0;
		var SUCCESS = 1;
		var EMPTY = 2;
	
		module.exports = createWrapper;
	
		function IntervalTreeNode(mid, left, right, leftPoints, rightPoints) {
		  this.mid = mid;
		  this.left = left;
		  this.right = right;
		  this.leftPoints = leftPoints;
		  this.rightPoints = rightPoints;
		  this.count = (left ? left.count : 0) + (right ? right.count : 0) + leftPoints.length;
		}
	
		var proto = IntervalTreeNode.prototype;
	
		function copy(a, b) {
		  a.mid = b.mid;
		  a.left = b.left;
		  a.right = b.right;
		  a.leftPoints = b.leftPoints;
		  a.rightPoints = b.rightPoints;
		  a.count = b.count;
		}
	
		function rebuild(node, intervals) {
		  var ntree = createIntervalTree(intervals);
		  node.mid = ntree.mid;
		  node.left = ntree.left;
		  node.right = ntree.right;
		  node.leftPoints = ntree.leftPoints;
		  node.rightPoints = ntree.rightPoints;
		  node.count = ntree.count;
		}
	
		function rebuildWithInterval(node, interval) {
		  var intervals = node.intervals([]);
		  intervals.push(interval);
		  rebuild(node, intervals);
		}
	
		function rebuildWithoutInterval(node, interval) {
		  var intervals = node.intervals([]);
		  var idx = intervals.indexOf(interval);
		  if (idx < 0) {
		    return NOT_FOUND;
		  }
		  intervals.splice(idx, 1);
		  rebuild(node, intervals);
		  return SUCCESS;
		}
	
		proto.intervals = function (result) {
		  result.push.apply(result, this.leftPoints);
		  if (this.left) {
		    this.left.intervals(result);
		  }
		  if (this.right) {
		    this.right.intervals(result);
		  }
		  return result;
		};
	
		proto.insert = function (interval) {
		  var weight = this.count - this.leftPoints.length;
		  this.count += 1;
		  if (interval[1] < this.mid) {
		    if (this.left) {
		      if (4 * (this.left.count + 1) > 3 * (weight + 1)) {
		        rebuildWithInterval(this, interval);
		      } else {
		        this.left.insert(interval);
		      }
		    } else {
		      this.left = createIntervalTree([interval]);
		    }
		  } else if (interval[0] > this.mid) {
		    if (this.right) {
		      if (4 * (this.right.count + 1) > 3 * (weight + 1)) {
		        rebuildWithInterval(this, interval);
		      } else {
		        this.right.insert(interval);
		      }
		    } else {
		      this.right = createIntervalTree([interval]);
		    }
		  } else {
		    var l = bounds.ge(this.leftPoints, interval, compareBegin);
		    var r = bounds.ge(this.rightPoints, interval, compareEnd);
		    this.leftPoints.splice(l, 0, interval);
		    this.rightPoints.splice(r, 0, interval);
		  }
		};
	
		proto.remove = function (interval) {
		  var weight = this.count - this.leftPoints;
		  if (interval[1] < this.mid) {
		    if (!this.left) {
		      return NOT_FOUND;
		    }
		    var rw = this.right ? this.right.count : 0;
		    if (4 * rw > 3 * (weight - 1)) {
		      return rebuildWithoutInterval(this, interval);
		    }
		    var r = this.left.remove(interval);
		    if (r === EMPTY) {
		      this.left = null;
		      this.count -= 1;
		      return SUCCESS;
		    } else if (r === SUCCESS) {
		      this.count -= 1;
		    }
		    return r;
		  } else if (interval[0] > this.mid) {
		    if (!this.right) {
		      return NOT_FOUND;
		    }
		    var lw = this.left ? this.left.count : 0;
		    if (4 * lw > 3 * (weight - 1)) {
		      return rebuildWithoutInterval(this, interval);
		    }
		    var r = this.right.remove(interval);
		    if (r === EMPTY) {
		      this.right = null;
		      this.count -= 1;
		      return SUCCESS;
		    } else if (r === SUCCESS) {
		      this.count -= 1;
		    }
		    return r;
		  } else {
		    if (this.count === 1) {
		      if (this.leftPoints[0] === interval) {
		        return EMPTY;
		      } else {
		        return NOT_FOUND;
		      }
		    }
		    if (this.leftPoints.length === 1 && this.leftPoints[0] === interval) {
		      if (this.left && this.right) {
		        var p = this;
		        var n = this.left;
		        while (n.right) {
		          p = n;
		          n = n.right;
		        }
		        if (p === this) {
		          n.right = this.right;
		        } else {
		          var l = this.left;
		          var r = this.right;
		          p.count -= n.count;
		          p.right = n.left;
		          n.left = l;
		          n.right = r;
		        }
		        copy(this, n);
		        this.count = (this.left ? this.left.count : 0) + (this.right ? this.right.count : 0) + this.leftPoints.length;
		      } else if (this.left) {
		        copy(this, this.left);
		      } else {
		        copy(this, this.right);
		      }
		      return SUCCESS;
		    }
		    for (var l = bounds.ge(this.leftPoints, interval, compareBegin); l < this.leftPoints.length; ++l) {
		      if (this.leftPoints[l][0] !== interval[0]) {
		        break;
		      }
		      if (this.leftPoints[l] === interval) {
		        this.count -= 1;
		        this.leftPoints.splice(l, 1);
		        for (var r = bounds.ge(this.rightPoints, interval, compareEnd); r < this.rightPoints.length; ++r) {
		          if (this.rightPoints[r][1] !== interval[1]) {
		            break;
		          } else if (this.rightPoints[r] === interval) {
		            this.rightPoints.splice(r, 1);
		            return SUCCESS;
		          }
		        }
		      }
		    }
		    return NOT_FOUND;
		  }
		};
	
		function reportLeftRange(arr, hi, cb) {
		  for (var i = 0; i < arr.length && arr[i][0] <= hi; ++i) {
		    var r = cb(arr[i]);
		    if (r) {
		      return r;
		    }
		  }
		}
	
		function reportRightRange(arr, lo, cb) {
		  for (var i = arr.length - 1; i >= 0 && arr[i][1] >= lo; --i) {
		    var r = cb(arr[i]);
		    if (r) {
		      return r;
		    }
		  }
		}
	
		function reportRange(arr, cb) {
		  for (var i = 0; i < arr.length; ++i) {
		    var r = cb(arr[i]);
		    if (r) {
		      return r;
		    }
		  }
		}
	
		proto.queryPoint = function (x, cb) {
		  if (x < this.mid) {
		    if (this.left) {
		      var r = this.left.queryPoint(x, cb);
		      if (r) {
		        return r;
		      }
		    }
		    return reportLeftRange(this.leftPoints, x, cb);
		  } else if (x > this.mid) {
		    if (this.right) {
		      var r = this.right.queryPoint(x, cb);
		      if (r) {
		        return r;
		      }
		    }
		    return reportRightRange(this.rightPoints, x, cb);
		  } else {
		    return reportRange(this.leftPoints, cb);
		  }
		};
	
		proto.queryInterval = function (lo, hi, cb) {
		  if (lo < this.mid && this.left) {
		    var r = this.left.queryInterval(lo, hi, cb);
		    if (r) {
		      return r;
		    }
		  }
		  if (hi > this.mid && this.right) {
		    var r = this.right.queryInterval(lo, hi, cb);
		    if (r) {
		      return r;
		    }
		  }
		  if (hi < this.mid) {
		    return reportLeftRange(this.leftPoints, hi, cb);
		  } else if (lo > this.mid) {
		    return reportRightRange(this.rightPoints, lo, cb);
		  } else {
		    return reportRange(this.leftPoints, cb);
		  }
		};
	
		function compareNumbers(a, b) {
		  return a - b;
		}
	
		function compareBegin(a, b) {
		  var d = a[0] - b[0];
		  if (d) {
		    return d;
		  }
		  return a[1] - b[1];
		}
	
		function compareEnd(a, b) {
		  var d = a[1] - b[1];
		  if (d) {
		    return d;
		  }
		  return a[0] - b[0];
		}
	
		function createIntervalTree(intervals) {
		  if (intervals.length === 0) {
		    return null;
		  }
		  var pts = [];
		  for (var i = 0; i < intervals.length; ++i) {
		    pts.push(intervals[i][0], intervals[i][1]);
		  }
		  pts.sort(compareNumbers);
	
		  var mid = pts[pts.length >> 1];
	
		  var leftIntervals = [];
		  var rightIntervals = [];
		  var centerIntervals = [];
		  for (var i = 0; i < intervals.length; ++i) {
		    var s = intervals[i];
		    if (s[1] < mid) {
		      leftIntervals.push(s);
		    } else if (mid < s[0]) {
		      rightIntervals.push(s);
		    } else {
		      centerIntervals.push(s);
		    }
		  }
	
		  //Split center intervals
		  var leftPoints = centerIntervals;
		  var rightPoints = centerIntervals.slice();
		  leftPoints.sort(compareBegin);
		  rightPoints.sort(compareEnd);
	
		  return new IntervalTreeNode(mid, createIntervalTree(leftIntervals), createIntervalTree(rightIntervals), leftPoints, rightPoints);
		}
	
		//User friendly wrapper that makes it possible to support empty trees
		function IntervalTree(root) {
		  this.root = root;
		}
	
		var tproto = IntervalTree.prototype;
	
		tproto.insert = function (interval) {
		  if (this.root) {
		    this.root.insert(interval);
		  } else {
		    this.root = new IntervalTreeNode(interval[0], null, null, [interval], [interval]);
		  }
		};
	
		tproto.remove = function (interval) {
		  if (this.root) {
		    var r = this.root.remove(interval);
		    if (r === EMPTY) {
		      this.root = null;
		    }
		    return r !== NOT_FOUND;
		  }
		  return false;
		};
	
		tproto.queryPoint = function (p, cb) {
		  if (this.root) {
		    return this.root.queryPoint(p, cb);
		  }
		};
	
		tproto.queryInterval = function (lo, hi, cb) {
		  if (lo <= hi && this.root) {
		    return this.root.queryInterval(lo, hi, cb);
		  }
		};
	
		Object.defineProperty(tproto, "count", {
		  get: function () {
		    if (this.root) {
		      return this.root.count;
		    }
		    return 0;
		  }
		});
	
		Object.defineProperty(tproto, "intervals", {
		  get: function () {
		    if (this.root) {
		      return this.root.intervals([]);
		    }
		    return [];
		  }
		});
	
		function createWrapper(intervals) {
		  if (!intervals || intervals.length === 0) {
		    return new IntervalTree(null);
		  }
		  return new IntervalTree(createIntervalTree(intervals));
		}
	
	/***/ }),
	/* 95 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		function compileSearch(funcName, predicate, reversed, extraArgs, useNdarray, earlyOut) {
		  var code = ["function ", funcName, "(a,l,h,", extraArgs.join(","), "){", earlyOut ? "" : "var i=", reversed ? "l-1" : "h+1", ";while(l<=h){\
		var m=(l+h)>>>1,x=a", useNdarray ? ".get(m)" : "[m]"];
		  if (earlyOut) {
		    if (predicate.indexOf("c") < 0) {
		      code.push(";if(x===y){return m}else if(x<=y){");
		    } else {
		      code.push(";var p=c(x,y);if(p===0){return m}else if(p<=0){");
		    }
		  } else {
		    code.push(";if(", predicate, "){i=m;");
		  }
		  if (reversed) {
		    code.push("l=m+1}else{h=m-1}");
		  } else {
		    code.push("h=m-1}else{l=m+1}");
		  }
		  code.push("}");
		  if (earlyOut) {
		    code.push("return -1};");
		  } else {
		    code.push("return i};");
		  }
		  return code.join("");
		}
	
		function compileBoundsSearch(predicate, reversed, suffix, earlyOut) {
		  var result = new Function([compileSearch("A", "x" + predicate + "y", reversed, ["y"], false, earlyOut), compileSearch("B", "x" + predicate + "y", reversed, ["y"], true, earlyOut), compileSearch("P", "c(x,y)" + predicate + "0", reversed, ["y", "c"], false, earlyOut), compileSearch("Q", "c(x,y)" + predicate + "0", reversed, ["y", "c"], true, earlyOut), "function dispatchBsearch", suffix, "(a,y,c,l,h){\
		if(a.shape){\
		if(typeof(c)==='function'){\
		return Q(a,(l===undefined)?0:l|0,(h===undefined)?a.shape[0]-1:h|0,y,c)\
		}else{\
		return B(a,(c===undefined)?0:c|0,(l===undefined)?a.shape[0]-1:l|0,y)\
		}}else{\
		if(typeof(c)==='function'){\
		return P(a,(l===undefined)?0:l|0,(h===undefined)?a.length-1:h|0,y,c)\
		}else{\
		return A(a,(c===undefined)?0:c|0,(l===undefined)?a.length-1:l|0,y)\
		}}}\
		return dispatchBsearch", suffix].join(""));
		  return result();
		}
	
		module.exports = {
		  ge: compileBoundsSearch(">=", false, "GE"),
		  gt: compileBoundsSearch(">", false, "GT"),
		  lt: compileBoundsSearch("<", true, "LT"),
		  le: compileBoundsSearch("<=", true, "LE"),
		  eq: compileBoundsSearch("-", true, "EQ", true)
			};
	
	/***/ }),
	/* 96 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		function compileSearch(funcName, predicate, reversed, extraArgs, useNdarray, earlyOut) {
		  var code = ["function ", funcName, "(a,l,h,", extraArgs.join(","), "){", earlyOut ? "" : "var i=", reversed ? "l-1" : "h+1", ";while(l<=h){\
		var m=(l+h)>>>1,x=a", useNdarray ? ".get(m)" : "[m]"];
		  if (earlyOut) {
		    if (predicate.indexOf("c") < 0) {
		      code.push(";if(x===y){return m}else if(x<=y){");
		    } else {
		      code.push(";var p=c(x,y);if(p===0){return m}else if(p<=0){");
		    }
		  } else {
		    code.push(";if(", predicate, "){i=m;");
		  }
		  if (reversed) {
		    code.push("l=m+1}else{h=m-1}");
		  } else {
		    code.push("h=m-1}else{l=m+1}");
		  }
		  code.push("}");
		  if (earlyOut) {
		    code.push("return -1};");
		  } else {
		    code.push("return i};");
		  }
		  return code.join("");
		}
	
		function compileBoundsSearch(predicate, reversed, suffix, earlyOut) {
		  var result = new Function([compileSearch("A", "x" + predicate + "y", reversed, ["y"], false, earlyOut), compileSearch("B", "x" + predicate + "y", reversed, ["y"], true, earlyOut), compileSearch("P", "c(x,y)" + predicate + "0", reversed, ["y", "c"], false, earlyOut), compileSearch("Q", "c(x,y)" + predicate + "0", reversed, ["y", "c"], true, earlyOut), "function dispatchBsearch", suffix, "(a,y,c,l,h){\
		if(a.shape){\
		if(typeof(c)==='function'){\
		return Q(a,(l===undefined)?0:l|0,(h===undefined)?a.shape[0]-1:h|0,y,c)\
		}else{\
		return B(a,(c===undefined)?0:c|0,(l===undefined)?a.shape[0]-1:l|0,y)\
		}}else{\
		if(typeof(c)==='function'){\
		return P(a,(l===undefined)?0:l|0,(h===undefined)?a.length-1:h|0,y,c)\
		}else{\
		return A(a,(c===undefined)?0:c|0,(l===undefined)?a.length-1:l|0,y)\
		}}}\
		return dispatchBsearch", suffix].join(""));
		  return result();
		}
	
		module.exports = {
		  ge: compileBoundsSearch(">=", false, "GE"),
		  gt: compileBoundsSearch(">", false, "GT"),
		  lt: compileBoundsSearch("<", true, "LT"),
		  le: compileBoundsSearch("<=", true, "LE"),
		  eq: compileBoundsSearch("-", true, "EQ", true)
			};
	
	/***/ }),
	/* 97 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		module.exports = trimLeaves;
	
		var e2a = __webpack_require__(84);
	
		function trimLeaves(edges, positions) {
		  var adj = e2a(edges, positions.length);
		  var live = new Array(positions.length);
		  var nbhd = new Array(positions.length);
	
		  var dead = [];
		  for (var i = 0; i < positions.length; ++i) {
		    var count = adj[i].length;
		    nbhd[i] = count;
		    live[i] = true;
		    if (count <= 1) {
		      dead.push(i);
		    }
		  }
	
		  while (dead.length > 0) {
		    var v = dead.pop();
		    live[v] = false;
		    var n = adj[v];
		    for (var i = 0; i < n.length; ++i) {
		      var u = n[i];
		      if (--nbhd[u] === 0) {
		        dead.push(u);
		      }
		    }
		  }
	
		  var newIndex = new Array(positions.length);
		  var npositions = [];
		  for (var i = 0; i < positions.length; ++i) {
		    if (live[i]) {
		      var v = npositions.length;
		      newIndex[i] = v;
		      npositions.push(positions[i]);
		    } else {
		      newIndex[i] = -1;
		    }
		  }
	
		  var nedges = [];
		  for (var i = 0; i < edges.length; ++i) {
		    var e = edges[i];
		    if (live[e[0]] && live[e[1]]) {
		      nedges.push([newIndex[e[0]], newIndex[e[1]]]);
		    }
		  }
	
		  return [nedges, npositions];
		}
	
	/***/ }),
	/* 98 */
	/***/ (function(module, exports, __webpack_require__) {
	
		const vectorizeText = __webpack_require__(5);
	
		module.exports = function calc_col_text_triangles(params) {
	
		  var inst_nodes = params.network.col_nodes;
		  var num_col = params.num_col;
	
		  var vect_text_attrs = {
		    textAlign: 'left',
		    textBaseline: 'middle',
		    triangles: true,
		    size: params.font_detail,
		    font: '"Open Sans", verdana, arial, sans-serif'
		  };
	
		  // draw matrix cells
		  /////////////////////////////////////////
	
		  var x_arr = params.canvas_pos.x_arr;
	
		  // generating array with col text triangles and y-offsets
		  var col_text_triangles = [];
	
		  var inst_order = 'clust';
	
		  var viz_area = params.viz_area;
		  var kept_col_x = [];
	
		  _.each(inst_nodes, function (inst_node, col_id) {
	
		    var col_order_id = params.network.col_nodes[col_id][inst_order];
	
		    var inst_x = x_arr[num_col - 1 - col_order_id] + 0.5 / num_col;
	
		    if (inst_x > viz_area.x_min && inst_x < viz_area.x_max) {
		      var inst_name = inst_node.name;
	
		      if (inst_name.indexOf(': ') >= 0) {
		        inst_name = inst_node.name.split(': ')[1];
		      }
	
		      var tmp_text_vect = vectorizeText(inst_name, vect_text_attrs);
	
		      tmp_text_vect.offset = [0, inst_x];
		      col_text_triangles.push(tmp_text_vect);
	
		      var inst_data = {};
		      inst_data.y = inst_x;
		      inst_data.name = inst_name;
		      kept_col_x.push(inst_data);
		    }
	
		    // var inst_name = inst_node.name.split(': ')[1];
		    // var tmp_text_vect = vectorizeText(inst_name, vect_text_attrs);
		    // var col_order_id = params.network.col_nodes[col_id][inst_order];
	
		    // var inst_x = x_arr[ col_order_id ];
		    // tmp_text_vect.offset = [ 0, inst_x];
	
		    // col_text_triangles.push(tmp_text_vect);
		  });
	
		  params.kept_col_x = kept_col_x;
	
		  return col_text_triangles;
			};
	
	/***/ }),
	/* 99 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var extend = __webpack_require__(100);
	
		module.exports = function calc_viz_dim(regl) {
	
		  // Set up viz_dim
		  ///////////////////////
		  var opts = opts || {};
		  var options = extend({
		    element: opts.element || regl._gl.canvas
		  }, opts || {});
	
		  var element = options.element;
	
		  var viz_dim = {};
		  viz_dim.canvas = {};
		  viz_dim.mat = {};
	
		  _.each(['width', 'height'], function (inst_dim) {
		    viz_dim.canvas[inst_dim] = Number.parseFloat(d3.select(element).style(inst_dim).replace('px', ''));
		  });
	
		  // square matrix size set by width of canvas
		  viz_dim.mat.width = viz_dim.canvas.width / 2;
		  viz_dim.mat.height = viz_dim.canvas.width / 2;
	
		  // min and max position of matrix
		  viz_dim.mat.x = {};
		  viz_dim.mat.x.min = viz_dim.canvas.width / 2 - viz_dim.mat.width / 2;
		  viz_dim.mat.x.max = viz_dim.canvas.width / 2 + viz_dim.mat.width / 2;
	
		  viz_dim.mat.y = {};
		  viz_dim.mat.y.min = viz_dim.canvas.height / 2 - viz_dim.mat.height / 2;
		  viz_dim.mat.y.max = viz_dim.canvas.height / 2 + viz_dim.mat.height / 2;
	
		  return viz_dim;
			};
	
	/***/ }),
	/* 100 */
	/***/ (function(module, exports) {
	
		module.exports = extend;
	
		var hasOwnProperty = Object.prototype.hasOwnProperty;
	
		function extend(target) {
		    for (var i = 1; i < arguments.length; i++) {
		        var source = arguments[i];
	
		        for (var key in source) {
		            if (hasOwnProperty.call(source, key)) {
		                target[key] = source[key];
		            }
		        }
		    }
	
		    return target;
		}
	
	/***/ }),
	/* 101 */
	/***/ (function(module, exports) {
	
		module.exports = function ini_zoom_data() {
	
		  // organize zoom rules into x and y components
		  var zoom_data = {};
		  _.each(['x', 'y'], function (inst_dim) {
		    var inst_data = {};
		    // total zooming (formerly tsx)
		    inst_data.total_zoom = 1;
		    // position of cursor (formerly x0)
		    inst_data.cursor_position = 0;
		    // total panning relative to the min
		    inst_data.total_pan_min = 0;
		    // total panning relative to the max
		    inst_data.total_pan_max = 0;
		    // pan_room (allowed negative panning)
		    inst_data.pan_room = 0;
		    // pan_by_zoom (formerly zdx)
		    inst_data.pan_by_zoom = 0;
		    inst_data.pan_by_drag = 0;
		    inst_data.inst_zoom = 1;
	
		    // zoom at which previous filtering was done (ini at 1)
		    inst_data.filter_zoom = 1;
	
		    // keep track of previous restrictions
		    inst_data.prev_restrict = false;
	
		    // delay viz area calculations until sufficient zooming has
		    // occurred
		    inst_data.zoom_step = 10;
		    inst_data.show_text = false;
	
		    // keep track of when zooming stops
		    inst_data.still_zooming = false;
	
		    inst_data.total_int = 0;
	
		    // add to zoom_data
		    zoom_data[inst_dim] = inst_data;
		  });
	
		  return zoom_data;
			};
	
	/***/ }),
	/* 102 */
	/***/ (function(module, exports) {
	
		module.exports = function ini_zoom_restrict(params) {
	
		  var num_row = params.num_row;
		  var num_col = params.num_col;
	
		  // working on improved matrix zooming
		  var max_zoom = 20;
		  var zoom_restrict = {};
		  zoom_restrict.x = {};
		  zoom_restrict.x.max = max_zoom;
		  zoom_restrict.x.min = 1.0;
		  zoom_restrict.x.ratio = 1;
	
		  zoom_restrict.y = {};
		  zoom_restrict.y.max = max_zoom;
		  zoom_restrict.y.min = 1.0;
		  zoom_restrict.y.ratio = 1;
	
		  // increase max zoom in y or x direction
		  if (num_row > num_col) {
		    zoom_restrict.y.max = zoom_restrict.y.max * (num_row / num_col);
		    zoom_restrict.y.ratio = num_row / num_col;
		  } else if (num_col < num_row) {
		    zoom_restrict.x.max = zoom_restrict.x.max * (num_col / num_row);
		    zoom_restrict.x.ratio = num_col / num_row;
		  }
	
		  return zoom_restrict;
			};
	
	/***/ }),
	/* 103 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var interactionEvents = __webpack_require__(104);
		var extend = __webpack_require__(100);
		var zoom_rules_low_mat = __webpack_require__(126);
		var keep_track_of_interactions = __webpack_require__(127);
	
		module.exports = function zoom_rules_high_mat(regl, params) {
	
		  var zoom_data = params.zoom_data;
		  var zoom_restrict = params.zoom_restrict;
		  var viz_dim = params.viz_dim;
	
		  var opts = opts || {};
		  var options = extend({
		    element: opts.element || regl._gl.canvas
		  }, opts || {});
	
		  var element = options.element;
	
		  var interaction_types = ['wheel', 'touch', 'pinch'];
	
		  interactionEvents({
		    element: element
		  }).on('interaction', function (ev) {
		    if (ev.buttons || interaction_types.indexOf(ev.type) !== -1) {
	
		      switch (ev.type) {
		        case 'wheel':
		          ev.dsx = ev.dsy = Math.exp(-ev.dy / 100);
		          ev.dx = ev.dy = 0;
		          break;
		      }
	
		      // transfer data from ev to zoom_data
		      // zoom_data.x.inst_zoom = 1;
		      zoom_data.x.inst_zoom = ev.dsx;
	
		      // zoom_data.x.pan_by_drag = 0;
		      zoom_data.x.pan_by_drag = ev.dx;
	
		      zoom_data.x.cursor_position = ev.x0;
	
		      // disable y zooming and panning
		      ///////////////////////////////////
	
		      // zoom_data.y.inst_zoom = 1;
		      zoom_data.y.inst_zoom = ev.dsy;
	
		      // zoom_data.y.pan_by_drag = 0;
		      zoom_data.y.pan_by_drag = ev.dy;
	
		      zoom_data.y.cursor_position = ev.y0;
	
		      /*
		      Zoom Switch only working for tall matrices not wide matrices
		      */
	
		      // set up two-stage zooming
		      if (zoom_data.y.total_zoom < zoom_restrict.y.ratio) {
	
		        zoom_data.x.inst_zoom = 1;
	
		        // console.log(zoom_data.y.inst_zoom)
		        var potential_zoom = zoom_data.y.total_zoom * zoom_data.y.inst_zoom;
	
		        // check potential_zoom
		        if (potential_zoom > zoom_restrict.y.ratio) {
	
		          // bump x inst_zoom
		          zoom_data.x.inst_zoom = potential_zoom / zoom_restrict.y.ratio;
		        }
		      }
	
		      zoom_data.x = zoom_rules_low_mat(zoom_restrict.x, zoom_data.x, viz_dim.mat.x, 'x');
	
		      zoom_data.y = zoom_rules_low_mat(zoom_restrict.y, zoom_data.y, viz_dim.mat.y, 'y');
	
		      keep_track_of_interactions(params);
		    }
		  });
			};
	
	/***/ }),
	/* 104 */
	/***/ (function(module, exports, __webpack_require__) {
	
		// 'use strict';
	
		module.exports = interactionEvents;
	
		var extend = __webpack_require__(105);
		var mouse = __webpack_require__(106);
		var mouseChange = __webpack_require__(107);
		var eventOffset = __webpack_require__(108);
		var eventEmitter = __webpack_require__(109);
	
		function Finger() {
		  this.position = [0, 0];
		  this.touch = null;
		}
	
		// can pass in callback as second argument
		function interactionEvents(opts) {
		  var options = extend({
		    element: window,
		    constrainZoom: false
		  }, opts || {});
	
		  var emitter = eventEmitter({});
	
		  var element = options.element;
		  var enabled = false;
		  // var mouseDown = false;
		  // var wheelSpeed = 0.01;
		  var pPos = [null, null];
		  var fingers = [null, null];
		  var ended = false;
		  var activeCount = 0;
		  var xprev;
		  var yprev;
	
		  var ev = {};
	
		  var buttons = 0;
		  var mods = {};
		  var changeListener = mouseChange(element, function (pbuttons, px, py, pmods) {
		    buttons = pbuttons;
		    mods = pmods;
		  });
	
		  function forward(evOut, evIn) {
		    evOut.preventDefault = evIn.preventDefault.bind(evIn);
		    evOut.stopPropagation = evIn.stopPropagation.bind(evIn);
		    return evOut;
		  }
	
		  function onWheel(event) {
		    // var dx, dy, dz, x0, y0;
	
		    ev.type = 'wheel';
		    ev.buttons = buttons;
		    ev.mods = mods;
		    ev.x0 = event.x;
		    ev.y0 = event.y;
		    ev.dx = event.deltaX;
		    ev.dy = event.deltaY;
		    ev.dz = event.deltaZ;
		    ev.dsx = 1;
		    ev.dsy = 1;
		    ev.dsz = 1;
		    ev.theta = 0;
		    ev.dtheta = 0;
	
		    emitter.emit('interaction', forward(ev, event));
		  }
	
		  function onMouseDown(event) {
		    xprev = mouse.x(event);
		    yprev = mouse.y(event);
	
		    ev.type = 'mousedown';
		    ev.buttons = buttons;
		    ev.mods = mods;
		    ev.x0 = xprev;
		    ev.y0 = yprev;
		    ev.dx = 0;
		    ev.dy = 0;
		    ev.dz = 0;
		    ev.dsx = 1;
		    ev.dsy = 1;
		    ev.dsz = 1;
		    ev.theta = 0;
		    ev.dtheta = 0;
	
		    emitter.emit('interactionend', forward(ev, event));
		  }
	
		  function onMouseMove(event) {
		    var x = mouse.x(event);
		    var y = mouse.y(event);
	
		    ev.type = 'mousemove';
		    ev.buttons = buttons;
		    ev.mods = mods;
		    ev.x0 = x;
		    ev.y0 = y;
		    ev.dx = x - xprev;
		    ev.dy = y - yprev;
		    ev.dz = 0;
		    ev.dsx = 1;
		    ev.dsy = 1;
		    ev.dsz = 1;
		    ev.theta = 0;
		    ev.dtheta = 0;
	
		    xprev = x;
		    yprev = y;
	
		    emitter.emit('interaction', forward(ev, event));
		  }
	
		  function indexOfTouch(touch) {
		    var id = touch.identifier;
		    for (var i = 0; i < fingers.length; i++) {
		      if (fingers[i] && fingers[i].touch && fingers[i].touch.identifier === id) {
		        return i;
		      }
		    }
		    return -1;
		  }
	
		  function onTouchStart(event) {
		    pPos = [null, null];
		    for (var i = 0; i < event.changedTouches.length; i++) {
		      var newTouch = event.changedTouches[i];
		      var id = newTouch.identifier;
		      var idx = indexOfTouch(id);
	
		      if (idx === -1 && activeCount < 2) {
		        var first = activeCount === 0;
	
		        // newest and previous finger (previous may be undefined)
		        var newIndex = fingers[0] ? 1 : 0;
		        // var oldIndex = fingers[0] ? 0 : 1;
		        var newFinger = new Finger();
	
		        // add to stack
		        fingers[newIndex] = newFinger;
	
		        // activeCount++
		        activeCount = activeCount + 1;
	
		        // update touch event & position
		        newFinger.touch = newTouch;
		        eventOffset(newTouch, element, newFinger.position);
	
		        // var oldTouch = fingers[oldIndex] ? fingers[oldIndex].touch : undefined;
	
		        if (!first) {
		          ended = false;
		        }
		      }
		    }
	
		    if (activeCount > 0) {
		      ev.type = activeCount === 1 ? 'touchstart' : 'pinchstart';
		      ev.buttons = 0;
		      ev.mods = {};
		      ev.x0 = 0;
		      ev.y0 = 0;
		      ev.dx = 0;
		      ev.dy = 0;
		      ev.dz = 0;
		      ev.dsx = 1;
		      ev.dsy = 1;
		      ev.dsz = 1;
		      ev.theta = 0;
		      ev.dtheta = 0;
	
		      emitter.emit('interactionstart', forward(ev, event));
		    }
		  }
	
		  // var px0 = null;
		  // var py0 = null;
	
		  function onTouchMove(event) {
		    var idx;
		    var changed = false;
		    for (var i = 0; i < event.changedTouches.length; i++) {
		      var movedTouch = event.changedTouches[i];
		      idx = indexOfTouch(movedTouch);
		      if (idx !== -1) {
		        changed = true;
		        fingers[idx].touch = movedTouch; // avoid caching touches
		        eventOffset(movedTouch, element, fingers[idx].position);
		      }
		    }
	
		    if (changed) {
		      if (activeCount === 1) {
		        for (idx = 0; idx < fingers.length; idx++) {
		          if (fingers[idx]) {
		            break;
		          }
		        }
	
		        if (fingers[idx] && pPos[idx]) {
		          var x = fingers[idx].position[0];
		          var y = fingers[idx].position[1];
	
		          var dx = x - pPos[idx][0];
		          var dy = y - pPos[idx][1];
	
		          ev.type = 'touch';
		          ev.buttons = 0;
		          ev.mods = {};
		          ev.x0 = x;
		          ev.y0 = y;
		          ev.dx = dx;
		          ev.dy = dy;
		          ev.dz = 0;
		          ev.dsx = 1;
		          ev.dsy = 1;
		          ev.dsz = 1;
		          ev.theta = 0;
		          ev.dtheta = 0;
	
		          emitter.emit('interaction', forward(ev, event));
		        }
		      } else if (activeCount === 2) {
		        if (pPos[0] && pPos[1]) {
		          // Previous two-finger vector:
		          var pos0A = pPos[0];
		          var pos0B = pPos[1];
		          var dx0 = pos0B[0] - pos0A[0];
		          var dy0 = pos0B[1] - pos0A[1];
	
		          // Current two-finger vector:
		          var pos1A = fingers[0].position;
		          var pos1B = fingers[1].position;
		          var dx1 = pos1B[0] - pos1A[0];
		          var dy1 = pos1B[1] - pos1A[1];
	
		          // r, theta for the previous two-finger touch:
		          var r0 = Math.sqrt(dx0 * dx0 + dy0 * dy0);
		          var theta0 = Math.atan2(dy0, dx0);
	
		          // r, theta for the current two-finger touch:
		          var r1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
		          var theta1 = Math.atan2(dy1, dx1);
	
		          var x0 = (pos0B[0] + pos0A[0]) * 0.5;
		          var y0 = (pos0B[1] + pos0A[1]) * 0.5;
		          dx = 0.5 * (pos1B[0] + pos1A[0] - pos0A[0] - pos0B[0]);
		          dy = 0.5 * (pos1B[1] + pos1A[1] - pos0A[1] - pos0B[1]);
		          var dr = r1 / r0;
		          var dtheta = theta1 - theta0;
	
		          ev.type = 'pinch';
		          ev.buttons = 0;
		          ev.mods = {};
		          ev.x0 = x0;
		          ev.y0 = y0;
		          ev.dx = dx;
		          ev.dy = dy;
		          ev.dz = 0;
		          ev.dsx = dr;
		          ev.dsy = dr;
		          ev.dsz = 1;
		          ev.theta = theta1;
		          ev.dtheta = dtheta;
	
		          emitter.emit('interaction', forward(ev, event));
	
		          // var px0 = x0;
		          // var py0 = y0;
		        }
		      }
		    }
	
		    if (fingers[0]) {
		      pPos[0] = fingers[0].position.slice();
		    }
	
		    if (fingers[1]) {
		      pPos[1] = fingers[1].position.slice();
		    }
		  }
	
		  function onTouchRemoved(event) {
		    for (var i = 0; i < event.changedTouches.length; i++) {
		      var removed = event.changedTouches[i];
		      var idx = indexOfTouch(removed);
	
		      if (idx !== -1) {
		        fingers[idx] = null;
	
		        // activeCount--
		        activeCount = activeCount - 1;
	
		        // var otherIdx = idx === 0 ? 1 : 0;
		        // var otherTouch = fingers[otherIdx] ? fingers[otherIdx].touch : undefined;
		      }
		    }
	
		    if (!ended && activeCount !== 2) {
		      ended = true;
		    }
	
		    if (activeCount < 2) {
		      ev.type = activeCount === 0 ? 'touchend' : 'pinchend';
		      ev.buttons = 0;
		      ev.mods = {};
		      ev.x0 = 0;
		      ev.y0 = 0;
		      ev.dx = 0;
		      ev.dy = 0;
		      ev.dz = 0;
		      ev.dsx = 1;
		      ev.dsy = 1;
		      ev.dsz = 1;
		      ev.theta = 0;
		      ev.dtheta = 0;
	
		      emitter.emit('interactionend', forward(ev, event));
		    }
		  }
	
		  function enable() {
		    if (enabled) {
		      return;
		    }
		    enabled = true;
		    changeListener.enabled = true;
		    element.addEventListener('wheel', onWheel, false);
		    element.addEventListener('mousedown', onMouseDown, false);
		    element.addEventListener('mousemove', onMouseMove, false);
	
		    element.addEventListener('touchstart', onTouchStart, false);
		    element.addEventListener('touchmove', onTouchMove, false);
		    element.addEventListener('touchend', onTouchRemoved, false);
		    element.addEventListener('touchcancel', onTouchRemoved, false);
		  }
	
		  function disable() {
		    if (!enabled) {
		      return;
		    }
		    enabled = false;
		    changeListener.enabled = false;
		    element.removeEventListener('wheel', onWheel, false);
		    element.removeEventListener('mousedown', onMouseDown, false);
		    element.removeEventListener('mousemove', onMouseMove, false);
	
		    element.removeEventListener('touchstart', onTouchStart, false);
		    element.removeEventListener('touchmove', onTouchMove, false);
		    element.removeEventListener('touchend', onTouchRemoved, false);
		    element.removeEventListener('touchcancel', onTouchRemoved, false);
		  }
	
		  enable();
	
		  emitter.enable = enable;
		  emitter.disable = disable;
	
		  return emitter;
		}
	
	/***/ }),
	/* 105 */
	/***/ (function(module, exports) {
	
		// Copyright Joyent, Inc. and other Node contributors.
		//
		// Permission is hereby granted, free of charge, to any person obtaining a
		// copy of this software and associated documentation files (the
		// "Software"), to deal in the Software without restriction, including
		// without limitation the rights to use, copy, modify, merge, publish,
		// distribute, sublicense, and/or sell copies of the Software, and to permit
		// persons to whom the Software is furnished to do so, subject to the
		// following conditions:
		//
		// The above copyright notice and this permission notice shall be included
		// in all copies or substantial portions of the Software.
		//
		// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
		// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
		// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
		// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
		// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
		// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
		// USE OR OTHER DEALINGS IN THE SOFTWARE.
	
		module.exports = extend;
		function extend(origin, add) {
		  // Don't do anything if add isn't an object
		  if (!add || typeof add !== 'object') return origin;
	
		  var keys = Object.keys(add);
		  var i = keys.length;
		  while (i--) {
		    origin[keys[i]] = add[keys[i]];
		  }
		  return origin;
		}
	
	/***/ }),
	/* 106 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		function mouseButtons(ev) {
		  if (typeof ev === 'object') {
		    if ('buttons' in ev) {
		      return ev.buttons;
		    } else if ('which' in ev) {
		      var b = ev.which;
		      if (b === 2) {
		        return 4;
		      } else if (b === 3) {
		        return 2;
		      } else if (b > 0) {
		        return 1 << b - 1;
		      }
		    } else if ('button' in ev) {
		      var b = ev.button;
		      if (b === 1) {
		        return 4;
		      } else if (b === 2) {
		        return 2;
		      } else if (b >= 0) {
		        return 1 << b;
		      }
		    }
		  }
		  return 0;
		}
		exports.buttons = mouseButtons;
	
		function mouseElement(ev) {
		  return ev.target || ev.srcElement || window;
		}
		exports.element = mouseElement;
	
		function mouseRelativeX(ev) {
		  if (typeof ev === 'object') {
		    if ('offsetX' in ev) {
		      return ev.offsetX;
		    }
		    var target = mouseElement(ev);
		    var bounds = target.getBoundingClientRect();
		    return ev.clientX - bounds.left;
		  }
		  return 0;
		}
		exports.x = mouseRelativeX;
	
		function mouseRelativeY(ev) {
		  if (typeof ev === 'object') {
		    if ('offsetY' in ev) {
		      return ev.offsetY;
		    }
		    var target = mouseElement(ev);
		    var bounds = target.getBoundingClientRect();
		    return ev.clientY - bounds.top;
		  }
		  return 0;
		}
		exports.y = mouseRelativeY;
	
	/***/ }),
	/* 107 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		module.exports = mouseListen;
	
		var mouse = __webpack_require__(106);
	
		function mouseListen(element, callback) {
		  if (!callback) {
		    callback = element;
		    element = window;
		  }
	
		  var buttonState = 0;
		  var x = 0;
		  var y = 0;
		  var mods = {
		    shift: false,
		    alt: false,
		    control: false,
		    meta: false
		  };
		  var attached = false;
	
		  function updateMods(ev) {
		    var changed = false;
		    if ('altKey' in ev) {
		      changed = changed || ev.altKey !== mods.alt;
		      mods.alt = !!ev.altKey;
		    }
		    if ('shiftKey' in ev) {
		      changed = changed || ev.shiftKey !== mods.shift;
		      mods.shift = !!ev.shiftKey;
		    }
		    if ('ctrlKey' in ev) {
		      changed = changed || ev.ctrlKey !== mods.control;
		      mods.control = !!ev.ctrlKey;
		    }
		    if ('metaKey' in ev) {
		      changed = changed || ev.metaKey !== mods.meta;
		      mods.meta = !!ev.metaKey;
		    }
		    return changed;
		  }
	
		  function handleEvent(nextButtons, ev) {
		    var nextX = mouse.x(ev);
		    var nextY = mouse.y(ev);
		    if ('buttons' in ev) {
		      nextButtons = ev.buttons | 0;
		    }
		    if (nextButtons !== buttonState || nextX !== x || nextY !== y || updateMods(ev)) {
		      buttonState = nextButtons | 0;
		      x = nextX || 0;
		      y = nextY || 0;
		      callback && callback(buttonState, x, y, mods);
		    }
		  }
	
		  function clearState(ev) {
		    handleEvent(0, ev);
		  }
	
		  function handleBlur() {
		    if (buttonState || x || y || mods.shift || mods.alt || mods.meta || mods.control) {
		      x = y = 0;
		      buttonState = 0;
		      mods.shift = mods.alt = mods.control = mods.meta = false;
		      callback && callback(0, 0, 0, mods);
		    }
		  }
	
		  function handleMods(ev) {
		    if (updateMods(ev)) {
		      callback && callback(buttonState, x, y, mods);
		    }
		  }
	
		  function handleMouseMove(ev) {
		    if (mouse.buttons(ev) === 0) {
		      handleEvent(0, ev);
		    } else {
		      handleEvent(buttonState, ev);
		    }
		  }
	
		  function handleMouseDown(ev) {
		    handleEvent(buttonState | mouse.buttons(ev), ev);
		  }
	
		  function handleMouseUp(ev) {
		    handleEvent(buttonState & ~mouse.buttons(ev), ev);
		  }
	
		  function attachListeners() {
		    if (attached) {
		      return;
		    }
		    attached = true;
	
		    element.addEventListener('mousemove', handleMouseMove);
	
		    element.addEventListener('mousedown', handleMouseDown);
	
		    element.addEventListener('mouseup', handleMouseUp);
	
		    element.addEventListener('mouseleave', clearState);
		    element.addEventListener('mouseenter', clearState);
		    element.addEventListener('mouseout', clearState);
		    element.addEventListener('mouseover', clearState);
	
		    element.addEventListener('blur', handleBlur);
	
		    element.addEventListener('keyup', handleMods);
		    element.addEventListener('keydown', handleMods);
		    element.addEventListener('keypress', handleMods);
	
		    if (element !== window) {
		      window.addEventListener('blur', handleBlur);
	
		      window.addEventListener('keyup', handleMods);
		      window.addEventListener('keydown', handleMods);
		      window.addEventListener('keypress', handleMods);
		    }
		  }
	
		  function detachListeners() {
		    if (!attached) {
		      return;
		    }
		    attached = false;
	
		    element.removeEventListener('mousemove', handleMouseMove);
	
		    element.removeEventListener('mousedown', handleMouseDown);
	
		    element.removeEventListener('mouseup', handleMouseUp);
	
		    element.removeEventListener('mouseleave', clearState);
		    element.removeEventListener('mouseenter', clearState);
		    element.removeEventListener('mouseout', clearState);
		    element.removeEventListener('mouseover', clearState);
	
		    element.removeEventListener('blur', handleBlur);
	
		    element.removeEventListener('keyup', handleMods);
		    element.removeEventListener('keydown', handleMods);
		    element.removeEventListener('keypress', handleMods);
	
		    if (element !== window) {
		      window.removeEventListener('blur', handleBlur);
	
		      window.removeEventListener('keyup', handleMods);
		      window.removeEventListener('keydown', handleMods);
		      window.removeEventListener('keypress', handleMods);
		    }
		  }
	
		  // Attach listeners
		  attachListeners();
	
		  var result = {
		    element: element
		  };
	
		  Object.defineProperties(result, {
		    enabled: {
		      get: function () {
		        return attached;
		      },
		      set: function (f) {
		        if (f) {
		          attachListeners();
		        } else {
		          detachListeners();
		        }
		      },
		      enumerable: true
		    },
		    buttons: {
		      get: function () {
		        return buttonState;
		      },
		      enumerable: true
		    },
		    x: {
		      get: function () {
		        return x;
		      },
		      enumerable: true
		    },
		    y: {
		      get: function () {
		        return y;
		      },
		      enumerable: true
		    },
		    mods: {
		      get: function () {
		        return mods;
		      },
		      enumerable: true
		    }
		  });
	
		  return result;
		}
	
	/***/ }),
	/* 108 */
	/***/ (function(module, exports) {
	
		var rootPosition = { left: 0, top: 0 };
	
		module.exports = mouseEventOffset;
		function mouseEventOffset(ev, target, out) {
		  target = target || ev.currentTarget || ev.srcElement;
		  if (!Array.isArray(out)) {
		    out = [0, 0];
		  }
		  var cx = ev.clientX || 0;
		  var cy = ev.clientY || 0;
		  var rect = getBoundingClientOffset(target);
		  out[0] = cx - rect.left;
		  out[1] = cy - rect.top;
		  return out;
		}
	
		function getBoundingClientOffset(element) {
		  if (element === window || element === document || element === document.body) {
		    return rootPosition;
		  } else {
		    return element.getBoundingClientRect();
		  }
		}
	
	/***/ }),
	/* 109 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var d = __webpack_require__(110),
		    callable = __webpack_require__(125),
		    apply = Function.prototype.apply,
		    call = Function.prototype.call,
		    create = Object.create,
		    defineProperty = Object.defineProperty,
		    defineProperties = Object.defineProperties,
		    hasOwnProperty = Object.prototype.hasOwnProperty,
		    descriptor = { configurable: true, enumerable: false, writable: true },
		    on,
		    once,
		    off,
		    emit,
		    methods,
		    descriptors,
		    base;
	
		on = function (type, listener) {
			var data;
	
			callable(listener);
	
			if (!hasOwnProperty.call(this, '__ee__')) {
				data = descriptor.value = create(null);
				defineProperty(this, '__ee__', descriptor);
				descriptor.value = null;
			} else {
				data = this.__ee__;
			}
			if (!data[type]) data[type] = listener;else if (typeof data[type] === 'object') data[type].push(listener);else data[type] = [data[type], listener];
	
			return this;
		};
	
		once = function (type, listener) {
			var once, self;
	
			callable(listener);
			self = this;
			on.call(this, type, once = function () {
				off.call(self, type, once);
				apply.call(listener, this, arguments);
			});
	
			once.__eeOnceListener__ = listener;
			return this;
		};
	
		off = function (type, listener) {
			var data, listeners, candidate, i;
	
			callable(listener);
	
			if (!hasOwnProperty.call(this, '__ee__')) return this;
			data = this.__ee__;
			if (!data[type]) return this;
			listeners = data[type];
	
			if (typeof listeners === 'object') {
				for (i = 0; candidate = listeners[i]; ++i) {
					if (candidate === listener || candidate.__eeOnceListener__ === listener) {
						if (listeners.length === 2) data[type] = listeners[i ? 0 : 1];else listeners.splice(i, 1);
					}
				}
			} else {
				if (listeners === listener || listeners.__eeOnceListener__ === listener) {
					delete data[type];
				}
			}
	
			return this;
		};
	
		emit = function (type) {
			var i, l, listener, listeners, args;
	
			if (!hasOwnProperty.call(this, '__ee__')) return;
			listeners = this.__ee__[type];
			if (!listeners) return;
	
			if (typeof listeners === 'object') {
				l = arguments.length;
				args = new Array(l - 1);
				for (i = 1; i < l; ++i) args[i - 1] = arguments[i];
	
				listeners = listeners.slice();
				for (i = 0; listener = listeners[i]; ++i) {
					apply.call(listener, this, args);
				}
			} else {
				switch (arguments.length) {
					case 1:
						call.call(listeners, this);
						break;
					case 2:
						call.call(listeners, this, arguments[1]);
						break;
					case 3:
						call.call(listeners, this, arguments[1], arguments[2]);
						break;
					default:
						l = arguments.length;
						args = new Array(l - 1);
						for (i = 1; i < l; ++i) {
							args[i - 1] = arguments[i];
						}
						apply.call(listeners, this, args);
				}
			}
		};
	
		methods = {
			on: on,
			once: once,
			off: off,
			emit: emit
		};
	
		descriptors = {
			on: d(on),
			once: d(once),
			off: d(off),
			emit: d(emit)
		};
	
		base = defineProperties({}, descriptors);
	
		module.exports = exports = function (o) {
			return o == null ? create(base) : defineProperties(Object(o), descriptors);
		};
		exports.methods = methods;
	
	/***/ }),
	/* 110 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var assign = __webpack_require__(111),
		    normalizeOpts = __webpack_require__(120),
		    isCallable = __webpack_require__(121),
		    contains = __webpack_require__(122),
		    d;
	
		d = module.exports = function (dscr, value /*, options*/) {
			var c, e, w, options, desc;
			if (arguments.length < 2 || typeof dscr !== 'string') {
				options = value;
				value = dscr;
				dscr = null;
			} else {
				options = arguments[2];
			}
			if (dscr == null) {
				c = w = true;
				e = false;
			} else {
				c = contains.call(dscr, 'c');
				e = contains.call(dscr, 'e');
				w = contains.call(dscr, 'w');
			}
	
			desc = { value: value, configurable: c, enumerable: e, writable: w };
			return !options ? desc : assign(normalizeOpts(options), desc);
		};
	
		d.gs = function (dscr, get, set /*, options*/) {
			var c, e, options, desc;
			if (typeof dscr !== 'string') {
				options = set;
				set = get;
				get = dscr;
				dscr = null;
			} else {
				options = arguments[3];
			}
			if (get == null) {
				get = undefined;
			} else if (!isCallable(get)) {
				options = get;
				get = set = undefined;
			} else if (set == null) {
				set = undefined;
			} else if (!isCallable(set)) {
				options = set;
				set = undefined;
			}
			if (dscr == null) {
				c = true;
				e = false;
			} else {
				c = contains.call(dscr, 'c');
				e = contains.call(dscr, 'e');
			}
	
			desc = { get: get, set: set, configurable: c, enumerable: e };
			return !options ? desc : assign(normalizeOpts(options), desc);
		};
	
	/***/ }),
	/* 111 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = __webpack_require__(112)() ? Object.assign : __webpack_require__(113);
	
	/***/ }),
	/* 112 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function () {
			var assign = Object.assign,
			    obj;
			if (typeof assign !== "function") return false;
			obj = { foo: "raz" };
			assign(obj, { bar: "dwa" }, { trzy: "trzy" });
			return obj.foo + obj.bar + obj.trzy === "razdwatrzy";
		};
	
	/***/ }),
	/* 113 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var keys = __webpack_require__(114),
		    value = __webpack_require__(119),
		    max = Math.max;
	
		module.exports = function (dest, src /*, …srcn*/) {
			var error,
			    i,
			    length = max(arguments.length, 2),
			    assign;
			dest = Object(value(dest));
			assign = function (key) {
				try {
					dest[key] = src[key];
				} catch (e) {
					if (!error) error = e;
				}
			};
			for (i = 1; i < length; ++i) {
				src = arguments[i];
				keys(src).forEach(assign);
			}
			if (error !== undefined) throw error;
			return dest;
		};
	
	/***/ }),
	/* 114 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = __webpack_require__(115)() ? Object.keys : __webpack_require__(116);
	
	/***/ }),
	/* 115 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function () {
			try {
				Object.keys("primitive");
				return true;
			} catch (e) {
				return false;
			}
		};
	
	/***/ }),
	/* 116 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var isValue = __webpack_require__(117);
	
		var keys = Object.keys;
	
		module.exports = function (object) {
			return keys(isValue(object) ? Object(object) : object);
		};
	
	/***/ }),
	/* 117 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var _undefined = __webpack_require__(118)(); // Support ES3 engines
	
		module.exports = function (val) {
		  return val !== _undefined && val !== null;
		};
	
	/***/ }),
	/* 118 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		// eslint-disable-next-line no-empty-function
	
			module.exports = function () {};
	
	/***/ }),
	/* 119 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var isValue = __webpack_require__(117);
	
		module.exports = function (value) {
			if (!isValue(value)) throw new TypeError("Cannot use null or undefined");
			return value;
		};
	
	/***/ }),
	/* 120 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		var isValue = __webpack_require__(117);
	
		var forEach = Array.prototype.forEach,
		    create = Object.create;
	
		var process = function (src, obj) {
			var key;
			for (key in src) obj[key] = src[key];
		};
	
		// eslint-disable-next-line no-unused-vars
		module.exports = function (opts1 /*, …options*/) {
			var result = create(null);
			forEach.call(arguments, function (options) {
				if (!isValue(options)) return;
				process(Object(options), result);
			});
			return result;
		};
	
	/***/ }),
	/* 121 */
	/***/ (function(module, exports) {
	
		// Deprecated
	
		"use strict";
	
		module.exports = function (obj) {
		  return typeof obj === "function";
		};
	
	/***/ }),
	/* 122 */
	/***/ (function(module, exports, __webpack_require__) {
	
		"use strict";
	
		module.exports = __webpack_require__(123)() ? String.prototype.contains : __webpack_require__(124);
	
	/***/ }),
	/* 123 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		var str = "razdwatrzy";
	
		module.exports = function () {
			if (typeof str.contains !== "function") return false;
			return str.contains("dwa") === true && str.contains("foo") === false;
		};
	
	/***/ }),
	/* 124 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		var indexOf = String.prototype.indexOf;
	
		module.exports = function (searchString /*, position*/) {
			return indexOf.call(this, searchString, arguments[1]) > -1;
		};
	
	/***/ }),
	/* 125 */
	/***/ (function(module, exports) {
	
		"use strict";
	
		module.exports = function (fn) {
			if (typeof fn !== "function") throw new TypeError(fn + " is not a function");
			return fn;
		};
	
	/***/ }),
	/* 126 */
	/***/ (function(module, exports) {
	
		
		module.exports = function zoom_rules_low_mat(zoom_restrict, zoom_data, viz_dim_mat, axis) {
	
		  // make a copy of zoom_data for later use (not a reference)
		  var zoom_data_copy = _.clone(zoom_data);
	
		  /////////////////////////
		  // Zooming Rules
		  /////////////////////////
	
		  var max_zoom = zoom_restrict.max;
		  var min_zoom = zoom_restrict.min;
	
		  // first sanitize zooming out if already completely zoomed out
		  if (zoom_data.total_zoom == 1 && zoom_data.inst_zoom < 1) {
		    zoom_data.inst_zoom = 1;
		  }
	
		  // calc unsanitized potential_total_zoom
		  // checking this prevents the real total_zoom from going out of bounds
		  var potential_total_zoom = zoom_data.total_zoom * zoom_data.inst_zoom;
	
		  // var zooming_below_one = false;
	
		  // zooming within allowed range
		  if (potential_total_zoom < max_zoom && potential_total_zoom > min_zoom) {
		    zoom_data.total_zoom = potential_total_zoom;
		  }
	
		  // Zoom above max
		  else if (potential_total_zoom >= max_zoom) {
		      if (zoom_data.inst_zoom < 1) {
		        zoom_data.total_zoom = zoom_data.total_zoom * zoom_data.inst_zoom;
		      } else {
		        // bump zoom up to max
		        zoom_data.inst_zoom = max_zoom / zoom_data.total_zoom;
		        // set zoom to max
		        zoom_data.total_zoom = max_zoom;
		      }
		    }
		    // Zoom below min
		    else if (potential_total_zoom <= min_zoom) {
		        if (zoom_data.inst_zoom > 1) {
		          zoom_data.total_zoom = zoom_data.total_zoom * zoom_data.inst_zoom;
		        } else {
		          // declare that this is zooming_below_one
		          // if (zoom_data.total_zoom == 1){
		          // if (axis === 'x'){
		          //   console.log('zooming_below_one')
		          // }
		          // zooming_below_one = false;
		          // }
	
		          // bump zoom down to min
		          zoom_data.inst_zoom = min_zoom / zoom_data.total_zoom;
		          // set zoom to min
		          zoom_data.total_zoom = min_zoom;
		        }
		      }
	
		  //////////////////////////////////
		  // Pan Rules
		  //////////////////////////////////
	
		  // do not allow simultaneous panning and zooming
		  if (zoom_data.inst_zoom > 1) {
		    zoom_data.pan_by_drag = 0;
		  }
	
		  // restrict min pan_by_drag if necessary
		  if (zoom_data.pan_by_drag > 0) {
		    if (zoom_data.total_pan_min + zoom_data.pan_by_drag >= 0) {
		      // push to edge
		      zoom_data.pan_by_drag = -zoom_data.total_pan_min;
		    }
		  }
	
		  // restrict max pan_by_drag if necessary
		  if (zoom_data.pan_by_drag < 0) {
		    if (zoom_data.total_pan_max - zoom_data.pan_by_drag >= 0) {
		      // push to edge
		      zoom_data.pan_by_drag = zoom_data.total_pan_max;
		    }
		  }
	
		  // restrict effective position of mouse
		  if (zoom_data.cursor_position < viz_dim_mat.min) {
		    zoom_data.cursor_position = viz_dim_mat.min;
		  } else if (zoom_data.cursor_position > viz_dim_mat.max) {
		    zoom_data.cursor_position = viz_dim_mat.max;
		  }
	
		  // tracking cursor position relative to the minimum
		  var cursor_relative_min = zoom_data.cursor_position - viz_dim_mat.min;
	
		  // restrict cursor_relative_min
		  if (cursor_relative_min < 0) {
		    cursor_relative_min = 0;
		  } else if (cursor_relative_min > viz_dim_mat.max) {
		    cursor_relative_min = viz_dim_mat.max;
		  }
	
		  // tracking cursor position relative to the maximum
		  var cursor_relative_max = viz_dim_mat.max - zoom_data.cursor_position;
	
		  // restrict cursor_relative_max
		  if (cursor_relative_max < 0) {
		    cursor_relative_max = 0;
		  } else if (cursor_relative_max > viz_dim_mat.max) {
		    cursor_relative_max = viz_dim_mat.max;
		  }
	
		  // pan_by_zoom relative to matrix max and min
		  // zooming in causes negative panning
		  // net positive panning is not allowed
		  var inst_eff_zoom = zoom_data.inst_zoom - 1;
		  zoom_data.pbz_relative_min = -inst_eff_zoom * cursor_relative_min;
		  zoom_data.pbz_relative_max = -inst_eff_zoom * cursor_relative_max;
	
		  // calculate unsanitized versions of total pan values
		  var potential_total_pan_min = zoom_data.total_pan_min + zoom_data.pan_by_drag / zoom_data.total_zoom + zoom_data.pbz_relative_min / zoom_data.total_zoom;
	
		  // panning by drag has the opposite effect relative to the max/right side
		  var potential_total_pan_max = zoom_data.total_pan_max + -zoom_data.pan_by_drag / zoom_data.total_zoom + zoom_data.pbz_relative_max / zoom_data.total_zoom;
	
		  var zero_threshold = 0.0001;
	
		  var fully_zoomed_out = false;
		  if (zoom_data.total_pan_min >= 0 && zoom_data.total_pan_max >= 0) {
		    fully_zoomed_out = true;
		  }
	
		  var double_restrict = false;
		  if (potential_total_pan_min > zero_threshold && potential_total_pan_max > zero_threshold) {
	
		    double_restrict = true;
	
		    // has_been_both = true;
		  }
	
		  // Panning in bounds
		  if (potential_total_pan_min <= zero_threshold && potential_total_pan_max <= zero_threshold) {
	
		    zoom_data.pan_by_zoom = -inst_eff_zoom * zoom_data.cursor_position;
		    zoom_data.total_pan_min = potential_total_pan_min;
		    zoom_data.total_pan_max = potential_total_pan_max;
	
		    zoom_data.prev_restrict = false;
		  }
	
		  if (potential_total_pan_min > zero_threshold) {
	
		    // push over by total_pan (negative value) times total zoom applied
		    // need to push more when matrix has been effectively increased in size
		    // steps: 1) pin to min matrix, and 2) push right (positive) by total remaining pan
		    zoom_data.pan_by_zoom = -inst_eff_zoom * viz_dim_mat.min - zoom_data.total_pan_min * zoom_data.total_zoom;
	
		    // set total_pan_min to 0, no panning room remaining after being pushed right
		    zoom_data.total_pan_min = 0;
	
		    // the cursor is effectively locked on the min (left) side of the matrix
		    var new_cursor_relative_max = viz_dim_mat.max - viz_dim_mat.min;
		    var new_pbz_relative_max = -inst_eff_zoom * new_cursor_relative_max;
		    zoom_data.total_pan_max = zoom_data.total_pan_max + new_pbz_relative_max / zoom_data.total_zoom;
	
		    // prevent push if fully zoomed out (&& inst_eff_zoom <=0)
		    if (fully_zoomed_out == true) {
		      if (axis === 'x') {
		        // console.log('<<<<<<<<<< Min prevent push');
		      }
		      zoom_data.pan_by_zoom = 0;
		      zoom_data.total_pan_max = 0;
		    }
	
		    // if (axis === 'x' && has_been_both === true){
		    //   // debugger
		    // }
	
		    zoom_data.prev_restrict = 'min';
		  }
	
		  if (potential_total_pan_max > zero_threshold) {
	
		    // zoom_data.pan_by_zoom = - inst_eff_zoom * zoom_data.cursor_position;
		    // steps: 1) pin to max matrix, and 2) push left (negative) by total remaining pan
		    // total_pan_max
		    zoom_data.pan_by_zoom = -inst_eff_zoom * viz_dim_mat.max + zoom_data.total_pan_max * zoom_data.total_zoom;
	
		    // set total_pan_max to 0, no panning room remaining after being pushed left
		    zoom_data.total_pan_max = 0;
	
		    // the cursor is effectively locked on the max (right) side of the matrix
		    var new_cursor_relative_min = viz_dim_mat.max - viz_dim_mat.min;
		    var new_pbz_relative_min = -inst_eff_zoom * new_cursor_relative_min;
		    zoom_data.total_pan_min = zoom_data.total_pan_min + new_pbz_relative_min / zoom_data.total_zoom;
	
		    // prevent push if fully zoomed out
		    if (fully_zoomed_out == true) {
		      if (axis === 'x') {
		        // console.log('>>>>>>>>>>>>> Max prevent push');
		      }
		      zoom_data.pan_by_zoom = 0;
		      zoom_data.total_pan_min = 0;
		    }
	
		    // if (axis === 'x' && has_been_both === true){
		    //   // debugger
		    // }
	
		    zoom_data.prev_restrict = 'max';
		  }
	
		  // if double restrict, pin to side that was previously pinned
		  if (double_restrict) {
	
		    // console.log('\n\nAbout to pin matrix after double restriction \n----------------------------------------');
		    // console.log('prev_restrict', zoom_data_copy.prev_restrict);
	
		    // pin the matrix to either side
		    // no need to push it to the edge since it was previously pushed to the edge
		    if (zoom_data_copy.prev_restrict === 'min') {
	
		      zoom_data.pan_by_zoom = -inst_eff_zoom * viz_dim_mat.min;
		    } else if (zoom_data_copy.prev_restrict === 'max') {
	
		      zoom_data.pan_by_zoom = -inst_eff_zoom * viz_dim_mat.max;
		    }
		  }
	
		  return zoom_data;
			};
	
	/***/ }),
	/* 127 */
	/***/ (function(module, exports) {
	
		module.exports = function keep_track_of_interactions(params) {
	
		  // keep track of interactions
		  if (params.still_interacting == false) {
	
		    params.still_interacting = true;
	
		    // wait some time to confirm still not interacting
		    setTimeout(function () {
		      params.still_interacting = false;
		    }, 1000);
		  }
			};
	
	/***/ }),
	/* 128 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var custom_camera_2d = __webpack_require__(129);
	
		module.exports = function make_cameras(regl, params) {
	
		  var zoom_data = params.zoom_data;
	
		  const cameras = {};
		  var ini_scale = 1.0;
		  var zoom_range = {
		    xrange: [-ini_scale, ini_scale],
		    yrange: [-ini_scale, ini_scale]
		  };
	
		  // requiring camera and
		  cameras.mat = custom_camera_2d(regl, zoom_range, zoom_data, 'matrix');
	
		  cameras['row-labels'] = custom_camera_2d(regl, zoom_range, zoom_data, 'row-labels');
	
		  cameras['col-labels'] = custom_camera_2d(regl, zoom_range, zoom_data, 'col-labels');
	
		  cameras.static = custom_camera_2d(regl, zoom_range, zoom_data, 'static');
	
		  return cameras;
			};
	
	/***/ }),
	/* 129 */
	/***/ (function(module, exports, __webpack_require__) {
	
		// © 2016 Ricky Reusser. MIT License.
		// 'use strict';
	
		var interactionEvents = __webpack_require__(104);
		var extend = __webpack_require__(100);
		var mat4 = __webpack_require__(130);
		var EventEmitter = __webpack_require__(109);
		var vec4 = __webpack_require__(154);
		// var $ = require('jquery');
	
		mat4.viewport = function viewport(out, x, y, w, h, n, f) {
		  out[0] = w * 0.5;
		  out[1] = 0;
		  out[2] = 0;
		  out[3] = 0;
		  out[4] = 0;
		  out[5] = h * 0.5;
		  out[6] = 0;
		  out[7] = 0;
		  out[8] = 0;
		  out[9] = 0;
		  out[10] = (f - n) * 0.5;
		  out[11] = 0;
		  out[12] = x + w * 0.5;
		  out[13] = y + h * 0.5;
		  out[14] = (f + n) * 0.5;
		  out[15] = 1;
		  return out;
		};
	
		module.exports = function makeCamera2D(regl, opts, zoom_data, viz_component) {
	
		  // var zoom_data = $.extend(true, {}, zoom_data_ini);
		  // var zoom_data = $.extend(true, {}, zoom_data_ini);
	
		  opts = opts || {};
	
		  var options = extend({
		    element: opts.element || regl._gl.canvas
		  }, opts || {});
	
		  var element = options.element;
	
		  var dirty = true;
	
		  var getWidth = element === window ?
	
		  // function () { return element.innerWidth } :
		  // function () { return element.offsetWidth }
	
	
		  function () {
		    return element.innerWidth;
		  } : function () {
		    return element.offsetWidth;
		  };
	
		  var getHeight = element === window ?
	
		  // function () { return element.innerHeight } :
		  // function () { return element.offsetHeight }
	
		  function () {
		    return element.innerHeight;
		  } : function () {
		    return element.offsetHeight;
		  };
	
		  var xrange = opts.xrange === undefined ? [-1, 1] : opts.xrange;
		  var yrange = opts.yrange === undefined ? [-1, 1] : opts.yrange;
		  var aspectRatio = opts.aspectRatio === undefined ? 1 : opts.aspectRatio;
	
		  var width = getWidth();
		  var height = getHeight();
	
		  var xcen = 0.5 * (xrange[1] + xrange[0]);
		  var ycen = 0.5 * (yrange[1] + yrange[0]);
		  var xrng = 0.5 * (xrange[1] - xrange[0]);
		  var yrng = xrng / aspectRatio / width * height;
	
		  var mView = mat4.identity([]);
		  mView[0] = 1 / xrng;
		  mView[5] = 1 / yrng;
		  mView[12] = -xcen / xrng;
		  mView[13] = -ycen / yrng;
	
		  var mViewport = mat4.identity([]);
		  var mInvViewport = mat4.identity([]);
	
		  function computeViewport() {
		    width = getWidth();
		    height = getHeight();
	
		    mat4.viewport(mViewport, 0, height, width, -height, 0, 1);
		    mat4.invert(mInvViewport, mViewport);
		  }
	
		  computeViewport();
	
		  var dViewport = [];
	
		  interactionEvents({
		    element: element
		  }).on('interactionstart', function (ev) {
		    ev.preventDefault();
		  }).on('interactionend', function (ev) {
		    ev.preventDefault();
		  }).on('interaction', function (ev) {
	
		    //ev.dtheta = 0;
		    //var c = Math.cos(ev.dtheta);
		    //var s = Math.sin(ev.dtheta);
	
		    switch (ev.type) {
		      case 'wheel':
		        ev.dsx = ev.dsy = Math.exp(-ev.dy / 100);
		        ev.dx = ev.dy = 0;
		        break;
		    }
	
		    if (ev.buttons || ['wheel', 'touch', 'pinch'].indexOf(ev.type) !== -1) {
	
		      // console.log('viz_component: ' + viz_component);
	
		      /*
		      Sanitize zoom data components
		      */
	
		      var inst_x_zoom = zoom_data.x.inst_zoom;
		      var inst_x_pan_by_zoom = zoom_data.x.pan_by_zoom;
		      var inst_x_pan_by_drag = zoom_data.x.pan_by_drag;
	
		      var inst_y_zoom = zoom_data.y.inst_zoom;
		      var inst_y_pan_by_zoom = zoom_data.y.pan_by_zoom;
		      var inst_y_pan_by_drag = zoom_data.y.pan_by_drag;
	
		      if (viz_component === 'row-labels') {
		        inst_x_zoom = 1;
		        inst_x_pan_by_drag = 0;
		        inst_x_pan_by_zoom = 0;
		      }
	
		      if (viz_component === 'col-labels') {
		        inst_y_zoom = 1;
		        inst_y_pan_by_drag = 0;
		        inst_y_pan_by_zoom = 0;
		      }
	
		      if (viz_component === 'static') {
		        inst_x_zoom = 1;
		        inst_x_pan_by_drag = 0;
		        inst_x_pan_by_zoom = 0;
		        inst_y_zoom = 1;
		        inst_y_pan_by_drag = 0;
		        inst_y_pan_by_zoom = 0;
		      }
	
		      ev.preventDefault();
	
		      dViewport[0] = inst_x_zoom;
		      dViewport[1] = 0;
		      dViewport[2] = 0;
		      dViewport[3] = 0;
		      dViewport[4] = 0;
		      dViewport[5] = inst_y_zoom;
		      dViewport[6] = 0;
		      dViewport[7] = 0;
		      dViewport[8] = 0;
		      dViewport[9] = 0;
		      dViewport[10] = 1;
		      dViewport[11] = 0;
		      dViewport[12] = inst_x_pan_by_zoom + inst_x_pan_by_drag;
		      dViewport[13] = inst_y_pan_by_zoom + inst_y_pan_by_drag;
		      dViewport[14] = 0;
		      dViewport[15] = 1;
	
		      mat4.multiply(dViewport, dViewport, mViewport);
		      mat4.multiply(dViewport, mInvViewport, dViewport);
		      mat4.multiply(mView, dViewport, mView);
		      dirty = true;
		    }
	
		    var xy = vec4.transformMat4([], vec4.transformMat4([], [ev.x0, ev.y0, 0, 1], mInvViewport), mat4.invert([], mView));
	
		    ev.x = xy[0];
		    ev.y = xy[1];
	
		    emitter.emit('move', ev);
		  });
	
		  var setProps = regl({
		    context: {
		      view: regl.prop('view')
		    }
		  });
	
		  var emitter = new EventEmitter();
	
		  var inst_camera = {
		    draw: function (cb) {
		      setProps({
		        view: mView
		      }, function () {
		        cb({
		          dirty: dirty
		        });
		      });
		      dirty = false;
		    },
		    on: function (eventName, callback) {
		      emitter.on(eventName, callback);
		    },
		    off: function (eventName, callback) {
		      emitter.off(eventName, callback);
		    },
		    taint: function () {
		      dirty = true;
		    },
		    resize: function () {
		      computeViewport();
	
		      // console.log('resizing');
	
		      // Reapply the aspect ratio:
		      mView[5] = mView[0] * aspectRatio * width / height;
		      dirty = true;
		    }
		  };
	
		  return inst_camera;
			};
	
	/***/ }),
	/* 130 */
	/***/ (function(module, exports, __webpack_require__) {
	
		module.exports = {
		  create: __webpack_require__(131),
		  clone: __webpack_require__(132),
		  copy: __webpack_require__(133),
		  identity: __webpack_require__(134),
		  transpose: __webpack_require__(135),
		  invert: __webpack_require__(136),
		  adjoint: __webpack_require__(137),
		  determinant: __webpack_require__(138),
		  multiply: __webpack_require__(139),
		  translate: __webpack_require__(140),
		  scale: __webpack_require__(141),
		  rotate: __webpack_require__(142),
		  rotateX: __webpack_require__(143),
		  rotateY: __webpack_require__(144),
		  rotateZ: __webpack_require__(145),
		  fromRotationTranslation: __webpack_require__(146),
		  fromQuat: __webpack_require__(147),
		  frustum: __webpack_require__(148),
		  perspective: __webpack_require__(149),
		  perspectiveFromFieldOfView: __webpack_require__(150),
		  ortho: __webpack_require__(151),
		  lookAt: __webpack_require__(152),
		  str: __webpack_require__(153)
			};
	
	/***/ }),
	/* 131 */
	/***/ (function(module, exports) {
	
		module.exports = create;
	
		/**
		 * Creates a new identity mat4
		 *
		 * @returns {mat4} a new 4x4 matrix
		 */
		function create() {
		    var out = new Float32Array(16);
		    out[0] = 1;
		    out[1] = 0;
		    out[2] = 0;
		    out[3] = 0;
		    out[4] = 0;
		    out[5] = 1;
		    out[6] = 0;
		    out[7] = 0;
		    out[8] = 0;
		    out[9] = 0;
		    out[10] = 1;
		    out[11] = 0;
		    out[12] = 0;
		    out[13] = 0;
		    out[14] = 0;
		    out[15] = 1;
		    return out;
		};
	
	/***/ }),
	/* 132 */
	/***/ (function(module, exports) {
	
		module.exports = clone;
	
		/**
		 * Creates a new mat4 initialized with values from an existing matrix
		 *
		 * @param {mat4} a matrix to clone
		 * @returns {mat4} a new 4x4 matrix
		 */
		function clone(a) {
		    var out = new Float32Array(16);
		    out[0] = a[0];
		    out[1] = a[1];
		    out[2] = a[2];
		    out[3] = a[3];
		    out[4] = a[4];
		    out[5] = a[5];
		    out[6] = a[6];
		    out[7] = a[7];
		    out[8] = a[8];
		    out[9] = a[9];
		    out[10] = a[10];
		    out[11] = a[11];
		    out[12] = a[12];
		    out[13] = a[13];
		    out[14] = a[14];
		    out[15] = a[15];
		    return out;
		};
	
	/***/ }),
	/* 133 */
	/***/ (function(module, exports) {
	
		module.exports = copy;
	
		/**
		 * Copy the values from one mat4 to another
		 *
		 * @param {mat4} out the receiving matrix
		 * @param {mat4} a the source matrix
		 * @returns {mat4} out
		 */
		function copy(out, a) {
		    out[0] = a[0];
		    out[1] = a[1];
		    out[2] = a[2];
		    out[3] = a[3];
		    out[4] = a[4];
		    out[5] = a[5];
		    out[6] = a[6];
		    out[7] = a[7];
		    out[8] = a[8];
		    out[9] = a[9];
		    out[10] = a[10];
		    out[11] = a[11];
		    out[12] = a[12];
		    out[13] = a[13];
		    out[14] = a[14];
		    out[15] = a[15];
		    return out;
		};
	
	/***/ }),
	/* 134 */
	/***/ (function(module, exports) {
	
		module.exports = identity;
	
		/**
		 * Set a mat4 to the identity matrix
		 *
		 * @param {mat4} out the receiving matrix
		 * @returns {mat4} out
		 */
		function identity(out) {
		    out[0] = 1;
		    out[1] = 0;
		    out[2] = 0;
		    out[3] = 0;
		    out[4] = 0;
		    out[5] = 1;
		    out[6] = 0;
		    out[7] = 0;
		    out[8] = 0;
		    out[9] = 0;
		    out[10] = 1;
		    out[11] = 0;
		    out[12] = 0;
		    out[13] = 0;
		    out[14] = 0;
		    out[15] = 1;
		    return out;
		};
	
	/***/ }),
	/* 135 */
	/***/ (function(module, exports) {
	
		module.exports = transpose;
	
		/**
		 * Transpose the values of a mat4
		 *
		 * @param {mat4} out the receiving matrix
		 * @param {mat4} a the source matrix
		 * @returns {mat4} out
		 */
		function transpose(out, a) {
		    // If we are transposing ourselves we can skip a few steps but have to cache some values
		    if (out === a) {
		        var a01 = a[1],
		            a02 = a[2],
		            a03 = a[3],
		            a12 = a[6],
		            a13 = a[7],
		            a23 = a[11];
	
		        out[1] = a[4];
		        out[2] = a[8];
		        out[3] = a[12];
		        out[4] = a01;
		        out[6] = a[9];
		        out[7] = a[13];
		        out[8] = a02;
		        out[9] = a12;
		        out[11] = a[14];
		        out[12] = a03;
		        out[13] = a13;
		        out[14] = a23;
		    } else {
		        out[0] = a[0];
		        out[1] = a[4];
		        out[2] = a[8];
		        out[3] = a[12];
		        out[4] = a[1];
		        out[5] = a[5];
		        out[6] = a[9];
		        out[7] = a[13];
		        out[8] = a[2];
		        out[9] = a[6];
		        out[10] = a[10];
		        out[11] = a[14];
		        out[12] = a[3];
		        out[13] = a[7];
		        out[14] = a[11];
		        out[15] = a[15];
		    }
	
		    return out;
		};
	
	/***/ }),
	/* 136 */
	/***/ (function(module, exports) {
	
		module.exports = invert;
	
		/**
		 * Inverts a mat4
		 *
		 * @param {mat4} out the receiving matrix
		 * @param {mat4} a the source matrix
		 * @returns {mat4} out
		 */
		function invert(out, a) {
		    var a00 = a[0],
		        a01 = a[1],
		        a02 = a[2],
		        a03 = a[3],
		        a10 = a[4],
		        a11 = a[5],
		        a12 = a[6],
		        a13 = a[7],
		        a20 = a[8],
		        a21 = a[9],
		        a22 = a[10],
		        a23 = a[11],
		        a30 = a[12],
		        a31 = a[13],
		        a32 = a[14],
		        a33 = a[15],
		        b00 = a00 * a11 - a01 * a10,
		        b01 = a00 * a12 - a02 * a10,
		        b02 = a00 * a13 - a03 * a10,
		        b03 = a01 * a12 - a02 * a11,
		        b04 = a01 * a13 - a03 * a11,
		        b05 = a02 * a13 - a03 * a12,
		        b06 = a20 * a31 - a21 * a30,
		        b07 = a20 * a32 - a22 * a30,
		        b08 = a20 * a33 - a23 * a30,
		        b09 = a21 * a32 - a22 * a31,
		        b10 = a21 * a33 - a23 * a31,
		        b11 = a22 * a33 - a23 * a32,
	
	
		    // Calculate the determinant
		    det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
	
		    if (!det) {
		        return null;
		    }
		    det = 1.0 / det;
	
		    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
		    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
		    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
		    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
		    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
		    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
		    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
		    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
		    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
		    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
		    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
		    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
		    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
		    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
		    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
		    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
	
		    return out;
		};
	
	/***/ }),
	/* 137 */
	/***/ (function(module, exports) {
	
		module.exports = adjoint;
	
		/**
		 * Calculates the adjugate of a mat4
		 *
		 * @param {mat4} out the receiving matrix
		 * @param {mat4} a the source matrix
		 * @returns {mat4} out
		 */
		function adjoint(out, a) {
		    var a00 = a[0],
		        a01 = a[1],
		        a02 = a[2],
		        a03 = a[3],
		        a10 = a[4],
		        a11 = a[5],
		        a12 = a[6],
		        a13 = a[7],
		        a20 = a[8],
		        a21 = a[9],
		        a22 = a[10],
		        a23 = a[11],
		        a30 = a[12],
		        a31 = a[13],
		        a32 = a[14],
		        a33 = a[15];
	
		    out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
		    out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
		    out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
		    out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
		    out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
		    out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
		    out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
		    out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
		    out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
		    out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
		    out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
		    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
		    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
		    out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
		    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
		    out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
		    return out;
		};
	
	/***/ }),
	/* 138 */
	/***/ (function(module, exports) {
	
		module.exports = determinant;
	
		/**
		 * Calculates the determinant of a mat4
		 *
		 * @param {mat4} a the source matrix
		 * @returns {Number} determinant of a
		 */
		function determinant(a) {
		    var a00 = a[0],
		        a01 = a[1],
		        a02 = a[2],
		        a03 = a[3],
		        a10 = a[4],
		        a11 = a[5],
		        a12 = a[6],
		        a13 = a[7],
		        a20 = a[8],
		        a21 = a[9],
		        a22 = a[10],
		        a23 = a[11],
		        a30 = a[12],
		        a31 = a[13],
		        a32 = a[14],
		        a33 = a[15],
		        b00 = a00 * a11 - a01 * a10,
		        b01 = a00 * a12 - a02 * a10,
		        b02 = a00 * a13 - a03 * a10,
		        b03 = a01 * a12 - a02 * a11,
		        b04 = a01 * a13 - a03 * a11,
		        b05 = a02 * a13 - a03 * a12,
		        b06 = a20 * a31 - a21 * a30,
		        b07 = a20 * a32 - a22 * a30,
		        b08 = a20 * a33 - a23 * a30,
		        b09 = a21 * a32 - a22 * a31,
		        b10 = a21 * a33 - a23 * a31,
		        b11 = a22 * a33 - a23 * a32;
	
		    // Calculate the determinant
		    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
		};
	
	/***/ }),
	/* 139 */
	/***/ (function(module, exports) {
	
		module.exports = multiply;
	
		/**
		 * Multiplies two mat4's
		 *
		 * @param {mat4} out the receiving matrix
		 * @param {mat4} a the first operand
		 * @param {mat4} b the second operand
		 * @returns {mat4} out
		 */
		function multiply(out, a, b) {
		    var a00 = a[0],
		        a01 = a[1],
		        a02 = a[2],
		        a03 = a[3],
		        a10 = a[4],
		        a11 = a[5],
		        a12 = a[6],
		        a13 = a[7],
		        a20 = a[8],
		        a21 = a[9],
		        a22 = a[10],
		        a23 = a[11],
		        a30 = a[12],
		        a31 = a[13],
		        a32 = a[14],
		        a33 = a[15];
	
		    // Cache only the current line of the second matrix
		    var b0 = b[0],
		        b1 = b[1],
		        b2 = b[2],
		        b3 = b[3];
		    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
		    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
		    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
		    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
	
		    b0 = b[4];b1 = b[5];b2 = b[6];b3 = b[7];
		    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
		    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
		    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
		    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
	
		    b0 = b[8];b1 = b[9];b2 = b[10];b3 = b[11];
		    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
		    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
		    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
		    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
	
		    b0 = b[12];b1 = b[13];b2 = b[14];b3 = b[15];
		    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
		    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
		    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
		    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
		    return out;
		};
	
	/***/ }),
	/* 140 */
	/***/ (function(module, exports) {
	
		module.exports = translate;
	
		/**
		 * Translate a mat4 by the given vector
		 *
		 * @param {mat4} out the receiving matrix
		 * @param {mat4} a the matrix to translate
		 * @param {vec3} v vector to translate by
		 * @returns {mat4} out
		 */
		function translate(out, a, v) {
		    var x = v[0],
		        y = v[1],
		        z = v[2],
		        a00,
		        a01,
		        a02,
		        a03,
		        a10,
		        a11,
		        a12,
		        a13,
		        a20,
		        a21,
		        a22,
		        a23;
	
		    if (a === out) {
		        out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
		        out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
		        out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
		        out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
		    } else {
		        a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3];
		        a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7];
		        a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11];
	
		        out[0] = a00;out[1] = a01;out[2] = a02;out[3] = a03;
		        out[4] = a10;out[5] = a11;out[6] = a12;out[7] = a13;
		        out[8] = a20;out[9] = a21;out[10] = a22;out[11] = a23;
	
		        out[12] = a00 * x + a10 * y + a20 * z + a[12];
		        out[13] = a01 * x + a11 * y + a21 * z + a[13];
		        out[14] = a02 * x + a12 * y + a22 * z + a[14];
		        out[15] = a03 * x + a13 * y + a23 * z + a[15];
		    }
	
		    return out;
		};
	
	/***/ }),
	/* 141 */
	/***/ (function(module, exports) {
	
		module.exports = scale;
	
		/**
		 * Scales the mat4 by the dimensions in the given vec3
		 *
		 * @param {mat4} out the receiving matrix
		 * @param {mat4} a the matrix to scale
		 * @param {vec3} v the vec3 to scale the matrix by
		 * @returns {mat4} out
		 **/
		function scale(out, a, v) {
		    var x = v[0],
		        y = v[1],
		        z = v[2];
	
		    out[0] = a[0] * x;
		    out[1] = a[1] * x;
		    out[2] = a[2] * x;
		    out[3] = a[3] * x;
		    out[4] = a[4] * y;
		    out[5] = a[5] * y;
		    out[6] = a[6] * y;
		    out[7] = a[7] * y;
		    out[8] = a[8] * z;
		    out[9] = a[9] * z;
		    out[10] = a[10] * z;
		    out[11] = a[11] * z;
		    out[12] = a[12];
		    out[13] = a[13];
		    out[14] = a[14];
		    out[15] = a[15];
		    return out;
		};
	
	/***/ }),
	/* 142 */
	/***/ (function(module, exports) {
	
		module.exports = rotate;
	
		/**
		 * Rotates a mat4 by the given angle
		 *
		 * @param {mat4} out the receiving matrix
		 * @param {mat4} a the matrix to rotate
		 * @param {Number} rad the angle to rotate the matrix by
		 * @param {vec3} axis the axis to rotate around
		 * @returns {mat4} out
		 */
		function rotate(out, a, rad, axis) {
		    var x = axis[0],
		        y = axis[1],
		        z = axis[2],
		        len = Math.sqrt(x * x + y * y + z * z),
		        s,
		        c,
		        t,
		        a00,
		        a01,
		        a02,
		        a03,
		        a10,
		        a11,
		        a12,
		        a13,
		        a20,
		        a21,
		        a22,
		        a23,
		        b00,
		        b01,
		        b02,
		        b10,
		        b11,
		        b12,
		        b20,
		        b21,
		        b22;
	
		    if (Math.abs(len) < 0.000001) {
		        return null;
		    }
	
		    len = 1 / len;
		    x *= len;
		    y *= len;
		    z *= len;
	
		    s = Math.sin(rad);
		    c = Math.cos(rad);
		    t = 1 - c;
	
		    a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3];
		    a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7];
		    a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11];
	
		    // Construct the elements of the rotation matrix
		    b00 = x * x * t + c;b01 = y * x * t + z * s;b02 = z * x * t - y * s;
		    b10 = x * y * t - z * s;b11 = y * y * t + c;b12 = z * y * t + x * s;
		    b20 = x * z * t + y * s;b21 = y * z * t - x * s;b22 = z * z * t + c;
	
		    // Perform rotation-specific matrix multiplication
		    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
		    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
		    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
		    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
		    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
		    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
		    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
		    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
		    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
		    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
		    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
		    out[11] = a03 * b20 + a13 * b21 + a23 * b22;
	
		    if (a !== out) {
		        // If the source and destination differ, copy the unchanged last row
		        out[12] = a[12];
		        out[13] = a[13];
		        out[14] = a[14];
		        out[15] = a[15];
		    }
		    return out;
		};
	
	/***/ }),
	/* 143 */
	/***/ (function(module, exports) {
	
		module.exports = rotateX;
	
		/**
		 * Rotates a matrix by the given angle around the X axis
		 *
		 * @param {mat4} out the receiving matrix
		 * @param {mat4} a the matrix to rotate
		 * @param {Number} rad the angle to rotate the matrix by
		 * @returns {mat4} out
		 */
		function rotateX(out, a, rad) {
		    var s = Math.sin(rad),
		        c = Math.cos(rad),
		        a10 = a[4],
		        a11 = a[5],
		        a12 = a[6],
		        a13 = a[7],
		        a20 = a[8],
		        a21 = a[9],
		        a22 = a[10],
		        a23 = a[11];
	
		    if (a !== out) {
		        // If the source and destination differ, copy the unchanged rows
		        out[0] = a[0];
		        out[1] = a[1];
		        out[2] = a[2];
		        out[3] = a[3];
		        out[12] = a[12];
		        out[13] = a[13];
		        out[14] = a[14];
		        out[15] = a[15];
		    }
	
		    // Perform axis-specific matrix multiplication
		    out[4] = a10 * c + a20 * s;
		    out[5] = a11 * c + a21 * s;
		    out[6] = a12 * c + a22 * s;
		    out[7] = a13 * c + a23 * s;
		    out[8] = a20 * c - a10 * s;
		    out[9] = a21 * c - a11 * s;
		    out[10] = a22 * c - a12 * s;
		    out[11] = a23 * c - a13 * s;
		    return out;
		};
	
	/***/ }),
	/* 144 */
	/***/ (function(module, exports) {
	
		module.exports = rotateY;
	
		/**
		 * Rotates a matrix by the given angle around the Y axis
		 *
		 * @param {mat4} out the receiving matrix
		 * @param {mat4} a the matrix to rotate
		 * @param {Number} rad the angle to rotate the matrix by
		 * @returns {mat4} out
		 */
		function rotateY(out, a, rad) {
		    var s = Math.sin(rad),
		        c = Math.cos(rad),
		        a00 = a[0],
		        a01 = a[1],
		        a02 = a[2],
		        a03 = a[3],
		        a20 = a[8],
		        a21 = a[9],
		        a22 = a[10],
		        a23 = a[11];
	
		    if (a !== out) {
		        // If the source and destination differ, copy the unchanged rows
		        out[4] = a[4];
		        out[5] = a[5];
		        out[6] = a[6];
		        out[7] = a[7];
		        out[12] = a[12];
		        out[13] = a[13];
		        out[14] = a[14];
		        out[15] = a[15];
		    }
	
		    // Perform axis-specific matrix multiplication
		    out[0] = a00 * c - a20 * s;
		    out[1] = a01 * c - a21 * s;
		    out[2] = a02 * c - a22 * s;
		    out[3] = a03 * c - a23 * s;
		    out[8] = a00 * s + a20 * c;
		    out[9] = a01 * s + a21 * c;
		    out[10] = a02 * s + a22 * c;
		    out[11] = a03 * s + a23 * c;
		    return out;
		};
	
	/***/ }),
	/* 145 */
	/***/ (function(module, exports) {
	
		module.exports = rotateZ;
	
		/**
		 * Rotates a matrix by the given angle around the Z axis
		 *
		 * @param {mat4} out the receiving matrix
		 * @param {mat4} a the matrix to rotate
		 * @param {Number} rad the angle to rotate the matrix by
		 * @returns {mat4} out
		 */
		function rotateZ(out, a, rad) {
		    var s = Math.sin(rad),
		        c = Math.cos(rad),
		        a00 = a[0],
		        a01 = a[1],
		        a02 = a[2],
		        a03 = a[3],
		        a10 = a[4],
		        a11 = a[5],
		        a12 = a[6],
		        a13 = a[7];
	
		    if (a !== out) {
		        // If the source and destination differ, copy the unchanged last row
		        out[8] = a[8];
		        out[9] = a[9];
		        out[10] = a[10];
		        out[11] = a[11];
		        out[12] = a[12];
		        out[13] = a[13];
		        out[14] = a[14];
		        out[15] = a[15];
		    }
	
		    // Perform axis-specific matrix multiplication
		    out[0] = a00 * c + a10 * s;
		    out[1] = a01 * c + a11 * s;
		    out[2] = a02 * c + a12 * s;
		    out[3] = a03 * c + a13 * s;
		    out[4] = a10 * c - a00 * s;
		    out[5] = a11 * c - a01 * s;
		    out[6] = a12 * c - a02 * s;
		    out[7] = a13 * c - a03 * s;
		    return out;
		};
	
	/***/ }),
	/* 146 */
	/***/ (function(module, exports) {
	
		module.exports = fromRotationTranslation;
	
		/**
		 * Creates a matrix from a quaternion rotation and vector translation
		 * This is equivalent to (but much faster than):
		 *
		 *     mat4.identity(dest);
		 *     mat4.translate(dest, vec);
		 *     var quatMat = mat4.create();
		 *     quat4.toMat4(quat, quatMat);
		 *     mat4.multiply(dest, quatMat);
		 *
		 * @param {mat4} out mat4 receiving operation result
		 * @param {quat4} q Rotation quaternion
		 * @param {vec3} v Translation vector
		 * @returns {mat4} out
		 */
		function fromRotationTranslation(out, q, v) {
		    // Quaternion math
		    var x = q[0],
		        y = q[1],
		        z = q[2],
		        w = q[3],
		        x2 = x + x,
		        y2 = y + y,
		        z2 = z + z,
		        xx = x * x2,
		        xy = x * y2,
		        xz = x * z2,
		        yy = y * y2,
		        yz = y * z2,
		        zz = z * z2,
		        wx = w * x2,
		        wy = w * y2,
		        wz = w * z2;
	
		    out[0] = 1 - (yy + zz);
		    out[1] = xy + wz;
		    out[2] = xz - wy;
		    out[3] = 0;
		    out[4] = xy - wz;
		    out[5] = 1 - (xx + zz);
		    out[6] = yz + wx;
		    out[7] = 0;
		    out[8] = xz + wy;
		    out[9] = yz - wx;
		    out[10] = 1 - (xx + yy);
		    out[11] = 0;
		    out[12] = v[0];
		    out[13] = v[1];
		    out[14] = v[2];
		    out[15] = 1;
	
		    return out;
		};
	
	/***/ }),
	/* 147 */
	/***/ (function(module, exports) {
	
		module.exports = fromQuat;
	
		/**
		 * Creates a matrix from a quaternion rotation.
		 *
		 * @param {mat4} out mat4 receiving operation result
		 * @param {quat4} q Rotation quaternion
		 * @returns {mat4} out
		 */
		function fromQuat(out, q) {
		    var x = q[0],
		        y = q[1],
		        z = q[2],
		        w = q[3],
		        x2 = x + x,
		        y2 = y + y,
		        z2 = z + z,
		        xx = x * x2,
		        yx = y * x2,
		        yy = y * y2,
		        zx = z * x2,
		        zy = z * y2,
		        zz = z * z2,
		        wx = w * x2,
		        wy = w * y2,
		        wz = w * z2;
	
		    out[0] = 1 - yy - zz;
		    out[1] = yx + wz;
		    out[2] = zx - wy;
		    out[3] = 0;
	
		    out[4] = yx - wz;
		    out[5] = 1 - xx - zz;
		    out[6] = zy + wx;
		    out[7] = 0;
	
		    out[8] = zx + wy;
		    out[9] = zy - wx;
		    out[10] = 1 - xx - yy;
		    out[11] = 0;
	
		    out[12] = 0;
		    out[13] = 0;
		    out[14] = 0;
		    out[15] = 1;
	
		    return out;
		};
	
	/***/ }),
	/* 148 */
	/***/ (function(module, exports) {
	
		module.exports = frustum;
	
		/**
		 * Generates a frustum matrix with the given bounds
		 *
		 * @param {mat4} out mat4 frustum matrix will be written into
		 * @param {Number} left Left bound of the frustum
		 * @param {Number} right Right bound of the frustum
		 * @param {Number} bottom Bottom bound of the frustum
		 * @param {Number} top Top bound of the frustum
		 * @param {Number} near Near bound of the frustum
		 * @param {Number} far Far bound of the frustum
		 * @returns {mat4} out
		 */
		function frustum(out, left, right, bottom, top, near, far) {
		    var rl = 1 / (right - left),
		        tb = 1 / (top - bottom),
		        nf = 1 / (near - far);
		    out[0] = near * 2 * rl;
		    out[1] = 0;
		    out[2] = 0;
		    out[3] = 0;
		    out[4] = 0;
		    out[5] = near * 2 * tb;
		    out[6] = 0;
		    out[7] = 0;
		    out[8] = (right + left) * rl;
		    out[9] = (top + bottom) * tb;
		    out[10] = (far + near) * nf;
		    out[11] = -1;
		    out[12] = 0;
		    out[13] = 0;
		    out[14] = far * near * 2 * nf;
		    out[15] = 0;
		    return out;
		};
	
	/***/ }),
	/* 149 */
	/***/ (function(module, exports) {
	
		module.exports = perspective;
	
		/**
		 * Generates a perspective projection matrix with the given bounds
		 *
		 * @param {mat4} out mat4 frustum matrix will be written into
		 * @param {number} fovy Vertical field of view in radians
		 * @param {number} aspect Aspect ratio. typically viewport width/height
		 * @param {number} near Near bound of the frustum
		 * @param {number} far Far bound of the frustum
		 * @returns {mat4} out
		 */
		function perspective(out, fovy, aspect, near, far) {
		    var f = 1.0 / Math.tan(fovy / 2),
		        nf = 1 / (near - far);
		    out[0] = f / aspect;
		    out[1] = 0;
		    out[2] = 0;
		    out[3] = 0;
		    out[4] = 0;
		    out[5] = f;
		    out[6] = 0;
		    out[7] = 0;
		    out[8] = 0;
		    out[9] = 0;
		    out[10] = (far + near) * nf;
		    out[11] = -1;
		    out[12] = 0;
		    out[13] = 0;
		    out[14] = 2 * far * near * nf;
		    out[15] = 0;
		    return out;
		};
	
	/***/ }),
	/* 150 */
	/***/ (function(module, exports) {
	
		module.exports = perspectiveFromFieldOfView;
	
		/**
		 * Generates a perspective projection matrix with the given field of view.
		 * This is primarily useful for generating projection matrices to be used
		 * with the still experiemental WebVR API.
		 *
		 * @param {mat4} out mat4 frustum matrix will be written into
		 * @param {number} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
		 * @param {number} near Near bound of the frustum
		 * @param {number} far Far bound of the frustum
		 * @returns {mat4} out
		 */
		function perspectiveFromFieldOfView(out, fov, near, far) {
		    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0),
		        downTan = Math.tan(fov.downDegrees * Math.PI / 180.0),
		        leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0),
		        rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0),
		        xScale = 2.0 / (leftTan + rightTan),
		        yScale = 2.0 / (upTan + downTan);
	
		    out[0] = xScale;
		    out[1] = 0.0;
		    out[2] = 0.0;
		    out[3] = 0.0;
		    out[4] = 0.0;
		    out[5] = yScale;
		    out[6] = 0.0;
		    out[7] = 0.0;
		    out[8] = -((leftTan - rightTan) * xScale * 0.5);
		    out[9] = (upTan - downTan) * yScale * 0.5;
		    out[10] = far / (near - far);
		    out[11] = -1.0;
		    out[12] = 0.0;
		    out[13] = 0.0;
		    out[14] = far * near / (near - far);
		    out[15] = 0.0;
		    return out;
		}
	
	/***/ }),
	/* 151 */
	/***/ (function(module, exports) {
	
		module.exports = ortho;
	
		/**
		 * Generates a orthogonal projection matrix with the given bounds
		 *
		 * @param {mat4} out mat4 frustum matrix will be written into
		 * @param {number} left Left bound of the frustum
		 * @param {number} right Right bound of the frustum
		 * @param {number} bottom Bottom bound of the frustum
		 * @param {number} top Top bound of the frustum
		 * @param {number} near Near bound of the frustum
		 * @param {number} far Far bound of the frustum
		 * @returns {mat4} out
		 */
		function ortho(out, left, right, bottom, top, near, far) {
		    var lr = 1 / (left - right),
		        bt = 1 / (bottom - top),
		        nf = 1 / (near - far);
		    out[0] = -2 * lr;
		    out[1] = 0;
		    out[2] = 0;
		    out[3] = 0;
		    out[4] = 0;
		    out[5] = -2 * bt;
		    out[6] = 0;
		    out[7] = 0;
		    out[8] = 0;
		    out[9] = 0;
		    out[10] = 2 * nf;
		    out[11] = 0;
		    out[12] = (left + right) * lr;
		    out[13] = (top + bottom) * bt;
		    out[14] = (far + near) * nf;
		    out[15] = 1;
		    return out;
		};
	
	/***/ }),
	/* 152 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var identity = __webpack_require__(134);
	
		module.exports = lookAt;
	
		/**
		 * Generates a look-at matrix with the given eye position, focal point, and up axis
		 *
		 * @param {mat4} out mat4 frustum matrix will be written into
		 * @param {vec3} eye Position of the viewer
		 * @param {vec3} center Point the viewer is looking at
		 * @param {vec3} up vec3 pointing up
		 * @returns {mat4} out
		 */
		function lookAt(out, eye, center, up) {
		    var x0,
		        x1,
		        x2,
		        y0,
		        y1,
		        y2,
		        z0,
		        z1,
		        z2,
		        len,
		        eyex = eye[0],
		        eyey = eye[1],
		        eyez = eye[2],
		        upx = up[0],
		        upy = up[1],
		        upz = up[2],
		        centerx = center[0],
		        centery = center[1],
		        centerz = center[2];
	
		    if (Math.abs(eyex - centerx) < 0.000001 && Math.abs(eyey - centery) < 0.000001 && Math.abs(eyez - centerz) < 0.000001) {
		        return identity(out);
		    }
	
		    z0 = eyex - centerx;
		    z1 = eyey - centery;
		    z2 = eyez - centerz;
	
		    len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
		    z0 *= len;
		    z1 *= len;
		    z2 *= len;
	
		    x0 = upy * z2 - upz * z1;
		    x1 = upz * z0 - upx * z2;
		    x2 = upx * z1 - upy * z0;
		    len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
		    if (!len) {
		        x0 = 0;
		        x1 = 0;
		        x2 = 0;
		    } else {
		        len = 1 / len;
		        x0 *= len;
		        x1 *= len;
		        x2 *= len;
		    }
	
		    y0 = z1 * x2 - z2 * x1;
		    y1 = z2 * x0 - z0 * x2;
		    y2 = z0 * x1 - z1 * x0;
	
		    len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
		    if (!len) {
		        y0 = 0;
		        y1 = 0;
		        y2 = 0;
		    } else {
		        len = 1 / len;
		        y0 *= len;
		        y1 *= len;
		        y2 *= len;
		    }
	
		    out[0] = x0;
		    out[1] = y0;
		    out[2] = z0;
		    out[3] = 0;
		    out[4] = x1;
		    out[5] = y1;
		    out[6] = z1;
		    out[7] = 0;
		    out[8] = x2;
		    out[9] = y2;
		    out[10] = z2;
		    out[11] = 0;
		    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
		    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
		    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
		    out[15] = 1;
	
		    return out;
		};
	
	/***/ }),
	/* 153 */
	/***/ (function(module, exports) {
	
		module.exports = str;
	
		/**
		 * Returns a string representation of a mat4
		 *
		 * @param {mat4} mat matrix to represent as a string
		 * @returns {String} string representation of the matrix
		 */
		function str(a) {
		  return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
			};
	
	/***/ }),
	/* 154 */
	/***/ (function(module, exports, __webpack_require__) {
	
		module.exports = {
		  create: __webpack_require__(155),
		  clone: __webpack_require__(156),
		  fromValues: __webpack_require__(157),
		  copy: __webpack_require__(158),
		  set: __webpack_require__(159),
		  add: __webpack_require__(160),
		  subtract: __webpack_require__(161),
		  multiply: __webpack_require__(162),
		  divide: __webpack_require__(163),
		  min: __webpack_require__(164),
		  max: __webpack_require__(165),
		  scale: __webpack_require__(166),
		  scaleAndAdd: __webpack_require__(167),
		  distance: __webpack_require__(168),
		  squaredDistance: __webpack_require__(169),
		  length: __webpack_require__(170),
		  squaredLength: __webpack_require__(171),
		  negate: __webpack_require__(172),
		  inverse: __webpack_require__(173),
		  normalize: __webpack_require__(174),
		  dot: __webpack_require__(175),
		  lerp: __webpack_require__(176),
		  random: __webpack_require__(177),
		  transformMat4: __webpack_require__(178),
		  transformQuat: __webpack_require__(179)
			};
	
	/***/ }),
	/* 155 */
	/***/ (function(module, exports) {
	
		module.exports = create;
	
		/**
		 * Creates a new, empty vec4
		 *
		 * @returns {vec4} a new 4D vector
		 */
		function create() {
		  var out = new Float32Array(4);
		  out[0] = 0;
		  out[1] = 0;
		  out[2] = 0;
		  out[3] = 0;
		  return out;
		}
	
	/***/ }),
	/* 156 */
	/***/ (function(module, exports) {
	
		module.exports = clone;
	
		/**
		 * Creates a new vec4 initialized with values from an existing vector
		 *
		 * @param {vec4} a vector to clone
		 * @returns {vec4} a new 4D vector
		 */
		function clone(a) {
		  var out = new Float32Array(4);
		  out[0] = a[0];
		  out[1] = a[1];
		  out[2] = a[2];
		  out[3] = a[3];
		  return out;
		}
	
	/***/ }),
	/* 157 */
	/***/ (function(module, exports) {
	
		module.exports = fromValues;
	
		/**
		 * Creates a new vec4 initialized with the given values
		 *
		 * @param {Number} x X component
		 * @param {Number} y Y component
		 * @param {Number} z Z component
		 * @param {Number} w W component
		 * @returns {vec4} a new 4D vector
		 */
		function fromValues(x, y, z, w) {
		  var out = new Float32Array(4);
		  out[0] = x;
		  out[1] = y;
		  out[2] = z;
		  out[3] = w;
		  return out;
		}
	
	/***/ }),
	/* 158 */
	/***/ (function(module, exports) {
	
		module.exports = copy;
	
		/**
		 * Copy the values from one vec4 to another
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a the source vector
		 * @returns {vec4} out
		 */
		function copy(out, a) {
		  out[0] = a[0];
		  out[1] = a[1];
		  out[2] = a[2];
		  out[3] = a[3];
		  return out;
		}
	
	/***/ }),
	/* 159 */
	/***/ (function(module, exports) {
	
		module.exports = set;
	
		/**
		 * Set the components of a vec4 to the given values
		 *
		 * @param {vec4} out the receiving vector
		 * @param {Number} x X component
		 * @param {Number} y Y component
		 * @param {Number} z Z component
		 * @param {Number} w W component
		 * @returns {vec4} out
		 */
		function set(out, x, y, z, w) {
		  out[0] = x;
		  out[1] = y;
		  out[2] = z;
		  out[3] = w;
		  return out;
		}
	
	/***/ }),
	/* 160 */
	/***/ (function(module, exports) {
	
		module.exports = add;
	
		/**
		 * Adds two vec4's
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a the first operand
		 * @param {vec4} b the second operand
		 * @returns {vec4} out
		 */
		function add(out, a, b) {
		  out[0] = a[0] + b[0];
		  out[1] = a[1] + b[1];
		  out[2] = a[2] + b[2];
		  out[3] = a[3] + b[3];
		  return out;
		}
	
	/***/ }),
	/* 161 */
	/***/ (function(module, exports) {
	
		module.exports = subtract;
	
		/**
		 * Subtracts vector b from vector a
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a the first operand
		 * @param {vec4} b the second operand
		 * @returns {vec4} out
		 */
		function subtract(out, a, b) {
		  out[0] = a[0] - b[0];
		  out[1] = a[1] - b[1];
		  out[2] = a[2] - b[2];
		  out[3] = a[3] - b[3];
		  return out;
		}
	
	/***/ }),
	/* 162 */
	/***/ (function(module, exports) {
	
		module.exports = multiply;
	
		/**
		 * Multiplies two vec4's
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a the first operand
		 * @param {vec4} b the second operand
		 * @returns {vec4} out
		 */
		function multiply(out, a, b) {
		  out[0] = a[0] * b[0];
		  out[1] = a[1] * b[1];
		  out[2] = a[2] * b[2];
		  out[3] = a[3] * b[3];
		  return out;
		}
	
	/***/ }),
	/* 163 */
	/***/ (function(module, exports) {
	
		module.exports = divide;
	
		/**
		 * Divides two vec4's
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a the first operand
		 * @param {vec4} b the second operand
		 * @returns {vec4} out
		 */
		function divide(out, a, b) {
		  out[0] = a[0] / b[0];
		  out[1] = a[1] / b[1];
		  out[2] = a[2] / b[2];
		  out[3] = a[3] / b[3];
		  return out;
		}
	
	/***/ }),
	/* 164 */
	/***/ (function(module, exports) {
	
		module.exports = min;
	
		/**
		 * Returns the minimum of two vec4's
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a the first operand
		 * @param {vec4} b the second operand
		 * @returns {vec4} out
		 */
		function min(out, a, b) {
		  out[0] = Math.min(a[0], b[0]);
		  out[1] = Math.min(a[1], b[1]);
		  out[2] = Math.min(a[2], b[2]);
		  out[3] = Math.min(a[3], b[3]);
		  return out;
		}
	
	/***/ }),
	/* 165 */
	/***/ (function(module, exports) {
	
		module.exports = max;
	
		/**
		 * Returns the maximum of two vec4's
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a the first operand
		 * @param {vec4} b the second operand
		 * @returns {vec4} out
		 */
		function max(out, a, b) {
		  out[0] = Math.max(a[0], b[0]);
		  out[1] = Math.max(a[1], b[1]);
		  out[2] = Math.max(a[2], b[2]);
		  out[3] = Math.max(a[3], b[3]);
		  return out;
		}
	
	/***/ }),
	/* 166 */
	/***/ (function(module, exports) {
	
		module.exports = scale;
	
		/**
		 * Scales a vec4 by a scalar number
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a the vector to scale
		 * @param {Number} b amount to scale the vector by
		 * @returns {vec4} out
		 */
		function scale(out, a, b) {
		  out[0] = a[0] * b;
		  out[1] = a[1] * b;
		  out[2] = a[2] * b;
		  out[3] = a[3] * b;
		  return out;
		}
	
	/***/ }),
	/* 167 */
	/***/ (function(module, exports) {
	
		module.exports = scaleAndAdd;
	
		/**
		 * Adds two vec4's after scaling the second operand by a scalar value
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a the first operand
		 * @param {vec4} b the second operand
		 * @param {Number} scale the amount to scale b by before adding
		 * @returns {vec4} out
		 */
		function scaleAndAdd(out, a, b, scale) {
		  out[0] = a[0] + b[0] * scale;
		  out[1] = a[1] + b[1] * scale;
		  out[2] = a[2] + b[2] * scale;
		  out[3] = a[3] + b[3] * scale;
		  return out;
		}
	
	/***/ }),
	/* 168 */
	/***/ (function(module, exports) {
	
		module.exports = distance;
	
		/**
		 * Calculates the euclidian distance between two vec4's
		 *
		 * @param {vec4} a the first operand
		 * @param {vec4} b the second operand
		 * @returns {Number} distance between a and b
		 */
		function distance(a, b) {
		  var x = b[0] - a[0],
		      y = b[1] - a[1],
		      z = b[2] - a[2],
		      w = b[3] - a[3];
		  return Math.sqrt(x * x + y * y + z * z + w * w);
		}
	
	/***/ }),
	/* 169 */
	/***/ (function(module, exports) {
	
		module.exports = squaredDistance;
	
		/**
		 * Calculates the squared euclidian distance between two vec4's
		 *
		 * @param {vec4} a the first operand
		 * @param {vec4} b the second operand
		 * @returns {Number} squared distance between a and b
		 */
		function squaredDistance(a, b) {
		  var x = b[0] - a[0],
		      y = b[1] - a[1],
		      z = b[2] - a[2],
		      w = b[3] - a[3];
		  return x * x + y * y + z * z + w * w;
		}
	
	/***/ }),
	/* 170 */
	/***/ (function(module, exports) {
	
		module.exports = length;
	
		/**
		 * Calculates the length of a vec4
		 *
		 * @param {vec4} a vector to calculate length of
		 * @returns {Number} length of a
		 */
		function length(a) {
		  var x = a[0],
		      y = a[1],
		      z = a[2],
		      w = a[3];
		  return Math.sqrt(x * x + y * y + z * z + w * w);
		}
	
	/***/ }),
	/* 171 */
	/***/ (function(module, exports) {
	
		module.exports = squaredLength;
	
		/**
		 * Calculates the squared length of a vec4
		 *
		 * @param {vec4} a vector to calculate squared length of
		 * @returns {Number} squared length of a
		 */
		function squaredLength(a) {
		  var x = a[0],
		      y = a[1],
		      z = a[2],
		      w = a[3];
		  return x * x + y * y + z * z + w * w;
		}
	
	/***/ }),
	/* 172 */
	/***/ (function(module, exports) {
	
		module.exports = negate;
	
		/**
		 * Negates the components of a vec4
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a vector to negate
		 * @returns {vec4} out
		 */
		function negate(out, a) {
		  out[0] = -a[0];
		  out[1] = -a[1];
		  out[2] = -a[2];
		  out[3] = -a[3];
		  return out;
		}
	
	/***/ }),
	/* 173 */
	/***/ (function(module, exports) {
	
		module.exports = inverse;
	
		/**
		 * Returns the inverse of the components of a vec4
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a vector to invert
		 * @returns {vec4} out
		 */
		function inverse(out, a) {
		  out[0] = 1.0 / a[0];
		  out[1] = 1.0 / a[1];
		  out[2] = 1.0 / a[2];
		  out[3] = 1.0 / a[3];
		  return out;
		}
	
	/***/ }),
	/* 174 */
	/***/ (function(module, exports) {
	
		module.exports = normalize;
	
		/**
		 * Normalize a vec4
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a vector to normalize
		 * @returns {vec4} out
		 */
		function normalize(out, a) {
		  var x = a[0],
		      y = a[1],
		      z = a[2],
		      w = a[3];
		  var len = x * x + y * y + z * z + w * w;
		  if (len > 0) {
		    len = 1 / Math.sqrt(len);
		    out[0] = x * len;
		    out[1] = y * len;
		    out[2] = z * len;
		    out[3] = w * len;
		  }
		  return out;
		}
	
	/***/ }),
	/* 175 */
	/***/ (function(module, exports) {
	
		module.exports = dot;
	
		/**
		 * Calculates the dot product of two vec4's
		 *
		 * @param {vec4} a the first operand
		 * @param {vec4} b the second operand
		 * @returns {Number} dot product of a and b
		 */
		function dot(a, b) {
		  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
		}
	
	/***/ }),
	/* 176 */
	/***/ (function(module, exports) {
	
		module.exports = lerp;
	
		/**
		 * Performs a linear interpolation between two vec4's
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a the first operand
		 * @param {vec4} b the second operand
		 * @param {Number} t interpolation amount between the two inputs
		 * @returns {vec4} out
		 */
		function lerp(out, a, b, t) {
		  var ax = a[0],
		      ay = a[1],
		      az = a[2],
		      aw = a[3];
		  out[0] = ax + t * (b[0] - ax);
		  out[1] = ay + t * (b[1] - ay);
		  out[2] = az + t * (b[2] - az);
		  out[3] = aw + t * (b[3] - aw);
		  return out;
		}
	
	/***/ }),
	/* 177 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var vecNormalize = __webpack_require__(174);
		var vecScale = __webpack_require__(166);
	
		module.exports = random;
	
		/**
		 * Generates a random vector with the given scale
		 *
		 * @param {vec4} out the receiving vector
		 * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
		 * @returns {vec4} out
		 */
		function random(out, scale) {
		  scale = scale || 1.0;
	
		  // TODO: This is a pretty awful way of doing this. Find something better.
		  out[0] = Math.random();
		  out[1] = Math.random();
		  out[2] = Math.random();
		  out[3] = Math.random();
		  vecNormalize(out, out);
		  vecScale(out, out, scale);
		  return out;
		}
	
	/***/ }),
	/* 178 */
	/***/ (function(module, exports) {
	
		module.exports = transformMat4;
	
		/**
		 * Transforms the vec4 with a mat4.
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a the vector to transform
		 * @param {mat4} m matrix to transform with
		 * @returns {vec4} out
		 */
		function transformMat4(out, a, m) {
		  var x = a[0],
		      y = a[1],
		      z = a[2],
		      w = a[3];
		  out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
		  out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
		  out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
		  out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
		  return out;
		}
	
	/***/ }),
	/* 179 */
	/***/ (function(module, exports) {
	
		module.exports = transformQuat;
	
		/**
		 * Transforms the vec4 with a quat
		 *
		 * @param {vec4} out the receiving vector
		 * @param {vec4} a the vector to transform
		 * @param {quat} q quaternion to transform with
		 * @returns {vec4} out
		 */
		function transformQuat(out, a, q) {
		  var x = a[0],
		      y = a[1],
		      z = a[2],
		      qx = q[0],
		      qy = q[1],
		      qz = q[2],
		      qw = q[3],
	
	
		  // calculate quat * vec
		  ix = qw * x + qy * z - qz * y,
		      iy = qw * y + qz * x - qx * z,
		      iz = qw * z + qx * y - qy * x,
		      iw = -qx * x - qy * y - qz * z;
	
		  // calculate result * inverse quat
		  out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
		  out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
		  out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
		  out[3] = a[3];
		  return out;
		}
	
	/***/ }),
	/* 180 */
	/***/ (function(module, exports) {
	
		module.exports = function calc_spillover_triangles(params) {
	
		  var viz_dim = params.viz_dim;
	
		  var height_to_width = viz_dim.canvas.height / viz_dim.canvas.width;
		  var scaled_height = 0.5 / height_to_width;
	
		  var spillover_triangles = {};
		  spillover_triangles.mat = [
		  // left spillover rect
		  { 'pos': [[-1, 1], [-0.5, -1], [-1.0, -1]] }, { 'pos': [[-1, 1], [-0.5, 1], [-0.5, -1]] },
	
		  // right spillover rect
		  { 'pos': [[1, 1], [0.5, -1], [1.0, -1]] }, { 'pos': [[1, 1], [0.5, 1], [0.5, -1]] },
	
		  // top spillover rect
		  { 'pos': [[-0.5, 1], [-0.5, scaled_height], [0.5, 1]] }, { 'pos': [[0.5, 1], [0.5, scaled_height], [-0.5, scaled_height]] },
	
		  // bottom spillover rect
		  { 'pos': [[-0.5, -1], [-0.5, -scaled_height], [0.5, -1]] }, { 'pos': [[0.5, -1], [0.5, -scaled_height], [-0.5, -scaled_height]] }];
	
		  spillover_triangles.corners = [
		  // top-left spillover rect
		  { 'pos': [[-1, 1], [-0.5, scaled_height], [-1.0, scaled_height]] }, { 'pos': [[-1, 1], [-0.5, 1], [-0.5, scaled_height]] },
	
		  // bottom-left spillover rect
		  { 'pos': [[-1, -1], [-0.5, -scaled_height], [-1.0, -scaled_height]] }, { 'pos': [[-1, -1], [-0.5, -1], [-0.5, -scaled_height]] },
	
		  // top-right spillover rect
		  { 'pos': [[1, 1], [0.5, scaled_height], [1.0, scaled_height]] }, { 'pos': [[1, 1], [0.5, 1], [0.5, scaled_height]] },
	
		  // bottom-right spillover rect
		  { 'pos': [[1, -1], [0.5, -scaled_height], [1.0, -scaled_height]] }, { 'pos': [[1, -1], [0.5, -1], [0.5, -scaled_height]] }];
	
		  return spillover_triangles;
			};
	
	/***/ }),
	/* 181 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var make_draw_cells_buffers = __webpack_require__(182);
		var blend_info = __webpack_require__(183);
		var $ = __webpack_require__(184);
		var make_draw_cells_arr = __webpack_require__(185);
	
		module.exports = function make_matrix_args(regl, params) {
	
		  // generate position and opacity arrays from params.mat_data
		  params.arrs = make_draw_cells_arr(regl, params);
	
		  // transfer to buffers is slow
		  //////////////////////////////////////////
		  var buffers = make_draw_cells_buffers(regl, params.arrs.position_arr, params.arrs.opacity_arr);
	
		  var opacity_buffer = buffers.opacity_buffer;
		  var position_buffer = buffers.position_buffer;
	
		  // var num_row = params.num_row;
		  // var num_col = params.num_col;
	
		  /*
		    Temporarily use latest mat_data dimensions (working on downsampling)
		  */
		  var num_row = params.mat_data.length;
		  var num_col = params.mat_data[0].length;
	
		  // bottom half
		  var bottom_half_verts = [[1 / num_col, 0.0], [0.0, 0.0], [0.0, 1 / num_row]];
	
		  // top half
		  var top_half_verts = [[1 / num_col, 0.0], [1 / num_col, 1 / num_row], [0.0, 1 / num_row]];
	
		  var vert_string = `
		    precision highp float;
	
		    attribute vec2 position;
	
		    // These three are instanced attributes.
		    attribute vec2 pos_att;
		    attribute float opacity_att;
		    uniform mat4 zoom;
	
		    // pass varying variables to fragment from vector
		    varying float var_opacity;
	
		    void main() {
	
		      gl_Position = zoom *
		                    vec4( position.x + pos_att.x,
		                          position.y + pos_att.y,
		                          // positioned further down (spillover recst are
		                          // above at 0.5)
		                          0.75,
		                          1
		                        );
	
		      // pass attribute (in vert) to varying in frag
		      var_opacity = opacity_att;
	
		    }`;
	
		  var frag_string = `
		    precision highp float;
		    varying float var_opacity;
		    uniform vec3 inst_color;
		    varying vec3 tmp_color;
		    void main() {
	
		      // tmp_color = vec3(0, 0, 1);
	
		      // manually tweaking opacity range, will improve to match old version
	
		      if (var_opacity > 0.0){
		        gl_FragColor = vec4(1, 0, 0, abs(var_opacity) + 0.15);
		      } else {
		        gl_FragColor = vec4(0, 0, 1, abs(var_opacity) + 0.15);
		      }
	
		    }`;
	
		  var num_instances = params.arrs.position_arr.length;
	
		  // var zoom_function = function(context){
		  //   return context.view;
		  // };
	
		  var zoom_function = params.zoom_function;
	
		  var regl_props = {
		    vert: vert_string,
		    frag: frag_string,
		    attributes: {
		      position: '',
		      pos_att: {
		        buffer: position_buffer,
		        divisor: 1
		      },
		      opacity_att: {
		        buffer: opacity_buffer,
		        divisor: 1
		      }
		    },
		    blend: blend_info,
		    count: 3,
		    uniforms: {
		      zoom: zoom_function,
		      inst_color: [0, 0, 1]
		    },
		    instances: num_instances,
		    depth: {
		      enable: true,
		      mask: true,
		      func: 'less',
		      // func: 'greater',
		      range: [0, 1]
		    }
		  };
	
		  // draw top and bottom of matrix cells
		  //////////////////////////////////////
		  var draw_cells_props = {};
		  draw_cells_props.regl_props = {};
	
		  var top_props = $.extend(true, {}, regl_props);
		  top_props.attributes.position = top_half_verts;
		  draw_cells_props.regl_props.top = top_props;
	
		  var bot_props = $.extend(true, {}, regl_props);
		  bot_props.attributes.position = bottom_half_verts;
		  draw_cells_props.regl_props.bot = bot_props;
	
		  return draw_cells_props;
			};
	
	/***/ }),
	/* 182 */
	/***/ (function(module, exports) {
	
		
		module.exports = function make_draw_cells_buffers(regl, position_arr, opacity_arr) {
	
		  // Make Buffers
		  ///////////////////////////
		  var position_buffer = regl.buffer(position_arr);
	
		  const opacity_buffer = regl.buffer({
		    // length: opacity_arr.length,
		    type: 'float',
		    usage: 'dynamic'
		  });
	
		  opacity_buffer(opacity_arr);
	
		  var buffers = {};
		  buffers.opacity_buffer = opacity_buffer;
		  buffers.position_buffer = position_buffer;
	
		  return buffers;
		};
	
	/***/ }),
	/* 183 */
	/***/ (function(module, exports) {
	
		module.exports = {
		  enable: true,
		  func: {
		    srcRGB: 'src alpha',
		    srcAlpha: 'src color',
		    dstRGB: 'one',
		    dstAlpha: 'one'
		    // src: 'one',
		    // dst: 'one'
		  },
		  equation: 'add',
		  color: [0, 0, 0, 0]
			};
	
	/***/ }),
	/* 184 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
		 * jQuery JavaScript Library v3.3.1
		 * https://jquery.com/
		 *
		 * Includes Sizzle.js
		 * https://sizzlejs.com/
		 *
		 * Copyright JS Foundation and other contributors
		 * Released under the MIT license
		 * https://jquery.org/license
		 *
		 * Date: 2018-01-20T17:24Z
		 */
		(function (global, factory) {
	
			"use strict";
	
			if (typeof module === "object" && typeof module.exports === "object") {
	
				// For CommonJS and CommonJS-like environments where a proper `window`
				// is present, execute the factory and get jQuery.
				// For environments that do not have a `window` with a `document`
				// (such as Node.js), expose a factory as module.exports.
				// This accentuates the need for the creation of a real `window`.
				// e.g. var jQuery = require("jquery")(window);
				// See ticket #14549 for more info.
				module.exports = global.document ? factory(global, true) : function (w) {
					if (!w.document) {
						throw new Error("jQuery requires a window with a document");
					}
					return factory(w);
				};
			} else {
				factory(global);
			}
	
			// Pass this if window is not defined yet
		})(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
	
			// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
			// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
			// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
			// enough that all such attempts are guarded in a try block.
			"use strict";
	
			var arr = [];
	
			var document = window.document;
	
			var getProto = Object.getPrototypeOf;
	
			var slice = arr.slice;
	
			var concat = arr.concat;
	
			var push = arr.push;
	
			var indexOf = arr.indexOf;
	
			var class2type = {};
	
			var toString = class2type.toString;
	
			var hasOwn = class2type.hasOwnProperty;
	
			var fnToString = hasOwn.toString;
	
			var ObjectFunctionString = fnToString.call(Object);
	
			var support = {};
	
			var isFunction = function isFunction(obj) {
	
				// Support: Chrome <=57, Firefox <=52
				// In some browsers, typeof returns "function" for HTML <object> elements
				// (i.e., `typeof document.createElement( "object" ) === "function"`).
				// We don't want to classify *any* DOM node as a function.
				return typeof obj === "function" && typeof obj.nodeType !== "number";
			};
	
			var isWindow = function isWindow(obj) {
				return obj != null && obj === obj.window;
			};
	
			var preservedScriptAttributes = {
				type: true,
				src: true,
				noModule: true
			};
	
			function DOMEval(code, doc, node) {
				doc = doc || document;
	
				var i,
				    script = doc.createElement("script");
	
				script.text = code;
				if (node) {
					for (i in preservedScriptAttributes) {
						if (node[i]) {
							script[i] = node[i];
						}
					}
				}
				doc.head.appendChild(script).parentNode.removeChild(script);
			}
	
			function toType(obj) {
				if (obj == null) {
					return obj + "";
				}
	
				// Support: Android <=2.3 only (functionish RegExp)
				return typeof obj === "object" || typeof obj === "function" ? class2type[toString.call(obj)] || "object" : typeof obj;
			}
			/* global Symbol */
			// Defining this global in .eslintrc.json would create a danger of using the global
			// unguarded in another place, it seems safer to define global only for this module
	
	
			var version = "3.3.1",
	
	
			// Define a local copy of jQuery
			jQuery = function (selector, context) {
	
				// The jQuery object is actually just the init constructor 'enhanced'
				// Need init if jQuery is called (just allow error to be thrown if not included)
				return new jQuery.fn.init(selector, context);
			},
	
	
			// Support: Android <=4.0 only
			// Make sure we trim BOM and NBSP
			rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
	
			jQuery.fn = jQuery.prototype = {
	
				// The current version of jQuery being used
				jquery: version,
	
				constructor: jQuery,
	
				// The default length of a jQuery object is 0
				length: 0,
	
				toArray: function () {
					return slice.call(this);
				},
	
				// Get the Nth element in the matched element set OR
				// Get the whole matched element set as a clean array
				get: function (num) {
	
					// Return all the elements in a clean array
					if (num == null) {
						return slice.call(this);
					}
	
					// Return just the one element from the set
					return num < 0 ? this[num + this.length] : this[num];
				},
	
				// Take an array of elements and push it onto the stack
				// (returning the new matched element set)
				pushStack: function (elems) {
	
					// Build a new jQuery matched element set
					var ret = jQuery.merge(this.constructor(), elems);
	
					// Add the old object onto the stack (as a reference)
					ret.prevObject = this;
	
					// Return the newly-formed element set
					return ret;
				},
	
				// Execute a callback for every element in the matched set.
				each: function (callback) {
					return jQuery.each(this, callback);
				},
	
				map: function (callback) {
					return this.pushStack(jQuery.map(this, function (elem, i) {
						return callback.call(elem, i, elem);
					}));
				},
	
				slice: function () {
					return this.pushStack(slice.apply(this, arguments));
				},
	
				first: function () {
					return this.eq(0);
				},
	
				last: function () {
					return this.eq(-1);
				},
	
				eq: function (i) {
					var len = this.length,
					    j = +i + (i < 0 ? len : 0);
					return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
				},
	
				end: function () {
					return this.prevObject || this.constructor();
				},
	
				// For internal use only.
				// Behaves like an Array's method, not like a jQuery method.
				push: push,
				sort: arr.sort,
				splice: arr.splice
			};
	
			jQuery.extend = jQuery.fn.extend = function () {
				var options,
				    name,
				    src,
				    copy,
				    copyIsArray,
				    clone,
				    target = arguments[0] || {},
				    i = 1,
				    length = arguments.length,
				    deep = false;
	
				// Handle a deep copy situation
				if (typeof target === "boolean") {
					deep = target;
	
					// Skip the boolean and the target
					target = arguments[i] || {};
					i++;
				}
	
				// Handle case when target is a string or something (possible in deep copy)
				if (typeof target !== "object" && !isFunction(target)) {
					target = {};
				}
	
				// Extend jQuery itself if only one argument is passed
				if (i === length) {
					target = this;
					i--;
				}
	
				for (; i < length; i++) {
	
					// Only deal with non-null/undefined values
					if ((options = arguments[i]) != null) {
	
						// Extend the base object
						for (name in options) {
							src = target[name];
							copy = options[name];
	
							// Prevent never-ending loop
							if (target === copy) {
								continue;
							}
	
							// Recurse if we're merging plain objects or arrays
							if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
	
								if (copyIsArray) {
									copyIsArray = false;
									clone = src && Array.isArray(src) ? src : [];
								} else {
									clone = src && jQuery.isPlainObject(src) ? src : {};
								}
	
								// Never move original objects, clone them
								target[name] = jQuery.extend(deep, clone, copy);
	
								// Don't bring in undefined values
							} else if (copy !== undefined) {
								target[name] = copy;
							}
						}
					}
				}
	
				// Return the modified object
				return target;
			};
	
			jQuery.extend({
	
				// Unique for each copy of jQuery on the page
				expando: "jQuery" + (version + Math.random()).replace(/\D/g, ""),
	
				// Assume jQuery is ready without the ready module
				isReady: true,
	
				error: function (msg) {
					throw new Error(msg);
				},
	
				noop: function () {},
	
				isPlainObject: function (obj) {
					var proto, Ctor;
	
					// Detect obvious negatives
					// Use toString instead of jQuery.type to catch host objects
					if (!obj || toString.call(obj) !== "[object Object]") {
						return false;
					}
	
					proto = getProto(obj);
	
					// Objects with no prototype (e.g., `Object.create( null )`) are plain
					if (!proto) {
						return true;
					}
	
					// Objects with prototype are plain iff they were constructed by a global Object function
					Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
					return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
				},
	
				isEmptyObject: function (obj) {
	
					/* eslint-disable no-unused-vars */
					// See https://github.com/eslint/eslint/issues/6125
					var name;
	
					for (name in obj) {
						return false;
					}
					return true;
				},
	
				// Evaluates a script in a global context
				globalEval: function (code) {
					DOMEval(code);
				},
	
				each: function (obj, callback) {
					var length,
					    i = 0;
	
					if (isArrayLike(obj)) {
						length = obj.length;
						for (; i < length; i++) {
							if (callback.call(obj[i], i, obj[i]) === false) {
								break;
							}
						}
					} else {
						for (i in obj) {
							if (callback.call(obj[i], i, obj[i]) === false) {
								break;
							}
						}
					}
	
					return obj;
				},
	
				// Support: Android <=4.0 only
				trim: function (text) {
					return text == null ? "" : (text + "").replace(rtrim, "");
				},
	
				// results is for internal usage only
				makeArray: function (arr, results) {
					var ret = results || [];
	
					if (arr != null) {
						if (isArrayLike(Object(arr))) {
							jQuery.merge(ret, typeof arr === "string" ? [arr] : arr);
						} else {
							push.call(ret, arr);
						}
					}
	
					return ret;
				},
	
				inArray: function (elem, arr, i) {
					return arr == null ? -1 : indexOf.call(arr, elem, i);
				},
	
				// Support: Android <=4.0 only, PhantomJS 1 only
				// push.apply(_, arraylike) throws on ancient WebKit
				merge: function (first, second) {
					var len = +second.length,
					    j = 0,
					    i = first.length;
	
					for (; j < len; j++) {
						first[i++] = second[j];
					}
	
					first.length = i;
	
					return first;
				},
	
				grep: function (elems, callback, invert) {
					var callbackInverse,
					    matches = [],
					    i = 0,
					    length = elems.length,
					    callbackExpect = !invert;
	
					// Go through the array, only saving the items
					// that pass the validator function
					for (; i < length; i++) {
						callbackInverse = !callback(elems[i], i);
						if (callbackInverse !== callbackExpect) {
							matches.push(elems[i]);
						}
					}
	
					return matches;
				},
	
				// arg is for internal usage only
				map: function (elems, callback, arg) {
					var length,
					    value,
					    i = 0,
					    ret = [];
	
					// Go through the array, translating each of the items to their new values
					if (isArrayLike(elems)) {
						length = elems.length;
						for (; i < length; i++) {
							value = callback(elems[i], i, arg);
	
							if (value != null) {
								ret.push(value);
							}
						}
	
						// Go through every key on the object,
					} else {
						for (i in elems) {
							value = callback(elems[i], i, arg);
	
							if (value != null) {
								ret.push(value);
							}
						}
					}
	
					// Flatten any nested arrays
					return concat.apply([], ret);
				},
	
				// A global GUID counter for objects
				guid: 1,
	
				// jQuery.support is not used in Core but other projects attach their
				// properties to it so it needs to exist.
				support: support
			});
	
			if (typeof Symbol === "function") {
				jQuery.fn[Symbol.iterator] = arr[Symbol.iterator];
			}
	
			// Populate the class2type map
			jQuery.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "), function (i, name) {
				class2type["[object " + name + "]"] = name.toLowerCase();
			});
	
			function isArrayLike(obj) {
	
				// Support: real iOS 8.2 only (not reproducible in simulator)
				// `in` check used to prevent JIT error (gh-2145)
				// hasOwn isn't used here due to false negatives
				// regarding Nodelist length in IE
				var length = !!obj && "length" in obj && obj.length,
				    type = toType(obj);
	
				if (isFunction(obj) || isWindow(obj)) {
					return false;
				}
	
				return type === "array" || length === 0 || typeof length === "number" && length > 0 && length - 1 in obj;
			}
			var Sizzle =
			/*!
		  * Sizzle CSS Selector Engine v2.3.3
		  * https://sizzlejs.com/
		  *
		  * Copyright jQuery Foundation and other contributors
		  * Released under the MIT license
		  * http://jquery.org/license
		  *
		  * Date: 2016-08-08
		  */
			function (window) {
	
				var i,
				    support,
				    Expr,
				    getText,
				    isXML,
				    tokenize,
				    compile,
				    select,
				    outermostContext,
				    sortInput,
				    hasDuplicate,
	
	
				// Local document vars
				setDocument,
				    document,
				    docElem,
				    documentIsHTML,
				    rbuggyQSA,
				    rbuggyMatches,
				    matches,
				    contains,
	
	
				// Instance-specific data
				expando = "sizzle" + 1 * new Date(),
				    preferredDoc = window.document,
				    dirruns = 0,
				    done = 0,
				    classCache = createCache(),
				    tokenCache = createCache(),
				    compilerCache = createCache(),
				    sortOrder = function (a, b) {
					if (a === b) {
						hasDuplicate = true;
					}
					return 0;
				},
	
	
				// Instance methods
				hasOwn = {}.hasOwnProperty,
				    arr = [],
				    pop = arr.pop,
				    push_native = arr.push,
				    push = arr.push,
				    slice = arr.slice,
	
				// Use a stripped-down indexOf as it's faster than native
				// https://jsperf.com/thor-indexof-vs-for/5
				indexOf = function (list, elem) {
					var i = 0,
					    len = list.length;
					for (; i < len; i++) {
						if (list[i] === elem) {
							return i;
						}
					}
					return -1;
				},
				    booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
	
	
				// Regular expressions
	
				// http://www.w3.org/TR/css3-selectors/#whitespace
				whitespace = "[\\x20\\t\\r\\n\\f]",
	
	
				// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
				identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
	
	
				// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
				attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
				// Operator (capture 2)
				"*([*^$|!~]?=)" + whitespace +
				// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
				"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]",
				    pseudos = ":(" + identifier + ")(?:\\((" +
				// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
				// 1. quoted (capture 3; capture 4 or capture 5)
				"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
				// 2. simple (capture 6)
				"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
				// 3. anything else (capture 2)
				".*" + ")\\)|)",
	
	
				// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
				rwhitespace = new RegExp(whitespace + "+", "g"),
				    rtrim = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g"),
				    rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*"),
				    rcombinators = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*"),
				    rattributeQuotes = new RegExp("=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g"),
				    rpseudo = new RegExp(pseudos),
				    ridentifier = new RegExp("^" + identifier + "$"),
				    matchExpr = {
					"ID": new RegExp("^#(" + identifier + ")"),
					"CLASS": new RegExp("^\\.(" + identifier + ")"),
					"TAG": new RegExp("^(" + identifier + "|[*])"),
					"ATTR": new RegExp("^" + attributes),
					"PSEUDO": new RegExp("^" + pseudos),
					"CHILD": new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i"),
					"bool": new RegExp("^(?:" + booleans + ")$", "i"),
					// For use in libraries implementing .is()
					// We use this for POS matching in `select`
					"needsContext": new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i")
				},
				    rinputs = /^(?:input|select|textarea|button)$/i,
				    rheader = /^h\d$/i,
				    rnative = /^[^{]+\{\s*\[native \w/,
	
	
				// Easily-parseable/retrievable ID or TAG or CLASS selectors
				rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
				    rsibling = /[+~]/,
	
	
				// CSS escapes
				// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
				runescape = new RegExp("\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig"),
				    funescape = function (_, escaped, escapedWhitespace) {
					var high = "0x" + escaped - 0x10000;
					// NaN means non-codepoint
					// Support: Firefox<24
					// Workaround erroneous numeric interpretation of +"0x"
					return high !== high || escapedWhitespace ? escaped : high < 0 ?
					// BMP codepoint
					String.fromCharCode(high + 0x10000) :
					// Supplemental Plane codepoint (surrogate pair)
					String.fromCharCode(high >> 10 | 0xD800, high & 0x3FF | 0xDC00);
				},
	
	
				// CSS string/identifier serialization
				// https://drafts.csswg.org/cssom/#common-serializing-idioms
				rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
				    fcssescape = function (ch, asCodePoint) {
					if (asCodePoint) {
	
						// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
						if (ch === "\0") {
							return "\uFFFD";
						}
	
						// Control characters and (dependent upon position) numbers get escaped as code points
						return ch.slice(0, -1) + "\\" + ch.charCodeAt(ch.length - 1).toString(16) + " ";
					}
	
					// Other potentially-special ASCII characters get backslash-escaped
					return "\\" + ch;
				},
	
	
				// Used for iframes
				// See setDocument()
				// Removing the function wrapper causes a "Permission Denied"
				// error in IE
				unloadHandler = function () {
					setDocument();
				},
				    disabledAncestor = addCombinator(function (elem) {
					return elem.disabled === true && ("form" in elem || "label" in elem);
				}, { dir: "parentNode", next: "legend" });
	
				// Optimize for push.apply( _, NodeList )
				try {
					push.apply(arr = slice.call(preferredDoc.childNodes), preferredDoc.childNodes);
					// Support: Android<4.0
					// Detect silently failing push.apply
					arr[preferredDoc.childNodes.length].nodeType;
				} catch (e) {
					push = { apply: arr.length ?
	
						// Leverage slice if possible
						function (target, els) {
							push_native.apply(target, slice.call(els));
						} :
	
						// Support: IE<9
						// Otherwise append directly
						function (target, els) {
							var j = target.length,
							    i = 0;
							// Can't trust NodeList.length
							while (target[j++] = els[i++]) {}
							target.length = j - 1;
						}
					};
				}
	
				function Sizzle(selector, context, results, seed) {
					var m,
					    i,
					    elem,
					    nid,
					    match,
					    groups,
					    newSelector,
					    newContext = context && context.ownerDocument,
	
	
					// nodeType defaults to 9, since context defaults to document
					nodeType = context ? context.nodeType : 9;
	
					results = results || [];
	
					// Return early from calls with invalid selector or context
					if (typeof selector !== "string" || !selector || nodeType !== 1 && nodeType !== 9 && nodeType !== 11) {
	
						return results;
					}
	
					// Try to shortcut find operations (as opposed to filters) in HTML documents
					if (!seed) {
	
						if ((context ? context.ownerDocument || context : preferredDoc) !== document) {
							setDocument(context);
						}
						context = context || document;
	
						if (documentIsHTML) {
	
							// If the selector is sufficiently simple, try using a "get*By*" DOM method
							// (excepting DocumentFragment context, where the methods don't exist)
							if (nodeType !== 11 && (match = rquickExpr.exec(selector))) {
	
								// ID selector
								if (m = match[1]) {
	
									// Document context
									if (nodeType === 9) {
										if (elem = context.getElementById(m)) {
	
											// Support: IE, Opera, Webkit
											// TODO: identify versions
											// getElementById can match elements by name instead of ID
											if (elem.id === m) {
												results.push(elem);
												return results;
											}
										} else {
											return results;
										}
	
										// Element context
									} else {
	
										// Support: IE, Opera, Webkit
										// TODO: identify versions
										// getElementById can match elements by name instead of ID
										if (newContext && (elem = newContext.getElementById(m)) && contains(context, elem) && elem.id === m) {
	
											results.push(elem);
											return results;
										}
									}
	
									// Type selector
								} else if (match[2]) {
									push.apply(results, context.getElementsByTagName(selector));
									return results;
	
									// Class selector
								} else if ((m = match[3]) && support.getElementsByClassName && context.getElementsByClassName) {
	
									push.apply(results, context.getElementsByClassName(m));
									return results;
								}
							}
	
							// Take advantage of querySelectorAll
							if (support.qsa && !compilerCache[selector + " "] && (!rbuggyQSA || !rbuggyQSA.test(selector))) {
	
								if (nodeType !== 1) {
									newContext = context;
									newSelector = selector;
	
									// qSA looks outside Element context, which is not what we want
									// Thanks to Andrew Dupont for this workaround technique
									// Support: IE <=8
									// Exclude object elements
								} else if (context.nodeName.toLowerCase() !== "object") {
	
									// Capture the context ID, setting it first if necessary
									if (nid = context.getAttribute("id")) {
										nid = nid.replace(rcssescape, fcssescape);
									} else {
										context.setAttribute("id", nid = expando);
									}
	
									// Prefix every selector in the list
									groups = tokenize(selector);
									i = groups.length;
									while (i--) {
										groups[i] = "#" + nid + " " + toSelector(groups[i]);
									}
									newSelector = groups.join(",");
	
									// Expand context for sibling selectors
									newContext = rsibling.test(selector) && testContext(context.parentNode) || context;
								}
	
								if (newSelector) {
									try {
										push.apply(results, newContext.querySelectorAll(newSelector));
										return results;
									} catch (qsaError) {} finally {
										if (nid === expando) {
											context.removeAttribute("id");
										}
									}
								}
							}
						}
					}
	
					// All others
					return select(selector.replace(rtrim, "$1"), context, results, seed);
				}
	
				/**
		   * Create key-value caches of limited size
		   * @returns {function(string, object)} Returns the Object data after storing it on itself with
		   *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
		   *	deleting the oldest entry
		   */
				function createCache() {
					var keys = [];
	
					function cache(key, value) {
						// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
						if (keys.push(key + " ") > Expr.cacheLength) {
							// Only keep the most recent entries
							delete cache[keys.shift()];
						}
						return cache[key + " "] = value;
					}
					return cache;
				}
	
				/**
		   * Mark a function for special use by Sizzle
		   * @param {Function} fn The function to mark
		   */
				function markFunction(fn) {
					fn[expando] = true;
					return fn;
				}
	
				/**
		   * Support testing using an element
		   * @param {Function} fn Passed the created element and returns a boolean result
		   */
				function assert(fn) {
					var el = document.createElement("fieldset");
	
					try {
						return !!fn(el);
					} catch (e) {
						return false;
					} finally {
						// Remove from its parent by default
						if (el.parentNode) {
							el.parentNode.removeChild(el);
						}
						// release memory in IE
						el = null;
					}
				}
	
				/**
		   * Adds the same handler for all of the specified attrs
		   * @param {String} attrs Pipe-separated list of attributes
		   * @param {Function} handler The method that will be applied
		   */
				function addHandle(attrs, handler) {
					var arr = attrs.split("|"),
					    i = arr.length;
	
					while (i--) {
						Expr.attrHandle[arr[i]] = handler;
					}
				}
	
				/**
		   * Checks document order of two siblings
		   * @param {Element} a
		   * @param {Element} b
		   * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
		   */
				function siblingCheck(a, b) {
					var cur = b && a,
					    diff = cur && a.nodeType === 1 && b.nodeType === 1 && a.sourceIndex - b.sourceIndex;
	
					// Use IE sourceIndex if available on both nodes
					if (diff) {
						return diff;
					}
	
					// Check if b follows a
					if (cur) {
						while (cur = cur.nextSibling) {
							if (cur === b) {
								return -1;
							}
						}
					}
	
					return a ? 1 : -1;
				}
	
				/**
		   * Returns a function to use in pseudos for input types
		   * @param {String} type
		   */
				function createInputPseudo(type) {
					return function (elem) {
						var name = elem.nodeName.toLowerCase();
						return name === "input" && elem.type === type;
					};
				}
	
				/**
		   * Returns a function to use in pseudos for buttons
		   * @param {String} type
		   */
				function createButtonPseudo(type) {
					return function (elem) {
						var name = elem.nodeName.toLowerCase();
						return (name === "input" || name === "button") && elem.type === type;
					};
				}
	
				/**
		   * Returns a function to use in pseudos for :enabled/:disabled
		   * @param {Boolean} disabled true for :disabled; false for :enabled
		   */
				function createDisabledPseudo(disabled) {
	
					// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
					return function (elem) {
	
						// Only certain elements can match :enabled or :disabled
						// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
						// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
						if ("form" in elem) {
	
							// Check for inherited disabledness on relevant non-disabled elements:
							// * listed form-associated elements in a disabled fieldset
							//   https://html.spec.whatwg.org/multipage/forms.html#category-listed
							//   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
							// * option elements in a disabled optgroup
							//   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
							// All such elements have a "form" property.
							if (elem.parentNode && elem.disabled === false) {
	
								// Option elements defer to a parent optgroup if present
								if ("label" in elem) {
									if ("label" in elem.parentNode) {
										return elem.parentNode.disabled === disabled;
									} else {
										return elem.disabled === disabled;
									}
								}
	
								// Support: IE 6 - 11
								// Use the isDisabled shortcut property to check for disabled fieldset ancestors
								return elem.isDisabled === disabled ||
	
								// Where there is no isDisabled, check manually
								/* jshint -W018 */
								elem.isDisabled !== !disabled && disabledAncestor(elem) === disabled;
							}
	
							return elem.disabled === disabled;
	
							// Try to winnow out elements that can't be disabled before trusting the disabled property.
							// Some victims get caught in our net (label, legend, menu, track), but it shouldn't
							// even exist on them, let alone have a boolean value.
						} else if ("label" in elem) {
							return elem.disabled === disabled;
						}
	
						// Remaining elements are neither :enabled nor :disabled
						return false;
					};
				}
	
				/**
		   * Returns a function to use in pseudos for positionals
		   * @param {Function} fn
		   */
				function createPositionalPseudo(fn) {
					return markFunction(function (argument) {
						argument = +argument;
						return markFunction(function (seed, matches) {
							var j,
							    matchIndexes = fn([], seed.length, argument),
							    i = matchIndexes.length;
	
							// Match elements found at the specified indexes
							while (i--) {
								if (seed[j = matchIndexes[i]]) {
									seed[j] = !(matches[j] = seed[j]);
								}
							}
						});
					});
				}
	
				/**
		   * Checks a node for validity as a Sizzle context
		   * @param {Element|Object=} context
		   * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
		   */
				function testContext(context) {
					return context && typeof context.getElementsByTagName !== "undefined" && context;
				}
	
				// Expose support vars for convenience
				support = Sizzle.support = {};
	
				/**
		   * Detects XML nodes
		   * @param {Element|Object} elem An element or a document
		   * @returns {Boolean} True iff elem is a non-HTML XML node
		   */
				isXML = Sizzle.isXML = function (elem) {
					// documentElement is verified for cases where it doesn't yet exist
					// (such as loading iframes in IE - #4833)
					var documentElement = elem && (elem.ownerDocument || elem).documentElement;
					return documentElement ? documentElement.nodeName !== "HTML" : false;
				};
	
				/**
		   * Sets document-related variables once based on the current document
		   * @param {Element|Object} [doc] An element or document object to use to set the document
		   * @returns {Object} Returns the current document
		   */
				setDocument = Sizzle.setDocument = function (node) {
					var hasCompare,
					    subWindow,
					    doc = node ? node.ownerDocument || node : preferredDoc;
	
					// Return early if doc is invalid or already selected
					if (doc === document || doc.nodeType !== 9 || !doc.documentElement) {
						return document;
					}
	
					// Update global variables
					document = doc;
					docElem = document.documentElement;
					documentIsHTML = !isXML(document);
	
					// Support: IE 9-11, Edge
					// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
					if (preferredDoc !== document && (subWindow = document.defaultView) && subWindow.top !== subWindow) {
	
						// Support: IE 11, Edge
						if (subWindow.addEventListener) {
							subWindow.addEventListener("unload", unloadHandler, false);
	
							// Support: IE 9 - 10 only
						} else if (subWindow.attachEvent) {
							subWindow.attachEvent("onunload", unloadHandler);
						}
					}
	
					/* Attributes
		   ---------------------------------------------------------------------- */
	
					// Support: IE<8
					// Verify that getAttribute really returns attributes and not properties
					// (excepting IE8 booleans)
					support.attributes = assert(function (el) {
						el.className = "i";
						return !el.getAttribute("className");
					});
	
					/* getElement(s)By*
		   ---------------------------------------------------------------------- */
	
					// Check if getElementsByTagName("*") returns only elements
					support.getElementsByTagName = assert(function (el) {
						el.appendChild(document.createComment(""));
						return !el.getElementsByTagName("*").length;
					});
	
					// Support: IE<9
					support.getElementsByClassName = rnative.test(document.getElementsByClassName);
	
					// Support: IE<10
					// Check if getElementById returns elements by name
					// The broken getElementById methods don't pick up programmatically-set names,
					// so use a roundabout getElementsByName test
					support.getById = assert(function (el) {
						docElem.appendChild(el).id = expando;
						return !document.getElementsByName || !document.getElementsByName(expando).length;
					});
	
					// ID filter and find
					if (support.getById) {
						Expr.filter["ID"] = function (id) {
							var attrId = id.replace(runescape, funescape);
							return function (elem) {
								return elem.getAttribute("id") === attrId;
							};
						};
						Expr.find["ID"] = function (id, context) {
							if (typeof context.getElementById !== "undefined" && documentIsHTML) {
								var elem = context.getElementById(id);
								return elem ? [elem] : [];
							}
						};
					} else {
						Expr.filter["ID"] = function (id) {
							var attrId = id.replace(runescape, funescape);
							return function (elem) {
								var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
								return node && node.value === attrId;
							};
						};
	
						// Support: IE 6 - 7 only
						// getElementById is not reliable as a find shortcut
						Expr.find["ID"] = function (id, context) {
							if (typeof context.getElementById !== "undefined" && documentIsHTML) {
								var node,
								    i,
								    elems,
								    elem = context.getElementById(id);
	
								if (elem) {
	
									// Verify the id attribute
									node = elem.getAttributeNode("id");
									if (node && node.value === id) {
										return [elem];
									}
	
									// Fall back on getElementsByName
									elems = context.getElementsByName(id);
									i = 0;
									while (elem = elems[i++]) {
										node = elem.getAttributeNode("id");
										if (node && node.value === id) {
											return [elem];
										}
									}
								}
	
								return [];
							}
						};
					}
	
					// Tag
					Expr.find["TAG"] = support.getElementsByTagName ? function (tag, context) {
						if (typeof context.getElementsByTagName !== "undefined") {
							return context.getElementsByTagName(tag);
	
							// DocumentFragment nodes don't have gEBTN
						} else if (support.qsa) {
							return context.querySelectorAll(tag);
						}
					} : function (tag, context) {
						var elem,
						    tmp = [],
						    i = 0,
	
						// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
						results = context.getElementsByTagName(tag);
	
						// Filter out possible comments
						if (tag === "*") {
							while (elem = results[i++]) {
								if (elem.nodeType === 1) {
									tmp.push(elem);
								}
							}
	
							return tmp;
						}
						return results;
					};
	
					// Class
					Expr.find["CLASS"] = support.getElementsByClassName && function (className, context) {
						if (typeof context.getElementsByClassName !== "undefined" && documentIsHTML) {
							return context.getElementsByClassName(className);
						}
					};
	
					/* QSA/matchesSelector
		   ---------------------------------------------------------------------- */
	
					// QSA and matchesSelector support
	
					// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
					rbuggyMatches = [];
	
					// qSa(:focus) reports false when true (Chrome 21)
					// We allow this because of a bug in IE8/9 that throws an error
					// whenever `document.activeElement` is accessed on an iframe
					// So, we allow :focus to pass through QSA all the time to avoid the IE error
					// See https://bugs.jquery.com/ticket/13378
					rbuggyQSA = [];
	
					if (support.qsa = rnative.test(document.querySelectorAll)) {
						// Build QSA regex
						// Regex strategy adopted from Diego Perini
						assert(function (el) {
							// Select is set to empty string on purpose
							// This is to test IE's treatment of not explicitly
							// setting a boolean content attribute,
							// since its presence should be enough
							// https://bugs.jquery.com/ticket/12359
							docElem.appendChild(el).innerHTML = "<a id='" + expando + "'></a>" + "<select id='" + expando + "-\r\\' msallowcapture=''>" + "<option selected=''></option></select>";
	
							// Support: IE8, Opera 11-12.16
							// Nothing should be selected when empty strings follow ^= or $= or *=
							// The test attribute must be unknown in Opera but "safe" for WinRT
							// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
							if (el.querySelectorAll("[msallowcapture^='']").length) {
								rbuggyQSA.push("[*^$]=" + whitespace + "*(?:''|\"\")");
							}
	
							// Support: IE8
							// Boolean attributes and "value" are not treated correctly
							if (!el.querySelectorAll("[selected]").length) {
								rbuggyQSA.push("\\[" + whitespace + "*(?:value|" + booleans + ")");
							}
	
							// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
							if (!el.querySelectorAll("[id~=" + expando + "-]").length) {
								rbuggyQSA.push("~=");
							}
	
							// Webkit/Opera - :checked should return selected option elements
							// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
							// IE8 throws error here and will not see later tests
							if (!el.querySelectorAll(":checked").length) {
								rbuggyQSA.push(":checked");
							}
	
							// Support: Safari 8+, iOS 8+
							// https://bugs.webkit.org/show_bug.cgi?id=136851
							// In-page `selector#id sibling-combinator selector` fails
							if (!el.querySelectorAll("a#" + expando + "+*").length) {
								rbuggyQSA.push(".#.+[+~]");
							}
						});
	
						assert(function (el) {
							el.innerHTML = "<a href='' disabled='disabled'></a>" + "<select disabled='disabled'><option/></select>";
	
							// Support: Windows 8 Native Apps
							// The type and name attributes are restricted during .innerHTML assignment
							var input = document.createElement("input");
							input.setAttribute("type", "hidden");
							el.appendChild(input).setAttribute("name", "D");
	
							// Support: IE8
							// Enforce case-sensitivity of name attribute
							if (el.querySelectorAll("[name=d]").length) {
								rbuggyQSA.push("name" + whitespace + "*[*^$|!~]?=");
							}
	
							// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
							// IE8 throws error here and will not see later tests
							if (el.querySelectorAll(":enabled").length !== 2) {
								rbuggyQSA.push(":enabled", ":disabled");
							}
	
							// Support: IE9-11+
							// IE's :disabled selector does not pick up the children of disabled fieldsets
							docElem.appendChild(el).disabled = true;
							if (el.querySelectorAll(":disabled").length !== 2) {
								rbuggyQSA.push(":enabled", ":disabled");
							}
	
							// Opera 10-11 does not throw on post-comma invalid pseudos
							el.querySelectorAll("*,:x");
							rbuggyQSA.push(",.*:");
						});
					}
	
					if (support.matchesSelector = rnative.test(matches = docElem.matches || docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || docElem.msMatchesSelector)) {
	
						assert(function (el) {
							// Check to see if it's possible to do matchesSelector
							// on a disconnected node (IE 9)
							support.disconnectedMatch = matches.call(el, "*");
	
							// This should fail with an exception
							// Gecko does not error, returns false instead
							matches.call(el, "[s!='']:x");
							rbuggyMatches.push("!=", pseudos);
						});
					}
	
					rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|"));
					rbuggyMatches = rbuggyMatches.length && new RegExp(rbuggyMatches.join("|"));
	
					/* Contains
		   ---------------------------------------------------------------------- */
					hasCompare = rnative.test(docElem.compareDocumentPosition);
	
					// Element contains another
					// Purposefully self-exclusive
					// As in, an element does not contain itself
					contains = hasCompare || rnative.test(docElem.contains) ? function (a, b) {
						var adown = a.nodeType === 9 ? a.documentElement : a,
						    bup = b && b.parentNode;
						return a === bup || !!(bup && bup.nodeType === 1 && (adown.contains ? adown.contains(bup) : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16));
					} : function (a, b) {
						if (b) {
							while (b = b.parentNode) {
								if (b === a) {
									return true;
								}
							}
						}
						return false;
					};
	
					/* Sorting
		   ---------------------------------------------------------------------- */
	
					// Document order sorting
					sortOrder = hasCompare ? function (a, b) {
	
						// Flag for duplicate removal
						if (a === b) {
							hasDuplicate = true;
							return 0;
						}
	
						// Sort on method existence if only one input has compareDocumentPosition
						var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
						if (compare) {
							return compare;
						}
	
						// Calculate position if both inputs belong to the same document
						compare = (a.ownerDocument || a) === (b.ownerDocument || b) ? a.compareDocumentPosition(b) :
	
						// Otherwise we know they are disconnected
						1;
	
						// Disconnected nodes
						if (compare & 1 || !support.sortDetached && b.compareDocumentPosition(a) === compare) {
	
							// Choose the first element that is related to our preferred document
							if (a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a)) {
								return -1;
							}
							if (b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b)) {
								return 1;
							}
	
							// Maintain original order
							return sortInput ? indexOf(sortInput, a) - indexOf(sortInput, b) : 0;
						}
	
						return compare & 4 ? -1 : 1;
					} : function (a, b) {
						// Exit early if the nodes are identical
						if (a === b) {
							hasDuplicate = true;
							return 0;
						}
	
						var cur,
						    i = 0,
						    aup = a.parentNode,
						    bup = b.parentNode,
						    ap = [a],
						    bp = [b];
	
						// Parentless nodes are either documents or disconnected
						if (!aup || !bup) {
							return a === document ? -1 : b === document ? 1 : aup ? -1 : bup ? 1 : sortInput ? indexOf(sortInput, a) - indexOf(sortInput, b) : 0;
	
							// If the nodes are siblings, we can do a quick check
						} else if (aup === bup) {
							return siblingCheck(a, b);
						}
	
						// Otherwise we need full lists of their ancestors for comparison
						cur = a;
						while (cur = cur.parentNode) {
							ap.unshift(cur);
						}
						cur = b;
						while (cur = cur.parentNode) {
							bp.unshift(cur);
						}
	
						// Walk down the tree looking for a discrepancy
						while (ap[i] === bp[i]) {
							i++;
						}
	
						return i ?
						// Do a sibling check if the nodes have a common ancestor
						siblingCheck(ap[i], bp[i]) :
	
						// Otherwise nodes in our document sort first
						ap[i] === preferredDoc ? -1 : bp[i] === preferredDoc ? 1 : 0;
					};
	
					return document;
				};
	
				Sizzle.matches = function (expr, elements) {
					return Sizzle(expr, null, null, elements);
				};
	
				Sizzle.matchesSelector = function (elem, expr) {
					// Set document vars if needed
					if ((elem.ownerDocument || elem) !== document) {
						setDocument(elem);
					}
	
					// Make sure that attribute selectors are quoted
					expr = expr.replace(rattributeQuotes, "='$1']");
	
					if (support.matchesSelector && documentIsHTML && !compilerCache[expr + " "] && (!rbuggyMatches || !rbuggyMatches.test(expr)) && (!rbuggyQSA || !rbuggyQSA.test(expr))) {
	
						try {
							var ret = matches.call(elem, expr);
	
							// IE 9's matchesSelector returns false on disconnected nodes
							if (ret || support.disconnectedMatch ||
							// As well, disconnected nodes are said to be in a document
							// fragment in IE 9
							elem.document && elem.document.nodeType !== 11) {
								return ret;
							}
						} catch (e) {}
					}
	
					return Sizzle(expr, document, null, [elem]).length > 0;
				};
	
				Sizzle.contains = function (context, elem) {
					// Set document vars if needed
					if ((context.ownerDocument || context) !== document) {
						setDocument(context);
					}
					return contains(context, elem);
				};
	
				Sizzle.attr = function (elem, name) {
					// Set document vars if needed
					if ((elem.ownerDocument || elem) !== document) {
						setDocument(elem);
					}
	
					var fn = Expr.attrHandle[name.toLowerCase()],
	
					// Don't get fooled by Object.prototype properties (jQuery #13807)
					val = fn && hasOwn.call(Expr.attrHandle, name.toLowerCase()) ? fn(elem, name, !documentIsHTML) : undefined;
	
					return val !== undefined ? val : support.attributes || !documentIsHTML ? elem.getAttribute(name) : (val = elem.getAttributeNode(name)) && val.specified ? val.value : null;
				};
	
				Sizzle.escape = function (sel) {
					return (sel + "").replace(rcssescape, fcssescape);
				};
	
				Sizzle.error = function (msg) {
					throw new Error("Syntax error, unrecognized expression: " + msg);
				};
	
				/**
		   * Document sorting and removing duplicates
		   * @param {ArrayLike} results
		   */
				Sizzle.uniqueSort = function (results) {
					var elem,
					    duplicates = [],
					    j = 0,
					    i = 0;
	
					// Unless we *know* we can detect duplicates, assume their presence
					hasDuplicate = !support.detectDuplicates;
					sortInput = !support.sortStable && results.slice(0);
					results.sort(sortOrder);
	
					if (hasDuplicate) {
						while (elem = results[i++]) {
							if (elem === results[i]) {
								j = duplicates.push(i);
							}
						}
						while (j--) {
							results.splice(duplicates[j], 1);
						}
					}
	
					// Clear input after sorting to release objects
					// See https://github.com/jquery/sizzle/pull/225
					sortInput = null;
	
					return results;
				};
	
				/**
		   * Utility function for retrieving the text value of an array of DOM nodes
		   * @param {Array|Element} elem
		   */
				getText = Sizzle.getText = function (elem) {
					var node,
					    ret = "",
					    i = 0,
					    nodeType = elem.nodeType;
	
					if (!nodeType) {
						// If no nodeType, this is expected to be an array
						while (node = elem[i++]) {
							// Do not traverse comment nodes
							ret += getText(node);
						}
					} else if (nodeType === 1 || nodeType === 9 || nodeType === 11) {
						// Use textContent for elements
						// innerText usage removed for consistency of new lines (jQuery #11153)
						if (typeof elem.textContent === "string") {
							return elem.textContent;
						} else {
							// Traverse its children
							for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
								ret += getText(elem);
							}
						}
					} else if (nodeType === 3 || nodeType === 4) {
						return elem.nodeValue;
					}
					// Do not include comment or processing instruction nodes
	
					return ret;
				};
	
				Expr = Sizzle.selectors = {
	
					// Can be adjusted by the user
					cacheLength: 50,
	
					createPseudo: markFunction,
	
					match: matchExpr,
	
					attrHandle: {},
	
					find: {},
	
					relative: {
						">": { dir: "parentNode", first: true },
						" ": { dir: "parentNode" },
						"+": { dir: "previousSibling", first: true },
						"~": { dir: "previousSibling" }
					},
	
					preFilter: {
						"ATTR": function (match) {
							match[1] = match[1].replace(runescape, funescape);
	
							// Move the given value to match[3] whether quoted or unquoted
							match[3] = (match[3] || match[4] || match[5] || "").replace(runescape, funescape);
	
							if (match[2] === "~=") {
								match[3] = " " + match[3] + " ";
							}
	
							return match.slice(0, 4);
						},
	
						"CHILD": function (match) {
							/* matches from matchExpr["CHILD"]
		     	1 type (only|nth|...)
		     	2 what (child|of-type)
		     	3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
		     	4 xn-component of xn+y argument ([+-]?\d*n|)
		     	5 sign of xn-component
		     	6 x of xn-component
		     	7 sign of y-component
		     	8 y of y-component
		     */
							match[1] = match[1].toLowerCase();
	
							if (match[1].slice(0, 3) === "nth") {
								// nth-* requires argument
								if (!match[3]) {
									Sizzle.error(match[0]);
								}
	
								// numeric x and y parameters for Expr.filter.CHILD
								// remember that false/true cast respectively to 0/1
								match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd"));
								match[5] = +(match[7] + match[8] || match[3] === "odd");
	
								// other types prohibit arguments
							} else if (match[3]) {
								Sizzle.error(match[0]);
							}
	
							return match;
						},
	
						"PSEUDO": function (match) {
							var excess,
							    unquoted = !match[6] && match[2];
	
							if (matchExpr["CHILD"].test(match[0])) {
								return null;
							}
	
							// Accept quoted arguments as-is
							if (match[3]) {
								match[2] = match[4] || match[5] || "";
	
								// Strip excess characters from unquoted arguments
							} else if (unquoted && rpseudo.test(unquoted) && (
							// Get excess from tokenize (recursively)
							excess = tokenize(unquoted, true)) && (
							// advance to the next closing parenthesis
							excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) {
	
								// excess is a negative index
								match[0] = match[0].slice(0, excess);
								match[2] = unquoted.slice(0, excess);
							}
	
							// Return only captures needed by the pseudo filter method (type and argument)
							return match.slice(0, 3);
						}
					},
	
					filter: {
	
						"TAG": function (nodeNameSelector) {
							var nodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase();
							return nodeNameSelector === "*" ? function () {
								return true;
							} : function (elem) {
								return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
							};
						},
	
						"CLASS": function (className) {
							var pattern = classCache[className + " "];
	
							return pattern || (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) && classCache(className, function (elem) {
								return pattern.test(typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "");
							});
						},
	
						"ATTR": function (name, operator, check) {
							return function (elem) {
								var result = Sizzle.attr(elem, name);
	
								if (result == null) {
									return operator === "!=";
								}
								if (!operator) {
									return true;
								}
	
								result += "";
	
								return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf(check) === 0 : operator === "*=" ? check && result.indexOf(check) > -1 : operator === "$=" ? check && result.slice(-check.length) === check : operator === "~=" ? (" " + result.replace(rwhitespace, " ") + " ").indexOf(check) > -1 : operator === "|=" ? result === check || result.slice(0, check.length + 1) === check + "-" : false;
							};
						},
	
						"CHILD": function (type, what, argument, first, last) {
							var simple = type.slice(0, 3) !== "nth",
							    forward = type.slice(-4) !== "last",
							    ofType = what === "of-type";
	
							return first === 1 && last === 0 ?
	
							// Shortcut for :nth-*(n)
							function (elem) {
								return !!elem.parentNode;
							} : function (elem, context, xml) {
								var cache,
								    uniqueCache,
								    outerCache,
								    node,
								    nodeIndex,
								    start,
								    dir = simple !== forward ? "nextSibling" : "previousSibling",
								    parent = elem.parentNode,
								    name = ofType && elem.nodeName.toLowerCase(),
								    useCache = !xml && !ofType,
								    diff = false;
	
								if (parent) {
	
									// :(first|last|only)-(child|of-type)
									if (simple) {
										while (dir) {
											node = elem;
											while (node = node[dir]) {
												if (ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) {
	
													return false;
												}
											}
											// Reverse direction for :only-* (if we haven't yet done so)
											start = dir = type === "only" && !start && "nextSibling";
										}
										return true;
									}
	
									start = [forward ? parent.firstChild : parent.lastChild];
	
									// non-xml :nth-child(...) stores cache data on `parent`
									if (forward && useCache) {
	
										// Seek `elem` from a previously-cached index
	
										// ...in a gzip-friendly way
										node = parent;
										outerCache = node[expando] || (node[expando] = {});
	
										// Support: IE <9 only
										// Defend against cloned attroperties (jQuery gh-1709)
										uniqueCache = outerCache[node.uniqueID] || (outerCache[node.uniqueID] = {});
	
										cache = uniqueCache[type] || [];
										nodeIndex = cache[0] === dirruns && cache[1];
										diff = nodeIndex && cache[2];
										node = nodeIndex && parent.childNodes[nodeIndex];
	
										while (node = ++nodeIndex && node && node[dir] || (
	
										// Fallback to seeking `elem` from the start
										diff = nodeIndex = 0) || start.pop()) {
	
											// When found, cache indexes on `parent` and break
											if (node.nodeType === 1 && ++diff && node === elem) {
												uniqueCache[type] = [dirruns, nodeIndex, diff];
												break;
											}
										}
									} else {
										// Use previously-cached element index if available
										if (useCache) {
											// ...in a gzip-friendly way
											node = elem;
											outerCache = node[expando] || (node[expando] = {});
	
											// Support: IE <9 only
											// Defend against cloned attroperties (jQuery gh-1709)
											uniqueCache = outerCache[node.uniqueID] || (outerCache[node.uniqueID] = {});
	
											cache = uniqueCache[type] || [];
											nodeIndex = cache[0] === dirruns && cache[1];
											diff = nodeIndex;
										}
	
										// xml :nth-child(...)
										// or :nth-last-child(...) or :nth(-last)?-of-type(...)
										if (diff === false) {
											// Use the same loop as above to seek `elem` from the start
											while (node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop()) {
	
												if ((ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) && ++diff) {
	
													// Cache the index of each encountered element
													if (useCache) {
														outerCache = node[expando] || (node[expando] = {});
	
														// Support: IE <9 only
														// Defend against cloned attroperties (jQuery gh-1709)
														uniqueCache = outerCache[node.uniqueID] || (outerCache[node.uniqueID] = {});
	
														uniqueCache[type] = [dirruns, diff];
													}
	
													if (node === elem) {
														break;
													}
												}
											}
										}
									}
	
									// Incorporate the offset, then check against cycle size
									diff -= last;
									return diff === first || diff % first === 0 && diff / first >= 0;
								}
							};
						},
	
						"PSEUDO": function (pseudo, argument) {
							// pseudo-class names are case-insensitive
							// http://www.w3.org/TR/selectors/#pseudo-classes
							// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
							// Remember that setFilters inherits from pseudos
							var args,
							    fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] || Sizzle.error("unsupported pseudo: " + pseudo);
	
							// The user may use createPseudo to indicate that
							// arguments are needed to create the filter function
							// just as Sizzle does
							if (fn[expando]) {
								return fn(argument);
							}
	
							// But maintain support for old signatures
							if (fn.length > 1) {
								args = [pseudo, pseudo, "", argument];
								return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ? markFunction(function (seed, matches) {
									var idx,
									    matched = fn(seed, argument),
									    i = matched.length;
									while (i--) {
										idx = indexOf(seed, matched[i]);
										seed[idx] = !(matches[idx] = matched[i]);
									}
								}) : function (elem) {
									return fn(elem, 0, args);
								};
							}
	
							return fn;
						}
					},
	
					pseudos: {
						// Potentially complex pseudos
						"not": markFunction(function (selector) {
							// Trim the selector passed to compile
							// to avoid treating leading and trailing
							// spaces as combinators
							var input = [],
							    results = [],
							    matcher = compile(selector.replace(rtrim, "$1"));
	
							return matcher[expando] ? markFunction(function (seed, matches, context, xml) {
								var elem,
								    unmatched = matcher(seed, null, xml, []),
								    i = seed.length;
	
								// Match elements unmatched by `matcher`
								while (i--) {
									if (elem = unmatched[i]) {
										seed[i] = !(matches[i] = elem);
									}
								}
							}) : function (elem, context, xml) {
								input[0] = elem;
								matcher(input, null, xml, results);
								// Don't keep the element (issue #299)
								input[0] = null;
								return !results.pop();
							};
						}),
	
						"has": markFunction(function (selector) {
							return function (elem) {
								return Sizzle(selector, elem).length > 0;
							};
						}),
	
						"contains": markFunction(function (text) {
							text = text.replace(runescape, funescape);
							return function (elem) {
								return (elem.textContent || elem.innerText || getText(elem)).indexOf(text) > -1;
							};
						}),
	
						// "Whether an element is represented by a :lang() selector
						// is based solely on the element's language value
						// being equal to the identifier C,
						// or beginning with the identifier C immediately followed by "-".
						// The matching of C against the element's language value is performed case-insensitively.
						// The identifier C does not have to be a valid language name."
						// http://www.w3.org/TR/selectors/#lang-pseudo
						"lang": markFunction(function (lang) {
							// lang value must be a valid identifier
							if (!ridentifier.test(lang || "")) {
								Sizzle.error("unsupported lang: " + lang);
							}
							lang = lang.replace(runescape, funescape).toLowerCase();
							return function (elem) {
								var elemLang;
								do {
									if (elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang")) {
	
										elemLang = elemLang.toLowerCase();
										return elemLang === lang || elemLang.indexOf(lang + "-") === 0;
									}
								} while ((elem = elem.parentNode) && elem.nodeType === 1);
								return false;
							};
						}),
	
						// Miscellaneous
						"target": function (elem) {
							var hash = window.location && window.location.hash;
							return hash && hash.slice(1) === elem.id;
						},
	
						"root": function (elem) {
							return elem === docElem;
						},
	
						"focus": function (elem) {
							return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
						},
	
						// Boolean properties
						"enabled": createDisabledPseudo(false),
						"disabled": createDisabledPseudo(true),
	
						"checked": function (elem) {
							// In CSS3, :checked should return both checked and selected elements
							// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
							var nodeName = elem.nodeName.toLowerCase();
							return nodeName === "input" && !!elem.checked || nodeName === "option" && !!elem.selected;
						},
	
						"selected": function (elem) {
							// Accessing this property makes selected-by-default
							// options in Safari work properly
							if (elem.parentNode) {
								elem.parentNode.selectedIndex;
							}
	
							return elem.selected === true;
						},
	
						// Contents
						"empty": function (elem) {
							// http://www.w3.org/TR/selectors/#empty-pseudo
							// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
							//   but not by others (comment: 8; processing instruction: 7; etc.)
							// nodeType < 6 works because attributes (2) do not appear as children
							for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
								if (elem.nodeType < 6) {
									return false;
								}
							}
							return true;
						},
	
						"parent": function (elem) {
							return !Expr.pseudos["empty"](elem);
						},
	
						// Element/input types
						"header": function (elem) {
							return rheader.test(elem.nodeName);
						},
	
						"input": function (elem) {
							return rinputs.test(elem.nodeName);
						},
	
						"button": function (elem) {
							var name = elem.nodeName.toLowerCase();
							return name === "input" && elem.type === "button" || name === "button";
						},
	
						"text": function (elem) {
							var attr;
							return elem.nodeName.toLowerCase() === "input" && elem.type === "text" && (
	
							// Support: IE<8
							// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
							(attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text");
						},
	
						// Position-in-collection
						"first": createPositionalPseudo(function () {
							return [0];
						}),
	
						"last": createPositionalPseudo(function (matchIndexes, length) {
							return [length - 1];
						}),
	
						"eq": createPositionalPseudo(function (matchIndexes, length, argument) {
							return [argument < 0 ? argument + length : argument];
						}),
	
						"even": createPositionalPseudo(function (matchIndexes, length) {
							var i = 0;
							for (; i < length; i += 2) {
								matchIndexes.push(i);
							}
							return matchIndexes;
						}),
	
						"odd": createPositionalPseudo(function (matchIndexes, length) {
							var i = 1;
							for (; i < length; i += 2) {
								matchIndexes.push(i);
							}
							return matchIndexes;
						}),
	
						"lt": createPositionalPseudo(function (matchIndexes, length, argument) {
							var i = argument < 0 ? argument + length : argument;
							for (; --i >= 0;) {
								matchIndexes.push(i);
							}
							return matchIndexes;
						}),
	
						"gt": createPositionalPseudo(function (matchIndexes, length, argument) {
							var i = argument < 0 ? argument + length : argument;
							for (; ++i < length;) {
								matchIndexes.push(i);
							}
							return matchIndexes;
						})
					}
				};
	
				Expr.pseudos["nth"] = Expr.pseudos["eq"];
	
				// Add button/input type pseudos
				for (i in { radio: true, checkbox: true, file: true, password: true, image: true }) {
					Expr.pseudos[i] = createInputPseudo(i);
				}
				for (i in { submit: true, reset: true }) {
					Expr.pseudos[i] = createButtonPseudo(i);
				}
	
				// Easy API for creating new setFilters
				function setFilters() {}
				setFilters.prototype = Expr.filters = Expr.pseudos;
				Expr.setFilters = new setFilters();
	
				tokenize = Sizzle.tokenize = function (selector, parseOnly) {
					var matched,
					    match,
					    tokens,
					    type,
					    soFar,
					    groups,
					    preFilters,
					    cached = tokenCache[selector + " "];
	
					if (cached) {
						return parseOnly ? 0 : cached.slice(0);
					}
	
					soFar = selector;
					groups = [];
					preFilters = Expr.preFilter;
	
					while (soFar) {
	
						// Comma and first run
						if (!matched || (match = rcomma.exec(soFar))) {
							if (match) {
								// Don't consume trailing commas as valid
								soFar = soFar.slice(match[0].length) || soFar;
							}
							groups.push(tokens = []);
						}
	
						matched = false;
	
						// Combinators
						if (match = rcombinators.exec(soFar)) {
							matched = match.shift();
							tokens.push({
								value: matched,
								// Cast descendant combinators to space
								type: match[0].replace(rtrim, " ")
							});
							soFar = soFar.slice(matched.length);
						}
	
						// Filters
						for (type in Expr.filter) {
							if ((match = matchExpr[type].exec(soFar)) && (!preFilters[type] || (match = preFilters[type](match)))) {
								matched = match.shift();
								tokens.push({
									value: matched,
									type: type,
									matches: match
								});
								soFar = soFar.slice(matched.length);
							}
						}
	
						if (!matched) {
							break;
						}
					}
	
					// Return the length of the invalid excess
					// if we're just parsing
					// Otherwise, throw an error or return tokens
					return parseOnly ? soFar.length : soFar ? Sizzle.error(selector) :
					// Cache the tokens
					tokenCache(selector, groups).slice(0);
				};
	
				function toSelector(tokens) {
					var i = 0,
					    len = tokens.length,
					    selector = "";
					for (; i < len; i++) {
						selector += tokens[i].value;
					}
					return selector;
				}
	
				function addCombinator(matcher, combinator, base) {
					var dir = combinator.dir,
					    skip = combinator.next,
					    key = skip || dir,
					    checkNonElements = base && key === "parentNode",
					    doneName = done++;
	
					return combinator.first ?
					// Check against closest ancestor/preceding element
					function (elem, context, xml) {
						while (elem = elem[dir]) {
							if (elem.nodeType === 1 || checkNonElements) {
								return matcher(elem, context, xml);
							}
						}
						return false;
					} :
	
					// Check against all ancestor/preceding elements
					function (elem, context, xml) {
						var oldCache,
						    uniqueCache,
						    outerCache,
						    newCache = [dirruns, doneName];
	
						// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
						if (xml) {
							while (elem = elem[dir]) {
								if (elem.nodeType === 1 || checkNonElements) {
									if (matcher(elem, context, xml)) {
										return true;
									}
								}
							}
						} else {
							while (elem = elem[dir]) {
								if (elem.nodeType === 1 || checkNonElements) {
									outerCache = elem[expando] || (elem[expando] = {});
	
									// Support: IE <9 only
									// Defend against cloned attroperties (jQuery gh-1709)
									uniqueCache = outerCache[elem.uniqueID] || (outerCache[elem.uniqueID] = {});
	
									if (skip && skip === elem.nodeName.toLowerCase()) {
										elem = elem[dir] || elem;
									} else if ((oldCache = uniqueCache[key]) && oldCache[0] === dirruns && oldCache[1] === doneName) {
	
										// Assign to newCache so results back-propagate to previous elements
										return newCache[2] = oldCache[2];
									} else {
										// Reuse newcache so results back-propagate to previous elements
										uniqueCache[key] = newCache;
	
										// A match means we're done; a fail means we have to keep checking
										if (newCache[2] = matcher(elem, context, xml)) {
											return true;
										}
									}
								}
							}
						}
						return false;
					};
				}
	
				function elementMatcher(matchers) {
					return matchers.length > 1 ? function (elem, context, xml) {
						var i = matchers.length;
						while (i--) {
							if (!matchers[i](elem, context, xml)) {
								return false;
							}
						}
						return true;
					} : matchers[0];
				}
	
				function multipleContexts(selector, contexts, results) {
					var i = 0,
					    len = contexts.length;
					for (; i < len; i++) {
						Sizzle(selector, contexts[i], results);
					}
					return results;
				}
	
				function condense(unmatched, map, filter, context, xml) {
					var elem,
					    newUnmatched = [],
					    i = 0,
					    len = unmatched.length,
					    mapped = map != null;
	
					for (; i < len; i++) {
						if (elem = unmatched[i]) {
							if (!filter || filter(elem, context, xml)) {
								newUnmatched.push(elem);
								if (mapped) {
									map.push(i);
								}
							}
						}
					}
	
					return newUnmatched;
				}
	
				function setMatcher(preFilter, selector, matcher, postFilter, postFinder, postSelector) {
					if (postFilter && !postFilter[expando]) {
						postFilter = setMatcher(postFilter);
					}
					if (postFinder && !postFinder[expando]) {
						postFinder = setMatcher(postFinder, postSelector);
					}
					return markFunction(function (seed, results, context, xml) {
						var temp,
						    i,
						    elem,
						    preMap = [],
						    postMap = [],
						    preexisting = results.length,
	
	
						// Get initial elements from seed or context
						elems = seed || multipleContexts(selector || "*", context.nodeType ? [context] : context, []),
	
	
						// Prefilter to get matcher input, preserving a map for seed-results synchronization
						matcherIn = preFilter && (seed || !selector) ? condense(elems, preMap, preFilter, context, xml) : elems,
						    matcherOut = matcher ?
						// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
						postFinder || (seed ? preFilter : preexisting || postFilter) ?
	
						// ...intermediate processing is necessary
						[] :
	
						// ...otherwise use results directly
						results : matcherIn;
	
						// Find primary matches
						if (matcher) {
							matcher(matcherIn, matcherOut, context, xml);
						}
	
						// Apply postFilter
						if (postFilter) {
							temp = condense(matcherOut, postMap);
							postFilter(temp, [], context, xml);
	
							// Un-match failing elements by moving them back to matcherIn
							i = temp.length;
							while (i--) {
								if (elem = temp[i]) {
									matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem);
								}
							}
						}
	
						if (seed) {
							if (postFinder || preFilter) {
								if (postFinder) {
									// Get the final matcherOut by condensing this intermediate into postFinder contexts
									temp = [];
									i = matcherOut.length;
									while (i--) {
										if (elem = matcherOut[i]) {
											// Restore matcherIn since elem is not yet a final match
											temp.push(matcherIn[i] = elem);
										}
									}
									postFinder(null, matcherOut = [], temp, xml);
								}
	
								// Move matched elements from seed to results to keep them synchronized
								i = matcherOut.length;
								while (i--) {
									if ((elem = matcherOut[i]) && (temp = postFinder ? indexOf(seed, elem) : preMap[i]) > -1) {
	
										seed[temp] = !(results[temp] = elem);
									}
								}
							}
	
							// Add elements to results, through postFinder if defined
						} else {
							matcherOut = condense(matcherOut === results ? matcherOut.splice(preexisting, matcherOut.length) : matcherOut);
							if (postFinder) {
								postFinder(null, results, matcherOut, xml);
							} else {
								push.apply(results, matcherOut);
							}
						}
					});
				}
	
				function matcherFromTokens(tokens) {
					var checkContext,
					    matcher,
					    j,
					    len = tokens.length,
					    leadingRelative = Expr.relative[tokens[0].type],
					    implicitRelative = leadingRelative || Expr.relative[" "],
					    i = leadingRelative ? 1 : 0,
	
	
					// The foundational matcher ensures that elements are reachable from top-level context(s)
					matchContext = addCombinator(function (elem) {
						return elem === checkContext;
					}, implicitRelative, true),
					    matchAnyContext = addCombinator(function (elem) {
						return indexOf(checkContext, elem) > -1;
					}, implicitRelative, true),
					    matchers = [function (elem, context, xml) {
						var ret = !leadingRelative && (xml || context !== outermostContext) || ((checkContext = context).nodeType ? matchContext(elem, context, xml) : matchAnyContext(elem, context, xml));
						// Avoid hanging onto element (issue #299)
						checkContext = null;
						return ret;
					}];
	
					for (; i < len; i++) {
						if (matcher = Expr.relative[tokens[i].type]) {
							matchers = [addCombinator(elementMatcher(matchers), matcher)];
						} else {
							matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches);
	
							// Return special upon seeing a positional matcher
							if (matcher[expando]) {
								// Find the next relative operator (if any) for proper handling
								j = ++i;
								for (; j < len; j++) {
									if (Expr.relative[tokens[j].type]) {
										break;
									}
								}
								return setMatcher(i > 1 && elementMatcher(matchers), i > 1 && toSelector(
								// If the preceding token was a descendant combinator, insert an implicit any-element `*`
								tokens.slice(0, i - 1).concat({ value: tokens[i - 2].type === " " ? "*" : "" })).replace(rtrim, "$1"), matcher, i < j && matcherFromTokens(tokens.slice(i, j)), j < len && matcherFromTokens(tokens = tokens.slice(j)), j < len && toSelector(tokens));
							}
							matchers.push(matcher);
						}
					}
	
					return elementMatcher(matchers);
				}
	
				function matcherFromGroupMatchers(elementMatchers, setMatchers) {
					var bySet = setMatchers.length > 0,
					    byElement = elementMatchers.length > 0,
					    superMatcher = function (seed, context, xml, results, outermost) {
						var elem,
						    j,
						    matcher,
						    matchedCount = 0,
						    i = "0",
						    unmatched = seed && [],
						    setMatched = [],
						    contextBackup = outermostContext,
	
						// We must always have either seed elements or outermost context
						elems = seed || byElement && Expr.find["TAG"]("*", outermost),
	
						// Use integer dirruns iff this is the outermost matcher
						dirrunsUnique = dirruns += contextBackup == null ? 1 : Math.random() || 0.1,
						    len = elems.length;
	
						if (outermost) {
							outermostContext = context === document || context || outermost;
						}
	
						// Add elements passing elementMatchers directly to results
						// Support: IE<9, Safari
						// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
						for (; i !== len && (elem = elems[i]) != null; i++) {
							if (byElement && elem) {
								j = 0;
								if (!context && elem.ownerDocument !== document) {
									setDocument(elem);
									xml = !documentIsHTML;
								}
								while (matcher = elementMatchers[j++]) {
									if (matcher(elem, context || document, xml)) {
										results.push(elem);
										break;
									}
								}
								if (outermost) {
									dirruns = dirrunsUnique;
								}
							}
	
							// Track unmatched elements for set filters
							if (bySet) {
								// They will have gone through all possible matchers
								if (elem = !matcher && elem) {
									matchedCount--;
								}
	
								// Lengthen the array for every element, matched or not
								if (seed) {
									unmatched.push(elem);
								}
							}
						}
	
						// `i` is now the count of elements visited above, and adding it to `matchedCount`
						// makes the latter nonnegative.
						matchedCount += i;
	
						// Apply set filters to unmatched elements
						// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
						// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
						// no element matchers and no seed.
						// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
						// case, which will result in a "00" `matchedCount` that differs from `i` but is also
						// numerically zero.
						if (bySet && i !== matchedCount) {
							j = 0;
							while (matcher = setMatchers[j++]) {
								matcher(unmatched, setMatched, context, xml);
							}
	
							if (seed) {
								// Reintegrate element matches to eliminate the need for sorting
								if (matchedCount > 0) {
									while (i--) {
										if (!(unmatched[i] || setMatched[i])) {
											setMatched[i] = pop.call(results);
										}
									}
								}
	
								// Discard index placeholder values to get only actual matches
								setMatched = condense(setMatched);
							}
	
							// Add matches to results
							push.apply(results, setMatched);
	
							// Seedless set matches succeeding multiple successful matchers stipulate sorting
							if (outermost && !seed && setMatched.length > 0 && matchedCount + setMatchers.length > 1) {
	
								Sizzle.uniqueSort(results);
							}
						}
	
						// Override manipulation of globals by nested matchers
						if (outermost) {
							dirruns = dirrunsUnique;
							outermostContext = contextBackup;
						}
	
						return unmatched;
					};
	
					return bySet ? markFunction(superMatcher) : superMatcher;
				}
	
				compile = Sizzle.compile = function (selector, match /* Internal Use Only */) {
					var i,
					    setMatchers = [],
					    elementMatchers = [],
					    cached = compilerCache[selector + " "];
	
					if (!cached) {
						// Generate a function of recursive functions that can be used to check each element
						if (!match) {
							match = tokenize(selector);
						}
						i = match.length;
						while (i--) {
							cached = matcherFromTokens(match[i]);
							if (cached[expando]) {
								setMatchers.push(cached);
							} else {
								elementMatchers.push(cached);
							}
						}
	
						// Cache the compiled function
						cached = compilerCache(selector, matcherFromGroupMatchers(elementMatchers, setMatchers));
	
						// Save selector and tokenization
						cached.selector = selector;
					}
					return cached;
				};
	
				/**
		   * A low-level selection function that works with Sizzle's compiled
		   *  selector functions
		   * @param {String|Function} selector A selector or a pre-compiled
		   *  selector function built with Sizzle.compile
		   * @param {Element} context
		   * @param {Array} [results]
		   * @param {Array} [seed] A set of elements to match against
		   */
				select = Sizzle.select = function (selector, context, results, seed) {
					var i,
					    tokens,
					    token,
					    type,
					    find,
					    compiled = typeof selector === "function" && selector,
					    match = !seed && tokenize(selector = compiled.selector || selector);
	
					results = results || [];
	
					// Try to minimize operations if there is only one selector in the list and no seed
					// (the latter of which guarantees us context)
					if (match.length === 1) {
	
						// Reduce context if the leading compound selector is an ID
						tokens = match[0] = match[0].slice(0);
						if (tokens.length > 2 && (token = tokens[0]).type === "ID" && context.nodeType === 9 && documentIsHTML && Expr.relative[tokens[1].type]) {
	
							context = (Expr.find["ID"](token.matches[0].replace(runescape, funescape), context) || [])[0];
							if (!context) {
								return results;
	
								// Precompiled matchers will still verify ancestry, so step up a level
							} else if (compiled) {
								context = context.parentNode;
							}
	
							selector = selector.slice(tokens.shift().value.length);
						}
	
						// Fetch a seed set for right-to-left matching
						i = matchExpr["needsContext"].test(selector) ? 0 : tokens.length;
						while (i--) {
							token = tokens[i];
	
							// Abort if we hit a combinator
							if (Expr.relative[type = token.type]) {
								break;
							}
							if (find = Expr.find[type]) {
								// Search, expanding context for leading sibling combinators
								if (seed = find(token.matches[0].replace(runescape, funescape), rsibling.test(tokens[0].type) && testContext(context.parentNode) || context)) {
	
									// If seed is empty or no tokens remain, we can return early
									tokens.splice(i, 1);
									selector = seed.length && toSelector(tokens);
									if (!selector) {
										push.apply(results, seed);
										return results;
									}
	
									break;
								}
							}
						}
					}
	
					// Compile and execute a filtering function if one is not provided
					// Provide `match` to avoid retokenization if we modified the selector above
					(compiled || compile(selector, match))(seed, context, !documentIsHTML, results, !context || rsibling.test(selector) && testContext(context.parentNode) || context);
					return results;
				};
	
				// One-time assignments
	
				// Sort stability
				support.sortStable = expando.split("").sort(sortOrder).join("") === expando;
	
				// Support: Chrome 14-35+
				// Always assume duplicates if they aren't passed to the comparison function
				support.detectDuplicates = !!hasDuplicate;
	
				// Initialize against the default document
				setDocument();
	
				// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
				// Detached nodes confoundingly follow *each other*
				support.sortDetached = assert(function (el) {
					// Should return 1, but returns 4 (following)
					return el.compareDocumentPosition(document.createElement("fieldset")) & 1;
				});
	
				// Support: IE<8
				// Prevent attribute/property "interpolation"
				// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
				if (!assert(function (el) {
					el.innerHTML = "<a href='#'></a>";
					return el.firstChild.getAttribute("href") === "#";
				})) {
					addHandle("type|href|height|width", function (elem, name, isXML) {
						if (!isXML) {
							return elem.getAttribute(name, name.toLowerCase() === "type" ? 1 : 2);
						}
					});
				}
	
				// Support: IE<9
				// Use defaultValue in place of getAttribute("value")
				if (!support.attributes || !assert(function (el) {
					el.innerHTML = "<input/>";
					el.firstChild.setAttribute("value", "");
					return el.firstChild.getAttribute("value") === "";
				})) {
					addHandle("value", function (elem, name, isXML) {
						if (!isXML && elem.nodeName.toLowerCase() === "input") {
							return elem.defaultValue;
						}
					});
				}
	
				// Support: IE<9
				// Use getAttributeNode to fetch booleans when getAttribute lies
				if (!assert(function (el) {
					return el.getAttribute("disabled") == null;
				})) {
					addHandle(booleans, function (elem, name, isXML) {
						var val;
						if (!isXML) {
							return elem[name] === true ? name.toLowerCase() : (val = elem.getAttributeNode(name)) && val.specified ? val.value : null;
						}
					});
				}
	
				return Sizzle;
			}(window);
	
			jQuery.find = Sizzle;
			jQuery.expr = Sizzle.selectors;
	
			// Deprecated
			jQuery.expr[":"] = jQuery.expr.pseudos;
			jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
			jQuery.text = Sizzle.getText;
			jQuery.isXMLDoc = Sizzle.isXML;
			jQuery.contains = Sizzle.contains;
			jQuery.escapeSelector = Sizzle.escape;
	
			var dir = function (elem, dir, until) {
				var matched = [],
				    truncate = until !== undefined;
	
				while ((elem = elem[dir]) && elem.nodeType !== 9) {
					if (elem.nodeType === 1) {
						if (truncate && jQuery(elem).is(until)) {
							break;
						}
						matched.push(elem);
					}
				}
				return matched;
			};
	
			var siblings = function (n, elem) {
				var matched = [];
	
				for (; n; n = n.nextSibling) {
					if (n.nodeType === 1 && n !== elem) {
						matched.push(n);
					}
				}
	
				return matched;
			};
	
			var rneedsContext = jQuery.expr.match.needsContext;
	
			function nodeName(elem, name) {
	
				return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
			};
			var rsingleTag = /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;
	
			// Implement the identical functionality for filter and not
			function winnow(elements, qualifier, not) {
				if (isFunction(qualifier)) {
					return jQuery.grep(elements, function (elem, i) {
						return !!qualifier.call(elem, i, elem) !== not;
					});
				}
	
				// Single element
				if (qualifier.nodeType) {
					return jQuery.grep(elements, function (elem) {
						return elem === qualifier !== not;
					});
				}
	
				// Arraylike of elements (jQuery, arguments, Array)
				if (typeof qualifier !== "string") {
					return jQuery.grep(elements, function (elem) {
						return indexOf.call(qualifier, elem) > -1 !== not;
					});
				}
	
				// Filtered directly for both simple and complex selectors
				return jQuery.filter(qualifier, elements, not);
			}
	
			jQuery.filter = function (expr, elems, not) {
				var elem = elems[0];
	
				if (not) {
					expr = ":not(" + expr + ")";
				}
	
				if (elems.length === 1 && elem.nodeType === 1) {
					return jQuery.find.matchesSelector(elem, expr) ? [elem] : [];
				}
	
				return jQuery.find.matches(expr, jQuery.grep(elems, function (elem) {
					return elem.nodeType === 1;
				}));
			};
	
			jQuery.fn.extend({
				find: function (selector) {
					var i,
					    ret,
					    len = this.length,
					    self = this;
	
					if (typeof selector !== "string") {
						return this.pushStack(jQuery(selector).filter(function () {
							for (i = 0; i < len; i++) {
								if (jQuery.contains(self[i], this)) {
									return true;
								}
							}
						}));
					}
	
					ret = this.pushStack([]);
	
					for (i = 0; i < len; i++) {
						jQuery.find(selector, self[i], ret);
					}
	
					return len > 1 ? jQuery.uniqueSort(ret) : ret;
				},
				filter: function (selector) {
					return this.pushStack(winnow(this, selector || [], false));
				},
				not: function (selector) {
					return this.pushStack(winnow(this, selector || [], true));
				},
				is: function (selector) {
					return !!winnow(this,
	
					// If this is a positional/relative selector, check membership in the returned set
					// so $("p:first").is("p:last") won't return true for a doc with two "p".
					typeof selector === "string" && rneedsContext.test(selector) ? jQuery(selector) : selector || [], false).length;
				}
			});
	
			// Initialize a jQuery object
	
	
			// A central reference to the root jQuery(document)
			var rootjQuery,
	
	
			// A simple way to check for HTML strings
			// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
			// Strict HTML recognition (#11290: must start with <)
			// Shortcut simple #id case for speed
			rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
			    init = jQuery.fn.init = function (selector, context, root) {
				var match, elem;
	
				// HANDLE: $(""), $(null), $(undefined), $(false)
				if (!selector) {
					return this;
				}
	
				// Method init() accepts an alternate rootjQuery
				// so migrate can support jQuery.sub (gh-2101)
				root = root || rootjQuery;
	
				// Handle HTML strings
				if (typeof selector === "string") {
					if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) {
	
						// Assume that strings that start and end with <> are HTML and skip the regex check
						match = [null, selector, null];
					} else {
						match = rquickExpr.exec(selector);
					}
	
					// Match html or make sure no context is specified for #id
					if (match && (match[1] || !context)) {
	
						// HANDLE: $(html) -> $(array)
						if (match[1]) {
							context = context instanceof jQuery ? context[0] : context;
	
							// Option to run scripts is true for back-compat
							// Intentionally let the error be thrown if parseHTML is not present
							jQuery.merge(this, jQuery.parseHTML(match[1], context && context.nodeType ? context.ownerDocument || context : document, true));
	
							// HANDLE: $(html, props)
							if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
								for (match in context) {
	
									// Properties of context are called as methods if possible
									if (isFunction(this[match])) {
										this[match](context[match]);
	
										// ...and otherwise set as attributes
									} else {
										this.attr(match, context[match]);
									}
								}
							}
	
							return this;
	
							// HANDLE: $(#id)
						} else {
							elem = document.getElementById(match[2]);
	
							if (elem) {
	
								// Inject the element directly into the jQuery object
								this[0] = elem;
								this.length = 1;
							}
							return this;
						}
	
						// HANDLE: $(expr, $(...))
					} else if (!context || context.jquery) {
						return (context || root).find(selector);
	
						// HANDLE: $(expr, context)
						// (which is just equivalent to: $(context).find(expr)
					} else {
						return this.constructor(context).find(selector);
					}
	
					// HANDLE: $(DOMElement)
				} else if (selector.nodeType) {
					this[0] = selector;
					this.length = 1;
					return this;
	
					// HANDLE: $(function)
					// Shortcut for document ready
				} else if (isFunction(selector)) {
					return root.ready !== undefined ? root.ready(selector) :
	
					// Execute immediately if ready is not present
					selector(jQuery);
				}
	
				return jQuery.makeArray(selector, this);
			};
	
			// Give the init function the jQuery prototype for later instantiation
			init.prototype = jQuery.fn;
	
			// Initialize central reference
			rootjQuery = jQuery(document);
	
			var rparentsprev = /^(?:parents|prev(?:Until|All))/,
	
	
			// Methods guaranteed to produce a unique set when starting from a unique set
			guaranteedUnique = {
				children: true,
				contents: true,
				next: true,
				prev: true
			};
	
			jQuery.fn.extend({
				has: function (target) {
					var targets = jQuery(target, this),
					    l = targets.length;
	
					return this.filter(function () {
						var i = 0;
						for (; i < l; i++) {
							if (jQuery.contains(this, targets[i])) {
								return true;
							}
						}
					});
				},
	
				closest: function (selectors, context) {
					var cur,
					    i = 0,
					    l = this.length,
					    matched = [],
					    targets = typeof selectors !== "string" && jQuery(selectors);
	
					// Positional selectors never match, since there's no _selection_ context
					if (!rneedsContext.test(selectors)) {
						for (; i < l; i++) {
							for (cur = this[i]; cur && cur !== context; cur = cur.parentNode) {
	
								// Always skip document fragments
								if (cur.nodeType < 11 && (targets ? targets.index(cur) > -1 :
	
								// Don't pass non-elements to Sizzle
								cur.nodeType === 1 && jQuery.find.matchesSelector(cur, selectors))) {
	
									matched.push(cur);
									break;
								}
							}
						}
					}
	
					return this.pushStack(matched.length > 1 ? jQuery.uniqueSort(matched) : matched);
				},
	
				// Determine the position of an element within the set
				index: function (elem) {
	
					// No argument, return index in parent
					if (!elem) {
						return this[0] && this[0].parentNode ? this.first().prevAll().length : -1;
					}
	
					// Index in selector
					if (typeof elem === "string") {
						return indexOf.call(jQuery(elem), this[0]);
					}
	
					// Locate the position of the desired element
					return indexOf.call(this,
	
					// If it receives a jQuery object, the first element is used
					elem.jquery ? elem[0] : elem);
				},
	
				add: function (selector, context) {
					return this.pushStack(jQuery.uniqueSort(jQuery.merge(this.get(), jQuery(selector, context))));
				},
	
				addBack: function (selector) {
					return this.add(selector == null ? this.prevObject : this.prevObject.filter(selector));
				}
			});
	
			function sibling(cur, dir) {
				while ((cur = cur[dir]) && cur.nodeType !== 1) {}
				return cur;
			}
	
			jQuery.each({
				parent: function (elem) {
					var parent = elem.parentNode;
					return parent && parent.nodeType !== 11 ? parent : null;
				},
				parents: function (elem) {
					return dir(elem, "parentNode");
				},
				parentsUntil: function (elem, i, until) {
					return dir(elem, "parentNode", until);
				},
				next: function (elem) {
					return sibling(elem, "nextSibling");
				},
				prev: function (elem) {
					return sibling(elem, "previousSibling");
				},
				nextAll: function (elem) {
					return dir(elem, "nextSibling");
				},
				prevAll: function (elem) {
					return dir(elem, "previousSibling");
				},
				nextUntil: function (elem, i, until) {
					return dir(elem, "nextSibling", until);
				},
				prevUntil: function (elem, i, until) {
					return dir(elem, "previousSibling", until);
				},
				siblings: function (elem) {
					return siblings((elem.parentNode || {}).firstChild, elem);
				},
				children: function (elem) {
					return siblings(elem.firstChild);
				},
				contents: function (elem) {
					if (nodeName(elem, "iframe")) {
						return elem.contentDocument;
					}
	
					// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
					// Treat the template element as a regular one in browsers that
					// don't support it.
					if (nodeName(elem, "template")) {
						elem = elem.content || elem;
					}
	
					return jQuery.merge([], elem.childNodes);
				}
			}, function (name, fn) {
				jQuery.fn[name] = function (until, selector) {
					var matched = jQuery.map(this, fn, until);
	
					if (name.slice(-5) !== "Until") {
						selector = until;
					}
	
					if (selector && typeof selector === "string") {
						matched = jQuery.filter(selector, matched);
					}
	
					if (this.length > 1) {
	
						// Remove duplicates
						if (!guaranteedUnique[name]) {
							jQuery.uniqueSort(matched);
						}
	
						// Reverse order for parents* and prev-derivatives
						if (rparentsprev.test(name)) {
							matched.reverse();
						}
					}
	
					return this.pushStack(matched);
				};
			});
			var rnothtmlwhite = /[^\x20\t\r\n\f]+/g;
	
			// Convert String-formatted options into Object-formatted ones
			function createOptions(options) {
				var object = {};
				jQuery.each(options.match(rnothtmlwhite) || [], function (_, flag) {
					object[flag] = true;
				});
				return object;
			}
	
			/*
		  * Create a callback list using the following parameters:
		  *
		  *	options: an optional list of space-separated options that will change how
		  *			the callback list behaves or a more traditional option object
		  *
		  * By default a callback list will act like an event callback list and can be
		  * "fired" multiple times.
		  *
		  * Possible options:
		  *
		  *	once:			will ensure the callback list can only be fired once (like a Deferred)
		  *
		  *	memory:			will keep track of previous values and will call any callback added
		  *					after the list has been fired right away with the latest "memorized"
		  *					values (like a Deferred)
		  *
		  *	unique:			will ensure a callback can only be added once (no duplicate in the list)
		  *
		  *	stopOnFalse:	interrupt callings when a callback returns false
		  *
		  */
			jQuery.Callbacks = function (options) {
	
				// Convert options from String-formatted to Object-formatted if needed
				// (we check in cache first)
				options = typeof options === "string" ? createOptions(options) : jQuery.extend({}, options);
	
				var // Flag to know if list is currently firing
				firing,
	
	
				// Last fire value for non-forgettable lists
				memory,
	
	
				// Flag to know if list was already fired
				fired,
	
	
				// Flag to prevent firing
				locked,
	
	
				// Actual callback list
				list = [],
	
	
				// Queue of execution data for repeatable lists
				queue = [],
	
	
				// Index of currently firing callback (modified by add/remove as needed)
				firingIndex = -1,
	
	
				// Fire callbacks
				fire = function () {
	
					// Enforce single-firing
					locked = locked || options.once;
	
					// Execute callbacks for all pending executions,
					// respecting firingIndex overrides and runtime changes
					fired = firing = true;
					for (; queue.length; firingIndex = -1) {
						memory = queue.shift();
						while (++firingIndex < list.length) {
	
							// Run callback and check for early termination
							if (list[firingIndex].apply(memory[0], memory[1]) === false && options.stopOnFalse) {
	
								// Jump to end and forget the data so .add doesn't re-fire
								firingIndex = list.length;
								memory = false;
							}
						}
					}
	
					// Forget the data if we're done with it
					if (!options.memory) {
						memory = false;
					}
	
					firing = false;
	
					// Clean up if we're done firing for good
					if (locked) {
	
						// Keep an empty list if we have data for future add calls
						if (memory) {
							list = [];
	
							// Otherwise, this object is spent
						} else {
							list = "";
						}
					}
				},
	
	
				// Actual Callbacks object
				self = {
	
					// Add a callback or a collection of callbacks to the list
					add: function () {
						if (list) {
	
							// If we have memory from a past run, we should fire after adding
							if (memory && !firing) {
								firingIndex = list.length - 1;
								queue.push(memory);
							}
	
							(function add(args) {
								jQuery.each(args, function (_, arg) {
									if (isFunction(arg)) {
										if (!options.unique || !self.has(arg)) {
											list.push(arg);
										}
									} else if (arg && arg.length && toType(arg) !== "string") {
	
										// Inspect recursively
										add(arg);
									}
								});
							})(arguments);
	
							if (memory && !firing) {
								fire();
							}
						}
						return this;
					},
	
					// Remove a callback from the list
					remove: function () {
						jQuery.each(arguments, function (_, arg) {
							var index;
							while ((index = jQuery.inArray(arg, list, index)) > -1) {
								list.splice(index, 1);
	
								// Handle firing indexes
								if (index <= firingIndex) {
									firingIndex--;
								}
							}
						});
						return this;
					},
	
					// Check if a given callback is in the list.
					// If no argument is given, return whether or not list has callbacks attached.
					has: function (fn) {
						return fn ? jQuery.inArray(fn, list) > -1 : list.length > 0;
					},
	
					// Remove all callbacks from the list
					empty: function () {
						if (list) {
							list = [];
						}
						return this;
					},
	
					// Disable .fire and .add
					// Abort any current/pending executions
					// Clear all callbacks and values
					disable: function () {
						locked = queue = [];
						list = memory = "";
						return this;
					},
					disabled: function () {
						return !list;
					},
	
					// Disable .fire
					// Also disable .add unless we have memory (since it would have no effect)
					// Abort any pending executions
					lock: function () {
						locked = queue = [];
						if (!memory && !firing) {
							list = memory = "";
						}
						return this;
					},
					locked: function () {
						return !!locked;
					},
	
					// Call all callbacks with the given context and arguments
					fireWith: function (context, args) {
						if (!locked) {
							args = args || [];
							args = [context, args.slice ? args.slice() : args];
							queue.push(args);
							if (!firing) {
								fire();
							}
						}
						return this;
					},
	
					// Call all the callbacks with the given arguments
					fire: function () {
						self.fireWith(this, arguments);
						return this;
					},
	
					// To know if the callbacks have already been called at least once
					fired: function () {
						return !!fired;
					}
				};
	
				return self;
			};
	
			function Identity(v) {
				return v;
			}
			function Thrower(ex) {
				throw ex;
			}
	
			function adoptValue(value, resolve, reject, noValue) {
				var method;
	
				try {
	
					// Check for promise aspect first to privilege synchronous behavior
					if (value && isFunction(method = value.promise)) {
						method.call(value).done(resolve).fail(reject);
	
						// Other thenables
					} else if (value && isFunction(method = value.then)) {
						method.call(value, resolve, reject);
	
						// Other non-thenables
					} else {
	
						// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
						// * false: [ value ].slice( 0 ) => resolve( value )
						// * true: [ value ].slice( 1 ) => resolve()
						resolve.apply(undefined, [value].slice(noValue));
					}
	
					// For Promises/A+, convert exceptions into rejections
					// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
					// Deferred#then to conditionally suppress rejection.
				} catch (value) {
	
					// Support: Android 4.0 only
					// Strict mode functions invoked without .call/.apply get global-object context
					reject.apply(undefined, [value]);
				}
			}
	
			jQuery.extend({
	
				Deferred: function (func) {
					var tuples = [
	
					// action, add listener, callbacks,
					// ... .then handlers, argument index, [final state]
					["notify", "progress", jQuery.Callbacks("memory"), jQuery.Callbacks("memory"), 2], ["resolve", "done", jQuery.Callbacks("once memory"), jQuery.Callbacks("once memory"), 0, "resolved"], ["reject", "fail", jQuery.Callbacks("once memory"), jQuery.Callbacks("once memory"), 1, "rejected"]],
					    state = "pending",
					    promise = {
						state: function () {
							return state;
						},
						always: function () {
							deferred.done(arguments).fail(arguments);
							return this;
						},
						"catch": function (fn) {
							return promise.then(null, fn);
						},
	
						// Keep pipe for back-compat
						pipe: function () /* fnDone, fnFail, fnProgress */{
							var fns = arguments;
	
							return jQuery.Deferred(function (newDefer) {
								jQuery.each(tuples, function (i, tuple) {
	
									// Map tuples (progress, done, fail) to arguments (done, fail, progress)
									var fn = isFunction(fns[tuple[4]]) && fns[tuple[4]];
	
									// deferred.progress(function() { bind to newDefer or newDefer.notify })
									// deferred.done(function() { bind to newDefer or newDefer.resolve })
									// deferred.fail(function() { bind to newDefer or newDefer.reject })
									deferred[tuple[1]](function () {
										var returned = fn && fn.apply(this, arguments);
										if (returned && isFunction(returned.promise)) {
											returned.promise().progress(newDefer.notify).done(newDefer.resolve).fail(newDefer.reject);
										} else {
											newDefer[tuple[0] + "With"](this, fn ? [returned] : arguments);
										}
									});
								});
								fns = null;
							}).promise();
						},
						then: function (onFulfilled, onRejected, onProgress) {
							var maxDepth = 0;
							function resolve(depth, deferred, handler, special) {
								return function () {
									var that = this,
									    args = arguments,
									    mightThrow = function () {
										var returned, then;
	
										// Support: Promises/A+ section 2.3.3.3.3
										// https://promisesaplus.com/#point-59
										// Ignore double-resolution attempts
										if (depth < maxDepth) {
											return;
										}
	
										returned = handler.apply(that, args);
	
										// Support: Promises/A+ section 2.3.1
										// https://promisesaplus.com/#point-48
										if (returned === deferred.promise()) {
											throw new TypeError("Thenable self-resolution");
										}
	
										// Support: Promises/A+ sections 2.3.3.1, 3.5
										// https://promisesaplus.com/#point-54
										// https://promisesaplus.com/#point-75
										// Retrieve `then` only once
										then = returned && (
	
										// Support: Promises/A+ section 2.3.4
										// https://promisesaplus.com/#point-64
										// Only check objects and functions for thenability
										typeof returned === "object" || typeof returned === "function") && returned.then;
	
										// Handle a returned thenable
										if (isFunction(then)) {
	
											// Special processors (notify) just wait for resolution
											if (special) {
												then.call(returned, resolve(maxDepth, deferred, Identity, special), resolve(maxDepth, deferred, Thrower, special));
	
												// Normal processors (resolve) also hook into progress
											} else {
	
												// ...and disregard older resolution values
												maxDepth++;
	
												then.call(returned, resolve(maxDepth, deferred, Identity, special), resolve(maxDepth, deferred, Thrower, special), resolve(maxDepth, deferred, Identity, deferred.notifyWith));
											}
	
											// Handle all other returned values
										} else {
	
											// Only substitute handlers pass on context
											// and multiple values (non-spec behavior)
											if (handler !== Identity) {
												that = undefined;
												args = [returned];
											}
	
											// Process the value(s)
											// Default process is resolve
											(special || deferred.resolveWith)(that, args);
										}
									},
	
	
									// Only normal processors (resolve) catch and reject exceptions
									process = special ? mightThrow : function () {
										try {
											mightThrow();
										} catch (e) {
	
											if (jQuery.Deferred.exceptionHook) {
												jQuery.Deferred.exceptionHook(e, process.stackTrace);
											}
	
											// Support: Promises/A+ section 2.3.3.3.4.1
											// https://promisesaplus.com/#point-61
											// Ignore post-resolution exceptions
											if (depth + 1 >= maxDepth) {
	
												// Only substitute handlers pass on context
												// and multiple values (non-spec behavior)
												if (handler !== Thrower) {
													that = undefined;
													args = [e];
												}
	
												deferred.rejectWith(that, args);
											}
										}
									};
	
									// Support: Promises/A+ section 2.3.3.3.1
									// https://promisesaplus.com/#point-57
									// Re-resolve promises immediately to dodge false rejection from
									// subsequent errors
									if (depth) {
										process();
									} else {
	
										// Call an optional hook to record the stack, in case of exception
										// since it's otherwise lost when execution goes async
										if (jQuery.Deferred.getStackHook) {
											process.stackTrace = jQuery.Deferred.getStackHook();
										}
										window.setTimeout(process);
									}
								};
							}
	
							return jQuery.Deferred(function (newDefer) {
	
								// progress_handlers.add( ... )
								tuples[0][3].add(resolve(0, newDefer, isFunction(onProgress) ? onProgress : Identity, newDefer.notifyWith));
	
								// fulfilled_handlers.add( ... )
								tuples[1][3].add(resolve(0, newDefer, isFunction(onFulfilled) ? onFulfilled : Identity));
	
								// rejected_handlers.add( ... )
								tuples[2][3].add(resolve(0, newDefer, isFunction(onRejected) ? onRejected : Thrower));
							}).promise();
						},
	
						// Get a promise for this deferred
						// If obj is provided, the promise aspect is added to the object
						promise: function (obj) {
							return obj != null ? jQuery.extend(obj, promise) : promise;
						}
					},
					    deferred = {};
	
					// Add list-specific methods
					jQuery.each(tuples, function (i, tuple) {
						var list = tuple[2],
						    stateString = tuple[5];
	
						// promise.progress = list.add
						// promise.done = list.add
						// promise.fail = list.add
						promise[tuple[1]] = list.add;
	
						// Handle state
						if (stateString) {
							list.add(function () {
	
								// state = "resolved" (i.e., fulfilled)
								// state = "rejected"
								state = stateString;
							},
	
							// rejected_callbacks.disable
							// fulfilled_callbacks.disable
							tuples[3 - i][2].disable,
	
							// rejected_handlers.disable
							// fulfilled_handlers.disable
							tuples[3 - i][3].disable,
	
							// progress_callbacks.lock
							tuples[0][2].lock,
	
							// progress_handlers.lock
							tuples[0][3].lock);
						}
	
						// progress_handlers.fire
						// fulfilled_handlers.fire
						// rejected_handlers.fire
						list.add(tuple[3].fire);
	
						// deferred.notify = function() { deferred.notifyWith(...) }
						// deferred.resolve = function() { deferred.resolveWith(...) }
						// deferred.reject = function() { deferred.rejectWith(...) }
						deferred[tuple[0]] = function () {
							deferred[tuple[0] + "With"](this === deferred ? undefined : this, arguments);
							return this;
						};
	
						// deferred.notifyWith = list.fireWith
						// deferred.resolveWith = list.fireWith
						// deferred.rejectWith = list.fireWith
						deferred[tuple[0] + "With"] = list.fireWith;
					});
	
					// Make the deferred a promise
					promise.promise(deferred);
	
					// Call given func if any
					if (func) {
						func.call(deferred, deferred);
					}
	
					// All done!
					return deferred;
				},
	
				// Deferred helper
				when: function (singleValue) {
					var
	
					// count of uncompleted subordinates
					remaining = arguments.length,
	
	
					// count of unprocessed arguments
					i = remaining,
	
	
					// subordinate fulfillment data
					resolveContexts = Array(i),
					    resolveValues = slice.call(arguments),
	
	
					// the master Deferred
					master = jQuery.Deferred(),
	
	
					// subordinate callback factory
					updateFunc = function (i) {
						return function (value) {
							resolveContexts[i] = this;
							resolveValues[i] = arguments.length > 1 ? slice.call(arguments) : value;
							if (! --remaining) {
								master.resolveWith(resolveContexts, resolveValues);
							}
						};
					};
	
					// Single- and empty arguments are adopted like Promise.resolve
					if (remaining <= 1) {
						adoptValue(singleValue, master.done(updateFunc(i)).resolve, master.reject, !remaining);
	
						// Use .then() to unwrap secondary thenables (cf. gh-3000)
						if (master.state() === "pending" || isFunction(resolveValues[i] && resolveValues[i].then)) {
	
							return master.then();
						}
					}
	
					// Multiple arguments are aggregated like Promise.all array elements
					while (i--) {
						adoptValue(resolveValues[i], updateFunc(i), master.reject);
					}
	
					return master.promise();
				}
			});
	
			// These usually indicate a programmer mistake during development,
			// warn about them ASAP rather than swallowing them by default.
			var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
	
			jQuery.Deferred.exceptionHook = function (error, stack) {
	
				// Support: IE 8 - 9 only
				// Console exists when dev tools are open, which can happen at any time
				if (window.console && window.console.warn && error && rerrorNames.test(error.name)) {
					window.console.warn("jQuery.Deferred exception: " + error.message, error.stack, stack);
				}
			};
	
			jQuery.readyException = function (error) {
				window.setTimeout(function () {
					throw error;
				});
			};
	
			// The deferred used on DOM ready
			var readyList = jQuery.Deferred();
	
			jQuery.fn.ready = function (fn) {
	
				readyList.then(fn)
	
				// Wrap jQuery.readyException in a function so that the lookup
				// happens at the time of error handling instead of callback
				// registration.
				.catch(function (error) {
					jQuery.readyException(error);
				});
	
				return this;
			};
	
			jQuery.extend({
	
				// Is the DOM ready to be used? Set to true once it occurs.
				isReady: false,
	
				// A counter to track how many items to wait for before
				// the ready event fires. See #6781
				readyWait: 1,
	
				// Handle when the DOM is ready
				ready: function (wait) {
	
					// Abort if there are pending holds or we're already ready
					if (wait === true ? --jQuery.readyWait : jQuery.isReady) {
						return;
					}
	
					// Remember that the DOM is ready
					jQuery.isReady = true;
	
					// If a normal DOM Ready event fired, decrement, and wait if need be
					if (wait !== true && --jQuery.readyWait > 0) {
						return;
					}
	
					// If there are functions bound, to execute
					readyList.resolveWith(document, [jQuery]);
				}
			});
	
			jQuery.ready.then = readyList.then;
	
			// The ready event handler and self cleanup method
			function completed() {
				document.removeEventListener("DOMContentLoaded", completed);
				window.removeEventListener("load", completed);
				jQuery.ready();
			}
	
			// Catch cases where $(document).ready() is called
			// after the browser event has already occurred.
			// Support: IE <=9 - 10 only
			// Older IE sometimes signals "interactive" too soon
			if (document.readyState === "complete" || document.readyState !== "loading" && !document.documentElement.doScroll) {
	
				// Handle it asynchronously to allow scripts the opportunity to delay ready
				window.setTimeout(jQuery.ready);
			} else {
	
				// Use the handy event callback
				document.addEventListener("DOMContentLoaded", completed);
	
				// A fallback to window.onload, that will always work
				window.addEventListener("load", completed);
			}
	
			// Multifunctional method to get and set values of a collection
			// The value/s can optionally be executed if it's a function
			var access = function (elems, fn, key, value, chainable, emptyGet, raw) {
				var i = 0,
				    len = elems.length,
				    bulk = key == null;
	
				// Sets many values
				if (toType(key) === "object") {
					chainable = true;
					for (i in key) {
						access(elems, fn, i, key[i], true, emptyGet, raw);
					}
	
					// Sets one value
				} else if (value !== undefined) {
					chainable = true;
	
					if (!isFunction(value)) {
						raw = true;
					}
	
					if (bulk) {
	
						// Bulk operations run against the entire set
						if (raw) {
							fn.call(elems, value);
							fn = null;
	
							// ...except when executing function values
						} else {
							bulk = fn;
							fn = function (elem, key, value) {
								return bulk.call(jQuery(elem), value);
							};
						}
					}
	
					if (fn) {
						for (; i < len; i++) {
							fn(elems[i], key, raw ? value : value.call(elems[i], i, fn(elems[i], key)));
						}
					}
				}
	
				if (chainable) {
					return elems;
				}
	
				// Gets
				if (bulk) {
					return fn.call(elems);
				}
	
				return len ? fn(elems[0], key) : emptyGet;
			};
	
			// Matches dashed string for camelizing
			var rmsPrefix = /^-ms-/,
			    rdashAlpha = /-([a-z])/g;
	
			// Used by camelCase as callback to replace()
			function fcamelCase(all, letter) {
				return letter.toUpperCase();
			}
	
			// Convert dashed to camelCase; used by the css and data modules
			// Support: IE <=9 - 11, Edge 12 - 15
			// Microsoft forgot to hump their vendor prefix (#9572)
			function camelCase(string) {
				return string.replace(rmsPrefix, "ms-").replace(rdashAlpha, fcamelCase);
			}
			var acceptData = function (owner) {
	
				// Accepts only:
				//  - Node
				//    - Node.ELEMENT_NODE
				//    - Node.DOCUMENT_NODE
				//  - Object
				//    - Any
				return owner.nodeType === 1 || owner.nodeType === 9 || !+owner.nodeType;
			};
	
			function Data() {
				this.expando = jQuery.expando + Data.uid++;
			}
	
			Data.uid = 1;
	
			Data.prototype = {
	
				cache: function (owner) {
	
					// Check if the owner object already has a cache
					var value = owner[this.expando];
	
					// If not, create one
					if (!value) {
						value = {};
	
						// We can accept data for non-element nodes in modern browsers,
						// but we should not, see #8335.
						// Always return an empty object.
						if (acceptData(owner)) {
	
							// If it is a node unlikely to be stringify-ed or looped over
							// use plain assignment
							if (owner.nodeType) {
								owner[this.expando] = value;
	
								// Otherwise secure it in a non-enumerable property
								// configurable must be true to allow the property to be
								// deleted when data is removed
							} else {
								Object.defineProperty(owner, this.expando, {
									value: value,
									configurable: true
								});
							}
						}
					}
	
					return value;
				},
				set: function (owner, data, value) {
					var prop,
					    cache = this.cache(owner);
	
					// Handle: [ owner, key, value ] args
					// Always use camelCase key (gh-2257)
					if (typeof data === "string") {
						cache[camelCase(data)] = value;
	
						// Handle: [ owner, { properties } ] args
					} else {
	
						// Copy the properties one-by-one to the cache object
						for (prop in data) {
							cache[camelCase(prop)] = data[prop];
						}
					}
					return cache;
				},
				get: function (owner, key) {
					return key === undefined ? this.cache(owner) :
	
					// Always use camelCase key (gh-2257)
					owner[this.expando] && owner[this.expando][camelCase(key)];
				},
				access: function (owner, key, value) {
	
					// In cases where either:
					//
					//   1. No key was specified
					//   2. A string key was specified, but no value provided
					//
					// Take the "read" path and allow the get method to determine
					// which value to return, respectively either:
					//
					//   1. The entire cache object
					//   2. The data stored at the key
					//
					if (key === undefined || key && typeof key === "string" && value === undefined) {
	
						return this.get(owner, key);
					}
	
					// When the key is not a string, or both a key and value
					// are specified, set or extend (existing objects) with either:
					//
					//   1. An object of properties
					//   2. A key and value
					//
					this.set(owner, key, value);
	
					// Since the "set" path can have two possible entry points
					// return the expected data based on which path was taken[*]
					return value !== undefined ? value : key;
				},
				remove: function (owner, key) {
					var i,
					    cache = owner[this.expando];
	
					if (cache === undefined) {
						return;
					}
	
					if (key !== undefined) {
	
						// Support array or space separated string of keys
						if (Array.isArray(key)) {
	
							// If key is an array of keys...
							// We always set camelCase keys, so remove that.
							key = key.map(camelCase);
						} else {
							key = camelCase(key);
	
							// If a key with the spaces exists, use it.
							// Otherwise, create an array by matching non-whitespace
							key = key in cache ? [key] : key.match(rnothtmlwhite) || [];
						}
	
						i = key.length;
	
						while (i--) {
							delete cache[key[i]];
						}
					}
	
					// Remove the expando if there's no more data
					if (key === undefined || jQuery.isEmptyObject(cache)) {
	
						// Support: Chrome <=35 - 45
						// Webkit & Blink performance suffers when deleting properties
						// from DOM nodes, so set to undefined instead
						// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
						if (owner.nodeType) {
							owner[this.expando] = undefined;
						} else {
							delete owner[this.expando];
						}
					}
				},
				hasData: function (owner) {
					var cache = owner[this.expando];
					return cache !== undefined && !jQuery.isEmptyObject(cache);
				}
			};
			var dataPriv = new Data();
	
			var dataUser = new Data();
	
			//	Implementation Summary
			//
			//	1. Enforce API surface and semantic compatibility with 1.9.x branch
			//	2. Improve the module's maintainability by reducing the storage
			//		paths to a single mechanism.
			//	3. Use the same single mechanism to support "private" and "user" data.
			//	4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
			//	5. Avoid exposing implementation details on user objects (eg. expando properties)
			//	6. Provide a clear path for implementation upgrade to WeakMap in 2014
	
			var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
			    rmultiDash = /[A-Z]/g;
	
			function getData(data) {
				if (data === "true") {
					return true;
				}
	
				if (data === "false") {
					return false;
				}
	
				if (data === "null") {
					return null;
				}
	
				// Only convert to a number if it doesn't change the string
				if (data === +data + "") {
					return +data;
				}
	
				if (rbrace.test(data)) {
					return JSON.parse(data);
				}
	
				return data;
			}
	
			function dataAttr(elem, key, data) {
				var name;
	
				// If nothing was found internally, try to fetch any
				// data from the HTML5 data-* attribute
				if (data === undefined && elem.nodeType === 1) {
					name = "data-" + key.replace(rmultiDash, "-$&").toLowerCase();
					data = elem.getAttribute(name);
	
					if (typeof data === "string") {
						try {
							data = getData(data);
						} catch (e) {}
	
						// Make sure we set the data so it isn't changed later
						dataUser.set(elem, key, data);
					} else {
						data = undefined;
					}
				}
				return data;
			}
	
			jQuery.extend({
				hasData: function (elem) {
					return dataUser.hasData(elem) || dataPriv.hasData(elem);
				},
	
				data: function (elem, name, data) {
					return dataUser.access(elem, name, data);
				},
	
				removeData: function (elem, name) {
					dataUser.remove(elem, name);
				},
	
				// TODO: Now that all calls to _data and _removeData have been replaced
				// with direct calls to dataPriv methods, these can be deprecated.
				_data: function (elem, name, data) {
					return dataPriv.access(elem, name, data);
				},
	
				_removeData: function (elem, name) {
					dataPriv.remove(elem, name);
				}
			});
	
			jQuery.fn.extend({
				data: function (key, value) {
					var i,
					    name,
					    data,
					    elem = this[0],
					    attrs = elem && elem.attributes;
	
					// Gets all values
					if (key === undefined) {
						if (this.length) {
							data = dataUser.get(elem);
	
							if (elem.nodeType === 1 && !dataPriv.get(elem, "hasDataAttrs")) {
								i = attrs.length;
								while (i--) {
	
									// Support: IE 11 only
									// The attrs elements can be null (#14894)
									if (attrs[i]) {
										name = attrs[i].name;
										if (name.indexOf("data-") === 0) {
											name = camelCase(name.slice(5));
											dataAttr(elem, name, data[name]);
										}
									}
								}
								dataPriv.set(elem, "hasDataAttrs", true);
							}
						}
	
						return data;
					}
	
					// Sets multiple values
					if (typeof key === "object") {
						return this.each(function () {
							dataUser.set(this, key);
						});
					}
	
					return access(this, function (value) {
						var data;
	
						// The calling jQuery object (element matches) is not empty
						// (and therefore has an element appears at this[ 0 ]) and the
						// `value` parameter was not undefined. An empty jQuery object
						// will result in `undefined` for elem = this[ 0 ] which will
						// throw an exception if an attempt to read a data cache is made.
						if (elem && value === undefined) {
	
							// Attempt to get data from the cache
							// The key will always be camelCased in Data
							data = dataUser.get(elem, key);
							if (data !== undefined) {
								return data;
							}
	
							// Attempt to "discover" the data in
							// HTML5 custom data-* attrs
							data = dataAttr(elem, key);
							if (data !== undefined) {
								return data;
							}
	
							// We tried really hard, but the data doesn't exist.
							return;
						}
	
						// Set the data...
						this.each(function () {
	
							// We always store the camelCased key
							dataUser.set(this, key, value);
						});
					}, null, value, arguments.length > 1, null, true);
				},
	
				removeData: function (key) {
					return this.each(function () {
						dataUser.remove(this, key);
					});
				}
			});
	
			jQuery.extend({
				queue: function (elem, type, data) {
					var queue;
	
					if (elem) {
						type = (type || "fx") + "queue";
						queue = dataPriv.get(elem, type);
	
						// Speed up dequeue by getting out quickly if this is just a lookup
						if (data) {
							if (!queue || Array.isArray(data)) {
								queue = dataPriv.access(elem, type, jQuery.makeArray(data));
							} else {
								queue.push(data);
							}
						}
						return queue || [];
					}
				},
	
				dequeue: function (elem, type) {
					type = type || "fx";
	
					var queue = jQuery.queue(elem, type),
					    startLength = queue.length,
					    fn = queue.shift(),
					    hooks = jQuery._queueHooks(elem, type),
					    next = function () {
						jQuery.dequeue(elem, type);
					};
	
					// If the fx queue is dequeued, always remove the progress sentinel
					if (fn === "inprogress") {
						fn = queue.shift();
						startLength--;
					}
	
					if (fn) {
	
						// Add a progress sentinel to prevent the fx queue from being
						// automatically dequeued
						if (type === "fx") {
							queue.unshift("inprogress");
						}
	
						// Clear up the last queue stop function
						delete hooks.stop;
						fn.call(elem, next, hooks);
					}
	
					if (!startLength && hooks) {
						hooks.empty.fire();
					}
				},
	
				// Not public - generate a queueHooks object, or return the current one
				_queueHooks: function (elem, type) {
					var key = type + "queueHooks";
					return dataPriv.get(elem, key) || dataPriv.access(elem, key, {
						empty: jQuery.Callbacks("once memory").add(function () {
							dataPriv.remove(elem, [type + "queue", key]);
						})
					});
				}
			});
	
			jQuery.fn.extend({
				queue: function (type, data) {
					var setter = 2;
	
					if (typeof type !== "string") {
						data = type;
						type = "fx";
						setter--;
					}
	
					if (arguments.length < setter) {
						return jQuery.queue(this[0], type);
					}
	
					return data === undefined ? this : this.each(function () {
						var queue = jQuery.queue(this, type, data);
	
						// Ensure a hooks for this queue
						jQuery._queueHooks(this, type);
	
						if (type === "fx" && queue[0] !== "inprogress") {
							jQuery.dequeue(this, type);
						}
					});
				},
				dequeue: function (type) {
					return this.each(function () {
						jQuery.dequeue(this, type);
					});
				},
				clearQueue: function (type) {
					return this.queue(type || "fx", []);
				},
	
				// Get a promise resolved when queues of a certain type
				// are emptied (fx is the type by default)
				promise: function (type, obj) {
					var tmp,
					    count = 1,
					    defer = jQuery.Deferred(),
					    elements = this,
					    i = this.length,
					    resolve = function () {
						if (! --count) {
							defer.resolveWith(elements, [elements]);
						}
					};
	
					if (typeof type !== "string") {
						obj = type;
						type = undefined;
					}
					type = type || "fx";
	
					while (i--) {
						tmp = dataPriv.get(elements[i], type + "queueHooks");
						if (tmp && tmp.empty) {
							count++;
							tmp.empty.add(resolve);
						}
					}
					resolve();
					return defer.promise(obj);
				}
			});
			var pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source;
	
			var rcssNum = new RegExp("^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i");
	
			var cssExpand = ["Top", "Right", "Bottom", "Left"];
	
			var isHiddenWithinTree = function (elem, el) {
	
				// isHiddenWithinTree might be called from jQuery#filter function;
				// in that case, element will be second argument
				elem = el || elem;
	
				// Inline style trumps all
				return elem.style.display === "none" || elem.style.display === "" &&
	
				// Otherwise, check computed style
				// Support: Firefox <=43 - 45
				// Disconnected elements can have computed display: none, so first confirm that elem is
				// in the document.
				jQuery.contains(elem.ownerDocument, elem) && jQuery.css(elem, "display") === "none";
			};
	
			var swap = function (elem, options, callback, args) {
				var ret,
				    name,
				    old = {};
	
				// Remember the old values, and insert the new ones
				for (name in options) {
					old[name] = elem.style[name];
					elem.style[name] = options[name];
				}
	
				ret = callback.apply(elem, args || []);
	
				// Revert the old values
				for (name in options) {
					elem.style[name] = old[name];
				}
	
				return ret;
			};
	
			function adjustCSS(elem, prop, valueParts, tween) {
				var adjusted,
				    scale,
				    maxIterations = 20,
				    currentValue = tween ? function () {
					return tween.cur();
				} : function () {
					return jQuery.css(elem, prop, "");
				},
				    initial = currentValue(),
				    unit = valueParts && valueParts[3] || (jQuery.cssNumber[prop] ? "" : "px"),
	
	
				// Starting value computation is required for potential unit mismatches
				initialInUnit = (jQuery.cssNumber[prop] || unit !== "px" && +initial) && rcssNum.exec(jQuery.css(elem, prop));
	
				if (initialInUnit && initialInUnit[3] !== unit) {
	
					// Support: Firefox <=54
					// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
					initial = initial / 2;
	
					// Trust units reported by jQuery.css
					unit = unit || initialInUnit[3];
	
					// Iteratively approximate from a nonzero starting point
					initialInUnit = +initial || 1;
	
					while (maxIterations--) {
	
						// Evaluate and update our best guess (doubling guesses that zero out).
						// Finish if the scale equals or crosses 1 (making the old*new product non-positive).
						jQuery.style(elem, prop, initialInUnit + unit);
						if ((1 - scale) * (1 - (scale = currentValue() / initial || 0.5)) <= 0) {
							maxIterations = 0;
						}
						initialInUnit = initialInUnit / scale;
					}
	
					initialInUnit = initialInUnit * 2;
					jQuery.style(elem, prop, initialInUnit + unit);
	
					// Make sure we update the tween properties later on
					valueParts = valueParts || [];
				}
	
				if (valueParts) {
					initialInUnit = +initialInUnit || +initial || 0;
	
					// Apply relative offset (+=/-=) if specified
					adjusted = valueParts[1] ? initialInUnit + (valueParts[1] + 1) * valueParts[2] : +valueParts[2];
					if (tween) {
						tween.unit = unit;
						tween.start = initialInUnit;
						tween.end = adjusted;
					}
				}
				return adjusted;
			}
	
			var defaultDisplayMap = {};
	
			function getDefaultDisplay(elem) {
				var temp,
				    doc = elem.ownerDocument,
				    nodeName = elem.nodeName,
				    display = defaultDisplayMap[nodeName];
	
				if (display) {
					return display;
				}
	
				temp = doc.body.appendChild(doc.createElement(nodeName));
				display = jQuery.css(temp, "display");
	
				temp.parentNode.removeChild(temp);
	
				if (display === "none") {
					display = "block";
				}
				defaultDisplayMap[nodeName] = display;
	
				return display;
			}
	
			function showHide(elements, show) {
				var display,
				    elem,
				    values = [],
				    index = 0,
				    length = elements.length;
	
				// Determine new display value for elements that need to change
				for (; index < length; index++) {
					elem = elements[index];
					if (!elem.style) {
						continue;
					}
	
					display = elem.style.display;
					if (show) {
	
						// Since we force visibility upon cascade-hidden elements, an immediate (and slow)
						// check is required in this first loop unless we have a nonempty display value (either
						// inline or about-to-be-restored)
						if (display === "none") {
							values[index] = dataPriv.get(elem, "display") || null;
							if (!values[index]) {
								elem.style.display = "";
							}
						}
						if (elem.style.display === "" && isHiddenWithinTree(elem)) {
							values[index] = getDefaultDisplay(elem);
						}
					} else {
						if (display !== "none") {
							values[index] = "none";
	
							// Remember what we're overwriting
							dataPriv.set(elem, "display", display);
						}
					}
				}
	
				// Set the display of the elements in a second loop to avoid constant reflow
				for (index = 0; index < length; index++) {
					if (values[index] != null) {
						elements[index].style.display = values[index];
					}
				}
	
				return elements;
			}
	
			jQuery.fn.extend({
				show: function () {
					return showHide(this, true);
				},
				hide: function () {
					return showHide(this);
				},
				toggle: function (state) {
					if (typeof state === "boolean") {
						return state ? this.show() : this.hide();
					}
	
					return this.each(function () {
						if (isHiddenWithinTree(this)) {
							jQuery(this).show();
						} else {
							jQuery(this).hide();
						}
					});
				}
			});
			var rcheckableType = /^(?:checkbox|radio)$/i;
	
			var rtagName = /<([a-z][^\/\0>\x20\t\r\n\f]+)/i;
	
			var rscriptType = /^$|^module$|\/(?:java|ecma)script/i;
	
			// We have to close these tags to support XHTML (#13200)
			var wrapMap = {
	
				// Support: IE <=9 only
				option: [1, "<select multiple='multiple'>", "</select>"],
	
				// XHTML parsers do not magically insert elements in the
				// same way that tag soup parsers do. So we cannot shorten
				// this by omitting <tbody> or other required elements.
				thead: [1, "<table>", "</table>"],
				col: [2, "<table><colgroup>", "</colgroup></table>"],
				tr: [2, "<table><tbody>", "</tbody></table>"],
				td: [3, "<table><tbody><tr>", "</tr></tbody></table>"],
	
				_default: [0, "", ""]
			};
	
			// Support: IE <=9 only
			wrapMap.optgroup = wrapMap.option;
	
			wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
			wrapMap.th = wrapMap.td;
	
			function getAll(context, tag) {
	
				// Support: IE <=9 - 11 only
				// Use typeof to avoid zero-argument method invocation on host objects (#15151)
				var ret;
	
				if (typeof context.getElementsByTagName !== "undefined") {
					ret = context.getElementsByTagName(tag || "*");
				} else if (typeof context.querySelectorAll !== "undefined") {
					ret = context.querySelectorAll(tag || "*");
				} else {
					ret = [];
				}
	
				if (tag === undefined || tag && nodeName(context, tag)) {
					return jQuery.merge([context], ret);
				}
	
				return ret;
			}
	
			// Mark scripts as having already been evaluated
			function setGlobalEval(elems, refElements) {
				var i = 0,
				    l = elems.length;
	
				for (; i < l; i++) {
					dataPriv.set(elems[i], "globalEval", !refElements || dataPriv.get(refElements[i], "globalEval"));
				}
			}
	
			var rhtml = /<|&#?\w+;/;
	
			function buildFragment(elems, context, scripts, selection, ignored) {
				var elem,
				    tmp,
				    tag,
				    wrap,
				    contains,
				    j,
				    fragment = context.createDocumentFragment(),
				    nodes = [],
				    i = 0,
				    l = elems.length;
	
				for (; i < l; i++) {
					elem = elems[i];
	
					if (elem || elem === 0) {
	
						// Add nodes directly
						if (toType(elem) === "object") {
	
							// Support: Android <=4.0 only, PhantomJS 1 only
							// push.apply(_, arraylike) throws on ancient WebKit
							jQuery.merge(nodes, elem.nodeType ? [elem] : elem);
	
							// Convert non-html into a text node
						} else if (!rhtml.test(elem)) {
							nodes.push(context.createTextNode(elem));
	
							// Convert html into DOM nodes
						} else {
							tmp = tmp || fragment.appendChild(context.createElement("div"));
	
							// Deserialize a standard representation
							tag = (rtagName.exec(elem) || ["", ""])[1].toLowerCase();
							wrap = wrapMap[tag] || wrapMap._default;
							tmp.innerHTML = wrap[1] + jQuery.htmlPrefilter(elem) + wrap[2];
	
							// Descend through wrappers to the right content
							j = wrap[0];
							while (j--) {
								tmp = tmp.lastChild;
							}
	
							// Support: Android <=4.0 only, PhantomJS 1 only
							// push.apply(_, arraylike) throws on ancient WebKit
							jQuery.merge(nodes, tmp.childNodes);
	
							// Remember the top-level container
							tmp = fragment.firstChild;
	
							// Ensure the created nodes are orphaned (#12392)
							tmp.textContent = "";
						}
					}
				}
	
				// Remove wrapper from fragment
				fragment.textContent = "";
	
				i = 0;
				while (elem = nodes[i++]) {
	
					// Skip elements already in the context collection (trac-4087)
					if (selection && jQuery.inArray(elem, selection) > -1) {
						if (ignored) {
							ignored.push(elem);
						}
						continue;
					}
	
					contains = jQuery.contains(elem.ownerDocument, elem);
	
					// Append to fragment
					tmp = getAll(fragment.appendChild(elem), "script");
	
					// Preserve script evaluation history
					if (contains) {
						setGlobalEval(tmp);
					}
	
					// Capture executables
					if (scripts) {
						j = 0;
						while (elem = tmp[j++]) {
							if (rscriptType.test(elem.type || "")) {
								scripts.push(elem);
							}
						}
					}
				}
	
				return fragment;
			}
	
			(function () {
				var fragment = document.createDocumentFragment(),
				    div = fragment.appendChild(document.createElement("div")),
				    input = document.createElement("input");
	
				// Support: Android 4.0 - 4.3 only
				// Check state lost if the name is set (#11217)
				// Support: Windows Web Apps (WWA)
				// `name` and `type` must use .setAttribute for WWA (#14901)
				input.setAttribute("type", "radio");
				input.setAttribute("checked", "checked");
				input.setAttribute("name", "t");
	
				div.appendChild(input);
	
				// Support: Android <=4.1 only
				// Older WebKit doesn't clone checked state correctly in fragments
				support.checkClone = div.cloneNode(true).cloneNode(true).lastChild.checked;
	
				// Support: IE <=11 only
				// Make sure textarea (and checkbox) defaultValue is properly cloned
				div.innerHTML = "<textarea>x</textarea>";
				support.noCloneChecked = !!div.cloneNode(true).lastChild.defaultValue;
			})();
			var documentElement = document.documentElement;
	
			var rkeyEvent = /^key/,
			    rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
			    rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
	
			function returnTrue() {
				return true;
			}
	
			function returnFalse() {
				return false;
			}
	
			// Support: IE <=9 only
			// See #13393 for more info
			function safeActiveElement() {
				try {
					return document.activeElement;
				} catch (err) {}
			}
	
			function on(elem, types, selector, data, fn, one) {
				var origFn, type;
	
				// Types can be a map of types/handlers
				if (typeof types === "object") {
	
					// ( types-Object, selector, data )
					if (typeof selector !== "string") {
	
						// ( types-Object, data )
						data = data || selector;
						selector = undefined;
					}
					for (type in types) {
						on(elem, type, selector, data, types[type], one);
					}
					return elem;
				}
	
				if (data == null && fn == null) {
	
					// ( types, fn )
					fn = selector;
					data = selector = undefined;
				} else if (fn == null) {
					if (typeof selector === "string") {
	
						// ( types, selector, fn )
						fn = data;
						data = undefined;
					} else {
	
						// ( types, data, fn )
						fn = data;
						data = selector;
						selector = undefined;
					}
				}
				if (fn === false) {
					fn = returnFalse;
				} else if (!fn) {
					return elem;
				}
	
				if (one === 1) {
					origFn = fn;
					fn = function (event) {
	
						// Can use an empty set, since event contains the info
						jQuery().off(event);
						return origFn.apply(this, arguments);
					};
	
					// Use same guid so caller can remove using origFn
					fn.guid = origFn.guid || (origFn.guid = jQuery.guid++);
				}
				return elem.each(function () {
					jQuery.event.add(this, types, fn, data, selector);
				});
			}
	
			/*
		  * Helper functions for managing events -- not part of the public interface.
		  * Props to Dean Edwards' addEvent library for many of the ideas.
		  */
			jQuery.event = {
	
				global: {},
	
				add: function (elem, types, handler, data, selector) {
	
					var handleObjIn,
					    eventHandle,
					    tmp,
					    events,
					    t,
					    handleObj,
					    special,
					    handlers,
					    type,
					    namespaces,
					    origType,
					    elemData = dataPriv.get(elem);
	
					// Don't attach events to noData or text/comment nodes (but allow plain objects)
					if (!elemData) {
						return;
					}
	
					// Caller can pass in an object of custom data in lieu of the handler
					if (handler.handler) {
						handleObjIn = handler;
						handler = handleObjIn.handler;
						selector = handleObjIn.selector;
					}
	
					// Ensure that invalid selectors throw exceptions at attach time
					// Evaluate against documentElement in case elem is a non-element node (e.g., document)
					if (selector) {
						jQuery.find.matchesSelector(documentElement, selector);
					}
	
					// Make sure that the handler has a unique ID, used to find/remove it later
					if (!handler.guid) {
						handler.guid = jQuery.guid++;
					}
	
					// Init the element's event structure and main handler, if this is the first
					if (!(events = elemData.events)) {
						events = elemData.events = {};
					}
					if (!(eventHandle = elemData.handle)) {
						eventHandle = elemData.handle = function (e) {
	
							// Discard the second event of a jQuery.event.trigger() and
							// when an event is called after a page has unloaded
							return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? jQuery.event.dispatch.apply(elem, arguments) : undefined;
						};
					}
	
					// Handle multiple events separated by a space
					types = (types || "").match(rnothtmlwhite) || [""];
					t = types.length;
					while (t--) {
						tmp = rtypenamespace.exec(types[t]) || [];
						type = origType = tmp[1];
						namespaces = (tmp[2] || "").split(".").sort();
	
						// There *must* be a type, no attaching namespace-only handlers
						if (!type) {
							continue;
						}
	
						// If event changes its type, use the special event handlers for the changed type
						special = jQuery.event.special[type] || {};
	
						// If selector defined, determine special event api type, otherwise given type
						type = (selector ? special.delegateType : special.bindType) || type;
	
						// Update special based on newly reset type
						special = jQuery.event.special[type] || {};
	
						// handleObj is passed to all event handlers
						handleObj = jQuery.extend({
							type: type,
							origType: origType,
							data: data,
							handler: handler,
							guid: handler.guid,
							selector: selector,
							needsContext: selector && jQuery.expr.match.needsContext.test(selector),
							namespace: namespaces.join(".")
						}, handleObjIn);
	
						// Init the event handler queue if we're the first
						if (!(handlers = events[type])) {
							handlers = events[type] = [];
							handlers.delegateCount = 0;
	
							// Only use addEventListener if the special events handler returns false
							if (!special.setup || special.setup.call(elem, data, namespaces, eventHandle) === false) {
	
								if (elem.addEventListener) {
									elem.addEventListener(type, eventHandle);
								}
							}
						}
	
						if (special.add) {
							special.add.call(elem, handleObj);
	
							if (!handleObj.handler.guid) {
								handleObj.handler.guid = handler.guid;
							}
						}
	
						// Add to the element's handler list, delegates in front
						if (selector) {
							handlers.splice(handlers.delegateCount++, 0, handleObj);
						} else {
							handlers.push(handleObj);
						}
	
						// Keep track of which events have ever been used, for event optimization
						jQuery.event.global[type] = true;
					}
				},
	
				// Detach an event or set of events from an element
				remove: function (elem, types, handler, selector, mappedTypes) {
	
					var j,
					    origCount,
					    tmp,
					    events,
					    t,
					    handleObj,
					    special,
					    handlers,
					    type,
					    namespaces,
					    origType,
					    elemData = dataPriv.hasData(elem) && dataPriv.get(elem);
	
					if (!elemData || !(events = elemData.events)) {
						return;
					}
	
					// Once for each type.namespace in types; type may be omitted
					types = (types || "").match(rnothtmlwhite) || [""];
					t = types.length;
					while (t--) {
						tmp = rtypenamespace.exec(types[t]) || [];
						type = origType = tmp[1];
						namespaces = (tmp[2] || "").split(".").sort();
	
						// Unbind all events (on this namespace, if provided) for the element
						if (!type) {
							for (type in events) {
								jQuery.event.remove(elem, type + types[t], handler, selector, true);
							}
							continue;
						}
	
						special = jQuery.event.special[type] || {};
						type = (selector ? special.delegateType : special.bindType) || type;
						handlers = events[type] || [];
						tmp = tmp[2] && new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)");
	
						// Remove matching events
						origCount = j = handlers.length;
						while (j--) {
							handleObj = handlers[j];
	
							if ((mappedTypes || origType === handleObj.origType) && (!handler || handler.guid === handleObj.guid) && (!tmp || tmp.test(handleObj.namespace)) && (!selector || selector === handleObj.selector || selector === "**" && handleObj.selector)) {
								handlers.splice(j, 1);
	
								if (handleObj.selector) {
									handlers.delegateCount--;
								}
								if (special.remove) {
									special.remove.call(elem, handleObj);
								}
							}
						}
	
						// Remove generic event handler if we removed something and no more handlers exist
						// (avoids potential for endless recursion during removal of special event handlers)
						if (origCount && !handlers.length) {
							if (!special.teardown || special.teardown.call(elem, namespaces, elemData.handle) === false) {
	
								jQuery.removeEvent(elem, type, elemData.handle);
							}
	
							delete events[type];
						}
					}
	
					// Remove data and the expando if it's no longer used
					if (jQuery.isEmptyObject(events)) {
						dataPriv.remove(elem, "handle events");
					}
				},
	
				dispatch: function (nativeEvent) {
	
					// Make a writable jQuery.Event from the native event object
					var event = jQuery.event.fix(nativeEvent);
	
					var i,
					    j,
					    ret,
					    matched,
					    handleObj,
					    handlerQueue,
					    args = new Array(arguments.length),
					    handlers = (dataPriv.get(this, "events") || {})[event.type] || [],
					    special = jQuery.event.special[event.type] || {};
	
					// Use the fix-ed jQuery.Event rather than the (read-only) native event
					args[0] = event;
	
					for (i = 1; i < arguments.length; i++) {
						args[i] = arguments[i];
					}
	
					event.delegateTarget = this;
	
					// Call the preDispatch hook for the mapped type, and let it bail if desired
					if (special.preDispatch && special.preDispatch.call(this, event) === false) {
						return;
					}
	
					// Determine handlers
					handlerQueue = jQuery.event.handlers.call(this, event, handlers);
	
					// Run delegates first; they may want to stop propagation beneath us
					i = 0;
					while ((matched = handlerQueue[i++]) && !event.isPropagationStopped()) {
						event.currentTarget = matched.elem;
	
						j = 0;
						while ((handleObj = matched.handlers[j++]) && !event.isImmediatePropagationStopped()) {
	
							// Triggered event must either 1) have no namespace, or 2) have namespace(s)
							// a subset or equal to those in the bound event (both can have no namespace).
							if (!event.rnamespace || event.rnamespace.test(handleObj.namespace)) {
	
								event.handleObj = handleObj;
								event.data = handleObj.data;
	
								ret = ((jQuery.event.special[handleObj.origType] || {}).handle || handleObj.handler).apply(matched.elem, args);
	
								if (ret !== undefined) {
									if ((event.result = ret) === false) {
										event.preventDefault();
										event.stopPropagation();
									}
								}
							}
						}
					}
	
					// Call the postDispatch hook for the mapped type
					if (special.postDispatch) {
						special.postDispatch.call(this, event);
					}
	
					return event.result;
				},
	
				handlers: function (event, handlers) {
					var i,
					    handleObj,
					    sel,
					    matchedHandlers,
					    matchedSelectors,
					    handlerQueue = [],
					    delegateCount = handlers.delegateCount,
					    cur = event.target;
	
					// Find delegate handlers
					if (delegateCount &&
	
					// Support: IE <=9
					// Black-hole SVG <use> instance trees (trac-13180)
					cur.nodeType &&
	
					// Support: Firefox <=42
					// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
					// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
					// Support: IE 11 only
					// ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
					!(event.type === "click" && event.button >= 1)) {
	
						for (; cur !== this; cur = cur.parentNode || this) {
	
							// Don't check non-elements (#13208)
							// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
							if (cur.nodeType === 1 && !(event.type === "click" && cur.disabled === true)) {
								matchedHandlers = [];
								matchedSelectors = {};
								for (i = 0; i < delegateCount; i++) {
									handleObj = handlers[i];
	
									// Don't conflict with Object.prototype properties (#13203)
									sel = handleObj.selector + " ";
	
									if (matchedSelectors[sel] === undefined) {
										matchedSelectors[sel] = handleObj.needsContext ? jQuery(sel, this).index(cur) > -1 : jQuery.find(sel, this, null, [cur]).length;
									}
									if (matchedSelectors[sel]) {
										matchedHandlers.push(handleObj);
									}
								}
								if (matchedHandlers.length) {
									handlerQueue.push({ elem: cur, handlers: matchedHandlers });
								}
							}
						}
					}
	
					// Add the remaining (directly-bound) handlers
					cur = this;
					if (delegateCount < handlers.length) {
						handlerQueue.push({ elem: cur, handlers: handlers.slice(delegateCount) });
					}
	
					return handlerQueue;
				},
	
				addProp: function (name, hook) {
					Object.defineProperty(jQuery.Event.prototype, name, {
						enumerable: true,
						configurable: true,
	
						get: isFunction(hook) ? function () {
							if (this.originalEvent) {
								return hook(this.originalEvent);
							}
						} : function () {
							if (this.originalEvent) {
								return this.originalEvent[name];
							}
						},
	
						set: function (value) {
							Object.defineProperty(this, name, {
								enumerable: true,
								configurable: true,
								writable: true,
								value: value
							});
						}
					});
				},
	
				fix: function (originalEvent) {
					return originalEvent[jQuery.expando] ? originalEvent : new jQuery.Event(originalEvent);
				},
	
				special: {
					load: {
	
						// Prevent triggered image.load events from bubbling to window.load
						noBubble: true
					},
					focus: {
	
						// Fire native event if possible so blur/focus sequence is correct
						trigger: function () {
							if (this !== safeActiveElement() && this.focus) {
								this.focus();
								return false;
							}
						},
						delegateType: "focusin"
					},
					blur: {
						trigger: function () {
							if (this === safeActiveElement() && this.blur) {
								this.blur();
								return false;
							}
						},
						delegateType: "focusout"
					},
					click: {
	
						// For checkbox, fire native event so checked state will be right
						trigger: function () {
							if (this.type === "checkbox" && this.click && nodeName(this, "input")) {
								this.click();
								return false;
							}
						},
	
						// For cross-browser consistency, don't fire native .click() on links
						_default: function (event) {
							return nodeName(event.target, "a");
						}
					},
	
					beforeunload: {
						postDispatch: function (event) {
	
							// Support: Firefox 20+
							// Firefox doesn't alert if the returnValue field is not set.
							if (event.result !== undefined && event.originalEvent) {
								event.originalEvent.returnValue = event.result;
							}
						}
					}
				}
			};
	
			jQuery.removeEvent = function (elem, type, handle) {
	
				// This "if" is needed for plain objects
				if (elem.removeEventListener) {
					elem.removeEventListener(type, handle);
				}
			};
	
			jQuery.Event = function (src, props) {
	
				// Allow instantiation without the 'new' keyword
				if (!(this instanceof jQuery.Event)) {
					return new jQuery.Event(src, props);
				}
	
				// Event object
				if (src && src.type) {
					this.originalEvent = src;
					this.type = src.type;
	
					// Events bubbling up the document may have been marked as prevented
					// by a handler lower down the tree; reflect the correct value.
					this.isDefaultPrevented = src.defaultPrevented || src.defaultPrevented === undefined &&
	
					// Support: Android <=2.3 only
					src.returnValue === false ? returnTrue : returnFalse;
	
					// Create target properties
					// Support: Safari <=6 - 7 only
					// Target should not be a text node (#504, #13143)
					this.target = src.target && src.target.nodeType === 3 ? src.target.parentNode : src.target;
	
					this.currentTarget = src.currentTarget;
					this.relatedTarget = src.relatedTarget;
	
					// Event type
				} else {
					this.type = src;
				}
	
				// Put explicitly provided properties onto the event object
				if (props) {
					jQuery.extend(this, props);
				}
	
				// Create a timestamp if incoming event doesn't have one
				this.timeStamp = src && src.timeStamp || Date.now();
	
				// Mark it as fixed
				this[jQuery.expando] = true;
			};
	
			// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
			// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
			jQuery.Event.prototype = {
				constructor: jQuery.Event,
				isDefaultPrevented: returnFalse,
				isPropagationStopped: returnFalse,
				isImmediatePropagationStopped: returnFalse,
				isSimulated: false,
	
				preventDefault: function () {
					var e = this.originalEvent;
	
					this.isDefaultPrevented = returnTrue;
	
					if (e && !this.isSimulated) {
						e.preventDefault();
					}
				},
				stopPropagation: function () {
					var e = this.originalEvent;
	
					this.isPropagationStopped = returnTrue;
	
					if (e && !this.isSimulated) {
						e.stopPropagation();
					}
				},
				stopImmediatePropagation: function () {
					var e = this.originalEvent;
	
					this.isImmediatePropagationStopped = returnTrue;
	
					if (e && !this.isSimulated) {
						e.stopImmediatePropagation();
					}
	
					this.stopPropagation();
				}
			};
	
			// Includes all common event props including KeyEvent and MouseEvent specific props
			jQuery.each({
				altKey: true,
				bubbles: true,
				cancelable: true,
				changedTouches: true,
				ctrlKey: true,
				detail: true,
				eventPhase: true,
				metaKey: true,
				pageX: true,
				pageY: true,
				shiftKey: true,
				view: true,
				"char": true,
				charCode: true,
				key: true,
				keyCode: true,
				button: true,
				buttons: true,
				clientX: true,
				clientY: true,
				offsetX: true,
				offsetY: true,
				pointerId: true,
				pointerType: true,
				screenX: true,
				screenY: true,
				targetTouches: true,
				toElement: true,
				touches: true,
	
				which: function (event) {
					var button = event.button;
	
					// Add which for key events
					if (event.which == null && rkeyEvent.test(event.type)) {
						return event.charCode != null ? event.charCode : event.keyCode;
					}
	
					// Add which for click: 1 === left; 2 === middle; 3 === right
					if (!event.which && button !== undefined && rmouseEvent.test(event.type)) {
						if (button & 1) {
							return 1;
						}
	
						if (button & 2) {
							return 3;
						}
	
						if (button & 4) {
							return 2;
						}
	
						return 0;
					}
	
					return event.which;
				}
			}, jQuery.event.addProp);
	
			// Create mouseenter/leave events using mouseover/out and event-time checks
			// so that event delegation works in jQuery.
			// Do the same for pointerenter/pointerleave and pointerover/pointerout
			//
			// Support: Safari 7 only
			// Safari sends mouseenter too often; see:
			// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
			// for the description of the bug (it existed in older Chrome versions as well).
			jQuery.each({
				mouseenter: "mouseover",
				mouseleave: "mouseout",
				pointerenter: "pointerover",
				pointerleave: "pointerout"
			}, function (orig, fix) {
				jQuery.event.special[orig] = {
					delegateType: fix,
					bindType: fix,
	
					handle: function (event) {
						var ret,
						    target = this,
						    related = event.relatedTarget,
						    handleObj = event.handleObj;
	
						// For mouseenter/leave call the handler if related is outside the target.
						// NB: No relatedTarget if the mouse left/entered the browser window
						if (!related || related !== target && !jQuery.contains(target, related)) {
							event.type = handleObj.origType;
							ret = handleObj.handler.apply(this, arguments);
							event.type = fix;
						}
						return ret;
					}
				};
			});
	
			jQuery.fn.extend({
	
				on: function (types, selector, data, fn) {
					return on(this, types, selector, data, fn);
				},
				one: function (types, selector, data, fn) {
					return on(this, types, selector, data, fn, 1);
				},
				off: function (types, selector, fn) {
					var handleObj, type;
					if (types && types.preventDefault && types.handleObj) {
	
						// ( event )  dispatched jQuery.Event
						handleObj = types.handleObj;
						jQuery(types.delegateTarget).off(handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler);
						return this;
					}
					if (typeof types === "object") {
	
						// ( types-object [, selector] )
						for (type in types) {
							this.off(type, selector, types[type]);
						}
						return this;
					}
					if (selector === false || typeof selector === "function") {
	
						// ( types [, fn] )
						fn = selector;
						selector = undefined;
					}
					if (fn === false) {
						fn = returnFalse;
					}
					return this.each(function () {
						jQuery.event.remove(this, types, fn, selector);
					});
				}
			});
	
			var
	
			/* eslint-disable max-len */
	
			// See https://github.com/eslint/eslint/issues/3229
			rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
	
	
			/* eslint-enable */
	
			// Support: IE <=10 - 11, Edge 12 - 13 only
			// In IE/Edge using regex groups here causes severe slowdowns.
			// See https://connect.microsoft.com/IE/feedback/details/1736512/
			rnoInnerhtml = /<script|<style|<link/i,
	
	
			// checked="checked" or checked
			rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
			    rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
	
			// Prefer a tbody over its parent table for containing new rows
			function manipulationTarget(elem, content) {
				if (nodeName(elem, "table") && nodeName(content.nodeType !== 11 ? content : content.firstChild, "tr")) {
	
					return jQuery(elem).children("tbody")[0] || elem;
				}
	
				return elem;
			}
	
			// Replace/restore the type attribute of script elements for safe DOM manipulation
			function disableScript(elem) {
				elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
				return elem;
			}
			function restoreScript(elem) {
				if ((elem.type || "").slice(0, 5) === "true/") {
					elem.type = elem.type.slice(5);
				} else {
					elem.removeAttribute("type");
				}
	
				return elem;
			}
	
			function cloneCopyEvent(src, dest) {
				var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
	
				if (dest.nodeType !== 1) {
					return;
				}
	
				// 1. Copy private data: events, handlers, etc.
				if (dataPriv.hasData(src)) {
					pdataOld = dataPriv.access(src);
					pdataCur = dataPriv.set(dest, pdataOld);
					events = pdataOld.events;
	
					if (events) {
						delete pdataCur.handle;
						pdataCur.events = {};
	
						for (type in events) {
							for (i = 0, l = events[type].length; i < l; i++) {
								jQuery.event.add(dest, type, events[type][i]);
							}
						}
					}
				}
	
				// 2. Copy user data
				if (dataUser.hasData(src)) {
					udataOld = dataUser.access(src);
					udataCur = jQuery.extend({}, udataOld);
	
					dataUser.set(dest, udataCur);
				}
			}
	
			// Fix IE bugs, see support tests
			function fixInput(src, dest) {
				var nodeName = dest.nodeName.toLowerCase();
	
				// Fails to persist the checked state of a cloned checkbox or radio button.
				if (nodeName === "input" && rcheckableType.test(src.type)) {
					dest.checked = src.checked;
	
					// Fails to return the selected option to the default selected state when cloning options
				} else if (nodeName === "input" || nodeName === "textarea") {
					dest.defaultValue = src.defaultValue;
				}
			}
	
			function domManip(collection, args, callback, ignored) {
	
				// Flatten any nested arrays
				args = concat.apply([], args);
	
				var fragment,
				    first,
				    scripts,
				    hasScripts,
				    node,
				    doc,
				    i = 0,
				    l = collection.length,
				    iNoClone = l - 1,
				    value = args[0],
				    valueIsFunction = isFunction(value);
	
				// We can't cloneNode fragments that contain checked, in WebKit
				if (valueIsFunction || l > 1 && typeof value === "string" && !support.checkClone && rchecked.test(value)) {
					return collection.each(function (index) {
						var self = collection.eq(index);
						if (valueIsFunction) {
							args[0] = value.call(this, index, self.html());
						}
						domManip(self, args, callback, ignored);
					});
				}
	
				if (l) {
					fragment = buildFragment(args, collection[0].ownerDocument, false, collection, ignored);
					first = fragment.firstChild;
	
					if (fragment.childNodes.length === 1) {
						fragment = first;
					}
	
					// Require either new content or an interest in ignored elements to invoke the callback
					if (first || ignored) {
						scripts = jQuery.map(getAll(fragment, "script"), disableScript);
						hasScripts = scripts.length;
	
						// Use the original fragment for the last item
						// instead of the first because it can end up
						// being emptied incorrectly in certain situations (#8070).
						for (; i < l; i++) {
							node = fragment;
	
							if (i !== iNoClone) {
								node = jQuery.clone(node, true, true);
	
								// Keep references to cloned scripts for later restoration
								if (hasScripts) {
	
									// Support: Android <=4.0 only, PhantomJS 1 only
									// push.apply(_, arraylike) throws on ancient WebKit
									jQuery.merge(scripts, getAll(node, "script"));
								}
							}
	
							callback.call(collection[i], node, i);
						}
	
						if (hasScripts) {
							doc = scripts[scripts.length - 1].ownerDocument;
	
							// Reenable scripts
							jQuery.map(scripts, restoreScript);
	
							// Evaluate executable scripts on first document insertion
							for (i = 0; i < hasScripts; i++) {
								node = scripts[i];
								if (rscriptType.test(node.type || "") && !dataPriv.access(node, "globalEval") && jQuery.contains(doc, node)) {
	
									if (node.src && (node.type || "").toLowerCase() !== "module") {
	
										// Optional AJAX dependency, but won't run scripts if not present
										if (jQuery._evalUrl) {
											jQuery._evalUrl(node.src);
										}
									} else {
										DOMEval(node.textContent.replace(rcleanScript, ""), doc, node);
									}
								}
							}
						}
					}
				}
	
				return collection;
			}
	
			function remove(elem, selector, keepData) {
				var node,
				    nodes = selector ? jQuery.filter(selector, elem) : elem,
				    i = 0;
	
				for (; (node = nodes[i]) != null; i++) {
					if (!keepData && node.nodeType === 1) {
						jQuery.cleanData(getAll(node));
					}
	
					if (node.parentNode) {
						if (keepData && jQuery.contains(node.ownerDocument, node)) {
							setGlobalEval(getAll(node, "script"));
						}
						node.parentNode.removeChild(node);
					}
				}
	
				return elem;
			}
	
			jQuery.extend({
				htmlPrefilter: function (html) {
					return html.replace(rxhtmlTag, "<$1></$2>");
				},
	
				clone: function (elem, dataAndEvents, deepDataAndEvents) {
					var i,
					    l,
					    srcElements,
					    destElements,
					    clone = elem.cloneNode(true),
					    inPage = jQuery.contains(elem.ownerDocument, elem);
	
					// Fix IE cloning issues
					if (!support.noCloneChecked && (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem)) {
	
						// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
						destElements = getAll(clone);
						srcElements = getAll(elem);
	
						for (i = 0, l = srcElements.length; i < l; i++) {
							fixInput(srcElements[i], destElements[i]);
						}
					}
	
					// Copy the events from the original to the clone
					if (dataAndEvents) {
						if (deepDataAndEvents) {
							srcElements = srcElements || getAll(elem);
							destElements = destElements || getAll(clone);
	
							for (i = 0, l = srcElements.length; i < l; i++) {
								cloneCopyEvent(srcElements[i], destElements[i]);
							}
						} else {
							cloneCopyEvent(elem, clone);
						}
					}
	
					// Preserve script evaluation history
					destElements = getAll(clone, "script");
					if (destElements.length > 0) {
						setGlobalEval(destElements, !inPage && getAll(elem, "script"));
					}
	
					// Return the cloned set
					return clone;
				},
	
				cleanData: function (elems) {
					var data,
					    elem,
					    type,
					    special = jQuery.event.special,
					    i = 0;
	
					for (; (elem = elems[i]) !== undefined; i++) {
						if (acceptData(elem)) {
							if (data = elem[dataPriv.expando]) {
								if (data.events) {
									for (type in data.events) {
										if (special[type]) {
											jQuery.event.remove(elem, type);
	
											// This is a shortcut to avoid jQuery.event.remove's overhead
										} else {
											jQuery.removeEvent(elem, type, data.handle);
										}
									}
								}
	
								// Support: Chrome <=35 - 45+
								// Assign undefined instead of using delete, see Data#remove
								elem[dataPriv.expando] = undefined;
							}
							if (elem[dataUser.expando]) {
	
								// Support: Chrome <=35 - 45+
								// Assign undefined instead of using delete, see Data#remove
								elem[dataUser.expando] = undefined;
							}
						}
					}
				}
			});
	
			jQuery.fn.extend({
				detach: function (selector) {
					return remove(this, selector, true);
				},
	
				remove: function (selector) {
					return remove(this, selector);
				},
	
				text: function (value) {
					return access(this, function (value) {
						return value === undefined ? jQuery.text(this) : this.empty().each(function () {
							if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
								this.textContent = value;
							}
						});
					}, null, value, arguments.length);
				},
	
				append: function () {
					return domManip(this, arguments, function (elem) {
						if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
							var target = manipulationTarget(this, elem);
							target.appendChild(elem);
						}
					});
				},
	
				prepend: function () {
					return domManip(this, arguments, function (elem) {
						if (this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9) {
							var target = manipulationTarget(this, elem);
							target.insertBefore(elem, target.firstChild);
						}
					});
				},
	
				before: function () {
					return domManip(this, arguments, function (elem) {
						if (this.parentNode) {
							this.parentNode.insertBefore(elem, this);
						}
					});
				},
	
				after: function () {
					return domManip(this, arguments, function (elem) {
						if (this.parentNode) {
							this.parentNode.insertBefore(elem, this.nextSibling);
						}
					});
				},
	
				empty: function () {
					var elem,
					    i = 0;
	
					for (; (elem = this[i]) != null; i++) {
						if (elem.nodeType === 1) {
	
							// Prevent memory leaks
							jQuery.cleanData(getAll(elem, false));
	
							// Remove any remaining nodes
							elem.textContent = "";
						}
					}
	
					return this;
				},
	
				clone: function (dataAndEvents, deepDataAndEvents) {
					dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
					deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
	
					return this.map(function () {
						return jQuery.clone(this, dataAndEvents, deepDataAndEvents);
					});
				},
	
				html: function (value) {
					return access(this, function (value) {
						var elem = this[0] || {},
						    i = 0,
						    l = this.length;
	
						if (value === undefined && elem.nodeType === 1) {
							return elem.innerHTML;
						}
	
						// See if we can take a shortcut and just use innerHTML
						if (typeof value === "string" && !rnoInnerhtml.test(value) && !wrapMap[(rtagName.exec(value) || ["", ""])[1].toLowerCase()]) {
	
							value = jQuery.htmlPrefilter(value);
	
							try {
								for (; i < l; i++) {
									elem = this[i] || {};
	
									// Remove element nodes and prevent memory leaks
									if (elem.nodeType === 1) {
										jQuery.cleanData(getAll(elem, false));
										elem.innerHTML = value;
									}
								}
	
								elem = 0;
	
								// If using innerHTML throws an exception, use the fallback method
							} catch (e) {}
						}
	
						if (elem) {
							this.empty().append(value);
						}
					}, null, value, arguments.length);
				},
	
				replaceWith: function () {
					var ignored = [];
	
					// Make the changes, replacing each non-ignored context element with the new content
					return domManip(this, arguments, function (elem) {
						var parent = this.parentNode;
	
						if (jQuery.inArray(this, ignored) < 0) {
							jQuery.cleanData(getAll(this));
							if (parent) {
								parent.replaceChild(elem, this);
							}
						}
	
						// Force callback invocation
					}, ignored);
				}
			});
	
			jQuery.each({
				appendTo: "append",
				prependTo: "prepend",
				insertBefore: "before",
				insertAfter: "after",
				replaceAll: "replaceWith"
			}, function (name, original) {
				jQuery.fn[name] = function (selector) {
					var elems,
					    ret = [],
					    insert = jQuery(selector),
					    last = insert.length - 1,
					    i = 0;
	
					for (; i <= last; i++) {
						elems = i === last ? this : this.clone(true);
						jQuery(insert[i])[original](elems);
	
						// Support: Android <=4.0 only, PhantomJS 1 only
						// .get() because push.apply(_, arraylike) throws on ancient WebKit
						push.apply(ret, elems.get());
					}
	
					return this.pushStack(ret);
				};
			});
			var rnumnonpx = new RegExp("^(" + pnum + ")(?!px)[a-z%]+$", "i");
	
			var getStyles = function (elem) {
	
				// Support: IE <=11 only, Firefox <=30 (#15098, #14150)
				// IE throws on elements created in popups
				// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
				var view = elem.ownerDocument.defaultView;
	
				if (!view || !view.opener) {
					view = window;
				}
	
				return view.getComputedStyle(elem);
			};
	
			var rboxStyle = new RegExp(cssExpand.join("|"), "i");
	
			(function () {
	
				// Executing both pixelPosition & boxSizingReliable tests require only one layout
				// so they're executed at the same time to save the second computation.
				function computeStyleTests() {
	
					// This is a singleton, we need to execute it only once
					if (!div) {
						return;
					}
	
					container.style.cssText = "position:absolute;left:-11111px;width:60px;" + "margin-top:1px;padding:0;border:0";
					div.style.cssText = "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + "margin:auto;border:1px;padding:1px;" + "width:60%;top:1%";
					documentElement.appendChild(container).appendChild(div);
	
					var divStyle = window.getComputedStyle(div);
					pixelPositionVal = divStyle.top !== "1%";
	
					// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
					reliableMarginLeftVal = roundPixelMeasures(divStyle.marginLeft) === 12;
	
					// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3
					// Some styles come back with percentage values, even though they shouldn't
					div.style.right = "60%";
					pixelBoxStylesVal = roundPixelMeasures(divStyle.right) === 36;
	
					// Support: IE 9 - 11 only
					// Detect misreporting of content dimensions for box-sizing:border-box elements
					boxSizingReliableVal = roundPixelMeasures(divStyle.width) === 36;
	
					// Support: IE 9 only
					// Detect overflow:scroll screwiness (gh-3699)
					div.style.position = "absolute";
					scrollboxSizeVal = div.offsetWidth === 36 || "absolute";
	
					documentElement.removeChild(container);
	
					// Nullify the div so it wouldn't be stored in the memory and
					// it will also be a sign that checks already performed
					div = null;
				}
	
				function roundPixelMeasures(measure) {
					return Math.round(parseFloat(measure));
				}
	
				var pixelPositionVal,
				    boxSizingReliableVal,
				    scrollboxSizeVal,
				    pixelBoxStylesVal,
				    reliableMarginLeftVal,
				    container = document.createElement("div"),
				    div = document.createElement("div");
	
				// Finish early in limited (non-browser) environments
				if (!div.style) {
					return;
				}
	
				// Support: IE <=9 - 11 only
				// Style of cloned element affects source element cloned (#8908)
				div.style.backgroundClip = "content-box";
				div.cloneNode(true).style.backgroundClip = "";
				support.clearCloneStyle = div.style.backgroundClip === "content-box";
	
				jQuery.extend(support, {
					boxSizingReliable: function () {
						computeStyleTests();
						return boxSizingReliableVal;
					},
					pixelBoxStyles: function () {
						computeStyleTests();
						return pixelBoxStylesVal;
					},
					pixelPosition: function () {
						computeStyleTests();
						return pixelPositionVal;
					},
					reliableMarginLeft: function () {
						computeStyleTests();
						return reliableMarginLeftVal;
					},
					scrollboxSize: function () {
						computeStyleTests();
						return scrollboxSizeVal;
					}
				});
			})();
	
			function curCSS(elem, name, computed) {
				var width,
				    minWidth,
				    maxWidth,
				    ret,
	
	
				// Support: Firefox 51+
				// Retrieving style before computed somehow
				// fixes an issue with getting wrong values
				// on detached elements
				style = elem.style;
	
				computed = computed || getStyles(elem);
	
				// getPropertyValue is needed for:
				//   .css('filter') (IE 9 only, #12537)
				//   .css('--customProperty) (#3144)
				if (computed) {
					ret = computed.getPropertyValue(name) || computed[name];
	
					if (ret === "" && !jQuery.contains(elem.ownerDocument, elem)) {
						ret = jQuery.style(elem, name);
					}
	
					// A tribute to the "awesome hack by Dean Edwards"
					// Android Browser returns percentage for some values,
					// but width seems to be reliably pixels.
					// This is against the CSSOM draft spec:
					// https://drafts.csswg.org/cssom/#resolved-values
					if (!support.pixelBoxStyles() && rnumnonpx.test(ret) && rboxStyle.test(name)) {
	
						// Remember the original values
						width = style.width;
						minWidth = style.minWidth;
						maxWidth = style.maxWidth;
	
						// Put in the new values to get a computed value out
						style.minWidth = style.maxWidth = style.width = ret;
						ret = computed.width;
	
						// Revert the changed values
						style.width = width;
						style.minWidth = minWidth;
						style.maxWidth = maxWidth;
					}
				}
	
				return ret !== undefined ?
	
				// Support: IE <=9 - 11 only
				// IE returns zIndex value as an integer.
				ret + "" : ret;
			}
	
			function addGetHookIf(conditionFn, hookFn) {
	
				// Define the hook, we'll check on the first run if it's really needed.
				return {
					get: function () {
						if (conditionFn()) {
	
							// Hook not needed (or it's not possible to use it due
							// to missing dependency), remove it.
							delete this.get;
							return;
						}
	
						// Hook needed; redefine it so that the support test is not executed again.
						return (this.get = hookFn).apply(this, arguments);
					}
				};
			}
	
			var
	
			// Swappable if display is none or starts with table
			// except "table", "table-cell", or "table-caption"
			// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
			rdisplayswap = /^(none|table(?!-c[ea]).+)/,
			    rcustomProp = /^--/,
			    cssShow = { position: "absolute", visibility: "hidden", display: "block" },
			    cssNormalTransform = {
				letterSpacing: "0",
				fontWeight: "400"
			},
			    cssPrefixes = ["Webkit", "Moz", "ms"],
			    emptyStyle = document.createElement("div").style;
	
			// Return a css property mapped to a potentially vendor prefixed property
			function vendorPropName(name) {
	
				// Shortcut for names that are not vendor prefixed
				if (name in emptyStyle) {
					return name;
				}
	
				// Check for vendor prefixed names
				var capName = name[0].toUpperCase() + name.slice(1),
				    i = cssPrefixes.length;
	
				while (i--) {
					name = cssPrefixes[i] + capName;
					if (name in emptyStyle) {
						return name;
					}
				}
			}
	
			// Return a property mapped along what jQuery.cssProps suggests or to
			// a vendor prefixed property.
			function finalPropName(name) {
				var ret = jQuery.cssProps[name];
				if (!ret) {
					ret = jQuery.cssProps[name] = vendorPropName(name) || name;
				}
				return ret;
			}
	
			function setPositiveNumber(elem, value, subtract) {
	
				// Any relative (+/-) values have already been
				// normalized at this point
				var matches = rcssNum.exec(value);
				return matches ?
	
				// Guard against undefined "subtract", e.g., when used as in cssHooks
				Math.max(0, matches[2] - (subtract || 0)) + (matches[3] || "px") : value;
			}
	
			function boxModelAdjustment(elem, dimension, box, isBorderBox, styles, computedVal) {
				var i = dimension === "width" ? 1 : 0,
				    extra = 0,
				    delta = 0;
	
				// Adjustment may not be necessary
				if (box === (isBorderBox ? "border" : "content")) {
					return 0;
				}
	
				for (; i < 4; i += 2) {
	
					// Both box models exclude margin
					if (box === "margin") {
						delta += jQuery.css(elem, box + cssExpand[i], true, styles);
					}
	
					// If we get here with a content-box, we're seeking "padding" or "border" or "margin"
					if (!isBorderBox) {
	
						// Add padding
						delta += jQuery.css(elem, "padding" + cssExpand[i], true, styles);
	
						// For "border" or "margin", add border
						if (box !== "padding") {
							delta += jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles);
	
							// But still keep track of it otherwise
						} else {
							extra += jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles);
						}
	
						// If we get here with a border-box (content + padding + border), we're seeking "content" or
						// "padding" or "margin"
					} else {
	
						// For "content", subtract padding
						if (box === "content") {
							delta -= jQuery.css(elem, "padding" + cssExpand[i], true, styles);
						}
	
						// For "content" or "padding", subtract border
						if (box !== "margin") {
							delta -= jQuery.css(elem, "border" + cssExpand[i] + "Width", true, styles);
						}
					}
				}
	
				// Account for positive content-box scroll gutter when requested by providing computedVal
				if (!isBorderBox && computedVal >= 0) {
	
					// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
					// Assuming integer scroll gutter, subtract the rest and round down
					delta += Math.max(0, Math.ceil(elem["offset" + dimension[0].toUpperCase() + dimension.slice(1)] - computedVal - delta - extra - 0.5));
				}
	
				return delta;
			}
	
			function getWidthOrHeight(elem, dimension, extra) {
	
				// Start with computed style
				var styles = getStyles(elem),
				    val = curCSS(elem, dimension, styles),
				    isBorderBox = jQuery.css(elem, "boxSizing", false, styles) === "border-box",
				    valueIsBorderBox = isBorderBox;
	
				// Support: Firefox <=54
				// Return a confounding non-pixel value or feign ignorance, as appropriate.
				if (rnumnonpx.test(val)) {
					if (!extra) {
						return val;
					}
					val = "auto";
				}
	
				// Check for style in case a browser which returns unreliable values
				// for getComputedStyle silently falls back to the reliable elem.style
				valueIsBorderBox = valueIsBorderBox && (support.boxSizingReliable() || val === elem.style[dimension]);
	
				// Fall back to offsetWidth/offsetHeight when value is "auto"
				// This happens for inline elements with no explicit setting (gh-3571)
				// Support: Android <=4.1 - 4.3 only
				// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
				if (val === "auto" || !parseFloat(val) && jQuery.css(elem, "display", false, styles) === "inline") {
	
					val = elem["offset" + dimension[0].toUpperCase() + dimension.slice(1)];
	
					// offsetWidth/offsetHeight provide border-box values
					valueIsBorderBox = true;
				}
	
				// Normalize "" and auto
				val = parseFloat(val) || 0;
	
				// Adjust for the element's box model
				return val + boxModelAdjustment(elem, dimension, extra || (isBorderBox ? "border" : "content"), valueIsBorderBox, styles,
	
				// Provide the current computed size to request scroll gutter calculation (gh-3589)
				val) + "px";
			}
	
			jQuery.extend({
	
				// Add in style property hooks for overriding the default
				// behavior of getting and setting a style property
				cssHooks: {
					opacity: {
						get: function (elem, computed) {
							if (computed) {
	
								// We should always get a number back from opacity
								var ret = curCSS(elem, "opacity");
								return ret === "" ? "1" : ret;
							}
						}
					}
				},
	
				// Don't automatically add "px" to these possibly-unitless properties
				cssNumber: {
					"animationIterationCount": true,
					"columnCount": true,
					"fillOpacity": true,
					"flexGrow": true,
					"flexShrink": true,
					"fontWeight": true,
					"lineHeight": true,
					"opacity": true,
					"order": true,
					"orphans": true,
					"widows": true,
					"zIndex": true,
					"zoom": true
				},
	
				// Add in properties whose names you wish to fix before
				// setting or getting the value
				cssProps: {},
	
				// Get and set the style property on a DOM Node
				style: function (elem, name, value, extra) {
	
					// Don't set styles on text and comment nodes
					if (!elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style) {
						return;
					}
	
					// Make sure that we're working with the right name
					var ret,
					    type,
					    hooks,
					    origName = camelCase(name),
					    isCustomProp = rcustomProp.test(name),
					    style = elem.style;
	
					// Make sure that we're working with the right name. We don't
					// want to query the value if it is a CSS custom property
					// since they are user-defined.
					if (!isCustomProp) {
						name = finalPropName(origName);
					}
	
					// Gets hook for the prefixed version, then unprefixed version
					hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName];
	
					// Check if we're setting a value
					if (value !== undefined) {
						type = typeof value;
	
						// Convert "+=" or "-=" to relative numbers (#7345)
						if (type === "string" && (ret = rcssNum.exec(value)) && ret[1]) {
							value = adjustCSS(elem, name, ret);
	
							// Fixes bug #9237
							type = "number";
						}
	
						// Make sure that null and NaN values aren't set (#7116)
						if (value == null || value !== value) {
							return;
						}
	
						// If a number was passed in, add the unit (except for certain CSS properties)
						if (type === "number") {
							value += ret && ret[3] || (jQuery.cssNumber[origName] ? "" : "px");
						}
	
						// background-* props affect original clone's values
						if (!support.clearCloneStyle && value === "" && name.indexOf("background") === 0) {
							style[name] = "inherit";
						}
	
						// If a hook was provided, use that value, otherwise just set the specified value
						if (!hooks || !("set" in hooks) || (value = hooks.set(elem, value, extra)) !== undefined) {
	
							if (isCustomProp) {
								style.setProperty(name, value);
							} else {
								style[name] = value;
							}
						}
					} else {
	
						// If a hook was provided get the non-computed value from there
						if (hooks && "get" in hooks && (ret = hooks.get(elem, false, extra)) !== undefined) {
	
							return ret;
						}
	
						// Otherwise just get the value from the style object
						return style[name];
					}
				},
	
				css: function (elem, name, extra, styles) {
					var val,
					    num,
					    hooks,
					    origName = camelCase(name),
					    isCustomProp = rcustomProp.test(name);
	
					// Make sure that we're working with the right name. We don't
					// want to modify the value if it is a CSS custom property
					// since they are user-defined.
					if (!isCustomProp) {
						name = finalPropName(origName);
					}
	
					// Try prefixed name followed by the unprefixed name
					hooks = jQuery.cssHooks[name] || jQuery.cssHooks[origName];
	
					// If a hook was provided get the computed value from there
					if (hooks && "get" in hooks) {
						val = hooks.get(elem, true, extra);
					}
	
					// Otherwise, if a way to get the computed value exists, use that
					if (val === undefined) {
						val = curCSS(elem, name, styles);
					}
	
					// Convert "normal" to computed value
					if (val === "normal" && name in cssNormalTransform) {
						val = cssNormalTransform[name];
					}
	
					// Make numeric if forced or a qualifier was provided and val looks numeric
					if (extra === "" || extra) {
						num = parseFloat(val);
						return extra === true || isFinite(num) ? num || 0 : val;
					}
	
					return val;
				}
			});
	
			jQuery.each(["height", "width"], function (i, dimension) {
				jQuery.cssHooks[dimension] = {
					get: function (elem, computed, extra) {
						if (computed) {
	
							// Certain elements can have dimension info if we invisibly show them
							// but it must have a current display style that would benefit
							return rdisplayswap.test(jQuery.css(elem, "display")) && (
	
							// Support: Safari 8+
							// Table columns in Safari have non-zero offsetWidth & zero
							// getBoundingClientRect().width unless display is changed.
							// Support: IE <=11 only
							// Running getBoundingClientRect on a disconnected node
							// in IE throws an error.
							!elem.getClientRects().length || !elem.getBoundingClientRect().width) ? swap(elem, cssShow, function () {
								return getWidthOrHeight(elem, dimension, extra);
							}) : getWidthOrHeight(elem, dimension, extra);
						}
					},
	
					set: function (elem, value, extra) {
						var matches,
						    styles = getStyles(elem),
						    isBorderBox = jQuery.css(elem, "boxSizing", false, styles) === "border-box",
						    subtract = extra && boxModelAdjustment(elem, dimension, extra, isBorderBox, styles);
	
						// Account for unreliable border-box dimensions by comparing offset* to computed and
						// faking a content-box to get border and padding (gh-3699)
						if (isBorderBox && support.scrollboxSize() === styles.position) {
							subtract -= Math.ceil(elem["offset" + dimension[0].toUpperCase() + dimension.slice(1)] - parseFloat(styles[dimension]) - boxModelAdjustment(elem, dimension, "border", false, styles) - 0.5);
						}
	
						// Convert to pixels if value adjustment is needed
						if (subtract && (matches = rcssNum.exec(value)) && (matches[3] || "px") !== "px") {
	
							elem.style[dimension] = value;
							value = jQuery.css(elem, dimension);
						}
	
						return setPositiveNumber(elem, value, subtract);
					}
				};
			});
	
			jQuery.cssHooks.marginLeft = addGetHookIf(support.reliableMarginLeft, function (elem, computed) {
				if (computed) {
					return (parseFloat(curCSS(elem, "marginLeft")) || elem.getBoundingClientRect().left - swap(elem, { marginLeft: 0 }, function () {
						return elem.getBoundingClientRect().left;
					})) + "px";
				}
			});
	
			// These hooks are used by animate to expand properties
			jQuery.each({
				margin: "",
				padding: "",
				border: "Width"
			}, function (prefix, suffix) {
				jQuery.cssHooks[prefix + suffix] = {
					expand: function (value) {
						var i = 0,
						    expanded = {},
	
	
						// Assumes a single number if not a string
						parts = typeof value === "string" ? value.split(" ") : [value];
	
						for (; i < 4; i++) {
							expanded[prefix + cssExpand[i] + suffix] = parts[i] || parts[i - 2] || parts[0];
						}
	
						return expanded;
					}
				};
	
				if (prefix !== "margin") {
					jQuery.cssHooks[prefix + suffix].set = setPositiveNumber;
				}
			});
	
			jQuery.fn.extend({
				css: function (name, value) {
					return access(this, function (elem, name, value) {
						var styles,
						    len,
						    map = {},
						    i = 0;
	
						if (Array.isArray(name)) {
							styles = getStyles(elem);
							len = name.length;
	
							for (; i < len; i++) {
								map[name[i]] = jQuery.css(elem, name[i], false, styles);
							}
	
							return map;
						}
	
						return value !== undefined ? jQuery.style(elem, name, value) : jQuery.css(elem, name);
					}, name, value, arguments.length > 1);
				}
			});
	
			function Tween(elem, options, prop, end, easing) {
				return new Tween.prototype.init(elem, options, prop, end, easing);
			}
			jQuery.Tween = Tween;
	
			Tween.prototype = {
				constructor: Tween,
				init: function (elem, options, prop, end, easing, unit) {
					this.elem = elem;
					this.prop = prop;
					this.easing = easing || jQuery.easing._default;
					this.options = options;
					this.start = this.now = this.cur();
					this.end = end;
					this.unit = unit || (jQuery.cssNumber[prop] ? "" : "px");
				},
				cur: function () {
					var hooks = Tween.propHooks[this.prop];
	
					return hooks && hooks.get ? hooks.get(this) : Tween.propHooks._default.get(this);
				},
				run: function (percent) {
					var eased,
					    hooks = Tween.propHooks[this.prop];
	
					if (this.options.duration) {
						this.pos = eased = jQuery.easing[this.easing](percent, this.options.duration * percent, 0, 1, this.options.duration);
					} else {
						this.pos = eased = percent;
					}
					this.now = (this.end - this.start) * eased + this.start;
	
					if (this.options.step) {
						this.options.step.call(this.elem, this.now, this);
					}
	
					if (hooks && hooks.set) {
						hooks.set(this);
					} else {
						Tween.propHooks._default.set(this);
					}
					return this;
				}
			};
	
			Tween.prototype.init.prototype = Tween.prototype;
	
			Tween.propHooks = {
				_default: {
					get: function (tween) {
						var result;
	
						// Use a property on the element directly when it is not a DOM element,
						// or when there is no matching style property that exists.
						if (tween.elem.nodeType !== 1 || tween.elem[tween.prop] != null && tween.elem.style[tween.prop] == null) {
							return tween.elem[tween.prop];
						}
	
						// Passing an empty string as a 3rd parameter to .css will automatically
						// attempt a parseFloat and fallback to a string if the parse fails.
						// Simple values such as "10px" are parsed to Float;
						// complex values such as "rotate(1rad)" are returned as-is.
						result = jQuery.css(tween.elem, tween.prop, "");
	
						// Empty strings, null, undefined and "auto" are converted to 0.
						return !result || result === "auto" ? 0 : result;
					},
					set: function (tween) {
	
						// Use step hook for back compat.
						// Use cssHook if its there.
						// Use .style if available and use plain properties where available.
						if (jQuery.fx.step[tween.prop]) {
							jQuery.fx.step[tween.prop](tween);
						} else if (tween.elem.nodeType === 1 && (tween.elem.style[jQuery.cssProps[tween.prop]] != null || jQuery.cssHooks[tween.prop])) {
							jQuery.style(tween.elem, tween.prop, tween.now + tween.unit);
						} else {
							tween.elem[tween.prop] = tween.now;
						}
					}
				}
			};
	
			// Support: IE <=9 only
			// Panic based approach to setting things on disconnected nodes
			Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
				set: function (tween) {
					if (tween.elem.nodeType && tween.elem.parentNode) {
						tween.elem[tween.prop] = tween.now;
					}
				}
			};
	
			jQuery.easing = {
				linear: function (p) {
					return p;
				},
				swing: function (p) {
					return 0.5 - Math.cos(p * Math.PI) / 2;
				},
				_default: "swing"
			};
	
			jQuery.fx = Tween.prototype.init;
	
			// Back compat <1.8 extension point
			jQuery.fx.step = {};
	
			var fxNow,
			    inProgress,
			    rfxtypes = /^(?:toggle|show|hide)$/,
			    rrun = /queueHooks$/;
	
			function schedule() {
				if (inProgress) {
					if (document.hidden === false && window.requestAnimationFrame) {
						window.requestAnimationFrame(schedule);
					} else {
						window.setTimeout(schedule, jQuery.fx.interval);
					}
	
					jQuery.fx.tick();
				}
			}
	
			// Animations created synchronously will run synchronously
			function createFxNow() {
				window.setTimeout(function () {
					fxNow = undefined;
				});
				return fxNow = Date.now();
			}
	
			// Generate parameters to create a standard animation
			function genFx(type, includeWidth) {
				var which,
				    i = 0,
				    attrs = { height: type };
	
				// If we include width, step value is 1 to do all cssExpand values,
				// otherwise step value is 2 to skip over Left and Right
				includeWidth = includeWidth ? 1 : 0;
				for (; i < 4; i += 2 - includeWidth) {
					which = cssExpand[i];
					attrs["margin" + which] = attrs["padding" + which] = type;
				}
	
				if (includeWidth) {
					attrs.opacity = attrs.width = type;
				}
	
				return attrs;
			}
	
			function createTween(value, prop, animation) {
				var tween,
				    collection = (Animation.tweeners[prop] || []).concat(Animation.tweeners["*"]),
				    index = 0,
				    length = collection.length;
				for (; index < length; index++) {
					if (tween = collection[index].call(animation, prop, value)) {
	
						// We're done with this property
						return tween;
					}
				}
			}
	
			function defaultPrefilter(elem, props, opts) {
				var prop,
				    value,
				    toggle,
				    hooks,
				    oldfire,
				    propTween,
				    restoreDisplay,
				    display,
				    isBox = "width" in props || "height" in props,
				    anim = this,
				    orig = {},
				    style = elem.style,
				    hidden = elem.nodeType && isHiddenWithinTree(elem),
				    dataShow = dataPriv.get(elem, "fxshow");
	
				// Queue-skipping animations hijack the fx hooks
				if (!opts.queue) {
					hooks = jQuery._queueHooks(elem, "fx");
					if (hooks.unqueued == null) {
						hooks.unqueued = 0;
						oldfire = hooks.empty.fire;
						hooks.empty.fire = function () {
							if (!hooks.unqueued) {
								oldfire();
							}
						};
					}
					hooks.unqueued++;
	
					anim.always(function () {
	
						// Ensure the complete handler is called before this completes
						anim.always(function () {
							hooks.unqueued--;
							if (!jQuery.queue(elem, "fx").length) {
								hooks.empty.fire();
							}
						});
					});
				}
	
				// Detect show/hide animations
				for (prop in props) {
					value = props[prop];
					if (rfxtypes.test(value)) {
						delete props[prop];
						toggle = toggle || value === "toggle";
						if (value === (hidden ? "hide" : "show")) {
	
							// Pretend to be hidden if this is a "show" and
							// there is still data from a stopped show/hide
							if (value === "show" && dataShow && dataShow[prop] !== undefined) {
								hidden = true;
	
								// Ignore all other no-op show/hide data
							} else {
								continue;
							}
						}
						orig[prop] = dataShow && dataShow[prop] || jQuery.style(elem, prop);
					}
				}
	
				// Bail out if this is a no-op like .hide().hide()
				propTween = !jQuery.isEmptyObject(props);
				if (!propTween && jQuery.isEmptyObject(orig)) {
					return;
				}
	
				// Restrict "overflow" and "display" styles during box animations
				if (isBox && elem.nodeType === 1) {
	
					// Support: IE <=9 - 11, Edge 12 - 15
					// Record all 3 overflow attributes because IE does not infer the shorthand
					// from identically-valued overflowX and overflowY and Edge just mirrors
					// the overflowX value there.
					opts.overflow = [style.overflow, style.overflowX, style.overflowY];
	
					// Identify a display type, preferring old show/hide data over the CSS cascade
					restoreDisplay = dataShow && dataShow.display;
					if (restoreDisplay == null) {
						restoreDisplay = dataPriv.get(elem, "display");
					}
					display = jQuery.css(elem, "display");
					if (display === "none") {
						if (restoreDisplay) {
							display = restoreDisplay;
						} else {
	
							// Get nonempty value(s) by temporarily forcing visibility
							showHide([elem], true);
							restoreDisplay = elem.style.display || restoreDisplay;
							display = jQuery.css(elem, "display");
							showHide([elem]);
						}
					}
	
					// Animate inline elements as inline-block
					if (display === "inline" || display === "inline-block" && restoreDisplay != null) {
						if (jQuery.css(elem, "float") === "none") {
	
							// Restore the original display value at the end of pure show/hide animations
							if (!propTween) {
								anim.done(function () {
									style.display = restoreDisplay;
								});
								if (restoreDisplay == null) {
									display = style.display;
									restoreDisplay = display === "none" ? "" : display;
								}
							}
							style.display = "inline-block";
						}
					}
				}
	
				if (opts.overflow) {
					style.overflow = "hidden";
					anim.always(function () {
						style.overflow = opts.overflow[0];
						style.overflowX = opts.overflow[1];
						style.overflowY = opts.overflow[2];
					});
				}
	
				// Implement show/hide animations
				propTween = false;
				for (prop in orig) {
	
					// General show/hide setup for this element animation
					if (!propTween) {
						if (dataShow) {
							if ("hidden" in dataShow) {
								hidden = dataShow.hidden;
							}
						} else {
							dataShow = dataPriv.access(elem, "fxshow", { display: restoreDisplay });
						}
	
						// Store hidden/visible for toggle so `.stop().toggle()` "reverses"
						if (toggle) {
							dataShow.hidden = !hidden;
						}
	
						// Show elements before animating them
						if (hidden) {
							showHide([elem], true);
						}
	
						/* eslint-disable no-loop-func */
	
						anim.done(function () {
	
							/* eslint-enable no-loop-func */
	
							// The final step of a "hide" animation is actually hiding the element
							if (!hidden) {
								showHide([elem]);
							}
							dataPriv.remove(elem, "fxshow");
							for (prop in orig) {
								jQuery.style(elem, prop, orig[prop]);
							}
						});
					}
	
					// Per-property setup
					propTween = createTween(hidden ? dataShow[prop] : 0, prop, anim);
					if (!(prop in dataShow)) {
						dataShow[prop] = propTween.start;
						if (hidden) {
							propTween.end = propTween.start;
							propTween.start = 0;
						}
					}
				}
			}
	
			function propFilter(props, specialEasing) {
				var index, name, easing, value, hooks;
	
				// camelCase, specialEasing and expand cssHook pass
				for (index in props) {
					name = camelCase(index);
					easing = specialEasing[name];
					value = props[index];
					if (Array.isArray(value)) {
						easing = value[1];
						value = props[index] = value[0];
					}
	
					if (index !== name) {
						props[name] = value;
						delete props[index];
					}
	
					hooks = jQuery.cssHooks[name];
					if (hooks && "expand" in hooks) {
						value = hooks.expand(value);
						delete props[name];
	
						// Not quite $.extend, this won't overwrite existing keys.
						// Reusing 'index' because we have the correct "name"
						for (index in value) {
							if (!(index in props)) {
								props[index] = value[index];
								specialEasing[index] = easing;
							}
						}
					} else {
						specialEasing[name] = easing;
					}
				}
			}
	
			function Animation(elem, properties, options) {
				var result,
				    stopped,
				    index = 0,
				    length = Animation.prefilters.length,
				    deferred = jQuery.Deferred().always(function () {
	
					// Don't match elem in the :animated selector
					delete tick.elem;
				}),
				    tick = function () {
					if (stopped) {
						return false;
					}
					var currentTime = fxNow || createFxNow(),
					    remaining = Math.max(0, animation.startTime + animation.duration - currentTime),
	
	
					// Support: Android 2.3 only
					// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
					temp = remaining / animation.duration || 0,
					    percent = 1 - temp,
					    index = 0,
					    length = animation.tweens.length;
	
					for (; index < length; index++) {
						animation.tweens[index].run(percent);
					}
	
					deferred.notifyWith(elem, [animation, percent, remaining]);
	
					// If there's more to do, yield
					if (percent < 1 && length) {
						return remaining;
					}
	
					// If this was an empty animation, synthesize a final progress notification
					if (!length) {
						deferred.notifyWith(elem, [animation, 1, 0]);
					}
	
					// Resolve the animation and report its conclusion
					deferred.resolveWith(elem, [animation]);
					return false;
				},
				    animation = deferred.promise({
					elem: elem,
					props: jQuery.extend({}, properties),
					opts: jQuery.extend(true, {
						specialEasing: {},
						easing: jQuery.easing._default
					}, options),
					originalProperties: properties,
					originalOptions: options,
					startTime: fxNow || createFxNow(),
					duration: options.duration,
					tweens: [],
					createTween: function (prop, end) {
						var tween = jQuery.Tween(elem, animation.opts, prop, end, animation.opts.specialEasing[prop] || animation.opts.easing);
						animation.tweens.push(tween);
						return tween;
					},
					stop: function (gotoEnd) {
						var index = 0,
	
	
						// If we are going to the end, we want to run all the tweens
						// otherwise we skip this part
						length = gotoEnd ? animation.tweens.length : 0;
						if (stopped) {
							return this;
						}
						stopped = true;
						for (; index < length; index++) {
							animation.tweens[index].run(1);
						}
	
						// Resolve when we played the last frame; otherwise, reject
						if (gotoEnd) {
							deferred.notifyWith(elem, [animation, 1, 0]);
							deferred.resolveWith(elem, [animation, gotoEnd]);
						} else {
							deferred.rejectWith(elem, [animation, gotoEnd]);
						}
						return this;
					}
				}),
				    props = animation.props;
	
				propFilter(props, animation.opts.specialEasing);
	
				for (; index < length; index++) {
					result = Animation.prefilters[index].call(animation, elem, props, animation.opts);
					if (result) {
						if (isFunction(result.stop)) {
							jQuery._queueHooks(animation.elem, animation.opts.queue).stop = result.stop.bind(result);
						}
						return result;
					}
				}
	
				jQuery.map(props, createTween, animation);
	
				if (isFunction(animation.opts.start)) {
					animation.opts.start.call(elem, animation);
				}
	
				// Attach callbacks from options
				animation.progress(animation.opts.progress).done(animation.opts.done, animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always);
	
				jQuery.fx.timer(jQuery.extend(tick, {
					elem: elem,
					anim: animation,
					queue: animation.opts.queue
				}));
	
				return animation;
			}
	
			jQuery.Animation = jQuery.extend(Animation, {
	
				tweeners: {
					"*": [function (prop, value) {
						var tween = this.createTween(prop, value);
						adjustCSS(tween.elem, prop, rcssNum.exec(value), tween);
						return tween;
					}]
				},
	
				tweener: function (props, callback) {
					if (isFunction(props)) {
						callback = props;
						props = ["*"];
					} else {
						props = props.match(rnothtmlwhite);
					}
	
					var prop,
					    index = 0,
					    length = props.length;
	
					for (; index < length; index++) {
						prop = props[index];
						Animation.tweeners[prop] = Animation.tweeners[prop] || [];
						Animation.tweeners[prop].unshift(callback);
					}
				},
	
				prefilters: [defaultPrefilter],
	
				prefilter: function (callback, prepend) {
					if (prepend) {
						Animation.prefilters.unshift(callback);
					} else {
						Animation.prefilters.push(callback);
					}
				}
			});
	
			jQuery.speed = function (speed, easing, fn) {
				var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
					complete: fn || !fn && easing || isFunction(speed) && speed,
					duration: speed,
					easing: fn && easing || easing && !isFunction(easing) && easing
				};
	
				// Go to the end state if fx are off
				if (jQuery.fx.off) {
					opt.duration = 0;
				} else {
					if (typeof opt.duration !== "number") {
						if (opt.duration in jQuery.fx.speeds) {
							opt.duration = jQuery.fx.speeds[opt.duration];
						} else {
							opt.duration = jQuery.fx.speeds._default;
						}
					}
				}
	
				// Normalize opt.queue - true/undefined/null -> "fx"
				if (opt.queue == null || opt.queue === true) {
					opt.queue = "fx";
				}
	
				// Queueing
				opt.old = opt.complete;
	
				opt.complete = function () {
					if (isFunction(opt.old)) {
						opt.old.call(this);
					}
	
					if (opt.queue) {
						jQuery.dequeue(this, opt.queue);
					}
				};
	
				return opt;
			};
	
			jQuery.fn.extend({
				fadeTo: function (speed, to, easing, callback) {
	
					// Show any hidden elements after setting opacity to 0
					return this.filter(isHiddenWithinTree).css("opacity", 0).show()
	
					// Animate to the value specified
					.end().animate({ opacity: to }, speed, easing, callback);
				},
				animate: function (prop, speed, easing, callback) {
					var empty = jQuery.isEmptyObject(prop),
					    optall = jQuery.speed(speed, easing, callback),
					    doAnimation = function () {
	
						// Operate on a copy of prop so per-property easing won't be lost
						var anim = Animation(this, jQuery.extend({}, prop), optall);
	
						// Empty animations, or finishing resolves immediately
						if (empty || dataPriv.get(this, "finish")) {
							anim.stop(true);
						}
					};
					doAnimation.finish = doAnimation;
	
					return empty || optall.queue === false ? this.each(doAnimation) : this.queue(optall.queue, doAnimation);
				},
				stop: function (type, clearQueue, gotoEnd) {
					var stopQueue = function (hooks) {
						var stop = hooks.stop;
						delete hooks.stop;
						stop(gotoEnd);
					};
	
					if (typeof type !== "string") {
						gotoEnd = clearQueue;
						clearQueue = type;
						type = undefined;
					}
					if (clearQueue && type !== false) {
						this.queue(type || "fx", []);
					}
	
					return this.each(function () {
						var dequeue = true,
						    index = type != null && type + "queueHooks",
						    timers = jQuery.timers,
						    data = dataPriv.get(this);
	
						if (index) {
							if (data[index] && data[index].stop) {
								stopQueue(data[index]);
							}
						} else {
							for (index in data) {
								if (data[index] && data[index].stop && rrun.test(index)) {
									stopQueue(data[index]);
								}
							}
						}
	
						for (index = timers.length; index--;) {
							if (timers[index].elem === this && (type == null || timers[index].queue === type)) {
	
								timers[index].anim.stop(gotoEnd);
								dequeue = false;
								timers.splice(index, 1);
							}
						}
	
						// Start the next in the queue if the last step wasn't forced.
						// Timers currently will call their complete callbacks, which
						// will dequeue but only if they were gotoEnd.
						if (dequeue || !gotoEnd) {
							jQuery.dequeue(this, type);
						}
					});
				},
				finish: function (type) {
					if (type !== false) {
						type = type || "fx";
					}
					return this.each(function () {
						var index,
						    data = dataPriv.get(this),
						    queue = data[type + "queue"],
						    hooks = data[type + "queueHooks"],
						    timers = jQuery.timers,
						    length = queue ? queue.length : 0;
	
						// Enable finishing flag on private data
						data.finish = true;
	
						// Empty the queue first
						jQuery.queue(this, type, []);
	
						if (hooks && hooks.stop) {
							hooks.stop.call(this, true);
						}
	
						// Look for any active animations, and finish them
						for (index = timers.length; index--;) {
							if (timers[index].elem === this && timers[index].queue === type) {
								timers[index].anim.stop(true);
								timers.splice(index, 1);
							}
						}
	
						// Look for any animations in the old queue and finish them
						for (index = 0; index < length; index++) {
							if (queue[index] && queue[index].finish) {
								queue[index].finish.call(this);
							}
						}
	
						// Turn off finishing flag
						delete data.finish;
					});
				}
			});
	
			jQuery.each(["toggle", "show", "hide"], function (i, name) {
				var cssFn = jQuery.fn[name];
				jQuery.fn[name] = function (speed, easing, callback) {
					return speed == null || typeof speed === "boolean" ? cssFn.apply(this, arguments) : this.animate(genFx(name, true), speed, easing, callback);
				};
			});
	
			// Generate shortcuts for custom animations
			jQuery.each({
				slideDown: genFx("show"),
				slideUp: genFx("hide"),
				slideToggle: genFx("toggle"),
				fadeIn: { opacity: "show" },
				fadeOut: { opacity: "hide" },
				fadeToggle: { opacity: "toggle" }
			}, function (name, props) {
				jQuery.fn[name] = function (speed, easing, callback) {
					return this.animate(props, speed, easing, callback);
				};
			});
	
			jQuery.timers = [];
			jQuery.fx.tick = function () {
				var timer,
				    i = 0,
				    timers = jQuery.timers;
	
				fxNow = Date.now();
	
				for (; i < timers.length; i++) {
					timer = timers[i];
	
					// Run the timer and safely remove it when done (allowing for external removal)
					if (!timer() && timers[i] === timer) {
						timers.splice(i--, 1);
					}
				}
	
				if (!timers.length) {
					jQuery.fx.stop();
				}
				fxNow = undefined;
			};
	
			jQuery.fx.timer = function (timer) {
				jQuery.timers.push(timer);
				jQuery.fx.start();
			};
	
			jQuery.fx.interval = 13;
			jQuery.fx.start = function () {
				if (inProgress) {
					return;
				}
	
				inProgress = true;
				schedule();
			};
	
			jQuery.fx.stop = function () {
				inProgress = null;
			};
	
			jQuery.fx.speeds = {
				slow: 600,
				fast: 200,
	
				// Default speed
				_default: 400
			};
	
			// Based off of the plugin by Clint Helfers, with permission.
			// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
			jQuery.fn.delay = function (time, type) {
				time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
				type = type || "fx";
	
				return this.queue(type, function (next, hooks) {
					var timeout = window.setTimeout(next, time);
					hooks.stop = function () {
						window.clearTimeout(timeout);
					};
				});
			};
	
			(function () {
				var input = document.createElement("input"),
				    select = document.createElement("select"),
				    opt = select.appendChild(document.createElement("option"));
	
				input.type = "checkbox";
	
				// Support: Android <=4.3 only
				// Default value for a checkbox should be "on"
				support.checkOn = input.value !== "";
	
				// Support: IE <=11 only
				// Must access selectedIndex to make default options select
				support.optSelected = opt.selected;
	
				// Support: IE <=11 only
				// An input loses its value after becoming a radio
				input = document.createElement("input");
				input.value = "t";
				input.type = "radio";
				support.radioValue = input.value === "t";
			})();
	
			var boolHook,
			    attrHandle = jQuery.expr.attrHandle;
	
			jQuery.fn.extend({
				attr: function (name, value) {
					return access(this, jQuery.attr, name, value, arguments.length > 1);
				},
	
				removeAttr: function (name) {
					return this.each(function () {
						jQuery.removeAttr(this, name);
					});
				}
			});
	
			jQuery.extend({
				attr: function (elem, name, value) {
					var ret,
					    hooks,
					    nType = elem.nodeType;
	
					// Don't get/set attributes on text, comment and attribute nodes
					if (nType === 3 || nType === 8 || nType === 2) {
						return;
					}
	
					// Fallback to prop when attributes are not supported
					if (typeof elem.getAttribute === "undefined") {
						return jQuery.prop(elem, name, value);
					}
	
					// Attribute hooks are determined by the lowercase version
					// Grab necessary hook if one is defined
					if (nType !== 1 || !jQuery.isXMLDoc(elem)) {
						hooks = jQuery.attrHooks[name.toLowerCase()] || (jQuery.expr.match.bool.test(name) ? boolHook : undefined);
					}
	
					if (value !== undefined) {
						if (value === null) {
							jQuery.removeAttr(elem, name);
							return;
						}
	
						if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== undefined) {
							return ret;
						}
	
						elem.setAttribute(name, value + "");
						return value;
					}
	
					if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) {
						return ret;
					}
	
					ret = jQuery.find.attr(elem, name);
	
					// Non-existent attributes return null, we normalize to undefined
					return ret == null ? undefined : ret;
				},
	
				attrHooks: {
					type: {
						set: function (elem, value) {
							if (!support.radioValue && value === "radio" && nodeName(elem, "input")) {
								var val = elem.value;
								elem.setAttribute("type", value);
								if (val) {
									elem.value = val;
								}
								return value;
							}
						}
					}
				},
	
				removeAttr: function (elem, value) {
					var name,
					    i = 0,
	
	
					// Attribute names can contain non-HTML whitespace characters
					// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
					attrNames = value && value.match(rnothtmlwhite);
	
					if (attrNames && elem.nodeType === 1) {
						while (name = attrNames[i++]) {
							elem.removeAttribute(name);
						}
					}
				}
			});
	
			// Hooks for boolean attributes
			boolHook = {
				set: function (elem, value, name) {
					if (value === false) {
	
						// Remove boolean attributes when set to false
						jQuery.removeAttr(elem, name);
					} else {
						elem.setAttribute(name, name);
					}
					return name;
				}
			};
	
			jQuery.each(jQuery.expr.match.bool.source.match(/\w+/g), function (i, name) {
				var getter = attrHandle[name] || jQuery.find.attr;
	
				attrHandle[name] = function (elem, name, isXML) {
					var ret,
					    handle,
					    lowercaseName = name.toLowerCase();
	
					if (!isXML) {
	
						// Avoid an infinite loop by temporarily removing this function from the getter
						handle = attrHandle[lowercaseName];
						attrHandle[lowercaseName] = ret;
						ret = getter(elem, name, isXML) != null ? lowercaseName : null;
						attrHandle[lowercaseName] = handle;
					}
					return ret;
				};
			});
	
			var rfocusable = /^(?:input|select|textarea|button)$/i,
			    rclickable = /^(?:a|area)$/i;
	
			jQuery.fn.extend({
				prop: function (name, value) {
					return access(this, jQuery.prop, name, value, arguments.length > 1);
				},
	
				removeProp: function (name) {
					return this.each(function () {
						delete this[jQuery.propFix[name] || name];
					});
				}
			});
	
			jQuery.extend({
				prop: function (elem, name, value) {
					var ret,
					    hooks,
					    nType = elem.nodeType;
	
					// Don't get/set properties on text, comment and attribute nodes
					if (nType === 3 || nType === 8 || nType === 2) {
						return;
					}
	
					if (nType !== 1 || !jQuery.isXMLDoc(elem)) {
	
						// Fix name and attach hooks
						name = jQuery.propFix[name] || name;
						hooks = jQuery.propHooks[name];
					}
	
					if (value !== undefined) {
						if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== undefined) {
							return ret;
						}
	
						return elem[name] = value;
					}
	
					if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) {
						return ret;
					}
	
					return elem[name];
				},
	
				propHooks: {
					tabIndex: {
						get: function (elem) {
	
							// Support: IE <=9 - 11 only
							// elem.tabIndex doesn't always return the
							// correct value when it hasn't been explicitly set
							// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
							// Use proper attribute retrieval(#12072)
							var tabindex = jQuery.find.attr(elem, "tabindex");
	
							if (tabindex) {
								return parseInt(tabindex, 10);
							}
	
							if (rfocusable.test(elem.nodeName) || rclickable.test(elem.nodeName) && elem.href) {
								return 0;
							}
	
							return -1;
						}
					}
				},
	
				propFix: {
					"for": "htmlFor",
					"class": "className"
				}
			});
	
			// Support: IE <=11 only
			// Accessing the selectedIndex property
			// forces the browser to respect setting selected
			// on the option
			// The getter ensures a default option is selected
			// when in an optgroup
			// eslint rule "no-unused-expressions" is disabled for this code
			// since it considers such accessions noop
			if (!support.optSelected) {
				jQuery.propHooks.selected = {
					get: function (elem) {
	
						/* eslint no-unused-expressions: "off" */
	
						var parent = elem.parentNode;
						if (parent && parent.parentNode) {
							parent.parentNode.selectedIndex;
						}
						return null;
					},
					set: function (elem) {
	
						/* eslint no-unused-expressions: "off" */
	
						var parent = elem.parentNode;
						if (parent) {
							parent.selectedIndex;
	
							if (parent.parentNode) {
								parent.parentNode.selectedIndex;
							}
						}
					}
				};
			}
	
			jQuery.each(["tabIndex", "readOnly", "maxLength", "cellSpacing", "cellPadding", "rowSpan", "colSpan", "useMap", "frameBorder", "contentEditable"], function () {
				jQuery.propFix[this.toLowerCase()] = this;
			});
	
			// Strip and collapse whitespace according to HTML spec
			// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
			function stripAndCollapse(value) {
				var tokens = value.match(rnothtmlwhite) || [];
				return tokens.join(" ");
			}
	
			function getClass(elem) {
				return elem.getAttribute && elem.getAttribute("class") || "";
			}
	
			function classesToArray(value) {
				if (Array.isArray(value)) {
					return value;
				}
				if (typeof value === "string") {
					return value.match(rnothtmlwhite) || [];
				}
				return [];
			}
	
			jQuery.fn.extend({
				addClass: function (value) {
					var classes,
					    elem,
					    cur,
					    curValue,
					    clazz,
					    j,
					    finalValue,
					    i = 0;
	
					if (isFunction(value)) {
						return this.each(function (j) {
							jQuery(this).addClass(value.call(this, j, getClass(this)));
						});
					}
	
					classes = classesToArray(value);
	
					if (classes.length) {
						while (elem = this[i++]) {
							curValue = getClass(elem);
							cur = elem.nodeType === 1 && " " + stripAndCollapse(curValue) + " ";
	
							if (cur) {
								j = 0;
								while (clazz = classes[j++]) {
									if (cur.indexOf(" " + clazz + " ") < 0) {
										cur += clazz + " ";
									}
								}
	
								// Only assign if different to avoid unneeded rendering.
								finalValue = stripAndCollapse(cur);
								if (curValue !== finalValue) {
									elem.setAttribute("class", finalValue);
								}
							}
						}
					}
	
					return this;
				},
	
				removeClass: function (value) {
					var classes,
					    elem,
					    cur,
					    curValue,
					    clazz,
					    j,
					    finalValue,
					    i = 0;
	
					if (isFunction(value)) {
						return this.each(function (j) {
							jQuery(this).removeClass(value.call(this, j, getClass(this)));
						});
					}
	
					if (!arguments.length) {
						return this.attr("class", "");
					}
	
					classes = classesToArray(value);
	
					if (classes.length) {
						while (elem = this[i++]) {
							curValue = getClass(elem);
	
							// This expression is here for better compressibility (see addClass)
							cur = elem.nodeType === 1 && " " + stripAndCollapse(curValue) + " ";
	
							if (cur) {
								j = 0;
								while (clazz = classes[j++]) {
	
									// Remove *all* instances
									while (cur.indexOf(" " + clazz + " ") > -1) {
										cur = cur.replace(" " + clazz + " ", " ");
									}
								}
	
								// Only assign if different to avoid unneeded rendering.
								finalValue = stripAndCollapse(cur);
								if (curValue !== finalValue) {
									elem.setAttribute("class", finalValue);
								}
							}
						}
					}
	
					return this;
				},
	
				toggleClass: function (value, stateVal) {
					var type = typeof value,
					    isValidValue = type === "string" || Array.isArray(value);
	
					if (typeof stateVal === "boolean" && isValidValue) {
						return stateVal ? this.addClass(value) : this.removeClass(value);
					}
	
					if (isFunction(value)) {
						return this.each(function (i) {
							jQuery(this).toggleClass(value.call(this, i, getClass(this), stateVal), stateVal);
						});
					}
	
					return this.each(function () {
						var className, i, self, classNames;
	
						if (isValidValue) {
	
							// Toggle individual class names
							i = 0;
							self = jQuery(this);
							classNames = classesToArray(value);
	
							while (className = classNames[i++]) {
	
								// Check each className given, space separated list
								if (self.hasClass(className)) {
									self.removeClass(className);
								} else {
									self.addClass(className);
								}
							}
	
							// Toggle whole class name
						} else if (value === undefined || type === "boolean") {
							className = getClass(this);
							if (className) {
	
								// Store className if set
								dataPriv.set(this, "__className__", className);
							}
	
							// If the element has a class name or if we're passed `false`,
							// then remove the whole classname (if there was one, the above saved it).
							// Otherwise bring back whatever was previously saved (if anything),
							// falling back to the empty string if nothing was stored.
							if (this.setAttribute) {
								this.setAttribute("class", className || value === false ? "" : dataPriv.get(this, "__className__") || "");
							}
						}
					});
				},
	
				hasClass: function (selector) {
					var className,
					    elem,
					    i = 0;
	
					className = " " + selector + " ";
					while (elem = this[i++]) {
						if (elem.nodeType === 1 && (" " + stripAndCollapse(getClass(elem)) + " ").indexOf(className) > -1) {
							return true;
						}
					}
	
					return false;
				}
			});
	
			var rreturn = /\r/g;
	
			jQuery.fn.extend({
				val: function (value) {
					var hooks,
					    ret,
					    valueIsFunction,
					    elem = this[0];
	
					if (!arguments.length) {
						if (elem) {
							hooks = jQuery.valHooks[elem.type] || jQuery.valHooks[elem.nodeName.toLowerCase()];
	
							if (hooks && "get" in hooks && (ret = hooks.get(elem, "value")) !== undefined) {
								return ret;
							}
	
							ret = elem.value;
	
							// Handle most common string cases
							if (typeof ret === "string") {
								return ret.replace(rreturn, "");
							}
	
							// Handle cases where value is null/undef or number
							return ret == null ? "" : ret;
						}
	
						return;
					}
	
					valueIsFunction = isFunction(value);
	
					return this.each(function (i) {
						var val;
	
						if (this.nodeType !== 1) {
							return;
						}
	
						if (valueIsFunction) {
							val = value.call(this, i, jQuery(this).val());
						} else {
							val = value;
						}
	
						// Treat null/undefined as ""; convert numbers to string
						if (val == null) {
							val = "";
						} else if (typeof val === "number") {
							val += "";
						} else if (Array.isArray(val)) {
							val = jQuery.map(val, function (value) {
								return value == null ? "" : value + "";
							});
						}
	
						hooks = jQuery.valHooks[this.type] || jQuery.valHooks[this.nodeName.toLowerCase()];
	
						// If set returns undefined, fall back to normal setting
						if (!hooks || !("set" in hooks) || hooks.set(this, val, "value") === undefined) {
							this.value = val;
						}
					});
				}
			});
	
			jQuery.extend({
				valHooks: {
					option: {
						get: function (elem) {
	
							var val = jQuery.find.attr(elem, "value");
							return val != null ? val :
	
							// Support: IE <=10 - 11 only
							// option.text throws exceptions (#14686, #14858)
							// Strip and collapse whitespace
							// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
							stripAndCollapse(jQuery.text(elem));
						}
					},
					select: {
						get: function (elem) {
							var value,
							    option,
							    i,
							    options = elem.options,
							    index = elem.selectedIndex,
							    one = elem.type === "select-one",
							    values = one ? null : [],
							    max = one ? index + 1 : options.length;
	
							if (index < 0) {
								i = max;
							} else {
								i = one ? index : 0;
							}
	
							// Loop through all the selected options
							for (; i < max; i++) {
								option = options[i];
	
								// Support: IE <=9 only
								// IE8-9 doesn't update selected after form reset (#2551)
								if ((option.selected || i === index) &&
	
								// Don't return options that are disabled or in a disabled optgroup
								!option.disabled && (!option.parentNode.disabled || !nodeName(option.parentNode, "optgroup"))) {
	
									// Get the specific value for the option
									value = jQuery(option).val();
	
									// We don't need an array for one selects
									if (one) {
										return value;
									}
	
									// Multi-Selects return an array
									values.push(value);
								}
							}
	
							return values;
						},
	
						set: function (elem, value) {
							var optionSet,
							    option,
							    options = elem.options,
							    values = jQuery.makeArray(value),
							    i = options.length;
	
							while (i--) {
								option = options[i];
	
								/* eslint-disable no-cond-assign */
	
								if (option.selected = jQuery.inArray(jQuery.valHooks.option.get(option), values) > -1) {
									optionSet = true;
								}
	
								/* eslint-enable no-cond-assign */
							}
	
							// Force browsers to behave consistently when non-matching value is set
							if (!optionSet) {
								elem.selectedIndex = -1;
							}
							return values;
						}
					}
				}
			});
	
			// Radios and checkboxes getter/setter
			jQuery.each(["radio", "checkbox"], function () {
				jQuery.valHooks[this] = {
					set: function (elem, value) {
						if (Array.isArray(value)) {
							return elem.checked = jQuery.inArray(jQuery(elem).val(), value) > -1;
						}
					}
				};
				if (!support.checkOn) {
					jQuery.valHooks[this].get = function (elem) {
						return elem.getAttribute("value") === null ? "on" : elem.value;
					};
				}
			});
	
			// Return jQuery for attributes-only inclusion
	
	
			support.focusin = "onfocusin" in window;
	
			var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
			    stopPropagationCallback = function (e) {
				e.stopPropagation();
			};
	
			jQuery.extend(jQuery.event, {
	
				trigger: function (event, data, elem, onlyHandlers) {
	
					var i,
					    cur,
					    tmp,
					    bubbleType,
					    ontype,
					    handle,
					    special,
					    lastElement,
					    eventPath = [elem || document],
					    type = hasOwn.call(event, "type") ? event.type : event,
					    namespaces = hasOwn.call(event, "namespace") ? event.namespace.split(".") : [];
	
					cur = lastElement = tmp = elem = elem || document;
	
					// Don't do events on text and comment nodes
					if (elem.nodeType === 3 || elem.nodeType === 8) {
						return;
					}
	
					// focus/blur morphs to focusin/out; ensure we're not firing them right now
					if (rfocusMorph.test(type + jQuery.event.triggered)) {
						return;
					}
	
					if (type.indexOf(".") > -1) {
	
						// Namespaced trigger; create a regexp to match event type in handle()
						namespaces = type.split(".");
						type = namespaces.shift();
						namespaces.sort();
					}
					ontype = type.indexOf(":") < 0 && "on" + type;
	
					// Caller can pass in a jQuery.Event object, Object, or just an event type string
					event = event[jQuery.expando] ? event : new jQuery.Event(type, typeof event === "object" && event);
	
					// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
					event.isTrigger = onlyHandlers ? 2 : 3;
					event.namespace = namespaces.join(".");
					event.rnamespace = event.namespace ? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)") : null;
	
					// Clean up the event in case it is being reused
					event.result = undefined;
					if (!event.target) {
						event.target = elem;
					}
	
					// Clone any incoming data and prepend the event, creating the handler arg list
					data = data == null ? [event] : jQuery.makeArray(data, [event]);
	
					// Allow special events to draw outside the lines
					special = jQuery.event.special[type] || {};
					if (!onlyHandlers && special.trigger && special.trigger.apply(elem, data) === false) {
						return;
					}
	
					// Determine event propagation path in advance, per W3C events spec (#9951)
					// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
					if (!onlyHandlers && !special.noBubble && !isWindow(elem)) {
	
						bubbleType = special.delegateType || type;
						if (!rfocusMorph.test(bubbleType + type)) {
							cur = cur.parentNode;
						}
						for (; cur; cur = cur.parentNode) {
							eventPath.push(cur);
							tmp = cur;
						}
	
						// Only add window if we got to document (e.g., not plain obj or detached DOM)
						if (tmp === (elem.ownerDocument || document)) {
							eventPath.push(tmp.defaultView || tmp.parentWindow || window);
						}
					}
	
					// Fire handlers on the event path
					i = 0;
					while ((cur = eventPath[i++]) && !event.isPropagationStopped()) {
						lastElement = cur;
						event.type = i > 1 ? bubbleType : special.bindType || type;
	
						// jQuery handler
						handle = (dataPriv.get(cur, "events") || {})[event.type] && dataPriv.get(cur, "handle");
						if (handle) {
							handle.apply(cur, data);
						}
	
						// Native handler
						handle = ontype && cur[ontype];
						if (handle && handle.apply && acceptData(cur)) {
							event.result = handle.apply(cur, data);
							if (event.result === false) {
								event.preventDefault();
							}
						}
					}
					event.type = type;
	
					// If nobody prevented the default action, do it now
					if (!onlyHandlers && !event.isDefaultPrevented()) {
	
						if ((!special._default || special._default.apply(eventPath.pop(), data) === false) && acceptData(elem)) {
	
							// Call a native DOM method on the target with the same name as the event.
							// Don't do default actions on window, that's where global variables be (#6170)
							if (ontype && isFunction(elem[type]) && !isWindow(elem)) {
	
								// Don't re-trigger an onFOO event when we call its FOO() method
								tmp = elem[ontype];
	
								if (tmp) {
									elem[ontype] = null;
								}
	
								// Prevent re-triggering of the same event, since we already bubbled it above
								jQuery.event.triggered = type;
	
								if (event.isPropagationStopped()) {
									lastElement.addEventListener(type, stopPropagationCallback);
								}
	
								elem[type]();
	
								if (event.isPropagationStopped()) {
									lastElement.removeEventListener(type, stopPropagationCallback);
								}
	
								jQuery.event.triggered = undefined;
	
								if (tmp) {
									elem[ontype] = tmp;
								}
							}
						}
					}
	
					return event.result;
				},
	
				// Piggyback on a donor event to simulate a different one
				// Used only for `focus(in | out)` events
				simulate: function (type, elem, event) {
					var e = jQuery.extend(new jQuery.Event(), event, {
						type: type,
						isSimulated: true
					});
	
					jQuery.event.trigger(e, null, elem);
				}
	
			});
	
			jQuery.fn.extend({
	
				trigger: function (type, data) {
					return this.each(function () {
						jQuery.event.trigger(type, data, this);
					});
				},
				triggerHandler: function (type, data) {
					var elem = this[0];
					if (elem) {
						return jQuery.event.trigger(type, data, elem, true);
					}
				}
			});
	
			// Support: Firefox <=44
			// Firefox doesn't have focus(in | out) events
			// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
			//
			// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
			// focus(in | out) events fire after focus & blur events,
			// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
			// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
			if (!support.focusin) {
				jQuery.each({ focus: "focusin", blur: "focusout" }, function (orig, fix) {
	
					// Attach a single capturing handler on the document while someone wants focusin/focusout
					var handler = function (event) {
						jQuery.event.simulate(fix, event.target, jQuery.event.fix(event));
					};
	
					jQuery.event.special[fix] = {
						setup: function () {
							var doc = this.ownerDocument || this,
							    attaches = dataPriv.access(doc, fix);
	
							if (!attaches) {
								doc.addEventListener(orig, handler, true);
							}
							dataPriv.access(doc, fix, (attaches || 0) + 1);
						},
						teardown: function () {
							var doc = this.ownerDocument || this,
							    attaches = dataPriv.access(doc, fix) - 1;
	
							if (!attaches) {
								doc.removeEventListener(orig, handler, true);
								dataPriv.remove(doc, fix);
							} else {
								dataPriv.access(doc, fix, attaches);
							}
						}
					};
				});
			}
			var location = window.location;
	
			var nonce = Date.now();
	
			var rquery = /\?/;
	
			// Cross-browser xml parsing
			jQuery.parseXML = function (data) {
				var xml;
				if (!data || typeof data !== "string") {
					return null;
				}
	
				// Support: IE 9 - 11 only
				// IE throws on parseFromString with invalid input.
				try {
					xml = new window.DOMParser().parseFromString(data, "text/xml");
				} catch (e) {
					xml = undefined;
				}
	
				if (!xml || xml.getElementsByTagName("parsererror").length) {
					jQuery.error("Invalid XML: " + data);
				}
				return xml;
			};
	
			var rbracket = /\[\]$/,
			    rCRLF = /\r?\n/g,
			    rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
			    rsubmittable = /^(?:input|select|textarea|keygen)/i;
	
			function buildParams(prefix, obj, traditional, add) {
				var name;
	
				if (Array.isArray(obj)) {
	
					// Serialize array item.
					jQuery.each(obj, function (i, v) {
						if (traditional || rbracket.test(prefix)) {
	
							// Treat each array item as a scalar.
							add(prefix, v);
						} else {
	
							// Item is non-scalar (array or object), encode its numeric index.
							buildParams(prefix + "[" + (typeof v === "object" && v != null ? i : "") + "]", v, traditional, add);
						}
					});
				} else if (!traditional && toType(obj) === "object") {
	
					// Serialize object item.
					for (name in obj) {
						buildParams(prefix + "[" + name + "]", obj[name], traditional, add);
					}
				} else {
	
					// Serialize scalar item.
					add(prefix, obj);
				}
			}
	
			// Serialize an array of form elements or a set of
			// key/values into a query string
			jQuery.param = function (a, traditional) {
				var prefix,
				    s = [],
				    add = function (key, valueOrFunction) {
	
					// If value is a function, invoke it and use its return value
					var value = isFunction(valueOrFunction) ? valueOrFunction() : valueOrFunction;
	
					s[s.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value == null ? "" : value);
				};
	
				// If an array was passed in, assume that it is an array of form elements.
				if (Array.isArray(a) || a.jquery && !jQuery.isPlainObject(a)) {
	
					// Serialize the form elements
					jQuery.each(a, function () {
						add(this.name, this.value);
					});
				} else {
	
					// If traditional, encode the "old" way (the way 1.3.2 or older
					// did it), otherwise encode params recursively.
					for (prefix in a) {
						buildParams(prefix, a[prefix], traditional, add);
					}
				}
	
				// Return the resulting serialization
				return s.join("&");
			};
	
			jQuery.fn.extend({
				serialize: function () {
					return jQuery.param(this.serializeArray());
				},
				serializeArray: function () {
					return this.map(function () {
	
						// Can add propHook for "elements" to filter or add form elements
						var elements = jQuery.prop(this, "elements");
						return elements ? jQuery.makeArray(elements) : this;
					}).filter(function () {
						var type = this.type;
	
						// Use .is( ":disabled" ) so that fieldset[disabled] works
						return this.name && !jQuery(this).is(":disabled") && rsubmittable.test(this.nodeName) && !rsubmitterTypes.test(type) && (this.checked || !rcheckableType.test(type));
					}).map(function (i, elem) {
						var val = jQuery(this).val();
	
						if (val == null) {
							return null;
						}
	
						if (Array.isArray(val)) {
							return jQuery.map(val, function (val) {
								return { name: elem.name, value: val.replace(rCRLF, "\r\n") };
							});
						}
	
						return { name: elem.name, value: val.replace(rCRLF, "\r\n") };
					}).get();
				}
			});
	
			var r20 = /%20/g,
			    rhash = /#.*$/,
			    rantiCache = /([?&])_=[^&]*/,
			    rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
	
	
			// #7653, #8125, #8152: local protocol detection
			rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
			    rnoContent = /^(?:GET|HEAD)$/,
			    rprotocol = /^\/\//,
	
	
			/* Prefilters
		  * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
		  * 2) These are called:
		  *    - BEFORE asking for a transport
		  *    - AFTER param serialization (s.data is a string if s.processData is true)
		  * 3) key is the dataType
		  * 4) the catchall symbol "*" can be used
		  * 5) execution will start with transport dataType and THEN continue down to "*" if needed
		  */
			prefilters = {},
	
	
			/* Transports bindings
		  * 1) key is the dataType
		  * 2) the catchall symbol "*" can be used
		  * 3) selection will start with transport dataType and THEN go to "*" if needed
		  */
			transports = {},
	
	
			// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
			allTypes = "*/".concat("*"),
	
	
			// Anchor tag for parsing the document origin
			originAnchor = document.createElement("a");
			originAnchor.href = location.href;
	
			// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
			function addToPrefiltersOrTransports(structure) {
	
				// dataTypeExpression is optional and defaults to "*"
				return function (dataTypeExpression, func) {
	
					if (typeof dataTypeExpression !== "string") {
						func = dataTypeExpression;
						dataTypeExpression = "*";
					}
	
					var dataType,
					    i = 0,
					    dataTypes = dataTypeExpression.toLowerCase().match(rnothtmlwhite) || [];
	
					if (isFunction(func)) {
	
						// For each dataType in the dataTypeExpression
						while (dataType = dataTypes[i++]) {
	
							// Prepend if requested
							if (dataType[0] === "+") {
								dataType = dataType.slice(1) || "*";
								(structure[dataType] = structure[dataType] || []).unshift(func);
	
								// Otherwise append
							} else {
								(structure[dataType] = structure[dataType] || []).push(func);
							}
						}
					}
				};
			}
	
			// Base inspection function for prefilters and transports
			function inspectPrefiltersOrTransports(structure, options, originalOptions, jqXHR) {
	
				var inspected = {},
				    seekingTransport = structure === transports;
	
				function inspect(dataType) {
					var selected;
					inspected[dataType] = true;
					jQuery.each(structure[dataType] || [], function (_, prefilterOrFactory) {
						var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR);
						if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) {
	
							options.dataTypes.unshift(dataTypeOrTransport);
							inspect(dataTypeOrTransport);
							return false;
						} else if (seekingTransport) {
							return !(selected = dataTypeOrTransport);
						}
					});
					return selected;
				}
	
				return inspect(options.dataTypes[0]) || !inspected["*"] && inspect("*");
			}
	
			// A special extend for ajax options
			// that takes "flat" options (not to be deep extended)
			// Fixes #9887
			function ajaxExtend(target, src) {
				var key,
				    deep,
				    flatOptions = jQuery.ajaxSettings.flatOptions || {};
	
				for (key in src) {
					if (src[key] !== undefined) {
						(flatOptions[key] ? target : deep || (deep = {}))[key] = src[key];
					}
				}
				if (deep) {
					jQuery.extend(true, target, deep);
				}
	
				return target;
			}
	
			/* Handles responses to an ajax request:
		  * - finds the right dataType (mediates between content-type and expected dataType)
		  * - returns the corresponding response
		  */
			function ajaxHandleResponses(s, jqXHR, responses) {
	
				var ct,
				    type,
				    finalDataType,
				    firstDataType,
				    contents = s.contents,
				    dataTypes = s.dataTypes;
	
				// Remove auto dataType and get content-type in the process
				while (dataTypes[0] === "*") {
					dataTypes.shift();
					if (ct === undefined) {
						ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
					}
				}
	
				// Check if we're dealing with a known content-type
				if (ct) {
					for (type in contents) {
						if (contents[type] && contents[type].test(ct)) {
							dataTypes.unshift(type);
							break;
						}
					}
				}
	
				// Check to see if we have a response for the expected dataType
				if (dataTypes[0] in responses) {
					finalDataType = dataTypes[0];
				} else {
	
					// Try convertible dataTypes
					for (type in responses) {
						if (!dataTypes[0] || s.converters[type + " " + dataTypes[0]]) {
							finalDataType = type;
							break;
						}
						if (!firstDataType) {
							firstDataType = type;
						}
					}
	
					// Or just use first one
					finalDataType = finalDataType || firstDataType;
				}
	
				// If we found a dataType
				// We add the dataType to the list if needed
				// and return the corresponding response
				if (finalDataType) {
					if (finalDataType !== dataTypes[0]) {
						dataTypes.unshift(finalDataType);
					}
					return responses[finalDataType];
				}
			}
	
			/* Chain conversions given the request and the original response
		  * Also sets the responseXXX fields on the jqXHR instance
		  */
			function ajaxConvert(s, response, jqXHR, isSuccess) {
				var conv2,
				    current,
				    conv,
				    tmp,
				    prev,
				    converters = {},
	
	
				// Work with a copy of dataTypes in case we need to modify it for conversion
				dataTypes = s.dataTypes.slice();
	
				// Create converters map with lowercased keys
				if (dataTypes[1]) {
					for (conv in s.converters) {
						converters[conv.toLowerCase()] = s.converters[conv];
					}
				}
	
				current = dataTypes.shift();
	
				// Convert to each sequential dataType
				while (current) {
	
					if (s.responseFields[current]) {
						jqXHR[s.responseFields[current]] = response;
					}
	
					// Apply the dataFilter if provided
					if (!prev && isSuccess && s.dataFilter) {
						response = s.dataFilter(response, s.dataType);
					}
	
					prev = current;
					current = dataTypes.shift();
	
					if (current) {
	
						// There's only work to do if current dataType is non-auto
						if (current === "*") {
	
							current = prev;
	
							// Convert response if prev dataType is non-auto and differs from current
						} else if (prev !== "*" && prev !== current) {
	
							// Seek a direct converter
							conv = converters[prev + " " + current] || converters["* " + current];
	
							// If none found, seek a pair
							if (!conv) {
								for (conv2 in converters) {
	
									// If conv2 outputs current
									tmp = conv2.split(" ");
									if (tmp[1] === current) {
	
										// If prev can be converted to accepted input
										conv = converters[prev + " " + tmp[0]] || converters["* " + tmp[0]];
										if (conv) {
	
											// Condense equivalence converters
											if (conv === true) {
												conv = converters[conv2];
	
												// Otherwise, insert the intermediate dataType
											} else if (converters[conv2] !== true) {
												current = tmp[0];
												dataTypes.unshift(tmp[1]);
											}
											break;
										}
									}
								}
							}
	
							// Apply converter (if not an equivalence)
							if (conv !== true) {
	
								// Unless errors are allowed to bubble, catch and return them
								if (conv && s.throws) {
									response = conv(response);
								} else {
									try {
										response = conv(response);
									} catch (e) {
										return {
											state: "parsererror",
											error: conv ? e : "No conversion from " + prev + " to " + current
										};
									}
								}
							}
						}
					}
				}
	
				return { state: "success", data: response };
			}
	
			jQuery.extend({
	
				// Counter for holding the number of active queries
				active: 0,
	
				// Last-Modified header cache for next request
				lastModified: {},
				etag: {},
	
				ajaxSettings: {
					url: location.href,
					type: "GET",
					isLocal: rlocalProtocol.test(location.protocol),
					global: true,
					processData: true,
					async: true,
					contentType: "application/x-www-form-urlencoded; charset=UTF-8",
	
					/*
		   timeout: 0,
		   data: null,
		   dataType: null,
		   username: null,
		   password: null,
		   cache: null,
		   throws: false,
		   traditional: false,
		   headers: {},
		   */
	
					accepts: {
						"*": allTypes,
						text: "text/plain",
						html: "text/html",
						xml: "application/xml, text/xml",
						json: "application/json, text/javascript"
					},
	
					contents: {
						xml: /\bxml\b/,
						html: /\bhtml/,
						json: /\bjson\b/
					},
	
					responseFields: {
						xml: "responseXML",
						text: "responseText",
						json: "responseJSON"
					},
	
					// Data converters
					// Keys separate source (or catchall "*") and destination types with a single space
					converters: {
	
						// Convert anything to text
						"* text": String,
	
						// Text to html (true = no transformation)
						"text html": true,
	
						// Evaluate text as a json expression
						"text json": JSON.parse,
	
						// Parse text as xml
						"text xml": jQuery.parseXML
					},
	
					// For options that shouldn't be deep extended:
					// you can add your own custom options here if
					// and when you create one that shouldn't be
					// deep extended (see ajaxExtend)
					flatOptions: {
						url: true,
						context: true
					}
				},
	
				// Creates a full fledged settings object into target
				// with both ajaxSettings and settings fields.
				// If target is omitted, writes into ajaxSettings.
				ajaxSetup: function (target, settings) {
					return settings ?
	
					// Building a settings object
					ajaxExtend(ajaxExtend(target, jQuery.ajaxSettings), settings) :
	
					// Extending ajaxSettings
					ajaxExtend(jQuery.ajaxSettings, target);
				},
	
				ajaxPrefilter: addToPrefiltersOrTransports(prefilters),
				ajaxTransport: addToPrefiltersOrTransports(transports),
	
				// Main method
				ajax: function (url, options) {
	
					// If url is an object, simulate pre-1.5 signature
					if (typeof url === "object") {
						options = url;
						url = undefined;
					}
	
					// Force options to be an object
					options = options || {};
	
					var transport,
	
	
					// URL without anti-cache param
					cacheURL,
	
	
					// Response headers
					responseHeadersString,
					    responseHeaders,
	
	
					// timeout handle
					timeoutTimer,
	
	
					// Url cleanup var
					urlAnchor,
	
	
					// Request state (becomes false upon send and true upon completion)
					completed,
	
	
					// To know if global events are to be dispatched
					fireGlobals,
	
	
					// Loop variable
					i,
	
	
					// uncached part of the url
					uncached,
	
	
					// Create the final options object
					s = jQuery.ajaxSetup({}, options),
	
	
					// Callbacks context
					callbackContext = s.context || s,
	
	
					// Context for global events is callbackContext if it is a DOM node or jQuery collection
					globalEventContext = s.context && (callbackContext.nodeType || callbackContext.jquery) ? jQuery(callbackContext) : jQuery.event,
	
	
					// Deferreds
					deferred = jQuery.Deferred(),
					    completeDeferred = jQuery.Callbacks("once memory"),
	
	
					// Status-dependent callbacks
					statusCode = s.statusCode || {},
	
	
					// Headers (they are sent all at once)
					requestHeaders = {},
					    requestHeadersNames = {},
	
	
					// Default abort message
					strAbort = "canceled",
	
	
					// Fake xhr
					jqXHR = {
						readyState: 0,
	
						// Builds headers hashtable if needed
						getResponseHeader: function (key) {
							var match;
							if (completed) {
								if (!responseHeaders) {
									responseHeaders = {};
									while (match = rheaders.exec(responseHeadersString)) {
										responseHeaders[match[1].toLowerCase()] = match[2];
									}
								}
								match = responseHeaders[key.toLowerCase()];
							}
							return match == null ? null : match;
						},
	
						// Raw string
						getAllResponseHeaders: function () {
							return completed ? responseHeadersString : null;
						},
	
						// Caches the header
						setRequestHeader: function (name, value) {
							if (completed == null) {
								name = requestHeadersNames[name.toLowerCase()] = requestHeadersNames[name.toLowerCase()] || name;
								requestHeaders[name] = value;
							}
							return this;
						},
	
						// Overrides response content-type header
						overrideMimeType: function (type) {
							if (completed == null) {
								s.mimeType = type;
							}
							return this;
						},
	
						// Status-dependent callbacks
						statusCode: function (map) {
							var code;
							if (map) {
								if (completed) {
	
									// Execute the appropriate callbacks
									jqXHR.always(map[jqXHR.status]);
								} else {
	
									// Lazy-add the new callbacks in a way that preserves old ones
									for (code in map) {
										statusCode[code] = [statusCode[code], map[code]];
									}
								}
							}
							return this;
						},
	
						// Cancel the request
						abort: function (statusText) {
							var finalText = statusText || strAbort;
							if (transport) {
								transport.abort(finalText);
							}
							done(0, finalText);
							return this;
						}
					};
	
					// Attach deferreds
					deferred.promise(jqXHR);
	
					// Add protocol if not provided (prefilters might expect it)
					// Handle falsy url in the settings object (#10093: consistency with old signature)
					// We also use the url parameter if available
					s.url = ((url || s.url || location.href) + "").replace(rprotocol, location.protocol + "//");
	
					// Alias method option to type as per ticket #12004
					s.type = options.method || options.type || s.method || s.type;
	
					// Extract dataTypes list
					s.dataTypes = (s.dataType || "*").toLowerCase().match(rnothtmlwhite) || [""];
	
					// A cross-domain request is in order when the origin doesn't match the current origin.
					if (s.crossDomain == null) {
						urlAnchor = document.createElement("a");
	
						// Support: IE <=8 - 11, Edge 12 - 15
						// IE throws exception on accessing the href property if url is malformed,
						// e.g. http://example.com:80x/
						try {
							urlAnchor.href = s.url;
	
							// Support: IE <=8 - 11 only
							// Anchor's host property isn't correctly set when s.url is relative
							urlAnchor.href = urlAnchor.href;
							s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== urlAnchor.protocol + "//" + urlAnchor.host;
						} catch (e) {
	
							// If there is an error parsing the URL, assume it is crossDomain,
							// it can be rejected by the transport if it is invalid
							s.crossDomain = true;
						}
					}
	
					// Convert data if not already a string
					if (s.data && s.processData && typeof s.data !== "string") {
						s.data = jQuery.param(s.data, s.traditional);
					}
	
					// Apply prefilters
					inspectPrefiltersOrTransports(prefilters, s, options, jqXHR);
	
					// If request was aborted inside a prefilter, stop there
					if (completed) {
						return jqXHR;
					}
	
					// We can fire global events as of now if asked to
					// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
					fireGlobals = jQuery.event && s.global;
	
					// Watch for a new set of requests
					if (fireGlobals && jQuery.active++ === 0) {
						jQuery.event.trigger("ajaxStart");
					}
	
					// Uppercase the type
					s.type = s.type.toUpperCase();
	
					// Determine if request has content
					s.hasContent = !rnoContent.test(s.type);
	
					// Save the URL in case we're toying with the If-Modified-Since
					// and/or If-None-Match header later on
					// Remove hash to simplify url manipulation
					cacheURL = s.url.replace(rhash, "");
	
					// More options handling for requests with no content
					if (!s.hasContent) {
	
						// Remember the hash so we can put it back
						uncached = s.url.slice(cacheURL.length);
	
						// If data is available and should be processed, append data to url
						if (s.data && (s.processData || typeof s.data === "string")) {
							cacheURL += (rquery.test(cacheURL) ? "&" : "?") + s.data;
	
							// #9682: remove data so that it's not used in an eventual retry
							delete s.data;
						}
	
						// Add or update anti-cache param if needed
						if (s.cache === false) {
							cacheURL = cacheURL.replace(rantiCache, "$1");
							uncached = (rquery.test(cacheURL) ? "&" : "?") + "_=" + nonce++ + uncached;
						}
	
						// Put hash and anti-cache on the URL that will be requested (gh-1732)
						s.url = cacheURL + uncached;
	
						// Change '%20' to '+' if this is encoded form body content (gh-2658)
					} else if (s.data && s.processData && (s.contentType || "").indexOf("application/x-www-form-urlencoded") === 0) {
						s.data = s.data.replace(r20, "+");
					}
	
					// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
					if (s.ifModified) {
						if (jQuery.lastModified[cacheURL]) {
							jqXHR.setRequestHeader("If-Modified-Since", jQuery.lastModified[cacheURL]);
						}
						if (jQuery.etag[cacheURL]) {
							jqXHR.setRequestHeader("If-None-Match", jQuery.etag[cacheURL]);
						}
					}
	
					// Set the correct header, if data is being sent
					if (s.data && s.hasContent && s.contentType !== false || options.contentType) {
						jqXHR.setRequestHeader("Content-Type", s.contentType);
					}
	
					// Set the Accepts header for the server, depending on the dataType
					jqXHR.setRequestHeader("Accept", s.dataTypes[0] && s.accepts[s.dataTypes[0]] ? s.accepts[s.dataTypes[0]] + (s.dataTypes[0] !== "*" ? ", " + allTypes + "; q=0.01" : "") : s.accepts["*"]);
	
					// Check for headers option
					for (i in s.headers) {
						jqXHR.setRequestHeader(i, s.headers[i]);
					}
	
					// Allow custom headers/mimetypes and early abort
					if (s.beforeSend && (s.beforeSend.call(callbackContext, jqXHR, s) === false || completed)) {
	
						// Abort if not done already and return
						return jqXHR.abort();
					}
	
					// Aborting is no longer a cancellation
					strAbort = "abort";
	
					// Install callbacks on deferreds
					completeDeferred.add(s.complete);
					jqXHR.done(s.success);
					jqXHR.fail(s.error);
	
					// Get transport
					transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR);
	
					// If no transport, we auto-abort
					if (!transport) {
						done(-1, "No Transport");
					} else {
						jqXHR.readyState = 1;
	
						// Send global event
						if (fireGlobals) {
							globalEventContext.trigger("ajaxSend", [jqXHR, s]);
						}
	
						// If request was aborted inside ajaxSend, stop there
						if (completed) {
							return jqXHR;
						}
	
						// Timeout
						if (s.async && s.timeout > 0) {
							timeoutTimer = window.setTimeout(function () {
								jqXHR.abort("timeout");
							}, s.timeout);
						}
	
						try {
							completed = false;
							transport.send(requestHeaders, done);
						} catch (e) {
	
							// Rethrow post-completion exceptions
							if (completed) {
								throw e;
							}
	
							// Propagate others as results
							done(-1, e);
						}
					}
	
					// Callback for when everything is done
					function done(status, nativeStatusText, responses, headers) {
						var isSuccess,
						    success,
						    error,
						    response,
						    modified,
						    statusText = nativeStatusText;
	
						// Ignore repeat invocations
						if (completed) {
							return;
						}
	
						completed = true;
	
						// Clear timeout if it exists
						if (timeoutTimer) {
							window.clearTimeout(timeoutTimer);
						}
	
						// Dereference transport for early garbage collection
						// (no matter how long the jqXHR object will be used)
						transport = undefined;
	
						// Cache response headers
						responseHeadersString = headers || "";
	
						// Set readyState
						jqXHR.readyState = status > 0 ? 4 : 0;
	
						// Determine if successful
						isSuccess = status >= 200 && status < 300 || status === 304;
	
						// Get response data
						if (responses) {
							response = ajaxHandleResponses(s, jqXHR, responses);
						}
	
						// Convert no matter what (that way responseXXX fields are always set)
						response = ajaxConvert(s, response, jqXHR, isSuccess);
	
						// If successful, handle type chaining
						if (isSuccess) {
	
							// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
							if (s.ifModified) {
								modified = jqXHR.getResponseHeader("Last-Modified");
								if (modified) {
									jQuery.lastModified[cacheURL] = modified;
								}
								modified = jqXHR.getResponseHeader("etag");
								if (modified) {
									jQuery.etag[cacheURL] = modified;
								}
							}
	
							// if no content
							if (status === 204 || s.type === "HEAD") {
								statusText = "nocontent";
	
								// if not modified
							} else if (status === 304) {
								statusText = "notmodified";
	
								// If we have data, let's convert it
							} else {
								statusText = response.state;
								success = response.data;
								error = response.error;
								isSuccess = !error;
							}
						} else {
	
							// Extract error from statusText and normalize for non-aborts
							error = statusText;
							if (status || !statusText) {
								statusText = "error";
								if (status < 0) {
									status = 0;
								}
							}
						}
	
						// Set data for the fake xhr object
						jqXHR.status = status;
						jqXHR.statusText = (nativeStatusText || statusText) + "";
	
						// Success/Error
						if (isSuccess) {
							deferred.resolveWith(callbackContext, [success, statusText, jqXHR]);
						} else {
							deferred.rejectWith(callbackContext, [jqXHR, statusText, error]);
						}
	
						// Status-dependent callbacks
						jqXHR.statusCode(statusCode);
						statusCode = undefined;
	
						if (fireGlobals) {
							globalEventContext.trigger(isSuccess ? "ajaxSuccess" : "ajaxError", [jqXHR, s, isSuccess ? success : error]);
						}
	
						// Complete
						completeDeferred.fireWith(callbackContext, [jqXHR, statusText]);
	
						if (fireGlobals) {
							globalEventContext.trigger("ajaxComplete", [jqXHR, s]);
	
							// Handle the global AJAX counter
							if (! --jQuery.active) {
								jQuery.event.trigger("ajaxStop");
							}
						}
					}
	
					return jqXHR;
				},
	
				getJSON: function (url, data, callback) {
					return jQuery.get(url, data, callback, "json");
				},
	
				getScript: function (url, callback) {
					return jQuery.get(url, undefined, callback, "script");
				}
			});
	
			jQuery.each(["get", "post"], function (i, method) {
				jQuery[method] = function (url, data, callback, type) {
	
					// Shift arguments if data argument was omitted
					if (isFunction(data)) {
						type = type || callback;
						callback = data;
						data = undefined;
					}
	
					// The url can be an options object (which then must have .url)
					return jQuery.ajax(jQuery.extend({
						url: url,
						type: method,
						dataType: type,
						data: data,
						success: callback
					}, jQuery.isPlainObject(url) && url));
				};
			});
	
			jQuery._evalUrl = function (url) {
				return jQuery.ajax({
					url: url,
	
					// Make this explicit, since user can override this through ajaxSetup (#11264)
					type: "GET",
					dataType: "script",
					cache: true,
					async: false,
					global: false,
					"throws": true
				});
			};
	
			jQuery.fn.extend({
				wrapAll: function (html) {
					var wrap;
	
					if (this[0]) {
						if (isFunction(html)) {
							html = html.call(this[0]);
						}
	
						// The elements to wrap the target around
						wrap = jQuery(html, this[0].ownerDocument).eq(0).clone(true);
	
						if (this[0].parentNode) {
							wrap.insertBefore(this[0]);
						}
	
						wrap.map(function () {
							var elem = this;
	
							while (elem.firstElementChild) {
								elem = elem.firstElementChild;
							}
	
							return elem;
						}).append(this);
					}
	
					return this;
				},
	
				wrapInner: function (html) {
					if (isFunction(html)) {
						return this.each(function (i) {
							jQuery(this).wrapInner(html.call(this, i));
						});
					}
	
					return this.each(function () {
						var self = jQuery(this),
						    contents = self.contents();
	
						if (contents.length) {
							contents.wrapAll(html);
						} else {
							self.append(html);
						}
					});
				},
	
				wrap: function (html) {
					var htmlIsFunction = isFunction(html);
	
					return this.each(function (i) {
						jQuery(this).wrapAll(htmlIsFunction ? html.call(this, i) : html);
					});
				},
	
				unwrap: function (selector) {
					this.parent(selector).not("body").each(function () {
						jQuery(this).replaceWith(this.childNodes);
					});
					return this;
				}
			});
	
			jQuery.expr.pseudos.hidden = function (elem) {
				return !jQuery.expr.pseudos.visible(elem);
			};
			jQuery.expr.pseudos.visible = function (elem) {
				return !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length);
			};
	
			jQuery.ajaxSettings.xhr = function () {
				try {
					return new window.XMLHttpRequest();
				} catch (e) {}
			};
	
			var xhrSuccessStatus = {
	
				// File protocol always yields status code 0, assume 200
				0: 200,
	
				// Support: IE <=9 only
				// #1450: sometimes IE returns 1223 when it should be 204
				1223: 204
			},
			    xhrSupported = jQuery.ajaxSettings.xhr();
	
			support.cors = !!xhrSupported && "withCredentials" in xhrSupported;
			support.ajax = xhrSupported = !!xhrSupported;
	
			jQuery.ajaxTransport(function (options) {
				var callback, errorCallback;
	
				// Cross domain only allowed if supported through XMLHttpRequest
				if (support.cors || xhrSupported && !options.crossDomain) {
					return {
						send: function (headers, complete) {
							var i,
							    xhr = options.xhr();
	
							xhr.open(options.type, options.url, options.async, options.username, options.password);
	
							// Apply custom fields if provided
							if (options.xhrFields) {
								for (i in options.xhrFields) {
									xhr[i] = options.xhrFields[i];
								}
							}
	
							// Override mime type if needed
							if (options.mimeType && xhr.overrideMimeType) {
								xhr.overrideMimeType(options.mimeType);
							}
	
							// X-Requested-With header
							// For cross-domain requests, seeing as conditions for a preflight are
							// akin to a jigsaw puzzle, we simply never set it to be sure.
							// (it can always be set on a per-request basis or even using ajaxSetup)
							// For same-domain requests, won't change header if already provided.
							if (!options.crossDomain && !headers["X-Requested-With"]) {
								headers["X-Requested-With"] = "XMLHttpRequest";
							}
	
							// Set headers
							for (i in headers) {
								xhr.setRequestHeader(i, headers[i]);
							}
	
							// Callback
							callback = function (type) {
								return function () {
									if (callback) {
										callback = errorCallback = xhr.onload = xhr.onerror = xhr.onabort = xhr.ontimeout = xhr.onreadystatechange = null;
	
										if (type === "abort") {
											xhr.abort();
										} else if (type === "error") {
	
											// Support: IE <=9 only
											// On a manual native abort, IE9 throws
											// errors on any property access that is not readyState
											if (typeof xhr.status !== "number") {
												complete(0, "error");
											} else {
												complete(
	
												// File: protocol always yields status 0; see #8605, #14207
												xhr.status, xhr.statusText);
											}
										} else {
											complete(xhrSuccessStatus[xhr.status] || xhr.status, xhr.statusText,
	
											// Support: IE <=9 only
											// IE9 has no XHR2 but throws on binary (trac-11426)
											// For XHR2 non-text, let the caller handle it (gh-2498)
											(xhr.responseType || "text") !== "text" || typeof xhr.responseText !== "string" ? { binary: xhr.response } : { text: xhr.responseText }, xhr.getAllResponseHeaders());
										}
									}
								};
							};
	
							// Listen to events
							xhr.onload = callback();
							errorCallback = xhr.onerror = xhr.ontimeout = callback("error");
	
							// Support: IE 9 only
							// Use onreadystatechange to replace onabort
							// to handle uncaught aborts
							if (xhr.onabort !== undefined) {
								xhr.onabort = errorCallback;
							} else {
								xhr.onreadystatechange = function () {
	
									// Check readyState before timeout as it changes
									if (xhr.readyState === 4) {
	
										// Allow onerror to be called first,
										// but that will not handle a native abort
										// Also, save errorCallback to a variable
										// as xhr.onerror cannot be accessed
										window.setTimeout(function () {
											if (callback) {
												errorCallback();
											}
										});
									}
								};
							}
	
							// Create the abort callback
							callback = callback("abort");
	
							try {
	
								// Do send the request (this may raise an exception)
								xhr.send(options.hasContent && options.data || null);
							} catch (e) {
	
								// #14683: Only rethrow if this hasn't been notified as an error yet
								if (callback) {
									throw e;
								}
							}
						},
	
						abort: function () {
							if (callback) {
								callback();
							}
						}
					};
				}
			});
	
			// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
			jQuery.ajaxPrefilter(function (s) {
				if (s.crossDomain) {
					s.contents.script = false;
				}
			});
	
			// Install script dataType
			jQuery.ajaxSetup({
				accepts: {
					script: "text/javascript, application/javascript, " + "application/ecmascript, application/x-ecmascript"
				},
				contents: {
					script: /\b(?:java|ecma)script\b/
				},
				converters: {
					"text script": function (text) {
						jQuery.globalEval(text);
						return text;
					}
				}
			});
	
			// Handle cache's special case and crossDomain
			jQuery.ajaxPrefilter("script", function (s) {
				if (s.cache === undefined) {
					s.cache = false;
				}
				if (s.crossDomain) {
					s.type = "GET";
				}
			});
	
			// Bind script tag hack transport
			jQuery.ajaxTransport("script", function (s) {
	
				// This transport only deals with cross domain requests
				if (s.crossDomain) {
					var script, callback;
					return {
						send: function (_, complete) {
							script = jQuery("<script>").prop({
								charset: s.scriptCharset,
								src: s.url
							}).on("load error", callback = function (evt) {
								script.remove();
								callback = null;
								if (evt) {
									complete(evt.type === "error" ? 404 : 200, evt.type);
								}
							});
	
							// Use native DOM manipulation to avoid our domManip AJAX trickery
							document.head.appendChild(script[0]);
						},
						abort: function () {
							if (callback) {
								callback();
							}
						}
					};
				}
			});
	
			var oldCallbacks = [],
			    rjsonp = /(=)\?(?=&|$)|\?\?/;
	
			// Default jsonp settings
			jQuery.ajaxSetup({
				jsonp: "callback",
				jsonpCallback: function () {
					var callback = oldCallbacks.pop() || jQuery.expando + "_" + nonce++;
					this[callback] = true;
					return callback;
				}
			});
	
			// Detect, normalize options and install callbacks for jsonp requests
			jQuery.ajaxPrefilter("json jsonp", function (s, originalSettings, jqXHR) {
	
				var callbackName,
				    overwritten,
				    responseContainer,
				    jsonProp = s.jsonp !== false && (rjsonp.test(s.url) ? "url" : typeof s.data === "string" && (s.contentType || "").indexOf("application/x-www-form-urlencoded") === 0 && rjsonp.test(s.data) && "data");
	
				// Handle iff the expected data type is "jsonp" or we have a parameter to set
				if (jsonProp || s.dataTypes[0] === "jsonp") {
	
					// Get callback name, remembering preexisting value associated with it
					callbackName = s.jsonpCallback = isFunction(s.jsonpCallback) ? s.jsonpCallback() : s.jsonpCallback;
	
					// Insert callback into url or form data
					if (jsonProp) {
						s[jsonProp] = s[jsonProp].replace(rjsonp, "$1" + callbackName);
					} else if (s.jsonp !== false) {
						s.url += (rquery.test(s.url) ? "&" : "?") + s.jsonp + "=" + callbackName;
					}
	
					// Use data converter to retrieve json after script execution
					s.converters["script json"] = function () {
						if (!responseContainer) {
							jQuery.error(callbackName + " was not called");
						}
						return responseContainer[0];
					};
	
					// Force json dataType
					s.dataTypes[0] = "json";
	
					// Install callback
					overwritten = window[callbackName];
					window[callbackName] = function () {
						responseContainer = arguments;
					};
	
					// Clean-up function (fires after converters)
					jqXHR.always(function () {
	
						// If previous value didn't exist - remove it
						if (overwritten === undefined) {
							jQuery(window).removeProp(callbackName);
	
							// Otherwise restore preexisting value
						} else {
							window[callbackName] = overwritten;
						}
	
						// Save back as free
						if (s[callbackName]) {
	
							// Make sure that re-using the options doesn't screw things around
							s.jsonpCallback = originalSettings.jsonpCallback;
	
							// Save the callback name for future use
							oldCallbacks.push(callbackName);
						}
	
						// Call if it was a function and we have a response
						if (responseContainer && isFunction(overwritten)) {
							overwritten(responseContainer[0]);
						}
	
						responseContainer = overwritten = undefined;
					});
	
					// Delegate to script
					return "script";
				}
			});
	
			// Support: Safari 8 only
			// In Safari 8 documents created via document.implementation.createHTMLDocument
			// collapse sibling forms: the second one becomes a child of the first one.
			// Because of that, this security measure has to be disabled in Safari 8.
			// https://bugs.webkit.org/show_bug.cgi?id=137337
			support.createHTMLDocument = function () {
				var body = document.implementation.createHTMLDocument("").body;
				body.innerHTML = "<form></form><form></form>";
				return body.childNodes.length === 2;
			}();
	
			// Argument "data" should be string of html
			// context (optional): If specified, the fragment will be created in this context,
			// defaults to document
			// keepScripts (optional): If true, will include scripts passed in the html string
			jQuery.parseHTML = function (data, context, keepScripts) {
				if (typeof data !== "string") {
					return [];
				}
				if (typeof context === "boolean") {
					keepScripts = context;
					context = false;
				}
	
				var base, parsed, scripts;
	
				if (!context) {
	
					// Stop scripts or inline event handlers from being executed immediately
					// by using document.implementation
					if (support.createHTMLDocument) {
						context = document.implementation.createHTMLDocument("");
	
						// Set the base href for the created document
						// so any parsed elements with URLs
						// are based on the document's URL (gh-2965)
						base = context.createElement("base");
						base.href = document.location.href;
						context.head.appendChild(base);
					} else {
						context = document;
					}
				}
	
				parsed = rsingleTag.exec(data);
				scripts = !keepScripts && [];
	
				// Single tag
				if (parsed) {
					return [context.createElement(parsed[1])];
				}
	
				parsed = buildFragment([data], context, scripts);
	
				if (scripts && scripts.length) {
					jQuery(scripts).remove();
				}
	
				return jQuery.merge([], parsed.childNodes);
			};
	
			/**
		  * Load a url into a page
		  */
			jQuery.fn.load = function (url, params, callback) {
				var selector,
				    type,
				    response,
				    self = this,
				    off = url.indexOf(" ");
	
				if (off > -1) {
					selector = stripAndCollapse(url.slice(off));
					url = url.slice(0, off);
				}
	
				// If it's a function
				if (isFunction(params)) {
	
					// We assume that it's the callback
					callback = params;
					params = undefined;
	
					// Otherwise, build a param string
				} else if (params && typeof params === "object") {
					type = "POST";
				}
	
				// If we have elements to modify, make the request
				if (self.length > 0) {
					jQuery.ajax({
						url: url,
	
						// If "type" variable is undefined, then "GET" method will be used.
						// Make value of this field explicit since
						// user can override it through ajaxSetup method
						type: type || "GET",
						dataType: "html",
						data: params
					}).done(function (responseText) {
	
						// Save response for use in complete callback
						response = arguments;
	
						self.html(selector ?
	
						// If a selector was specified, locate the right elements in a dummy div
						// Exclude scripts to avoid IE 'Permission Denied' errors
						jQuery("<div>").append(jQuery.parseHTML(responseText)).find(selector) :
	
						// Otherwise use the full result
						responseText);
	
						// If the request succeeds, this function gets "data", "status", "jqXHR"
						// but they are ignored because response was set above.
						// If it fails, this function gets "jqXHR", "status", "error"
					}).always(callback && function (jqXHR, status) {
						self.each(function () {
							callback.apply(this, response || [jqXHR.responseText, status, jqXHR]);
						});
					});
				}
	
				return this;
			};
	
			// Attach a bunch of functions for handling common AJAX events
			jQuery.each(["ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend"], function (i, type) {
				jQuery.fn[type] = function (fn) {
					return this.on(type, fn);
				};
			});
	
			jQuery.expr.pseudos.animated = function (elem) {
				return jQuery.grep(jQuery.timers, function (fn) {
					return elem === fn.elem;
				}).length;
			};
	
			jQuery.offset = {
				setOffset: function (elem, options, i) {
					var curPosition,
					    curLeft,
					    curCSSTop,
					    curTop,
					    curOffset,
					    curCSSLeft,
					    calculatePosition,
					    position = jQuery.css(elem, "position"),
					    curElem = jQuery(elem),
					    props = {};
	
					// Set position first, in-case top/left are set even on static elem
					if (position === "static") {
						elem.style.position = "relative";
					}
	
					curOffset = curElem.offset();
					curCSSTop = jQuery.css(elem, "top");
					curCSSLeft = jQuery.css(elem, "left");
					calculatePosition = (position === "absolute" || position === "fixed") && (curCSSTop + curCSSLeft).indexOf("auto") > -1;
	
					// Need to be able to calculate position if either
					// top or left is auto and position is either absolute or fixed
					if (calculatePosition) {
						curPosition = curElem.position();
						curTop = curPosition.top;
						curLeft = curPosition.left;
					} else {
						curTop = parseFloat(curCSSTop) || 0;
						curLeft = parseFloat(curCSSLeft) || 0;
					}
	
					if (isFunction(options)) {
	
						// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
						options = options.call(elem, i, jQuery.extend({}, curOffset));
					}
	
					if (options.top != null) {
						props.top = options.top - curOffset.top + curTop;
					}
					if (options.left != null) {
						props.left = options.left - curOffset.left + curLeft;
					}
	
					if ("using" in options) {
						options.using.call(elem, props);
					} else {
						curElem.css(props);
					}
				}
			};
	
			jQuery.fn.extend({
	
				// offset() relates an element's border box to the document origin
				offset: function (options) {
	
					// Preserve chaining for setter
					if (arguments.length) {
						return options === undefined ? this : this.each(function (i) {
							jQuery.offset.setOffset(this, options, i);
						});
					}
	
					var rect,
					    win,
					    elem = this[0];
	
					if (!elem) {
						return;
					}
	
					// Return zeros for disconnected and hidden (display: none) elements (gh-2310)
					// Support: IE <=11 only
					// Running getBoundingClientRect on a
					// disconnected node in IE throws an error
					if (!elem.getClientRects().length) {
						return { top: 0, left: 0 };
					}
	
					// Get document-relative position by adding viewport scroll to viewport-relative gBCR
					rect = elem.getBoundingClientRect();
					win = elem.ownerDocument.defaultView;
					return {
						top: rect.top + win.pageYOffset,
						left: rect.left + win.pageXOffset
					};
				},
	
				// position() relates an element's margin box to its offset parent's padding box
				// This corresponds to the behavior of CSS absolute positioning
				position: function () {
					if (!this[0]) {
						return;
					}
	
					var offsetParent,
					    offset,
					    doc,
					    elem = this[0],
					    parentOffset = { top: 0, left: 0 };
	
					// position:fixed elements are offset from the viewport, which itself always has zero offset
					if (jQuery.css(elem, "position") === "fixed") {
	
						// Assume position:fixed implies availability of getBoundingClientRect
						offset = elem.getBoundingClientRect();
					} else {
						offset = this.offset();
	
						// Account for the *real* offset parent, which can be the document or its root element
						// when a statically positioned element is identified
						doc = elem.ownerDocument;
						offsetParent = elem.offsetParent || doc.documentElement;
						while (offsetParent && (offsetParent === doc.body || offsetParent === doc.documentElement) && jQuery.css(offsetParent, "position") === "static") {
	
							offsetParent = offsetParent.parentNode;
						}
						if (offsetParent && offsetParent !== elem && offsetParent.nodeType === 1) {
	
							// Incorporate borders into its offset, since they are outside its content origin
							parentOffset = jQuery(offsetParent).offset();
							parentOffset.top += jQuery.css(offsetParent, "borderTopWidth", true);
							parentOffset.left += jQuery.css(offsetParent, "borderLeftWidth", true);
						}
					}
	
					// Subtract parent offsets and element margins
					return {
						top: offset.top - parentOffset.top - jQuery.css(elem, "marginTop", true),
						left: offset.left - parentOffset.left - jQuery.css(elem, "marginLeft", true)
					};
				},
	
				// This method will return documentElement in the following cases:
				// 1) For the element inside the iframe without offsetParent, this method will return
				//    documentElement of the parent window
				// 2) For the hidden or detached element
				// 3) For body or html element, i.e. in case of the html node - it will return itself
				//
				// but those exceptions were never presented as a real life use-cases
				// and might be considered as more preferable results.
				//
				// This logic, however, is not guaranteed and can change at any point in the future
				offsetParent: function () {
					return this.map(function () {
						var offsetParent = this.offsetParent;
	
						while (offsetParent && jQuery.css(offsetParent, "position") === "static") {
							offsetParent = offsetParent.offsetParent;
						}
	
						return offsetParent || documentElement;
					});
				}
			});
	
			// Create scrollLeft and scrollTop methods
			jQuery.each({ scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function (method, prop) {
				var top = "pageYOffset" === prop;
	
				jQuery.fn[method] = function (val) {
					return access(this, function (elem, method, val) {
	
						// Coalesce documents and windows
						var win;
						if (isWindow(elem)) {
							win = elem;
						} else if (elem.nodeType === 9) {
							win = elem.defaultView;
						}
	
						if (val === undefined) {
							return win ? win[prop] : elem[method];
						}
	
						if (win) {
							win.scrollTo(!top ? val : win.pageXOffset, top ? val : win.pageYOffset);
						} else {
							elem[method] = val;
						}
					}, method, val, arguments.length);
				};
			});
	
			// Support: Safari <=7 - 9.1, Chrome <=37 - 49
			// Add the top/left cssHooks using jQuery.fn.position
			// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
			// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
			// getComputedStyle returns percent when specified for top/left/bottom/right;
			// rather than make the css module depend on the offset module, just check for it here
			jQuery.each(["top", "left"], function (i, prop) {
				jQuery.cssHooks[prop] = addGetHookIf(support.pixelPosition, function (elem, computed) {
					if (computed) {
						computed = curCSS(elem, prop);
	
						// If curCSS returns percentage, fallback to offset
						return rnumnonpx.test(computed) ? jQuery(elem).position()[prop] + "px" : computed;
					}
				});
			});
	
			// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
			jQuery.each({ Height: "height", Width: "width" }, function (name, type) {
				jQuery.each({ padding: "inner" + name, content: type, "": "outer" + name }, function (defaultExtra, funcName) {
	
					// Margin is only for outerHeight, outerWidth
					jQuery.fn[funcName] = function (margin, value) {
						var chainable = arguments.length && (defaultExtra || typeof margin !== "boolean"),
						    extra = defaultExtra || (margin === true || value === true ? "margin" : "border");
	
						return access(this, function (elem, type, value) {
							var doc;
	
							if (isWindow(elem)) {
	
								// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
								return funcName.indexOf("outer") === 0 ? elem["inner" + name] : elem.document.documentElement["client" + name];
							}
	
							// Get document width or height
							if (elem.nodeType === 9) {
								doc = elem.documentElement;
	
								// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
								// whichever is greatest
								return Math.max(elem.body["scroll" + name], doc["scroll" + name], elem.body["offset" + name], doc["offset" + name], doc["client" + name]);
							}
	
							return value === undefined ?
	
							// Get width or height on the element, requesting but not forcing parseFloat
							jQuery.css(elem, type, extra) :
	
							// Set width or height on the element
							jQuery.style(elem, type, value, extra);
						}, type, chainable ? margin : undefined, chainable);
					};
				});
			});
	
			jQuery.each(("blur focus focusin focusout resize scroll click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup contextmenu").split(" "), function (i, name) {
	
				// Handle event binding
				jQuery.fn[name] = function (data, fn) {
					return arguments.length > 0 ? this.on(name, null, data, fn) : this.trigger(name);
				};
			});
	
			jQuery.fn.extend({
				hover: function (fnOver, fnOut) {
					return this.mouseenter(fnOver).mouseleave(fnOut || fnOver);
				}
			});
	
			jQuery.fn.extend({
	
				bind: function (types, data, fn) {
					return this.on(types, null, data, fn);
				},
				unbind: function (types, fn) {
					return this.off(types, null, fn);
				},
	
				delegate: function (selector, types, data, fn) {
					return this.on(types, selector, data, fn);
				},
				undelegate: function (selector, types, fn) {
	
					// ( namespace ) or ( selector, types [, fn] )
					return arguments.length === 1 ? this.off(selector, "**") : this.off(types, selector || "**", fn);
				}
			});
	
			// Bind a function to a context, optionally partially applying any
			// arguments.
			// jQuery.proxy is deprecated to promote standards (specifically Function#bind)
			// However, it is not slated for removal any time soon
			jQuery.proxy = function (fn, context) {
				var tmp, args, proxy;
	
				if (typeof context === "string") {
					tmp = fn[context];
					context = fn;
					fn = tmp;
				}
	
				// Quick check to determine if target is callable, in the spec
				// this throws a TypeError, but we will just return undefined.
				if (!isFunction(fn)) {
					return undefined;
				}
	
				// Simulated bind
				args = slice.call(arguments, 2);
				proxy = function () {
					return fn.apply(context || this, args.concat(slice.call(arguments)));
				};
	
				// Set the guid of unique handler to the same of original handler, so it can be removed
				proxy.guid = fn.guid = fn.guid || jQuery.guid++;
	
				return proxy;
			};
	
			jQuery.holdReady = function (hold) {
				if (hold) {
					jQuery.readyWait++;
				} else {
					jQuery.ready(true);
				}
			};
			jQuery.isArray = Array.isArray;
			jQuery.parseJSON = JSON.parse;
			jQuery.nodeName = nodeName;
			jQuery.isFunction = isFunction;
			jQuery.isWindow = isWindow;
			jQuery.camelCase = camelCase;
			jQuery.type = toType;
	
			jQuery.now = Date.now;
	
			jQuery.isNumeric = function (obj) {
	
				// As of jQuery 3.0, isNumeric is limited to
				// strings and numbers (primitives or objects)
				// that can be coerced to finite numbers (gh-2662)
				var type = jQuery.type(obj);
				return (type === "number" || type === "string") &&
	
				// parseFloat NaNs numeric-cast false positives ("")
				// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
				// subtraction forces infinities to NaN
				!isNaN(obj - parseFloat(obj));
			};
	
			// Register as a named AMD module, since jQuery can be concatenated with other
			// files that may use define, but not via a proper concatenation script that
			// understands anonymous AMD modules. A named AMD is safest and most robust
			// way to register. Lowercase jquery is used because AMD module names are
			// derived from file names, and jQuery is normally delivered in a lowercase
			// file name. Do this after creating the global so that if an AMD module wants
			// to call noConflict to hide this version of jQuery, it will work.
	
			// Note that for maximum portability, libraries that are not jQuery should
			// declare themselves as anonymous modules, and avoid setting a global if an
			// AMD loader is present. jQuery is a special case. For more information, see
			// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
	
			if (true) {
				!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () {
					return jQuery;
				}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
			}
	
			var
	
			// Map over jQuery in case of overwrite
			_jQuery = window.jQuery,
	
	
			// Map over the $ in case of overwrite
			_$ = window.$;
	
			jQuery.noConflict = function (deep) {
				if (window.$ === jQuery) {
					window.$ = _$;
				}
	
				if (deep && window.jQuery === jQuery) {
					window.jQuery = _jQuery;
				}
	
				return jQuery;
			};
	
			// Expose jQuery and $ identifiers, even in AMD
			// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
			// and CommonJS for browser emulators (#13566)
			if (!noGlobal) {
				window.jQuery = window.$ = jQuery;
			}
	
			return jQuery;
		});
	
	/***/ }),
	/* 185 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var make_position_arr = __webpack_require__(186);
		var make_opacity_arr = __webpack_require__(187);
	
		module.exports = function make_draw_cells_arr(regl, params) {
	
		  // Make Arrays
		  var opacity_arr = make_opacity_arr(params);
		  var position_arr = make_position_arr(params);
	
		  var arrs = {};
		  arrs.opacity_arr = opacity_arr;
		  arrs.position_arr = position_arr;
	
		  // arrs.opacity_arr = arrs.opacity_arr.slice(10,20);
		  // arrs.position_arr = arrs.position_arr.slice(10,20);
	
		  console.log('hard filtering');
		  console.log(arrs.opacity_arr.length);
	
		  /*
		  Make initial array and then only keep elements that have opacity above some
		  value as a test. We might try to only render the top opacity elements while
		  zooming to speed up interaction.
		  */
	
		  _.each(arrs.opacity_arr, function (d) {
		    // console.log(d)
		  });
	
		  return arrs;
			};
	
	/***/ }),
	/* 186 */
	/***/ (function(module, exports) {
	
		// var calc_node_canvas_positions = require('./calc_node_canvas_positions');
	
		module.exports = function make_position_arr(params) {
	
		  var network = params.network;
	
		  // var num_row = params.num_row;
		  // var num_col = params.num_col;
	
		  var num_row = params.mat_data.length;
		  var num_col = params.mat_data[0].length;
	
		  // calc_node_canvas_positions();
	
		  /*
		   reverting to how positions were previously calculated
		   */
	
		  // draw matrix cells
		  /////////////////////////////////////////
		  // set up offset array for buffer
		  var offset = {};
		  offset.x = 0.5;
		  offset.y = 0.5;
	
		  // generate x position array
		  var x_arr = Array(num_col).fill().map(function (_, i) {
		    return i / num_col - offset.x;
		  });
	
		  var y_arr = Array(num_row).fill().map(function (_, i) {
		    return -i / num_row + offset.y - 1 / num_row;
		  });
	
		  node_canvas_pos = {};
		  node_canvas_pos.x_arr = x_arr;
		  node_canvas_pos.y_arr = y_arr;
	
		  var canvas_pos = params.canvas_pos;
	
		  // pass along row and col node information
		  var row_nodes = network.row_nodes;
		  var col_nodes = network.col_nodes;
	
		  // inst_order = 'rank';
		  var inst_order = 'clust';
	
		  /*
		    working on saving actual row positions (downsampling)
		  */
		  params.row_positions = _.range(row_nodes.length);
	
		  var row_order_id;
		  var col_order_id;
	
		  // generate x and y positions
		  ////////////////////////////////
		  function position_function(_, i) {
	
		    // looking up x and y position
		    var col_id = i % num_col;
		    var row_id = Math.floor(i / num_col);
	
		    if (params.is_downsampled) {
	
		      /*
		        the downsampled matrix should be plotted in its inherent order
		      */
		      row_order_id = row_id;
		      col_order_id = col_id;
		    } else {
	
		      /*
		        regular data needs to be plotted in the order given by the order
		        arguments in row_nodes/col_nodes
		      */
	
		      row_order_id = num_row - 1 - row_nodes[row_id][inst_order];
		      col_order_id = num_col - 1 - col_nodes[col_id][inst_order];
		    }
	
		    var y = node_canvas_pos.y_arr[row_order_id];
		    var x = node_canvas_pos.x_arr[col_order_id];
	
		    // var y = canvas_pos.y_arr[row_order_id];
		    // var x = canvas_pos.x_arr[col_order_id];
	
		    params.row_positions[row_id] = y;
	
		    return [x, y];
		  }
	
		  var position_arr = Array(num_row * num_col).fill().map(position_function);
	
		  return position_arr;
			};
	
	/***/ }),
	/* 187 */
	/***/ (function(module, exports) {
	
		module.exports = function make_opacity_arr(params) {
	
		  var mat_data = params.mat_data;
	
		  var opacity_arr = [].concat.apply([], mat_data);
	
		  var abs_max_val = _.max(opacity_arr, function (d) {
		    return Math.abs(d);
		  });
	
		  var opacity_scale = d3.scale.linear();
	
		  var opacity_domain = abs_max_val / 1.5;
		  var opacity_range = 0.80;
	
		  opacity_scale.domain([-opacity_domain, opacity_domain]).range([-opacity_range, opacity_range]).clamp(true);
	
		  opacity_arr = opacity_arr.map(function (x) {
		    return opacity_scale(x);
		  });
	
		  return opacity_arr;
			};
	
	/***/ }),
	/* 188 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var m3 = __webpack_require__(189);
	
		module.exports = function make_viz_aid_tri_args(regl, params, inst_rc) {
	
		  var num_rows = params['num_' + inst_rc];
	
		  var row_width = 0.025;
		  var row_height = 1 / num_rows;
	
		  var zoom_function = function (context) {
		    return context.view;
		  };
	
		  /////////////////////////////////
		  // make buffer for row offsets
		  /////////////////////////////////
	
		  var x_offset = -0.5 - row_width;
	
		  var y_offset_array = [];
		  for (var i = 0; i < num_rows; i++) {
		    y_offset_array[i] = 0.5 - row_height / 2 - i * row_height;
		  }
	
		  const y_offset_buffer = regl.buffer({
		    length: num_rows,
		    type: 'float',
		    usage: 'dynamic'
		  });
	
		  y_offset_buffer(y_offset_array);
	
		  var scale_y = m3.scaling(2, 1);
	
		  var rotation_radians;
		  if (inst_rc === 'row') {
		    rotation_radians = 0;
		  } else if (inst_rc === 'col') {
		    rotation_radians = Math.PI / 2;
		  }
	
		  var mat_rotate = m3.rotation(rotation_radians);
	
		  var args = {
	
		    vert: `
		      precision highp float;
		      attribute vec2 position;
		      attribute float y_offset_att;
	
		      uniform mat3 mat_rotate;
		      uniform mat3 scale_y;
		      uniform mat4 zoom;
		      uniform float x_offset;
	
		      varying vec3 new_position;
		      varying vec3 vec_translate;
	
		      void main () {
	
		        new_position = vec3(position, 0);
	
		        vec_translate = vec3(x_offset, y_offset_att, 0);
	
		        // rotate translated triangles
		        new_position = mat_rotate * ( new_position + vec_translate ) ;
	
		        /*
		          need to stretch column viz_aid_triangles in y direction
		        */
	
		        // depth is being set to 0.45
		        gl_Position = zoom * vec4( vec2(new_position), 0.45, 1);
	
		      }
		    `,
	
		    frag: `
	
		      // color triangle red
		      void main () {
		        gl_FragColor = vec4(0.6, 0.6, 0.6, 1);
		      }
	
		    `,
	
		    attributes: {
		      position: [[row_width, row_height / 2], [row_width / 2, 0.0], [row_width, -row_height / 2]],
		      y_offset_att: {
		        buffer: y_offset_buffer,
		        divisor: 1
		      }
		    },
	
		    uniforms: {
		      zoom: zoom_function,
		      mat_rotate: mat_rotate,
		      scale_y: scale_y,
		      x_offset: x_offset
		    },
	
		    count: 3,
		    instances: num_rows,
		    depth: {
		      enable: true,
		      mask: true,
		      func: 'less',
		      // func: 'greater',
		      range: [0, 1]
		    }
	
		  };
	
		  return args;
			};
	
	/***/ }),
	/* 189 */
	/***/ (function(module, exports) {
	
		module.exports = {
		  translation: function (tx, ty) {
		    return [1, 0, 0, 0, 1, 0, tx, ty, 1];
		  },
	
		  rotation: function (angleInRadians) {
		    var c = Math.cos(angleInRadians);
		    var s = Math.sin(angleInRadians);
		    return [c, -s, 0, s, c, 0, 0, 0, 1];
		  },
	
		  scaling: function (sx, sy) {
		    return [sx, 0, 0, 0, sy, 0, 0, 0, 1];
		  }
			};
	
	/***/ }),
	/* 190 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var m3 = __webpack_require__(189);
	
		module.exports = function draw_mat_labels(regl, num_rows, inst_rc) {
	
		  var row_width = 0.025;
		  var row_height = 1 / num_rows;
	
		  var zoom_function = function (context) {
		    return context.view;
		  };
	
		  /////////////////////////////////
		  // make buffer for row offsets
		  /////////////////////////////////
	
		  var x_offset = 0.5; // row_width;
	
		  var y_offset_array = [];
		  for (var i = 0; i < num_rows; i++) {
		    y_offset_array[i] = 0.5 - row_height / 2 - i * row_height;
		  }
	
		  const y_offset_buffer = regl.buffer({
		    length: num_rows,
		    type: 'float',
		    usage: 'dynamic'
		  });
	
		  y_offset_buffer(y_offset_array);
	
		  var mat_scale = m3.scaling(1, 1);
	
		  var rotation_radians;
		  if (inst_rc === 'row') {
		    rotation_radians = 0;
		  } else if (inst_rc === 'col') {
		    rotation_radians = Math.PI / 2;
		  }
	
		  var mat_rotate = m3.rotation(rotation_radians);
	
		  var args = {
	
		    vert: `
		      precision highp float;
		      attribute vec2 position;
		      attribute float y_offset_att;
	
		      uniform mat3 mat_rotate;
		      uniform mat3 mat_scale;
		      uniform mat4 zoom;
		      uniform float x_offset;
	
		      varying vec3 new_position;
		      varying vec3 vec_translate;
	
		      void main () {
	
		        new_position = vec3(position, 0);
	
		        vec_translate = vec3(x_offset, y_offset_att, 0);
	
		        // new_position = mat_rotate * mat_scale * new_position + vec_translate;
		        new_position = mat_rotate * ( mat_scale * new_position + vec_translate ) ;
	
		        // depth is being set to 0.45
		        gl_Position = zoom * vec4(new_position[0], new_position[1], 0.45, 1);
	
		      }
		    `,
	
		    frag: `
	
		      // color triangle red
		      void main () {
		        gl_FragColor = vec4(0.0, 1, 0.0, 1);
		      }
	
		    `,
	
		    attributes: {
		      position: [[0.0, row_height / 2], [row_width / 2, 0.0], [0.0, -row_height / 2]],
		      y_offset_att: {
		        buffer: y_offset_buffer,
		        divisor: 1
		      }
		    },
	
		    uniforms: {
		      zoom: zoom_function,
		      mat_rotate: mat_rotate,
		      mat_scale: mat_scale,
		      x_offset: x_offset
		    },
	
		    count: 3,
		    instances: num_rows,
		    depth: {
		      enable: true,
		      mask: true,
		      func: 'less',
		      // func: 'greater',
		      range: [0, 1]
		    }
	
		  };
	
		  return args;
			};
	
	/***/ }),
	/* 191 */
	/***/ (function(module, exports) {
	
		module.exports = function draw_spillover_rects(regl, zoom_function, inst_depth, inst_color = [1, 1, 1, 1]) {
	
		  // Spillover Arguments
		  ///////////////////////////////
		  var args = {
		    // In a draw call, we can pass the shader source code to regl
		    frag: `
		    precision mediump float;
		    uniform vec4 color;
		    void main () {
		      gl_FragColor = color;
		    }`,
	
		    vert: `
		    precision mediump float;
		    attribute vec2 position;
		    uniform float inst_depth;
		    void main () {
		      // positioned further up (matrix is lower at 0.)
		      gl_Position = vec4(position, inst_depth, 1);
		    }`,
	
		    attributes: {
		      position: regl.prop('pos')
		    },
	
		    uniforms: {
		      color: inst_color,
		      inst_depth: inst_depth
		    },
	
		    count: 3,
		    depth: {
		      enable: true,
		      mask: true,
		      func: 'less',
		      // func: 'greater',
		      range: [0, 1]
		    }
		  };
	
		  return args;
			};
	
	/***/ }),
	/* 192 */
	/***/ (function(module, exports) {
	
		module.exports = function calc_viz_area(params) {
	
		  // console.log('calc_viz_area');
	
		  var zoom_data = params.zoom_data;
	
		  // make a d3.scale to transition from 0px - 500px to -1, 1 space
		  var mat_width = params.viz_dim.mat.width;
		  var mat_height = params.viz_dim.mat.height;
	
		  var pix_to_webgl = {};
	
		  pix_to_webgl.x = d3.scale.linear();
		  pix_to_webgl.x.domain([0, mat_height]).range([-0.5, 0.5]).clamp(true);
	
		  /*
		     Experimenting with scales to improve viz area calculation
		   */
	
		  pix_to_webgl.y = d3.scale.linear();
		  pix_to_webgl.y.domain([0, mat_width]).range([0.5, -0.5]).clamp(true);
	
		  var tmp_scale = 1.0;
	
		  // panning is defined as negative pixel values
		  var total_pan = {};
		  total_pan.x_min = -zoom_data.x.total_pan_min;
		  total_pan.x_max = mat_width * tmp_scale + zoom_data.x.total_pan_max;
	
		  total_pan.y_min = -zoom_data.y.total_pan_min;
		  total_pan.y_max = mat_width * tmp_scale + zoom_data.y.total_pan_max;
	
		  var buffer_width = 0.0;
	
		  var viz_area = {};
		  viz_area.x_min = pix_to_webgl.x(total_pan.x_min) - buffer_width;
		  viz_area.x_max = pix_to_webgl.x(total_pan.x_max) + buffer_width;
	
		  /*
		  experimenting with viz_area calc
		  */
	
		  viz_area.y_max = pix_to_webgl.y(total_pan.y_min) - buffer_width;
		  viz_area.y_min = pix_to_webgl.y(total_pan.y_max) + buffer_width;
	
		  // console.log('y_min', viz_area.y_min);
		  // console.log('y_max', viz_area.y_max);
	
		  params.viz_area = viz_area;
			};
	
	/***/ }),
	/* 193 */
	/***/ (function(module, exports) {
	
		module.exports = function calc_row_downsampled_mat(params, run_downsampling = false) {
	
		  // console.log('calc_row_downsampled_mat');
	
		  var mat_data = params.mat_data;
		  var row_pos = params.row_positions;
		  var ds_mat = [];
		  var inst_pos;
	
		  if (run_downsampling) {
		    /*
		      Perform trivial downsampling (subsampling)
		    */
	
		    mat_data = params.mat_data;
		    mat_data = mat_data.slice(0, 5);
	
		    // column downsampling
		    new_mat_data = [];
		    _.each(mat_data, function (inst_row) {
		      inst_row = inst_row.slice(0, 3);
		      new_mat_data.push(inst_row);
		    });
	
		    params.mat_data = new_mat_data;
		    params.is_downsampled = true;
		  }
	
		  /*
		    Working on actual downsampling
		  */
	
		  /*
		    row_pos go from -0.5 to 0.5
		  */
	
		  // make 10 positions
		  var new_pos = _.range(-0.5, 0.5, 0.1);
		  console.log(new_pos.length);
	
		  // mod_value = 0.1;
	
		  // _.each(mat_data, function(inst_row, inst_index){
	
		  //   inst_pos = row_pos[inst_index];
	
		  //   ds_pos = Math.round(inst_pos/mod_value);
	
		  //   console.log('inst_pos: ', inst_pos);
		  //   console.log('ds_pos', ds_pos)
		  //   console.log('\n');
	
		  // });
			};
	
	/***/ }),
	/* 194 */
	/***/ (function(module, exports, __webpack_require__) {
	
		module.exports = __webpack_require__(195);
	
	/***/ }),
	/* 195 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var isFactory = __webpack_require__(196).isFactory;
		var typedFactory = __webpack_require__(198);
		var emitter = __webpack_require__(202);
	
		var importFactory = __webpack_require__(204);
		var configFactory = __webpack_require__(206);
	
		/**
		 * Math.js core. Creates a new, empty math.js instance
		 * @param {Object} [options] Available options:
		 *                            {number} epsilon
		 *                              Minimum relative difference between two
		 *                              compared values, used by all comparison functions.
		 *                            {string} matrix
		 *                              A string 'Matrix' (default) or 'Array'.
		 *                            {string} number
		 *                              A string 'number' (default), 'BigNumber', or 'Fraction'
		 *                            {number} precision
		 *                              The number of significant digits for BigNumbers.
		 *                              Not applicable for Numbers.
		 *                            {boolean} predictable
		 *                              Predictable output type of functions. When true,
		 *                              output type depends only on the input types. When
		 *                              false (default), output type can vary depending
		 *                              on input values. For example `math.sqrt(-4)`
		 *                              returns `complex('2i')` when predictable is false, and
		 *                              returns `NaN` when true.
		 *                            {string} randomSeed
		 *                              Random seed for seeded pseudo random number generator.
		 *                              Set to null to randomly seed.
		 * @returns {Object} Returns a bare-bone math.js instance containing
		 *                   functions:
		 *                   - `import` to add new functions
		 *                   - `config` to change configuration
		 *                   - `on`, `off`, `once`, `emit` for events
		 */
		exports.create = function create(options) {
		  // simple test for ES5 support
		  if (typeof Object.create !== 'function') {
		    throw new Error('ES5 not supported by this JavaScript engine. ' + 'Please load the es5-shim and es5-sham library for compatibility.');
		  }
	
		  // cached factories and instances
		  var factories = [];
		  var instances = [];
	
		  // create a namespace for the mathjs instance, and attach emitter functions
		  var math = emitter.mixin({});
		  math.type = {};
		  math.expression = {
		    transform: {},
		    mathWithTransform: {}
		  };
	
		  // create a new typed instance
		  math.typed = typedFactory.create(math.type);
	
		  // create configuration options. These are private
		  var _config = {
		    // minimum relative difference between two compared values,
		    // used by all comparison functions
		    epsilon: 1e-12,
	
		    // type of default matrix output. Choose 'matrix' (default) or 'array'
		    matrix: 'Matrix',
	
		    // type of default number output. Choose 'number' (default) 'BigNumber', or 'Fraction
		    number: 'number',
	
		    // number of significant digits in BigNumbers
		    precision: 64,
	
		    // predictable output type of functions. When true, output type depends only
		    // on the input types. When false (default), output type can vary depending
		    // on input values. For example `math.sqrt(-4)` returns `complex('2i')` when
		    // predictable is false, and returns `NaN` when true.
		    predictable: false,
	
		    // random seed for seeded pseudo random number generation
		    // null = randomly seed
		    randomSeed: null
		  };
	
		  /**
		   * Load a function or data type from a factory.
		   * If the function or data type already exists, the existing instance is
		   * returned.
		   * @param {{type: string, name: string, factory: Function}} factory
		   * @returns {*}
		   */
		  function load(factory) {
		    if (!isFactory(factory)) {
		      throw new Error('Factory object with properties `type`, `name`, and `factory` expected');
		    }
	
		    var index = factories.indexOf(factory);
		    var instance;
		    if (index === -1) {
		      // doesn't yet exist
		      if (factory.math === true) {
		        // pass with math namespace
		        instance = factory.factory(math.type, _config, load, math.typed, math);
		      } else {
		        instance = factory.factory(math.type, _config, load, math.typed);
		      }
	
		      // append to the cache
		      factories.push(factory);
		      instances.push(instance);
		    } else {
		      // already existing function, return the cached instance
		      instance = instances[index];
		    }
	
		    return instance;
		  }
	
		  // load the import and config functions
		  math['import'] = load(importFactory);
		  math['config'] = load(configFactory);
		  math.expression.mathWithTransform['config'] = math['config'];
	
		  // apply options
		  if (options) {
		    math.config(options);
		  }
	
		  return math;
		};
	
	/***/ }),
	/* 196 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var isBigNumber = __webpack_require__(197);
	
		/**
		 * Clone an object
		 *
		 *     clone(x)
		 *
		 * Can clone any primitive type, array, and object.
		 * If x has a function clone, this function will be invoked to clone the object.
		 *
		 * @param {*} x
		 * @return {*} clone
		 */
		exports.clone = function clone(x) {
		  var type = typeof x;
	
		  // immutable primitive types
		  if (type === 'number' || type === 'string' || type === 'boolean' || x === null || x === undefined) {
		    return x;
		  }
	
		  // use clone function of the object when available
		  if (typeof x.clone === 'function') {
		    return x.clone();
		  }
	
		  // array
		  if (Array.isArray(x)) {
		    return x.map(function (value) {
		      return clone(value);
		    });
		  }
	
		  if (x instanceof Number) return new Number(x.valueOf());
		  if (x instanceof String) return new String(x.valueOf());
		  if (x instanceof Boolean) return new Boolean(x.valueOf());
		  if (x instanceof Date) return new Date(x.valueOf());
		  if (isBigNumber(x)) return x; // bignumbers are immutable
		  if (x instanceof RegExp) throw new TypeError('Cannot clone ' + x); // TODO: clone a RegExp
	
		  // object
		  return exports.map(x, clone);
		};
	
		/**
		 * Apply map to all properties of an object
		 * @param {Object} object
		 * @param {function} callback
		 * @return {Object} Returns a copy of the object with mapped properties
		 */
		exports.map = function (object, callback) {
		  var clone = {};
	
		  for (var key in object) {
		    if (exports.hasOwnProperty(object, key)) {
		      clone[key] = callback(object[key]);
		    }
		  }
	
		  return clone;
		};
	
		/**
		 * Extend object a with the properties of object b
		 * @param {Object} a
		 * @param {Object} b
		 * @return {Object} a
		 */
		exports.extend = function (a, b) {
		  for (var prop in b) {
		    if (exports.hasOwnProperty(b, prop)) {
		      a[prop] = b[prop];
		    }
		  }
		  return a;
		};
	
		/**
		 * Deep extend an object a with the properties of object b
		 * @param {Object} a
		 * @param {Object} b
		 * @returns {Object}
		 */
		exports.deepExtend = function deepExtend(a, b) {
		  // TODO: add support for Arrays to deepExtend
		  if (Array.isArray(b)) {
		    throw new TypeError('Arrays are not supported by deepExtend');
		  }
	
		  for (var prop in b) {
		    if (exports.hasOwnProperty(b, prop)) {
		      if (b[prop] && b[prop].constructor === Object) {
		        if (a[prop] === undefined) {
		          a[prop] = {};
		        }
		        if (a[prop].constructor === Object) {
		          deepExtend(a[prop], b[prop]);
		        } else {
		          a[prop] = b[prop];
		        }
		      } else if (Array.isArray(b[prop])) {
		        throw new TypeError('Arrays are not supported by deepExtend');
		      } else {
		        a[prop] = b[prop];
		      }
		    }
		  }
		  return a;
		};
	
		/**
		 * Deep test equality of all fields in two pairs of arrays or objects.
		 * @param {Array | Object} a
		 * @param {Array | Object} b
		 * @returns {boolean}
		 */
		exports.deepEqual = function deepEqual(a, b) {
		  var prop, i, len;
		  if (Array.isArray(a)) {
		    if (!Array.isArray(b)) {
		      return false;
		    }
	
		    if (a.length != b.length) {
		      return false;
		    }
	
		    for (i = 0, len = a.length; i < len; i++) {
		      if (!exports.deepEqual(a[i], b[i])) {
		        return false;
		      }
		    }
		    return true;
		  } else if (a instanceof Object) {
		    if (Array.isArray(b) || !(b instanceof Object)) {
		      return false;
		    }
	
		    for (prop in a) {
		      //noinspection JSUnfilteredForInLoop
		      if (!exports.deepEqual(a[prop], b[prop])) {
		        return false;
		      }
		    }
		    for (prop in b) {
		      //noinspection JSUnfilteredForInLoop
		      if (!exports.deepEqual(a[prop], b[prop])) {
		        return false;
		      }
		    }
		    return true;
		  } else {
		    return typeof a === typeof b && a == b;
		  }
		};
	
		/**
		 * Test whether the current JavaScript engine supports Object.defineProperty
		 * @returns {boolean} returns true if supported
		 */
		exports.canDefineProperty = function () {
		  // test needed for broken IE8 implementation
		  try {
		    if (Object.defineProperty) {
		      Object.defineProperty({}, 'x', { get: function () {} });
		      return true;
		    }
		  } catch (e) {}
	
		  return false;
		};
	
		/**
		 * Attach a lazy loading property to a constant.
		 * The given function `fn` is called once when the property is first requested.
		 * On older browsers (<IE8), the function will fall back to direct evaluation
		 * of the properties value.
		 * @param {Object} object   Object where to add the property
		 * @param {string} prop     Property name
		 * @param {Function} fn     Function returning the property value. Called
		 *                          without arguments.
		 */
		exports.lazy = function (object, prop, fn) {
		  if (exports.canDefineProperty()) {
		    var _uninitialized = true;
		    var _value;
		    Object.defineProperty(object, prop, {
		      get: function () {
		        if (_uninitialized) {
		          _value = fn();
		          _uninitialized = false;
		        }
		        return _value;
		      },
	
		      set: function (value) {
		        _value = value;
		        _uninitialized = false;
		      },
	
		      configurable: true,
		      enumerable: true
		    });
		  } else {
		    // fall back to immediate evaluation
		    object[prop] = fn();
		  }
		};
	
		/**
		 * Traverse a path into an object.
		 * When a namespace is missing, it will be created
		 * @param {Object} object
		 * @param {string} path   A dot separated string like 'name.space'
		 * @return {Object} Returns the object at the end of the path
		 */
		exports.traverse = function (object, path) {
		  var obj = object;
	
		  if (path) {
		    var names = path.split('.');
		    for (var i = 0; i < names.length; i++) {
		      var name = names[i];
		      if (!(name in obj)) {
		        obj[name] = {};
		      }
		      obj = obj[name];
		    }
		  }
	
		  return obj;
		};
	
		/**
		 * A safe hasOwnProperty
		 * @param {Object} object
		 * @param {string} property
		 */
		exports.hasOwnProperty = function (object, property) {
		  return object && Object.hasOwnProperty.call(object, property);
		};
	
		/**
		 * Test whether an object is a factory. a factory has fields:
		 *
		 * - factory: function (type: Object, config: Object, load: function, typed: function [, math: Object])   (required)
		 * - name: string (optional)
		 * - path: string    A dot separated path (optional)
		 * - math: boolean   If true (false by default), the math namespace is passed
		 *                   as fifth argument of the factory function
		 *
		 * @param {*} object
		 * @returns {boolean}
		 */
		exports.isFactory = function (object) {
		  return object && typeof object.factory === 'function';
		};
	
	/***/ }),
	/* 197 */
	/***/ (function(module, exports) {
	
		/**
		 * Test whether a value is a BigNumber
		 * @param {*} x
		 * @return {boolean}
		 */
		module.exports = function isBigNumber(x) {
		  return x && x.constructor.prototype.isBigNumber || false;
		};
	
	/***/ }),
	/* 198 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var typedFunction = __webpack_require__(199);
		var digits = __webpack_require__(200).digits;
		var isBigNumber = __webpack_require__(197);
		var isMatrix = __webpack_require__(201);
	
		// returns a new instance of typed-function
		var createTyped = function () {
		  // initially, return the original instance of typed-function
		  // consecutively, return a new instance from typed.create.
		  createTyped = typedFunction.create;
		  return typedFunction;
		};
	
		/**
		 * Factory function for creating a new typed instance
		 * @param {Object} type   Object with data types like Complex and BigNumber
		 * @returns {Function}
		 */
		exports.create = function create(type) {
		  // TODO: typed-function must be able to silently ignore signatures with unknown data types
	
		  // type checks for all known types
		  //
		  // note that:
		  //
		  // - check by duck-typing on a property like `isUnit`, instead of checking instanceof.
		  //   instanceof cannot be used because that would not allow to pass data from
		  //   one instance of math.js to another since each has it's own instance of Unit.
		  // - check the `isUnit` property via the constructor, so there will be no
		  //   matches for "fake" instances like plain objects with a property `isUnit`.
		  //   That is important for security reasons.
		  // - It must not be possible to override the type checks used internally,
		  //   for security reasons, so these functions are not exposed in the expression
		  //   parser.
		  type.isNumber = function (x) {
		    return typeof x === 'number';
		  };
		  type.isComplex = function (x) {
		    return type.Complex && x instanceof type.Complex || false;
		  };
		  type.isBigNumber = isBigNumber;
		  type.isFraction = function (x) {
		    return type.Fraction && x instanceof type.Fraction || false;
		  };
		  type.isUnit = function (x) {
		    return x && x.constructor.prototype.isUnit || false;
		  };
		  type.isString = function (x) {
		    return typeof x === 'string';
		  };
		  type.isArray = Array.isArray;
		  type.isMatrix = isMatrix;
		  type.isDenseMatrix = function (x) {
		    return x && x.isDenseMatrix && x.constructor.prototype.isMatrix || false;
		  };
		  type.isSparseMatrix = function (x) {
		    return x && x.isSparseMatrix && x.constructor.prototype.isMatrix || false;
		  };
		  type.isRange = function (x) {
		    return x && x.constructor.prototype.isRange || false;
		  };
		  type.isIndex = function (x) {
		    return x && x.constructor.prototype.isIndex || false;
		  };
		  type.isBoolean = function (x) {
		    return typeof x === 'boolean';
		  };
		  type.isResultSet = function (x) {
		    return x && x.constructor.prototype.isResultSet || false;
		  };
		  type.isHelp = function (x) {
		    return x && x.constructor.prototype.isHelp || false;
		  };
		  type.isFunction = function (x) {
		    return typeof x === 'function';
		  };
		  type.isDate = function (x) {
		    return x instanceof Date;
		  };
		  type.isRegExp = function (x) {
		    return x instanceof RegExp;
		  };
		  type.isObject = function (x) {
		    return typeof x === 'object';
		  };
		  type.isNull = function (x) {
		    return x === null;
		  };
		  type.isUndefined = function (x) {
		    return x === undefined;
		  };
	
		  type.isAccessorNode = function (x) {
		    return x && x.isAccessorNode && x.constructor.prototype.isNode || false;
		  };
		  type.isArrayNode = function (x) {
		    return x && x.isArrayNode && x.constructor.prototype.isNode || false;
		  };
		  type.isAssignmentNode = function (x) {
		    return x && x.isAssignmentNode && x.constructor.prototype.isNode || false;
		  };
		  type.isBlockNode = function (x) {
		    return x && x.isBlockNode && x.constructor.prototype.isNode || false;
		  };
		  type.isConditionalNode = function (x) {
		    return x && x.isConditionalNode && x.constructor.prototype.isNode || false;
		  };
		  type.isConstantNode = function (x) {
		    return x && x.isConstantNode && x.constructor.prototype.isNode || false;
		  };
		  type.isFunctionAssignmentNode = function (x) {
		    return x && x.isFunctionAssignmentNode && x.constructor.prototype.isNode || false;
		  };
		  type.isFunctionNode = function (x) {
		    return x && x.isFunctionNode && x.constructor.prototype.isNode || false;
		  };
		  type.isIndexNode = function (x) {
		    return x && x.isIndexNode && x.constructor.prototype.isNode || false;
		  };
		  type.isNode = function (x) {
		    return x && x.isNode && x.constructor.prototype.isNode || false;
		  };
		  type.isObjectNode = function (x) {
		    return x && x.isObjectNode && x.constructor.prototype.isNode || false;
		  };
		  type.isOperatorNode = function (x) {
		    return x && x.isOperatorNode && x.constructor.prototype.isNode || false;
		  };
		  type.isParenthesisNode = function (x) {
		    return x && x.isParenthesisNode && x.constructor.prototype.isNode || false;
		  };
		  type.isRangeNode = function (x) {
		    return x && x.isRangeNode && x.constructor.prototype.isNode || false;
		  };
		  type.isSymbolNode = function (x) {
		    return x && x.isSymbolNode && x.constructor.prototype.isNode || false;
		  };
	
		  type.isChain = function (x) {
		    return x && x.constructor.prototype.isChain || false;
		  };
	
		  // get a new instance of typed-function
		  var typed = createTyped();
	
		  // define all types. The order of the types determines in which order function
		  // arguments are type-checked (so for performance it's important to put the
		  // most used types first).
		  typed.types = [{ name: 'number', test: type.isNumber }, { name: 'Complex', test: type.isComplex }, { name: 'BigNumber', test: type.isBigNumber }, { name: 'Fraction', test: type.isFraction }, { name: 'Unit', test: type.isUnit }, { name: 'string', test: type.isString }, { name: 'Array', test: type.isArray }, { name: 'Matrix', test: type.isMatrix }, { name: 'DenseMatrix', test: type.isDenseMatrix }, { name: 'SparseMatrix', test: type.isSparseMatrix }, { name: 'Range', test: type.isRange }, { name: 'Index', test: type.isIndex }, { name: 'boolean', test: type.isBoolean }, { name: 'ResultSet', test: type.isResultSet }, { name: 'Help', test: type.isHelp }, { name: 'function', test: type.isFunction }, { name: 'Date', test: type.isDate }, { name: 'RegExp', test: type.isRegExp }, { name: 'Object', test: type.isObject }, { name: 'null', test: type.isNull }, { name: 'undefined', test: type.isUndefined }, { name: 'OperatorNode', test: type.isOperatorNode }, { name: 'ConstantNode', test: type.isConstantNode }, { name: 'SymbolNode', test: type.isSymbolNode }, { name: 'ParenthesisNode', test: type.isParenthesisNode }, { name: 'FunctionNode', test: type.isFunctionNode }, { name: 'FunctionAssignmentNode', test: type.isFunctionAssignmentNode }, { name: 'ArrayNode', test: type.isArrayNode }, { name: 'AssignmentNode', test: type.isAssignmentNode }, { name: 'BlockNode', test: type.isBlockNode }, { name: 'ConditionalNode', test: type.isConditionalNode }, { name: 'IndexNode', test: type.isIndexNode }, { name: 'RangeNode', test: type.isRangeNode }, { name: 'Node', test: type.isNode }];
	
		  // TODO: add conversion from BigNumber to number?
		  typed.conversions = [{
		    from: 'number',
		    to: 'BigNumber',
		    convert: function (x) {
		      // note: conversion from number to BigNumber can fail if x has >15 digits
		      if (digits(x) > 15) {
		        throw new TypeError('Cannot implicitly convert a number with >15 significant digits to BigNumber ' + '(value: ' + x + '). ' + 'Use function bignumber(x) to convert to BigNumber.');
		      }
		      return new type.BigNumber(x);
		    }
		  }, {
		    from: 'number',
		    to: 'Complex',
		    convert: function (x) {
		      return new type.Complex(x, 0);
		    }
		  }, {
		    from: 'number',
		    to: 'string',
		    convert: function (x) {
		      return x + '';
		    }
		  }, {
		    from: 'BigNumber',
		    to: 'Complex',
		    convert: function (x) {
		      return new type.Complex(x.toNumber(), 0);
		    }
		  }, {
		    from: 'Fraction',
		    to: 'BigNumber',
		    convert: function (x) {
		      throw new TypeError('Cannot implicitly convert a Fraction to BigNumber or vice versa. ' + 'Use function bignumber(x) to convert to BigNumber or fraction(x) to convert to Fraction.');
		    }
		  }, {
		    from: 'Fraction',
		    to: 'Complex',
		    convert: function (x) {
		      return new type.Complex(x.valueOf(), 0);
		    }
		  }, {
		    from: 'number',
		    to: 'Fraction',
		    convert: function (x) {
		      var f = new type.Fraction(x);
		      if (f.valueOf() !== x) {
		        throw new TypeError('Cannot implicitly convert a number to a Fraction when there will be a loss of precision ' + '(value: ' + x + '). ' + 'Use function fraction(x) to convert to Fraction.');
		      }
		      return new type.Fraction(x);
		    }
		  }, {
		    // FIXME: add conversion from Fraction to number, for example for `sqrt(fraction(1,3))`
		    //  from: 'Fraction',
		    //  to: 'number',
		    //  convert: function (x) {
		    //    return x.valueOf();
		    //  }
		    //}, {
		    from: 'string',
		    to: 'number',
		    convert: function (x) {
		      var n = Number(x);
		      if (isNaN(n)) {
		        throw new Error('Cannot convert "' + x + '" to a number');
		      }
		      return n;
		    }
		  }, {
		    from: 'string',
		    to: 'BigNumber',
		    convert: function (x) {
		      try {
		        return new type.BigNumber(x);
		      } catch (err) {
		        throw new Error('Cannot convert "' + x + '" to BigNumber');
		      }
		    }
		  }, {
		    from: 'string',
		    to: 'Fraction',
		    convert: function (x) {
		      try {
		        return new type.Fraction(x);
		      } catch (err) {
		        throw new Error('Cannot convert "' + x + '" to Fraction');
		      }
		    }
		  }, {
		    from: 'string',
		    to: 'Complex',
		    convert: function (x) {
		      try {
		        return new type.Complex(x);
		      } catch (err) {
		        throw new Error('Cannot convert "' + x + '" to Complex');
		      }
		    }
		  }, {
		    from: 'boolean',
		    to: 'number',
		    convert: function (x) {
		      return +x;
		    }
		  }, {
		    from: 'boolean',
		    to: 'BigNumber',
		    convert: function (x) {
		      return new type.BigNumber(+x);
		    }
		  }, {
		    from: 'boolean',
		    to: 'Fraction',
		    convert: function (x) {
		      return new type.Fraction(+x);
		    }
		  }, {
		    from: 'boolean',
		    to: 'string',
		    convert: function (x) {
		      return +x;
		    }
		  }, {
		    from: 'null',
		    to: 'number',
		    convert: function () {
		      return 0;
		    }
		  }, {
		    from: 'null',
		    to: 'string',
		    convert: function () {
		      return 'null';
		    }
		  }, {
		    from: 'null',
		    to: 'BigNumber',
		    convert: function () {
		      return new type.BigNumber(0);
		    }
		  }, {
		    from: 'null',
		    to: 'Fraction',
		    convert: function () {
		      return new type.Fraction(0);
		    }
		  }, {
		    from: 'Array',
		    to: 'Matrix',
		    convert: function (array) {
		      // TODO: how to decide on the right type of matrix to create?
		      return new type.DenseMatrix(array);
		    }
		  }, {
		    from: 'Matrix',
		    to: 'Array',
		    convert: function (matrix) {
		      return matrix.valueOf();
		    }
		  }];
	
		  return typed;
		};
	
	/***/ }),
	/* 199 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/**
		 * typed-function
		 *
		 * Type checking for JavaScript functions
		 *
		 * https://github.com/josdejong/typed-function
		 */
		'use strict';
	
		(function (root, factory) {
		  if (true) {
		    // AMD. Register as an anonymous module.
		    !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
		  } else if (typeof exports === 'object') {
		    // OldNode. Does not work with strict CommonJS, but
		    // only CommonJS-like environments that support module.exports,
		    // like OldNode.
		    module.exports = factory();
		  } else {
		    // Browser globals (root is window)
		    root.typed = factory();
		  }
		})(this, function () {
		  // factory function to create a new instance of typed-function
		  // TODO: allow passing configuration, types, tests via the factory function
		  function create() {
		    /**
		     * Get a type test function for a specific data type
		     * @param {string} name                   Name of a data type like 'number' or 'string'
		     * @returns {Function(obj: *) : boolean}  Returns a type testing function.
		     *                                        Throws an error for an unknown type.
		     */
		    function getTypeTest(name) {
		      var test;
		      for (var i = 0; i < typed.types.length; i++) {
		        var entry = typed.types[i];
		        if (entry.name === name) {
		          test = entry.test;
		          break;
		        }
		      }
	
		      if (!test) {
		        var hint;
		        for (i = 0; i < typed.types.length; i++) {
		          entry = typed.types[i];
		          if (entry.name.toLowerCase() == name.toLowerCase()) {
		            hint = entry.name;
		            break;
		          }
		        }
	
		        throw new Error('Unknown type "' + name + '"' + (hint ? '. Did you mean "' + hint + '"?' : ''));
		      }
		      return test;
		    }
	
		    /**
		     * Retrieve the function name from a set of functions, and check
		     * whether the name of all functions match (if given)
		     * @param {Array.<function>} fns
		     */
		    function getName(fns) {
		      var name = '';
	
		      for (var i = 0; i < fns.length; i++) {
		        var fn = fns[i];
	
		        // merge function name when this is a typed function
		        if (fn.signatures && fn.name != '') {
		          if (name == '') {
		            name = fn.name;
		          } else if (name != fn.name) {
		            var err = new Error('Function names do not match (expected: ' + name + ', actual: ' + fn.name + ')');
		            err.data = {
		              actual: fn.name,
		              expected: name
		            };
		            throw err;
		          }
		        }
		      }
	
		      return name;
		    }
	
		    /**
		     * Create an ArgumentsError. Creates messages like:
		     *
		     *   Unexpected type of argument (expected: ..., actual: ..., index: ...)
		     *   Too few arguments (expected: ..., index: ...)
		     *   Too many arguments (expected: ..., actual: ...)
		     *
		     * @param {String} fn         Function name
		     * @param {number} argCount   Number of arguments
		     * @param {Number} index      Current argument index
		     * @param {*} actual          Current argument
		     * @param {string} [expected] An optional, comma separated string with
		     *                            expected types on given index
		     * @extends Error
		     */
		    function createError(fn, argCount, index, actual, expected) {
		      var actualType = getTypeOf(actual);
		      var _expected = expected ? expected.split(',') : null;
		      var _fn = fn || 'unnamed';
		      var anyType = _expected && contains(_expected, 'any');
		      var message;
		      var data = {
		        fn: fn,
		        index: index,
		        actual: actual,
		        expected: _expected
		      };
	
		      if (_expected) {
		        if (argCount > index && !anyType) {
		          // unexpected type
		          message = 'Unexpected type of argument in function ' + _fn + ' (expected: ' + _expected.join(' or ') + ', actual: ' + actualType + ', index: ' + index + ')';
		        } else {
		          // too few arguments
		          message = 'Too few arguments in function ' + _fn + ' (expected: ' + _expected.join(' or ') + ', index: ' + index + ')';
		        }
		      } else {
		        // too many arguments
		        message = 'Too many arguments in function ' + _fn + ' (expected: ' + index + ', actual: ' + argCount + ')';
		      }
	
		      var err = new TypeError(message);
		      err.data = data;
		      return err;
		    }
	
		    /**
		     * Collection with function references (local shortcuts to functions)
		     * @constructor
		     * @param {string} [name='refs']  Optional name for the refs, used to generate
		     *                                JavaScript code
		     */
		    function Refs(name) {
		      this.name = name || 'refs';
		      this.categories = {};
		    }
	
		    /**
		     * Add a function reference.
		     * @param {Function} fn
		     * @param {string} [category='fn']    A function category, like 'fn' or 'signature'
		     * @returns {string} Returns the function name, for example 'fn0' or 'signature2'
		     */
		    Refs.prototype.add = function (fn, category) {
		      var cat = category || 'fn';
		      if (!this.categories[cat]) this.categories[cat] = [];
	
		      var index = this.categories[cat].indexOf(fn);
		      if (index == -1) {
		        index = this.categories[cat].length;
		        this.categories[cat].push(fn);
		      }
	
		      return cat + index;
		    };
	
		    /**
		     * Create code lines for all function references
		     * @returns {string} Returns the code containing all function references
		     */
		    Refs.prototype.toCode = function () {
		      var code = [];
		      var path = this.name + '.categories';
		      var categories = this.categories;
	
		      for (var cat in categories) {
		        if (categories.hasOwnProperty(cat)) {
		          var category = categories[cat];
	
		          for (var i = 0; i < category.length; i++) {
		            code.push('var ' + cat + i + ' = ' + path + '[\'' + cat + '\'][' + i + '];');
		          }
		        }
		      }
	
		      return code.join('\n');
		    };
	
		    /**
		     * A function parameter
		     * @param {string | string[] | Param} types    A parameter type like 'string',
		     *                                             'number | boolean'
		     * @param {boolean} [varArgs=false]            Variable arguments if true
		     * @constructor
		     */
		    function Param(types, varArgs) {
		      // parse the types, can be a string with types separated by pipe characters |
		      if (typeof types === 'string') {
		        // parse variable arguments operator (ellipses '...number')
		        var _types = types.trim();
		        var _varArgs = _types.substr(0, 3) === '...';
		        if (_varArgs) {
		          _types = _types.substr(3);
		        }
		        if (_types === '') {
		          this.types = ['any'];
		        } else {
		          this.types = _types.split('|');
		          for (var i = 0; i < this.types.length; i++) {
		            this.types[i] = this.types[i].trim();
		          }
		        }
		      } else if (Array.isArray(types)) {
		        this.types = types;
		      } else if (types instanceof Param) {
		        return types.clone();
		      } else {
		        throw new Error('String or Array expected');
		      }
	
		      // can hold a type to which to convert when handling this parameter
		      this.conversions = [];
		      // TODO: implement better API for conversions, be able to add conversions via constructor (support a new type Object?)
	
		      // variable arguments
		      this.varArgs = _varArgs || varArgs || false;
	
		      // check for any type arguments
		      this.anyType = this.types.indexOf('any') !== -1;
		    }
	
		    /**
		     * Order Params
		     * any type ('any') will be ordered last, and object as second last (as other
		     * types may be an object as well, like Array).
		     *
		     * @param {Param} a
		     * @param {Param} b
		     * @returns {number} Returns 1 if a > b, -1 if a < b, and else 0.
		     */
		    Param.compare = function (a, b) {
		      // TODO: simplify parameter comparison, it's a mess
		      if (a.anyType) return 1;
		      if (b.anyType) return -1;
	
		      if (contains(a.types, 'Object')) return 1;
		      if (contains(b.types, 'Object')) return -1;
	
		      if (a.hasConversions()) {
		        if (b.hasConversions()) {
		          var i, ac, bc;
	
		          for (i = 0; i < a.conversions.length; i++) {
		            if (a.conversions[i] !== undefined) {
		              ac = a.conversions[i];
		              break;
		            }
		          }
	
		          for (i = 0; i < b.conversions.length; i++) {
		            if (b.conversions[i] !== undefined) {
		              bc = b.conversions[i];
		              break;
		            }
		          }
	
		          return typed.conversions.indexOf(ac) - typed.conversions.indexOf(bc);
		        } else {
		          return 1;
		        }
		      } else {
		        if (b.hasConversions()) {
		          return -1;
		        } else {
		          // both params have no conversions
		          var ai, bi;
	
		          for (i = 0; i < typed.types.length; i++) {
		            if (typed.types[i].name === a.types[0]) {
		              ai = i;
		              break;
		            }
		          }
	
		          for (i = 0; i < typed.types.length; i++) {
		            if (typed.types[i].name === b.types[0]) {
		              bi = i;
		              break;
		            }
		          }
	
		          return ai - bi;
		        }
		      }
		    };
	
		    /**
		     * Test whether this parameters types overlap an other parameters types.
		     * Will not match ['any'] with ['number']
		     * @param {Param} other
		     * @return {boolean} Returns true when there are overlapping types
		     */
		    Param.prototype.overlapping = function (other) {
		      for (var i = 0; i < this.types.length; i++) {
		        if (contains(other.types, this.types[i])) {
		          return true;
		        }
		      }
		      return false;
		    };
	
		    /**
		     * Test whether this parameters types matches an other parameters types.
		     * When any of the two parameters contains `any`, true is returned
		     * @param {Param} other
		     * @return {boolean} Returns true when there are matching types
		     */
		    Param.prototype.matches = function (other) {
		      return this.anyType || other.anyType || this.overlapping(other);
		    };
	
		    /**
		     * Create a clone of this param
		     * @returns {Param} Returns a cloned version of this param
		     */
		    Param.prototype.clone = function () {
		      var param = new Param(this.types.slice(), this.varArgs);
		      param.conversions = this.conversions.slice();
		      return param;
		    };
	
		    /**
		     * Test whether this parameter contains conversions
		     * @returns {boolean} Returns true if the parameter contains one or
		     *                    multiple conversions.
		     */
		    Param.prototype.hasConversions = function () {
		      return this.conversions.length > 0;
		    };
	
		    /**
		     * Tests whether this parameters contains any of the provided types
		     * @param {Object} types  A Map with types, like {'number': true}
		     * @returns {boolean}     Returns true when the parameter contains any
		     *                        of the provided types
		     */
		    Param.prototype.contains = function (types) {
		      for (var i = 0; i < this.types.length; i++) {
		        if (types[this.types[i]]) {
		          return true;
		        }
		      }
		      return false;
		    };
	
		    /**
		     * Return a string representation of this params types, like 'string' or
		     * 'number | boolean' or '...number'
		     * @param {boolean} [toConversion]   If true, the returned types string
		     *                                   contains the types where the parameter
		     *                                   will convert to. If false (default)
		     *                                   the "from" types are returned
		     * @returns {string}
		     */
		    Param.prototype.toString = function (toConversion) {
		      var types = [];
		      var keys = {};
	
		      for (var i = 0; i < this.types.length; i++) {
		        var conversion = this.conversions[i];
		        var type = toConversion && conversion ? conversion.to : this.types[i];
		        if (!(type in keys)) {
		          keys[type] = true;
		          types.push(type);
		        }
		      }
	
		      return (this.varArgs ? '...' : '') + types.join('|');
		    };
	
		    /**
		     * A function signature
		     * @param {string | string[] | Param[]} params
		     *                         Array with the type(s) of each parameter,
		     *                         or a comma separated string with types
		     * @param {Function} fn    The actual function
		     * @constructor
		     */
		    function Signature(params, fn) {
		      var _params;
		      if (typeof params === 'string') {
		        _params = params !== '' ? params.split(',') : [];
		      } else if (Array.isArray(params)) {
		        _params = params;
		      } else {
		        throw new Error('string or Array expected');
		      }
	
		      this.params = new Array(_params.length);
		      this.anyType = false;
		      this.varArgs = false;
		      for (var i = 0; i < _params.length; i++) {
		        var param = new Param(_params[i]);
		        this.params[i] = param;
		        if (param.anyType) {
		          this.anyType = true;
		        }
		        if (i === _params.length - 1) {
		          // the last argument
		          this.varArgs = param.varArgs;
		        } else {
		          // non-last argument
		          if (param.varArgs) {
		            throw new SyntaxError('Unexpected variable arguments operator "..."');
		          }
		        }
		      }
	
		      this.fn = fn;
		    }
	
		    /**
		     * Create a clone of this signature
		     * @returns {Signature} Returns a cloned version of this signature
		     */
		    Signature.prototype.clone = function () {
		      return new Signature(this.params.slice(), this.fn);
		    };
	
		    /**
		     * Expand a signature: split params with union types in separate signatures
		     * For example split a Signature "string | number" into two signatures.
		     * @return {Signature[]} Returns an array with signatures (at least one)
		     */
		    Signature.prototype.expand = function () {
		      var signatures = [];
	
		      function recurse(signature, path) {
		        if (path.length < signature.params.length) {
		          var i, newParam, conversion;
	
		          var param = signature.params[path.length];
		          if (param.varArgs) {
		            // a variable argument. do not split the types in the parameter
		            newParam = param.clone();
	
		            // add conversions to the parameter
		            // recurse for all conversions
		            for (i = 0; i < typed.conversions.length; i++) {
		              conversion = typed.conversions[i];
		              if (!contains(param.types, conversion.from) && contains(param.types, conversion.to)) {
		                var j = newParam.types.length;
		                newParam.types[j] = conversion.from;
		                newParam.conversions[j] = conversion;
		              }
		            }
	
		            recurse(signature, path.concat(newParam));
		          } else {
		            // split each type in the parameter
		            for (i = 0; i < param.types.length; i++) {
		              recurse(signature, path.concat(new Param(param.types[i])));
		            }
	
		            // recurse for all conversions
		            for (i = 0; i < typed.conversions.length; i++) {
		              conversion = typed.conversions[i];
		              if (!contains(param.types, conversion.from) && contains(param.types, conversion.to)) {
		                newParam = new Param(conversion.from);
		                newParam.conversions[0] = conversion;
		                recurse(signature, path.concat(newParam));
		              }
		            }
		          }
		        } else {
		          signatures.push(new Signature(path, signature.fn));
		        }
		      }
	
		      recurse(this, []);
	
		      return signatures;
		    };
	
		    /**
		     * Compare two signatures.
		     *
		     * When two params are equal and contain conversions, they will be sorted
		     * by lowest index of the first conversions.
		     *
		     * @param {Signature} a
		     * @param {Signature} b
		     * @returns {number} Returns 1 if a > b, -1 if a < b, and else 0.
		     */
		    Signature.compare = function (a, b) {
		      if (a.params.length > b.params.length) return 1;
		      if (a.params.length < b.params.length) return -1;
	
		      // count the number of conversions
		      var i;
		      var len = a.params.length; // a and b have equal amount of params
		      var ac = 0;
		      var bc = 0;
		      for (i = 0; i < len; i++) {
		        if (a.params[i].hasConversions()) ac++;
		        if (b.params[i].hasConversions()) bc++;
		      }
	
		      if (ac > bc) return 1;
		      if (ac < bc) return -1;
	
		      // compare the order per parameter
		      for (i = 0; i < a.params.length; i++) {
		        var cmp = Param.compare(a.params[i], b.params[i]);
		        if (cmp !== 0) {
		          return cmp;
		        }
		      }
	
		      return 0;
		    };
	
		    /**
		     * Test whether any of the signatures parameters has conversions
		     * @return {boolean} Returns true when any of the parameters contains
		     *                   conversions.
		     */
		    Signature.prototype.hasConversions = function () {
		      for (var i = 0; i < this.params.length; i++) {
		        if (this.params[i].hasConversions()) {
		          return true;
		        }
		      }
		      return false;
		    };
	
		    /**
		     * Test whether this signature should be ignored.
		     * Checks whether any of the parameters contains a type listed in
		     * typed.ignore
		     * @return {boolean} Returns true when the signature should be ignored
		     */
		    Signature.prototype.ignore = function () {
		      // create a map with ignored types
		      var types = {};
		      for (var i = 0; i < typed.ignore.length; i++) {
		        types[typed.ignore[i]] = true;
		      }
	
		      // test whether any of the parameters contains this type
		      for (i = 0; i < this.params.length; i++) {
		        if (this.params[i].contains(types)) {
		          return true;
		        }
		      }
	
		      return false;
		    };
	
		    /**
		     * Test whether the path of this signature matches a given path.
		     * @param {Param[]} params
		     */
		    Signature.prototype.paramsStartWith = function (params) {
		      if (params.length === 0) {
		        return true;
		      }
	
		      var aLast = last(this.params);
		      var bLast = last(params);
	
		      for (var i = 0; i < params.length; i++) {
		        var a = this.params[i] || (aLast.varArgs ? aLast : null);
		        var b = params[i] || (bLast.varArgs ? bLast : null);
	
		        if (!a || !b || !a.matches(b)) {
		          return false;
		        }
		      }
	
		      return true;
		    };
	
		    /**
		     * Generate the code to invoke this signature
		     * @param {Refs} refs
		     * @param {string} prefix
		     * @returns {string} Returns code
		     */
		    Signature.prototype.toCode = function (refs, prefix) {
		      var code = [];
	
		      var args = new Array(this.params.length);
		      for (var i = 0; i < this.params.length; i++) {
		        var param = this.params[i];
		        var conversion = param.conversions[0];
		        if (param.varArgs) {
		          args[i] = 'varArgs';
		        } else if (conversion) {
		          args[i] = refs.add(conversion.convert, 'convert') + '(arg' + i + ')';
		        } else {
		          args[i] = 'arg' + i;
		        }
		      }
	
		      var ref = this.fn ? refs.add(this.fn, 'signature') : undefined;
		      if (ref) {
		        return prefix + 'return ' + ref + '(' + args.join(', ') + '); // signature: ' + this.params.join(', ');
		      }
	
		      return code.join('\n');
		    };
	
		    /**
		     * Return a string representation of the signature
		     * @returns {string}
		     */
		    Signature.prototype.toString = function () {
		      return this.params.join(', ');
		    };
	
		    /**
		     * A group of signatures with the same parameter on given index
		     * @param {Param[]} path
		     * @param {Signature} [signature]
		     * @param {Node[]} childs
		     * @param {boolean} [fallThrough=false]
		     * @constructor
		     */
		    function Node(path, signature, childs, fallThrough) {
		      this.path = path || [];
		      this.param = path[path.length - 1] || null;
		      this.signature = signature || null;
		      this.childs = childs || [];
		      this.fallThrough = fallThrough || false;
		    }
	
		    /**
		     * Generate code for this group of signatures
		     * @param {Refs} refs
		     * @param {string} prefix
		     * @returns {string} Returns the code as string
		     */
		    Node.prototype.toCode = function (refs, prefix) {
		      // TODO: split this function in multiple functions, it's too large
		      var code = [];
	
		      if (this.param) {
		        var index = this.path.length - 1;
		        var conversion = this.param.conversions[0];
		        var comment = '// type: ' + (conversion ? conversion.from + ' (convert to ' + conversion.to + ')' : this.param);
	
		        // non-root node (path is non-empty)
		        if (this.param.varArgs) {
		          if (this.param.anyType) {
		            // variable arguments with any type
		            code.push(prefix + 'if (arguments.length > ' + index + ') {');
		            code.push(prefix + '  var varArgs = [];');
		            code.push(prefix + '  for (var i = ' + index + '; i < arguments.length; i++) {');
		            code.push(prefix + '    varArgs.push(arguments[i]);');
		            code.push(prefix + '  }');
		            code.push(this.signature.toCode(refs, prefix + '  '));
		            code.push(prefix + '}');
		          } else {
		            // variable arguments with a fixed type
		            var getTests = function (types, arg) {
		              var tests = [];
		              for (var i = 0; i < types.length; i++) {
		                tests[i] = refs.add(getTypeTest(types[i]), 'test') + '(' + arg + ')';
		              }
		              return tests.join(' || ');
		            }.bind(this);
	
		            var allTypes = this.param.types;
		            var exactTypes = [];
		            for (var i = 0; i < allTypes.length; i++) {
		              if (this.param.conversions[i] === undefined) {
		                exactTypes.push(allTypes[i]);
		              }
		            }
	
		            code.push(prefix + 'if (' + getTests(allTypes, 'arg' + index) + ') { ' + comment);
		            code.push(prefix + '  var varArgs = [arg' + index + '];');
		            code.push(prefix + '  for (var i = ' + (index + 1) + '; i < arguments.length; i++) {');
		            code.push(prefix + '    if (' + getTests(exactTypes, 'arguments[i]') + ') {');
		            code.push(prefix + '      varArgs.push(arguments[i]);');
	
		            for (var i = 0; i < allTypes.length; i++) {
		              var conversion_i = this.param.conversions[i];
		              if (conversion_i) {
		                var test = refs.add(getTypeTest(allTypes[i]), 'test');
		                var convert = refs.add(conversion_i.convert, 'convert');
		                code.push(prefix + '    }');
		                code.push(prefix + '    else if (' + test + '(arguments[i])) {');
		                code.push(prefix + '      varArgs.push(' + convert + '(arguments[i]));');
		              }
		            }
		            code.push(prefix + '    } else {');
		            code.push(prefix + '      throw createError(name, arguments.length, i, arguments[i], \'' + exactTypes.join(',') + '\');');
		            code.push(prefix + '    }');
		            code.push(prefix + '  }');
		            code.push(this.signature.toCode(refs, prefix + '  '));
		            code.push(prefix + '}');
		          }
		        } else {
		          if (this.param.anyType) {
		            // any type
		            code.push(prefix + '// type: any');
		            code.push(this._innerCode(refs, prefix));
		          } else {
		            // regular type
		            var type = this.param.types[0];
		            var test = type !== 'any' ? refs.add(getTypeTest(type), 'test') : null;
	
		            code.push(prefix + 'if (' + test + '(arg' + index + ')) { ' + comment);
		            code.push(this._innerCode(refs, prefix + '  '));
		            code.push(prefix + '}');
		          }
		        }
		      } else {
		        // root node (path is empty)
		        code.push(this._innerCode(refs, prefix));
		      }
	
		      return code.join('\n');
		    };
	
		    /**
		     * Generate inner code for this group of signatures.
		     * This is a helper function of Node.prototype.toCode
		     * @param {Refs} refs
		     * @param {string} prefix
		     * @returns {string} Returns the inner code as string
		     * @private
		     */
		    Node.prototype._innerCode = function (refs, prefix) {
		      var code = [];
		      var i;
	
		      if (this.signature) {
		        code.push(prefix + 'if (arguments.length === ' + this.path.length + ') {');
		        code.push(this.signature.toCode(refs, prefix + '  '));
		        code.push(prefix + '}');
		      }
	
		      for (i = 0; i < this.childs.length; i++) {
		        code.push(this.childs[i].toCode(refs, prefix));
		      }
	
		      // TODO: shouldn't the this.param.anyType check be redundant
		      if (!this.fallThrough || this.param && this.param.anyType) {
		        var exceptions = this._exceptions(refs, prefix);
		        if (exceptions) {
		          code.push(exceptions);
		        }
		      }
	
		      return code.join('\n');
		    };
	
		    /**
		     * Generate code to throw exceptions
		     * @param {Refs} refs
		     * @param {string} prefix
		     * @returns {string} Returns the inner code as string
		     * @private
		     */
		    Node.prototype._exceptions = function (refs, prefix) {
		      var index = this.path.length;
	
		      if (this.childs.length === 0) {
		        // TODO: can this condition be simplified? (we have a fall-through here)
		        return [prefix + 'if (arguments.length > ' + index + ') {', prefix + '  throw createError(name, arguments.length, ' + index + ', arguments[' + index + ']);', prefix + '}'].join('\n');
		      } else {
		        var keys = {};
		        var types = [];
	
		        for (var i = 0; i < this.childs.length; i++) {
		          var node = this.childs[i];
		          if (node.param) {
		            for (var j = 0; j < node.param.types.length; j++) {
		              var type = node.param.types[j];
		              if (!(type in keys) && !node.param.conversions[j]) {
		                keys[type] = true;
		                types.push(type);
		              }
		            }
		          }
		        }
	
		        return prefix + 'throw createError(name, arguments.length, ' + index + ', arguments[' + index + '], \'' + types.join(',') + '\');';
		      }
		    };
	
		    /**
		     * Split all raw signatures into an array with expanded Signatures
		     * @param {Object.<string, Function>} rawSignatures
		     * @return {Signature[]} Returns an array with expanded signatures
		     */
		    function parseSignatures(rawSignatures) {
		      // FIXME: need to have deterministic ordering of signatures, do not create via object
		      var signature;
		      var keys = {};
		      var signatures = [];
		      var i;
	
		      for (var types in rawSignatures) {
		        if (rawSignatures.hasOwnProperty(types)) {
		          var fn = rawSignatures[types];
		          signature = new Signature(types, fn);
	
		          if (signature.ignore()) {
		            continue;
		          }
	
		          var expanded = signature.expand();
	
		          for (i = 0; i < expanded.length; i++) {
		            var signature_i = expanded[i];
		            var key = signature_i.toString();
		            var existing = keys[key];
		            if (!existing) {
		              keys[key] = signature_i;
		            } else {
		              var cmp = Signature.compare(signature_i, existing);
		              if (cmp < 0) {
		                // override if sorted first
		                keys[key] = signature_i;
		              } else if (cmp === 0) {
		                throw new Error('Signature "' + key + '" is defined twice');
		              }
		              // else: just ignore
		            }
		          }
		        }
		      }
	
		      // convert from map to array
		      for (key in keys) {
		        if (keys.hasOwnProperty(key)) {
		          signatures.push(keys[key]);
		        }
		      }
	
		      // order the signatures
		      signatures.sort(function (a, b) {
		        return Signature.compare(a, b);
		      });
	
		      // filter redundant conversions from signatures with varArgs
		      // TODO: simplify this loop or move it to a separate function
		      for (i = 0; i < signatures.length; i++) {
		        signature = signatures[i];
	
		        if (signature.varArgs) {
		          var index = signature.params.length - 1;
		          var param = signature.params[index];
	
		          var t = 0;
		          while (t < param.types.length) {
		            if (param.conversions[t]) {
		              var type = param.types[t];
	
		              for (var j = 0; j < signatures.length; j++) {
		                var other = signatures[j];
		                var p = other.params[index];
	
		                if (other !== signature && p && contains(p.types, type) && !p.conversions[index]) {
		                  // this (conversion) type already exists, remove it
		                  param.types.splice(t, 1);
		                  param.conversions.splice(t, 1);
		                  t--;
		                  break;
		                }
		              }
		            }
		            t++;
		          }
		        }
		      }
	
		      return signatures;
		    }
	
		    /**
		     * Filter all any type signatures
		     * @param {Signature[]} signatures
		     * @return {Signature[]} Returns only any type signatures
		     */
		    function filterAnyTypeSignatures(signatures) {
		      var filtered = [];
	
		      for (var i = 0; i < signatures.length; i++) {
		        if (signatures[i].anyType) {
		          filtered.push(signatures[i]);
		        }
		      }
	
		      return filtered;
		    }
	
		    /**
		     * create a map with normalized signatures as key and the function as value
		     * @param {Signature[]} signatures   An array with split signatures
		     * @return {Object.<string, Function>} Returns a map with normalized
		     *                                     signatures as key, and the function
		     *                                     as value.
		     */
		    function mapSignatures(signatures) {
		      var normalized = {};
	
		      for (var i = 0; i < signatures.length; i++) {
		        var signature = signatures[i];
		        if (signature.fn && !signature.hasConversions()) {
		          var params = signature.params.join(',');
		          normalized[params] = signature.fn;
		        }
		      }
	
		      return normalized;
		    }
	
		    /**
		     * Parse signatures recursively in a node tree.
		     * @param {Signature[]} signatures  Array with expanded signatures
		     * @param {Param[]} path            Traversed path of parameter types
		     * @param {Signature[]} anys
		     * @return {Node}                   Returns a node tree
		     */
		    function parseTree(signatures, path, anys) {
		      var i, signature;
		      var index = path.length;
		      var nodeSignature;
	
		      var filtered = [];
		      for (i = 0; i < signatures.length; i++) {
		        signature = signatures[i];
	
		        // filter the first signature with the correct number of params
		        if (signature.params.length === index && !nodeSignature) {
		          nodeSignature = signature;
		        }
	
		        if (signature.params[index] != undefined) {
		          filtered.push(signature);
		        }
		      }
	
		      // sort the filtered signatures by param
		      filtered.sort(function (a, b) {
		        return Param.compare(a.params[index], b.params[index]);
		      });
	
		      // recurse over the signatures
		      var entries = [];
		      for (i = 0; i < filtered.length; i++) {
		        signature = filtered[i];
		        // group signatures with the same param at current index
		        var param = signature.params[index];
	
		        // TODO: replace the next filter loop
		        var existing = entries.filter(function (entry) {
		          return entry.param.overlapping(param);
		        })[0];
	
		        //var existing;
		        //for (var j = 0; j < entries.length; j++) {
		        //  if (entries[j].param.overlapping(param)) {
		        //    existing = entries[j];
		        //    break;
		        //  }
		        //}
	
		        if (existing) {
		          if (existing.param.varArgs) {
		            throw new Error('Conflicting types "' + existing.param + '" and "' + param + '"');
		          }
		          existing.signatures.push(signature);
		        } else {
		          entries.push({
		            param: param,
		            signatures: [signature]
		          });
		        }
		      }
	
		      // find all any type signature that can still match our current path
		      var matchingAnys = [];
		      for (i = 0; i < anys.length; i++) {
		        if (anys[i].paramsStartWith(path)) {
		          matchingAnys.push(anys[i]);
		        }
		      }
	
		      // see if there are any type signatures that don't match any of the
		      // signatures that we have in our tree, i.e. we have alternative
		      // matching signature(s) outside of our current tree and we should
		      // fall through to them instead of throwing an exception
		      var fallThrough = false;
		      for (i = 0; i < matchingAnys.length; i++) {
		        if (!contains(signatures, matchingAnys[i])) {
		          fallThrough = true;
		          break;
		        }
		      }
	
		      // parse the childs
		      var childs = new Array(entries.length);
		      for (i = 0; i < entries.length; i++) {
		        var entry = entries[i];
		        childs[i] = parseTree(entry.signatures, path.concat(entry.param), matchingAnys);
		      }
	
		      return new Node(path, nodeSignature, childs, fallThrough);
		    }
	
		    /**
		     * Generate an array like ['arg0', 'arg1', 'arg2']
		     * @param {number} count Number of arguments to generate
		     * @returns {Array} Returns an array with argument names
		     */
		    function getArgs(count) {
		      // create an array with all argument names
		      var args = [];
		      for (var i = 0; i < count; i++) {
		        args[i] = 'arg' + i;
		      }
	
		      return args;
		    }
	
		    /**
		     * Compose a function from sub-functions each handling a single type signature.
		     * Signatures:
		     *   typed(signature: string, fn: function)
		     *   typed(name: string, signature: string, fn: function)
		     *   typed(signatures: Object.<string, function>)
		     *   typed(name: string, signatures: Object.<string, function>)
		     *
		     * @param {string | null} name
		     * @param {Object.<string, Function>} signatures
		     * @return {Function} Returns the typed function
		     * @private
		     */
		    function _typed(name, signatures) {
		      var refs = new Refs();
	
		      // parse signatures, expand them
		      var _signatures = parseSignatures(signatures);
		      if (_signatures.length == 0) {
		        throw new Error('No signatures provided');
		      }
	
		      // filter all any type signatures
		      var anys = filterAnyTypeSignatures(_signatures);
	
		      // parse signatures into a node tree
		      var node = parseTree(_signatures, [], anys);
	
		      //var util = require('util');
		      //console.log('ROOT');
		      //console.log(util.inspect(node, { depth: null }));
	
		      // generate code for the typed function
		      // safeName is a conservative replacement of characters 
		      // to prevend being able to inject JS code at the place of the function name 
		      // the name is useful for stack trackes therefore we want have it there
		      var code = [];
		      var safeName = (name || '').replace(/[^a-zA-Z0-9_$]/g, '_');
		      var args = getArgs(maxParams(_signatures));
		      code.push('function ' + safeName + '(' + args.join(', ') + ') {');
		      code.push('  "use strict";');
		      code.push('  var name = ' + JSON.stringify(name || '') + ';');
		      code.push(node.toCode(refs, '  ', false));
		      code.push('}');
	
		      // generate body for the factory function
		      var body = [refs.toCode(), 'return ' + code.join('\n')].join('\n');
	
		      // evaluate the JavaScript code and attach function references
		      var factory = new Function(refs.name, 'createError', body);
		      var fn = factory(refs, createError);
	
		      //console.log('FN\n' + fn.toString()); // TODO: cleanup
	
		      // attach the signatures with sub-functions to the constructed function
		      fn.signatures = mapSignatures(_signatures);
	
		      return fn;
		    }
	
		    /**
		     * Calculate the maximum number of parameters in givens signatures
		     * @param {Signature[]} signatures
		     * @returns {number} The maximum number of parameters
		     */
		    function maxParams(signatures) {
		      var max = 0;
	
		      for (var i = 0; i < signatures.length; i++) {
		        var len = signatures[i].params.length;
		        if (len > max) {
		          max = len;
		        }
		      }
	
		      return max;
		    }
	
		    /**
		     * Get the type of a value
		     * @param {*} x
		     * @returns {string} Returns a string with the type of value
		     */
		    function getTypeOf(x) {
		      var obj;
	
		      for (var i = 0; i < typed.types.length; i++) {
		        var entry = typed.types[i];
	
		        if (entry.name === 'Object') {
		          // Array and Date are also Object, so test for Object afterwards
		          obj = entry;
		        } else {
		          if (entry.test(x)) return entry.name;
		        }
		      }
	
		      // at last, test whether an object
		      if (obj && obj.test(x)) return obj.name;
	
		      return 'unknown';
		    }
	
		    /**
		     * Test whether an array contains some item
		     * @param {Array} array
		     * @param {*} item
		     * @return {boolean} Returns true if array contains item, false if not.
		     */
		    function contains(array, item) {
		      return array.indexOf(item) !== -1;
		    }
	
		    /**
		     * Returns the last item in the array
		     * @param {Array} array
		     * @return {*} item
		     */
		    function last(array) {
		      return array[array.length - 1];
		    }
	
		    // data type tests
		    var types = [{ name: 'number', test: function (x) {
		        return typeof x === 'number';
		      } }, { name: 'string', test: function (x) {
		        return typeof x === 'string';
		      } }, { name: 'boolean', test: function (x) {
		        return typeof x === 'boolean';
		      } }, { name: 'Function', test: function (x) {
		        return typeof x === 'function';
		      } }, { name: 'Array', test: Array.isArray }, { name: 'Date', test: function (x) {
		        return x instanceof Date;
		      } }, { name: 'RegExp', test: function (x) {
		        return x instanceof RegExp;
		      } }, { name: 'Object', test: function (x) {
		        return typeof x === 'object';
		      } }, { name: 'null', test: function (x) {
		        return x === null;
		      } }, { name: 'undefined', test: function (x) {
		        return x === undefined;
		      } }];
	
		    // configuration
		    var config = {};
	
		    // type conversions. Order is important
		    var conversions = [];
	
		    // types to be ignored
		    var ignore = [];
	
		    // temporary object for holding types and conversions, for constructing
		    // the `typed` function itself
		    // TODO: find a more elegant solution for this
		    var typed = {
		      config: config,
		      types: types,
		      conversions: conversions,
		      ignore: ignore
		    };
	
		    /**
		     * Construct the typed function itself with various signatures
		     *
		     * Signatures:
		     *
		     *   typed(signatures: Object.<string, function>)
		     *   typed(name: string, signatures: Object.<string, function>)
		     */
		    typed = _typed('typed', {
		      'Object': function (signatures) {
		        var fns = [];
		        for (var signature in signatures) {
		          if (signatures.hasOwnProperty(signature)) {
		            fns.push(signatures[signature]);
		          }
		        }
		        var name = getName(fns);
	
		        return _typed(name, signatures);
		      },
		      'string, Object': _typed,
		      // TODO: add a signature 'Array.<function>'
		      '...Function': function (fns) {
		        var err;
		        var name = getName(fns);
		        var signatures = {};
	
		        for (var i = 0; i < fns.length; i++) {
		          var fn = fns[i];
	
		          // test whether this is a typed-function
		          if (!(typeof fn.signatures === 'object')) {
		            err = new TypeError('Function is no typed-function (index: ' + i + ')');
		            err.data = { index: i };
		            throw err;
		          }
	
		          // merge the signatures
		          for (var signature in fn.signatures) {
		            if (fn.signatures.hasOwnProperty(signature)) {
		              if (signatures.hasOwnProperty(signature)) {
		                if (fn.signatures[signature] !== signatures[signature]) {
		                  err = new Error('Signature "' + signature + '" is defined twice');
		                  err.data = { signature: signature };
		                  throw err;
		                }
		                // else: both signatures point to the same function, that's fine
		              } else {
		                signatures[signature] = fn.signatures[signature];
		              }
		            }
		          }
		        }
	
		        return _typed(name, signatures);
		      }
		    });
	
		    /**
		     * Find a specific signature from a (composed) typed function, for
		     * example:
		     *
		     *   typed.find(fn, ['number', 'string'])
		     *   typed.find(fn, 'number, string')
		     *
		     * Function find only only works for exact matches.
		     *
		     * @param {Function} fn                   A typed-function
		     * @param {string | string[]} signature   Signature to be found, can be
		     *                                        an array or a comma separated string.
		     * @return {Function}                     Returns the matching signature, or
		     *                                        throws an errror when no signature
		     *                                        is found.
		     */
		    function find(fn, signature) {
		      if (!fn.signatures) {
		        throw new TypeError('Function is no typed-function');
		      }
	
		      // normalize input
		      var arr;
		      if (typeof signature === 'string') {
		        arr = signature.split(',');
		        for (var i = 0; i < arr.length; i++) {
		          arr[i] = arr[i].trim();
		        }
		      } else if (Array.isArray(signature)) {
		        arr = signature;
		      } else {
		        throw new TypeError('String array or a comma separated string expected');
		      }
	
		      var str = arr.join(',');
	
		      // find an exact match
		      var match = fn.signatures[str];
		      if (match) {
		        return match;
		      }
	
		      // TODO: extend find to match non-exact signatures
	
		      throw new TypeError('Signature not found (signature: ' + (fn.name || 'unnamed') + '(' + arr.join(', ') + '))');
		    }
	
		    /**
		     * Convert a given value to another data type.
		     * @param {*} value
		     * @param {string} type
		     */
		    function convert(value, type) {
		      var from = getTypeOf(value);
	
		      // check conversion is needed
		      if (type === from) {
		        return value;
		      }
	
		      for (var i = 0; i < typed.conversions.length; i++) {
		        var conversion = typed.conversions[i];
		        if (conversion.from === from && conversion.to === type) {
		          return conversion.convert(value);
		        }
		      }
	
		      throw new Error('Cannot convert from ' + from + ' to ' + type);
		    }
	
		    // attach types and conversions to the final `typed` function
		    typed.config = config;
		    typed.types = types;
		    typed.conversions = conversions;
		    typed.ignore = ignore;
		    typed.create = create;
		    typed.find = find;
		    typed.convert = convert;
	
		    // add a type
		    typed.addType = function (type) {
		      if (!type || typeof type.name !== 'string' || typeof type.test !== 'function') {
		        throw new TypeError('Object with properties {name: string, test: function} expected');
		      }
	
		      typed.types.push(type);
		    };
	
		    // add a conversion
		    typed.addConversion = function (conversion) {
		      if (!conversion || typeof conversion.from !== 'string' || typeof conversion.to !== 'string' || typeof conversion.convert !== 'function') {
		        throw new TypeError('Object with properties {from: string, to: string, convert: function} expected');
		      }
	
		      typed.conversions.push(conversion);
		    };
	
		    return typed;
		  }
	
		  return create();
		});
	
	/***/ }),
	/* 200 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * @typedef {{sign: '+' | '-' | '', coefficients: number[], exponent: number}} SplitValue
		 */
	
		/**
		 * Test whether value is a number
		 * @param {*} value
		 * @return {boolean} isNumber
		 */
	
		exports.isNumber = function (value) {
		  return typeof value === 'number';
		};
	
		/**
		 * Check if a number is integer
		 * @param {number | boolean} value
		 * @return {boolean} isInteger
		 */
		exports.isInteger = function (value) {
		  return isFinite(value) ? value == Math.round(value) : false;
		  // Note: we use ==, not ===, as we can have Booleans as well
		};
	
		/**
		 * Calculate the sign of a number
		 * @param {number} x
		 * @returns {*}
		 */
		exports.sign = Math.sign || function (x) {
		  if (x > 0) {
		    return 1;
		  } else if (x < 0) {
		    return -1;
		  } else {
		    return 0;
		  }
		};
	
		/**
		 * Convert a number to a formatted string representation.
		 *
		 * Syntax:
		 *
		 *    format(value)
		 *    format(value, options)
		 *    format(value, precision)
		 *    format(value, fn)
		 *
		 * Where:
		 *
		 *    {number} value   The value to be formatted
		 *    {Object} options An object with formatting options. Available options:
		 *                     {string} notation
		 *                         Number notation. Choose from:
		 *                         'fixed'          Always use regular number notation.
		 *                                          For example '123.40' and '14000000'
		 *                         'exponential'    Always use exponential notation.
		 *                                          For example '1.234e+2' and '1.4e+7'
		 *                         'engineering'    Always use engineering notation.
		 *                                          For example '123.4e+0' and '14.0e+6'
		 *                         'auto' (default) Regular number notation for numbers
		 *                                          having an absolute value between
		 *                                          `lower` and `upper` bounds, and uses
		 *                                          exponential notation elsewhere.
		 *                                          Lower bound is included, upper bound
		 *                                          is excluded.
		 *                                          For example '123.4' and '1.4e7'.
		 *                     {number} precision   A number between 0 and 16 to round
		 *                                          the digits of the number.
		 *                                          In case of notations 'exponential' and
		 *                                          'auto', `precision` defines the total
		 *                                          number of significant digits returned
		 *                                          and is undefined by default.
		 *                                          In case of notation 'fixed',
		 *                                          `precision` defines the number of
		 *                                          significant digits after the decimal
		 *                                          point, and is 0 by default.
		 *                     {Object} exponential An object containing two parameters,
		 *                                          {number} lower and {number} upper,
		 *                                          used by notation 'auto' to determine
		 *                                          when to return exponential notation.
		 *                                          Default values are `lower=1e-3` and
		 *                                          `upper=1e5`.
		 *                                          Only applicable for notation `auto`.
		 *    {Function} fn    A custom formatting function. Can be used to override the
		 *                     built-in notations. Function `fn` is called with `value` as
		 *                     parameter and must return a string. Is useful for example to
		 *                     format all values inside a matrix in a particular way.
		 *
		 * Examples:
		 *
		 *    format(6.4);                                        // '6.4'
		 *    format(1240000);                                    // '1.24e6'
		 *    format(1/3);                                        // '0.3333333333333333'
		 *    format(1/3, 3);                                     // '0.333'
		 *    format(21385, 2);                                   // '21000'
		 *    format(12.071, {notation: 'fixed'});                // '12'
		 *    format(2.3,    {notation: 'fixed', precision: 2});  // '2.30'
		 *    format(52.8,   {notation: 'exponential'});          // '5.28e+1'
		 *    format(12345678, {notation: 'engineering'});        // '12.345678e+6'
		 *
		 * @param {number} value
		 * @param {Object | Function | number} [options]
		 * @return {string} str The formatted value
		 */
		exports.format = function (value, options) {
		  if (typeof options === 'function') {
		    // handle format(value, fn)
		    return options(value);
		  }
	
		  // handle special cases
		  if (value === Infinity) {
		    return 'Infinity';
		  } else if (value === -Infinity) {
		    return '-Infinity';
		  } else if (isNaN(value)) {
		    return 'NaN';
		  }
	
		  // default values for options
		  var notation = 'auto';
		  var precision = undefined;
	
		  if (options) {
		    // determine notation from options
		    if (options.notation) {
		      notation = options.notation;
		    }
	
		    // determine precision from options
		    if (exports.isNumber(options)) {
		      precision = options;
		    } else if (options.precision) {
		      precision = options.precision;
		    }
		  }
	
		  // handle the various notations
		  switch (notation) {
		    case 'fixed':
		      return exports.toFixed(value, precision);
	
		    case 'exponential':
		      return exports.toExponential(value, precision);
	
		    case 'engineering':
		      return exports.toEngineering(value, precision);
	
		    case 'auto':
		      return exports.toPrecision(value, precision, options && options.exponential)
	
		      // remove trailing zeros after the decimal point
		      .replace(/((\.\d*?)(0+))($|e)/, function () {
		        var digits = arguments[2];
		        var e = arguments[4];
		        return digits !== '.' ? digits + e : e;
		      });
	
		    default:
		      throw new Error('Unknown notation "' + notation + '". ' + 'Choose "auto", "exponential", or "fixed".');
		  }
		};
	
		/**
		 * Split a number into sign, coefficients, and exponent
		 * @param {number | string} value
		 * @return {SplitValue}
		 *              Returns an object containing sign, coefficients, and exponent
		 */
		exports.splitNumber = function (value) {
		  // parse the input value
		  var match = String(value).toLowerCase().match(/^0*?(-?)(\d+\.?\d*)(e([+-]?\d+))?$/);
		  if (!match) {
		    throw new SyntaxError('Invalid number ' + value);
		  }
	
		  var sign = match[1];
		  var digits = match[2];
		  var exponent = parseFloat(match[4] || '0');
	
		  var dot = digits.indexOf('.');
		  exponent += dot !== -1 ? dot - 1 : digits.length - 1;
	
		  var coefficients = digits.replace('.', '') // remove the dot (must be removed before removing leading zeros)
		  .replace(/^0*/, function (zeros) {
		    // remove leading zeros, add their count to the exponent
		    exponent -= zeros.length;
		    return '';
		  }).replace(/0*$/, '') // remove trailing zeros
		  .split('').map(function (d) {
		    return parseInt(d);
		  });
	
		  if (coefficients.length === 0) {
		    coefficients.push(0);
		    exponent++;
		  }
	
		  return {
		    sign: sign,
		    coefficients: coefficients,
		    exponent: exponent
		  };
		};
	
		/**
		 * Format a number in engineering notation. Like '1.23e+6', '2.3e+0', '3.500e-3'
		 * @param {number | string} value
		 * @param {number} [precision=0]        Optional number of decimals after the
		 *                                      decimal point. Zero by default.
		 */
		exports.toEngineering = function (value, precision) {
		  if (isNaN(value) || !isFinite(value)) {
		    return String(value);
		  }
	
		  var rounded = exports.roundDigits(exports.splitNumber(value), precision);
	
		  var e = rounded.exponent;
		  var c = rounded.coefficients;
	
		  // find nearest lower multiple of 3 for exponent
		  var newExp = e % 3 === 0 ? e : e < 0 ? e - 3 - e % 3 : e - e % 3;
	
		  // concatenate coefficients with necessary zeros
		  var significandsDiff = e >= 0 ? e : Math.abs(newExp);
	
		  // add zeros if necessary (for ex: 1e+8)
		  if (c.length - 1 < significandsDiff) c = c.concat(zeros(significandsDiff - (c.length - 1)));
	
		  // find difference in exponents
		  var expDiff = Math.abs(e - newExp);
	
		  var decimalIdx = 1;
	
		  // push decimal index over by expDiff times
		  while (--expDiff >= 0) decimalIdx++;
	
		  // if all coefficient values are zero after the decimal point, don't add a decimal value.
		  // otherwise concat with the rest of the coefficients
		  var decimals = c.slice(decimalIdx).join('');
		  var decimalVal = decimals.match(/[1-9]/) ? '.' + decimals : '';
	
		  var str = c.slice(0, decimalIdx).join('') + decimalVal + 'e' + (e >= 0 ? '+' : '') + newExp.toString();
		  return rounded.sign + str;
		};
	
		/**
		 * Format a number with fixed notation.
		 * @param {number | string} value
		 * @param {number} [precision=0]        Optional number of decimals after the
		 *                                      decimal point. Zero by default.
		 */
		exports.toFixed = function (value, precision) {
		  if (isNaN(value) || !isFinite(value)) {
		    return String(value);
		  }
	
		  var splitValue = exports.splitNumber(value);
		  var rounded = exports.roundDigits(splitValue, splitValue.exponent + 1 + (precision || 0));
		  var c = rounded.coefficients;
		  var p = rounded.exponent + 1; // exponent may have changed
	
		  // append zeros if needed
		  var pp = p + (precision || 0);
		  if (c.length < pp) {
		    c = c.concat(zeros(pp - c.length));
		  }
	
		  // prepend zeros if needed
		  if (p < 0) {
		    c = zeros(-p + 1).concat(c);
		    p = 1;
		  }
	
		  // insert a dot if needed
		  if (precision) {
		    c.splice(p, 0, p === 0 ? '0.' : '.');
		  }
	
		  return rounded.sign + c.join('');
		};
	
		/**
		 * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3'
		 * @param {number | string} value
		 * @param {number} [precision]  Number of digits in formatted output.
		 *                              If not provided, the maximum available digits
		 *                              is used.
		 */
		exports.toExponential = function (value, precision) {
		  if (isNaN(value) || !isFinite(value)) {
		    return String(value);
		  }
	
		  // round if needed, else create a clone
		  var split = exports.splitNumber(value);
		  var rounded = precision ? exports.roundDigits(split, precision) : split;
		  var c = rounded.coefficients;
		  var e = rounded.exponent;
	
		  // append zeros if needed
		  if (c.length < precision) {
		    c = c.concat(zeros(precision - c.length));
		  }
	
		  // format as `C.CCCe+EEE` or `C.CCCe-EEE`
		  var first = c.shift();
		  return rounded.sign + first + (c.length > 0 ? '.' + c.join('') : '') + 'e' + (e >= 0 ? '+' : '') + e;
		};
	
		/**
		 * Format a number with a certain precision
		 * @param {number | string} value
		 * @param {number} [precision=undefined] Optional number of digits.
		 * @param {{lower: number | undefined, upper: number | undefined}} [options]
		 *                                       By default:
		 *                                         lower = 1e-3 (excl)
		 *                                         upper = 1e+5 (incl)
		 * @return {string}
		 */
		exports.toPrecision = function (value, precision, options) {
		  if (isNaN(value) || !isFinite(value)) {
		    return String(value);
		  }
	
		  // determine lower and upper bound for exponential notation.
		  var lower = options && options.lower !== undefined ? options.lower : 1e-3;
		  var upper = options && options.upper !== undefined ? options.upper : 1e+5;
	
		  var split = exports.splitNumber(value);
		  var abs = Math.abs(Math.pow(10, split.exponent));
		  if (abs < lower || abs >= upper) {
		    // exponential notation
		    return exports.toExponential(value, precision);
		  } else {
		    var rounded = precision ? exports.roundDigits(split, precision) : split;
		    var c = rounded.coefficients;
		    var e = rounded.exponent;
	
		    // append trailing zeros
		    if (c.length < precision) {
		      c = c.concat(zeros(precision - c.length));
		    }
	
		    // append trailing zeros
		    // TODO: simplify the next statement
		    c = c.concat(zeros(e - c.length + 1 + (c.length < precision ? precision - c.length : 0)));
	
		    // prepend zeros
		    c = zeros(-e).concat(c);
	
		    var dot = e > 0 ? e : 0;
		    if (dot < c.length - 1) {
		      c.splice(dot + 1, 0, '.');
		    }
	
		    return rounded.sign + c.join('');
		  }
		};
	
		/**
		 * Round the number of digits of a number *
		 * @param {SplitValue} split       A value split with .splitNumber(value)
		 * @param {number} precision  A positive integer
		 * @return {SplitValue}
		 *              Returns an object containing sign, coefficients, and exponent
		 *              with rounded digits
		 */
		exports.roundDigits = function (split, precision) {
		  // create a clone
		  var rounded = {
		    sign: split.sign,
		    coefficients: split.coefficients,
		    exponent: split.exponent
		  };
		  var c = rounded.coefficients;
	
		  // prepend zeros if needed
		  while (precision <= 0) {
		    c.unshift(0);
		    rounded.exponent++;
		    precision++;
		  }
	
		  if (c.length > precision) {
		    var removed = c.splice(precision, c.length - precision);
	
		    if (removed[0] >= 5) {
		      var i = precision - 1;
		      c[i]++;
		      while (c[i] === 10) {
		        c.pop();
		        if (i === 0) {
		          c.unshift(0);
		          rounded.exponent++;
		          i++;
		        }
		        i--;
		        c[i]++;
		      }
		    }
		  }
	
		  return rounded;
		};
	
		/**
		 * Create an array filled with zeros.
		 * @param {number} length
		 * @return {Array}
		 */
		function zeros(length) {
		  var arr = [];
		  for (var i = 0; i < length; i++) {
		    arr.push(0);
		  }
		  return arr;
		}
	
		/**
		 * Count the number of significant digits of a number.
		 *
		 * For example:
		 *   2.34 returns 3
		 *   0.0034 returns 2
		 *   120.5e+30 returns 4
		 *
		 * @param {number} value
		 * @return {number} digits   Number of significant digits
		 */
		exports.digits = function (value) {
		  return value.toExponential().replace(/e.*$/, '') // remove exponential notation
		  .replace(/^0\.?0*|\./, '') // remove decimal point and leading zeros
		  .length;
		};
	
		/**
		 * Minimum number added to one that makes the result different than one
		 */
		exports.DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-16;
	
		/**
		 * Compares two floating point numbers.
		 * @param {number} x          First value to compare
		 * @param {number} y          Second value to compare
		 * @param {number} [epsilon]  The maximum relative difference between x and y
		 *                            If epsilon is undefined or null, the function will
		 *                            test whether x and y are exactly equal.
		 * @return {boolean} whether the two numbers are nearly equal
		*/
		exports.nearlyEqual = function (x, y, epsilon) {
		  // if epsilon is null or undefined, test whether x and y are exactly equal
		  if (epsilon == null) {
		    return x == y;
		  }
	
		  // use "==" operator, handles infinities
		  if (x == y) {
		    return true;
		  }
	
		  // NaN
		  if (isNaN(x) || isNaN(y)) {
		    return false;
		  }
	
		  // at this point x and y should be finite
		  if (isFinite(x) && isFinite(y)) {
		    // check numbers are very close, needed when comparing numbers near zero
		    var diff = Math.abs(x - y);
		    if (diff < exports.DBL_EPSILON) {
		      return true;
		    } else {
		      // use relative error
		      return diff <= Math.max(Math.abs(x), Math.abs(y)) * epsilon;
		    }
		  }
	
		  // Infinite and Number or negative Infinite and positive Infinite cases
		  return false;
		};
	
	/***/ }),
	/* 201 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Test whether a value is a Matrix
		 * @param {*} x
		 * @returns {boolean} returns true with input is a Matrix
		 *                    (like a DenseMatrix or SparseMatrix)
		 */
	
		module.exports = function isMatrix(x) {
		  return x && x.constructor.prototype.isMatrix || false;
		};
	
	/***/ }),
	/* 202 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var Emitter = __webpack_require__(203);
	
		/**
		 * Extend given object with emitter functions `on`, `off`, `once`, `emit`
		 * @param {Object} obj
		 * @return {Object} obj
		 */
		exports.mixin = function (obj) {
		  // create event emitter
		  var emitter = new Emitter();
	
		  // bind methods to obj (we don't want to expose the emitter.e Array...)
		  obj.on = emitter.on.bind(emitter);
		  obj.off = emitter.off.bind(emitter);
		  obj.once = emitter.once.bind(emitter);
		  obj.emit = emitter.emit.bind(emitter);
	
		  return obj;
		};
	
	/***/ }),
	/* 203 */
	/***/ (function(module, exports) {
	
		function E() {
		  // Keep this empty so it's easier to inherit from
		  // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
		}
	
		E.prototype = {
		  on: function (name, callback, ctx) {
		    var e = this.e || (this.e = {});
	
		    (e[name] || (e[name] = [])).push({
		      fn: callback,
		      ctx: ctx
		    });
	
		    return this;
		  },
	
		  once: function (name, callback, ctx) {
		    var self = this;
		    function listener() {
		      self.off(name, listener);
		      callback.apply(ctx, arguments);
		    };
	
		    listener._ = callback;
		    return this.on(name, listener, ctx);
		  },
	
		  emit: function (name) {
		    var data = [].slice.call(arguments, 1);
		    var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
		    var i = 0;
		    var len = evtArr.length;
	
		    for (i; i < len; i++) {
		      evtArr[i].fn.apply(evtArr[i].ctx, data);
		    }
	
		    return this;
		  },
	
		  off: function (name, callback) {
		    var e = this.e || (this.e = {});
		    var evts = e[name];
		    var liveEvents = [];
	
		    if (evts && callback) {
		      for (var i = 0, len = evts.length; i < len; i++) {
		        if (evts[i].fn !== callback && evts[i].fn._ !== callback) liveEvents.push(evts[i]);
		      }
		    }
	
		    // Remove event from queue to prevent memory leak
		    // Suggested by https://github.com/lazd
		    // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
	
		    liveEvents.length ? e[name] = liveEvents : delete e[name];
	
		    return this;
		  }
		};
	
			module.exports = E;
	
	/***/ }),
	/* 204 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var lazy = __webpack_require__(196).lazy;
		var isFactory = __webpack_require__(196).isFactory;
		var traverse = __webpack_require__(196).traverse;
		var ArgumentsError = __webpack_require__(205);
	
		function factory(type, config, load, typed, math) {
		  /**
		   * Import functions from an object or a module
		   *
		   * Syntax:
		   *
		   *    math.import(object)
		   *    math.import(object, options)
		   *
		   * Where:
		   *
		   * - `object: Object`
		   *   An object with functions to be imported.
		   * - `options: Object` An object with import options. Available options:
		   *   - `override: boolean`
		   *     If true, existing functions will be overwritten. False by default.
		   *   - `silent: boolean`
		   *     If true, the function will not throw errors on duplicates or invalid
		   *     types. False by default.
		   *   - `wrap: boolean`
		   *     If true, the functions will be wrapped in a wrapper function
		   *     which converts data types like Matrix to primitive data types like Array.
		   *     The wrapper is needed when extending math.js with libraries which do not
		   *     support these data type. False by default.
		   *
		   * Examples:
		   *
		   *    // define new functions and variables
		   *    math.import({
		   *      myvalue: 42,
		   *      hello: function (name) {
		   *        return 'hello, ' + name + '!';
		   *      }
		   *    });
		   *
		   *    // use the imported function and variable
		   *    math.myvalue * 2;               // 84
		   *    math.hello('user');             // 'hello, user!'
		   *
		   *    // import the npm module 'numbers'
		   *    // (must be installed first with `npm install numbers`)
		   *    math.import(require('numbers'), {wrap: true});
		   *
		   *    math.fibonacci(7); // returns 13
		   *
		   * @param {Object | Array} object   Object with functions to be imported.
		   * @param {Object} [options]        Import options.
		   */
		  function math_import(object, options) {
		    var num = arguments.length;
		    if (num !== 1 && num !== 2) {
		      throw new ArgumentsError('import', num, 1, 2);
		    }
	
		    if (!options) {
		      options = {};
		    }
	
		    if (isFactory(object)) {
		      _importFactory(object, options);
		    }
		    // TODO: allow a typed-function with name too
		    else if (Array.isArray(object)) {
		        object.forEach(function (entry) {
		          math_import(entry, options);
		        });
		      } else if (typeof object === 'object') {
		        // a map with functions
		        for (var name in object) {
		          if (object.hasOwnProperty(name)) {
		            var value = object[name];
		            if (isSupportedType(value)) {
		              _import(name, value, options);
		            } else if (isFactory(object)) {
		              _importFactory(object, options);
		            } else {
		              math_import(value, options);
		            }
		          }
		        }
		      } else {
		        if (!options.silent) {
		          throw new TypeError('Factory, Object, or Array expected');
		        }
		      }
		  }
	
		  /**
		   * Add a property to the math namespace and create a chain proxy for it.
		   * @param {string} name
		   * @param {*} value
		   * @param {Object} options  See import for a description of the options
		   * @private
		   */
		  function _import(name, value, options) {
		    // TODO: refactor this function, it's to complicated and contains duplicate code
		    if (options.wrap && typeof value === 'function') {
		      // create a wrapper around the function
		      value = _wrap(value);
		    }
	
		    if (isTypedFunction(math[name]) && isTypedFunction(value)) {
		      if (options.override) {
		        // give the typed function the right name
		        value = typed(name, value.signatures);
		      } else {
		        // merge the existing and typed function
		        value = typed(math[name], value);
		      }
	
		      math[name] = value;
		      _importTransform(name, value);
		      math.emit('import', name, function resolver() {
		        return value;
		      });
		      return;
		    }
	
		    if (math[name] === undefined || options.override) {
		      math[name] = value;
		      _importTransform(name, value);
		      math.emit('import', name, function resolver() {
		        return value;
		      });
		      return;
		    }
	
		    if (!options.silent) {
		      throw new Error('Cannot import "' + name + '": already exists');
		    }
		  }
	
		  function _importTransform(name, value) {
		    if (value && typeof value.transform === 'function') {
		      math.expression.transform[name] = value.transform;
		      if (allowedInExpressions(name)) {
		        math.expression.mathWithTransform[name] = value.transform;
		      }
		    } else {
		      // remove existing transform
		      delete math.expression.transform[name];
		      if (allowedInExpressions(name)) {
		        math.expression.mathWithTransform[name] = value;
		      }
		    }
		  }
	
		  /**
		   * Create a wrapper a round an function which converts the arguments
		   * to their primitive values (like convert a Matrix to Array)
		   * @param {Function} fn
		   * @return {Function} Returns the wrapped function
		   * @private
		   */
		  function _wrap(fn) {
		    var wrapper = function wrapper() {
		      var args = [];
		      for (var i = 0, len = arguments.length; i < len; i++) {
		        var arg = arguments[i];
		        args[i] = arg && arg.valueOf();
		      }
		      return fn.apply(math, args);
		    };
	
		    if (fn.transform) {
		      wrapper.transform = fn.transform;
		    }
	
		    return wrapper;
		  }
	
		  /**
		   * Import an instance of a factory into math.js
		   * @param {{factory: Function, name: string, path: string, math: boolean}} factory
		   * @param {Object} options  See import for a description of the options
		   * @private
		   */
		  function _importFactory(factory, options) {
		    if (typeof factory.name === 'string') {
		      var name = factory.name;
		      var existingTransform = name in math.expression.transform;
		      var namespace = factory.path ? traverse(math, factory.path) : math;
		      var existing = namespace.hasOwnProperty(name) ? namespace[name] : undefined;
	
		      var resolver = function () {
		        var instance = load(factory);
		        if (instance && typeof instance.transform === 'function') {
		          throw new Error('Transforms cannot be attached to factory functions. ' + 'Please create a separate function for it with exports.path="expression.transform"');
		        }
	
		        if (isTypedFunction(existing) && isTypedFunction(instance)) {
		          if (options.override) {
		            // replace the existing typed function (nothing to do)
		          } else {
		            // merge the existing and new typed function
		            instance = typed(existing, instance);
		          }
	
		          return instance;
		        }
	
		        if (existing === undefined || options.override) {
		          return instance;
		        }
	
		        if (!options.silent) {
		          throw new Error('Cannot import "' + name + '": already exists');
		        }
		      };
	
		      if (factory.lazy !== false) {
		        lazy(namespace, name, resolver);
	
		        if (!existingTransform) {
		          if (factory.path === 'expression.transform' || factoryAllowedInExpressions(factory)) {
		            lazy(math.expression.mathWithTransform, name, resolver);
		          }
		        }
		      } else {
		        namespace[name] = resolver();
	
		        if (!existingTransform) {
		          if (factory.path === 'expression.transform' || factoryAllowedInExpressions(factory)) {
		            math.expression.mathWithTransform[name] = resolver();
		          }
		        }
		      }
	
		      math.emit('import', name, resolver, factory.path);
		    } else {
		      // unnamed factory.
		      // no lazy loading
		      load(factory);
		    }
		  }
	
		  /**
		   * Check whether given object is a type which can be imported
		   * @param {Function | number | string | boolean | null | Unit | Complex} object
		   * @return {boolean}
		   * @private
		   */
		  function isSupportedType(object) {
		    return typeof object === 'function' || typeof object === 'number' || typeof object === 'string' || typeof object === 'boolean' || object === null || object && type.isUnit(object) || object && type.isComplex(object) || object && type.isBigNumber(object) || object && type.isFraction(object) || object && type.isMatrix(object) || object && Array.isArray(object);
		  }
	
		  /**
		   * Test whether a given thing is a typed-function
		   * @param {*} fn
		   * @return {boolean} Returns true when `fn` is a typed-function
		   */
		  function isTypedFunction(fn) {
		    return typeof fn === 'function' && typeof fn.signatures === 'object';
		  }
	
		  function allowedInExpressions(name) {
		    return !unsafe.hasOwnProperty(name);
		  }
	
		  function factoryAllowedInExpressions(factory) {
		    return factory.path === undefined && !unsafe.hasOwnProperty(factory.name);
		  }
	
		  // namespaces and functions not available in the parser for safety reasons
		  var unsafe = {
		    'expression': true,
		    'type': true,
		    'docs': true,
		    'error': true,
		    'json': true,
		    'chain': true // chain method not supported. Note that there is a unit chain too.
		  };
	
		  return math_import;
		}
	
		exports.math = true; // request access to the math namespace as 5th argument of the factory function
		exports.name = 'import';
		exports.factory = factory;
		exports.lazy = true;
	
	/***/ }),
	/* 205 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Create a syntax error with the message:
		 *     'Wrong number of arguments in function <fn> (<count> provided, <min>-<max> expected)'
		 * @param {string} fn     Function name
		 * @param {number} count  Actual argument count
		 * @param {number} min    Minimum required argument count
		 * @param {number} [max]  Maximum required argument count
		 * @extends Error
		 */
	
		function ArgumentsError(fn, count, min, max) {
		  if (!(this instanceof ArgumentsError)) {
		    throw new SyntaxError('Constructor must be called with the new operator');
		  }
	
		  this.fn = fn;
		  this.count = count;
		  this.min = min;
		  this.max = max;
	
		  this.message = 'Wrong number of arguments in function ' + fn + ' (' + count + ' provided, ' + min + (max != undefined ? '-' + max : '') + ' expected)';
	
		  this.stack = new Error().stack;
		}
	
		ArgumentsError.prototype = new Error();
		ArgumentsError.prototype.constructor = Error;
		ArgumentsError.prototype.name = 'ArgumentsError';
		ArgumentsError.prototype.isArgumentsError = true;
	
		module.exports = ArgumentsError;
	
	/***/ }),
	/* 206 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var object = __webpack_require__(196);
	
		function factory(type, config, load, typed, math) {
		  var MATRIX = ['Matrix', 'Array']; // valid values for option matrix
		  var NUMBER = ['number', 'BigNumber', 'Fraction']; // valid values for option number
	
		  /**
		   * Set configuration options for math.js, and get current options.
		   * Will emit a 'config' event, with arguments (curr, prev, changes).
		   *
		   * Syntax:
		   *
		   *     math.config(config: Object): Object
		   *
		   * Examples:
		   *
		   *     math.config().number;                // outputs 'number'
		   *     math.eval('0.4');                    // outputs number 0.4
		   *     math.config({number: 'Fraction'});
		   *     math.eval('0.4');                    // outputs Fraction 2/5
		   *
		   * @param {Object} [options] Available options:
		   *                            {number} epsilon
		   *                              Minimum relative difference between two
		   *                              compared values, used by all comparison functions.
		   *                            {string} matrix
		   *                              A string 'Matrix' (default) or 'Array'.
		   *                            {string} number
		   *                              A string 'number' (default), 'BigNumber', or 'Fraction'
		   *                            {number} precision
		   *                              The number of significant digits for BigNumbers.
		   *                              Not applicable for Numbers.
		   *                            {string} parenthesis
		   *                              How to display parentheses in LaTeX and string
		   *                              output.
		   *                            {string} randomSeed
		   *                              Random seed for seeded pseudo random number generator.
		   *                              Set to null to randomly seed.
		   * @return {Object} Returns the current configuration
		   */
		  function _config(options) {
		    if (options) {
		      var prev = object.map(config, object.clone);
	
		      // validate some of the options
		      validateOption(options, 'matrix', MATRIX);
		      validateOption(options, 'number', NUMBER);
	
		      // merge options
		      object.deepExtend(config, options);
	
		      var curr = object.map(config, object.clone);
	
		      var changes = object.map(options, object.clone);
	
		      // emit 'config' event
		      math.emit('config', curr, prev, changes);
	
		      return curr;
		    } else {
		      return object.map(config, object.clone);
		    }
		  }
	
		  // attach the valid options to the function so they can be extended
		  _config.MATRIX = MATRIX;
		  _config.NUMBER = NUMBER;
	
		  return _config;
		}
	
		/**
		 * Test whether an Array contains a specific item.
		 * @param {Array.<string>} array
		 * @param {string} item
		 * @return {boolean}
		 */
		function contains(array, item) {
		  return array.indexOf(item) !== -1;
		}
	
		/**
		 * Find a string in an array. Case insensitive search
		 * @param {Array.<string>} array
		 * @param {string} item
		 * @return {number} Returns the index when found. Returns -1 when not found
		 */
		function findIndex(array, item) {
		  return array.map(function (i) {
		    return i.toLowerCase();
		  }).indexOf(item.toLowerCase());
		}
	
		/**
		 * Validate an option
		 * @param {Object} options         Object with options
		 * @param {string} name            Name of the option to validate
		 * @param {Array.<string>} values  Array with valid values for this option
		 */
		function validateOption(options, name, values) {
		  if (options[name] !== undefined && !contains(values, options[name])) {
		    var index = findIndex(values, options[name]);
		    if (index !== -1) {
		      // right value, wrong casing
		      // TODO: lower case values are deprecated since v3, remove this warning some day.
		      console.warn('Warning: Wrong casing for configuration option "' + name + '", should be "' + values[index] + '" instead of "' + options[name] + '".');
	
		      options[name] = values[index]; // change the option to the right casing
		    } else {
		      // unknown value
		      console.warn('Warning: Unknown value "' + options[name] + '" for configuration option "' + name + '". Available options: ' + values.map(JSON.stringify).join(', ') + '.');
		    }
		  }
		}
	
		exports.name = 'config';
		exports.math = true; // request the math namespace as fifth argument
		exports.factory = factory;
	
	/***/ }),
	/* 207 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var deepMap = __webpack_require__(208);
	
		function factory(type, config, load, typed) {
		  var gamma = load(__webpack_require__(209));
		  var latex = __webpack_require__(217);
	
		  /**
		   * Compute the factorial of a value
		   *
		   * Factorial only supports an integer value as argument.
		   * For matrices, the function is evaluated element wise.
		   *
		   * Syntax:
		   *
		   *    math.factorial(n)
		   *
		   * Examples:
		   *
		   *    math.factorial(5);    // returns 120
		   *    math.factorial(3);    // returns 6
		   *
		   * See also:
		   *
		   *    combinations, gamma, permutations
		   *
		   * @param {number | BigNumber | Array | Matrix} n   An integer number
		   * @return {number | BigNumber | Array | Matrix}    The factorial of `n`
		   */
		  var factorial = typed('factorial', {
		    'number': function (n) {
		      if (n < 0) {
		        throw new Error('Value must be non-negative');
		      }
	
		      return gamma(n + 1);
		    },
	
		    'BigNumber': function (n) {
		      if (n.isNegative()) {
		        throw new Error('Value must be non-negative');
		      }
	
		      return gamma(n.plus(1));
		    },
	
		    'Array | Matrix': function (n) {
		      return deepMap(n, factorial);
		    }
		  });
	
		  factorial.toTex = {
		    1: '\\left(${args[0]}\\right)' + latex.operators['factorial']
		  };
	
		  return factorial;
		}
	
		exports.name = 'factorial';
		exports.factory = factory;
	
	/***/ }),
	/* 208 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Execute the callback function element wise for each element in array and any
		 * nested array
		 * Returns an array with the results
		 * @param {Array | Matrix} array
		 * @param {Function} callback   The callback is called with two parameters:
		 *                              value1 and value2, which contain the current
		 *                              element of both arrays.
		 * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
		 *
		 * @return {Array | Matrix} res
		 */
	
		module.exports = function deepMap(array, callback, skipZeros) {
		  if (array && typeof array.map === 'function') {
		    // TODO: replace array.map with a for loop to improve performance
		    return array.map(function (x) {
		      return deepMap(x, callback, skipZeros);
		    });
		  } else {
		    return callback(array);
		  }
		};
	
	/***/ }),
	/* 209 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var deepMap = __webpack_require__(208);
		var isInteger = __webpack_require__(200).isInteger;
	
		function factory(type, config, load, typed) {
		  var multiply = load(__webpack_require__(210));
		  var pow = load(__webpack_require__(225));
	
		  /**
		   * Compute the gamma function of a value using Lanczos approximation for
		   * small values, and an extended Stirling approximation for large values.
		   *
		   * For matrices, the function is evaluated element wise.
		   *
		   * Syntax:
		   *
		   *    math.gamma(n)
		   *
		   * Examples:
		   *
		   *    math.gamma(5);       // returns 24
		   *    math.gamma(-0.5);    // returns -3.5449077018110335
		   *    math.gamma(math.i);  // returns -0.15494982830180973 - 0.49801566811835596i
		   *
		   * See also:
		   *
		   *    combinations, factorial, permutations
		   *
		   * @param {number | Array | Matrix} n   A real or complex number
		   * @return {number | Array | Matrix}    The gamma of `n`
		   */
		  var gamma = typed('gamma', {
		    'number': function (n) {
		      var t, x;
	
		      if (isInteger(n)) {
		        if (n <= 0) {
		          return isFinite(n) ? Infinity : NaN;
		        }
	
		        if (n > 171) {
		          return Infinity; // Will overflow
		        }
	
		        var value = n - 2;
		        var res = n - 1;
		        while (value > 1) {
		          res *= value;
		          value--;
		        }
	
		        if (res == 0) {
		          res = 1; // 0! is per definition 1
		        }
	
		        return res;
		      }
	
		      if (n < 0.5) {
		        return Math.PI / (Math.sin(Math.PI * n) * gamma(1 - n));
		      }
	
		      if (n >= 171.35) {
		        return Infinity; // will overflow
		      }
	
		      if (n > 85.0) {
		        // Extended Stirling Approx
		        var twoN = n * n;
		        var threeN = twoN * n;
		        var fourN = threeN * n;
		        var fiveN = fourN * n;
		        return Math.sqrt(2 * Math.PI / n) * Math.pow(n / Math.E, n) * (1 + 1 / (12 * n) + 1 / (288 * twoN) - 139 / (51840 * threeN) - 571 / (2488320 * fourN) + 163879 / (209018880 * fiveN) + 5246819 / (75246796800 * fiveN * n));
		      }
	
		      --n;
		      x = p[0];
		      for (var i = 1; i < p.length; ++i) {
		        x += p[i] / (n + i);
		      }
	
		      t = n + g + 0.5;
		      return Math.sqrt(2 * Math.PI) * Math.pow(t, n + 0.5) * Math.exp(-t) * x;
		    },
	
		    'Complex': function (n) {
		      var t, x;
	
		      if (n.im == 0) {
		        return gamma(n.re);
		      }
	
		      n = new type.Complex(n.re - 1, n.im);
		      x = new type.Complex(p[0], 0);
		      for (var i = 1; i < p.length; ++i) {
		        var real = n.re + i; // x += p[i]/(n+i)
		        var den = real * real + n.im * n.im;
		        if (den != 0) {
		          x.re += p[i] * real / den;
		          x.im += -(p[i] * n.im) / den;
		        } else {
		          x.re = p[i] < 0 ? -Infinity : Infinity;
		        }
		      }
	
		      t = new type.Complex(n.re + g + 0.5, n.im);
		      var twoPiSqrt = Math.sqrt(2 * Math.PI);
	
		      n.re += 0.5;
		      var result = pow(t, n);
		      if (result.im == 0) {
		        // sqrt(2*PI)*result
		        result.re *= twoPiSqrt;
		      } else if (result.re == 0) {
		        result.im *= twoPiSqrt;
		      } else {
		        result.re *= twoPiSqrt;
		        result.im *= twoPiSqrt;
		      }
	
		      var r = Math.exp(-t.re); // exp(-t)
		      t.re = r * Math.cos(-t.im);
		      t.im = r * Math.sin(-t.im);
	
		      return multiply(multiply(result, t), x);
		    },
	
		    'BigNumber': function (n) {
		      if (n.isInteger()) {
		        return n.isNegative() || n.isZero() ? new type.BigNumber(Infinity) : bigFactorial(n.minus(1));
		      }
	
		      if (!n.isFinite()) {
		        return new type.BigNumber(n.isNegative() ? NaN : Infinity);
		      }
	
		      throw new Error('Integer BigNumber expected');
		    },
	
		    'Array | Matrix': function (n) {
		      return deepMap(n, gamma);
		    }
		  });
	
		  /**
		   * Calculate factorial for a BigNumber
		   * @param {BigNumber} n
		   * @returns {BigNumber} Returns the factorial of n
		   */
		  function bigFactorial(n) {
		    if (n.isZero()) {
		      return new type.BigNumber(1); // 0! is per definition 1
		    }
	
		    var precision = config.precision + (Math.log(n.toNumber()) | 0);
		    var Big = type.BigNumber.clone({ precision: precision });
	
		    var res = new Big(n);
		    var value = n.toNumber() - 1; // number
		    while (value > 1) {
		      res = res.times(value);
		      value--;
		    }
	
		    return new type.BigNumber(res.toPrecision(type.BigNumber.precision));
		  }
	
		  gamma.toTex = { 1: '\\Gamma\\left(${args[0]}\\right)' };
	
		  return gamma;
		}
	
		// TODO: comment on the variables g and p
	
		var g = 4.7421875;
	
		var p = [0.99999999999999709182, 57.156235665862923517, -59.597960355475491248, 14.136097974741747174, -0.49191381609762019978, 0.33994649984811888699e-4, 0.46523628927048575665e-4, -0.98374475304879564677e-4, 0.15808870322491248884e-3, -0.21026444172410488319e-3, 0.21743961811521264320e-3, -0.16431810653676389022e-3, 0.84418223983852743293e-4, -0.26190838401581408670e-4, 0.36899182659531622704e-5];
	
		exports.name = 'gamma';
		exports.factory = factory;
	
	/***/ }),
	/* 210 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var extend = __webpack_require__(196).extend;
		var array = __webpack_require__(211);
	
		function factory(type, config, load, typed) {
		  var latex = __webpack_require__(217);
	
		  var matrix = load(__webpack_require__(218));
		  var addScalar = load(__webpack_require__(219));
		  var multiplyScalar = load(__webpack_require__(220));
		  var equalScalar = load(__webpack_require__(221));
	
		  var algorithm11 = load(__webpack_require__(223));
		  var algorithm14 = load(__webpack_require__(224));
	
		  var DenseMatrix = type.DenseMatrix;
		  var SparseMatrix = type.SparseMatrix;
	
		  /**
		   * Multiply two or more values, `x * y`.
		   * For matrices, the matrix product is calculated.
		   *
		   * Syntax:
		   *
		   *    math.multiply(x, y)
		   *    math.multiply(x, y, z, ...)
		   *
		   * Examples:
		   *
		   *    math.multiply(4, 5.2);        // returns number 20.8
		   *    math.multiply(2, 3, 4);       // returns number 24
		   *
		   *    var a = math.complex(2, 3);
		   *    var b = math.complex(4, 1);
		   *    math.multiply(a, b);          // returns Complex 5 + 14i
		   *
		   *    var c = [[1, 2], [4, 3]];
		   *    var d = [[1, 2, 3], [3, -4, 7]];
		   *    math.multiply(c, d);          // returns Array [[7, -6, 17], [13, -4, 33]]
		   *
		   *    var e = math.unit('2.1 km');
		   *    math.multiply(3, e);          // returns Unit 6.3 km
		   *
		   * See also:
		   *
		   *    divide, prod, cross, dot
		   *
		   * @param  {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First value to multiply
		   * @param  {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second value to multiply
		   * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Multiplication of `x` and `y`
		   */
		  var multiply = typed('multiply', extend({
		    // we extend the signatures of multiplyScalar with signatures dealing with matrices
	
		    'Array, Array': function (x, y) {
		      // check dimensions
		      _validateMatrixDimensions(array.size(x), array.size(y));
	
		      // use dense matrix implementation
		      var m = multiply(matrix(x), matrix(y));
		      // return array or scalar
		      return type.isMatrix(m) ? m.valueOf() : m;
		    },
	
		    'Matrix, Matrix': function (x, y) {
		      // dimensions
		      var xsize = x.size();
		      var ysize = y.size();
	
		      // check dimensions
		      _validateMatrixDimensions(xsize, ysize);
	
		      // process dimensions
		      if (xsize.length === 1) {
		        // process y dimensions
		        if (ysize.length === 1) {
		          // Vector * Vector
		          return _multiplyVectorVector(x, y, xsize[0]);
		        }
		        // Vector * Matrix
		        return _multiplyVectorMatrix(x, y);
		      }
		      // process y dimensions
		      if (ysize.length === 1) {
		        // Matrix * Vector
		        return _multiplyMatrixVector(x, y);
		      }
		      // Matrix * Matrix
		      return _multiplyMatrixMatrix(x, y);
		    },
	
		    'Matrix, Array': function (x, y) {
		      // use Matrix * Matrix implementation
		      return multiply(x, matrix(y));
		    },
	
		    'Array, Matrix': function (x, y) {
		      // use Matrix * Matrix implementation
		      return multiply(matrix(x, y.storage()), y);
		    },
	
		    'Matrix, any': function (x, y) {
		      // result
		      var c;
	
		      // process storage format
		      switch (x.storage()) {
		        case 'sparse':
		          c = algorithm11(x, y, multiplyScalar, false);
		          break;
		        case 'dense':
		          c = algorithm14(x, y, multiplyScalar, false);
		          break;
		      }
		      return c;
		    },
	
		    'any, Matrix': function (x, y) {
		      // result
		      var c;
		      // check storage format
		      switch (y.storage()) {
		        case 'sparse':
		          c = algorithm11(y, x, multiplyScalar, true);
		          break;
		        case 'dense':
		          c = algorithm14(y, x, multiplyScalar, true);
		          break;
		      }
		      return c;
		    },
	
		    'Array, any': function (x, y) {
		      // use matrix implementation
		      return algorithm14(matrix(x), y, multiplyScalar, false).valueOf();
		    },
	
		    'any, Array': function (x, y) {
		      // use matrix implementation
		      return algorithm14(matrix(y), x, multiplyScalar, true).valueOf();
		    },
	
		    'any, any': multiplyScalar,
	
		    'Array | Matrix | any, Array | Matrix | any, ...any': function (x, y, rest) {
		      var result = multiply(x, y);
	
		      for (var i = 0; i < rest.length; i++) {
		        result = multiply(result, rest[i]);
		      }
	
		      return result;
		    }
		  }, multiplyScalar.signatures));
	
		  var _validateMatrixDimensions = function (size1, size2) {
		    // check left operand dimensions
		    switch (size1.length) {
		      case 1:
		        // check size2
		        switch (size2.length) {
		          case 1:
		            // Vector x Vector
		            if (size1[0] !== size2[0]) {
		              // throw error
		              throw new RangeError('Dimension mismatch in multiplication. Vectors must have the same length');
		            }
		            break;
		          case 2:
		            // Vector x Matrix
		            if (size1[0] !== size2[0]) {
		              // throw error
		              throw new RangeError('Dimension mismatch in multiplication. Vector length (' + size1[0] + ') must match Matrix rows (' + size2[0] + ')');
		            }
		            break;
		          default:
		            throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix B has ' + size2.length + ' dimensions)');
		        }
		        break;
		      case 2:
		        // check size2
		        switch (size2.length) {
		          case 1:
		            // Matrix x Vector
		            if (size1[1] !== size2[0]) {
		              // throw error
		              throw new RangeError('Dimension mismatch in multiplication. Matrix columns (' + size1[1] + ') must match Vector length (' + size2[0] + ')');
		            }
		            break;
		          case 2:
		            // Matrix x Matrix
		            if (size1[1] !== size2[0]) {
		              // throw error
		              throw new RangeError('Dimension mismatch in multiplication. Matrix A columns (' + size1[1] + ') must match Matrix B rows (' + size2[0] + ')');
		            }
		            break;
		          default:
		            throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix B has ' + size2.length + ' dimensions)');
		        }
		        break;
		      default:
		        throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix A has ' + size1.length + ' dimensions)');
		    }
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            Dense Vector   (N)
		   * @param {Matrix} b            Dense Vector   (N)
		   *
		   * @return {number}             Scalar value
		   */
		  var _multiplyVectorVector = function (a, b, n) {
		    // check empty vector
		    if (n === 0) throw new Error('Cannot multiply two empty vectors');
	
		    // a dense
		    var adata = a._data;
		    var adt = a._datatype;
		    // b dense
		    var bdata = b._data;
		    var bdt = b._datatype;
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		    }
	
		    // result (do not initialize it with zero)
		    var c = mf(adata[0], bdata[0]);
		    // loop data
		    for (var i = 1; i < n; i++) {
		      // multiply and accumulate
		      c = af(c, mf(adata[i], bdata[i]));
		    }
		    return c;
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            Dense Vector   (M)
		   * @param {Matrix} b            Matrix         (MxN)
		   *
		   * @return {Matrix}             Dense Vector   (N)
		   */
		  var _multiplyVectorMatrix = function (a, b) {
		    // process storage
		    switch (b.storage()) {
		      case 'dense':
		        return _multiplyVectorDenseMatrix(a, b);
		    }
		    throw new Error('Not implemented');
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            Dense Vector   (M)
		   * @param {Matrix} b            Dense Matrix   (MxN)
		   *
		   * @return {Matrix}             Dense Vector   (N)
		   */
		  var _multiplyVectorDenseMatrix = function (a, b) {
		    // a dense
		    var adata = a._data;
		    var asize = a._size;
		    var adt = a._datatype;
		    // b dense
		    var bdata = b._data;
		    var bsize = b._size;
		    var bdt = b._datatype;
		    // rows & columns
		    var alength = asize[0];
		    var bcolumns = bsize[1];
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		    }
	
		    // result
		    var c = [];
	
		    // loop matrix columns
		    for (var j = 0; j < bcolumns; j++) {
		      // sum (do not initialize it with zero)
		      var sum = mf(adata[0], bdata[0][j]);
		      // loop vector
		      for (var i = 1; i < alength; i++) {
		        // multiply & accumulate
		        sum = af(sum, mf(adata[i], bdata[i][j]));
		      }
		      c[j] = sum;
		    }
	
		    // return matrix
		    return new DenseMatrix({
		      data: c,
		      size: [bcolumns],
		      datatype: dt
		    });
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            Matrix         (MxN)
		   * @param {Matrix} b            Dense Vector   (N)
		   *
		   * @return {Matrix}             Dense Vector   (M)
		   */
		  var _multiplyMatrixVector = function (a, b) {
		    // process storage
		    switch (a.storage()) {
		      case 'dense':
		        return _multiplyDenseMatrixVector(a, b);
		      case 'sparse':
		        return _multiplySparseMatrixVector(a, b);
		    }
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            Matrix         (MxN)
		   * @param {Matrix} b            Matrix         (NxC)
		   *
		   * @return {Matrix}             Matrix         (MxC)
		   */
		  var _multiplyMatrixMatrix = function (a, b) {
		    // process storage
		    switch (a.storage()) {
		      case 'dense':
		        // process storage
		        switch (b.storage()) {
		          case 'dense':
		            return _multiplyDenseMatrixDenseMatrix(a, b);
		          case 'sparse':
		            return _multiplyDenseMatrixSparseMatrix(a, b);
		        }
		        break;
		      case 'sparse':
		        // process storage
		        switch (b.storage()) {
		          case 'dense':
		            return _multiplySparseMatrixDenseMatrix(a, b);
		          case 'sparse':
		            return _multiplySparseMatrixSparseMatrix(a, b);
		        }
		        break;
		    }
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            DenseMatrix  (MxN)
		   * @param {Matrix} b            Dense Vector (N)
		   *
		   * @return {Matrix}             Dense Vector (M) 
		   */
		  var _multiplyDenseMatrixVector = function (a, b) {
		    // a dense
		    var adata = a._data;
		    var asize = a._size;
		    var adt = a._datatype;
		    // b dense
		    var bdata = b._data;
		    var bdt = b._datatype;
		    // rows & columns
		    var arows = asize[0];
		    var acolumns = asize[1];
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		    }
	
		    // result
		    var c = [];
	
		    // loop matrix a rows
		    for (var i = 0; i < arows; i++) {
		      // current row
		      var row = adata[i];
		      // sum (do not initialize it with zero)
		      var sum = mf(row[0], bdata[0]);
		      // loop matrix a columns
		      for (var j = 1; j < acolumns; j++) {
		        // multiply & accumulate
		        sum = af(sum, mf(row[j], bdata[j]));
		      }
		      c[i] = sum;
		    }
	
		    // return matrix
		    return new DenseMatrix({
		      data: c,
		      size: [arows],
		      datatype: dt
		    });
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            DenseMatrix    (MxN)
		   * @param {Matrix} b            DenseMatrix    (NxC)
		   *
		   * @return {Matrix}             DenseMatrix    (MxC)
		   */
		  var _multiplyDenseMatrixDenseMatrix = function (a, b) {
		    // a dense
		    var adata = a._data;
		    var asize = a._size;
		    var adt = a._datatype;
		    // b dense
		    var bdata = b._data;
		    var bsize = b._size;
		    var bdt = b._datatype;
		    // rows & columns
		    var arows = asize[0];
		    var acolumns = asize[1];
		    var bcolumns = bsize[1];
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		    }
	
		    // result
		    var c = [];
	
		    // loop matrix a rows
		    for (var i = 0; i < arows; i++) {
		      // current row
		      var row = adata[i];
		      // initialize row array
		      c[i] = [];
		      // loop matrix b columns
		      for (var j = 0; j < bcolumns; j++) {
		        // sum (avoid initializing sum to zero)
		        var sum = mf(row[0], bdata[0][j]);
		        // loop matrix a columns
		        for (var x = 1; x < acolumns; x++) {
		          // multiply & accumulate
		          sum = af(sum, mf(row[x], bdata[x][j]));
		        }
		        c[i][j] = sum;
		      }
		    }
	
		    // return matrix
		    return new DenseMatrix({
		      data: c,
		      size: [arows, bcolumns],
		      datatype: dt
		    });
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            DenseMatrix    (MxN)
		   * @param {Matrix} b            SparseMatrix   (NxC)
		   *
		   * @return {Matrix}             SparseMatrix   (MxC)
		   */
		  var _multiplyDenseMatrixSparseMatrix = function (a, b) {
		    // a dense
		    var adata = a._data;
		    var asize = a._size;
		    var adt = a._datatype;
		    // b sparse
		    var bvalues = b._values;
		    var bindex = b._index;
		    var bptr = b._ptr;
		    var bsize = b._size;
		    var bdt = b._datatype;
		    // validate b matrix
		    if (!bvalues) throw new Error('Cannot multiply Dense Matrix times Pattern only Matrix');
		    // rows & columns
		    var arows = asize[0];
		    var bcolumns = bsize[1];
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
		    // equalScalar signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		      eq = typed.find(equalScalar, [dt, dt]);
		      // convert 0 to the same datatype
		      zero = typed.convert(0, dt);
		    }
	
		    // result
		    var cvalues = [];
		    var cindex = [];
		    var cptr = [];
		    // c matrix
		    var c = new SparseMatrix({
		      values: cvalues,
		      index: cindex,
		      ptr: cptr,
		      size: [arows, bcolumns],
		      datatype: dt
		    });
	
		    // loop b columns
		    for (var jb = 0; jb < bcolumns; jb++) {
		      // update ptr
		      cptr[jb] = cindex.length;
		      // indeces in column jb
		      var kb0 = bptr[jb];
		      var kb1 = bptr[jb + 1];
		      // do not process column jb if no data exists
		      if (kb1 > kb0) {
		        // last row mark processed
		        var last = 0;
		        // loop a rows
		        for (var i = 0; i < arows; i++) {
		          // column mark
		          var mark = i + 1;
		          // C[i, jb]
		          var cij;
		          // values in b column j
		          for (var kb = kb0; kb < kb1; kb++) {
		            // row
		            var ib = bindex[kb];
		            // check value has been initialized
		            if (last !== mark) {
		              // first value in column jb
		              cij = mf(adata[i][ib], bvalues[kb]);
		              // update mark
		              last = mark;
		            } else {
		              // accumulate value
		              cij = af(cij, mf(adata[i][ib], bvalues[kb]));
		            }
		          }
		          // check column has been processed and value != 0
		          if (last === mark && !eq(cij, zero)) {
		            // push row & value
		            cindex.push(i);
		            cvalues.push(cij);
		          }
		        }
		      }
		    }
		    // update ptr
		    cptr[bcolumns] = cindex.length;
	
		    // return sparse matrix
		    return c;
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            SparseMatrix    (MxN)
		   * @param {Matrix} b            Dense Vector (N)
		   *
		   * @return {Matrix}             SparseMatrix    (M, 1) 
		   */
		  var _multiplySparseMatrixVector = function (a, b) {
		    // a sparse
		    var avalues = a._values;
		    var aindex = a._index;
		    var aptr = a._ptr;
		    var adt = a._datatype;
		    // validate a matrix
		    if (!avalues) throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix');
		    // b dense
		    var bdata = b._data;
		    var bdt = b._datatype;
		    // rows & columns
		    var arows = a._size[0];
		    var brows = b._size[0];
		    // result
		    var cvalues = [];
		    var cindex = [];
		    var cptr = [];
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
		    // equalScalar signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		      eq = typed.find(equalScalar, [dt, dt]);
		      // convert 0 to the same datatype
		      zero = typed.convert(0, dt);
		    }
	
		    // workspace
		    var x = [];
		    // vector with marks indicating a value x[i] exists in a given column
		    var w = [];
	
		    // update ptr
		    cptr[0] = 0;
		    // rows in b
		    for (var ib = 0; ib < brows; ib++) {
		      // b[ib]
		      var vbi = bdata[ib];
		      // check b[ib] != 0, avoid loops
		      if (!eq(vbi, zero)) {
		        // A values & index in ib column
		        for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) {
		          // a row
		          var ia = aindex[ka];
		          // check value exists in current j
		          if (!w[ia]) {
		            // ia is new entry in j
		            w[ia] = true;
		            // add i to pattern of C
		            cindex.push(ia);
		            // x(ia) = A
		            x[ia] = mf(vbi, avalues[ka]);
		          } else {
		            // i exists in C already
		            x[ia] = af(x[ia], mf(vbi, avalues[ka]));
		          }
		        }
		      }
		    }
		    // copy values from x to column jb of c
		    for (var p1 = cindex.length, p = 0; p < p1; p++) {
		      // row
		      var ic = cindex[p];
		      // copy value
		      cvalues[p] = x[ic];
		    }
		    // update ptr
		    cptr[1] = cindex.length;
	
		    // return sparse matrix
		    return new SparseMatrix({
		      values: cvalues,
		      index: cindex,
		      ptr: cptr,
		      size: [arows, 1],
		      datatype: dt
		    });
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            SparseMatrix      (MxN)
		   * @param {Matrix} b            DenseMatrix       (NxC)
		   *
		   * @return {Matrix}             SparseMatrix      (MxC)
		   */
		  var _multiplySparseMatrixDenseMatrix = function (a, b) {
		    // a sparse
		    var avalues = a._values;
		    var aindex = a._index;
		    var aptr = a._ptr;
		    var adt = a._datatype;
		    // validate a matrix
		    if (!avalues) throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix');
		    // b dense
		    var bdata = b._data;
		    var bdt = b._datatype;
		    // rows & columns
		    var arows = a._size[0];
		    var brows = b._size[0];
		    var bcolumns = b._size[1];
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
		    // equalScalar signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		      eq = typed.find(equalScalar, [dt, dt]);
		      // convert 0 to the same datatype
		      zero = typed.convert(0, dt);
		    }
	
		    // result
		    var cvalues = [];
		    var cindex = [];
		    var cptr = [];
		    // c matrix
		    var c = new SparseMatrix({
		      values: cvalues,
		      index: cindex,
		      ptr: cptr,
		      size: [arows, bcolumns],
		      datatype: dt
		    });
	
		    // workspace
		    var x = [];
		    // vector with marks indicating a value x[i] exists in a given column
		    var w = [];
	
		    // loop b columns
		    for (var jb = 0; jb < bcolumns; jb++) {
		      // update ptr
		      cptr[jb] = cindex.length;
		      // mark in workspace for current column
		      var mark = jb + 1;
		      // rows in jb
		      for (var ib = 0; ib < brows; ib++) {
		        // b[ib, jb]
		        var vbij = bdata[ib][jb];
		        // check b[ib, jb] != 0, avoid loops
		        if (!eq(vbij, zero)) {
		          // A values & index in ib column
		          for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) {
		            // a row
		            var ia = aindex[ka];
		            // check value exists in current j
		            if (w[ia] !== mark) {
		              // ia is new entry in j
		              w[ia] = mark;
		              // add i to pattern of C
		              cindex.push(ia);
		              // x(ia) = A
		              x[ia] = mf(vbij, avalues[ka]);
		            } else {
		              // i exists in C already
		              x[ia] = af(x[ia], mf(vbij, avalues[ka]));
		            }
		          }
		        }
		      }
		      // copy values from x to column jb of c
		      for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) {
		        // row
		        var ic = cindex[p];
		        // copy value
		        cvalues[p] = x[ic];
		      }
		    }
		    // update ptr
		    cptr[bcolumns] = cindex.length;
	
		    // return sparse matrix
		    return c;
		  };
	
		  /**
		   * C = A * B
		   *
		   * @param {Matrix} a            SparseMatrix      (MxN)
		   * @param {Matrix} b            SparseMatrix      (NxC)
		   *
		   * @return {Matrix}             SparseMatrix      (MxC)
		   */
		  var _multiplySparseMatrixSparseMatrix = function (a, b) {
		    // a sparse
		    var avalues = a._values;
		    var aindex = a._index;
		    var aptr = a._ptr;
		    var adt = a._datatype;
		    // b sparse
		    var bvalues = b._values;
		    var bindex = b._index;
		    var bptr = b._ptr;
		    var bdt = b._datatype;
	
		    // rows & columns
		    var arows = a._size[0];
		    var bcolumns = b._size[1];
		    // flag indicating both matrices (a & b) contain data
		    var values = avalues && bvalues;
	
		    // datatype
		    var dt;
		    // addScalar signature to use
		    var af = addScalar;
		    // multiplyScalar signature to use
		    var mf = multiplyScalar;
	
		    // process data types
		    if (adt && bdt && adt === bdt && typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signatures that matches (dt, dt)
		      af = typed.find(addScalar, [dt, dt]);
		      mf = typed.find(multiplyScalar, [dt, dt]);
		    }
	
		    // result
		    var cvalues = values ? [] : undefined;
		    var cindex = [];
		    var cptr = [];
		    // c matrix
		    var c = new SparseMatrix({
		      values: cvalues,
		      index: cindex,
		      ptr: cptr,
		      size: [arows, bcolumns],
		      datatype: dt
		    });
	
		    // workspace
		    var x = values ? [] : undefined;
		    // vector with marks indicating a value x[i] exists in a given column
		    var w = [];
		    // variables
		    var ka, ka0, ka1, kb, kb0, kb1, ia, ib;
		    // loop b columns
		    for (var jb = 0; jb < bcolumns; jb++) {
		      // update ptr
		      cptr[jb] = cindex.length;
		      // mark in workspace for current column
		      var mark = jb + 1;
		      // B values & index in j
		      for (kb0 = bptr[jb], kb1 = bptr[jb + 1], kb = kb0; kb < kb1; kb++) {
		        // b row
		        ib = bindex[kb];
		        // check we need to process values
		        if (values) {
		          // loop values in a[:,ib]
		          for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) {
		            // row
		            ia = aindex[ka];
		            // check value exists in current j
		            if (w[ia] !== mark) {
		              // ia is new entry in j
		              w[ia] = mark;
		              // add i to pattern of C
		              cindex.push(ia);
		              // x(ia) = A
		              x[ia] = mf(bvalues[kb], avalues[ka]);
		            } else {
		              // i exists in C already
		              x[ia] = af(x[ia], mf(bvalues[kb], avalues[ka]));
		            }
		          }
		        } else {
		          // loop values in a[:,ib]
		          for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) {
		            // row
		            ia = aindex[ka];
		            // check value exists in current j
		            if (w[ia] !== mark) {
		              // ia is new entry in j
		              w[ia] = mark;
		              // add i to pattern of C
		              cindex.push(ia);
		            }
		          }
		        }
		      }
		      // check we need to process matrix values (pattern matrix)
		      if (values) {
		        // copy values from x to column jb of c
		        for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) {
		          // row
		          var ic = cindex[p];
		          // copy value
		          cvalues[p] = x[ic];
		        }
		      }
		    }
		    // update ptr
		    cptr[bcolumns] = cindex.length;
	
		    // return sparse matrix
		    return c;
		  };
	
		  multiply.toTex = {
		    2: '\\left(${args[0]}' + latex.operators['multiply'] + '${args[1]}\\right)'
		  };
	
		  return multiply;
		}
	
		exports.name = 'multiply';
		exports.factory = factory;
	
	/***/ }),
	/* 211 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var number = __webpack_require__(200);
		var string = __webpack_require__(212);
		var object = __webpack_require__(196);
		var types = __webpack_require__(214);
	
		var DimensionError = __webpack_require__(215);
		var IndexError = __webpack_require__(216);
	
		/**
		 * Calculate the size of a multi dimensional array.
		 * This function checks the size of the first entry, it does not validate
		 * whether all dimensions match. (use function `validate` for that)
		 * @param {Array} x
		 * @Return {Number[]} size
		 */
		exports.size = function (x) {
		  var s = [];
	
		  while (Array.isArray(x)) {
		    s.push(x.length);
		    x = x[0];
		  }
	
		  return s;
		};
	
		/**
		 * Recursively validate whether each element in a multi dimensional array
		 * has a size corresponding to the provided size array.
		 * @param {Array} array    Array to be validated
		 * @param {number[]} size  Array with the size of each dimension
		 * @param {number} dim   Current dimension
		 * @throws DimensionError
		 * @private
		 */
		function _validate(array, size, dim) {
		  var i;
		  var len = array.length;
	
		  if (len != size[dim]) {
		    throw new DimensionError(len, size[dim]);
		  }
	
		  if (dim < size.length - 1) {
		    // recursively validate each child array
		    var dimNext = dim + 1;
		    for (i = 0; i < len; i++) {
		      var child = array[i];
		      if (!Array.isArray(child)) {
		        throw new DimensionError(size.length - 1, size.length, '<');
		      }
		      _validate(array[i], size, dimNext);
		    }
		  } else {
		    // last dimension. none of the childs may be an array
		    for (i = 0; i < len; i++) {
		      if (Array.isArray(array[i])) {
		        throw new DimensionError(size.length + 1, size.length, '>');
		      }
		    }
		  }
		}
	
		/**
		 * Validate whether each element in a multi dimensional array has
		 * a size corresponding to the provided size array.
		 * @param {Array} array    Array to be validated
		 * @param {number[]} size  Array with the size of each dimension
		 * @throws DimensionError
		 */
		exports.validate = function (array, size) {
		  var isScalar = size.length == 0;
		  if (isScalar) {
		    // scalar
		    if (Array.isArray(array)) {
		      throw new DimensionError(array.length, 0);
		    }
		  } else {
		    // array
		    _validate(array, size, 0);
		  }
		};
	
		/**
		 * Test whether index is an integer number with index >= 0 and index < length
		 * when length is provided
		 * @param {number} index    Zero-based index
		 * @param {number} [length] Length of the array
		 */
		exports.validateIndex = function (index, length) {
		  if (!number.isNumber(index) || !number.isInteger(index)) {
		    throw new TypeError('Index must be an integer (value: ' + index + ')');
		  }
		  if (index < 0 || typeof length === 'number' && index >= length) {
		    throw new IndexError(index, length);
		  }
		};
	
		// a constant used to specify an undefined defaultValue
		exports.UNINITIALIZED = {};
	
		/**
		 * Resize a multi dimensional array. The resized array is returned.
		 * @param {Array} array         Array to be resized
		 * @param {Array.<number>} size Array with the size of each dimension
		 * @param {*} [defaultValue=0]  Value to be filled in in new entries,
		 *                              zero by default. To leave new entries undefined,
		 *                              specify array.UNINITIALIZED as defaultValue
		 * @return {Array} array         The resized array
		 */
		exports.resize = function (array, size, defaultValue) {
		  // TODO: add support for scalars, having size=[] ?
	
		  // check the type of the arguments
		  if (!Array.isArray(array) || !Array.isArray(size)) {
		    throw new TypeError('Array expected');
		  }
		  if (size.length === 0) {
		    throw new Error('Resizing to scalar is not supported');
		  }
	
		  // check whether size contains positive integers
		  size.forEach(function (value) {
		    if (!number.isNumber(value) || !number.isInteger(value) || value < 0) {
		      throw new TypeError('Invalid size, must contain positive integers ' + '(size: ' + string.format(size) + ')');
		    }
		  });
	
		  // recursively resize the array
		  var _defaultValue = defaultValue !== undefined ? defaultValue : 0;
		  _resize(array, size, 0, _defaultValue);
	
		  return array;
		};
	
		/**
		 * Recursively resize a multi dimensional array
		 * @param {Array} array         Array to be resized
		 * @param {number[]} size       Array with the size of each dimension
		 * @param {number} dim          Current dimension
		 * @param {*} [defaultValue]    Value to be filled in in new entries,
		 *                              undefined by default.
		 * @private
		 */
		function _resize(array, size, dim, defaultValue) {
		  var i;
		  var elem;
		  var oldLen = array.length;
		  var newLen = size[dim];
		  var minLen = Math.min(oldLen, newLen);
	
		  // apply new length
		  array.length = newLen;
	
		  if (dim < size.length - 1) {
		    // non-last dimension
		    var dimNext = dim + 1;
	
		    // resize existing child arrays
		    for (i = 0; i < minLen; i++) {
		      // resize child array
		      elem = array[i];
		      if (!Array.isArray(elem)) {
		        elem = [elem]; // add a dimension
		        array[i] = elem;
		      }
		      _resize(elem, size, dimNext, defaultValue);
		    }
	
		    // create new child arrays
		    for (i = minLen; i < newLen; i++) {
		      // get child array
		      elem = [];
		      array[i] = elem;
	
		      // resize new child array
		      _resize(elem, size, dimNext, defaultValue);
		    }
		  } else {
		    // last dimension
	
		    // remove dimensions of existing values
		    for (i = 0; i < minLen; i++) {
		      while (Array.isArray(array[i])) {
		        array[i] = array[i][0];
		      }
		    }
	
		    if (defaultValue !== exports.UNINITIALIZED) {
		      // fill new elements with the default value
		      for (i = minLen; i < newLen; i++) {
		        array[i] = defaultValue;
		      }
		    }
		  }
		}
	
		/**
		 * Re-shape a multi dimensional array to fit the specified dimensions
		 * @param {Array} array           Array to be reshaped
		 * @param {Array.<number>} sizes  List of sizes for each dimension
		 * @returns {Array}               Array whose data has been formatted to fit the
		 *                                specified dimensions
		 *
		 * @throws {DimensionError}       If the product of the new dimension sizes does
		 *                                not equal that of the old ones
		 */
		exports.reshape = function (array, sizes) {
		  var flatArray = exports.flatten(array);
		  var newArray;
	
		  var product = function (arr) {
		    return arr.reduce(function (prev, curr) {
		      return prev * curr;
		    });
		  };
	
		  if (!Array.isArray(array) || !Array.isArray(sizes)) {
		    throw new TypeError('Array expected');
		  }
	
		  if (sizes.length === 0) {
		    throw new DimensionError(0, product(exports.size(array)), '!=');
		  }
	
		  try {
		    newArray = _reshape(flatArray, sizes);
		  } catch (e) {
		    if (e instanceof DimensionError) {
		      throw new DimensionError(product(sizes), product(exports.size(array)), '!=');
		    }
		    throw e;
		  }
	
		  if (flatArray.length > 0) {
		    throw new DimensionError(product(sizes), product(exports.size(array)), '!=');
		  }
	
		  return newArray;
		};
	
		/**
		 * Recursively re-shape a multi dimensional array to fit the specified dimensions
		 * @param {Array} array           Array to be reshaped
		 * @param {Array.<number>} sizes  List of sizes for each dimension
		 * @returns {Array}               Array whose data has been formatted to fit the
		 *                                specified dimensions
		 *
		 * @throws {DimensionError}       If the product of the new dimension sizes does
		 *                                not equal that of the old ones
		 */
		function _reshape(array, sizes) {
		  var accumulator = [];
		  var i;
	
		  if (sizes.length === 0) {
		    if (array.length === 0) {
		      throw new DimensionError(null, null, '!=');
		    }
		    return array.shift();
		  }
		  for (i = 0; i < sizes[0]; i += 1) {
		    accumulator.push(_reshape(array, sizes.slice(1)));
		  }
		  return accumulator;
		}
	
		/**
		 * Squeeze a multi dimensional array
		 * @param {Array} array
		 * @param {Array} [size]
		 * @returns {Array} returns the array itself
		 */
		exports.squeeze = function (array, size) {
		  var s = size || exports.size(array);
	
		  // squeeze outer dimensions
		  while (Array.isArray(array) && array.length === 1) {
		    array = array[0];
		    s.shift();
		  }
	
		  // find the first dimension to be squeezed
		  var dims = s.length;
		  while (s[dims - 1] === 1) {
		    dims--;
		  }
	
		  // squeeze inner dimensions
		  if (dims < s.length) {
		    array = _squeeze(array, dims, 0);
		    s.length = dims;
		  }
	
		  return array;
		};
	
		/**
		 * Recursively squeeze a multi dimensional array
		 * @param {Array} array
		 * @param {number} dims Required number of dimensions
		 * @param {number} dim  Current dimension
		 * @returns {Array | *} Returns the squeezed array
		 * @private
		 */
		function _squeeze(array, dims, dim) {
		  var i, ii;
	
		  if (dim < dims) {
		    var next = dim + 1;
		    for (i = 0, ii = array.length; i < ii; i++) {
		      array[i] = _squeeze(array[i], dims, next);
		    }
		  } else {
		    while (Array.isArray(array)) {
		      array = array[0];
		    }
		  }
	
		  return array;
		}
	
		/**
		 * Unsqueeze a multi dimensional array: add dimensions when missing
		 * 
		 * Paramter `size` will be mutated to match the new, unqueezed matrix size.
		 * 
		 * @param {Array} array
		 * @param {number} dims     Desired number of dimensions of the array
		 * @param {number} [outer]  Number of outer dimensions to be added
		 * @param {Array} [size]    Current size of array.
		 * @returns {Array} returns the array itself
		 * @private
		 */
		exports.unsqueeze = function (array, dims, outer, size) {
		  var s = size || exports.size(array);
	
		  // unsqueeze outer dimensions
		  if (outer) {
		    for (var i = 0; i < outer; i++) {
		      array = [array];
		      s.unshift(1);
		    }
		  }
	
		  // unsqueeze inner dimensions
		  array = _unsqueeze(array, dims, 0);
		  while (s.length < dims) {
		    s.push(1);
		  }
	
		  return array;
		};
	
		/**
		 * Recursively unsqueeze a multi dimensional array
		 * @param {Array} array
		 * @param {number} dims Required number of dimensions
		 * @param {number} dim  Current dimension
		 * @returns {Array | *} Returns the squeezed array
		 * @private
		 */
		function _unsqueeze(array, dims, dim) {
		  var i, ii;
	
		  if (Array.isArray(array)) {
		    var next = dim + 1;
		    for (i = 0, ii = array.length; i < ii; i++) {
		      array[i] = _unsqueeze(array[i], dims, next);
		    }
		  } else {
		    for (var d = dim; d < dims; d++) {
		      array = [array];
		    }
		  }
	
		  return array;
		}
		/**
		 * Flatten a multi dimensional array, put all elements in a one dimensional
		 * array
		 * @param {Array} array   A multi dimensional array
		 * @return {Array}        The flattened array (1 dimensional)
		 */
		exports.flatten = function (array) {
		  if (!Array.isArray(array)) {
		    //if not an array, return as is
		    return array;
		  }
		  var flat = [];
	
		  array.forEach(function callback(value) {
		    if (Array.isArray(value)) {
		      value.forEach(callback); //traverse through sub-arrays recursively
		    } else {
		      flat.push(value);
		    }
		  });
	
		  return flat;
		};
	
		/**
		 * A safe map
		 * @param {Array} array
		 * @param {function} callback
		 */
		exports.map = function (array, callback) {
		  return Array.prototype.map.call(array, callback);
		};
	
		/**
		 * A safe forEach
		 * @param {Array} array
		 * @param {function} callback
		 */
		exports.forEach = function (array, callback) {
		  Array.prototype.forEach.call(array, callback);
		};
	
		/**
		 * A safe filter
		 * @param {Array} array
		 * @param {function} callback
		 */
		exports.filter = function (array, callback) {
		  if (exports.size(array).length !== 1) {
		    throw new Error('Only one dimensional matrices supported');
		  }
	
		  return Array.prototype.filter.call(array, callback);
		};
	
		/**
		 * Filter values in a callback given a regular expression
		 * @param {Array} array
		 * @param {RegExp} regexp
		 * @return {Array} Returns the filtered array
		 * @private
		 */
		exports.filterRegExp = function (array, regexp) {
		  if (exports.size(array).length !== 1) {
		    throw new Error('Only one dimensional matrices supported');
		  }
	
		  return Array.prototype.filter.call(array, function (entry) {
		    return regexp.test(entry);
		  });
		};
	
		/**
		 * A safe join
		 * @param {Array} array
		 * @param {string} separator
		 */
		exports.join = function (array, separator) {
		  return Array.prototype.join.call(array, separator);
		};
	
		/**
		 * Assign a numeric identifier to every element of a sorted array
		 * @param {Array}	a  An array
		 * @return {Array}	An array of objects containing the original value and its identifier
		 */
		exports.identify = function (a) {
		  if (!Array.isArray(a)) {
		    throw new TypeError('Array input expected');
		  }
	
		  if (a.length === 0) {
		    return a;
		  }
	
		  var b = [];
		  var count = 0;
		  b[0] = { value: a[0], identifier: 0 };
		  for (var i = 1; i < a.length; i++) {
		    if (a[i] === a[i - 1]) {
		      count++;
		    } else {
		      count = 0;
		    }
		    b.push({ value: a[i], identifier: count });
		  }
		  return b;
		};
	
		/**
		 * Remove the numeric identifier from the elements
		 * @param	a  An array
		 * @return	An array of values without identifiers
		 */
		exports.generalize = function (a) {
		  if (!Array.isArray(a)) {
		    throw new TypeError('Array input expected');
		  }
	
		  if (a.length === 0) {
		    return a;
		  }
	
		  var b = [];
		  for (var i = 0; i < a.length; i++) {
		    b.push(a[i].value);
		  }
		  return b;
		};
	
		/**
		 * Test whether an object is an array
		 * @param {*} value
		 * @return {boolean} isArray
		 */
			exports.isArray = Array.isArray;
	
	/***/ }),
	/* 212 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var formatNumber = __webpack_require__(200).format;
		var formatBigNumber = __webpack_require__(213).format;
		var isBigNumber = __webpack_require__(197);
	
		/**
		 * Test whether value is a string
		 * @param {*} value
		 * @return {boolean} isString
		 */
		exports.isString = function (value) {
		  return typeof value === 'string';
		};
	
		/**
		 * Check if a text ends with a certain string.
		 * @param {string} text
		 * @param {string} search
		 */
		exports.endsWith = function (text, search) {
		  var start = text.length - search.length;
		  var end = text.length;
		  return text.substring(start, end) === search;
		};
	
		/**
		 * Format a value of any type into a string.
		 *
		 * Usage:
		 *     math.format(value)
		 *     math.format(value, precision)
		 *
		 * When value is a function:
		 *
		 * - When the function has a property `syntax`, it returns this
		 *   syntax description.
		 * - In other cases, a string `'function'` is returned.
		 *
		 * When `value` is an Object:
		 *
		 * - When the object contains a property `format` being a function, this
		 *   function is invoked as `value.format(options)` and the result is returned.
		 * - When the object has its own `toString` method, this method is invoked
		 *   and the result is returned.
		 * - In other cases the function will loop over all object properties and
		 *   return JSON object notation like '{"a": 2, "b": 3}'.
		 *
		 * Example usage:
		 *     math.format(2/7);                // '0.2857142857142857'
		 *     math.format(math.pi, 3);         // '3.14'
		 *     math.format(new Complex(2, 3));  // '2 + 3i'
		 *     math.format('hello');            // '"hello"'
		 *
		 * @param {*} value             Value to be stringified
		 * @param {Object | number | Function} [options]  Formatting options. See
		 *                                                lib/utils/number:format for a
		 *                                                description of the available
		 *                                                options.
		 * @return {string} str
		 */
		exports.format = function (value, options) {
		  if (typeof value === 'number') {
		    return formatNumber(value, options);
		  }
	
		  if (isBigNumber(value)) {
		    return formatBigNumber(value, options);
		  }
	
		  // note: we use unsafe duck-typing here to check for Fractions, this is
		  // ok here since we're only invoking toString or concatenating its values
		  if (looksLikeFraction(value)) {
		    if (!options || options.fraction !== 'decimal') {
		      // output as ratio, like '1/3'
		      return value.s * value.n + '/' + value.d;
		    } else {
		      // output as decimal, like '0.(3)'
		      return value.toString();
		    }
		  }
	
		  if (Array.isArray(value)) {
		    return formatArray(value, options);
		  }
	
		  if (exports.isString(value)) {
		    return '"' + value + '"';
		  }
	
		  if (typeof value === 'function') {
		    return value.syntax ? String(value.syntax) : 'function';
		  }
	
		  if (value && typeof value === 'object') {
		    if (typeof value.format === 'function') {
		      return value.format(options);
		    } else if (value && value.toString() !== {}.toString()) {
		      // this object has a non-native toString method, use that one
		      return value.toString();
		    } else {
		      var entries = [];
	
		      for (var key in value) {
		        if (value.hasOwnProperty(key)) {
		          entries.push('"' + key + '": ' + exports.format(value[key], options));
		        }
		      }
	
		      return '{' + entries.join(', ') + '}';
		    }
		  }
	
		  return String(value);
		};
	
		/**
		 * Stringify a value into a string enclosed in double quotes.
		 * Unescaped double quotes and backslashes inside the value are escaped.
		 * @param {*} value
		 * @return {string}
		 */
		exports.stringify = function (value) {
		  var text = String(value);
		  var escaped = '';
		  var i = 0;
		  while (i < text.length) {
		    var c = text.charAt(i);
	
		    if (c === '\\') {
		      escaped += c;
		      i++;
	
		      c = text.charAt(i);
		      if (c === '' || '"\\/bfnrtu'.indexOf(c) === -1) {
		        escaped += '\\'; // no valid escape character -> escape it
		      }
		      escaped += c;
		    } else if (c === '"') {
		      escaped += '\\"';
		    } else {
		      escaped += c;
		    }
		    i++;
		  }
	
		  return '"' + escaped + '"';
		};
	
		/**
		 * Escape special HTML characters
		 * @param {*} value
		 * @return {string}
		 */
		exports.escape = function (value) {
		  var text = String(value);
		  text = text.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
	
		  return text;
		};
	
		/**
		 * Recursively format an n-dimensional matrix
		 * Example output: "[[1, 2], [3, 4]]"
		 * @param {Array} array
		 * @param {Object | number | Function} [options]  Formatting options. See
		 *                                                lib/utils/number:format for a
		 *                                                description of the available
		 *                                                options.
		 * @returns {string} str
		 */
		function formatArray(array, options) {
		  if (Array.isArray(array)) {
		    var str = '[';
		    var len = array.length;
		    for (var i = 0; i < len; i++) {
		      if (i != 0) {
		        str += ', ';
		      }
		      str += formatArray(array[i], options);
		    }
		    str += ']';
		    return str;
		  } else {
		    return exports.format(array, options);
		  }
		}
	
		/**
		 * Check whether a value looks like a Fraction (unsafe duck-type check)
		 * @param {*} value
		 * @return {boolean}
		 */
		function looksLikeFraction(value) {
		  return value && typeof value === 'object' && typeof value.s === 'number' && typeof value.n === 'number' && typeof value.d === 'number' || false;
			}
	
	/***/ }),
	/* 213 */
	/***/ (function(module, exports) {
	
		/**
		 * Convert a BigNumber to a formatted string representation.
		 *
		 * Syntax:
		 *
		 *    format(value)
		 *    format(value, options)
		 *    format(value, precision)
		 *    format(value, fn)
		 *
		 * Where:
		 *
		 *    {number} value   The value to be formatted
		 *    {Object} options An object with formatting options. Available options:
		 *                     {string} notation
		 *                         Number notation. Choose from:
		 *                         'fixed'          Always use regular number notation.
		 *                                          For example '123.40' and '14000000'
		 *                         'exponential'    Always use exponential notation.
		 *                                          For example '1.234e+2' and '1.4e+7'
		 *                         'auto' (default) Regular number notation for numbers
		 *                                          having an absolute value between
		 *                                          `lower` and `upper` bounds, and uses
		 *                                          exponential notation elsewhere.
		 *                                          Lower bound is included, upper bound
		 *                                          is excluded.
		 *                                          For example '123.4' and '1.4e7'.
		 *                     {number} precision   A number between 0 and 16 to round
		 *                                          the digits of the number.
		 *                                          In case of notations 'exponential' and
		 *                                          'auto', `precision` defines the total
		 *                                          number of significant digits returned
		 *                                          and is undefined by default.
		 *                                          In case of notation 'fixed',
		 *                                          `precision` defines the number of
		 *                                          significant digits after the decimal
		 *                                          point, and is 0 by default.
		 *                     {Object} exponential An object containing two parameters,
		 *                                          {number} lower and {number} upper,
		 *                                          used by notation 'auto' to determine
		 *                                          when to return exponential notation.
		 *                                          Default values are `lower=1e-3` and
		 *                                          `upper=1e5`.
		 *                                          Only applicable for notation `auto`.
		 *    {Function} fn    A custom formatting function. Can be used to override the
		 *                     built-in notations. Function `fn` is called with `value` as
		 *                     parameter and must return a string. Is useful for example to
		 *                     format all values inside a matrix in a particular way.
		 *
		 * Examples:
		 *
		 *    format(6.4);                                        // '6.4'
		 *    format(1240000);                                    // '1.24e6'
		 *    format(1/3);                                        // '0.3333333333333333'
		 *    format(1/3, 3);                                     // '0.333'
		 *    format(21385, 2);                                   // '21000'
		 *    format(12.071, {notation: 'fixed'});                // '12'
		 *    format(2.3,    {notation: 'fixed', precision: 2});  // '2.30'
		 *    format(52.8,   {notation: 'exponential'});          // '5.28e+1'
		 *
		 * @param {BigNumber} value
		 * @param {Object | Function | number} [options]
		 * @return {string} str The formatted value
		 */
		exports.format = function (value, options) {
		  if (typeof options === 'function') {
		    // handle format(value, fn)
		    return options(value);
		  }
	
		  // handle special cases
		  if (!value.isFinite()) {
		    return value.isNaN() ? 'NaN' : value.gt(0) ? 'Infinity' : '-Infinity';
		  }
	
		  // default values for options
		  var notation = 'auto';
		  var precision = undefined;
	
		  if (options !== undefined) {
		    // determine notation from options
		    if (options.notation) {
		      notation = options.notation;
		    }
	
		    // determine precision from options
		    if (typeof options === 'number') {
		      precision = options;
		    } else if (options.precision) {
		      precision = options.precision;
		    }
		  }
	
		  // handle the various notations
		  switch (notation) {
		    case 'fixed':
		      return exports.toFixed(value, precision);
	
		    case 'exponential':
		      return exports.toExponential(value, precision);
	
		    case 'auto':
		      // determine lower and upper bound for exponential notation.
		      // TODO: implement support for upper and lower to be BigNumbers themselves
		      var lower = 1e-3;
		      var upper = 1e5;
		      if (options && options.exponential) {
		        if (options.exponential.lower !== undefined) {
		          lower = options.exponential.lower;
		        }
		        if (options.exponential.upper !== undefined) {
		          upper = options.exponential.upper;
		        }
		      }
	
		      // adjust the configuration of the BigNumber constructor (yeah, this is quite tricky...)
		      var oldConfig = {
		        toExpNeg: value.constructor.toExpNeg,
		        toExpPos: value.constructor.toExpPos
		      };
	
		      value.constructor.config({
		        toExpNeg: Math.round(Math.log(lower) / Math.LN10),
		        toExpPos: Math.round(Math.log(upper) / Math.LN10)
		      });
	
		      // handle special case zero
		      if (value.isZero()) return '0';
	
		      // determine whether or not to output exponential notation
		      var str;
		      var abs = value.abs();
		      if (abs.gte(lower) && abs.lt(upper)) {
		        // normal number notation
		        str = value.toSignificantDigits(precision).toFixed();
		      } else {
		        // exponential notation
		        str = exports.toExponential(value, precision);
		      }
	
		      // remove trailing zeros after the decimal point
		      return str.replace(/((\.\d*?)(0+))($|e)/, function () {
		        var digits = arguments[2];
		        var e = arguments[4];
		        return digits !== '.' ? digits + e : e;
		      });
	
		    default:
		      throw new Error('Unknown notation "' + notation + '". ' + 'Choose "auto", "exponential", or "fixed".');
		  }
		};
	
		/**
		 * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3'
		 * @param {BigNumber} value
		 * @param {number} [precision]  Number of digits in formatted output.
		 *                              If not provided, the maximum available digits
		 *                              is used.
		 * @returns {string} str
		 */
		exports.toExponential = function (value, precision) {
		  if (precision !== undefined) {
		    return value.toExponential(precision - 1); // Note the offset of one
		  } else {
		    return value.toExponential();
		  }
		};
	
		/**
		 * Format a number with fixed notation.
		 * @param {BigNumber} value
		 * @param {number} [precision=0]        Optional number of decimals after the
		 *                                      decimal point. Zero by default.
		 */
		exports.toFixed = function (value, precision) {
		  return value.toFixed(precision || 0);
		  // Note: the (precision || 0) is needed as the toFixed of BigNumber has an
		  // undefined default precision instead of 0.
		};
	
	/***/ }),
	/* 214 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Determine the type of a variable
		 *
		 *     type(x)
		 *
		 * The following types are recognized:
		 *
		 *     'undefined'
		 *     'null'
		 *     'boolean'
		 *     'number'
		 *     'string'
		 *     'Array'
		 *     'Function'
		 *     'Date'
		 *     'RegExp'
		 *     'Object'
		 *
		 * @param {*} x
		 * @return {string} Returns the name of the type. Primitive types are lower case,
		 *                  non-primitive types are upper-camel-case.
		 *                  For example 'number', 'string', 'Array', 'Date'.
		 */
	
		exports.type = function (x) {
		  var type = typeof x;
	
		  if (type === 'object') {
		    if (x === null) return 'null';
		    if (Array.isArray(x)) return 'Array';
		    if (x instanceof Date) return 'Date';
		    if (x instanceof RegExp) return 'RegExp';
		    if (x instanceof Boolean) return 'boolean';
		    if (x instanceof Number) return 'number';
		    if (x instanceof String) return 'string';
	
		    return 'Object';
		  }
	
		  if (type === 'function') return 'Function';
	
		  return type;
		};
	
	/***/ }),
	/* 215 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Create a range error with the message:
		 *     'Dimension mismatch (<actual size> != <expected size>)'
		 * @param {number | number[]} actual        The actual size
		 * @param {number | number[]} expected      The expected size
		 * @param {string} [relation='!=']          Optional relation between actual
		 *                                          and expected size: '!=', '<', etc.
		 * @extends RangeError
		 */
	
		function DimensionError(actual, expected, relation) {
		  if (!(this instanceof DimensionError)) {
		    throw new SyntaxError('Constructor must be called with the new operator');
		  }
	
		  this.actual = actual;
		  this.expected = expected;
		  this.relation = relation;
	
		  this.message = 'Dimension mismatch (' + (Array.isArray(actual) ? '[' + actual.join(', ') + ']' : actual) + ' ' + (this.relation || '!=') + ' ' + (Array.isArray(expected) ? '[' + expected.join(', ') + ']' : expected) + ')';
	
		  this.stack = new Error().stack;
		}
	
		DimensionError.prototype = new RangeError();
		DimensionError.prototype.constructor = RangeError;
		DimensionError.prototype.name = 'DimensionError';
		DimensionError.prototype.isDimensionError = true;
	
		module.exports = DimensionError;
	
	/***/ }),
	/* 216 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Create a range error with the message:
		 *     'Index out of range (index < min)'
		 *     'Index out of range (index < max)'
		 *
		 * @param {number} index     The actual index
		 * @param {number} [min=0]   Minimum index (included)
		 * @param {number} [max]     Maximum index (excluded)
		 * @extends RangeError
		 */
	
		function IndexError(index, min, max) {
		  if (!(this instanceof IndexError)) {
		    throw new SyntaxError('Constructor must be called with the new operator');
		  }
	
		  this.index = index;
		  if (arguments.length < 3) {
		    this.min = 0;
		    this.max = min;
		  } else {
		    this.min = min;
		    this.max = max;
		  }
	
		  if (this.min !== undefined && this.index < this.min) {
		    this.message = 'Index out of range (' + this.index + ' < ' + this.min + ')';
		  } else if (this.max !== undefined && this.index >= this.max) {
		    this.message = 'Index out of range (' + this.index + ' > ' + (this.max - 1) + ')';
		  } else {
		    this.message = 'Index out of range (' + this.index + ')';
		  }
	
		  this.stack = new Error().stack;
		}
	
		IndexError.prototype = new RangeError();
		IndexError.prototype.constructor = RangeError;
		IndexError.prototype.name = 'IndexError';
		IndexError.prototype.isIndexError = true;
	
		module.exports = IndexError;
	
	/***/ }),
	/* 217 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		exports.symbols = {
		  // GREEK LETTERS
		  Alpha: 'A', alpha: '\\alpha',
		  Beta: 'B', beta: '\\beta',
		  Gamma: '\\Gamma', gamma: '\\gamma',
		  Delta: '\\Delta', delta: '\\delta',
		  Epsilon: 'E', epsilon: '\\epsilon', varepsilon: '\\varepsilon',
		  Zeta: 'Z', zeta: '\\zeta',
		  Eta: 'H', eta: '\\eta',
		  Theta: '\\Theta', theta: '\\theta', vartheta: '\\vartheta',
		  Iota: 'I', iota: '\\iota',
		  Kappa: 'K', kappa: '\\kappa', varkappa: '\\varkappa',
		  Lambda: '\\Lambda', lambda: '\\lambda',
		  Mu: 'M', mu: '\\mu',
		  Nu: 'N', nu: '\\nu',
		  Xi: '\\Xi', xi: '\\xi',
		  Omicron: 'O', omicron: 'o',
		  Pi: '\\Pi', pi: '\\pi', varpi: '\\varpi',
		  Rho: 'P', rho: '\\rho', varrho: '\\varrho',
		  Sigma: '\\Sigma', sigma: '\\sigma', varsigma: '\\varsigma',
		  Tau: 'T', tau: '\\tau',
		  Upsilon: '\\Upsilon', upsilon: '\\upsilon',
		  Phi: '\\Phi', phi: '\\phi', varphi: '\\varphi',
		  Chi: 'X', chi: '\\chi',
		  Psi: '\\Psi', psi: '\\psi',
		  Omega: '\\Omega', omega: '\\omega',
		  //logic
		  'true': '\\mathrm{True}',
		  'false': '\\mathrm{False}',
		  //other
		  i: 'i', //TODO use \i ??
		  inf: '\\infty',
		  Inf: '\\infty',
		  infinity: '\\infty',
		  Infinity: '\\infty',
		  oo: '\\infty',
		  lim: '\\lim',
		  'undefined': '\\mathbf{?}'
		};
	
		exports.operators = {
		  'transpose': '^\\top',
		  'factorial': '!',
		  'pow': '^',
		  'dotPow': '.^\\wedge', //TODO find ideal solution
		  'unaryPlus': '+',
		  'unaryMinus': '-',
		  'bitNot': '~', //TODO find ideal solution
		  'not': '\\neg',
		  'multiply': '\\cdot',
		  'divide': '\\frac', //TODO how to handle that properly?
		  'dotMultiply': '.\\cdot', //TODO find ideal solution
		  'dotDivide': '.:', //TODO find ideal solution
		  'mod': '\\mod',
		  'add': '+',
		  'subtract': '-',
		  'to': '\\rightarrow',
		  'leftShift': '<<',
		  'rightArithShift': '>>',
		  'rightLogShift': '>>>',
		  'equal': '=',
		  'unequal': '\\neq',
		  'smaller': '<',
		  'larger': '>',
		  'smallerEq': '\\leq',
		  'largerEq': '\\geq',
		  'bitAnd': '\\&',
		  'bitXor': '\\underline{|}',
		  'bitOr': '|',
		  'and': '\\wedge',
		  'xor': '\\veebar',
		  'or': '\\vee'
		};
	
		exports.defaultTemplate = '\\mathrm{${name}}\\left(${args}\\right)';
	
		var units = {
		  deg: '^\\circ'
		};
	
		//@param {string} name
		//@param {boolean} isUnit
		exports.toSymbol = function (name, isUnit) {
		  isUnit = typeof isUnit === 'undefined' ? false : isUnit;
		  if (isUnit) {
		    if (units.hasOwnProperty(name)) {
		      return units[name];
		    }
		    return '\\mathrm{' + name + '}';
		  }
	
		  if (exports.symbols.hasOwnProperty(name)) {
		    return exports.symbols[name];
		  } else if (name.indexOf('_') !== -1) {
		    //symbol with index (eg. alpha_1)
		    var index = name.indexOf('_');
		    return exports.toSymbol(name.substring(0, index)) + '_{' + exports.toSymbol(name.substring(index + 1)) + '}';
		  }
		  return name;
		};
	
	/***/ }),
	/* 218 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
		  /**
		   * Create a Matrix. The function creates a new `math.type.Matrix` object from
		   * an `Array`. A Matrix has utility functions to manipulate the data in the
		   * matrix, like getting the size and getting or setting values in the matrix.
		   * Supported storage formats are 'dense' and 'sparse'.
		   *
		   * Syntax:
		   *
		   *    math.matrix()                         // creates an empty matrix using default storage format (dense).
		   *    math.matrix(data)                     // creates a matrix with initial data using default storage format (dense).
		   *    math.matrix('dense')                  // creates an empty matrix using the given storage format.
		   *    math.matrix(data, 'dense')            // creates a matrix with initial data using the given storage format.
		   *    math.matrix(data, 'sparse')           // creates a sparse matrix with initial data.
		   *    math.matrix(data, 'sparse', 'number') // creates a sparse matrix with initial data, number data type.
		   *
		   * Examples:
		   *
		   *    var m = math.matrix([[1, 2], [3, 4]]);
		   *    m.size();                        // Array [2, 2]
		   *    m.resize([3, 2], 5);
		   *    m.valueOf();                     // Array [[1, 2], [3, 4], [5, 5]]
		   *    m.get([1, 0])                    // number 3
		   *
		   * See also:
		   *
		   *    bignumber, boolean, complex, index, number, string, unit, sparse
		   *
		   * @param {Array | Matrix} [data]    A multi dimensional array
		   * @param {string} [format]          The Matrix storage format
		   *
		   * @return {Matrix} The created matrix
		   */
		  var matrix = typed('matrix', {
		    '': function () {
		      return _create([]);
		    },
	
		    'string': function (format) {
		      return _create([], format);
		    },
	
		    'string, string': function (format, datatype) {
		      return _create([], format, datatype);
		    },
	
		    'Array': function (data) {
		      return _create(data);
		    },
	
		    'Matrix': function (data) {
		      return _create(data, data.storage());
		    },
	
		    'Array | Matrix, string': _create,
	
		    'Array | Matrix, string, string': _create
		  });
	
		  matrix.toTex = {
		    0: '\\begin{bmatrix}\\end{bmatrix}',
		    1: '\\left(${args[0]}\\right)',
		    2: '\\left(${args[0]}\\right)'
		  };
	
		  return matrix;
	
		  /**
		   * Create a new Matrix with given storage format
		   * @param {Array} data
		   * @param {string} [format]
		   * @param {string} [datatype]
		   * @returns {Matrix} Returns a new Matrix
		   * @private
		   */
		  function _create(data, format, datatype) {
		    // get storage format constructor
		    var M = type.Matrix.storage(format || 'default');
	
		    // create instance
		    return new M(data, datatype);
		  }
		}
	
		exports.name = 'matrix';
		exports.factory = factory;
	
	/***/ }),
	/* 219 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
	
		  /**
		   * Add two scalar values, `x + y`.
		   * This function is meant for internal use: it is used by the public function
		   * `add`
		   *
		   * This function does not support collections (Array or Matrix), and does
		   * not validate the number of of inputs.
		   *
		   * @param  {number | BigNumber | Fraction | Complex | Unit} x   First value to add
		   * @param  {number | BigNumber | Fraction | Complex} y          Second value to add
		   * @return {number | BigNumber | Fraction | Complex | Unit}                      Sum of `x` and `y`
		   * @private
		   */
		  var add = typed('add', {
	
		    'number, number': function (x, y) {
		      return x + y;
		    },
	
		    'Complex, Complex': function (x, y) {
		      return x.add(y);
		    },
	
		    'BigNumber, BigNumber': function (x, y) {
		      return x.plus(y);
		    },
	
		    'Fraction, Fraction': function (x, y) {
		      return x.add(y);
		    },
	
		    'Unit, Unit': function (x, y) {
		      if (x.value == null) throw new Error('Parameter x contains a unit with undefined value');
		      if (y.value == null) throw new Error('Parameter y contains a unit with undefined value');
		      if (!x.equalBase(y)) throw new Error('Units do not match');
	
		      var res = x.clone();
		      res.value = add(res.value, y.value);
		      res.fixPrefix = false;
		      return res;
		    }
		  });
	
		  return add;
		}
	
		exports.factory = factory;
	
	/***/ }),
	/* 220 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
	
		  /**
		   * Multiply two scalar values, `x * y`.
		   * This function is meant for internal use: it is used by the public function
		   * `multiply`
		   *
		   * This function does not support collections (Array or Matrix), and does
		   * not validate the number of of inputs.
		   *
		   * @param  {number | BigNumber | Fraction | Complex | Unit} x   First value to multiply
		   * @param  {number | BigNumber | Fraction | Complex} y          Second value to multiply
		   * @return {number | BigNumber | Fraction | Complex | Unit}                      Multiplication of `x` and `y`
		   * @private
		   */
		  var multiplyScalar = typed('multiplyScalar', {
	
		    'number, number': function (x, y) {
		      return x * y;
		    },
	
		    'Complex, Complex': function (x, y) {
		      return x.mul(y);
		    },
	
		    'BigNumber, BigNumber': function (x, y) {
		      return x.times(y);
		    },
	
		    'Fraction, Fraction': function (x, y) {
		      return x.mul(y);
		    },
	
		    'number | Fraction | BigNumber | Complex, Unit': function (x, y) {
		      var res = y.clone();
		      res.value = res.value === null ? res._normalize(x) : multiplyScalar(res.value, x);
		      return res;
		    },
	
		    'Unit, number | Fraction | BigNumber | Complex': function (x, y) {
		      var res = x.clone();
		      res.value = res.value === null ? res._normalize(y) : multiplyScalar(res.value, y);
		      return res;
		    },
	
		    'Unit, Unit': function (x, y) {
		      return x.multiply(y);
		    }
	
		  });
	
		  return multiplyScalar;
		}
	
		exports.factory = factory;
	
	/***/ }),
	/* 221 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var nearlyEqual = __webpack_require__(200).nearlyEqual;
		var bigNearlyEqual = __webpack_require__(222);
	
		function factory(type, config, load, typed) {
	
		  /**
		   * Test whether two values are equal.
		   *
		   * @param  {number | BigNumber | Fraction | boolean | Complex | Unit} x   First value to compare
		   * @param  {number | BigNumber | Fraction | boolean | Complex} y          Second value to compare
		   * @return {boolean}                                                  Returns true when the compared values are equal, else returns false
		   * @private
		   */
		  var equalScalar = typed('equalScalar', {
	
		    'boolean, boolean': function (x, y) {
		      return x === y;
		    },
	
		    'number, number': function (x, y) {
		      return x === y || nearlyEqual(x, y, config.epsilon);
		    },
	
		    'BigNumber, BigNumber': function (x, y) {
		      return x.eq(y) || bigNearlyEqual(x, y, config.epsilon);
		    },
	
		    'Fraction, Fraction': function (x, y) {
		      return x.equals(y);
		    },
	
		    'Complex, Complex': function (x, y) {
		      return x.equals(y);
		    },
	
		    'Unit, Unit': function (x, y) {
		      if (!x.equalBase(y)) {
		        throw new Error('Cannot compare units with different base');
		      }
		      return equalScalar(x.value, y.value);
		    },
	
		    'string, string': function (x, y) {
		      return x === y;
		    }
		  });
	
		  return equalScalar;
		}
	
		exports.factory = factory;
	
	/***/ }),
	/* 222 */
	/***/ (function(module, exports) {
	
		'use strict';
	
		/**
		 * Compares two BigNumbers.
		 * @param {BigNumber} x       First value to compare
		 * @param {BigNumber} y       Second value to compare
		 * @param {number} [epsilon]  The maximum relative difference between x and y
		 *                            If epsilon is undefined or null, the function will
		 *                            test whether x and y are exactly equal.
		 * @return {boolean} whether the two numbers are nearly equal
		 */
	
		module.exports = function nearlyEqual(x, y, epsilon) {
		  // if epsilon is null or undefined, test whether x and y are exactly equal
		  if (epsilon == null) {
		    return x.eq(y);
		  }
	
		  // use "==" operator, handles infinities
		  if (x.eq(y)) {
		    return true;
		  }
	
		  // NaN
		  if (x.isNaN() || y.isNaN()) {
		    return false;
		  }
	
		  // at this point x and y should be finite
		  if (x.isFinite() && y.isFinite()) {
		    // check numbers are very close, needed when comparing numbers near zero
		    var diff = x.minus(y).abs();
		    if (diff.isZero()) {
		      return true;
		    } else {
		      // use relative error
		      var max = x.constructor.max(x.abs(), y.abs());
		      return diff.lte(max.times(epsilon));
		    }
		  }
	
		  // Infinite and Number or negative Infinite and positive Infinite cases
		  return false;
		};
	
	/***/ }),
	/* 223 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		function factory(type, config, load, typed) {
	
		  var equalScalar = load(__webpack_require__(221));
	
		  var SparseMatrix = type.SparseMatrix;
	
		  /**
		   * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). 
		   * Callback function invoked NZ times (number of nonzero items in S).
		   *
		   *
		   *          ┌  f(Sij, b)  ; S(i,j) !== 0
		   * C(i,j) = ┤  
		   *          └  0          ; otherwise
		   *
		   *
		   * @param {Matrix}   s                 The SparseMatrix instance (S)
		   * @param {Scalar}   b                 The Scalar value
		   * @param {Function} callback          The f(Aij,b) operation to invoke
		   * @param {boolean}  inverse           A true value indicates callback should be invoked f(b,Sij)
		   *
		   * @return {Matrix}                    SparseMatrix (C)
		   *
		   * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813
		   */
		  var algorithm11 = function (s, b, callback, inverse) {
		    // sparse matrix arrays
		    var avalues = s._values;
		    var aindex = s._index;
		    var aptr = s._ptr;
		    var asize = s._size;
		    var adt = s._datatype;
	
		    // sparse matrix cannot be a Pattern matrix
		    if (!avalues) throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value');
	
		    // rows & columns
		    var rows = asize[0];
		    var columns = asize[1];
	
		    // datatype
		    var dt;
		    // equal signature to use
		    var eq = equalScalar;
		    // zero value
		    var zero = 0;
		    // callback signature to use
		    var cf = callback;
	
		    // process data types
		    if (typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // find signature that matches (dt, dt)
		      eq = typed.find(equalScalar, [dt, dt]);
		      // convert 0 to the same datatype
		      zero = typed.convert(0, dt);
		      // convert b to the same datatype
		      b = typed.convert(b, dt);
		      // callback
		      cf = typed.find(callback, [dt, dt]);
		    }
	
		    // result arrays
		    var cvalues = [];
		    var cindex = [];
		    var cptr = [];
		    // matrix
		    var c = new SparseMatrix({
		      values: cvalues,
		      index: cindex,
		      ptr: cptr,
		      size: [rows, columns],
		      datatype: dt
		    });
	
		    // loop columns
		    for (var j = 0; j < columns; j++) {
		      // initialize ptr
		      cptr[j] = cindex.length;
		      // values in j
		      for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) {
		        // row
		        var i = aindex[k];
		        // invoke callback
		        var v = inverse ? cf(b, avalues[k]) : cf(avalues[k], b);
		        // check value is zero
		        if (!eq(v, zero)) {
		          // push index & value
		          cindex.push(i);
		          cvalues.push(v);
		        }
		      }
		    }
		    // update ptr
		    cptr[columns] = cindex.length;
	
		    // return sparse matrix
		    return c;
		  };
	
		  return algorithm11;
		}
	
		exports.name = 'algorithm11';
		exports.factory = factory;
	
	/***/ }),
	/* 224 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var clone = __webpack_require__(196).clone;
	
		function factory(type, config, load, typed) {
	
		  var DenseMatrix = type.DenseMatrix;
	
		  /**
		   * Iterates over DenseMatrix items and invokes the callback function f(Aij..z, b). 
		   * Callback function invoked MxN times.
		   *
		   * C(i,j,...z) = f(Aij..z, b)
		   *
		   * @param {Matrix}   a                 The DenseMatrix instance (A)
		   * @param {Scalar}   b                 The Scalar value
		   * @param {Function} callback          The f(Aij..z,b) operation to invoke
		   * @param {boolean}  inverse           A true value indicates callback should be invoked f(b,Aij..z)
		   *
		   * @return {Matrix}                    DenseMatrix (C)
		   *
		   * https://github.com/josdejong/mathjs/pull/346#issuecomment-97659042
		   */
		  var algorithm14 = function (a, b, callback, inverse) {
		    // a arrays
		    var adata = a._data;
		    var asize = a._size;
		    var adt = a._datatype;
	
		    // datatype
		    var dt;
		    // callback signature to use
		    var cf = callback;
	
		    // process data types
		    if (typeof adt === 'string') {
		      // datatype
		      dt = adt;
		      // convert b to the same datatype
		      b = typed.convert(b, dt);
		      // callback
		      cf = typed.find(callback, [dt, dt]);
		    }
	
		    // populate cdata, iterate through dimensions
		    var cdata = asize.length > 0 ? _iterate(cf, 0, asize, asize[0], adata, b, inverse) : [];
	
		    // c matrix
		    return new DenseMatrix({
		      data: cdata,
		      size: clone(asize),
		      datatype: dt
		    });
		  };
	
		  // recursive function
		  var _iterate = function (f, level, s, n, av, bv, inverse) {
		    // initialize array for this level
		    var cv = [];
		    // check we reach the last level
		    if (level === s.length - 1) {
		      // loop arrays in last level
		      for (var i = 0; i < n; i++) {
		        // invoke callback and store value
		        cv[i] = inverse ? f(bv, av[i]) : f(av[i], bv);
		      }
		    } else {
		      // iterate current level
		      for (var j = 0; j < n; j++) {
		        // iterate next level
		        cv[j] = _iterate(f, level + 1, s, s[level + 1], av[j], bv, inverse);
		      }
		    }
		    return cv;
		  };
	
		  return algorithm14;
		}
	
		exports.name = 'algorithm14';
		exports.factory = factory;
	
	/***/ }),
	/* 225 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var isInteger = __webpack_require__(200).isInteger;
		var size = __webpack_require__(211).size;
	
		function factory(type, config, load, typed) {
		  var latex = __webpack_require__(217);
		  var eye = load(__webpack_require__(226));
		  var multiply = load(__webpack_require__(210));
		  var matrix = load(__webpack_require__(218));
		  var fraction = load(__webpack_require__(227));
		  var number = load(__webpack_require__(228));
	
		  /**
		   * Calculates the power of x to y, `x ^ y`.
		   * Matrix exponentiation is supported for square matrices `x`, and positive
		   * integer exponents `y`.
		   *
		   * For cubic roots of negative numbers, the function returns the principal
		   * root by default. In order to let the function return the real root,
		   * math.js can be configured with `math.config({predictable: true})`.
		   * To retrieve all cubic roots of a value, use `math.cbrt(x, true)`.
		   *
		   * Syntax:
		   *
		   *    math.pow(x, y)
		   *
		   * Examples:
		   *
		   *    math.pow(2, 3);               // returns number 8
		   *
		   *    var a = math.complex(2, 3);
		   *    math.pow(a, 2)                // returns Complex -5 + 12i
		   *
		   *    var b = [[1, 2], [4, 3]];
		   *    math.pow(b, 2);               // returns Array [[9, 8], [16, 17]]
		   *
		   * See also:
		   *
		   *    multiply, sqrt, cbrt, nthRoot
		   *
		   * @param  {number | BigNumber | Complex | Array | Matrix} x  The base
		   * @param  {number | BigNumber | Complex} y                   The exponent
		   * @return {number | BigNumber | Complex | Array | Matrix} The value of `x` to the power `y`
		   */
		  var pow = typed('pow', {
		    'number, number': _pow,
	
		    'Complex, Complex': function (x, y) {
		      return x.pow(y);
		    },
	
		    'BigNumber, BigNumber': function (x, y) {
		      if (y.isInteger() || x >= 0 || config.predictable) {
		        return x.pow(y);
		      } else {
		        return new type.Complex(x.toNumber(), 0).pow(y.toNumber(), 0);
		      }
		    },
	
		    'Fraction, Fraction': function (x, y) {
		      if (y.d !== 1) {
		        if (config.predictable) {
		          throw new Error('Function pow does not support non-integer exponents for fractions.');
		        } else {
		          return _pow(x.valueOf(), y.valueOf());
		        }
		      } else {
		        return x.pow(y);
		      }
		    },
	
		    'Array, number': _powArray,
	
		    'Array, BigNumber': function (x, y) {
		      return _powArray(x, y.toNumber());
		    },
	
		    'Matrix, number': _powMatrix,
	
		    'Matrix, BigNumber': function (x, y) {
		      return _powMatrix(x, y.toNumber());
		    },
	
		    'Unit, number': function (x, y) {
		      return x.pow(y);
		    }
	
		  });
	
		  /**
		   * Calculates the power of x to y, x^y, for two numbers.
		   * @param {number} x
		   * @param {number} y
		   * @return {number | Complex} res
		   * @private
		   */
		  function _pow(x, y) {
	
		    // Alternatively could define a 'realmode' config option or something, but
		    // 'predictable' will work for now
		    if (config.predictable && !isInteger(y) && x < 0) {
		      // Check to see if y can be represented as a fraction
		      try {
		        var yFrac = fraction(y);
		        var yNum = number(yFrac);
		        if (y === yNum || Math.abs((y - yNum) / y) < 1e-14) {
		          if (yFrac.d % 2 === 1) {
		            return (yFrac.n % 2 === 0 ? 1 : -1) * Math.pow(-x, y);
		          }
		        }
		      } catch (ex) {}
		      // fraction() throws an error if y is Infinity, etc.
	
	
		      // Unable to express y as a fraction, so continue on
		    }
	
		    // x^Infinity === 0 if -1 < x < 1
		    // A real number 0 is returned instead of complex(0)
		    if (x * x < 1 && y === Infinity || x * x > 1 && y === -Infinity) {
		      return 0;
		    }
	
		    // **for predictable mode** x^Infinity === NaN if x < -1
		    // N.B. this behavour is different from `Math.pow` which gives
		    // (-2)^Infinity === Infinity
		    if (config.predictable && (x < -1 && y === Infinity || x > -1 && x < 0 && y === -Infinity)) {
		      return NaN;
		    }
	
		    if (isInteger(y) || x >= 0 || config.predictable) {
		      return Math.pow(x, y);
		    } else {
		      return new type.Complex(x, 0).pow(y, 0);
		    }
		  }
	
		  /**
		   * Calculate the power of a 2d array
		   * @param {Array} x     must be a 2 dimensional, square matrix
		   * @param {number} y    a positive, integer value
		   * @returns {Array}
		   * @private
		   */
		  function _powArray(x, y) {
		    if (!isInteger(y) || y < 0) {
		      throw new TypeError('For A^b, b must be a positive integer (value is ' + y + ')');
		    }
		    // verify that A is a 2 dimensional square matrix
		    var s = size(x);
		    if (s.length != 2) {
		      throw new Error('For A^b, A must be 2 dimensional (A has ' + s.length + ' dimensions)');
		    }
		    if (s[0] != s[1]) {
		      throw new Error('For A^b, A must be square (size is ' + s[0] + 'x' + s[1] + ')');
		    }
	
		    var res = eye(s[0]).valueOf();
		    var px = x;
		    while (y >= 1) {
		      if ((y & 1) == 1) {
		        res = multiply(px, res);
		      }
		      y >>= 1;
		      px = multiply(px, px);
		    }
		    return res;
		  }
	
		  /**
		   * Calculate the power of a 2d matrix
		   * @param {Matrix} x     must be a 2 dimensional, square matrix
		   * @param {number} y    a positive, integer value
		   * @returns {Matrix}
		   * @private
		   */
		  function _powMatrix(x, y) {
		    return matrix(_powArray(x.valueOf(), y));
		  }
	
		  pow.toTex = {
		    2: '\\left(${args[0]}\\right)' + latex.operators['pow'] + '{${args[1]}}'
		  };
	
		  return pow;
		}
	
		exports.name = 'pow';
		exports.factory = factory;
	
	/***/ }),
	/* 226 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var array = __webpack_require__(211);
		var isInteger = __webpack_require__(200).isInteger;
	
		function factory(type, config, load, typed) {
	
		  var matrix = load(__webpack_require__(218));
	
		  /**
		   * Create a 2-dimensional identity matrix with size m x n or n x n.
		   * The matrix has ones on the diagonal and zeros elsewhere.
		   *
		   * Syntax:
		   *
		   *    math.eye(n)
		   *    math.eye(n, format)
		   *    math.eye(m, n)
		   *    math.eye(m, n, format)
		   *    math.eye([m, n])
		   *    math.eye([m, n], format)
		   *
		   * Examples:
		   *
		   *    math.eye(3);                    // returns [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
		   *    math.eye(3, 2);                 // returns [[1, 0], [0, 1], [0, 0]]
		   *
		   *    var A = [[1, 2, 3], [4, 5, 6]];
		   *    math.eye(math.size(A));         // returns [[1, 0, 0], [0, 1, 0]]
		   *
		   * See also:
		   *
		   *    diag, ones, zeros, size, range
		   *
		   * @param {...number | Matrix | Array} size   The size for the matrix
		   * @param {string} [format]                   The Matrix storage format
		   *
		   * @return {Matrix | Array | number} A matrix with ones on the diagonal.
		   */
		  var eye = typed('eye', {
		    '': function () {
		      return config.matrix === 'Matrix' ? matrix([]) : [];
		    },
	
		    'string': function (format) {
		      return matrix(format);
		    },
	
		    'number | BigNumber': function (rows) {
		      return _eye(rows, rows, config.matrix === 'Matrix' ? 'default' : undefined);
		    },
	
		    'number | BigNumber, string': function (rows, format) {
		      return _eye(rows, rows, format);
		    },
	
		    'number | BigNumber, number | BigNumber': function (rows, cols) {
		      return _eye(rows, cols, config.matrix === 'Matrix' ? 'default' : undefined);
		    },
	
		    'number | BigNumber, number | BigNumber, string': function (rows, cols, format) {
		      return _eye(rows, cols, format);
		    },
	
		    'Array': function (size) {
		      return _eyeVector(size);
		    },
	
		    'Array, string': function (size, format) {
		      return _eyeVector(size, format);
		    },
	
		    'Matrix': function (size) {
		      return _eyeVector(size.valueOf(), size.storage());
		    },
	
		    'Matrix, string': function (size, format) {
		      return _eyeVector(size.valueOf(), format);
		    }
		  });
	
		  eye.toTex = undefined; // use default template
	
		  return eye;
	
		  function _eyeVector(size, format) {
		    switch (size.length) {
		      case 0:
		        return format ? matrix(format) : [];
		      case 1:
		        return _eye(size[0], size[0], format);
		      case 2:
		        return _eye(size[0], size[1], format);
		      default:
		        throw new Error('Vector containing two values expected');
		    }
		  }
	
		  /**
		   * Create an identity matrix
		   * @param {number | BigNumber} rows
		   * @param {number | BigNumber} cols
		   * @param {string} [format]
		   * @returns {Matrix}
		   * @private
		   */
		  function _eye(rows, cols, format) {
		    // BigNumber constructor with the right precision
		    var Big = type.isBigNumber(rows) || type.isBigNumber(cols) ? type.BigNumber : null;
	
		    if (type.isBigNumber(rows)) rows = rows.toNumber();
		    if (type.isBigNumber(cols)) cols = cols.toNumber();
	
		    if (!isInteger(rows) || rows < 1) {
		      throw new Error('Parameters in function eye must be positive integers');
		    }
		    if (!isInteger(cols) || cols < 1) {
		      throw new Error('Parameters in function eye must be positive integers');
		    }
	
		    var one = Big ? new type.BigNumber(1) : 1;
		    var defaultValue = Big ? new Big(0) : 0;
		    var size = [rows, cols];
	
		    // check we need to return a matrix
		    if (format) {
		      // get matrix storage constructor
		      var F = type.Matrix.storage(format);
		      // create diagonal matrix (use optimized implementation for storage format)
		      return F.diagonal(size, one, 0, defaultValue);
		    }
	
		    // create and resize array
		    var res = array.resize([], size, defaultValue);
		    // fill in ones on the diagonal
		    var minimum = rows < cols ? rows : cols;
		    // fill diagonal
		    for (var d = 0; d < minimum; d++) {
		      res[d][d] = one;
		    }
		    return res;
		  }
		}
	
		exports.name = 'eye';
		exports.factory = factory;
	
	/***/ }),
	/* 227 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var deepMap = __webpack_require__(208);
	
		function factory(type, config, load, typed) {
		  /**
		   * Create a fraction convert a value to a fraction.
		   *
		   * Syntax:
		   *     math.fraction(numerator, denominator)
		   *     math.fraction({n: numerator, d: denominator})
		   *     math.fraction(matrix: Array | Matrix)         Turn all matrix entries
		   *                                                   into fractions
		   *
		   * Examples:
		   *
		   *     math.fraction(1, 3);
		   *     math.fraction('2/3');
		   *     math.fraction({n: 2, d: 3});
		   *     math.fraction([0.2, 0.25, 1.25]);
		   *
		   * See also:
		   *
		   *    bignumber, number, string, unit
		   *
		   * @param {number | string | Fraction | BigNumber | Array | Matrix} [args]
		   *            Arguments specifying the numerator and denominator of
		   *            the fraction
		   * @return {Fraction | Array | Matrix} Returns a fraction
		   */
		  var fraction = typed('fraction', {
		    'number': function (x) {
		      if (!isFinite(x) || isNaN(x)) {
		        throw new Error(x + ' cannot be represented as a fraction');
		      }
	
		      return new type.Fraction(x);
		    },
	
		    'string': function (x) {
		      return new type.Fraction(x);
		    },
	
		    'number, number': function (numerator, denominator) {
		      return new type.Fraction(numerator, denominator);
		    },
	
		    'BigNumber': function (x) {
		      return new type.Fraction(x.toString());
		    },
	
		    'Fraction': function (x) {
		      return x; // fractions are immutable
		    },
	
		    'Object': function (x) {
		      return new type.Fraction(x);
		    },
	
		    'Array | Matrix': function (x) {
		      return deepMap(x, fraction);
		    }
		  });
	
		  return fraction;
		}
	
		exports.name = 'fraction';
		exports.factory = factory;
	
	/***/ }),
	/* 228 */
	/***/ (function(module, exports, __webpack_require__) {
	
		'use strict';
	
		var deepMap = __webpack_require__(208);
	
		function factory(type, config, load, typed) {
		  /**
		   * Create a number or convert a string, boolean, or unit to a number.
		   * When value is a matrix, all elements will be converted to number.
		   *
		   * Syntax:
		   *
		   *    math.number(value)
		   *    math.number(unit, valuelessUnit)
		   *
		   * Examples:
		   *
		   *    math.number(2);                         // returns number 2
		   *    math.number('7.2');                     // returns number 7.2
		   *    math.number(true);                      // returns number 1
		   *    math.number([true, false, true, true]); // returns [1, 0, 1, 1]
		   *    math.number(math.unit('52cm'), 'm');    // returns 0.52
		   *
		   * See also:
		   *
		   *    bignumber, boolean, complex, index, matrix, string, unit
		   *
		   * @param {string | number | BigNumber | Fraction | boolean | Array | Matrix | Unit | null} [value]  Value to be converted
		   * @param {Unit | string} [valuelessUnit] A valueless unit, used to convert a unit to a number
		   * @return {number | Array | Matrix} The created number
		   */
		  var number = typed('number', {
		    '': function () {
		      return 0;
		    },
	
		    'number': function (x) {
		      return x;
		    },
	
		    'string': function (x) {
		      var num = Number(x);
		      if (isNaN(num)) {
		        throw new SyntaxError('String "' + x + '" is no valid number');
		      }
		      return num;
		    },
	
		    'BigNumber': function (x) {
		      return x.toNumber();
		    },
	
		    'Fraction': function (x) {
		      return x.valueOf();
		    },
	
		    'Unit': function (x) {
		      throw new Error('Second argument with valueless unit expected');
		    },
	
		    'Unit, string | Unit': function (unit, valuelessUnit) {
		      return unit.toNumber(valuelessUnit);
		    },
	
		    'Array | Matrix': function (x) {
		      return deepMap(x, number);
		    }
		  });
	
		  number.toTex = {
		    0: '0',
		    1: '\\left(${args[0]}\\right)',
		    2: '\\left(\\left(${args[0]}\\right)${args[1]}\\right)'
		  };
	
		  return number;
		}
	
		exports.name = 'number';
		exports.factory = factory;
	
	/***/ }),
	/* 229 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var draw_matrix_components = __webpack_require__(230);
		var draw_row_components = __webpack_require__(231);
		var draw_col_components = __webpack_require__(233);
		var draw_spillover_components = __webpack_require__(235);
	
		module.exports = function draw_commands(regl, params, slow_draw = false) {
	
		  // if (slow_draw){
		  //   console.log('\n***************');
		  //   console.log('** slow draw **');
		  //   console.log('***************');
		  // }
	
		  draw_matrix_components(regl, params);
	
		  draw_row_components(regl, params, slow_draw);
	
		  draw_col_components(regl, params, slow_draw);
	
		  draw_spillover_components(regl, params);
			};
	
	/***/ }),
	/* 230 */
	/***/ (function(module, exports) {
	
		// var filter_visible_mat = require('./filter_visible_mat');
		// var make_matrix_args = require('./make_matrix_args');
	
		module.exports = function draw_matrix_components(regl, params) {
	
		  /* Matrix */
		  params.cameras.mat.draw(() => {
	
		    /*
		      Disabling this, prevents the screen from flashing when working with very
		      large datasets
		    */
		    // regl.clear({color: [0, 0, 0, 0]});
	
		    /*
		      Filter and regenerate args is slow
		    */
		    // // Filter
		    // params.arrs_filt = filter_visible_mat(params.arrs, params.zoom_data);
		    // // Regenerate args
		    // params.matrix_args = make_matrix_args(regl, params);
	
		    regl(params.matrix_args.regl_props.top)();
		    regl(params.matrix_args.regl_props.bot)();
		  });
			};
	
	/***/ }),
	/* 231 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var make_row_text_triangle_args = __webpack_require__(232);
		var calc_viz_area = __webpack_require__(192);
		var calc_row_text_triangles = __webpack_require__(4);
	
		module.exports = function draw_row_components(regl, params, slow_draw = false) {
	
		  /* Row Components */
		  params.cameras['row-labels'].draw(() => {
	
		    regl(params.viz_aid_tri_args.row)();
		    regl(params.dendro_args.row)();
	
		    // make the arguments for the draw command
		    var text_triangle_args = make_row_text_triangle_args(regl, params, params.zoom_function);
	
		    if (slow_draw) {
	
		      var num_viz_rows = params.num_row / params.zoom_data.y.total_zoom;
	
		      if (num_viz_rows < params.max_num_text) {
	
		        calc_viz_area(params);
	
		        // draw using text_triangle_args and row_text_triangles
		        params.row_text_triangles = calc_row_text_triangles(params);
		        regl(text_triangle_args)(params.row_text_triangles);
		      } else {
		        // console.log('too many rows to draw');
		      }
		    } else {
	
		      /*
		        show text triangles if avaialble
		      */
	
		      if (params.row_text_triangles != false) {
		        regl(text_triangle_args)(params.row_text_triangles);
		      }
		    }
		  });
			};
	
	/***/ }),
	/* 232 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var m3 = __webpack_require__(189);
	
		module.exports = function make_row_text_triangle_args(regl, params, zoom_function) {
	
		  // prevent text from getting too large when zooming
		  params.text_scale.row = d3.scale.linear().domain([1, 10]).range([1, 10 / params.allowable_zoom_factor]);
	
		  // console.log('scaled_num', params.text_zoom.row.scaled_num);
	
		  // /* Row Text */
		  // // update text information with zooming
		  // params.text_zoom.row.scaled_num = params.text_zoom.row.reference *
		  //                                   // reduce text size when zooming
		  //                                   params.text_scale.row(params.zoom_data.y.total_zoom);
	
		  // var row_x_offset = d3.scale.linear()
		  //   .domain([50, 100])
		  //   .range([-26.1, -53]);
	
		  // smaller scale_y -> larger text
		  var tmp_reduce_text_factor = 3;
		  var scale_y = params.text_zoom.row.scaled_num * tmp_reduce_text_factor;
	
		  // console.log('scale_y', scale_y);
	
		  var scale_x = params.zoom_data.y.total_zoom;
	
		  // var x_offset = row_x_offset(params.text_zoom.row.scaled_num);
	
		  // scale_y is applying a zoom to x and y
		  // so the normal offset of -0.5 to get to the left side of the matrix now
		  // needs to be scaled by scale_y
		  var x_offset = -0.5 * scale_y;
	
		  // console.log('scale_y', scale_y)
	
		  var mat_rotate = m3.rotation(Math.PI / 2);
	
		  var args = {
		    vert: `
		      precision mediump float;
		      attribute vec2 position;
		      uniform mat4 zoom;
		      uniform vec2 offset;
		      uniform float x_offset;
		      uniform float scale_y;
		      uniform float scale_x;
		      uniform mat3 mat_rotate;
	
		      // vec3 tmp = vec3(1,1,1);
	
		      // last value is a sort-of zoom
		      void main () {
		        // reverse y position to get words to be upright
	
		        gl_Position = zoom *
		                      vec4(
		                            (position.x * scale_x) + x_offset,
		                           -position.y + (offset[1]) * scale_y,
		                           // depth
		                           0.50,
		                           // zoom
		                           scale_y);
		      }`,
		    frag: `
		      precision mediump float;
		      void main () {
		        gl_FragColor = vec4(0.2, 0.2, 0.2, 1.0);
		      }`,
		    attributes: {
		      position: regl.prop('positions')
		    },
		    elements: regl.prop('cells'),
		    uniforms: {
		      zoom: zoom_function,
		      offset: regl.prop('offset'),
		      x_offset: x_offset,
		      scale_y: scale_y,
		      scale_x: scale_x,
		      mat_rotate: mat_rotate
		    },
		    depth: {
		      enable: true,
		      mask: true,
		      func: 'less',
		      // func: 'greater',
		      range: [0, 1]
		    }
		  };
	
		  return args;
			};
	
	/***/ }),
	/* 233 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var make_col_text_triangle_args = __webpack_require__(234);
		var calc_viz_area = __webpack_require__(192);
		var calc_col_text_triangles = __webpack_require__(98);
	
		module.exports = function draw_col_components(regl, params, slow_draw = false) {
	
		  /* Column Components */
		  params.cameras['col-labels'].draw(() => {
	
		    regl(params.viz_aid_tri_args.col)();
		    regl(params.dendro_args.col)();
	
		    // make the arguments for the draw command
		    var text_triangle_args = make_col_text_triangle_args(regl, params, params.zoom_function);
	
		    // // draw using text_triangle_args and col_text_triangles
		    // regl(text_triangle_args)(params.col_text_triangles);
	
		    if (slow_draw) {
	
		      var num_viz_rows = params.num_row / params.zoom_data.y.total_zoom;
	
		      if (num_viz_rows < params.max_num_text) {
	
		        calc_viz_area(params);
	
		        // draw using text_triangle_args and col_text_triangles
		        params.col_text_triangles = calc_col_text_triangles(params);
		        regl(text_triangle_args)(params.col_text_triangles);
		      } else {
		        // console.log('too many rows to draw');
		      }
		    } else {
	
		      /*
		        show text triangles if avaialble
		      */
	
		      if (params.col_text_triangles != false) {
		        regl(text_triangle_args)(params.col_text_triangles);
		      }
		    }
		  });
			};
	
	/***/ }),
	/* 234 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var m3 = __webpack_require__(189);
	
		module.exports = function make_col_text_triangle_args(regl, params, zoom_function) {
	
		  /* control allowable zoom for column text */
	
		  params.text_scale.col = d3.scale.linear().domain([1, 10]).range([1, 10 / params.allowable_zoom_factor]);
	
		  /* Col Text */
		  // update text information with zooming
		  params.text_zoom.col.scaled_num = params.text_zoom.col.reference * params.text_scale.col(params.zoom_data.x.total_zoom);
	
		  /*
		  works but needs to be improved
		  */
	
		  // manually tuned numbers
		  var col_x_offset = d3.scale.linear().domain([50, 100]).range([25.9, 52]);
	
		  // console.log(params.text_zoom.col.scaled_num);
		  var offset_y = col_x_offset(params.text_zoom.col.scaled_num);
		  // console.log('offset_y: ', offset_y);
	
		  /*
		  Not using mat_translate since each label needs to be translated a specific
		  amount that is saved in the batch data.
		  */
		  var mat_rotate = m3.rotation(Math.PI / 4);
		  var text_y_scale = m3.scaling(1, params.zoom_data.x.total_zoom);
	
		  // smaller number gives smaller text
		  // rc_two_cats: 0.75
		  // mnist: 1
		  var reduce_factor = 0.75; // 1 / params.zoom_data.x.total_zoom;
		  var total_zoom = params.zoom_data.x.total_zoom;
		  var mat_reduce_text_size = m3.scaling(reduce_factor, reduce_factor);
	
		  var scale_x = params.text_zoom.col.scaled_num;
	
		  var args = {
		    vert: `
		      precision mediump float;
		      attribute vec2 position;
		      uniform mat4 zoom;
		      uniform vec2 offset;
		      uniform float offset_y;
		      uniform float scale_x;
		      uniform float width_scale;
		      uniform mat3 mat_rotate;
		      uniform mat3 text_y_scale;
		      uniform mat3 mat_reduce_text_size;
		      uniform float total_zoom;
		      uniform float col_width;
		      varying vec3 rotated_text;
		      varying vec3 shift_to_right;
		      varying vec3 position_cols;
	
		      // last value is a sort-of zoom
		      void main () {
	
		        // rotate, reduce size, stretch in y, and give text triangles positions
		        rotated_text = text_y_scale *
		                       mat_rotate *
		                       mat_reduce_text_size *
		                       vec3(position.y, position.x, 0.5);
	
		        /*
		          Shift text over a little by a fixed amount and then
		          shift by a zoom-dependent amount so that the bottom
		          of the text remains at the same lower right position
		          vec3( 0.11 * total_zoom  + 0.2 , 0, 0)
	
		          need to have
		            0.11 * total_zoom
		          factor scale with the number of columns
		          so that the labels remain on top of the correct columns
		        */
		        shift_to_right = vec3( col_width * total_zoom , 0, 0);
	
		        position_cols = vec3( offset[1] * scale_x, offset_y, 0);
	
		        // reverse y position to get words to be upright
		        gl_Position = zoom *
	
		          vec4(
	
		                //////////////////////
		                // vec3: x, y, depth
		                //////////////////////
	
		                rotated_text + shift_to_right + position_cols,
	
		                /////////////////////
		                // vec4: zoom
		                /////////////////////
	
		                // zoom element in vec4
		                scale_x
	
		          );
	
		      }`,
		    frag: `
		      precision mediump float;
		      void main () {
		        gl_FragColor = vec4(0.2, 0.2, 0.2, 1.0);
		      }`,
		    attributes: {
		      position: regl.prop('positions')
		    },
		    elements: regl.prop('cells'),
		    uniforms: {
		      zoom: zoom_function,
		      offset: regl.prop('offset'),
		      scale_x: scale_x,
		      offset_y: offset_y,
		      width_scale: params.zoom_data.x.total_zoom,
		      mat_rotate: mat_rotate,
		      text_y_scale: text_y_scale,
		      mat_reduce_text_size: mat_reduce_text_size,
		      total_zoom: total_zoom,
		      // need to pin down number
		      col_width: 4.5 / params.num_col
		    },
		    depth: {
		      enable: true,
		      mask: true,
		      func: 'less',
		      // func: 'greater',
		      range: [0, 1]
		    }
		  };
	
		  return args;
			};
	
	/***/ }),
	/* 235 */
	/***/ (function(module, exports) {
	
		module.exports = function draw_spillover_components(regl, params) {
		  // Spillover Components (may not need to redraw)
		  params.cameras.static.draw(() => {
	
		    var args = params.spillover_args;
		    var triangles = params.spillover_triangles;
	
		    // spillover rects to hide matrix spillover
		    regl(args.mat_sides)(triangles.mat);
		    regl(args.mat_corners)(triangles.corners);
		    regl(args.label_corners)(triangles.corners);
		  });
		};
	
	/***/ }),
	/* 236 */
	/***/ (function(module, exports, __webpack_require__) {
	
		var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;//     Underscore.js 1.8.3
		//     http://underscorejs.org
		//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
		//     Underscore may be freely distributed under the MIT license.
	
		(function () {
	
		  // Baseline setup
		  // --------------
	
		  // Establish the root object, `window` in the browser, or `exports` on the server.
		  var root = this;
	
		  // Save the previous value of the `_` variable.
		  var previousUnderscore = root._;
	
		  // Save bytes in the minified (but not gzipped) version:
		  var ArrayProto = Array.prototype,
		      ObjProto = Object.prototype,
		      FuncProto = Function.prototype;
	
		  // Create quick reference variables for speed access to core prototypes.
		  var push = ArrayProto.push,
		      slice = ArrayProto.slice,
		      toString = ObjProto.toString,
		      hasOwnProperty = ObjProto.hasOwnProperty;
	
		  // All **ECMAScript 5** native function implementations that we hope to use
		  // are declared here.
		  var nativeIsArray = Array.isArray,
		      nativeKeys = Object.keys,
		      nativeBind = FuncProto.bind,
		      nativeCreate = Object.create;
	
		  // Naked function reference for surrogate-prototype-swapping.
		  var Ctor = function () {};
	
		  // Create a safe reference to the Underscore object for use below.
		  var _ = function (obj) {
		    if (obj instanceof _) return obj;
		    if (!(this instanceof _)) return new _(obj);
		    this._wrapped = obj;
		  };
	
		  // Export the Underscore object for **Node.js**, with
		  // backwards-compatibility for the old `require()` API. If we're in
		  // the browser, add `_` as a global object.
		  if (true) {
		    if (typeof module !== 'undefined' && module.exports) {
		      exports = module.exports = _;
		    }
		    exports._ = _;
		  } else {
		    root._ = _;
		  }
	
		  // Current version.
		  _.VERSION = '1.8.3';
	
		  // Internal function that returns an efficient (for current engines) version
		  // of the passed-in callback, to be repeatedly applied in other Underscore
		  // functions.
		  var optimizeCb = function (func, context, argCount) {
		    if (context === void 0) return func;
		    switch (argCount == null ? 3 : argCount) {
		      case 1:
		        return function (value) {
		          return func.call(context, value);
		        };
		      case 2:
		        return function (value, other) {
		          return func.call(context, value, other);
		        };
		      case 3:
		        return function (value, index, collection) {
		          return func.call(context, value, index, collection);
		        };
		      case 4:
		        return function (accumulator, value, index, collection) {
		          return func.call(context, accumulator, value, index, collection);
		        };
		    }
		    return function () {
		      return func.apply(context, arguments);
		    };
		  };
	
		  // A mostly-internal function to generate callbacks that can be applied
		  // to each element in a collection, returning the desired result — either
		  // identity, an arbitrary callback, a property matcher, or a property accessor.
		  var cb = function (value, context, argCount) {
		    if (value == null) return _.identity;
		    if (_.isFunction(value)) return optimizeCb(value, context, argCount);
		    if (_.isObject(value)) return _.matcher(value);
		    return _.property(value);
		  };
		  _.iteratee = function (value, context) {
		    return cb(value, context, Infinity);
		  };
	
		  // An internal function for creating assigner functions.
		  var createAssigner = function (keysFunc, undefinedOnly) {
		    return function (obj) {
		      var length = arguments.length;
		      if (length < 2 || obj == null) return obj;
		      for (var index = 1; index < length; index++) {
		        var source = arguments[index],
		            keys = keysFunc(source),
		            l = keys.length;
		        for (var i = 0; i < l; i++) {
		          var key = keys[i];
		          if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
		        }
		      }
		      return obj;
		    };
		  };
	
		  // An internal function for creating a new object that inherits from another.
		  var baseCreate = function (prototype) {
		    if (!_.isObject(prototype)) return {};
		    if (nativeCreate) return nativeCreate(prototype);
		    Ctor.prototype = prototype;
		    var result = new Ctor();
		    Ctor.prototype = null;
		    return result;
		  };
	
		  var property = function (key) {
		    return function (obj) {
		      return obj == null ? void 0 : obj[key];
		    };
		  };
	
		  // Helper for collection methods to determine whether a collection
		  // should be iterated as an array or as an object
		  // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
		  // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
		  var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
		  var getLength = property('length');
		  var isArrayLike = function (collection) {
		    var length = getLength(collection);
		    return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
		  };
	
		  // Collection Functions
		  // --------------------
	
		  // The cornerstone, an `each` implementation, aka `forEach`.
		  // Handles raw objects in addition to array-likes. Treats all
		  // sparse array-likes as if they were dense.
		  _.each = _.forEach = function (obj, iteratee, context) {
		    iteratee = optimizeCb(iteratee, context);
		    var i, length;
		    if (isArrayLike(obj)) {
		      for (i = 0, length = obj.length; i < length; i++) {
		        iteratee(obj[i], i, obj);
		      }
		    } else {
		      var keys = _.keys(obj);
		      for (i = 0, length = keys.length; i < length; i++) {
		        iteratee(obj[keys[i]], keys[i], obj);
		      }
		    }
		    return obj;
		  };
	
		  // Return the results of applying the iteratee to each element.
		  _.map = _.collect = function (obj, iteratee, context) {
		    iteratee = cb(iteratee, context);
		    var keys = !isArrayLike(obj) && _.keys(obj),
		        length = (keys || obj).length,
		        results = Array(length);
		    for (var index = 0; index < length; index++) {
		      var currentKey = keys ? keys[index] : index;
		      results[index] = iteratee(obj[currentKey], currentKey, obj);
		    }
		    return results;
		  };
	
		  // Create a reducing function iterating left or right.
		  function createReduce(dir) {
		    // Optimized iterator function as using arguments.length
		    // in the main function will deoptimize the, see #1991.
		    function iterator(obj, iteratee, memo, keys, index, length) {
		      for (; index >= 0 && index < length; index += dir) {
		        var currentKey = keys ? keys[index] : index;
		        memo = iteratee(memo, obj[currentKey], currentKey, obj);
		      }
		      return memo;
		    }
	
		    return function (obj, iteratee, memo, context) {
		      iteratee = optimizeCb(iteratee, context, 4);
		      var keys = !isArrayLike(obj) && _.keys(obj),
		          length = (keys || obj).length,
		          index = dir > 0 ? 0 : length - 1;
		      // Determine the initial value if none is provided.
		      if (arguments.length < 3) {
		        memo = obj[keys ? keys[index] : index];
		        index += dir;
		      }
		      return iterator(obj, iteratee, memo, keys, index, length);
		    };
		  }
	
		  // **Reduce** builds up a single result from a list of values, aka `inject`,
		  // or `foldl`.
		  _.reduce = _.foldl = _.inject = createReduce(1);
	
		  // The right-associative version of reduce, also known as `foldr`.
		  _.reduceRight = _.foldr = createReduce(-1);
	
		  // Return the first value which passes a truth test. Aliased as `detect`.
		  _.find = _.detect = function (obj, predicate, context) {
		    var key;
		    if (isArrayLike(obj)) {
		      key = _.findIndex(obj, predicate, context);
		    } else {
		      key = _.findKey(obj, predicate, context);
		    }
		    if (key !== void 0 && key !== -1) return obj[key];
		  };
	
		  // Return all the elements that pass a truth test.
		  // Aliased as `select`.
		  _.filter = _.select = function (obj, predicate, context) {
		    var results = [];
		    predicate = cb(predicate, context);
		    _.each(obj, function (value, index, list) {
		      if (predicate(value, index, list)) results.push(value);
		    });
		    return results;
		  };
	
		  // Return all the elements for which a truth test fails.
		  _.reject = function (obj, predicate, context) {
		    return _.filter(obj, _.negate(cb(predicate)), context);
		  };
	
		  // Determine whether all of the elements match a truth test.
		  // Aliased as `all`.
		  _.every = _.all = function (obj, predicate, context) {
		    predicate = cb(predicate, context);
		    var keys = !isArrayLike(obj) && _.keys(obj),
		        length = (keys || obj).length;
		    for (var index = 0; index < length; index++) {
		      var currentKey = keys ? keys[index] : index;
		      if (!predicate(obj[currentKey], currentKey, obj)) return false;
		    }
		    return true;
		  };
	
		  // Determine if at least one element in the object matches a truth test.
		  // Aliased as `any`.
		  _.some = _.any = function (obj, predicate, context) {
		    predicate = cb(predicate, context);
		    var keys = !isArrayLike(obj) && _.keys(obj),
		        length = (keys || obj).length;
		    for (var index = 0; index < length; index++) {
		      var currentKey = keys ? keys[index] : index;
		      if (predicate(obj[currentKey], currentKey, obj)) return true;
		    }
		    return false;
		  };
	
		  // Determine if the array or object contains a given item (using `===`).
		  // Aliased as `includes` and `include`.
		  _.contains = _.includes = _.include = function (obj, item, fromIndex, guard) {
		    if (!isArrayLike(obj)) obj = _.values(obj);
		    if (typeof fromIndex != 'number' || guard) fromIndex = 0;
		    return _.indexOf(obj, item, fromIndex) >= 0;
		  };
	
		  // Invoke a method (with arguments) on every item in a collection.
		  _.invoke = function (obj, method) {
		    var args = slice.call(arguments, 2);
		    var isFunc = _.isFunction(method);
		    return _.map(obj, function (value) {
		      var func = isFunc ? method : value[method];
		      return func == null ? func : func.apply(value, args);
		    });
		  };
	
		  // Convenience version of a common use case of `map`: fetching a property.
		  _.pluck = function (obj, key) {
		    return _.map(obj, _.property(key));
		  };
	
		  // Convenience version of a common use case of `filter`: selecting only objects
		  // containing specific `key:value` pairs.
		  _.where = function (obj, attrs) {
		    return _.filter(obj, _.matcher(attrs));
		  };
	
		  // Convenience version of a common use case of `find`: getting the first object
		  // containing specific `key:value` pairs.
		  _.findWhere = function (obj, attrs) {
		    return _.find(obj, _.matcher(attrs));
		  };
	
		  // Return the maximum element (or element-based computation).
		  _.max = function (obj, iteratee, context) {
		    var result = -Infinity,
		        lastComputed = -Infinity,
		        value,
		        computed;
		    if (iteratee == null && obj != null) {
		      obj = isArrayLike(obj) ? obj : _.values(obj);
		      for (var i = 0, length = obj.length; i < length; i++) {
		        value = obj[i];
		        if (value > result) {
		          result = value;
		        }
		      }
		    } else {
		      iteratee = cb(iteratee, context);
		      _.each(obj, function (value, index, list) {
		        computed = iteratee(value, index, list);
		        if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
		          result = value;
		          lastComputed = computed;
		        }
		      });
		    }
		    return result;
		  };
	
		  // Return the minimum element (or element-based computation).
		  _.min = function (obj, iteratee, context) {
		    var result = Infinity,
		        lastComputed = Infinity,
		        value,
		        computed;
		    if (iteratee == null && obj != null) {
		      obj = isArrayLike(obj) ? obj : _.values(obj);
		      for (var i = 0, length = obj.length; i < length; i++) {
		        value = obj[i];
		        if (value < result) {
		          result = value;
		        }
		      }
		    } else {
		      iteratee = cb(iteratee, context);
		      _.each(obj, function (value, index, list) {
		        computed = iteratee(value, index, list);
		        if (computed < lastComputed || computed === Infinity && result === Infinity) {
		          result = value;
		          lastComputed = computed;
		        }
		      });
		    }
		    return result;
		  };
	
		  // Shuffle a collection, using the modern version of the
		  // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
		  _.shuffle = function (obj) {
		    var set = isArrayLike(obj) ? obj : _.values(obj);
		    var length = set.length;
		    var shuffled = Array(length);
		    for (var index = 0, rand; index < length; index++) {
		      rand = _.random(0, index);
		      if (rand !== index) shuffled[index] = shuffled[rand];
		      shuffled[rand] = set[index];
		    }
		    return shuffled;
		  };
	
		  // Sample **n** random values from a collection.
		  // If **n** is not specified, returns a single random element.
		  // The internal `guard` argument allows it to work with `map`.
		  _.sample = function (obj, n, guard) {
		    if (n == null || guard) {
		      if (!isArrayLike(obj)) obj = _.values(obj);
		      return obj[_.random(obj.length - 1)];
		    }
		    return _.shuffle(obj).slice(0, Math.max(0, n));
		  };
	
		  // Sort the object's values by a criterion produced by an iteratee.
		  _.sortBy = function (obj, iteratee, context) {
		    iteratee = cb(iteratee, context);
		    return _.pluck(_.map(obj, function (value, index, list) {
		      return {
		        value: value,
		        index: index,
		        criteria: iteratee(value, index, list)
		      };
		    }).sort(function (left, right) {
		      var a = left.criteria;
		      var b = right.criteria;
		      if (a !== b) {
		        if (a > b || a === void 0) return 1;
		        if (a < b || b === void 0) return -1;
		      }
		      return left.index - right.index;
		    }), 'value');
		  };
	
		  // An internal function used for aggregate "group by" operations.
		  var group = function (behavior) {
		    return function (obj, iteratee, context) {
		      var result = {};
		      iteratee = cb(iteratee, context);
		      _.each(obj, function (value, index) {
		        var key = iteratee(value, index, obj);
		        behavior(result, value, key);
		      });
		      return result;
		    };
		  };
	
		  // Groups the object's values by a criterion. Pass either a string attribute
		  // to group by, or a function that returns the criterion.
		  _.groupBy = group(function (result, value, key) {
		    if (_.has(result, key)) result[key].push(value);else result[key] = [value];
		  });
	
		  // Indexes the object's values by a criterion, similar to `groupBy`, but for
		  // when you know that your index values will be unique.
		  _.indexBy = group(function (result, value, key) {
		    result[key] = value;
		  });
	
		  // Counts instances of an object that group by a certain criterion. Pass
		  // either a string attribute to count by, or a function that returns the
		  // criterion.
		  _.countBy = group(function (result, value, key) {
		    if (_.has(result, key)) result[key]++;else result[key] = 1;
		  });
	
		  // Safely create a real, live array from anything iterable.
		  _.toArray = function (obj) {
		    if (!obj) return [];
		    if (_.isArray(obj)) return slice.call(obj);
		    if (isArrayLike(obj)) return _.map(obj, _.identity);
		    return _.values(obj);
		  };
	
		  // Return the number of elements in an object.
		  _.size = function (obj) {
		    if (obj == null) return 0;
		    return isArrayLike(obj) ? obj.length : _.keys(obj).length;
		  };
	
		  // Split a collection into two arrays: one whose elements all satisfy the given
		  // predicate, and one whose elements all do not satisfy the predicate.
		  _.partition = function (obj, predicate, context) {
		    predicate = cb(predicate, context);
		    var pass = [],
		        fail = [];
		    _.each(obj, function (value, key, obj) {
		      (predicate(value, key, obj) ? pass : fail).push(value);
		    });
		    return [pass, fail];
		  };
	
		  // Array Functions
		  // ---------------
	
		  // Get the first element of an array. Passing **n** will return the first N
		  // values in the array. Aliased as `head` and `take`. The **guard** check
		  // allows it to work with `_.map`.
		  _.first = _.head = _.take = function (array, n, guard) {
		    if (array == null) return void 0;
		    if (n == null || guard) return array[0];
		    return _.initial(array, array.length - n);
		  };
	
		  // Returns everything but the last entry of the array. Especially useful on
		  // the arguments object. Passing **n** will return all the values in
		  // the array, excluding the last N.
		  _.initial = function (array, n, guard) {
		    return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
		  };
	
		  // Get the last element of an array. Passing **n** will return the last N
		  // values in the array.
		  _.last = function (array, n, guard) {
		    if (array == null) return void 0;
		    if (n == null || guard) return array[array.length - 1];
		    return _.rest(array, Math.max(0, array.length - n));
		  };
	
		  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
		  // Especially useful on the arguments object. Passing an **n** will return
		  // the rest N values in the array.
		  _.rest = _.tail = _.drop = function (array, n, guard) {
		    return slice.call(array, n == null || guard ? 1 : n);
		  };
	
		  // Trim out all falsy values from an array.
		  _.compact = function (array) {
		    return _.filter(array, _.identity);
		  };
	
		  // Internal implementation of a recursive `flatten` function.
		  var flatten = function (input, shallow, strict, startIndex) {
		    var output = [],
		        idx = 0;
		    for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
		      var value = input[i];
		      if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
		        //flatten current level of array or arguments object
		        if (!shallow) value = flatten(value, shallow, strict);
		        var j = 0,
		            len = value.length;
		        output.length += len;
		        while (j < len) {
		          output[idx++] = value[j++];
		        }
		      } else if (!strict) {
		        output[idx++] = value;
		      }
		    }
		    return output;
		  };
	
		  // Flatten out an array, either recursively (by default), or just one level.
		  _.flatten = function (array, shallow) {
		    return flatten(array, shallow, false);
		  };
	
		  // Return a version of the array that does not contain the specified value(s).
		  _.without = function (array) {
		    return _.difference(array, slice.call(arguments, 1));
		  };
	
		  // Produce a duplicate-free version of the array. If the array has already
		  // been sorted, you have the option of using a faster algorithm.
		  // Aliased as `unique`.
		  _.uniq = _.unique = function (array, isSorted, iteratee, context) {
		    if (!_.isBoolean(isSorted)) {
		      context = iteratee;
		      iteratee = isSorted;
		      isSorted = false;
		    }
		    if (iteratee != null) iteratee = cb(iteratee, context);
		    var result = [];
		    var seen = [];
		    for (var i = 0, length = getLength(array); i < length; i++) {
		      var value = array[i],
		          computed = iteratee ? iteratee(value, i, array) : value;
		      if (isSorted) {
		        if (!i || seen !== computed) result.push(value);
		        seen = computed;
		      } else if (iteratee) {
		        if (!_.contains(seen, computed)) {
		          seen.push(computed);
		          result.push(value);
		        }
		      } else if (!_.contains(result, value)) {
		        result.push(value);
		      }
		    }
		    return result;
		  };
	
		  // Produce an array that contains the union: each distinct element from all of
		  // the passed-in arrays.
		  _.union = function () {
		    return _.uniq(flatten(arguments, true, true));
		  };
	
		  // Produce an array that contains every item shared between all the
		  // passed-in arrays.
		  _.intersection = function (array) {
		    var result = [];
		    var argsLength = arguments.length;
		    for (var i = 0, length = getLength(array); i < length; i++) {
		      var item = array[i];
		      if (_.contains(result, item)) continue;
		      for (var j = 1; j < argsLength; j++) {
		        if (!_.contains(arguments[j], item)) break;
		      }
		      if (j === argsLength) result.push(item);
		    }
		    return result;
		  };
	
		  // Take the difference between one array and a number of other arrays.
		  // Only the elements present in just the first array will remain.
		  _.difference = function (array) {
		    var rest = flatten(arguments, true, true, 1);
		    return _.filter(array, function (value) {
		      return !_.contains(rest, value);
		    });
		  };
	
		  // Zip together multiple lists into a single array -- elements that share
		  // an index go together.
		  _.zip = function () {
		    return _.unzip(arguments);
		  };
	
		  // Complement of _.zip. Unzip accepts an array of arrays and groups
		  // each array's elements on shared indices
		  _.unzip = function (array) {
		    var length = array && _.max(array, getLength).length || 0;
		    var result = Array(length);
	
		    for (var index = 0; index < length; index++) {
		      result[index] = _.pluck(array, index);
		    }
		    return result;
		  };
	
		  // Converts lists into objects. Pass either a single array of `[key, value]`
		  // pairs, or two parallel arrays of the same length -- one of keys, and one of
		  // the corresponding values.
		  _.object = function (list, values) {
		    var result = {};
		    for (var i = 0, length = getLength(list); i < length; i++) {
		      if (values) {
		        result[list[i]] = values[i];
		      } else {
		        result[list[i][0]] = list[i][1];
		      }
		    }
		    return result;
		  };
	
		  // Generator function to create the findIndex and findLastIndex functions
		  function createPredicateIndexFinder(dir) {
		    return function (array, predicate, context) {
		      predicate = cb(predicate, context);
		      var length = getLength(array);
		      var index = dir > 0 ? 0 : length - 1;
		      for (; index >= 0 && index < length; index += dir) {
		        if (predicate(array[index], index, array)) return index;
		      }
		      return -1;
		    };
		  }
	
		  // Returns the first index on an array-like that passes a predicate test
		  _.findIndex = createPredicateIndexFinder(1);
		  _.findLastIndex = createPredicateIndexFinder(-1);
	
		  // Use a comparator function to figure out the smallest index at which
		  // an object should be inserted so as to maintain order. Uses binary search.
		  _.sortedIndex = function (array, obj, iteratee, context) {
		    iteratee = cb(iteratee, context, 1);
		    var value = iteratee(obj);
		    var low = 0,
		        high = getLength(array);
		    while (low < high) {
		      var mid = Math.floor((low + high) / 2);
		      if (iteratee(array[mid]) < value) low = mid + 1;else high = mid;
		    }
		    return low;
		  };
	
		  // Generator function to create the indexOf and lastIndexOf functions
		  function createIndexFinder(dir, predicateFind, sortedIndex) {
		    return function (array, item, idx) {
		      var i = 0,
		          length = getLength(array);
		      if (typeof idx == 'number') {
		        if (dir > 0) {
		          i = idx >= 0 ? idx : Math.max(idx + length, i);
		        } else {
		          length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
		        }
		      } else if (sortedIndex && idx && length) {
		        idx = sortedIndex(array, item);
		        return array[idx] === item ? idx : -1;
		      }
		      if (item !== item) {
		        idx = predicateFind(slice.call(array, i, length), _.isNaN);
		        return idx >= 0 ? idx + i : -1;
		      }
		      for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
		        if (array[idx] === item) return idx;
		      }
		      return -1;
		    };
		  }
	
		  // Return the position of the first occurrence of an item in an array,
		  // or -1 if the item is not included in the array.
		  // If the array is large and already in sort order, pass `true`
		  // for **isSorted** to use binary search.
		  _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
		  _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
	
		  // Generate an integer Array containing an arithmetic progression. A port of
		  // the native Python `range()` function. See
		  // [the Python documentation](http://docs.python.org/library/functions.html#range).
		  _.range = function (start, stop, step) {
		    if (stop == null) {
		      stop = start || 0;
		      start = 0;
		    }
		    step = step || 1;
	
		    var length = Math.max(Math.ceil((stop - start) / step), 0);
		    var range = Array(length);
	
		    for (var idx = 0; idx < length; idx++, start += step) {
		      range[idx] = start;
		    }
	
		    return range;
		  };
	
		  // Function (ahem) Functions
		  // ------------------
	
		  // Determines whether to execute a function as a constructor
		  // or a normal function with the provided arguments
		  var executeBound = function (sourceFunc, boundFunc, context, callingContext, args) {
		    if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
		    var self = baseCreate(sourceFunc.prototype);
		    var result = sourceFunc.apply(self, args);
		    if (_.isObject(result)) return result;
		    return self;
		  };
	
		  // Create a function bound to a given object (assigning `this`, and arguments,
		  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
		  // available.
		  _.bind = function (func, context) {
		    if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
		    if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
		    var args = slice.call(arguments, 2);
		    var bound = function () {
		      return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
		    };
		    return bound;
		  };
	
		  // Partially apply a function by creating a version that has had some of its
		  // arguments pre-filled, without changing its dynamic `this` context. _ acts
		  // as a placeholder, allowing any combination of arguments to be pre-filled.
		  _.partial = function (func) {
		    var boundArgs = slice.call(arguments, 1);
		    var bound = function () {
		      var position = 0,
		          length = boundArgs.length;
		      var args = Array(length);
		      for (var i = 0; i < length; i++) {
		        args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
		      }
		      while (position < arguments.length) args.push(arguments[position++]);
		      return executeBound(func, bound, this, this, args);
		    };
		    return bound;
		  };
	
		  // Bind a number of an object's methods to that object. Remaining arguments
		  // are the method names to be bound. Useful for ensuring that all callbacks
		  // defined on an object belong to it.
		  _.bindAll = function (obj) {
		    var i,
		        length = arguments.length,
		        key;
		    if (length <= 1) throw new Error('bindAll must be passed function names');
		    for (i = 1; i < length; i++) {
		      key = arguments[i];
		      obj[key] = _.bind(obj[key], obj);
		    }
		    return obj;
		  };
	
		  // Memoize an expensive function by storing its results.
		  _.memoize = function (func, hasher) {
		    var memoize = function (key) {
		      var cache = memoize.cache;
		      var address = '' + (hasher ? hasher.apply(this, arguments) : key);
		      if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
		      return cache[address];
		    };
		    memoize.cache = {};
		    return memoize;
		  };
	
		  // Delays a function for the given number of milliseconds, and then calls
		  // it with the arguments supplied.
		  _.delay = function (func, wait) {
		    var args = slice.call(arguments, 2);
		    return setTimeout(function () {
		      return func.apply(null, args);
		    }, wait);
		  };
	
		  // Defers a function, scheduling it to run after the current call stack has
		  // cleared.
		  _.defer = _.partial(_.delay, _, 1);
	
		  // Returns a function, that, when invoked, will only be triggered at most once
		  // during a given window of time. Normally, the throttled function will run
		  // as much as it can, without ever going more than once per `wait` duration;
		  // but if you'd like to disable the execution on the leading edge, pass
		  // `{leading: false}`. To disable execution on the trailing edge, ditto.
		  _.throttle = function (func, wait, options) {
		    var context, args, result;
		    var timeout = null;
		    var previous = 0;
		    if (!options) options = {};
		    var later = function () {
		      previous = options.leading === false ? 0 : _.now();
		      timeout = null;
		      result = func.apply(context, args);
		      if (!timeout) context = args = null;
		    };
		    return function () {
		      var now = _.now();
		      if (!previous && options.leading === false) previous = now;
		      var remaining = wait - (now - previous);
		      context = this;
		      args = arguments;
		      if (remaining <= 0 || remaining > wait) {
		        if (timeout) {
		          clearTimeout(timeout);
		          timeout = null;
		        }
		        previous = now;
		        result = func.apply(context, args);
		        if (!timeout) context = args = null;
		      } else if (!timeout && options.trailing !== false) {
		        timeout = setTimeout(later, remaining);
		      }
		      return result;
		    };
		  };
	
		  // Returns a function, that, as long as it continues to be invoked, will not
		  // be triggered. The function will be called after it stops being called for
		  // N milliseconds. If `immediate` is passed, trigger the function on the
		  // leading edge, instead of the trailing.
		  _.debounce = function (func, wait, immediate) {
		    var timeout, args, context, timestamp, result;
	
		    var later = function () {
		      var last = _.now() - timestamp;
	
		      if (last < wait && last >= 0) {
		        timeout = setTimeout(later, wait - last);
		      } else {
		        timeout = null;
		        if (!immediate) {
		          result = func.apply(context, args);
		          if (!timeout) context = args = null;
		        }
		      }
		    };
	
		    return function () {
		      context = this;
		      args = arguments;
		      timestamp = _.now();
		      var callNow = immediate && !timeout;
		      if (!timeout) timeout = setTimeout(later, wait);
		      if (callNow) {
		        result = func.apply(context, args);
		        context = args = null;
		      }
	
		      return result;
		    };
		  };
	
		  // Returns the first function passed as an argument to the second,
		  // allowing you to adjust arguments, run code before and after, and
		  // conditionally execute the original function.
		  _.wrap = function (func, wrapper) {
		    return _.partial(wrapper, func);
		  };
	
		  // Returns a negated version of the passed-in predicate.
		  _.negate = function (predicate) {
		    return function () {
		      return !predicate.apply(this, arguments);
		    };
		  };
	
		  // Returns a function that is the composition of a list of functions, each
		  // consuming the return value of the function that follows.
		  _.compose = function () {
		    var args = arguments;
		    var start = args.length - 1;
		    return function () {
		      var i = start;
		      var result = args[start].apply(this, arguments);
		      while (i--) result = args[i].call(this, result);
		      return result;
		    };
		  };
	
		  // Returns a function that will only be executed on and after the Nth call.
		  _.after = function (times, func) {
		    return function () {
		      if (--times < 1) {
		        return func.apply(this, arguments);
		      }
		    };
		  };
	
		  // Returns a function that will only be executed up to (but not including) the Nth call.
		  _.before = function (times, func) {
		    var memo;
		    return function () {
		      if (--times > 0) {
		        memo = func.apply(this, arguments);
		      }
		      if (times <= 1) func = null;
		      return memo;
		    };
		  };
	
		  // Returns a function that will be executed at most one time, no matter how
		  // often you call it. Useful for lazy initialization.
		  _.once = _.partial(_.before, 2);
	
		  // Object Functions
		  // ----------------
	
		  // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
		  var hasEnumBug = !{ toString: null }.propertyIsEnumerable('toString');
		  var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
	
		  function collectNonEnumProps(obj, keys) {
		    var nonEnumIdx = nonEnumerableProps.length;
		    var constructor = obj.constructor;
		    var proto = _.isFunction(constructor) && constructor.prototype || ObjProto;
	
		    // Constructor is a special case.
		    var prop = 'constructor';
		    if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
	
		    while (nonEnumIdx--) {
		      prop = nonEnumerableProps[nonEnumIdx];
		      if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
		        keys.push(prop);
		      }
		    }
		  }
	
		  // Retrieve the names of an object's own properties.
		  // Delegates to **ECMAScript 5**'s native `Object.keys`
		  _.keys = function (obj) {
		    if (!_.isObject(obj)) return [];
		    if (nativeKeys) return nativeKeys(obj);
		    var keys = [];
		    for (var key in obj) if (_.has(obj, key)) keys.push(key);
		    // Ahem, IE < 9.
		    if (hasEnumBug) collectNonEnumProps(obj, keys);
		    return keys;
		  };
	
		  // Retrieve all the property names of an object.
		  _.allKeys = function (obj) {
		    if (!_.isObject(obj)) return [];
		    var keys = [];
		    for (var key in obj) keys.push(key);
		    // Ahem, IE < 9.
		    if (hasEnumBug) collectNonEnumProps(obj, keys);
		    return keys;
		  };
	
		  // Retrieve the values of an object's properties.
		  _.values = function (obj) {
		    var keys = _.keys(obj);
		    var length = keys.length;
		    var values = Array(length);
		    for (var i = 0; i < length; i++) {
		      values[i] = obj[keys[i]];
		    }
		    return values;
		  };
	
		  // Returns the results of applying the iteratee to each element of the object
		  // In contrast to _.map it returns an object
		  _.mapObject = function (obj, iteratee, context) {
		    iteratee = cb(iteratee, context);
		    var keys = _.keys(obj),
		        length = keys.length,
		        results = {},
		        currentKey;
		    for (var index = 0; index < length; index++) {
		      currentKey = keys[index];
		      results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
		    }
		    return results;
		  };
	
		  // Convert an object into a list of `[key, value]` pairs.
		  _.pairs = function (obj) {
		    var keys = _.keys(obj);
		    var length = keys.length;
		    var pairs = Array(length);
		    for (var i = 0; i < length; i++) {
		      pairs[i] = [keys[i], obj[keys[i]]];
		    }
		    return pairs;
		  };
	
		  // Invert the keys and values of an object. The values must be serializable.
		  _.invert = function (obj) {
		    var result = {};
		    var keys = _.keys(obj);
		    for (var i = 0, length = keys.length; i < length; i++) {
		      result[obj[keys[i]]] = keys[i];
		    }
		    return result;
		  };
	
		  // Return a sorted list of the function names available on the object.
		  // Aliased as `methods`
		  _.functions = _.methods = function (obj) {
		    var names = [];
		    for (var key in obj) {
		      if (_.isFunction(obj[key])) names.push(key);
		    }
		    return names.sort();
		  };
	
		  // Extend a given object with all the properties in passed-in object(s).
		  _.extend = createAssigner(_.allKeys);
	
		  // Assigns a given object with all the own properties in the passed-in object(s)
		  // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
		  _.extendOwn = _.assign = createAssigner(_.keys);
	
		  // Returns the first key on an object that passes a predicate test
		  _.findKey = function (obj, predicate, context) {
		    predicate = cb(predicate, context);
		    var keys = _.keys(obj),
		        key;
		    for (var i = 0, length = keys.length; i < length; i++) {
		      key = keys[i];
		      if (predicate(obj[key], key, obj)) return key;
		    }
		  };
	
		  // Return a copy of the object only containing the whitelisted properties.
		  _.pick = function (object, oiteratee, context) {
		    var result = {},
		        obj = object,
		        iteratee,
		        keys;
		    if (obj == null) return result;
		    if (_.isFunction(oiteratee)) {
		      keys = _.allKeys(obj);
		      iteratee = optimizeCb(oiteratee, context);
		    } else {
		      keys = flatten(arguments, false, false, 1);
		      iteratee = function (value, key, obj) {
		        return key in obj;
		      };
		      obj = Object(obj);
		    }
		    for (var i = 0, length = keys.length; i < length; i++) {
		      var key = keys[i];
		      var value = obj[key];
		      if (iteratee(value, key, obj)) result[key] = value;
		    }
		    return result;
		  };
	
		  // Return a copy of the object without the blacklisted properties.
		  _.omit = function (obj, iteratee, context) {
		    if (_.isFunction(iteratee)) {
		      iteratee = _.negate(iteratee);
		    } else {
		      var keys = _.map(flatten(arguments, false, false, 1), String);
		      iteratee = function (value, key) {
		        return !_.contains(keys, key);
		      };
		    }
		    return _.pick(obj, iteratee, context);
		  };
	
		  // Fill in a given object with default properties.
		  _.defaults = createAssigner(_.allKeys, true);
	
		  // Creates an object that inherits from the given prototype object.
		  // If additional properties are provided then they will be added to the
		  // created object.
		  _.create = function (prototype, props) {
		    var result = baseCreate(prototype);
		    if (props) _.extendOwn(result, props);
		    return result;
		  };
	
		  // Create a (shallow-cloned) duplicate of an object.
		  _.clone = function (obj) {
		    if (!_.isObject(obj)) return obj;
		    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
		  };
	
		  // Invokes interceptor with the obj, and then returns obj.
		  // The primary purpose of this method is to "tap into" a method chain, in
		  // order to perform operations on intermediate results within the chain.
		  _.tap = function (obj, interceptor) {
		    interceptor(obj);
		    return obj;
		  };
	
		  // Returns whether an object has a given set of `key:value` pairs.
		  _.isMatch = function (object, attrs) {
		    var keys = _.keys(attrs),
		        length = keys.length;
		    if (object == null) return !length;
		    var obj = Object(object);
		    for (var i = 0; i < length; i++) {
		      var key = keys[i];
		      if (attrs[key] !== obj[key] || !(key in obj)) return false;
		    }
		    return true;
		  };
	
		  // Internal recursive comparison function for `isEqual`.
		  var eq = function (a, b, aStack, bStack) {
		    // Identical objects are equal. `0 === -0`, but they aren't identical.
		    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
		    if (a === b) return a !== 0 || 1 / a === 1 / b;
		    // A strict comparison is necessary because `null == undefined`.
		    if (a == null || b == null) return a === b;
		    // Unwrap any wrapped objects.
		    if (a instanceof _) a = a._wrapped;
		    if (b instanceof _) b = b._wrapped;
		    // Compare `[[Class]]` names.
		    var className = toString.call(a);
		    if (className !== toString.call(b)) return false;
		    switch (className) {
		      // Strings, numbers, regular expressions, dates, and booleans are compared by value.
		      case '[object RegExp]':
		      // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
		      case '[object String]':
		        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
		        // equivalent to `new String("5")`.
		        return '' + a === '' + b;
		      case '[object Number]':
		        // `NaN`s are equivalent, but non-reflexive.
		        // Object(NaN) is equivalent to NaN
		        if (+a !== +a) return +b !== +b;
		        // An `egal` comparison is performed for other numeric values.
		        return +a === 0 ? 1 / +a === 1 / b : +a === +b;
		      case '[object Date]':
		      case '[object Boolean]':
		        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
		        // millisecond representations. Note that invalid dates with millisecond representations
		        // of `NaN` are not equivalent.
		        return +a === +b;
		    }
	
		    var areArrays = className === '[object Array]';
		    if (!areArrays) {
		      if (typeof a != 'object' || typeof b != 'object') return false;
	
		      // Objects with different constructors are not equivalent, but `Object`s or `Array`s
		      // from different frames are.
		      var aCtor = a.constructor,
		          bCtor = b.constructor;
		      if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && _.isFunction(bCtor) && bCtor instanceof bCtor) && 'constructor' in a && 'constructor' in b) {
		        return false;
		      }
		    }
		    // Assume equality for cyclic structures. The algorithm for detecting cyclic
		    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
	
		    // Initializing stack of traversed objects.
		    // It's done here since we only need them for objects and arrays comparison.
		    aStack = aStack || [];
		    bStack = bStack || [];
		    var length = aStack.length;
		    while (length--) {
		      // Linear search. Performance is inversely proportional to the number of
		      // unique nested structures.
		      if (aStack[length] === a) return bStack[length] === b;
		    }
	
		    // Add the first object to the stack of traversed objects.
		    aStack.push(a);
		    bStack.push(b);
	
		    // Recursively compare objects and arrays.
		    if (areArrays) {
		      // Compare array lengths to determine if a deep comparison is necessary.
		      length = a.length;
		      if (length !== b.length) return false;
		      // Deep compare the contents, ignoring non-numeric properties.
		      while (length--) {
		        if (!eq(a[length], b[length], aStack, bStack)) return false;
		      }
		    } else {
		      // Deep compare objects.
		      var keys = _.keys(a),
		          key;
		      length = keys.length;
		      // Ensure that both objects contain the same number of properties before comparing deep equality.
		      if (_.keys(b).length !== length) return false;
		      while (length--) {
		        // Deep compare each member
		        key = keys[length];
		        if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
		      }
		    }
		    // Remove the first object from the stack of traversed objects.
		    aStack.pop();
		    bStack.pop();
		    return true;
		  };
	
		  // Perform a deep comparison to check if two objects are equal.
		  _.isEqual = function (a, b) {
		    return eq(a, b);
		  };
	
		  // Is a given array, string, or object empty?
		  // An "empty" object has no enumerable own-properties.
		  _.isEmpty = function (obj) {
		    if (obj == null) return true;
		    if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
		    return _.keys(obj).length === 0;
		  };
	
		  // Is a given value a DOM element?
		  _.isElement = function (obj) {
		    return !!(obj && obj.nodeType === 1);
		  };
	
		  // Is a given value an array?
		  // Delegates to ECMA5's native Array.isArray
		  _.isArray = nativeIsArray || function (obj) {
		    return toString.call(obj) === '[object Array]';
		  };
	
		  // Is a given variable an object?
		  _.isObject = function (obj) {
		    var type = typeof obj;
		    return type === 'function' || type === 'object' && !!obj;
		  };
	
		  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
		  _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function (name) {
		    _['is' + name] = function (obj) {
		      return toString.call(obj) === '[object ' + name + ']';
		    };
		  });
	
		  // Define a fallback version of the method in browsers (ahem, IE < 9), where
		  // there isn't any inspectable "Arguments" type.
		  if (!_.isArguments(arguments)) {
		    _.isArguments = function (obj) {
		      return _.has(obj, 'callee');
		    };
		  }
	
		  // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
		  // IE 11 (#1621), and in Safari 8 (#1929).
		  if (typeof /./ != 'function' && typeof Int8Array != 'object') {
		    _.isFunction = function (obj) {
		      return typeof obj == 'function' || false;
		    };
		  }
	
		  // Is a given object a finite number?
		  _.isFinite = function (obj) {
		    return isFinite(obj) && !isNaN(parseFloat(obj));
		  };
	
		  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
		  _.isNaN = function (obj) {
		    return _.isNumber(obj) && obj !== +obj;
		  };
	
		  // Is a given value a boolean?
		  _.isBoolean = function (obj) {
		    return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
		  };
	
		  // Is a given value equal to null?
		  _.isNull = function (obj) {
		    return obj === null;
		  };
	
		  // Is a given variable undefined?
		  _.isUndefined = function (obj) {
		    return obj === void 0;
		  };
	
		  // Shortcut function for checking if an object has a given property directly
		  // on itself (in other words, not on a prototype).
		  _.has = function (obj, key) {
		    return obj != null && hasOwnProperty.call(obj, key);
		  };
	
		  // Utility Functions
		  // -----------------
	
		  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
		  // previous owner. Returns a reference to the Underscore object.
		  _.noConflict = function () {
		    root._ = previousUnderscore;
		    return this;
		  };
	
		  // Keep the identity function around for default iteratees.
		  _.identity = function (value) {
		    return value;
		  };
	
		  // Predicate-generating functions. Often useful outside of Underscore.
		  _.constant = function (value) {
		    return function () {
		      return value;
		    };
		  };
	
		  _.noop = function () {};
	
		  _.property = property;
	
		  // Generates a function for a given object that returns a given property.
		  _.propertyOf = function (obj) {
		    return obj == null ? function () {} : function (key) {
		      return obj[key];
		    };
		  };
	
		  // Returns a predicate for checking whether an object has a given set of
		  // `key:value` pairs.
		  _.matcher = _.matches = function (attrs) {
		    attrs = _.extendOwn({}, attrs);
		    return function (obj) {
		      return _.isMatch(obj, attrs);
		    };
		  };
	
		  // Run a function **n** times.
		  _.times = function (n, iteratee, context) {
		    var accum = Array(Math.max(0, n));
		    iteratee = optimizeCb(iteratee, context, 1);
		    for (var i = 0; i < n; i++) accum[i] = iteratee(i);
		    return accum;
		  };
	
		  // Return a random integer between min and max (inclusive).
		  _.random = function (min, max) {
		    if (max == null) {
		      max = min;
		      min = 0;
		    }
		    return min + Math.floor(Math.random() * (max - min + 1));
		  };
	
		  // A (possibly faster) way to get the current timestamp as an integer.
		  _.now = Date.now || function () {
		    return new Date().getTime();
		  };
	
		  // List of HTML entities for escaping.
		  var escapeMap = {
		    '&': '&amp;',
		    '<': '&lt;',
		    '>': '&gt;',
		    '"': '&quot;',
		    "'": '&#x27;',
		    '`': '&#x60;'
		  };
		  var unescapeMap = _.invert(escapeMap);
	
		  // Functions for escaping and unescaping strings to/from HTML interpolation.
		  var createEscaper = function (map) {
		    var escaper = function (match) {
		      return map[match];
		    };
		    // Regexes for identifying a key that needs to be escaped
		    var source = '(?:' + _.keys(map).join('|') + ')';
		    var testRegexp = RegExp(source);
		    var replaceRegexp = RegExp(source, 'g');
		    return function (string) {
		      string = string == null ? '' : '' + string;
		      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
		    };
		  };
		  _.escape = createEscaper(escapeMap);
		  _.unescape = createEscaper(unescapeMap);
	
		  // If the value of the named `property` is a function then invoke it with the
		  // `object` as context; otherwise, return it.
		  _.result = function (object, property, fallback) {
		    var value = object == null ? void 0 : object[property];
		    if (value === void 0) {
		      value = fallback;
		    }
		    return _.isFunction(value) ? value.call(object) : value;
		  };
	
		  // Generate a unique integer id (unique within the entire client session).
		  // Useful for temporary DOM ids.
		  var idCounter = 0;
		  _.uniqueId = function (prefix) {
		    var id = ++idCounter + '';
		    return prefix ? prefix + id : id;
		  };
	
		  // By default, Underscore uses ERB-style template delimiters, change the
		  // following template settings to use alternative delimiters.
		  _.templateSettings = {
		    evaluate: /<%([\s\S]+?)%>/g,
		    interpolate: /<%=([\s\S]+?)%>/g,
		    escape: /<%-([\s\S]+?)%>/g
		  };
	
		  // When customizing `templateSettings`, if you don't want to define an
		  // interpolation, evaluation or escaping regex, we need one that is
		  // guaranteed not to match.
		  var noMatch = /(.)^/;
	
		  // Certain characters need to be escaped so that they can be put into a
		  // string literal.
		  var escapes = {
		    "'": "'",
		    '\\': '\\',
		    '\r': 'r',
		    '\n': 'n',
		    '\u2028': 'u2028',
		    '\u2029': 'u2029'
		  };
	
		  var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
	
		  var escapeChar = function (match) {
		    return '\\' + escapes[match];
		  };
	
		  // JavaScript micro-templating, similar to John Resig's implementation.
		  // Underscore templating handles arbitrary delimiters, preserves whitespace,
		  // and correctly escapes quotes within interpolated code.
		  // NB: `oldSettings` only exists for backwards compatibility.
		  _.template = function (text, settings, oldSettings) {
		    if (!settings && oldSettings) settings = oldSettings;
		    settings = _.defaults({}, settings, _.templateSettings);
	
		    // Combine delimiters into one regular expression via alternation.
		    var matcher = RegExp([(settings.escape || noMatch).source, (settings.interpolate || noMatch).source, (settings.evaluate || noMatch).source].join('|') + '|$', 'g');
	
		    // Compile the template source, escaping string literals appropriately.
		    var index = 0;
		    var source = "__p+='";
		    text.replace(matcher, function (match, escape, interpolate, evaluate, offset) {
		      source += text.slice(index, offset).replace(escaper, escapeChar);
		      index = offset + match.length;
	
		      if (escape) {
		        source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
		      } else if (interpolate) {
		        source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
		      } else if (evaluate) {
		        source += "';\n" + evaluate + "\n__p+='";
		      }
	
		      // Adobe VMs need the match returned to produce the correct offest.
		      return match;
		    });
		    source += "';\n";
	
		    // If a variable is not specified, place data values in local scope.
		    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
	
		    source = "var __t,__p='',__j=Array.prototype.join," + "print=function(){__p+=__j.call(arguments,'');};\n" + source + 'return __p;\n';
	
		    try {
		      var render = new Function(settings.variable || 'obj', '_', source);
		    } catch (e) {
		      e.source = source;
		      throw e;
		    }
	
		    var template = function (data) {
		      return render.call(this, data, _);
		    };
	
		    // Provide the compiled source as a convenience for precompilation.
		    var argument = settings.variable || 'obj';
		    template.source = 'function(' + argument + '){\n' + source + '}';
	
		    return template;
		  };
	
		  // Add a "chain" function. Start chaining a wrapped Underscore object.
		  _.chain = function (obj) {
		    var instance = _(obj);
		    instance._chain = true;
		    return instance;
		  };
	
		  // OOP
		  // ---------------
		  // If Underscore is called as a function, it returns a wrapped object that
		  // can be used OO-style. This wrapper holds altered versions of all the
		  // underscore functions. Wrapped objects may be chained.
	
		  // Helper function to continue chaining intermediate results.
		  var result = function (instance, obj) {
		    return instance._chain ? _(obj).chain() : obj;
		  };
	
		  // Add your own custom functions to the Underscore object.
		  _.mixin = function (obj) {
		    _.each(_.functions(obj), function (name) {
		      var func = _[name] = obj[name];
		      _.prototype[name] = function () {
		        var args = [this._wrapped];
		        push.apply(args, arguments);
		        return result(this, func.apply(_, args));
		      };
		    });
		  };
	
		  // Add all of the Underscore functions to the wrapper object.
		  _.mixin(_);
	
		  // Add all mutator Array functions to the wrapper.
		  _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function (name) {
		    var method = ArrayProto[name];
		    _.prototype[name] = function () {
		      var obj = this._wrapped;
		      method.apply(obj, arguments);
		      if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
		      return result(this, obj);
		    };
		  });
	
		  // Add all accessor Array functions to the wrapper.
		  _.each(['concat', 'join', 'slice'], function (name) {
		    var method = ArrayProto[name];
		    _.prototype[name] = function () {
		      return result(this, method.apply(this._wrapped, arguments));
		    };
		  });
	
		  // Extracts the result from a wrapped and chained object.
		  _.prototype.value = function () {
		    return this._wrapped;
		  };
	
		  // Provide unwrapping proxy for some methods used in engine operations
		  // such as arithmetic and JSON stringification.
		  _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
	
		  _.prototype.toString = function () {
		    return '' + this._wrapped;
		  };
	
		  // AMD registration happens at the end for compatibility with AMD loaders
		  // that may not enforce next-turn semantics on modules. Even though general
		  // practice for AMD registration is to be anonymous, underscore registers
		  // as a named module because, like jQuery, it is a base library that is
		  // popular enough to be bundled in a third party lib, but not be part of
		  // an AMD load request. Those cases could generate an error when an
		  // anonymous define() is called outside of a loader request.
		  if (true) {
		    !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () {
		      return _;
		    }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
		  }
		}).call(this);
	
	/***/ }),
	/* 237 */
	/***/ (function(module, exports, __webpack_require__) {
	
		(function (global, factory) {
		   true ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : global.createREGL = factory();
		})(this, function () {
		  'use strict';
	
		  var arrayTypes = {
		    "[object Int8Array]": 5120,
		    "[object Int16Array]": 5122,
		    "[object Int32Array]": 5124,
		    "[object Uint8Array]": 5121,
		    "[object Uint8ClampedArray]": 5121,
		    "[object Uint16Array]": 5123,
		    "[object Uint32Array]": 5125,
		    "[object Float32Array]": 5126,
		    "[object Float64Array]": 5121,
		    "[object ArrayBuffer]": 5121
		  };
	
		  var isTypedArray = function (x) {
		    return Object.prototype.toString.call(x) in arrayTypes;
		  };
	
		  var extend = function (base, opts) {
		    var keys = Object.keys(opts);
		    for (var i = 0; i < keys.length; ++i) {
		      base[keys[i]] = opts[keys[i]];
		    }
		    return base;
		  };
	
		  // Error checking and parameter validation.
		  //
		  // Statements for the form `check.someProcedure(...)` get removed by
		  // a browserify transform for optimized/minified bundles.
		  //
		  /* globals btoa */
		  // only used for extracting shader names.  if btoa not present, then errors
		  // will be slightly crappier
		  function decodeB64(str) {
		    if (typeof btoa !== 'undefined') {
		      return btoa(str);
		    }
		    return 'base64:' + str;
		  }
	
		  function raise(message) {
		    var error = new Error('(regl) ' + message);
		    console.error(error);
		    throw error;
		  }
	
		  function check(pred, message) {
		    if (!pred) {
		      raise(message);
		    }
		  }
	
		  function encolon(message) {
		    if (message) {
		      return ': ' + message;
		    }
		    return '';
		  }
	
		  function checkParameter(param, possibilities, message) {
		    if (!(param in possibilities)) {
		      raise('unknown parameter (' + param + ')' + encolon(message) + '. possible values: ' + Object.keys(possibilities).join());
		    }
		  }
	
		  function checkIsTypedArray(data, message) {
		    if (!isTypedArray(data)) {
		      raise('invalid parameter type' + encolon(message) + '. must be a typed array');
		    }
		  }
	
		  function checkTypeOf(value, type, message) {
		    if (typeof value !== type) {
		      raise('invalid parameter type' + encolon(message) + '. expected ' + type + ', got ' + typeof value);
		    }
		  }
	
		  function checkNonNegativeInt(value, message) {
		    if (!(value >= 0 && (value | 0) === value)) {
		      raise('invalid parameter type, (' + value + ')' + encolon(message) + '. must be a nonnegative integer');
		    }
		  }
	
		  function checkOneOf(value, list, message) {
		    if (list.indexOf(value) < 0) {
		      raise('invalid value' + encolon(message) + '. must be one of: ' + list);
		    }
		  }
	
		  var constructorKeys = ['gl', 'canvas', 'container', 'attributes', 'pixelRatio', 'extensions', 'optionalExtensions', 'profile', 'onDone'];
	
		  function checkConstructor(obj) {
		    Object.keys(obj).forEach(function (key) {
		      if (constructorKeys.indexOf(key) < 0) {
		        raise('invalid regl constructor argument "' + key + '". must be one of ' + constructorKeys);
		      }
		    });
		  }
	
		  function leftPad(str, n) {
		    str = str + '';
		    while (str.length < n) {
		      str = ' ' + str;
		    }
		    return str;
		  }
	
		  function ShaderFile() {
		    this.name = 'unknown';
		    this.lines = [];
		    this.index = {};
		    this.hasErrors = false;
		  }
	
		  function ShaderLine(number, line) {
		    this.number = number;
		    this.line = line;
		    this.errors = [];
		  }
	
		  function ShaderError(fileNumber, lineNumber, message) {
		    this.file = fileNumber;
		    this.line = lineNumber;
		    this.message = message;
		  }
	
		  function guessCommand() {
		    var error = new Error();
		    var stack = (error.stack || error).toString();
		    var pat = /compileProcedure.*\n\s*at.*\((.*)\)/.exec(stack);
		    if (pat) {
		      return pat[1];
		    }
		    var pat2 = /compileProcedure.*\n\s*at\s+(.*)(\n|$)/.exec(stack);
		    if (pat2) {
		      return pat2[1];
		    }
		    return 'unknown';
		  }
	
		  function guessCallSite() {
		    var error = new Error();
		    var stack = (error.stack || error).toString();
		    var pat = /at REGLCommand.*\n\s+at.*\((.*)\)/.exec(stack);
		    if (pat) {
		      return pat[1];
		    }
		    var pat2 = /at REGLCommand.*\n\s+at\s+(.*)\n/.exec(stack);
		    if (pat2) {
		      return pat2[1];
		    }
		    return 'unknown';
		  }
	
		  function parseSource(source, command) {
		    var lines = source.split('\n');
		    var lineNumber = 1;
		    var fileNumber = 0;
		    var files = {
		      unknown: new ShaderFile(),
		      0: new ShaderFile()
		    };
		    files.unknown.name = files[0].name = command || guessCommand();
		    files.unknown.lines.push(new ShaderLine(0, ''));
		    for (var i = 0; i < lines.length; ++i) {
		      var line = lines[i];
		      var parts = /^\s*\#\s*(\w+)\s+(.+)\s*$/.exec(line);
		      if (parts) {
		        switch (parts[1]) {
		          case 'line':
		            var lineNumberInfo = /(\d+)(\s+\d+)?/.exec(parts[2]);
		            if (lineNumberInfo) {
		              lineNumber = lineNumberInfo[1] | 0;
		              if (lineNumberInfo[2]) {
		                fileNumber = lineNumberInfo[2] | 0;
		                if (!(fileNumber in files)) {
		                  files[fileNumber] = new ShaderFile();
		                }
		              }
		            }
		            break;
		          case 'define':
		            var nameInfo = /SHADER_NAME(_B64)?\s+(.*)$/.exec(parts[2]);
		            if (nameInfo) {
		              files[fileNumber].name = nameInfo[1] ? decodeB64(nameInfo[2]) : nameInfo[2];
		            }
		            break;
		        }
		      }
		      files[fileNumber].lines.push(new ShaderLine(lineNumber++, line));
		    }
		    Object.keys(files).forEach(function (fileNumber) {
		      var file = files[fileNumber];
		      file.lines.forEach(function (line) {
		        file.index[line.number] = line;
		      });
		    });
		    return files;
		  }
	
		  function parseErrorLog(errLog) {
		    var result = [];
		    errLog.split('\n').forEach(function (errMsg) {
		      if (errMsg.length < 5) {
		        return;
		      }
		      var parts = /^ERROR\:\s+(\d+)\:(\d+)\:\s*(.*)$/.exec(errMsg);
		      if (parts) {
		        result.push(new ShaderError(parts[1] | 0, parts[2] | 0, parts[3].trim()));
		      } else if (errMsg.length > 0) {
		        result.push(new ShaderError('unknown', 0, errMsg));
		      }
		    });
		    return result;
		  }
	
		  function annotateFiles(files, errors) {
		    errors.forEach(function (error) {
		      var file = files[error.file];
		      if (file) {
		        var line = file.index[error.line];
		        if (line) {
		          line.errors.push(error);
		          file.hasErrors = true;
		          return;
		        }
		      }
		      files.unknown.hasErrors = true;
		      files.unknown.lines[0].errors.push(error);
		    });
		  }
	
		  function checkShaderError(gl, shader, source, type, command) {
		    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
		      var errLog = gl.getShaderInfoLog(shader);
		      var typeName = type === gl.FRAGMENT_SHADER ? 'fragment' : 'vertex';
		      checkCommandType(source, 'string', typeName + ' shader source must be a string', command);
		      var files = parseSource(source, command);
		      var errors = parseErrorLog(errLog);
		      annotateFiles(files, errors);
	
		      Object.keys(files).forEach(function (fileNumber) {
		        var file = files[fileNumber];
		        if (!file.hasErrors) {
		          return;
		        }
	
		        var strings = [''];
		        var styles = [''];
	
		        function push(str, style) {
		          strings.push(str);
		          styles.push(style || '');
		        }
	
		        push('file number ' + fileNumber + ': ' + file.name + '\n', 'color:red;text-decoration:underline;font-weight:bold');
	
		        file.lines.forEach(function (line) {
		          if (line.errors.length > 0) {
		            push(leftPad(line.number, 4) + '|  ', 'background-color:yellow; font-weight:bold');
		            push(line.line + '\n', 'color:red; background-color:yellow; font-weight:bold');
	
		            // try to guess token
		            var offset = 0;
		            line.errors.forEach(function (error) {
		              var message = error.message;
		              var token = /^\s*\'(.*)\'\s*\:\s*(.*)$/.exec(message);
		              if (token) {
		                var tokenPat = token[1];
		                message = token[2];
		                switch (tokenPat) {
		                  case 'assign':
		                    tokenPat = '=';
		                    break;
		                }
		                offset = Math.max(line.line.indexOf(tokenPat, offset), 0);
		              } else {
		                offset = 0;
		              }
	
		              push(leftPad('| ', 6));
		              push(leftPad('^^^', offset + 3) + '\n', 'font-weight:bold');
		              push(leftPad('| ', 6));
		              push(message + '\n', 'font-weight:bold');
		            });
		            push(leftPad('| ', 6) + '\n');
		          } else {
		            push(leftPad(line.number, 4) + '|  ');
		            push(line.line + '\n', 'color:red');
		          }
		        });
		        if (typeof document !== 'undefined') {
		          styles[0] = strings.join('%c');
		          console.log.apply(console, styles);
		        } else {
		          console.log(strings.join(''));
		        }
		      });
	
		      check.raise('Error compiling ' + typeName + ' shader, ' + files[0].name);
		    }
		  }
	
		  function checkLinkError(gl, program, fragShader, vertShader, command) {
		    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
		      var errLog = gl.getProgramInfoLog(program);
		      var fragParse = parseSource(fragShader, command);
		      var vertParse = parseSource(vertShader, command);
	
		      var header = 'Error linking program with vertex shader, "' + vertParse[0].name + '", and fragment shader "' + fragParse[0].name + '"';
	
		      if (typeof document !== 'undefined') {
		        console.log('%c' + header + '\n%c' + errLog, 'color:red;text-decoration:underline;font-weight:bold', 'color:red');
		      } else {
		        console.log(header + '\n' + errLog);
		      }
		      check.raise(header);
		    }
		  }
	
		  function saveCommandRef(object) {
		    object._commandRef = guessCommand();
		  }
	
		  function saveDrawCommandInfo(opts, uniforms, attributes, stringStore) {
		    saveCommandRef(opts);
	
		    function id(str) {
		      if (str) {
		        return stringStore.id(str);
		      }
		      return 0;
		    }
		    opts._fragId = id(opts.static.frag);
		    opts._vertId = id(opts.static.vert);
	
		    function addProps(dict, set) {
		      Object.keys(set).forEach(function (u) {
		        dict[stringStore.id(u)] = true;
		      });
		    }
	
		    var uniformSet = opts._uniformSet = {};
		    addProps(uniformSet, uniforms.static);
		    addProps(uniformSet, uniforms.dynamic);
	
		    var attributeSet = opts._attributeSet = {};
		    addProps(attributeSet, attributes.static);
		    addProps(attributeSet, attributes.dynamic);
	
		    opts._hasCount = 'count' in opts.static || 'count' in opts.dynamic || 'elements' in opts.static || 'elements' in opts.dynamic;
		  }
	
		  function commandRaise(message, command) {
		    var callSite = guessCallSite();
		    raise(message + ' in command ' + (command || guessCommand()) + (callSite === 'unknown' ? '' : ' called from ' + callSite));
		  }
	
		  function checkCommand(pred, message, command) {
		    if (!pred) {
		      commandRaise(message, command || guessCommand());
		    }
		  }
	
		  function checkParameterCommand(param, possibilities, message, command) {
		    if (!(param in possibilities)) {
		      commandRaise('unknown parameter (' + param + ')' + encolon(message) + '. possible values: ' + Object.keys(possibilities).join(), command || guessCommand());
		    }
		  }
	
		  function checkCommandType(value, type, message, command) {
		    if (typeof value !== type) {
		      commandRaise('invalid parameter type' + encolon(message) + '. expected ' + type + ', got ' + typeof value, command || guessCommand());
		    }
		  }
	
		  function checkOptional(block) {
		    block();
		  }
	
		  function checkFramebufferFormat(attachment, texFormats, rbFormats) {
		    if (attachment.texture) {
		      checkOneOf(attachment.texture._texture.internalformat, texFormats, 'unsupported texture format for attachment');
		    } else {
		      checkOneOf(attachment.renderbuffer._renderbuffer.format, rbFormats, 'unsupported renderbuffer format for attachment');
		    }
		  }
	
		  var GL_CLAMP_TO_EDGE = 0x812F;
	
		  var GL_NEAREST = 0x2600;
		  var GL_NEAREST_MIPMAP_NEAREST = 0x2700;
		  var GL_LINEAR_MIPMAP_NEAREST = 0x2701;
		  var GL_NEAREST_MIPMAP_LINEAR = 0x2702;
		  var GL_LINEAR_MIPMAP_LINEAR = 0x2703;
	
		  var GL_BYTE = 5120;
		  var GL_UNSIGNED_BYTE = 5121;
		  var GL_SHORT = 5122;
		  var GL_UNSIGNED_SHORT = 5123;
		  var GL_INT = 5124;
		  var GL_UNSIGNED_INT = 5125;
		  var GL_FLOAT = 5126;
	
		  var GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033;
		  var GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034;
		  var GL_UNSIGNED_SHORT_5_6_5 = 0x8363;
		  var GL_UNSIGNED_INT_24_8_WEBGL = 0x84FA;
	
		  var GL_HALF_FLOAT_OES = 0x8D61;
	
		  var TYPE_SIZE = {};
	
		  TYPE_SIZE[GL_BYTE] = TYPE_SIZE[GL_UNSIGNED_BYTE] = 1;
	
		  TYPE_SIZE[GL_SHORT] = TYPE_SIZE[GL_UNSIGNED_SHORT] = TYPE_SIZE[GL_HALF_FLOAT_OES] = TYPE_SIZE[GL_UNSIGNED_SHORT_5_6_5] = TYPE_SIZE[GL_UNSIGNED_SHORT_4_4_4_4] = TYPE_SIZE[GL_UNSIGNED_SHORT_5_5_5_1] = 2;
	
		  TYPE_SIZE[GL_INT] = TYPE_SIZE[GL_UNSIGNED_INT] = TYPE_SIZE[GL_FLOAT] = TYPE_SIZE[GL_UNSIGNED_INT_24_8_WEBGL] = 4;
	
		  function pixelSize(type, channels) {
		    if (type === GL_UNSIGNED_SHORT_5_5_5_1 || type === GL_UNSIGNED_SHORT_4_4_4_4 || type === GL_UNSIGNED_SHORT_5_6_5) {
		      return 2;
		    } else if (type === GL_UNSIGNED_INT_24_8_WEBGL) {
		      return 4;
		    } else {
		      return TYPE_SIZE[type] * channels;
		    }
		  }
	
		  function isPow2(v) {
		    return !(v & v - 1) && !!v;
		  }
	
		  function checkTexture2D(info, mipData, limits) {
		    var i;
		    var w = mipData.width;
		    var h = mipData.height;
		    var c = mipData.channels;
	
		    // Check texture shape
		    check(w > 0 && w <= limits.maxTextureSize && h > 0 && h <= limits.maxTextureSize, 'invalid texture shape');
	
		    // check wrap mode
		    if (info.wrapS !== GL_CLAMP_TO_EDGE || info.wrapT !== GL_CLAMP_TO_EDGE) {
		      check(isPow2(w) && isPow2(h), 'incompatible wrap mode for texture, both width and height must be power of 2');
		    }
	
		    if (mipData.mipmask === 1) {
		      if (w !== 1 && h !== 1) {
		        check(info.minFilter !== GL_NEAREST_MIPMAP_NEAREST && info.minFilter !== GL_NEAREST_MIPMAP_LINEAR && info.minFilter !== GL_LINEAR_MIPMAP_NEAREST && info.minFilter !== GL_LINEAR_MIPMAP_LINEAR, 'min filter requires mipmap');
		      }
		    } else {
		      // texture must be power of 2
		      check(isPow2(w) && isPow2(h), 'texture must be a square power of 2 to support mipmapping');
		      check(mipData.mipmask === (w << 1) - 1, 'missing or incomplete mipmap data');
		    }
	
		    if (mipData.type === GL_FLOAT) {
		      if (limits.extensions.indexOf('oes_texture_float_linear') < 0) {
		        check(info.minFilter === GL_NEAREST && info.magFilter === GL_NEAREST, 'filter not supported, must enable oes_texture_float_linear');
		      }
		      check(!info.genMipmaps, 'mipmap generation not supported with float textures');
		    }
	
		    // check image complete
		    var mipimages = mipData.images;
		    for (i = 0; i < 16; ++i) {
		      if (mipimages[i]) {
		        var mw = w >> i;
		        var mh = h >> i;
		        check(mipData.mipmask & 1 << i, 'missing mipmap data');
	
		        var img = mipimages[i];
	
		        check(img.width === mw && img.height === mh, 'invalid shape for mip images');
	
		        check(img.format === mipData.format && img.internalformat === mipData.internalformat && img.type === mipData.type, 'incompatible type for mip image');
	
		        if (img.compressed) {
		          // TODO: check size for compressed images
		        } else if (img.data) {
		          // check(img.data.byteLength === mw * mh *
		          // Math.max(pixelSize(img.type, c), img.unpackAlignment),
		          var rowSize = Math.ceil(pixelSize(img.type, c) * mw / img.unpackAlignment) * img.unpackAlignment;
		          check(img.data.byteLength === rowSize * mh, 'invalid data for image, buffer size is inconsistent with image format');
		        } else if (img.element) {
		          // TODO: check element can be loaded
		        } else if (img.copy) {
		          // TODO: check compatible format and type
		        }
		      } else if (!info.genMipmaps) {
		        check((mipData.mipmask & 1 << i) === 0, 'extra mipmap data');
		      }
		    }
	
		    if (mipData.compressed) {
		      check(!info.genMipmaps, 'mipmap generation for compressed images not supported');
		    }
		  }
	
		  function checkTextureCube(texture, info, faces, limits) {
		    var w = texture.width;
		    var h = texture.height;
		    var c = texture.channels;
	
		    // Check texture shape
		    check(w > 0 && w <= limits.maxTextureSize && h > 0 && h <= limits.maxTextureSize, 'invalid texture shape');
		    check(w === h, 'cube map must be square');
		    check(info.wrapS === GL_CLAMP_TO_EDGE && info.wrapT === GL_CLAMP_TO_EDGE, 'wrap mode not supported by cube map');
	
		    for (var i = 0; i < faces.length; ++i) {
		      var face = faces[i];
		      check(face.width === w && face.height === h, 'inconsistent cube map face shape');
	
		      if (info.genMipmaps) {
		        check(!face.compressed, 'can not generate mipmap for compressed textures');
		        check(face.mipmask === 1, 'can not specify mipmaps and generate mipmaps');
		      } else {
		        // TODO: check mip and filter mode
		      }
	
		      var mipmaps = face.images;
		      for (var j = 0; j < 16; ++j) {
		        var img = mipmaps[j];
		        if (img) {
		          var mw = w >> j;
		          var mh = h >> j;
		          check(face.mipmask & 1 << j, 'missing mipmap data');
		          check(img.width === mw && img.height === mh, 'invalid shape for mip images');
		          check(img.format === texture.format && img.internalformat === texture.internalformat && img.type === texture.type, 'incompatible type for mip image');
	
		          if (img.compressed) {
		            // TODO: check size for compressed images
		          } else if (img.data) {
		            check(img.data.byteLength === mw * mh * Math.max(pixelSize(img.type, c), img.unpackAlignment), 'invalid data for image, buffer size is inconsistent with image format');
		          } else if (img.element) {
		            // TODO: check element can be loaded
		          } else if (img.copy) {
		            // TODO: check compatible format and type
		          }
		        }
		      }
		    }
		  }
	
		  var check$1 = extend(check, {
		    optional: checkOptional,
		    raise: raise,
		    commandRaise: commandRaise,
		    command: checkCommand,
		    parameter: checkParameter,
		    commandParameter: checkParameterCommand,
		    constructor: checkConstructor,
		    type: checkTypeOf,
		    commandType: checkCommandType,
		    isTypedArray: checkIsTypedArray,
		    nni: checkNonNegativeInt,
		    oneOf: checkOneOf,
		    shaderError: checkShaderError,
		    linkError: checkLinkError,
		    callSite: guessCallSite,
		    saveCommandRef: saveCommandRef,
		    saveDrawInfo: saveDrawCommandInfo,
		    framebufferFormat: checkFramebufferFormat,
		    guessCommand: guessCommand,
		    texture2D: checkTexture2D,
		    textureCube: checkTextureCube
		  });
	
		  var VARIABLE_COUNTER = 0;
	
		  var DYN_FUNC = 0;
	
		  function DynamicVariable(type, data) {
		    this.id = VARIABLE_COUNTER++;
		    this.type = type;
		    this.data = data;
		  }
	
		  function escapeStr(str) {
		    return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
		  }
	
		  function splitParts(str) {
		    if (str.length === 0) {
		      return [];
		    }
	
		    var firstChar = str.charAt(0);
		    var lastChar = str.charAt(str.length - 1);
	
		    if (str.length > 1 && firstChar === lastChar && (firstChar === '"' || firstChar === "'")) {
		      return ['"' + escapeStr(str.substr(1, str.length - 2)) + '"'];
		    }
	
		    var parts = /\[(false|true|null|\d+|'[^']*'|"[^"]*")\]/.exec(str);
		    if (parts) {
		      return splitParts(str.substr(0, parts.index)).concat(splitParts(parts[1])).concat(splitParts(str.substr(parts.index + parts[0].length)));
		    }
	
		    var subparts = str.split('.');
		    if (subparts.length === 1) {
		      return ['"' + escapeStr(str) + '"'];
		    }
	
		    var result = [];
		    for (var i = 0; i < subparts.length; ++i) {
		      result = result.concat(splitParts(subparts[i]));
		    }
		    return result;
		  }
	
		  function toAccessorString(str) {
		    return '[' + splitParts(str).join('][') + ']';
		  }
	
		  function defineDynamic(type, data) {
		    return new DynamicVariable(type, toAccessorString(data + ''));
		  }
	
		  function isDynamic(x) {
		    return typeof x === 'function' && !x._reglType || x instanceof DynamicVariable;
		  }
	
		  function unbox(x, path) {
		    if (typeof x === 'function') {
		      return new DynamicVariable(DYN_FUNC, x);
		    }
		    return x;
		  }
	
		  var dynamic = {
		    DynamicVariable: DynamicVariable,
		    define: defineDynamic,
		    isDynamic: isDynamic,
		    unbox: unbox,
		    accessor: toAccessorString
		  };
	
		  /* globals requestAnimationFrame, cancelAnimationFrame */
		  var raf = {
		    next: typeof requestAnimationFrame === 'function' ? function (cb) {
		      return requestAnimationFrame(cb);
		    } : function (cb) {
		      return setTimeout(cb, 16);
		    },
		    cancel: typeof cancelAnimationFrame === 'function' ? function (raf) {
		      return cancelAnimationFrame(raf);
		    } : clearTimeout
		  };
	
		  /* globals performance */
		  var clock = typeof performance !== 'undefined' && performance.now ? function () {
		    return performance.now();
		  } : function () {
		    return +new Date();
		  };
	
		  function createStringStore() {
		    var stringIds = { '': 0 };
		    var stringValues = [''];
		    return {
		      id: function (str) {
		        var result = stringIds[str];
		        if (result) {
		          return result;
		        }
		        result = stringIds[str] = stringValues.length;
		        stringValues.push(str);
		        return result;
		      },
	
		      str: function (id) {
		        return stringValues[id];
		      }
		    };
		  }
	
		  // Context and canvas creation helper functions
		  function createCanvas(element, onDone, pixelRatio) {
		    var canvas = document.createElement('canvas');
		    extend(canvas.style, {
		      border: 0,
		      margin: 0,
		      padding: 0,
		      top: 0,
		      left: 0
		    });
		    element.appendChild(canvas);
	
		    if (element === document.body) {
		      canvas.style.position = 'absolute';
		      extend(element.style, {
		        margin: 0,
		        padding: 0
		      });
		    }
	
		    function resize() {
		      var w = window.innerWidth;
		      var h = window.innerHeight;
		      if (element !== document.body) {
		        var bounds = element.getBoundingClientRect();
		        w = bounds.right - bounds.left;
		        h = bounds.bottom - bounds.top;
		      }
		      canvas.width = pixelRatio * w;
		      canvas.height = pixelRatio * h;
		      extend(canvas.style, {
		        width: w + 'px',
		        height: h + 'px'
		      });
		    }
	
		    window.addEventListener('resize', resize, false);
	
		    function onDestroy() {
		      window.removeEventListener('resize', resize);
		      element.removeChild(canvas);
		    }
	
		    resize();
	
		    return {
		      canvas: canvas,
		      onDestroy: onDestroy
		    };
		  }
	
		  function createContext(canvas, contexAttributes) {
		    function get(name) {
		      try {
		        return canvas.getContext(name, contexAttributes);
		      } catch (e) {
		        return null;
		      }
		    }
		    return get('webgl') || get('experimental-webgl') || get('webgl-experimental');
		  }
	
		  function isHTMLElement(obj) {
		    return typeof obj.nodeName === 'string' && typeof obj.appendChild === 'function' && typeof obj.getBoundingClientRect === 'function';
		  }
	
		  function isWebGLContext(obj) {
		    return typeof obj.drawArrays === 'function' || typeof obj.drawElements === 'function';
		  }
	
		  function parseExtensions(input) {
		    if (typeof input === 'string') {
		      return input.split();
		    }
		    check$1(Array.isArray(input), 'invalid extension array');
		    return input;
		  }
	
		  function getElement(desc) {
		    if (typeof desc === 'string') {
		      check$1(typeof document !== 'undefined', 'not supported outside of DOM');
		      return document.querySelector(desc);
		    }
		    return desc;
		  }
	
		  function parseArgs(args_) {
		    var args = args_ || {};
		    var element, container, canvas, gl;
		    var contextAttributes = {};
		    var extensions = [];
		    var optionalExtensions = [];
		    var pixelRatio = typeof window === 'undefined' ? 1 : window.devicePixelRatio;
		    var profile = false;
		    var onDone = function (err) {
		      if (err) {
		        check$1.raise(err);
		      }
		    };
		    var onDestroy = function () {};
		    if (typeof args === 'string') {
		      check$1(typeof document !== 'undefined', 'selector queries only supported in DOM enviroments');
		      element = document.querySelector(args);
		      check$1(element, 'invalid query string for element');
		    } else if (typeof args === 'object') {
		      if (isHTMLElement(args)) {
		        element = args;
		      } else if (isWebGLContext(args)) {
		        gl = args;
		        canvas = gl.canvas;
		      } else {
		        check$1.constructor(args);
		        if ('gl' in args) {
		          gl = args.gl;
		        } else if ('canvas' in args) {
		          canvas = getElement(args.canvas);
		        } else if ('container' in args) {
		          container = getElement(args.container);
		        }
		        if ('attributes' in args) {
		          contextAttributes = args.attributes;
		          check$1.type(contextAttributes, 'object', 'invalid context attributes');
		        }
		        if ('extensions' in args) {
		          extensions = parseExtensions(args.extensions);
		        }
		        if ('optionalExtensions' in args) {
		          optionalExtensions = parseExtensions(args.optionalExtensions);
		        }
		        if ('onDone' in args) {
		          check$1.type(args.onDone, 'function', 'invalid or missing onDone callback');
		          onDone = args.onDone;
		        }
		        if ('profile' in args) {
		          profile = !!args.profile;
		        }
		        if ('pixelRatio' in args) {
		          pixelRatio = +args.pixelRatio;
		          check$1(pixelRatio > 0, 'invalid pixel ratio');
		        }
		      }
		    } else {
		      check$1.raise('invalid arguments to regl');
		    }
	
		    if (element) {
		      if (element.nodeName.toLowerCase() === 'canvas') {
		        canvas = element;
		      } else {
		        container = element;
		      }
		    }
	
		    if (!gl) {
		      if (!canvas) {
		        check$1(typeof document !== 'undefined', 'must manually specify webgl context outside of DOM environments');
		        var result = createCanvas(container || document.body, onDone, pixelRatio);
		        if (!result) {
		          return null;
		        }
		        canvas = result.canvas;
		        onDestroy = result.onDestroy;
		      }
		      gl = createContext(canvas, contextAttributes);
		    }
	
		    if (!gl) {
		      onDestroy();
		      onDone('webgl not supported, try upgrading your browser or graphics drivers http://get.webgl.org');
		      return null;
		    }
	
		    return {
		      gl: gl,
		      canvas: canvas,
		      container: container,
		      extensions: extensions,
		      optionalExtensions: optionalExtensions,
		      pixelRatio: pixelRatio,
		      profile: profile,
		      onDone: onDone,
		      onDestroy: onDestroy
		    };
		  }
	
		  function createExtensionCache(gl, config) {
		    var extensions = {};
	
		    function tryLoadExtension(name_) {
		      check$1.type(name_, 'string', 'extension name must be string');
		      var name = name_.toLowerCase();
		      var ext;
		      try {
		        ext = extensions[name] = gl.getExtension(name);
		      } catch (e) {}
		      return !!ext;
		    }
	
		    for (var i = 0; i < config.extensions.length; ++i) {
		      var name = config.extensions[i];
		      if (!tryLoadExtension(name)) {
		        config.onDestroy();
		        config.onDone('"' + name + '" extension is not supported by the current WebGL context, try upgrading your system or a different browser');
		        return null;
		      }
		    }
	
		    config.optionalExtensions.forEach(tryLoadExtension);
	
		    return {
		      extensions: extensions,
		      restore: function () {
		        Object.keys(extensions).forEach(function (name) {
		          if (!tryLoadExtension(name)) {
		            throw new Error('(regl): error restoring extension ' + name);
		          }
		        });
		      }
		    };
		  }
	
		  var GL_SUBPIXEL_BITS = 0x0D50;
		  var GL_RED_BITS = 0x0D52;
		  var GL_GREEN_BITS = 0x0D53;
		  var GL_BLUE_BITS = 0x0D54;
		  var GL_ALPHA_BITS = 0x0D55;
		  var GL_DEPTH_BITS = 0x0D56;
		  var GL_STENCIL_BITS = 0x0D57;
	
		  var GL_ALIASED_POINT_SIZE_RANGE = 0x846D;
		  var GL_ALIASED_LINE_WIDTH_RANGE = 0x846E;
	
		  var GL_MAX_TEXTURE_SIZE = 0x0D33;
		  var GL_MAX_VIEWPORT_DIMS = 0x0D3A;
		  var GL_MAX_VERTEX_ATTRIBS = 0x8869;
		  var GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB;
		  var GL_MAX_VARYING_VECTORS = 0x8DFC;
		  var GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D;
		  var GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C;
		  var GL_MAX_TEXTURE_IMAGE_UNITS = 0x8872;
		  var GL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD;
		  var GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C;
		  var GL_MAX_RENDERBUFFER_SIZE = 0x84E8;
	
		  var GL_VENDOR = 0x1F00;
		  var GL_RENDERER = 0x1F01;
		  var GL_VERSION = 0x1F02;
		  var GL_SHADING_LANGUAGE_VERSION = 0x8B8C;
	
		  var GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
	
		  var GL_MAX_COLOR_ATTACHMENTS_WEBGL = 0x8CDF;
		  var GL_MAX_DRAW_BUFFERS_WEBGL = 0x8824;
	
		  var wrapLimits = function (gl, extensions) {
		    var maxAnisotropic = 1;
		    if (extensions.ext_texture_filter_anisotropic) {
		      maxAnisotropic = gl.getParameter(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT);
		    }
	
		    var maxDrawbuffers = 1;
		    var maxColorAttachments = 1;
		    if (extensions.webgl_draw_buffers) {
		      maxDrawbuffers = gl.getParameter(GL_MAX_DRAW_BUFFERS_WEBGL);
		      maxColorAttachments = gl.getParameter(GL_MAX_COLOR_ATTACHMENTS_WEBGL);
		    }
	
		    return {
		      // drawing buffer bit depth
		      colorBits: [gl.getParameter(GL_RED_BITS), gl.getParameter(GL_GREEN_BITS), gl.getParameter(GL_BLUE_BITS), gl.getParameter(GL_ALPHA_BITS)],
		      depthBits: gl.getParameter(GL_DEPTH_BITS),
		      stencilBits: gl.getParameter(GL_STENCIL_BITS),
		      subpixelBits: gl.getParameter(GL_SUBPIXEL_BITS),
	
		      // supported extensions
		      extensions: Object.keys(extensions).filter(function (ext) {
		        return !!extensions[ext];
		      }),
	
		      // max aniso samples
		      maxAnisotropic: maxAnisotropic,
	
		      // max draw buffers
		      maxDrawbuffers: maxDrawbuffers,
		      maxColorAttachments: maxColorAttachments,
	
		      // point and line size ranges
		      pointSizeDims: gl.getParameter(GL_ALIASED_POINT_SIZE_RANGE),
		      lineWidthDims: gl.getParameter(GL_ALIASED_LINE_WIDTH_RANGE),
		      maxViewportDims: gl.getParameter(GL_MAX_VIEWPORT_DIMS),
		      maxCombinedTextureUnits: gl.getParameter(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS),
		      maxCubeMapSize: gl.getParameter(GL_MAX_CUBE_MAP_TEXTURE_SIZE),
		      maxRenderbufferSize: gl.getParameter(GL_MAX_RENDERBUFFER_SIZE),
		      maxTextureUnits: gl.getParameter(GL_MAX_TEXTURE_IMAGE_UNITS),
		      maxTextureSize: gl.getParameter(GL_MAX_TEXTURE_SIZE),
		      maxAttributes: gl.getParameter(GL_MAX_VERTEX_ATTRIBS),
		      maxVertexUniforms: gl.getParameter(GL_MAX_VERTEX_UNIFORM_VECTORS),
		      maxVertexTextureUnits: gl.getParameter(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS),
		      maxVaryingVectors: gl.getParameter(GL_MAX_VARYING_VECTORS),
		      maxFragmentUniforms: gl.getParameter(GL_MAX_FRAGMENT_UNIFORM_VECTORS),
	
		      // vendor info
		      glsl: gl.getParameter(GL_SHADING_LANGUAGE_VERSION),
		      renderer: gl.getParameter(GL_RENDERER),
		      vendor: gl.getParameter(GL_VENDOR),
		      version: gl.getParameter(GL_VERSION)
		    };
		  };
	
		  function isNDArrayLike(obj) {
		    return !!obj && typeof obj === 'object' && Array.isArray(obj.shape) && Array.isArray(obj.stride) && typeof obj.offset === 'number' && obj.shape.length === obj.stride.length && (Array.isArray(obj.data) || isTypedArray(obj.data));
		  }
	
		  var values = function (obj) {
		    return Object.keys(obj).map(function (key) {
		      return obj[key];
		    });
		  };
	
		  function loop(n, f) {
		    var result = Array(n);
		    for (var i = 0; i < n; ++i) {
		      result[i] = f(i);
		    }
		    return result;
		  }
	
		  var GL_BYTE$1 = 5120;
		  var GL_UNSIGNED_BYTE$2 = 5121;
		  var GL_SHORT$1 = 5122;
		  var GL_UNSIGNED_SHORT$1 = 5123;
		  var GL_INT$1 = 5124;
		  var GL_UNSIGNED_INT$1 = 5125;
		  var GL_FLOAT$2 = 5126;
	
		  var bufferPool = loop(8, function () {
		    return [];
		  });
	
		  function nextPow16(v) {
		    for (var i = 16; i <= 1 << 28; i *= 16) {
		      if (v <= i) {
		        return i;
		      }
		    }
		    return 0;
		  }
	
		  function log2(v) {
		    var r, shift;
		    r = (v > 0xFFFF) << 4;
		    v >>>= r;
		    shift = (v > 0xFF) << 3;
		    v >>>= shift;r |= shift;
		    shift = (v > 0xF) << 2;
		    v >>>= shift;r |= shift;
		    shift = (v > 0x3) << 1;
		    v >>>= shift;r |= shift;
		    return r | v >> 1;
		  }
	
		  function alloc(n) {
		    var sz = nextPow16(n);
		    var bin = bufferPool[log2(sz) >> 2];
		    if (bin.length > 0) {
		      return bin.pop();
		    }
		    return new ArrayBuffer(sz);
		  }
	
		  function free(buf) {
		    bufferPool[log2(buf.byteLength) >> 2].push(buf);
		  }
	
		  function allocType(type, n) {
		    var result = null;
		    switch (type) {
		      case GL_BYTE$1:
		        result = new Int8Array(alloc(n), 0, n);
		        break;
		      case GL_UNSIGNED_BYTE$2:
		        result = new Uint8Array(alloc(n), 0, n);
		        break;
		      case GL_SHORT$1:
		        result = new Int16Array(alloc(2 * n), 0, n);
		        break;
		      case GL_UNSIGNED_SHORT$1:
		        result = new Uint16Array(alloc(2 * n), 0, n);
		        break;
		      case GL_INT$1:
		        result = new Int32Array(alloc(4 * n), 0, n);
		        break;
		      case GL_UNSIGNED_INT$1:
		        result = new Uint32Array(alloc(4 * n), 0, n);
		        break;
		      case GL_FLOAT$2:
		        result = new Float32Array(alloc(4 * n), 0, n);
		        break;
		      default:
		        return null;
		    }
		    if (result.length !== n) {
		      return result.subarray(0, n);
		    }
		    return result;
		  }
	
		  function freeType(array) {
		    free(array.buffer);
		  }
	
		  var pool = {
		    alloc: alloc,
		    free: free,
		    allocType: allocType,
		    freeType: freeType
		  };
	
		  var flattenUtils = {
		    shape: arrayShape$1,
		    flatten: flattenArray
		  };
	
		  function flatten1D(array, nx, out) {
		    for (var i = 0; i < nx; ++i) {
		      out[i] = array[i];
		    }
		  }
	
		  function flatten2D(array, nx, ny, out) {
		    var ptr = 0;
		    for (var i = 0; i < nx; ++i) {
		      var row = array[i];
		      for (var j = 0; j < ny; ++j) {
		        out[ptr++] = row[j];
		      }
		    }
		  }
	
		  function flatten3D(array, nx, ny, nz, out, ptr_) {
		    var ptr = ptr_;
		    for (var i = 0; i < nx; ++i) {
		      var row = array[i];
		      for (var j = 0; j < ny; ++j) {
		        var col = row[j];
		        for (var k = 0; k < nz; ++k) {
		          out[ptr++] = col[k];
		        }
		      }
		    }
		  }
	
		  function flattenRec(array, shape, level, out, ptr) {
		    var stride = 1;
		    for (var i = level + 1; i < shape.length; ++i) {
		      stride *= shape[i];
		    }
		    var n = shape[level];
		    if (shape.length - level === 4) {
		      var nx = shape[level + 1];
		      var ny = shape[level + 2];
		      var nz = shape[level + 3];
		      for (i = 0; i < n; ++i) {
		        flatten3D(array[i], nx, ny, nz, out, ptr);
		        ptr += stride;
		      }
		    } else {
		      for (i = 0; i < n; ++i) {
		        flattenRec(array[i], shape, level + 1, out, ptr);
		        ptr += stride;
		      }
		    }
		  }
	
		  function flattenArray(array, shape, type, out_) {
		    var sz = 1;
		    if (shape.length) {
		      for (var i = 0; i < shape.length; ++i) {
		        sz *= shape[i];
		      }
		    } else {
		      sz = 0;
		    }
		    var out = out_ || pool.allocType(type, sz);
		    switch (shape.length) {
		      case 0:
		        break;
		      case 1:
		        flatten1D(array, shape[0], out);
		        break;
		      case 2:
		        flatten2D(array, shape[0], shape[1], out);
		        break;
		      case 3:
		        flatten3D(array, shape[0], shape[1], shape[2], out, 0);
		        break;
		      default:
		        flattenRec(array, shape, 0, out, 0);
		    }
		    return out;
		  }
	
		  function arrayShape$1(array_) {
		    var shape = [];
		    for (var array = array_; array.length; array = array[0]) {
		      shape.push(array.length);
		    }
		    return shape;
		  }
	
		  var int8 = 5120;
		  var int16 = 5122;
		  var int32 = 5124;
		  var uint8 = 5121;
		  var uint16 = 5123;
		  var uint32 = 5125;
		  var float = 5126;
		  var float32 = 5126;
		  var glTypes = {
		    int8: int8,
		    int16: int16,
		    int32: int32,
		    uint8: uint8,
		    uint16: uint16,
		    uint32: uint32,
		    float: float,
		    float32: float32
		  };
	
		  var dynamic$1 = 35048;
		  var stream = 35040;
		  var usageTypes = {
		    dynamic: dynamic$1,
		    stream: stream,
		    "static": 35044
		  };
	
		  var arrayFlatten = flattenUtils.flatten;
		  var arrayShape = flattenUtils.shape;
	
		  var GL_STATIC_DRAW = 0x88E4;
		  var GL_STREAM_DRAW = 0x88E0;
	
		  var GL_UNSIGNED_BYTE$1 = 5121;
		  var GL_FLOAT$1 = 5126;
	
		  var DTYPES_SIZES = [];
		  DTYPES_SIZES[5120] = 1; // int8
		  DTYPES_SIZES[5122] = 2; // int16
		  DTYPES_SIZES[5124] = 4; // int32
		  DTYPES_SIZES[5121] = 1; // uint8
		  DTYPES_SIZES[5123] = 2; // uint16
		  DTYPES_SIZES[5125] = 4; // uint32
		  DTYPES_SIZES[5126] = 4; // float32
	
		  function typedArrayCode(data) {
		    return arrayTypes[Object.prototype.toString.call(data)] | 0;
		  }
	
		  function copyArray(out, inp) {
		    for (var i = 0; i < inp.length; ++i) {
		      out[i] = inp[i];
		    }
		  }
	
		  function transpose(result, data, shapeX, shapeY, strideX, strideY, offset) {
		    var ptr = 0;
		    for (var i = 0; i < shapeX; ++i) {
		      for (var j = 0; j < shapeY; ++j) {
		        result[ptr++] = data[strideX * i + strideY * j + offset];
		      }
		    }
		  }
	
		  function wrapBufferState(gl, stats, config) {
		    var bufferCount = 0;
		    var bufferSet = {};
	
		    function REGLBuffer(type) {
		      this.id = bufferCount++;
		      this.buffer = gl.createBuffer();
		      this.type = type;
		      this.usage = GL_STATIC_DRAW;
		      this.byteLength = 0;
		      this.dimension = 1;
		      this.dtype = GL_UNSIGNED_BYTE$1;
	
		      this.persistentData = null;
	
		      if (config.profile) {
		        this.stats = { size: 0 };
		      }
		    }
	
		    REGLBuffer.prototype.bind = function () {
		      gl.bindBuffer(this.type, this.buffer);
		    };
	
		    REGLBuffer.prototype.destroy = function () {
		      destroy(this);
		    };
	
		    var streamPool = [];
	
		    function createStream(type, data) {
		      var buffer = streamPool.pop();
		      if (!buffer) {
		        buffer = new REGLBuffer(type);
		      }
		      buffer.bind();
		      initBufferFromData(buffer, data, GL_STREAM_DRAW, 0, 1, false);
		      return buffer;
		    }
	
		    function destroyStream(stream$$1) {
		      streamPool.push(stream$$1);
		    }
	
		    function initBufferFromTypedArray(buffer, data, usage) {
		      buffer.byteLength = data.byteLength;
		      gl.bufferData(buffer.type, data, usage);
		    }
	
		    function initBufferFromData(buffer, data, usage, dtype, dimension, persist) {
		      var shape;
		      buffer.usage = usage;
		      if (Array.isArray(data)) {
		        buffer.dtype = dtype || GL_FLOAT$1;
		        if (data.length > 0) {
		          var flatData;
		          if (Array.isArray(data[0])) {
		            shape = arrayShape(data);
		            var dim = 1;
		            for (var i = 1; i < shape.length; ++i) {
		              dim *= shape[i];
		            }
		            buffer.dimension = dim;
		            flatData = arrayFlatten(data, shape, buffer.dtype);
		            initBufferFromTypedArray(buffer, flatData, usage);
		            if (persist) {
		              buffer.persistentData = flatData;
		            } else {
		              pool.freeType(flatData);
		            }
		          } else if (typeof data[0] === 'number') {
		            buffer.dimension = dimension;
		            var typedData = pool.allocType(buffer.dtype, data.length);
		            copyArray(typedData, data);
		            initBufferFromTypedArray(buffer, typedData, usage);
		            if (persist) {
		              buffer.persistentData = typedData;
		            } else {
		              pool.freeType(typedData);
		            }
		          } else if (isTypedArray(data[0])) {
		            buffer.dimension = data[0].length;
		            buffer.dtype = dtype || typedArrayCode(data[0]) || GL_FLOAT$1;
		            flatData = arrayFlatten(data, [data.length, data[0].length], buffer.dtype);
		            initBufferFromTypedArray(buffer, flatData, usage);
		            if (persist) {
		              buffer.persistentData = flatData;
		            } else {
		              pool.freeType(flatData);
		            }
		          } else {
		            check$1.raise('invalid buffer data');
		          }
		        }
		      } else if (isTypedArray(data)) {
		        buffer.dtype = dtype || typedArrayCode(data);
		        buffer.dimension = dimension;
		        initBufferFromTypedArray(buffer, data, usage);
		        if (persist) {
		          buffer.persistentData = new Uint8Array(new Uint8Array(data.buffer));
		        }
		      } else if (isNDArrayLike(data)) {
		        shape = data.shape;
		        var stride = data.stride;
		        var offset = data.offset;
	
		        var shapeX = 0;
		        var shapeY = 0;
		        var strideX = 0;
		        var strideY = 0;
		        if (shape.length === 1) {
		          shapeX = shape[0];
		          shapeY = 1;
		          strideX = stride[0];
		          strideY = 0;
		        } else if (shape.length === 2) {
		          shapeX = shape[0];
		          shapeY = shape[1];
		          strideX = stride[0];
		          strideY = stride[1];
		        } else {
		          check$1.raise('invalid shape');
		        }
	
		        buffer.dtype = dtype || typedArrayCode(data.data) || GL_FLOAT$1;
		        buffer.dimension = shapeY;
	
		        var transposeData = pool.allocType(buffer.dtype, shapeX * shapeY);
		        transpose(transposeData, data.data, shapeX, shapeY, strideX, strideY, offset);
		        initBufferFromTypedArray(buffer, transposeData, usage);
		        if (persist) {
		          buffer.persistentData = transposeData;
		        } else {
		          pool.freeType(transposeData);
		        }
		      } else {
		        check$1.raise('invalid buffer data');
		      }
		    }
	
		    function destroy(buffer) {
		      stats.bufferCount--;
	
		      var handle = buffer.buffer;
		      check$1(handle, 'buffer must not be deleted already');
		      gl.deleteBuffer(handle);
		      buffer.buffer = null;
		      delete bufferSet[buffer.id];
		    }
	
		    function createBuffer(options, type, deferInit, persistent) {
		      stats.bufferCount++;
	
		      var buffer = new REGLBuffer(type);
		      bufferSet[buffer.id] = buffer;
	
		      function reglBuffer(options) {
		        var usage = GL_STATIC_DRAW;
		        var data = null;
		        var byteLength = 0;
		        var dtype = 0;
		        var dimension = 1;
		        if (Array.isArray(options) || isTypedArray(options) || isNDArrayLike(options)) {
		          data = options;
		        } else if (typeof options === 'number') {
		          byteLength = options | 0;
		        } else if (options) {
		          check$1.type(options, 'object', 'buffer arguments must be an object, a number or an array');
	
		          if ('data' in options) {
		            check$1(data === null || Array.isArray(data) || isTypedArray(data) || isNDArrayLike(data), 'invalid data for buffer');
		            data = options.data;
		          }
	
		          if ('usage' in options) {
		            check$1.parameter(options.usage, usageTypes, 'invalid buffer usage');
		            usage = usageTypes[options.usage];
		          }
	
		          if ('type' in options) {
		            check$1.parameter(options.type, glTypes, 'invalid buffer type');
		            dtype = glTypes[options.type];
		          }
	
		          if ('dimension' in options) {
		            check$1.type(options.dimension, 'number', 'invalid dimension');
		            dimension = options.dimension | 0;
		          }
	
		          if ('length' in options) {
		            check$1.nni(byteLength, 'buffer length must be a nonnegative integer');
		            byteLength = options.length | 0;
		          }
		        }
	
		        buffer.bind();
		        if (!data) {
		          gl.bufferData(buffer.type, byteLength, usage);
		          buffer.dtype = dtype || GL_UNSIGNED_BYTE$1;
		          buffer.usage = usage;
		          buffer.dimension = dimension;
		          buffer.byteLength = byteLength;
		        } else {
		          initBufferFromData(buffer, data, usage, dtype, dimension, persistent);
		        }
	
		        if (config.profile) {
		          buffer.stats.size = buffer.byteLength * DTYPES_SIZES[buffer.dtype];
		        }
	
		        return reglBuffer;
		      }
	
		      function setSubData(data, offset) {
		        check$1(offset + data.byteLength <= buffer.byteLength, 'invalid buffer subdata call, buffer is too small. ' + ' Can\'t write data of size ' + data.byteLength + ' starting from offset ' + offset + ' to a buffer of size ' + buffer.byteLength);
	
		        gl.bufferSubData(buffer.type, offset, data);
		      }
	
		      function subdata(data, offset_) {
		        var offset = (offset_ || 0) | 0;
		        var shape;
		        buffer.bind();
		        if (Array.isArray(data)) {
		          if (data.length > 0) {
		            if (typeof data[0] === 'number') {
		              var converted = pool.allocType(buffer.dtype, data.length);
		              copyArray(converted, data);
		              setSubData(converted, offset);
		              pool.freeType(converted);
		            } else if (Array.isArray(data[0]) || isTypedArray(data[0])) {
		              shape = arrayShape(data);
		              var flatData = arrayFlatten(data, shape, buffer.dtype);
		              setSubData(flatData, offset);
		              pool.freeType(flatData);
		            } else {
		              check$1.raise('invalid buffer data');
		            }
		          }
		        } else if (isTypedArray(data)) {
		          setSubData(data, offset);
		        } else if (isNDArrayLike(data)) {
		          shape = data.shape;
		          var stride = data.stride;
	
		          var shapeX = 0;
		          var shapeY = 0;
		          var strideX = 0;
		          var strideY = 0;
		          if (shape.length === 1) {
		            shapeX = shape[0];
		            shapeY = 1;
		            strideX = stride[0];
		            strideY = 0;
		          } else if (shape.length === 2) {
		            shapeX = shape[0];
		            shapeY = shape[1];
		            strideX = stride[0];
		            strideY = stride[1];
		          } else {
		            check$1.raise('invalid shape');
		          }
		          var dtype = Array.isArray(data.data) ? buffer.dtype : typedArrayCode(data.data);
	
		          var transposeData = pool.allocType(dtype, shapeX * shapeY);
		          transpose(transposeData, data.data, shapeX, shapeY, strideX, strideY, data.offset);
		          setSubData(transposeData, offset);
		          pool.freeType(transposeData);
		        } else {
		          check$1.raise('invalid data for buffer subdata');
		        }
		        return reglBuffer;
		      }
	
		      if (!deferInit) {
		        reglBuffer(options);
		      }
	
		      reglBuffer._reglType = 'buffer';
		      reglBuffer._buffer = buffer;
		      reglBuffer.subdata = subdata;
		      if (config.profile) {
		        reglBuffer.stats = buffer.stats;
		      }
		      reglBuffer.destroy = function () {
		        destroy(buffer);
		      };
	
		      return reglBuffer;
		    }
	
		    function restoreBuffers() {
		      values(bufferSet).forEach(function (buffer) {
		        buffer.buffer = gl.createBuffer();
		        gl.bindBuffer(buffer.type, buffer.buffer);
		        gl.bufferData(buffer.type, buffer.persistentData || buffer.byteLength, buffer.usage);
		      });
		    }
	
		    if (config.profile) {
		      stats.getTotalBufferSize = function () {
		        var total = 0;
		        // TODO: Right now, the streams are not part of the total count.
		        Object.keys(bufferSet).forEach(function (key) {
		          total += bufferSet[key].stats.size;
		        });
		        return total;
		      };
		    }
	
		    return {
		      create: createBuffer,
	
		      createStream: createStream,
		      destroyStream: destroyStream,
	
		      clear: function () {
		        values(bufferSet).forEach(destroy);
		        streamPool.forEach(destroy);
		      },
	
		      getBuffer: function (wrapper) {
		        if (wrapper && wrapper._buffer instanceof REGLBuffer) {
		          return wrapper._buffer;
		        }
		        return null;
		      },
	
		      restore: restoreBuffers,
	
		      _initBuffer: initBufferFromData
		    };
		  }
	
		  var points = 0;
		  var point = 0;
		  var lines = 1;
		  var line = 1;
		  var triangles = 4;
		  var triangle = 4;
		  var primTypes = {
		    points: points,
		    point: point,
		    lines: lines,
		    line: line,
		    triangles: triangles,
		    triangle: triangle,
		    "line loop": 2,
		    "line strip": 3,
		    "triangle strip": 5,
		    "triangle fan": 6
		  };
	
		  var GL_POINTS = 0;
		  var GL_LINES = 1;
		  var GL_TRIANGLES = 4;
	
		  var GL_BYTE$2 = 5120;
		  var GL_UNSIGNED_BYTE$3 = 5121;
		  var GL_SHORT$2 = 5122;
		  var GL_UNSIGNED_SHORT$2 = 5123;
		  var GL_INT$2 = 5124;
		  var GL_UNSIGNED_INT$2 = 5125;
	
		  var GL_ELEMENT_ARRAY_BUFFER = 34963;
	
		  var GL_STREAM_DRAW$1 = 0x88E0;
		  var GL_STATIC_DRAW$1 = 0x88E4;
	
		  function wrapElementsState(gl, extensions, bufferState, stats) {
		    var elementSet = {};
		    var elementCount = 0;
	
		    var elementTypes = {
		      'uint8': GL_UNSIGNED_BYTE$3,
		      'uint16': GL_UNSIGNED_SHORT$2
		    };
	
		    if (extensions.oes_element_index_uint) {
		      elementTypes.uint32 = GL_UNSIGNED_INT$2;
		    }
	
		    function REGLElementBuffer(buffer) {
		      this.id = elementCount++;
		      elementSet[this.id] = this;
		      this.buffer = buffer;
		      this.primType = GL_TRIANGLES;
		      this.vertCount = 0;
		      this.type = 0;
		    }
	
		    REGLElementBuffer.prototype.bind = function () {
		      this.buffer.bind();
		    };
	
		    var bufferPool = [];
	
		    function createElementStream(data) {
		      var result = bufferPool.pop();
		      if (!result) {
		        result = new REGLElementBuffer(bufferState.create(null, GL_ELEMENT_ARRAY_BUFFER, true, false)._buffer);
		      }
		      initElements(result, data, GL_STREAM_DRAW$1, -1, -1, 0, 0);
		      return result;
		    }
	
		    function destroyElementStream(elements) {
		      bufferPool.push(elements);
		    }
	
		    function initElements(elements, data, usage, prim, count, byteLength, type) {
		      elements.buffer.bind();
		      if (data) {
		        var predictedType = type;
		        if (!type && (!isTypedArray(data) || isNDArrayLike(data) && !isTypedArray(data.data))) {
		          predictedType = extensions.oes_element_index_uint ? GL_UNSIGNED_INT$2 : GL_UNSIGNED_SHORT$2;
		        }
		        bufferState._initBuffer(elements.buffer, data, usage, predictedType, 3);
		      } else {
		        gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, byteLength, usage);
		        elements.buffer.dtype = dtype || GL_UNSIGNED_BYTE$3;
		        elements.buffer.usage = usage;
		        elements.buffer.dimension = 3;
		        elements.buffer.byteLength = byteLength;
		      }
	
		      var dtype = type;
		      if (!type) {
		        switch (elements.buffer.dtype) {
		          case GL_UNSIGNED_BYTE$3:
		          case GL_BYTE$2:
		            dtype = GL_UNSIGNED_BYTE$3;
		            break;
	
		          case GL_UNSIGNED_SHORT$2:
		          case GL_SHORT$2:
		            dtype = GL_UNSIGNED_SHORT$2;
		            break;
	
		          case GL_UNSIGNED_INT$2:
		          case GL_INT$2:
		            dtype = GL_UNSIGNED_INT$2;
		            break;
	
		          default:
		            check$1.raise('unsupported type for element array');
		        }
		        elements.buffer.dtype = dtype;
		      }
		      elements.type = dtype;
	
		      // Check oes_element_index_uint extension
		      check$1(dtype !== GL_UNSIGNED_INT$2 || !!extensions.oes_element_index_uint, '32 bit element buffers not supported, enable oes_element_index_uint first');
	
		      // try to guess default primitive type and arguments
		      var vertCount = count;
		      if (vertCount < 0) {
		        vertCount = elements.buffer.byteLength;
		        if (dtype === GL_UNSIGNED_SHORT$2) {
		          vertCount >>= 1;
		        } else if (dtype === GL_UNSIGNED_INT$2) {
		          vertCount >>= 2;
		        }
		      }
		      elements.vertCount = vertCount;
	
		      // try to guess primitive type from cell dimension
		      var primType = prim;
		      if (prim < 0) {
		        primType = GL_TRIANGLES;
		        var dimension = elements.buffer.dimension;
		        if (dimension === 1) primType = GL_POINTS;
		        if (dimension === 2) primType = GL_LINES;
		        if (dimension === 3) primType = GL_TRIANGLES;
		      }
		      elements.primType = primType;
		    }
	
		    function destroyElements(elements) {
		      stats.elementsCount--;
	
		      check$1(elements.buffer !== null, 'must not double destroy elements');
		      delete elementSet[elements.id];
		      elements.buffer.destroy();
		      elements.buffer = null;
		    }
	
		    function createElements(options, persistent) {
		      var buffer = bufferState.create(null, GL_ELEMENT_ARRAY_BUFFER, true);
		      var elements = new REGLElementBuffer(buffer._buffer);
		      stats.elementsCount++;
	
		      function reglElements(options) {
		        if (!options) {
		          buffer();
		          elements.primType = GL_TRIANGLES;
		          elements.vertCount = 0;
		          elements.type = GL_UNSIGNED_BYTE$3;
		        } else if (typeof options === 'number') {
		          buffer(options);
		          elements.primType = GL_TRIANGLES;
		          elements.vertCount = options | 0;
		          elements.type = GL_UNSIGNED_BYTE$3;
		        } else {
		          var data = null;
		          var usage = GL_STATIC_DRAW$1;
		          var primType = -1;
		          var vertCount = -1;
		          var byteLength = 0;
		          var dtype = 0;
		          if (Array.isArray(options) || isTypedArray(options) || isNDArrayLike(options)) {
		            data = options;
		          } else {
		            check$1.type(options, 'object', 'invalid arguments for elements');
		            if ('data' in options) {
		              data = options.data;
		              check$1(Array.isArray(data) || isTypedArray(data) || isNDArrayLike(data), 'invalid data for element buffer');
		            }
		            if ('usage' in options) {
		              check$1.parameter(options.usage, usageTypes, 'invalid element buffer usage');
		              usage = usageTypes[options.usage];
		            }
		            if ('primitive' in options) {
		              check$1.parameter(options.primitive, primTypes, 'invalid element buffer primitive');
		              primType = primTypes[options.primitive];
		            }
		            if ('count' in options) {
		              check$1(typeof options.count === 'number' && options.count >= 0, 'invalid vertex count for elements');
		              vertCount = options.count | 0;
		            }
		            if ('type' in options) {
		              check$1.parameter(options.type, elementTypes, 'invalid buffer type');
		              dtype = elementTypes[options.type];
		            }
		            if ('length' in options) {
		              byteLength = options.length | 0;
		            } else {
		              byteLength = vertCount;
		              if (dtype === GL_UNSIGNED_SHORT$2 || dtype === GL_SHORT$2) {
		                byteLength *= 2;
		              } else if (dtype === GL_UNSIGNED_INT$2 || dtype === GL_INT$2) {
		                byteLength *= 4;
		              }
		            }
		          }
		          initElements(elements, data, usage, primType, vertCount, byteLength, dtype);
		        }
	
		        return reglElements;
		      }
	
		      reglElements(options);
	
		      reglElements._reglType = 'elements';
		      reglElements._elements = elements;
		      reglElements.subdata = function (data, offset) {
		        buffer.subdata(data, offset);
		        return reglElements;
		      };
		      reglElements.destroy = function () {
		        destroyElements(elements);
		      };
	
		      return reglElements;
		    }
	
		    return {
		      create: createElements,
		      createStream: createElementStream,
		      destroyStream: destroyElementStream,
		      getElements: function (elements) {
		        if (typeof elements === 'function' && elements._elements instanceof REGLElementBuffer) {
		          return elements._elements;
		        }
		        return null;
		      },
		      clear: function () {
		        values(elementSet).forEach(destroyElements);
		      }
		    };
		  }
	
		  var FLOAT = new Float32Array(1);
		  var INT = new Uint32Array(FLOAT.buffer);
	
		  var GL_UNSIGNED_SHORT$4 = 5123;
	
		  function convertToHalfFloat(array) {
		    var ushorts = pool.allocType(GL_UNSIGNED_SHORT$4, array.length);
	
		    for (var i = 0; i < array.length; ++i) {
		      if (isNaN(array[i])) {
		        ushorts[i] = 0xffff;
		      } else if (array[i] === Infinity) {
		        ushorts[i] = 0x7c00;
		      } else if (array[i] === -Infinity) {
		        ushorts[i] = 0xfc00;
		      } else {
		        FLOAT[0] = array[i];
		        var x = INT[0];
	
		        var sgn = x >>> 31 << 15;
		        var exp = (x << 1 >>> 24) - 127;
		        var frac = x >> 13 & (1 << 10) - 1;
	
		        if (exp < -24) {
		          // round non-representable denormals to 0
		          ushorts[i] = sgn;
		        } else if (exp < -14) {
		          // handle denormals
		          var s = -14 - exp;
		          ushorts[i] = sgn + (frac + (1 << 10) >> s);
		        } else if (exp > 15) {
		          // round overflow to +/- Infinity
		          ushorts[i] = sgn + 0x7c00;
		        } else {
		          // otherwise convert directly
		          ushorts[i] = sgn + (exp + 15 << 10) + frac;
		        }
		      }
		    }
	
		    return ushorts;
		  }
	
		  function isArrayLike(s) {
		    return Array.isArray(s) || isTypedArray(s);
		  }
	
		  var GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3;
	
		  var GL_TEXTURE_2D = 0x0DE1;
		  var GL_TEXTURE_CUBE_MAP = 0x8513;
		  var GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515;
	
		  var GL_RGBA = 0x1908;
		  var GL_ALPHA = 0x1906;
		  var GL_RGB = 0x1907;
		  var GL_LUMINANCE = 0x1909;
		  var GL_LUMINANCE_ALPHA = 0x190A;
	
		  var GL_RGBA4 = 0x8056;
		  var GL_RGB5_A1 = 0x8057;
		  var GL_RGB565 = 0x8D62;
	
		  var GL_UNSIGNED_SHORT_4_4_4_4$1 = 0x8033;
		  var GL_UNSIGNED_SHORT_5_5_5_1$1 = 0x8034;
		  var GL_UNSIGNED_SHORT_5_6_5$1 = 0x8363;
		  var GL_UNSIGNED_INT_24_8_WEBGL$1 = 0x84FA;
	
		  var GL_DEPTH_COMPONENT = 0x1902;
		  var GL_DEPTH_STENCIL = 0x84F9;
	
		  var GL_SRGB_EXT = 0x8C40;
		  var GL_SRGB_ALPHA_EXT = 0x8C42;
	
		  var GL_HALF_FLOAT_OES$1 = 0x8D61;
	
		  var GL_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
		  var GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
		  var GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
		  var GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
	
		  var GL_COMPRESSED_RGB_ATC_WEBGL = 0x8C92;
		  var GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL = 0x8C93;
		  var GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE;
	
		  var GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
		  var GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01;
		  var GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
		  var GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03;
	
		  var GL_COMPRESSED_RGB_ETC1_WEBGL = 0x8D64;
	
		  var GL_UNSIGNED_BYTE$4 = 0x1401;
		  var GL_UNSIGNED_SHORT$3 = 0x1403;
		  var GL_UNSIGNED_INT$3 = 0x1405;
		  var GL_FLOAT$3 = 0x1406;
	
		  var GL_TEXTURE_WRAP_S = 0x2802;
		  var GL_TEXTURE_WRAP_T = 0x2803;
	
		  var GL_REPEAT = 0x2901;
		  var GL_CLAMP_TO_EDGE$1 = 0x812F;
		  var GL_MIRRORED_REPEAT = 0x8370;
	
		  var GL_TEXTURE_MAG_FILTER = 0x2800;
		  var GL_TEXTURE_MIN_FILTER = 0x2801;
	
		  var GL_NEAREST$1 = 0x2600;
		  var GL_LINEAR = 0x2601;
		  var GL_NEAREST_MIPMAP_NEAREST$1 = 0x2700;
		  var GL_LINEAR_MIPMAP_NEAREST$1 = 0x2701;
		  var GL_NEAREST_MIPMAP_LINEAR$1 = 0x2702;
		  var GL_LINEAR_MIPMAP_LINEAR$1 = 0x2703;
	
		  var GL_GENERATE_MIPMAP_HINT = 0x8192;
		  var GL_DONT_CARE = 0x1100;
		  var GL_FASTEST = 0x1101;
		  var GL_NICEST = 0x1102;
	
		  var GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
	
		  var GL_UNPACK_ALIGNMENT = 0x0CF5;
		  var GL_UNPACK_FLIP_Y_WEBGL = 0x9240;
		  var GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241;
		  var GL_UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243;
	
		  var GL_BROWSER_DEFAULT_WEBGL = 0x9244;
	
		  var GL_TEXTURE0 = 0x84C0;
	
		  var MIPMAP_FILTERS = [GL_NEAREST_MIPMAP_NEAREST$1, GL_NEAREST_MIPMAP_LINEAR$1, GL_LINEAR_MIPMAP_NEAREST$1, GL_LINEAR_MIPMAP_LINEAR$1];
	
		  var CHANNELS_FORMAT = [0, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA];
	
		  var FORMAT_CHANNELS = {};
		  FORMAT_CHANNELS[GL_LUMINANCE] = FORMAT_CHANNELS[GL_ALPHA] = FORMAT_CHANNELS[GL_DEPTH_COMPONENT] = 1;
		  FORMAT_CHANNELS[GL_DEPTH_STENCIL] = FORMAT_CHANNELS[GL_LUMINANCE_ALPHA] = 2;
		  FORMAT_CHANNELS[GL_RGB] = FORMAT_CHANNELS[GL_SRGB_EXT] = 3;
		  FORMAT_CHANNELS[GL_RGBA] = FORMAT_CHANNELS[GL_SRGB_ALPHA_EXT] = 4;
	
		  function objectName(str) {
		    return '[object ' + str + ']';
		  }
	
		  var CANVAS_CLASS = objectName('HTMLCanvasElement');
		  var CONTEXT2D_CLASS = objectName('CanvasRenderingContext2D');
		  var IMAGE_CLASS = objectName('HTMLImageElement');
		  var VIDEO_CLASS = objectName('HTMLVideoElement');
	
		  var PIXEL_CLASSES = Object.keys(arrayTypes).concat([CANVAS_CLASS, CONTEXT2D_CLASS, IMAGE_CLASS, VIDEO_CLASS]);
	
		  // for every texture type, store
		  // the size in bytes.
		  var TYPE_SIZES = [];
		  TYPE_SIZES[GL_UNSIGNED_BYTE$4] = 1;
		  TYPE_SIZES[GL_FLOAT$3] = 4;
		  TYPE_SIZES[GL_HALF_FLOAT_OES$1] = 2;
	
		  TYPE_SIZES[GL_UNSIGNED_SHORT$3] = 2;
		  TYPE_SIZES[GL_UNSIGNED_INT$3] = 4;
	
		  var FORMAT_SIZES_SPECIAL = [];
		  FORMAT_SIZES_SPECIAL[GL_RGBA4] = 2;
		  FORMAT_SIZES_SPECIAL[GL_RGB5_A1] = 2;
		  FORMAT_SIZES_SPECIAL[GL_RGB565] = 2;
		  FORMAT_SIZES_SPECIAL[GL_DEPTH_STENCIL] = 4;
	
		  FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_S3TC_DXT1_EXT] = 0.5;
		  FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT1_EXT] = 0.5;
		  FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT3_EXT] = 1;
		  FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT5_EXT] = 1;
	
		  FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_ATC_WEBGL] = 0.5;
		  FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL] = 1;
		  FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL] = 1;
	
		  FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG] = 0.5;
		  FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG] = 0.25;
		  FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG] = 0.5;
		  FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG] = 0.25;
	
		  FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_ETC1_WEBGL] = 0.5;
	
		  function isNumericArray(arr) {
		    return Array.isArray(arr) && (arr.length === 0 || typeof arr[0] === 'number');
		  }
	
		  function isRectArray(arr) {
		    if (!Array.isArray(arr)) {
		      return false;
		    }
		    var width = arr.length;
		    if (width === 0 || !isArrayLike(arr[0])) {
		      return false;
		    }
		    return true;
		  }
	
		  function classString(x) {
		    return Object.prototype.toString.call(x);
		  }
	
		  function isCanvasElement(object) {
		    return classString(object) === CANVAS_CLASS;
		  }
	
		  function isContext2D(object) {
		    return classString(object) === CONTEXT2D_CLASS;
		  }
	
		  function isImageElement(object) {
		    return classString(object) === IMAGE_CLASS;
		  }
	
		  function isVideoElement(object) {
		    return classString(object) === VIDEO_CLASS;
		  }
	
		  function isPixelData(object) {
		    if (!object) {
		      return false;
		    }
		    var className = classString(object);
		    if (PIXEL_CLASSES.indexOf(className) >= 0) {
		      return true;
		    }
		    return isNumericArray(object) || isRectArray(object) || isNDArrayLike(object);
		  }
	
		  function typedArrayCode$1(data) {
		    return arrayTypes[Object.prototype.toString.call(data)] | 0;
		  }
	
		  function convertData(result, data) {
		    var n = data.length;
		    switch (result.type) {
		      case GL_UNSIGNED_BYTE$4:
		      case GL_UNSIGNED_SHORT$3:
		      case GL_UNSIGNED_INT$3:
		      case GL_FLOAT$3:
		        var converted = pool.allocType(result.type, n);
		        converted.set(data);
		        result.data = converted;
		        break;
	
		      case GL_HALF_FLOAT_OES$1:
		        result.data = convertToHalfFloat(data);
		        break;
	
		      default:
		        check$1.raise('unsupported texture type, must specify a typed array');
		    }
		  }
	
		  function preConvert(image, n) {
		    return pool.allocType(image.type === GL_HALF_FLOAT_OES$1 ? GL_FLOAT$3 : image.type, n);
		  }
	
		  function postConvert(image, data) {
		    if (image.type === GL_HALF_FLOAT_OES$1) {
		      image.data = convertToHalfFloat(data);
		      pool.freeType(data);
		    } else {
		      image.data = data;
		    }
		  }
	
		  function transposeData(image, array, strideX, strideY, strideC, offset) {
		    var w = image.width;
		    var h = image.height;
		    var c = image.channels;
		    var n = w * h * c;
		    var data = preConvert(image, n);
	
		    var p = 0;
		    for (var i = 0; i < h; ++i) {
		      for (var j = 0; j < w; ++j) {
		        for (var k = 0; k < c; ++k) {
		          data[p++] = array[strideX * j + strideY * i + strideC * k + offset];
		        }
		      }
		    }
	
		    postConvert(image, data);
		  }
	
		  function getTextureSize(format, type, width, height, isMipmap, isCube) {
		    var s;
		    if (typeof FORMAT_SIZES_SPECIAL[format] !== 'undefined') {
		      // we have a special array for dealing with weird color formats such as RGB5A1
		      s = FORMAT_SIZES_SPECIAL[format];
		    } else {
		      s = FORMAT_CHANNELS[format] * TYPE_SIZES[type];
		    }
	
		    if (isCube) {
		      s *= 6;
		    }
	
		    if (isMipmap) {
		      // compute the total size of all the mipmaps.
		      var total = 0;
	
		      var w = width;
		      while (w >= 1) {
		        // we can only use mipmaps on a square image,
		        // so we can simply use the width and ignore the height:
		        total += s * w * w;
		        w /= 2;
		      }
		      return total;
		    } else {
		      return s * width * height;
		    }
		  }
	
		  function createTextureSet(gl, extensions, limits, reglPoll, contextState, stats, config) {
		    // -------------------------------------------------------
		    // Initialize constants and parameter tables here
		    // -------------------------------------------------------
		    var mipmapHint = {
		      "don't care": GL_DONT_CARE,
		      'dont care': GL_DONT_CARE,
		      'nice': GL_NICEST,
		      'fast': GL_FASTEST
		    };
	
		    var wrapModes = {
		      'repeat': GL_REPEAT,
		      'clamp': GL_CLAMP_TO_EDGE$1,
		      'mirror': GL_MIRRORED_REPEAT
		    };
	
		    var magFilters = {
		      'nearest': GL_NEAREST$1,
		      'linear': GL_LINEAR
		    };
	
		    var minFilters = extend({
		      'mipmap': GL_LINEAR_MIPMAP_LINEAR$1,
		      'nearest mipmap nearest': GL_NEAREST_MIPMAP_NEAREST$1,
		      'linear mipmap nearest': GL_LINEAR_MIPMAP_NEAREST$1,
		      'nearest mipmap linear': GL_NEAREST_MIPMAP_LINEAR$1,
		      'linear mipmap linear': GL_LINEAR_MIPMAP_LINEAR$1
		    }, magFilters);
	
		    var colorSpace = {
		      'none': 0,
		      'browser': GL_BROWSER_DEFAULT_WEBGL
		    };
	
		    var textureTypes = {
		      'uint8': GL_UNSIGNED_BYTE$4,
		      'rgba4': GL_UNSIGNED_SHORT_4_4_4_4$1,
		      'rgb565': GL_UNSIGNED_SHORT_5_6_5$1,
		      'rgb5 a1': GL_UNSIGNED_SHORT_5_5_5_1$1
		    };
	
		    var textureFormats = {
		      'alpha': GL_ALPHA,
		      'luminance': GL_LUMINANCE,
		      'luminance alpha': GL_LUMINANCE_ALPHA,
		      'rgb': GL_RGB,
		      'rgba': GL_RGBA,
		      'rgba4': GL_RGBA4,
		      'rgb5 a1': GL_RGB5_A1,
		      'rgb565': GL_RGB565
		    };
	
		    var compressedTextureFormats = {};
	
		    if (extensions.ext_srgb) {
		      textureFormats.srgb = GL_SRGB_EXT;
		      textureFormats.srgba = GL_SRGB_ALPHA_EXT;
		    }
	
		    if (extensions.oes_texture_float) {
		      textureTypes.float32 = textureTypes.float = GL_FLOAT$3;
		    }
	
		    if (extensions.oes_texture_half_float) {
		      textureTypes['float16'] = textureTypes['half float'] = GL_HALF_FLOAT_OES$1;
		    }
	
		    if (extensions.webgl_depth_texture) {
		      extend(textureFormats, {
		        'depth': GL_DEPTH_COMPONENT,
		        'depth stencil': GL_DEPTH_STENCIL
		      });
	
		      extend(textureTypes, {
		        'uint16': GL_UNSIGNED_SHORT$3,
		        'uint32': GL_UNSIGNED_INT$3,
		        'depth stencil': GL_UNSIGNED_INT_24_8_WEBGL$1
		      });
		    }
	
		    if (extensions.webgl_compressed_texture_s3tc) {
		      extend(compressedTextureFormats, {
		        'rgb s3tc dxt1': GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
		        'rgba s3tc dxt1': GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
		        'rgba s3tc dxt3': GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
		        'rgba s3tc dxt5': GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
		      });
		    }
	
		    if (extensions.webgl_compressed_texture_atc) {
		      extend(compressedTextureFormats, {
		        'rgb atc': GL_COMPRESSED_RGB_ATC_WEBGL,
		        'rgba atc explicit alpha': GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL,
		        'rgba atc interpolated alpha': GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL
		      });
		    }
	
		    if (extensions.webgl_compressed_texture_pvrtc) {
		      extend(compressedTextureFormats, {
		        'rgb pvrtc 4bppv1': GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG,
		        'rgb pvrtc 2bppv1': GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG,
		        'rgba pvrtc 4bppv1': GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG,
		        'rgba pvrtc 2bppv1': GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
		      });
		    }
	
		    if (extensions.webgl_compressed_texture_etc1) {
		      compressedTextureFormats['rgb etc1'] = GL_COMPRESSED_RGB_ETC1_WEBGL;
		    }
	
		    // Copy over all texture formats
		    var supportedCompressedFormats = Array.prototype.slice.call(gl.getParameter(GL_COMPRESSED_TEXTURE_FORMATS));
		    Object.keys(compressedTextureFormats).forEach(function (name) {
		      var format = compressedTextureFormats[name];
		      if (supportedCompressedFormats.indexOf(format) >= 0) {
		        textureFormats[name] = format;
		      }
		    });
	
		    var supportedFormats = Object.keys(textureFormats);
		    limits.textureFormats = supportedFormats;
	
		    // associate with every format string its
		    // corresponding GL-value.
		    var textureFormatsInvert = [];
		    Object.keys(textureFormats).forEach(function (key) {
		      var val = textureFormats[key];
		      textureFormatsInvert[val] = key;
		    });
	
		    // associate with every type string its
		    // corresponding GL-value.
		    var textureTypesInvert = [];
		    Object.keys(textureTypes).forEach(function (key) {
		      var val = textureTypes[key];
		      textureTypesInvert[val] = key;
		    });
	
		    var magFiltersInvert = [];
		    Object.keys(magFilters).forEach(function (key) {
		      var val = magFilters[key];
		      magFiltersInvert[val] = key;
		    });
	
		    var minFiltersInvert = [];
		    Object.keys(minFilters).forEach(function (key) {
		      var val = minFilters[key];
		      minFiltersInvert[val] = key;
		    });
	
		    var wrapModesInvert = [];
		    Object.keys(wrapModes).forEach(function (key) {
		      var val = wrapModes[key];
		      wrapModesInvert[val] = key;
		    });
	
		    // colorFormats[] gives the format (channels) associated to an
		    // internalformat
		    var colorFormats = supportedFormats.reduce(function (color, key) {
		      var glenum = textureFormats[key];
		      if (glenum === GL_LUMINANCE || glenum === GL_ALPHA || glenum === GL_LUMINANCE || glenum === GL_LUMINANCE_ALPHA || glenum === GL_DEPTH_COMPONENT || glenum === GL_DEPTH_STENCIL) {
		        color[glenum] = glenum;
		      } else if (glenum === GL_RGB5_A1 || key.indexOf('rgba') >= 0) {
		        color[glenum] = GL_RGBA;
		      } else {
		        color[glenum] = GL_RGB;
		      }
		      return color;
		    }, {});
	
		    function TexFlags() {
		      // format info
		      this.internalformat = GL_RGBA;
		      this.format = GL_RGBA;
		      this.type = GL_UNSIGNED_BYTE$4;
		      this.compressed = false;
	
		      // pixel storage
		      this.premultiplyAlpha = false;
		      this.flipY = false;
		      this.unpackAlignment = 1;
		      this.colorSpace = 0;
	
		      // shape info
		      this.width = 0;
		      this.height = 0;
		      this.channels = 0;
		    }
	
		    function copyFlags(result, other) {
		      result.internalformat = other.internalformat;
		      result.format = other.format;
		      result.type = other.type;
		      result.compressed = other.compressed;
	
		      result.premultiplyAlpha = other.premultiplyAlpha;
		      result.flipY = other.flipY;
		      result.unpackAlignment = other.unpackAlignment;
		      result.colorSpace = other.colorSpace;
	
		      result.width = other.width;
		      result.height = other.height;
		      result.channels = other.channels;
		    }
	
		    function parseFlags(flags, options) {
		      if (typeof options !== 'object' || !options) {
		        return;
		      }
	
		      if ('premultiplyAlpha' in options) {
		        check$1.type(options.premultiplyAlpha, 'boolean', 'invalid premultiplyAlpha');
		        flags.premultiplyAlpha = options.premultiplyAlpha;
		      }
	
		      if ('flipY' in options) {
		        check$1.type(options.flipY, 'boolean', 'invalid texture flip');
		        flags.flipY = options.flipY;
		      }
	
		      if ('alignment' in options) {
		        check$1.oneOf(options.alignment, [1, 2, 4, 8], 'invalid texture unpack alignment');
		        flags.unpackAlignment = options.alignment;
		      }
	
		      if ('colorSpace' in options) {
		        check$1.parameter(options.colorSpace, colorSpace, 'invalid colorSpace');
		        flags.colorSpace = colorSpace[options.colorSpace];
		      }
	
		      if ('type' in options) {
		        var type = options.type;
		        check$1(extensions.oes_texture_float || !(type === 'float' || type === 'float32'), 'you must enable the OES_texture_float extension in order to use floating point textures.');
		        check$1(extensions.oes_texture_half_float || !(type === 'half float' || type === 'float16'), 'you must enable the OES_texture_half_float extension in order to use 16-bit floating point textures.');
		        check$1(extensions.webgl_depth_texture || !(type === 'uint16' || type === 'uint32' || type === 'depth stencil'), 'you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures.');
		        check$1.parameter(type, textureTypes, 'invalid texture type');
		        flags.type = textureTypes[type];
		      }
	
		      var w = flags.width;
		      var h = flags.height;
		      var c = flags.channels;
		      var hasChannels = false;
		      if ('shape' in options) {
		        check$1(Array.isArray(options.shape) && options.shape.length >= 2, 'shape must be an array');
		        w = options.shape[0];
		        h = options.shape[1];
		        if (options.shape.length === 3) {
		          c = options.shape[2];
		          check$1(c > 0 && c <= 4, 'invalid number of channels');
		          hasChannels = true;
		        }
		        check$1(w >= 0 && w <= limits.maxTextureSize, 'invalid width');
		        check$1(h >= 0 && h <= limits.maxTextureSize, 'invalid height');
		      } else {
		        if ('radius' in options) {
		          w = h = options.radius;
		          check$1(w >= 0 && w <= limits.maxTextureSize, 'invalid radius');
		        }
		        if ('width' in options) {
		          w = options.width;
		          check$1(w >= 0 && w <= limits.maxTextureSize, 'invalid width');
		        }
		        if ('height' in options) {
		          h = options.height;
		          check$1(h >= 0 && h <= limits.maxTextureSize, 'invalid height');
		        }
		        if ('channels' in options) {
		          c = options.channels;
		          check$1(c > 0 && c <= 4, 'invalid number of channels');
		          hasChannels = true;
		        }
		      }
		      flags.width = w | 0;
		      flags.height = h | 0;
		      flags.channels = c | 0;
	
		      var hasFormat = false;
		      if ('format' in options) {
		        var formatStr = options.format;
		        check$1(extensions.webgl_depth_texture || !(formatStr === 'depth' || formatStr === 'depth stencil'), 'you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures.');
		        check$1.parameter(formatStr, textureFormats, 'invalid texture format');
		        var internalformat = flags.internalformat = textureFormats[formatStr];
		        flags.format = colorFormats[internalformat];
		        if (formatStr in textureTypes) {
		          if (!('type' in options)) {
		            flags.type = textureTypes[formatStr];
		          }
		        }
		        if (formatStr in compressedTextureFormats) {
		          flags.compressed = true;
		        }
		        hasFormat = true;
		      }
	
		      // Reconcile channels and format
		      if (!hasChannels && hasFormat) {
		        flags.channels = FORMAT_CHANNELS[flags.format];
		      } else if (hasChannels && !hasFormat) {
		        if (flags.channels !== CHANNELS_FORMAT[flags.format]) {
		          flags.format = flags.internalformat = CHANNELS_FORMAT[flags.channels];
		        }
		      } else if (hasFormat && hasChannels) {
		        check$1(flags.channels === FORMAT_CHANNELS[flags.format], 'number of channels inconsistent with specified format');
		      }
		    }
	
		    function setFlags(flags) {
		      gl.pixelStorei(GL_UNPACK_FLIP_Y_WEBGL, flags.flipY);
		      gl.pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL, flags.premultiplyAlpha);
		      gl.pixelStorei(GL_UNPACK_COLORSPACE_CONVERSION_WEBGL, flags.colorSpace);
		      gl.pixelStorei(GL_UNPACK_ALIGNMENT, flags.unpackAlignment);
		    }
	
		    // -------------------------------------------------------
		    // Tex image data
		    // -------------------------------------------------------
		    function TexImage() {
		      TexFlags.call(this);
	
		      this.xOffset = 0;
		      this.yOffset = 0;
	
		      // data
		      this.data = null;
		      this.needsFree = false;
	
		      // html element
		      this.element = null;
	
		      // copyTexImage info
		      this.needsCopy = false;
		    }
	
		    function parseImage(image, options) {
		      var data = null;
		      if (isPixelData(options)) {
		        data = options;
		      } else if (options) {
		        check$1.type(options, 'object', 'invalid pixel data type');
		        parseFlags(image, options);
		        if ('x' in options) {
		          image.xOffset = options.x | 0;
		        }
		        if ('y' in options) {
		          image.yOffset = options.y | 0;
		        }
		        if (isPixelData(options.data)) {
		          data = options.data;
		        }
		      }
	
		      check$1(!image.compressed || data instanceof Uint8Array, 'compressed texture data must be stored in a uint8array');
	
		      if (options.copy) {
		        check$1(!data, 'can not specify copy and data field for the same texture');
		        var viewW = contextState.viewportWidth;
		        var viewH = contextState.viewportHeight;
		        image.width = image.width || viewW - image.xOffset;
		        image.height = image.height || viewH - image.yOffset;
		        image.needsCopy = true;
		        check$1(image.xOffset >= 0 && image.xOffset < viewW && image.yOffset >= 0 && image.yOffset < viewH && image.width > 0 && image.width <= viewW && image.height > 0 && image.height <= viewH, 'copy texture read out of bounds');
		      } else if (!data) {
		        image.width = image.width || 1;
		        image.height = image.height || 1;
		        image.channels = image.channels || 4;
		      } else if (isTypedArray(data)) {
		        image.channels = image.channels || 4;
		        image.data = data;
		        if (!('type' in options) && image.type === GL_UNSIGNED_BYTE$4) {
		          image.type = typedArrayCode$1(data);
		        }
		      } else if (isNumericArray(data)) {
		        image.channels = image.channels || 4;
		        convertData(image, data);
		        image.alignment = 1;
		        image.needsFree = true;
		      } else if (isNDArrayLike(data)) {
		        var array = data.data;
		        if (!Array.isArray(array) && image.type === GL_UNSIGNED_BYTE$4) {
		          image.type = typedArrayCode$1(array);
		        }
		        var shape = data.shape;
		        var stride = data.stride;
		        var shapeX, shapeY, shapeC, strideX, strideY, strideC;
		        if (shape.length === 3) {
		          shapeC = shape[2];
		          strideC = stride[2];
		        } else {
		          check$1(shape.length === 2, 'invalid ndarray pixel data, must be 2 or 3D');
		          shapeC = 1;
		          strideC = 1;
		        }
		        shapeX = shape[0];
		        shapeY = shape[1];
		        strideX = stride[0];
		        strideY = stride[1];
		        image.alignment = 1;
		        image.width = shapeX;
		        image.height = shapeY;
		        image.channels = shapeC;
		        image.format = image.internalformat = CHANNELS_FORMAT[shapeC];
		        image.needsFree = true;
		        transposeData(image, array, strideX, strideY, strideC, data.offset);
		      } else if (isCanvasElement(data) || isContext2D(data)) {
		        if (isCanvasElement(data)) {
		          image.element = data;
		        } else {
		          image.element = data.canvas;
		        }
		        image.width = image.element.width;
		        image.height = image.element.height;
		        image.channels = 4;
		      } else if (isImageElement(data)) {
		        image.element = data;
		        image.width = data.naturalWidth;
		        image.height = data.naturalHeight;
		        image.channels = 4;
		      } else if (isVideoElement(data)) {
		        image.element = data;
		        image.width = data.videoWidth;
		        image.height = data.videoHeight;
		        image.channels = 4;
		      } else if (isRectArray(data)) {
		        var w = image.width || data[0].length;
		        var h = image.height || data.length;
		        var c = image.channels;
		        if (isArrayLike(data[0][0])) {
		          c = c || data[0][0].length;
		        } else {
		          c = c || 1;
		        }
		        var arrayShape = flattenUtils.shape(data);
		        var n = 1;
		        for (var dd = 0; dd < arrayShape.length; ++dd) {
		          n *= arrayShape[dd];
		        }
		        var allocData = preConvert(image, n);
		        flattenUtils.flatten(data, arrayShape, '', allocData);
		        postConvert(image, allocData);
		        image.alignment = 1;
		        image.width = w;
		        image.height = h;
		        image.channels = c;
		        image.format = image.internalformat = CHANNELS_FORMAT[c];
		        image.needsFree = true;
		      }
	
		      if (image.type === GL_FLOAT$3) {
		        check$1(limits.extensions.indexOf('oes_texture_float') >= 0, 'oes_texture_float extension not enabled');
		      } else if (image.type === GL_HALF_FLOAT_OES$1) {
		        check$1(limits.extensions.indexOf('oes_texture_half_float') >= 0, 'oes_texture_half_float extension not enabled');
		      }
	
		      // do compressed texture  validation here.
		    }
	
		    function setImage(info, target, miplevel) {
		      var element = info.element;
		      var data = info.data;
		      var internalformat = info.internalformat;
		      var format = info.format;
		      var type = info.type;
		      var width = info.width;
		      var height = info.height;
	
		      setFlags(info);
	
		      if (element) {
		        gl.texImage2D(target, miplevel, format, format, type, element);
		      } else if (info.compressed) {
		        gl.compressedTexImage2D(target, miplevel, internalformat, width, height, 0, data);
		      } else if (info.needsCopy) {
		        reglPoll();
		        gl.copyTexImage2D(target, miplevel, format, info.xOffset, info.yOffset, width, height, 0);
		      } else {
		        gl.texImage2D(target, miplevel, format, width, height, 0, format, type, data);
		      }
		    }
	
		    function setSubImage(info, target, x, y, miplevel) {
		      var element = info.element;
		      var data = info.data;
		      var internalformat = info.internalformat;
		      var format = info.format;
		      var type = info.type;
		      var width = info.width;
		      var height = info.height;
	
		      setFlags(info);
	
		      if (element) {
		        gl.texSubImage2D(target, miplevel, x, y, format, type, element);
		      } else if (info.compressed) {
		        gl.compressedTexSubImage2D(target, miplevel, x, y, internalformat, width, height, data);
		      } else if (info.needsCopy) {
		        reglPoll();
		        gl.copyTexSubImage2D(target, miplevel, x, y, info.xOffset, info.yOffset, width, height);
		      } else {
		        gl.texSubImage2D(target, miplevel, x, y, width, height, format, type, data);
		      }
		    }
	
		    // texImage pool
		    var imagePool = [];
	
		    function allocImage() {
		      return imagePool.pop() || new TexImage();
		    }
	
		    function freeImage(image) {
		      if (image.needsFree) {
		        pool.freeType(image.data);
		      }
		      TexImage.call(image);
		      imagePool.push(image);
		    }
	
		    // -------------------------------------------------------
		    // Mip map
		    // -------------------------------------------------------
		    function MipMap() {
		      TexFlags.call(this);
	
		      this.genMipmaps = false;
		      this.mipmapHint = GL_DONT_CARE;
		      this.mipmask = 0;
		      this.images = Array(16);
		    }
	
		    function parseMipMapFromShape(mipmap, width, height) {
		      var img = mipmap.images[0] = allocImage();
		      mipmap.mipmask = 1;
		      img.width = mipmap.width = width;
		      img.height = mipmap.height = height;
		      img.channels = mipmap.channels = 4;
		    }
	
		    function parseMipMapFromObject(mipmap, options) {
		      var imgData = null;
		      if (isPixelData(options)) {
		        imgData = mipmap.images[0] = allocImage();
		        copyFlags(imgData, mipmap);
		        parseImage(imgData, options);
		        mipmap.mipmask = 1;
		      } else {
		        parseFlags(mipmap, options);
		        if (Array.isArray(options.mipmap)) {
		          var mipData = options.mipmap;
		          for (var i = 0; i < mipData.length; ++i) {
		            imgData = mipmap.images[i] = allocImage();
		            copyFlags(imgData, mipmap);
		            imgData.width >>= i;
		            imgData.height >>= i;
		            parseImage(imgData, mipData[i]);
		            mipmap.mipmask |= 1 << i;
		          }
		        } else {
		          imgData = mipmap.images[0] = allocImage();
		          copyFlags(imgData, mipmap);
		          parseImage(imgData, options);
		          mipmap.mipmask = 1;
		        }
		      }
		      copyFlags(mipmap, mipmap.images[0]);
	
		      // For textures of the compressed format WEBGL_compressed_texture_s3tc
		      // we must have that
		      //
		      // "When level equals zero width and height must be a multiple of 4.
		      // When level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4. "
		      //
		      // but we do not yet support having multiple mipmap levels for compressed textures,
		      // so we only test for level zero.
	
		      if (mipmap.compressed && mipmap.internalformat === GL_COMPRESSED_RGB_S3TC_DXT1_EXT || mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT3_EXT || mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) {
		        check$1(mipmap.width % 4 === 0 && mipmap.height % 4 === 0, 'for compressed texture formats, mipmap level 0 must have width and height that are a multiple of 4');
		      }
		    }
	
		    function setMipMap(mipmap, target) {
		      var images = mipmap.images;
		      for (var i = 0; i < images.length; ++i) {
		        if (!images[i]) {
		          return;
		        }
		        setImage(images[i], target, i);
		      }
		    }
	
		    var mipPool = [];
	
		    function allocMipMap() {
		      var result = mipPool.pop() || new MipMap();
		      TexFlags.call(result);
		      result.mipmask = 0;
		      for (var i = 0; i < 16; ++i) {
		        result.images[i] = null;
		      }
		      return result;
		    }
	
		    function freeMipMap(mipmap) {
		      var images = mipmap.images;
		      for (var i = 0; i < images.length; ++i) {
		        if (images[i]) {
		          freeImage(images[i]);
		        }
		        images[i] = null;
		      }
		      mipPool.push(mipmap);
		    }
	
		    // -------------------------------------------------------
		    // Tex info
		    // -------------------------------------------------------
		    function TexInfo() {
		      this.minFilter = GL_NEAREST$1;
		      this.magFilter = GL_NEAREST$1;
	
		      this.wrapS = GL_CLAMP_TO_EDGE$1;
		      this.wrapT = GL_CLAMP_TO_EDGE$1;
	
		      this.anisotropic = 1;
	
		      this.genMipmaps = false;
		      this.mipmapHint = GL_DONT_CARE;
		    }
	
		    function parseTexInfo(info, options) {
		      if ('min' in options) {
		        var minFilter = options.min;
		        check$1.parameter(minFilter, minFilters);
		        info.minFilter = minFilters[minFilter];
		        if (MIPMAP_FILTERS.indexOf(info.minFilter) >= 0) {
		          info.genMipmaps = true;
		        }
		      }
	
		      if ('mag' in options) {
		        var magFilter = options.mag;
		        check$1.parameter(magFilter, magFilters);
		        info.magFilter = magFilters[magFilter];
		      }
	
		      var wrapS = info.wrapS;
		      var wrapT = info.wrapT;
		      if ('wrap' in options) {
		        var wrap = options.wrap;
		        if (typeof wrap === 'string') {
		          check$1.parameter(wrap, wrapModes);
		          wrapS = wrapT = wrapModes[wrap];
		        } else if (Array.isArray(wrap)) {
		          check$1.parameter(wrap[0], wrapModes);
		          check$1.parameter(wrap[1], wrapModes);
		          wrapS = wrapModes[wrap[0]];
		          wrapT = wrapModes[wrap[1]];
		        }
		      } else {
		        if ('wrapS' in options) {
		          var optWrapS = options.wrapS;
		          check$1.parameter(optWrapS, wrapModes);
		          wrapS = wrapModes[optWrapS];
		        }
		        if ('wrapT' in options) {
		          var optWrapT = options.wrapT;
		          check$1.parameter(optWrapT, wrapModes);
		          wrapT = wrapModes[optWrapT];
		        }
		      }
		      info.wrapS = wrapS;
		      info.wrapT = wrapT;
	
		      if ('anisotropic' in options) {
		        var anisotropic = options.anisotropic;
		        check$1(typeof anisotropic === 'number' && anisotropic >= 1 && anisotropic <= limits.maxAnisotropic, 'aniso samples must be between 1 and ');
		        info.anisotropic = options.anisotropic;
		      }
	
		      if ('mipmap' in options) {
		        var hasMipMap = false;
		        switch (typeof options.mipmap) {
		          case 'string':
		            check$1.parameter(options.mipmap, mipmapHint, 'invalid mipmap hint');
		            info.mipmapHint = mipmapHint[options.mipmap];
		            info.genMipmaps = true;
		            hasMipMap = true;
		            break;
	
		          case 'boolean':
		            hasMipMap = info.genMipmaps = options.mipmap;
		            break;
	
		          case 'object':
		            check$1(Array.isArray(options.mipmap), 'invalid mipmap type');
		            info.genMipmaps = false;
		            hasMipMap = true;
		            break;
	
		          default:
		            check$1.raise('invalid mipmap type');
		        }
		        if (hasMipMap && !('min' in options)) {
		          info.minFilter = GL_NEAREST_MIPMAP_NEAREST$1;
		        }
		      }
		    }
	
		    function setTexInfo(info, target) {
		      gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, info.minFilter);
		      gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, info.magFilter);
		      gl.texParameteri(target, GL_TEXTURE_WRAP_S, info.wrapS);
		      gl.texParameteri(target, GL_TEXTURE_WRAP_T, info.wrapT);
		      if (extensions.ext_texture_filter_anisotropic) {
		        gl.texParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, info.anisotropic);
		      }
		      if (info.genMipmaps) {
		        gl.hint(GL_GENERATE_MIPMAP_HINT, info.mipmapHint);
		        gl.generateMipmap(target);
		      }
		    }
	
		    // -------------------------------------------------------
		    // Full texture object
		    // -------------------------------------------------------
		    var textureCount = 0;
		    var textureSet = {};
		    var numTexUnits = limits.maxTextureUnits;
		    var textureUnits = Array(numTexUnits).map(function () {
		      return null;
		    });
	
		    function REGLTexture(target) {
		      TexFlags.call(this);
		      this.mipmask = 0;
		      this.internalformat = GL_RGBA;
	
		      this.id = textureCount++;
	
		      this.refCount = 1;
	
		      this.target = target;
		      this.texture = gl.createTexture();
	
		      this.unit = -1;
		      this.bindCount = 0;
	
		      this.texInfo = new TexInfo();
	
		      if (config.profile) {
		        this.stats = { size: 0 };
		      }
		    }
	
		    function tempBind(texture) {
		      gl.activeTexture(GL_TEXTURE0);
		      gl.bindTexture(texture.target, texture.texture);
		    }
	
		    function tempRestore() {
		      var prev = textureUnits[0];
		      if (prev) {
		        gl.bindTexture(prev.target, prev.texture);
		      } else {
		        gl.bindTexture(GL_TEXTURE_2D, null);
		      }
		    }
	
		    function destroy(texture) {
		      var handle = texture.texture;
		      check$1(handle, 'must not double destroy texture');
		      var unit = texture.unit;
		      var target = texture.target;
		      if (unit >= 0) {
		        gl.activeTexture(GL_TEXTURE0 + unit);
		        gl.bindTexture(target, null);
		        textureUnits[unit] = null;
		      }
		      gl.deleteTexture(handle);
		      texture.texture = null;
		      texture.params = null;
		      texture.pixels = null;
		      texture.refCount = 0;
		      delete textureSet[texture.id];
		      stats.textureCount--;
		    }
	
		    extend(REGLTexture.prototype, {
		      bind: function () {
		        var texture = this;
		        texture.bindCount += 1;
		        var unit = texture.unit;
		        if (unit < 0) {
		          for (var i = 0; i < numTexUnits; ++i) {
		            var other = textureUnits[i];
		            if (other) {
		              if (other.bindCount > 0) {
		                continue;
		              }
		              other.unit = -1;
		            }
		            textureUnits[i] = texture;
		            unit = i;
		            break;
		          }
		          if (unit >= numTexUnits) {
		            check$1.raise('insufficient number of texture units');
		          }
		          if (config.profile && stats.maxTextureUnits < unit + 1) {
		            stats.maxTextureUnits = unit + 1; // +1, since the units are zero-based
		          }
		          texture.unit = unit;
		          gl.activeTexture(GL_TEXTURE0 + unit);
		          gl.bindTexture(texture.target, texture.texture);
		        }
		        return unit;
		      },
	
		      unbind: function () {
		        this.bindCount -= 1;
		      },
	
		      decRef: function () {
		        if (--this.refCount <= 0) {
		          destroy(this);
		        }
		      }
		    });
	
		    function createTexture2D(a, b) {
		      var texture = new REGLTexture(GL_TEXTURE_2D);
		      textureSet[texture.id] = texture;
		      stats.textureCount++;
	
		      function reglTexture2D(a, b) {
		        var texInfo = texture.texInfo;
		        TexInfo.call(texInfo);
		        var mipData = allocMipMap();
	
		        if (typeof a === 'number') {
		          if (typeof b === 'number') {
		            parseMipMapFromShape(mipData, a | 0, b | 0);
		          } else {
		            parseMipMapFromShape(mipData, a | 0, a | 0);
		          }
		        } else if (a) {
		          check$1.type(a, 'object', 'invalid arguments to regl.texture');
		          parseTexInfo(texInfo, a);
		          parseMipMapFromObject(mipData, a);
		        } else {
		          // empty textures get assigned a default shape of 1x1
		          parseMipMapFromShape(mipData, 1, 1);
		        }
	
		        if (texInfo.genMipmaps) {
		          mipData.mipmask = (mipData.width << 1) - 1;
		        }
		        texture.mipmask = mipData.mipmask;
	
		        copyFlags(texture, mipData);
	
		        check$1.texture2D(texInfo, mipData, limits);
		        texture.internalformat = mipData.internalformat;
	
		        reglTexture2D.width = mipData.width;
		        reglTexture2D.height = mipData.height;
	
		        tempBind(texture);
		        setMipMap(mipData, GL_TEXTURE_2D);
		        setTexInfo(texInfo, GL_TEXTURE_2D);
		        tempRestore();
	
		        freeMipMap(mipData);
	
		        if (config.profile) {
		          texture.stats.size = getTextureSize(texture.internalformat, texture.type, mipData.width, mipData.height, texInfo.genMipmaps, false);
		        }
		        reglTexture2D.format = textureFormatsInvert[texture.internalformat];
		        reglTexture2D.type = textureTypesInvert[texture.type];
	
		        reglTexture2D.mag = magFiltersInvert[texInfo.magFilter];
		        reglTexture2D.min = minFiltersInvert[texInfo.minFilter];
	
		        reglTexture2D.wrapS = wrapModesInvert[texInfo.wrapS];
		        reglTexture2D.wrapT = wrapModesInvert[texInfo.wrapT];
	
		        return reglTexture2D;
		      }
	
		      function subimage(image, x_, y_, level_) {
		        check$1(!!image, 'must specify image data');
	
		        var x = x_ | 0;
		        var y = y_ | 0;
		        var level = level_ | 0;
	
		        var imageData = allocImage();
		        copyFlags(imageData, texture);
		        imageData.width = 0;
		        imageData.height = 0;
		        parseImage(imageData, image);
		        imageData.width = imageData.width || (texture.width >> level) - x;
		        imageData.height = imageData.height || (texture.height >> level) - y;
	
		        check$1(texture.type === imageData.type && texture.format === imageData.format && texture.internalformat === imageData.internalformat, 'incompatible format for texture.subimage');
		        check$1(x >= 0 && y >= 0 && x + imageData.width <= texture.width && y + imageData.height <= texture.height, 'texture.subimage write out of bounds');
		        check$1(texture.mipmask & 1 << level, 'missing mipmap data');
		        check$1(imageData.data || imageData.element || imageData.needsCopy, 'missing image data');
	
		        tempBind(texture);
		        setSubImage(imageData, GL_TEXTURE_2D, x, y, level);
		        tempRestore();
	
		        freeImage(imageData);
	
		        return reglTexture2D;
		      }
	
		      function resize(w_, h_) {
		        var w = w_ | 0;
		        var h = h_ | 0 || w;
		        if (w === texture.width && h === texture.height) {
		          return reglTexture2D;
		        }
	
		        reglTexture2D.width = texture.width = w;
		        reglTexture2D.height = texture.height = h;
	
		        tempBind(texture);
		        for (var i = 0; texture.mipmask >> i; ++i) {
		          gl.texImage2D(GL_TEXTURE_2D, i, texture.format, w >> i, h >> i, 0, texture.format, texture.type, null);
		        }
		        tempRestore();
	
		        // also, recompute the texture size.
		        if (config.profile) {
		          texture.stats.size = getTextureSize(texture.internalformat, texture.type, w, h, false, false);
		        }
	
		        return reglTexture2D;
		      }
	
		      reglTexture2D(a, b);
	
		      reglTexture2D.subimage = subimage;
		      reglTexture2D.resize = resize;
		      reglTexture2D._reglType = 'texture2d';
		      reglTexture2D._texture = texture;
		      if (config.profile) {
		        reglTexture2D.stats = texture.stats;
		      }
		      reglTexture2D.destroy = function () {
		        texture.decRef();
		      };
	
		      return reglTexture2D;
		    }
	
		    function createTextureCube(a0, a1, a2, a3, a4, a5) {
		      var texture = new REGLTexture(GL_TEXTURE_CUBE_MAP);
		      textureSet[texture.id] = texture;
		      stats.cubeCount++;
	
		      var faces = new Array(6);
	
		      function reglTextureCube(a0, a1, a2, a3, a4, a5) {
		        var i;
		        var texInfo = texture.texInfo;
		        TexInfo.call(texInfo);
		        for (i = 0; i < 6; ++i) {
		          faces[i] = allocMipMap();
		        }
	
		        if (typeof a0 === 'number' || !a0) {
		          var s = a0 | 0 || 1;
		          for (i = 0; i < 6; ++i) {
		            parseMipMapFromShape(faces[i], s, s);
		          }
		        } else if (typeof a0 === 'object') {
		          if (a1) {
		            parseMipMapFromObject(faces[0], a0);
		            parseMipMapFromObject(faces[1], a1);
		            parseMipMapFromObject(faces[2], a2);
		            parseMipMapFromObject(faces[3], a3);
		            parseMipMapFromObject(faces[4], a4);
		            parseMipMapFromObject(faces[5], a5);
		          } else {
		            parseTexInfo(texInfo, a0);
		            parseFlags(texture, a0);
		            if ('faces' in a0) {
		              var face_input = a0.faces;
		              check$1(Array.isArray(face_input) && face_input.length === 6, 'cube faces must be a length 6 array');
		              for (i = 0; i < 6; ++i) {
		                check$1(typeof face_input[i] === 'object' && !!face_input[i], 'invalid input for cube map face');
		                copyFlags(faces[i], texture);
		                parseMipMapFromObject(faces[i], face_input[i]);
		              }
		            } else {
		              for (i = 0; i < 6; ++i) {
		                parseMipMapFromObject(faces[i], a0);
		              }
		            }
		          }
		        } else {
		          check$1.raise('invalid arguments to cube map');
		        }
	
		        copyFlags(texture, faces[0]);
		        if (texInfo.genMipmaps) {
		          texture.mipmask = (faces[0].width << 1) - 1;
		        } else {
		          texture.mipmask = faces[0].mipmask;
		        }
	
		        check$1.textureCube(texture, texInfo, faces, limits);
		        texture.internalformat = faces[0].internalformat;
	
		        reglTextureCube.width = faces[0].width;
		        reglTextureCube.height = faces[0].height;
	
		        tempBind(texture);
		        for (i = 0; i < 6; ++i) {
		          setMipMap(faces[i], GL_TEXTURE_CUBE_MAP_POSITIVE_X + i);
		        }
		        setTexInfo(texInfo, GL_TEXTURE_CUBE_MAP);
		        tempRestore();
	
		        if (config.profile) {
		          texture.stats.size = getTextureSize(texture.internalformat, texture.type, reglTextureCube.width, reglTextureCube.height, texInfo.genMipmaps, true);
		        }
	
		        reglTextureCube.format = textureFormatsInvert[texture.internalformat];
		        reglTextureCube.type = textureTypesInvert[texture.type];
	
		        reglTextureCube.mag = magFiltersInvert[texInfo.magFilter];
		        reglTextureCube.min = minFiltersInvert[texInfo.minFilter];
	
		        reglTextureCube.wrapS = wrapModesInvert[texInfo.wrapS];
		        reglTextureCube.wrapT = wrapModesInvert[texInfo.wrapT];
	
		        for (i = 0; i < 6; ++i) {
		          freeMipMap(faces[i]);
		        }
	
		        return reglTextureCube;
		      }
	
		      function subimage(face, image, x_, y_, level_) {
		        check$1(!!image, 'must specify image data');
		        check$1(typeof face === 'number' && face === (face | 0) && face >= 0 && face < 6, 'invalid face');
	
		        var x = x_ | 0;
		        var y = y_ | 0;
		        var level = level_ | 0;
	
		        var imageData = allocImage();
		        copyFlags(imageData, texture);
		        imageData.width = 0;
		        imageData.height = 0;
		        parseImage(imageData, image);
		        imageData.width = imageData.width || (texture.width >> level) - x;
		        imageData.height = imageData.height || (texture.height >> level) - y;
	
		        check$1(texture.type === imageData.type && texture.format === imageData.format && texture.internalformat === imageData.internalformat, 'incompatible format for texture.subimage');
		        check$1(x >= 0 && y >= 0 && x + imageData.width <= texture.width && y + imageData.height <= texture.height, 'texture.subimage write out of bounds');
		        check$1(texture.mipmask & 1 << level, 'missing mipmap data');
		        check$1(imageData.data || imageData.element || imageData.needsCopy, 'missing image data');
	
		        tempBind(texture);
		        setSubImage(imageData, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, x, y, level);
		        tempRestore();
	
		        freeImage(imageData);
	
		        return reglTextureCube;
		      }
	
		      function resize(radius_) {
		        var radius = radius_ | 0;
		        if (radius === texture.width) {
		          return;
		        }
	
		        reglTextureCube.width = texture.width = radius;
		        reglTextureCube.height = texture.height = radius;
	
		        tempBind(texture);
		        for (var i = 0; i < 6; ++i) {
		          for (var j = 0; texture.mipmask >> j; ++j) {
		            gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, j, texture.format, radius >> j, radius >> j, 0, texture.format, texture.type, null);
		          }
		        }
		        tempRestore();
	
		        if (config.profile) {
		          texture.stats.size = getTextureSize(texture.internalformat, texture.type, reglTextureCube.width, reglTextureCube.height, false, true);
		        }
	
		        return reglTextureCube;
		      }
	
		      reglTextureCube(a0, a1, a2, a3, a4, a5);
	
		      reglTextureCube.subimage = subimage;
		      reglTextureCube.resize = resize;
		      reglTextureCube._reglType = 'textureCube';
		      reglTextureCube._texture = texture;
		      if (config.profile) {
		        reglTextureCube.stats = texture.stats;
		      }
		      reglTextureCube.destroy = function () {
		        texture.decRef();
		      };
	
		      return reglTextureCube;
		    }
	
		    // Called when regl is destroyed
		    function destroyTextures() {
		      for (var i = 0; i < numTexUnits; ++i) {
		        gl.activeTexture(GL_TEXTURE0 + i);
		        gl.bindTexture(GL_TEXTURE_2D, null);
		        textureUnits[i] = null;
		      }
		      values(textureSet).forEach(destroy);
	
		      stats.cubeCount = 0;
		      stats.textureCount = 0;
		    }
	
		    if (config.profile) {
		      stats.getTotalTextureSize = function () {
		        var total = 0;
		        Object.keys(textureSet).forEach(function (key) {
		          total += textureSet[key].stats.size;
		        });
		        return total;
		      };
		    }
	
		    function restoreTextures() {
		      values(textureSet).forEach(function (texture) {
		        texture.texture = gl.createTexture();
		        gl.bindTexture(texture.target, texture.texture);
		        for (var i = 0; i < 32; ++i) {
		          if ((texture.mipmask & 1 << i) === 0) {
		            continue;
		          }
		          if (texture.target === GL_TEXTURE_2D) {
		            gl.texImage2D(GL_TEXTURE_2D, i, texture.internalformat, texture.width >> i, texture.height >> i, 0, texture.internalformat, texture.type, null);
		          } else {
		            for (var j = 0; j < 6; ++j) {
		              gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i, texture.internalformat, texture.width >> i, texture.height >> i, 0, texture.internalformat, texture.type, null);
		            }
		          }
		        }
		        setTexInfo(texture.texInfo, texture.target);
		      });
		    }
	
		    return {
		      create2D: createTexture2D,
		      createCube: createTextureCube,
		      clear: destroyTextures,
		      getTexture: function (wrapper) {
		        return null;
		      },
		      restore: restoreTextures
		    };
		  }
	
		  var GL_RENDERBUFFER = 0x8D41;
	
		  var GL_RGBA4$1 = 0x8056;
		  var GL_RGB5_A1$1 = 0x8057;
		  var GL_RGB565$1 = 0x8D62;
		  var GL_DEPTH_COMPONENT16 = 0x81A5;
		  var GL_STENCIL_INDEX8 = 0x8D48;
		  var GL_DEPTH_STENCIL$1 = 0x84F9;
	
		  var GL_SRGB8_ALPHA8_EXT = 0x8C43;
	
		  var GL_RGBA32F_EXT = 0x8814;
	
		  var GL_RGBA16F_EXT = 0x881A;
		  var GL_RGB16F_EXT = 0x881B;
	
		  var FORMAT_SIZES = [];
	
		  FORMAT_SIZES[GL_RGBA4$1] = 2;
		  FORMAT_SIZES[GL_RGB5_A1$1] = 2;
		  FORMAT_SIZES[GL_RGB565$1] = 2;
	
		  FORMAT_SIZES[GL_DEPTH_COMPONENT16] = 2;
		  FORMAT_SIZES[GL_STENCIL_INDEX8] = 1;
		  FORMAT_SIZES[GL_DEPTH_STENCIL$1] = 4;
	
		  FORMAT_SIZES[GL_SRGB8_ALPHA8_EXT] = 4;
		  FORMAT_SIZES[GL_RGBA32F_EXT] = 16;
		  FORMAT_SIZES[GL_RGBA16F_EXT] = 8;
		  FORMAT_SIZES[GL_RGB16F_EXT] = 6;
	
		  function getRenderbufferSize(format, width, height) {
		    return FORMAT_SIZES[format] * width * height;
		  }
	
		  var wrapRenderbuffers = function (gl, extensions, limits, stats, config) {
		    var formatTypes = {
		      'rgba4': GL_RGBA4$1,
		      'rgb565': GL_RGB565$1,
		      'rgb5 a1': GL_RGB5_A1$1,
		      'depth': GL_DEPTH_COMPONENT16,
		      'stencil': GL_STENCIL_INDEX8,
		      'depth stencil': GL_DEPTH_STENCIL$1
		    };
	
		    if (extensions.ext_srgb) {
		      formatTypes['srgba'] = GL_SRGB8_ALPHA8_EXT;
		    }
	
		    if (extensions.ext_color_buffer_half_float) {
		      formatTypes['rgba16f'] = GL_RGBA16F_EXT;
		      formatTypes['rgb16f'] = GL_RGB16F_EXT;
		    }
	
		    if (extensions.webgl_color_buffer_float) {
		      formatTypes['rgba32f'] = GL_RGBA32F_EXT;
		    }
	
		    var formatTypesInvert = [];
		    Object.keys(formatTypes).forEach(function (key) {
		      var val = formatTypes[key];
		      formatTypesInvert[val] = key;
		    });
	
		    var renderbufferCount = 0;
		    var renderbufferSet = {};
	
		    function REGLRenderbuffer(renderbuffer) {
		      this.id = renderbufferCount++;
		      this.refCount = 1;
	
		      this.renderbuffer = renderbuffer;
	
		      this.format = GL_RGBA4$1;
		      this.width = 0;
		      this.height = 0;
	
		      if (config.profile) {
		        this.stats = { size: 0 };
		      }
		    }
	
		    REGLRenderbuffer.prototype.decRef = function () {
		      if (--this.refCount <= 0) {
		        destroy(this);
		      }
		    };
	
		    function destroy(rb) {
		      var handle = rb.renderbuffer;
		      check$1(handle, 'must not double destroy renderbuffer');
		      gl.bindRenderbuffer(GL_RENDERBUFFER, null);
		      gl.deleteRenderbuffer(handle);
		      rb.renderbuffer = null;
		      rb.refCount = 0;
		      delete renderbufferSet[rb.id];
		      stats.renderbufferCount--;
		    }
	
		    function createRenderbuffer(a, b) {
		      var renderbuffer = new REGLRenderbuffer(gl.createRenderbuffer());
		      renderbufferSet[renderbuffer.id] = renderbuffer;
		      stats.renderbufferCount++;
	
		      function reglRenderbuffer(a, b) {
		        var w = 0;
		        var h = 0;
		        var format = GL_RGBA4$1;
	
		        if (typeof a === 'object' && a) {
		          var options = a;
		          if ('shape' in options) {
		            var shape = options.shape;
		            check$1(Array.isArray(shape) && shape.length >= 2, 'invalid renderbuffer shape');
		            w = shape[0] | 0;
		            h = shape[1] | 0;
		          } else {
		            if ('radius' in options) {
		              w = h = options.radius | 0;
		            }
		            if ('width' in options) {
		              w = options.width | 0;
		            }
		            if ('height' in options) {
		              h = options.height | 0;
		            }
		          }
		          if ('format' in options) {
		            check$1.parameter(options.format, formatTypes, 'invalid renderbuffer format');
		            format = formatTypes[options.format];
		          }
		        } else if (typeof a === 'number') {
		          w = a | 0;
		          if (typeof b === 'number') {
		            h = b | 0;
		          } else {
		            h = w;
		          }
		        } else if (!a) {
		          w = h = 1;
		        } else {
		          check$1.raise('invalid arguments to renderbuffer constructor');
		        }
	
		        // check shape
		        check$1(w > 0 && h > 0 && w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize, 'invalid renderbuffer size');
	
		        if (w === renderbuffer.width && h === renderbuffer.height && format === renderbuffer.format) {
		          return;
		        }
	
		        reglRenderbuffer.width = renderbuffer.width = w;
		        reglRenderbuffer.height = renderbuffer.height = h;
		        renderbuffer.format = format;
	
		        gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer);
		        gl.renderbufferStorage(GL_RENDERBUFFER, format, w, h);
	
		        if (config.profile) {
		          renderbuffer.stats.size = getRenderbufferSize(renderbuffer.format, renderbuffer.width, renderbuffer.height);
		        }
		        reglRenderbuffer.format = formatTypesInvert[renderbuffer.format];
	
		        return reglRenderbuffer;
		      }
	
		      function resize(w_, h_) {
		        var w = w_ | 0;
		        var h = h_ | 0 || w;
	
		        if (w === renderbuffer.width && h === renderbuffer.height) {
		          return reglRenderbuffer;
		        }
	
		        // check shape
		        check$1(w > 0 && h > 0 && w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize, 'invalid renderbuffer size');
	
		        reglRenderbuffer.width = renderbuffer.width = w;
		        reglRenderbuffer.height = renderbuffer.height = h;
	
		        gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer);
		        gl.renderbufferStorage(GL_RENDERBUFFER, renderbuffer.format, w, h);
	
		        // also, recompute size.
		        if (config.profile) {
		          renderbuffer.stats.size = getRenderbufferSize(renderbuffer.format, renderbuffer.width, renderbuffer.height);
		        }
	
		        return reglRenderbuffer;
		      }
	
		      reglRenderbuffer(a, b);
	
		      reglRenderbuffer.resize = resize;
		      reglRenderbuffer._reglType = 'renderbuffer';
		      reglRenderbuffer._renderbuffer = renderbuffer;
		      if (config.profile) {
		        reglRenderbuffer.stats = renderbuffer.stats;
		      }
		      reglRenderbuffer.destroy = function () {
		        renderbuffer.decRef();
		      };
	
		      return reglRenderbuffer;
		    }
	
		    if (config.profile) {
		      stats.getTotalRenderbufferSize = function () {
		        var total = 0;
		        Object.keys(renderbufferSet).forEach(function (key) {
		          total += renderbufferSet[key].stats.size;
		        });
		        return total;
		      };
		    }
	
		    function restoreRenderbuffers() {
		      values(renderbufferSet).forEach(function (rb) {
		        rb.renderbuffer = gl.createRenderbuffer();
		        gl.bindRenderbuffer(GL_RENDERBUFFER, rb.renderbuffer);
		        gl.renderbufferStorage(GL_RENDERBUFFER, rb.format, rb.width, rb.height);
		      });
		      gl.bindRenderbuffer(GL_RENDERBUFFER, null);
		    }
	
		    return {
		      create: createRenderbuffer,
		      clear: function () {
		        values(renderbufferSet).forEach(destroy);
		      },
		      restore: restoreRenderbuffers
		    };
		  };
	
		  // We store these constants so that the minifier can inline them
		  var GL_FRAMEBUFFER = 0x8D40;
		  var GL_RENDERBUFFER$1 = 0x8D41;
	
		  var GL_TEXTURE_2D$1 = 0x0DE1;
		  var GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 = 0x8515;
	
		  var GL_COLOR_ATTACHMENT0 = 0x8CE0;
		  var GL_DEPTH_ATTACHMENT = 0x8D00;
		  var GL_STENCIL_ATTACHMENT = 0x8D20;
		  var GL_DEPTH_STENCIL_ATTACHMENT = 0x821A;
	
		  var GL_FRAMEBUFFER_COMPLETE = 0x8CD5;
		  var GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6;
		  var GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7;
		  var GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9;
		  var GL_FRAMEBUFFER_UNSUPPORTED = 0x8CDD;
	
		  var GL_HALF_FLOAT_OES$2 = 0x8D61;
		  var GL_UNSIGNED_BYTE$5 = 0x1401;
		  var GL_FLOAT$4 = 0x1406;
	
		  var GL_RGBA$1 = 0x1908;
	
		  var GL_DEPTH_COMPONENT$1 = 0x1902;
	
		  var colorTextureFormatEnums = [GL_RGBA$1];
	
		  // for every texture format, store
		  // the number of channels
		  var textureFormatChannels = [];
		  textureFormatChannels[GL_RGBA$1] = 4;
	
		  // for every texture type, store
		  // the size in bytes.
		  var textureTypeSizes = [];
		  textureTypeSizes[GL_UNSIGNED_BYTE$5] = 1;
		  textureTypeSizes[GL_FLOAT$4] = 4;
		  textureTypeSizes[GL_HALF_FLOAT_OES$2] = 2;
	
		  var GL_RGBA4$2 = 0x8056;
		  var GL_RGB5_A1$2 = 0x8057;
		  var GL_RGB565$2 = 0x8D62;
		  var GL_DEPTH_COMPONENT16$1 = 0x81A5;
		  var GL_STENCIL_INDEX8$1 = 0x8D48;
		  var GL_DEPTH_STENCIL$2 = 0x84F9;
	
		  var GL_SRGB8_ALPHA8_EXT$1 = 0x8C43;
	
		  var GL_RGBA32F_EXT$1 = 0x8814;
	
		  var GL_RGBA16F_EXT$1 = 0x881A;
		  var GL_RGB16F_EXT$1 = 0x881B;
	
		  var colorRenderbufferFormatEnums = [GL_RGBA4$2, GL_RGB5_A1$2, GL_RGB565$2, GL_SRGB8_ALPHA8_EXT$1, GL_RGBA16F_EXT$1, GL_RGB16F_EXT$1, GL_RGBA32F_EXT$1];
	
		  var statusCode = {};
		  statusCode[GL_FRAMEBUFFER_COMPLETE] = 'complete';
		  statusCode[GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT] = 'incomplete attachment';
		  statusCode[GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS] = 'incomplete dimensions';
		  statusCode[GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT] = 'incomplete, missing attachment';
		  statusCode[GL_FRAMEBUFFER_UNSUPPORTED] = 'unsupported';
	
		  function wrapFBOState(gl, extensions, limits, textureState, renderbufferState, stats) {
		    var framebufferState = {
		      cur: null,
		      next: null,
		      dirty: false,
		      setFBO: null
		    };
	
		    var colorTextureFormats = ['rgba'];
		    var colorRenderbufferFormats = ['rgba4', 'rgb565', 'rgb5 a1'];
	
		    if (extensions.ext_srgb) {
		      colorRenderbufferFormats.push('srgba');
		    }
	
		    if (extensions.ext_color_buffer_half_float) {
		      colorRenderbufferFormats.push('rgba16f', 'rgb16f');
		    }
	
		    if (extensions.webgl_color_buffer_float) {
		      colorRenderbufferFormats.push('rgba32f');
		    }
	
		    var colorTypes = ['uint8'];
		    if (extensions.oes_texture_half_float) {
		      colorTypes.push('half float', 'float16');
		    }
		    if (extensions.oes_texture_float) {
		      colorTypes.push('float', 'float32');
		    }
	
		    function FramebufferAttachment(target, texture, renderbuffer) {
		      this.target = target;
		      this.texture = texture;
		      this.renderbuffer = renderbuffer;
	
		      var w = 0;
		      var h = 0;
		      if (texture) {
		        w = texture.width;
		        h = texture.height;
		      } else if (renderbuffer) {
		        w = renderbuffer.width;
		        h = renderbuffer.height;
		      }
		      this.width = w;
		      this.height = h;
		    }
	
		    function decRef(attachment) {
		      if (attachment) {
		        if (attachment.texture) {
		          attachment.texture._texture.decRef();
		        }
		        if (attachment.renderbuffer) {
		          attachment.renderbuffer._renderbuffer.decRef();
		        }
		      }
		    }
	
		    function incRefAndCheckShape(attachment, width, height) {
		      if (!attachment) {
		        return;
		      }
		      if (attachment.texture) {
		        var texture = attachment.texture._texture;
		        var tw = Math.max(1, texture.width);
		        var th = Math.max(1, texture.height);
		        check$1(tw === width && th === height, 'inconsistent width/height for supplied texture');
		        texture.refCount += 1;
		      } else {
		        var renderbuffer = attachment.renderbuffer._renderbuffer;
		        check$1(renderbuffer.width === width && renderbuffer.height === height, 'inconsistent width/height for renderbuffer');
		        renderbuffer.refCount += 1;
		      }
		    }
	
		    function attach(location, attachment) {
		      if (attachment) {
		        if (attachment.texture) {
		          gl.framebufferTexture2D(GL_FRAMEBUFFER, location, attachment.target, attachment.texture._texture.texture, 0);
		        } else {
		          gl.framebufferRenderbuffer(GL_FRAMEBUFFER, location, GL_RENDERBUFFER$1, attachment.renderbuffer._renderbuffer.renderbuffer);
		        }
		      }
		    }
	
		    function parseAttachment(attachment) {
		      var target = GL_TEXTURE_2D$1;
		      var texture = null;
		      var renderbuffer = null;
	
		      var data = attachment;
		      if (typeof attachment === 'object') {
		        data = attachment.data;
		        if ('target' in attachment) {
		          target = attachment.target | 0;
		        }
		      }
	
		      check$1.type(data, 'function', 'invalid attachment data');
	
		      var type = data._reglType;
		      if (type === 'texture2d') {
		        texture = data;
		        check$1(target === GL_TEXTURE_2D$1);
		      } else if (type === 'textureCube') {
		        texture = data;
		        check$1(target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 && target < GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + 6, 'invalid cube map target');
		      } else if (type === 'renderbuffer') {
		        renderbuffer = data;
		        target = GL_RENDERBUFFER$1;
		      } else {
		        check$1.raise('invalid regl object for attachment');
		      }
	
		      return new FramebufferAttachment(target, texture, renderbuffer);
		    }
	
		    function allocAttachment(width, height, isTexture, format, type) {
		      if (isTexture) {
		        var texture = textureState.create2D({
		          width: width,
		          height: height,
		          format: format,
		          type: type
		        });
		        texture._texture.refCount = 0;
		        return new FramebufferAttachment(GL_TEXTURE_2D$1, texture, null);
		      } else {
		        var rb = renderbufferState.create({
		          width: width,
		          height: height,
		          format: format
		        });
		        rb._renderbuffer.refCount = 0;
		        return new FramebufferAttachment(GL_RENDERBUFFER$1, null, rb);
		      }
		    }
	
		    function unwrapAttachment(attachment) {
		      return attachment && (attachment.texture || attachment.renderbuffer);
		    }
	
		    function resizeAttachment(attachment, w, h) {
		      if (attachment) {
		        if (attachment.texture) {
		          attachment.texture.resize(w, h);
		        } else if (attachment.renderbuffer) {
		          attachment.renderbuffer.resize(w, h);
		        }
		      }
		    }
	
		    var framebufferCount = 0;
		    var framebufferSet = {};
	
		    function REGLFramebuffer() {
		      this.id = framebufferCount++;
		      framebufferSet[this.id] = this;
	
		      this.framebuffer = gl.createFramebuffer();
		      this.width = 0;
		      this.height = 0;
	
		      this.colorAttachments = [];
		      this.depthAttachment = null;
		      this.stencilAttachment = null;
		      this.depthStencilAttachment = null;
		    }
	
		    function decFBORefs(framebuffer) {
		      framebuffer.colorAttachments.forEach(decRef);
		      decRef(framebuffer.depthAttachment);
		      decRef(framebuffer.stencilAttachment);
		      decRef(framebuffer.depthStencilAttachment);
		    }
	
		    function destroy(framebuffer) {
		      var handle = framebuffer.framebuffer;
		      check$1(handle, 'must not double destroy framebuffer');
		      gl.deleteFramebuffer(handle);
		      framebuffer.framebuffer = null;
		      stats.framebufferCount--;
		      delete framebufferSet[framebuffer.id];
		    }
	
		    function updateFramebuffer(framebuffer) {
		      var i;
	
		      gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer.framebuffer);
		      var colorAttachments = framebuffer.colorAttachments;
		      for (i = 0; i < colorAttachments.length; ++i) {
		        attach(GL_COLOR_ATTACHMENT0 + i, colorAttachments[i]);
		      }
		      for (i = colorAttachments.length; i < limits.maxColorAttachments; ++i) {
		        gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D$1, null, 0);
		      }
	
		      gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D$1, null, 0);
		      gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D$1, null, 0);
		      gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D$1, null, 0);
	
		      attach(GL_DEPTH_ATTACHMENT, framebuffer.depthAttachment);
		      attach(GL_STENCIL_ATTACHMENT, framebuffer.stencilAttachment);
		      attach(GL_DEPTH_STENCIL_ATTACHMENT, framebuffer.depthStencilAttachment);
	
		      // Check status code
		      var status = gl.checkFramebufferStatus(GL_FRAMEBUFFER);
		      if (status !== GL_FRAMEBUFFER_COMPLETE) {
		        check$1.raise('framebuffer configuration not supported, status = ' + statusCode[status]);
		      }
	
		      gl.bindFramebuffer(GL_FRAMEBUFFER, framebufferState.next);
		      framebufferState.cur = framebufferState.next;
	
		      // FIXME: Clear error code here.  This is a work around for a bug in
		      // headless-gl
		      gl.getError();
		    }
	
		    function createFBO(a0, a1) {
		      var framebuffer = new REGLFramebuffer();
		      stats.framebufferCount++;
	
		      function reglFramebuffer(a, b) {
		        var i;
	
		        check$1(framebufferState.next !== framebuffer, 'can not update framebuffer which is currently in use');
	
		        var extDrawBuffers = extensions.webgl_draw_buffers;
	
		        var width = 0;
		        var height = 0;
	
		        var needsDepth = true;
		        var needsStencil = true;
	
		        var colorBuffer = null;
		        var colorTexture = true;
		        var colorFormat = 'rgba';
		        var colorType = 'uint8';
		        var colorCount = 1;
	
		        var depthBuffer = null;
		        var stencilBuffer = null;
		        var depthStencilBuffer = null;
		        var depthStencilTexture = false;
	
		        if (typeof a === 'number') {
		          width = a | 0;
		          height = b | 0 || width;
		        } else if (!a) {
		          width = height = 1;
		        } else {
		          check$1.type(a, 'object', 'invalid arguments for framebuffer');
		          var options = a;
	
		          if ('shape' in options) {
		            var shape = options.shape;
		            check$1(Array.isArray(shape) && shape.length >= 2, 'invalid shape for framebuffer');
		            width = shape[0];
		            height = shape[1];
		          } else {
		            if ('radius' in options) {
		              width = height = options.radius;
		            }
		            if ('width' in options) {
		              width = options.width;
		            }
		            if ('height' in options) {
		              height = options.height;
		            }
		          }
	
		          if ('color' in options || 'colors' in options) {
		            colorBuffer = options.color || options.colors;
		            if (Array.isArray(colorBuffer)) {
		              check$1(colorBuffer.length === 1 || extDrawBuffers, 'multiple render targets not supported');
		            }
		          }
	
		          if (!colorBuffer) {
		            if ('colorCount' in options) {
		              colorCount = options.colorCount | 0;
		              check$1(colorCount > 0, 'invalid color buffer count');
		            }
	
		            if ('colorTexture' in options) {
		              colorTexture = !!options.colorTexture;
		              colorFormat = 'rgba4';
		            }
	
		            if ('colorType' in options) {
		              colorType = options.colorType;
		              if (!colorTexture) {
		                if (colorType === 'half float' || colorType === 'float16') {
		                  check$1(extensions.ext_color_buffer_half_float, 'you must enable EXT_color_buffer_half_float to use 16-bit render buffers');
		                  colorFormat = 'rgba16f';
		                } else if (colorType === 'float' || colorType === 'float32') {
		                  check$1(extensions.webgl_color_buffer_float, 'you must enable WEBGL_color_buffer_float in order to use 32-bit floating point renderbuffers');
		                  colorFormat = 'rgba32f';
		                }
		              } else {
		                check$1(extensions.oes_texture_float || !(colorType === 'float' || colorType === 'float32'), 'you must enable OES_texture_float in order to use floating point framebuffer objects');
		                check$1(extensions.oes_texture_half_float || !(colorType === 'half float' || colorType === 'float16'), 'you must enable OES_texture_half_float in order to use 16-bit floating point framebuffer objects');
		              }
		              check$1.oneOf(colorType, colorTypes, 'invalid color type');
		            }
	
		            if ('colorFormat' in options) {
		              colorFormat = options.colorFormat;
		              if (colorTextureFormats.indexOf(colorFormat) >= 0) {
		                colorTexture = true;
		              } else if (colorRenderbufferFormats.indexOf(colorFormat) >= 0) {
		                colorTexture = false;
		              } else {
		                if (colorTexture) {
		                  check$1.oneOf(options.colorFormat, colorTextureFormats, 'invalid color format for texture');
		                } else {
		                  check$1.oneOf(options.colorFormat, colorRenderbufferFormats, 'invalid color format for renderbuffer');
		                }
		              }
		            }
		          }
	
		          if ('depthTexture' in options || 'depthStencilTexture' in options) {
		            depthStencilTexture = !!(options.depthTexture || options.depthStencilTexture);
		            check$1(!depthStencilTexture || extensions.webgl_depth_texture, 'webgl_depth_texture extension not supported');
		          }
	
		          if ('depth' in options) {
		            if (typeof options.depth === 'boolean') {
		              needsDepth = options.depth;
		            } else {
		              depthBuffer = options.depth;
		              needsStencil = false;
		            }
		          }
	
		          if ('stencil' in options) {
		            if (typeof options.stencil === 'boolean') {
		              needsStencil = options.stencil;
		            } else {
		              stencilBuffer = options.stencil;
		              needsDepth = false;
		            }
		          }
	
		          if ('depthStencil' in options) {
		            if (typeof options.depthStencil === 'boolean') {
		              needsDepth = needsStencil = options.depthStencil;
		            } else {
		              depthStencilBuffer = options.depthStencil;
		              needsDepth = false;
		              needsStencil = false;
		            }
		          }
		        }
	
		        // parse attachments
		        var colorAttachments = null;
		        var depthAttachment = null;
		        var stencilAttachment = null;
		        var depthStencilAttachment = null;
	
		        // Set up color attachments
		        if (Array.isArray(colorBuffer)) {
		          colorAttachments = colorBuffer.map(parseAttachment);
		        } else if (colorBuffer) {
		          colorAttachments = [parseAttachment(colorBuffer)];
		        } else {
		          colorAttachments = new Array(colorCount);
		          for (i = 0; i < colorCount; ++i) {
		            colorAttachments[i] = allocAttachment(width, height, colorTexture, colorFormat, colorType);
		          }
		        }
	
		        check$1(extensions.webgl_draw_buffers || colorAttachments.length <= 1, 'you must enable the WEBGL_draw_buffers extension in order to use multiple color buffers.');
		        check$1(colorAttachments.length <= limits.maxColorAttachments, 'too many color attachments, not supported');
	
		        width = width || colorAttachments[0].width;
		        height = height || colorAttachments[0].height;
	
		        if (depthBuffer) {
		          depthAttachment = parseAttachment(depthBuffer);
		        } else if (needsDepth && !needsStencil) {
		          depthAttachment = allocAttachment(width, height, depthStencilTexture, 'depth', 'uint32');
		        }
	
		        if (stencilBuffer) {
		          stencilAttachment = parseAttachment(stencilBuffer);
		        } else if (needsStencil && !needsDepth) {
		          stencilAttachment = allocAttachment(width, height, false, 'stencil', 'uint8');
		        }
	
		        if (depthStencilBuffer) {
		          depthStencilAttachment = parseAttachment(depthStencilBuffer);
		        } else if (!depthBuffer && !stencilBuffer && needsStencil && needsDepth) {
		          depthStencilAttachment = allocAttachment(width, height, depthStencilTexture, 'depth stencil', 'depth stencil');
		        }
	
		        check$1(!!depthBuffer + !!stencilBuffer + !!depthStencilBuffer <= 1, 'invalid framebuffer configuration, can specify exactly one depth/stencil attachment');
	
		        var commonColorAttachmentSize = null;
	
		        for (i = 0; i < colorAttachments.length; ++i) {
		          incRefAndCheckShape(colorAttachments[i], width, height);
		          check$1(!colorAttachments[i] || colorAttachments[i].texture && colorTextureFormatEnums.indexOf(colorAttachments[i].texture._texture.format) >= 0 || colorAttachments[i].renderbuffer && colorRenderbufferFormatEnums.indexOf(colorAttachments[i].renderbuffer._renderbuffer.format) >= 0, 'framebuffer color attachment ' + i + ' is invalid');
	
		          if (colorAttachments[i] && colorAttachments[i].texture) {
		            var colorAttachmentSize = textureFormatChannels[colorAttachments[i].texture._texture.format] * textureTypeSizes[colorAttachments[i].texture._texture.type];
	
		            if (commonColorAttachmentSize === null) {
		              commonColorAttachmentSize = colorAttachmentSize;
		            } else {
		              // We need to make sure that all color attachments have the same number of bitplanes
		              // (that is, the same numer of bits per pixel)
		              // This is required by the GLES2.0 standard. See the beginning of Chapter 4 in that document.
		              check$1(commonColorAttachmentSize === colorAttachmentSize, 'all color attachments much have the same number of bits per pixel.');
		            }
		          }
		        }
		        incRefAndCheckShape(depthAttachment, width, height);
		        check$1(!depthAttachment || depthAttachment.texture && depthAttachment.texture._texture.format === GL_DEPTH_COMPONENT$1 || depthAttachment.renderbuffer && depthAttachment.renderbuffer._renderbuffer.format === GL_DEPTH_COMPONENT16$1, 'invalid depth attachment for framebuffer object');
		        incRefAndCheckShape(stencilAttachment, width, height);
		        check$1(!stencilAttachment || stencilAttachment.renderbuffer && stencilAttachment.renderbuffer._renderbuffer.format === GL_STENCIL_INDEX8$1, 'invalid stencil attachment for framebuffer object');
		        incRefAndCheckShape(depthStencilAttachment, width, height);
		        check$1(!depthStencilAttachment || depthStencilAttachment.texture && depthStencilAttachment.texture._texture.format === GL_DEPTH_STENCIL$2 || depthStencilAttachment.renderbuffer && depthStencilAttachment.renderbuffer._renderbuffer.format === GL_DEPTH_STENCIL$2, 'invalid depth-stencil attachment for framebuffer object');
	
		        // decrement references
		        decFBORefs(framebuffer);
	
		        framebuffer.width = width;
		        framebuffer.height = height;
	
		        framebuffer.colorAttachments = colorAttachments;
		        framebuffer.depthAttachment = depthAttachment;
		        framebuffer.stencilAttachment = stencilAttachment;
		        framebuffer.depthStencilAttachment = depthStencilAttachment;
	
		        reglFramebuffer.color = colorAttachments.map(unwrapAttachment);
		        reglFramebuffer.depth = unwrapAttachment(depthAttachment);
		        reglFramebuffer.stencil = unwrapAttachment(stencilAttachment);
		        reglFramebuffer.depthStencil = unwrapAttachment(depthStencilAttachment);
	
		        reglFramebuffer.width = framebuffer.width;
		        reglFramebuffer.height = framebuffer.height;
	
		        updateFramebuffer(framebuffer);
	
		        return reglFramebuffer;
		      }
	
		      function resize(w_, h_) {
		        check$1(framebufferState.next !== framebuffer, 'can not resize a framebuffer which is currently in use');
	
		        var w = w_ | 0;
		        var h = h_ | 0 || w;
		        if (w === framebuffer.width && h === framebuffer.height) {
		          return reglFramebuffer;
		        }
	
		        // resize all buffers
		        var colorAttachments = framebuffer.colorAttachments;
		        for (var i = 0; i < colorAttachments.length; ++i) {
		          resizeAttachment(colorAttachments[i], w, h);
		        }
		        resizeAttachment(framebuffer.depthAttachment, w, h);
		        resizeAttachment(framebuffer.stencilAttachment, w, h);
		        resizeAttachment(framebuffer.depthStencilAttachment, w, h);
	
		        framebuffer.width = reglFramebuffer.width = w;
		        framebuffer.height = reglFramebuffer.height = h;
	
		        updateFramebuffer(framebuffer);
	
		        return reglFramebuffer;
		      }
	
		      reglFramebuffer(a0, a1);
	
		      return extend(reglFramebuffer, {
		        resize: resize,
		        _reglType: 'framebuffer',
		        _framebuffer: framebuffer,
		        destroy: function () {
		          destroy(framebuffer);
		          decFBORefs(framebuffer);
		        },
		        use: function (block) {
		          framebufferState.setFBO({
		            framebuffer: reglFramebuffer
		          }, block);
		        }
		      });
		    }
	
		    function createCubeFBO(options) {
		      var faces = Array(6);
	
		      function reglFramebufferCube(a) {
		        var i;
	
		        check$1(faces.indexOf(framebufferState.next) < 0, 'can not update framebuffer which is currently in use');
	
		        var extDrawBuffers = extensions.webgl_draw_buffers;
	
		        var params = {
		          color: null
		        };
	
		        var radius = 0;
	
		        var colorBuffer = null;
		        var colorFormat = 'rgba';
		        var colorType = 'uint8';
		        var colorCount = 1;
	
		        if (typeof a === 'number') {
		          radius = a | 0;
		        } else if (!a) {
		          radius = 1;
		        } else {
		          check$1.type(a, 'object', 'invalid arguments for framebuffer');
		          var options = a;
	
		          if ('shape' in options) {
		            var shape = options.shape;
		            check$1(Array.isArray(shape) && shape.length >= 2, 'invalid shape for framebuffer');
		            check$1(shape[0] === shape[1], 'cube framebuffer must be square');
		            radius = shape[0];
		          } else {
		            if ('radius' in options) {
		              radius = options.radius | 0;
		            }
		            if ('width' in options) {
		              radius = options.width | 0;
		              if ('height' in options) {
		                check$1(options.height === radius, 'must be square');
		              }
		            } else if ('height' in options) {
		              radius = options.height | 0;
		            }
		          }
	
		          if ('color' in options || 'colors' in options) {
		            colorBuffer = options.color || options.colors;
		            if (Array.isArray(colorBuffer)) {
		              check$1(colorBuffer.length === 1 || extDrawBuffers, 'multiple render targets not supported');
		            }
		          }
	
		          if (!colorBuffer) {
		            if ('colorCount' in options) {
		              colorCount = options.colorCount | 0;
		              check$1(colorCount > 0, 'invalid color buffer count');
		            }
	
		            if ('colorType' in options) {
		              check$1.oneOf(options.colorType, colorTypes, 'invalid color type');
		              colorType = options.colorType;
		            }
	
		            if ('colorFormat' in options) {
		              colorFormat = options.colorFormat;
		              check$1.oneOf(options.colorFormat, colorTextureFormats, 'invalid color format for texture');
		            }
		          }
	
		          if ('depth' in options) {
		            params.depth = options.depth;
		          }
	
		          if ('stencil' in options) {
		            params.stencil = options.stencil;
		          }
	
		          if ('depthStencil' in options) {
		            params.depthStencil = options.depthStencil;
		          }
		        }
	
		        var colorCubes;
		        if (colorBuffer) {
		          if (Array.isArray(colorBuffer)) {
		            colorCubes = [];
		            for (i = 0; i < colorBuffer.length; ++i) {
		              colorCubes[i] = colorBuffer[i];
		            }
		          } else {
		            colorCubes = [colorBuffer];
		          }
		        } else {
		          colorCubes = Array(colorCount);
		          var cubeMapParams = {
		            radius: radius,
		            format: colorFormat,
		            type: colorType
		          };
		          for (i = 0; i < colorCount; ++i) {
		            colorCubes[i] = textureState.createCube(cubeMapParams);
		          }
		        }
	
		        // Check color cubes
		        params.color = Array(colorCubes.length);
		        for (i = 0; i < colorCubes.length; ++i) {
		          var cube = colorCubes[i];
		          check$1(typeof cube === 'function' && cube._reglType === 'textureCube', 'invalid cube map');
		          radius = radius || cube.width;
		          check$1(cube.width === radius && cube.height === radius, 'invalid cube map shape');
		          params.color[i] = {
		            target: GL_TEXTURE_CUBE_MAP_POSITIVE_X$1,
		            data: colorCubes[i]
		          };
		        }
	
		        for (i = 0; i < 6; ++i) {
		          for (var j = 0; j < colorCubes.length; ++j) {
		            params.color[j].target = GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + i;
		          }
		          // reuse depth-stencil attachments across all cube maps
		          if (i > 0) {
		            params.depth = faces[0].depth;
		            params.stencil = faces[0].stencil;
		            params.depthStencil = faces[0].depthStencil;
		          }
		          if (faces[i]) {
		            faces[i](params);
		          } else {
		            faces[i] = createFBO(params);
		          }
		        }
	
		        return extend(reglFramebufferCube, {
		          width: radius,
		          height: radius,
		          color: colorCubes
		        });
		      }
	
		      function resize(radius_) {
		        var i;
		        var radius = radius_ | 0;
		        check$1(radius > 0 && radius <= limits.maxCubeMapSize, 'invalid radius for cube fbo');
	
		        if (radius === reglFramebufferCube.width) {
		          return reglFramebufferCube;
		        }
	
		        var colors = reglFramebufferCube.color;
		        for (i = 0; i < colors.length; ++i) {
		          colors[i].resize(radius);
		        }
	
		        for (i = 0; i < 6; ++i) {
		          faces[i].resize(radius);
		        }
	
		        reglFramebufferCube.width = reglFramebufferCube.height = radius;
	
		        return reglFramebufferCube;
		      }
	
		      reglFramebufferCube(options);
	
		      return extend(reglFramebufferCube, {
		        faces: faces,
		        resize: resize,
		        _reglType: 'framebufferCube',
		        destroy: function () {
		          faces.forEach(function (f) {
		            f.destroy();
		          });
		        }
		      });
		    }
	
		    function restoreFramebuffers() {
		      values(framebufferSet).forEach(function (fb) {
		        fb.framebuffer = gl.createFramebuffer();
		        updateFramebuffer(fb);
		      });
		    }
	
		    return extend(framebufferState, {
		      getFramebuffer: function (object) {
		        if (typeof object === 'function' && object._reglType === 'framebuffer') {
		          var fbo = object._framebuffer;
		          if (fbo instanceof REGLFramebuffer) {
		            return fbo;
		          }
		        }
		        return null;
		      },
		      create: createFBO,
		      createCube: createCubeFBO,
		      clear: function () {
		        values(framebufferSet).forEach(destroy);
		      },
		      restore: restoreFramebuffers
		    });
		  }
	
		  var GL_FLOAT$5 = 5126;
	
		  function AttributeRecord() {
		    this.state = 0;
	
		    this.x = 0.0;
		    this.y = 0.0;
		    this.z = 0.0;
		    this.w = 0.0;
	
		    this.buffer = null;
		    this.size = 0;
		    this.normalized = false;
		    this.type = GL_FLOAT$5;
		    this.offset = 0;
		    this.stride = 0;
		    this.divisor = 0;
		  }
	
		  function wrapAttributeState(gl, extensions, limits, bufferState, stringStore) {
		    var NUM_ATTRIBUTES = limits.maxAttributes;
		    var attributeBindings = new Array(NUM_ATTRIBUTES);
		    for (var i = 0; i < NUM_ATTRIBUTES; ++i) {
		      attributeBindings[i] = new AttributeRecord();
		    }
	
		    return {
		      Record: AttributeRecord,
		      scope: {},
		      state: attributeBindings
		    };
		  }
	
		  var GL_FRAGMENT_SHADER = 35632;
		  var GL_VERTEX_SHADER = 35633;
	
		  var GL_ACTIVE_UNIFORMS = 0x8B86;
		  var GL_ACTIVE_ATTRIBUTES = 0x8B89;
	
		  function wrapShaderState(gl, stringStore, stats, config) {
		    // ===================================================
		    // glsl compilation and linking
		    // ===================================================
		    var fragShaders = {};
		    var vertShaders = {};
	
		    function ActiveInfo(name, id, location, info) {
		      this.name = name;
		      this.id = id;
		      this.location = location;
		      this.info = info;
		    }
	
		    function insertActiveInfo(list, info) {
		      for (var i = 0; i < list.length; ++i) {
		        if (list[i].id === info.id) {
		          list[i].location = info.location;
		          return;
		        }
		      }
		      list.push(info);
		    }
	
		    function getShader(type, id, command) {
		      var cache = type === GL_FRAGMENT_SHADER ? fragShaders : vertShaders;
		      var shader = cache[id];
	
		      if (!shader) {
		        var source = stringStore.str(id);
		        shader = gl.createShader(type);
		        gl.shaderSource(shader, source);
		        gl.compileShader(shader);
		        check$1.shaderError(gl, shader, source, type, command);
		        cache[id] = shader;
		      }
	
		      return shader;
		    }
	
		    // ===================================================
		    // program linking
		    // ===================================================
		    var programCache = {};
		    var programList = [];
	
		    var PROGRAM_COUNTER = 0;
	
		    function REGLProgram(fragId, vertId) {
		      this.id = PROGRAM_COUNTER++;
		      this.fragId = fragId;
		      this.vertId = vertId;
		      this.program = null;
		      this.uniforms = [];
		      this.attributes = [];
	
		      if (config.profile) {
		        this.stats = {
		          uniformsCount: 0,
		          attributesCount: 0
		        };
		      }
		    }
	
		    function linkProgram(desc, command) {
		      var i, info;
	
		      // -------------------------------
		      // compile & link
		      // -------------------------------
		      var fragShader = getShader(GL_FRAGMENT_SHADER, desc.fragId);
		      var vertShader = getShader(GL_VERTEX_SHADER, desc.vertId);
	
		      var program = desc.program = gl.createProgram();
		      gl.attachShader(program, fragShader);
		      gl.attachShader(program, vertShader);
		      gl.linkProgram(program);
		      check$1.linkError(gl, program, stringStore.str(desc.fragId), stringStore.str(desc.vertId), command);
	
		      // -------------------------------
		      // grab uniforms
		      // -------------------------------
		      var numUniforms = gl.getProgramParameter(program, GL_ACTIVE_UNIFORMS);
		      if (config.profile) {
		        desc.stats.uniformsCount = numUniforms;
		      }
		      var uniforms = desc.uniforms;
		      for (i = 0; i < numUniforms; ++i) {
		        info = gl.getActiveUniform(program, i);
		        if (info) {
		          if (info.size > 1) {
		            for (var j = 0; j < info.size; ++j) {
		              var name = info.name.replace('[0]', '[' + j + ']');
		              insertActiveInfo(uniforms, new ActiveInfo(name, stringStore.id(name), gl.getUniformLocation(program, name), info));
		            }
		          } else {
		            insertActiveInfo(uniforms, new ActiveInfo(info.name, stringStore.id(info.name), gl.getUniformLocation(program, info.name), info));
		          }
		        }
		      }
	
		      // -------------------------------
		      // grab attributes
		      // -------------------------------
		      var numAttributes = gl.getProgramParameter(program, GL_ACTIVE_ATTRIBUTES);
		      if (config.profile) {
		        desc.stats.attributesCount = numAttributes;
		      }
	
		      var attributes = desc.attributes;
		      for (i = 0; i < numAttributes; ++i) {
		        info = gl.getActiveAttrib(program, i);
		        if (info) {
		          insertActiveInfo(attributes, new ActiveInfo(info.name, stringStore.id(info.name), gl.getAttribLocation(program, info.name), info));
		        }
		      }
		    }
	
		    if (config.profile) {
		      stats.getMaxUniformsCount = function () {
		        var m = 0;
		        programList.forEach(function (desc) {
		          if (desc.stats.uniformsCount > m) {
		            m = desc.stats.uniformsCount;
		          }
		        });
		        return m;
		      };
	
		      stats.getMaxAttributesCount = function () {
		        var m = 0;
		        programList.forEach(function (desc) {
		          if (desc.stats.attributesCount > m) {
		            m = desc.stats.attributesCount;
		          }
		        });
		        return m;
		      };
		    }
	
		    function restoreShaders() {
		      fragShaders = {};
		      vertShaders = {};
		      for (var i = 0; i < programList.length; ++i) {
		        linkProgram(programList[i]);
		      }
		    }
	
		    return {
		      clear: function () {
		        var deleteShader = gl.deleteShader.bind(gl);
		        values(fragShaders).forEach(deleteShader);
		        fragShaders = {};
		        values(vertShaders).forEach(deleteShader);
		        vertShaders = {};
	
		        programList.forEach(function (desc) {
		          gl.deleteProgram(desc.program);
		        });
		        programList.length = 0;
		        programCache = {};
	
		        stats.shaderCount = 0;
		      },
	
		      program: function (vertId, fragId, command) {
		        check$1.command(vertId >= 0, 'missing vertex shader', command);
		        check$1.command(fragId >= 0, 'missing fragment shader', command);
	
		        var cache = programCache[fragId];
		        if (!cache) {
		          cache = programCache[fragId] = {};
		        }
		        var program = cache[vertId];
		        if (!program) {
		          program = new REGLProgram(fragId, vertId);
		          stats.shaderCount++;
	
		          linkProgram(program, command);
		          cache[vertId] = program;
		          programList.push(program);
		        }
		        return program;
		      },
	
		      restore: restoreShaders,
	
		      shader: getShader,
	
		      frag: -1,
		      vert: -1
		    };
		  }
	
		  var GL_RGBA$2 = 6408;
		  var GL_UNSIGNED_BYTE$6 = 5121;
		  var GL_PACK_ALIGNMENT = 0x0D05;
		  var GL_FLOAT$6 = 0x1406; // 5126
	
		  function wrapReadPixels(gl, framebufferState, reglPoll, context, glAttributes, extensions) {
		    function readPixelsImpl(input) {
		      var type;
		      if (framebufferState.next === null) {
		        check$1(glAttributes.preserveDrawingBuffer, 'you must create a webgl context with "preserveDrawingBuffer":true in order to read pixels from the drawing buffer');
		        type = GL_UNSIGNED_BYTE$6;
		      } else {
		        check$1(framebufferState.next.colorAttachments[0].texture !== null, 'You cannot read from a renderbuffer');
		        type = framebufferState.next.colorAttachments[0].texture._texture.type;
	
		        if (extensions.oes_texture_float) {
		          check$1(type === GL_UNSIGNED_BYTE$6 || type === GL_FLOAT$6, 'Reading from a framebuffer is only allowed for the types \'uint8\' and \'float\'');
		        } else {
		          check$1(type === GL_UNSIGNED_BYTE$6, 'Reading from a framebuffer is only allowed for the type \'uint8\'');
		        }
		      }
	
		      var x = 0;
		      var y = 0;
		      var width = context.framebufferWidth;
		      var height = context.framebufferHeight;
		      var data = null;
	
		      if (isTypedArray(input)) {
		        data = input;
		      } else if (input) {
		        check$1.type(input, 'object', 'invalid arguments to regl.read()');
		        x = input.x | 0;
		        y = input.y | 0;
		        check$1(x >= 0 && x < context.framebufferWidth, 'invalid x offset for regl.read');
		        check$1(y >= 0 && y < context.framebufferHeight, 'invalid y offset for regl.read');
		        width = (input.width || context.framebufferWidth - x) | 0;
		        height = (input.height || context.framebufferHeight - y) | 0;
		        data = input.data || null;
		      }
	
		      // sanity check input.data
		      if (data) {
		        if (type === GL_UNSIGNED_BYTE$6) {
		          check$1(data instanceof Uint8Array, 'buffer must be \'Uint8Array\' when reading from a framebuffer of type \'uint8\'');
		        } else if (type === GL_FLOAT$6) {
		          check$1(data instanceof Float32Array, 'buffer must be \'Float32Array\' when reading from a framebuffer of type \'float\'');
		        }
		      }
	
		      check$1(width > 0 && width + x <= context.framebufferWidth, 'invalid width for read pixels');
		      check$1(height > 0 && height + y <= context.framebufferHeight, 'invalid height for read pixels');
	
		      // Update WebGL state
		      reglPoll();
	
		      // Compute size
		      var size = width * height * 4;
	
		      // Allocate data
		      if (!data) {
		        if (type === GL_UNSIGNED_BYTE$6) {
		          data = new Uint8Array(size);
		        } else if (type === GL_FLOAT$6) {
		          data = data || new Float32Array(size);
		        }
		      }
	
		      // Type check
		      check$1.isTypedArray(data, 'data buffer for regl.read() must be a typedarray');
		      check$1(data.byteLength >= size, 'data buffer for regl.read() too small');
	
		      // Run read pixels
		      gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
		      gl.readPixels(x, y, width, height, GL_RGBA$2, type, data);
	
		      return data;
		    }
	
		    function readPixelsFBO(options) {
		      var result;
		      framebufferState.setFBO({
		        framebuffer: options.framebuffer
		      }, function () {
		        result = readPixelsImpl(options);
		      });
		      return result;
		    }
	
		    function readPixels(options) {
		      if (!options || !('framebuffer' in options)) {
		        return readPixelsImpl(options);
		      } else {
		        return readPixelsFBO(options);
		      }
		    }
	
		    return readPixels;
		  }
	
		  function slice(x) {
		    return Array.prototype.slice.call(x);
		  }
	
		  function join(x) {
		    return slice(x).join('');
		  }
	
		  function createEnvironment() {
		    // Unique variable id counter
		    var varCounter = 0;
	
		    // Linked values are passed from this scope into the generated code block
		    // Calling link() passes a value into the generated scope and returns
		    // the variable name which it is bound to
		    var linkedNames = [];
		    var linkedValues = [];
		    function link(value) {
		      for (var i = 0; i < linkedValues.length; ++i) {
		        if (linkedValues[i] === value) {
		          return linkedNames[i];
		        }
		      }
	
		      var name = 'g' + varCounter++;
		      linkedNames.push(name);
		      linkedValues.push(value);
		      return name;
		    }
	
		    // create a code block
		    function block() {
		      var code = [];
		      function push() {
		        code.push.apply(code, slice(arguments));
		      }
	
		      var vars = [];
		      function def() {
		        var name = 'v' + varCounter++;
		        vars.push(name);
	
		        if (arguments.length > 0) {
		          code.push(name, '=');
		          code.push.apply(code, slice(arguments));
		          code.push(';');
		        }
	
		        return name;
		      }
	
		      return extend(push, {
		        def: def,
		        toString: function () {
		          return join([vars.length > 0 ? 'var ' + vars + ';' : '', join(code)]);
		        }
		      });
		    }
	
		    function scope() {
		      var entry = block();
		      var exit = block();
	
		      var entryToString = entry.toString;
		      var exitToString = exit.toString;
	
		      function save(object, prop) {
		        exit(object, prop, '=', entry.def(object, prop), ';');
		      }
	
		      return extend(function () {
		        entry.apply(entry, slice(arguments));
		      }, {
		        def: entry.def,
		        entry: entry,
		        exit: exit,
		        save: save,
		        set: function (object, prop, value) {
		          save(object, prop);
		          entry(object, prop, '=', value, ';');
		        },
		        toString: function () {
		          return entryToString() + exitToString();
		        }
		      });
		    }
	
		    function conditional() {
		      var pred = join(arguments);
		      var thenBlock = scope();
		      var elseBlock = scope();
	
		      var thenToString = thenBlock.toString;
		      var elseToString = elseBlock.toString;
	
		      return extend(thenBlock, {
		        then: function () {
		          thenBlock.apply(thenBlock, slice(arguments));
		          return this;
		        },
		        else: function () {
		          elseBlock.apply(elseBlock, slice(arguments));
		          return this;
		        },
		        toString: function () {
		          var elseClause = elseToString();
		          if (elseClause) {
		            elseClause = 'else{' + elseClause + '}';
		          }
		          return join(['if(', pred, '){', thenToString(), '}', elseClause]);
		        }
		      });
		    }
	
		    // procedure list
		    var globalBlock = block();
		    var procedures = {};
		    function proc(name, count) {
		      var args = [];
		      function arg() {
		        var name = 'a' + args.length;
		        args.push(name);
		        return name;
		      }
	
		      count = count || 0;
		      for (var i = 0; i < count; ++i) {
		        arg();
		      }
	
		      var body = scope();
		      var bodyToString = body.toString;
	
		      var result = procedures[name] = extend(body, {
		        arg: arg,
		        toString: function () {
		          return join(['function(', args.join(), '){', bodyToString(), '}']);
		        }
		      });
	
		      return result;
		    }
	
		    function compile() {
		      var code = ['"use strict";', globalBlock, 'return {'];
		      Object.keys(procedures).forEach(function (name) {
		        code.push('"', name, '":', procedures[name].toString(), ',');
		      });
		      code.push('}');
		      var src = join(code).replace(/;/g, ';\n').replace(/}/g, '}\n').replace(/{/g, '{\n');
		      var proc = Function.apply(null, linkedNames.concat(src));
		      return proc.apply(null, linkedValues);
		    }
	
		    return {
		      global: globalBlock,
		      link: link,
		      block: block,
		      proc: proc,
		      scope: scope,
		      cond: conditional,
		      compile: compile
		    };
		  }
	
		  // "cute" names for vector components
		  var CUTE_COMPONENTS = 'xyzw'.split('');
	
		  var GL_UNSIGNED_BYTE$7 = 5121;
	
		  var ATTRIB_STATE_POINTER = 1;
		  var ATTRIB_STATE_CONSTANT = 2;
	
		  var DYN_FUNC$1 = 0;
		  var DYN_PROP$1 = 1;
		  var DYN_CONTEXT$1 = 2;
		  var DYN_STATE$1 = 3;
		  var DYN_THUNK = 4;
	
		  var S_DITHER = 'dither';
		  var S_BLEND_ENABLE = 'blend.enable';
		  var S_BLEND_COLOR = 'blend.color';
		  var S_BLEND_EQUATION = 'blend.equation';
		  var S_BLEND_FUNC = 'blend.func';
		  var S_DEPTH_ENABLE = 'depth.enable';
		  var S_DEPTH_FUNC = 'depth.func';
		  var S_DEPTH_RANGE = 'depth.range';
		  var S_DEPTH_MASK = 'depth.mask';
		  var S_COLOR_MASK = 'colorMask';
		  var S_CULL_ENABLE = 'cull.enable';
		  var S_CULL_FACE = 'cull.face';
		  var S_FRONT_FACE = 'frontFace';
		  var S_LINE_WIDTH = 'lineWidth';
		  var S_POLYGON_OFFSET_ENABLE = 'polygonOffset.enable';
		  var S_POLYGON_OFFSET_OFFSET = 'polygonOffset.offset';
		  var S_SAMPLE_ALPHA = 'sample.alpha';
		  var S_SAMPLE_ENABLE = 'sample.enable';
		  var S_SAMPLE_COVERAGE = 'sample.coverage';
		  var S_STENCIL_ENABLE = 'stencil.enable';
		  var S_STENCIL_MASK = 'stencil.mask';
		  var S_STENCIL_FUNC = 'stencil.func';
		  var S_STENCIL_OPFRONT = 'stencil.opFront';
		  var S_STENCIL_OPBACK = 'stencil.opBack';
		  var S_SCISSOR_ENABLE = 'scissor.enable';
		  var S_SCISSOR_BOX = 'scissor.box';
		  var S_VIEWPORT = 'viewport';
	
		  var S_PROFILE = 'profile';
	
		  var S_FRAMEBUFFER = 'framebuffer';
		  var S_VERT = 'vert';
		  var S_FRAG = 'frag';
		  var S_ELEMENTS = 'elements';
		  var S_PRIMITIVE = 'primitive';
		  var S_COUNT = 'count';
		  var S_OFFSET = 'offset';
		  var S_INSTANCES = 'instances';
	
		  var SUFFIX_WIDTH = 'Width';
		  var SUFFIX_HEIGHT = 'Height';
	
		  var S_FRAMEBUFFER_WIDTH = S_FRAMEBUFFER + SUFFIX_WIDTH;
		  var S_FRAMEBUFFER_HEIGHT = S_FRAMEBUFFER + SUFFIX_HEIGHT;
		  var S_VIEWPORT_WIDTH = S_VIEWPORT + SUFFIX_WIDTH;
		  var S_VIEWPORT_HEIGHT = S_VIEWPORT + SUFFIX_HEIGHT;
		  var S_DRAWINGBUFFER = 'drawingBuffer';
		  var S_DRAWINGBUFFER_WIDTH = S_DRAWINGBUFFER + SUFFIX_WIDTH;
		  var S_DRAWINGBUFFER_HEIGHT = S_DRAWINGBUFFER + SUFFIX_HEIGHT;
	
		  var NESTED_OPTIONS = [S_BLEND_FUNC, S_BLEND_EQUATION, S_STENCIL_FUNC, S_STENCIL_OPFRONT, S_STENCIL_OPBACK, S_SAMPLE_COVERAGE, S_VIEWPORT, S_SCISSOR_BOX, S_POLYGON_OFFSET_OFFSET];
	
		  var GL_ARRAY_BUFFER$1 = 34962;
		  var GL_ELEMENT_ARRAY_BUFFER$1 = 34963;
	
		  var GL_FRAGMENT_SHADER$1 = 35632;
		  var GL_VERTEX_SHADER$1 = 35633;
	
		  var GL_TEXTURE_2D$2 = 0x0DE1;
		  var GL_TEXTURE_CUBE_MAP$1 = 0x8513;
	
		  var GL_CULL_FACE = 0x0B44;
		  var GL_BLEND = 0x0BE2;
		  var GL_DITHER = 0x0BD0;
		  var GL_STENCIL_TEST = 0x0B90;
		  var GL_DEPTH_TEST = 0x0B71;
		  var GL_SCISSOR_TEST = 0x0C11;
		  var GL_POLYGON_OFFSET_FILL = 0x8037;
		  var GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E;
		  var GL_SAMPLE_COVERAGE = 0x80A0;
	
		  var GL_FLOAT$7 = 5126;
		  var GL_FLOAT_VEC2 = 35664;
		  var GL_FLOAT_VEC3 = 35665;
		  var GL_FLOAT_VEC4 = 35666;
		  var GL_INT$3 = 5124;
		  var GL_INT_VEC2 = 35667;
		  var GL_INT_VEC3 = 35668;
		  var GL_INT_VEC4 = 35669;
		  var GL_BOOL = 35670;
		  var GL_BOOL_VEC2 = 35671;
		  var GL_BOOL_VEC3 = 35672;
		  var GL_BOOL_VEC4 = 35673;
		  var GL_FLOAT_MAT2 = 35674;
		  var GL_FLOAT_MAT3 = 35675;
		  var GL_FLOAT_MAT4 = 35676;
		  var GL_SAMPLER_2D = 35678;
		  var GL_SAMPLER_CUBE = 35680;
	
		  var GL_TRIANGLES$1 = 4;
	
		  var GL_FRONT = 1028;
		  var GL_BACK = 1029;
		  var GL_CW = 0x0900;
		  var GL_CCW = 0x0901;
		  var GL_MIN_EXT = 0x8007;
		  var GL_MAX_EXT = 0x8008;
		  var GL_ALWAYS = 519;
		  var GL_KEEP = 7680;
		  var GL_ZERO = 0;
		  var GL_ONE = 1;
		  var GL_FUNC_ADD = 0x8006;
		  var GL_LESS = 513;
	
		  var GL_FRAMEBUFFER$1 = 0x8D40;
		  var GL_COLOR_ATTACHMENT0$1 = 0x8CE0;
	
		  var blendFuncs = {
		    '0': 0,
		    '1': 1,
		    'zero': 0,
		    'one': 1,
		    'src color': 768,
		    'one minus src color': 769,
		    'src alpha': 770,
		    'one minus src alpha': 771,
		    'dst color': 774,
		    'one minus dst color': 775,
		    'dst alpha': 772,
		    'one minus dst alpha': 773,
		    'constant color': 32769,
		    'one minus constant color': 32770,
		    'constant alpha': 32771,
		    'one minus constant alpha': 32772,
		    'src alpha saturate': 776
		  };
	
		  // There are invalid values for srcRGB and dstRGB. See:
		  // https://www.khronos.org/registry/webgl/specs/1.0/#6.13
		  // https://github.com/KhronosGroup/WebGL/blob/0d3201f5f7ec3c0060bc1f04077461541f1987b9/conformance-suites/1.0.3/conformance/misc/webgl-specific.html#L56
		  var invalidBlendCombinations = ['constant color, constant alpha', 'one minus constant color, constant alpha', 'constant color, one minus constant alpha', 'one minus constant color, one minus constant alpha', 'constant alpha, constant color', 'constant alpha, one minus constant color', 'one minus constant alpha, constant color', 'one minus constant alpha, one minus constant color'];
	
		  var compareFuncs = {
		    'never': 512,
		    'less': 513,
		    '<': 513,
		    'equal': 514,
		    '=': 514,
		    '==': 514,
		    '===': 514,
		    'lequal': 515,
		    '<=': 515,
		    'greater': 516,
		    '>': 516,
		    'notequal': 517,
		    '!=': 517,
		    '!==': 517,
		    'gequal': 518,
		    '>=': 518,
		    'always': 519
		  };
	
		  var stencilOps = {
		    '0': 0,
		    'zero': 0,
		    'keep': 7680,
		    'replace': 7681,
		    'increment': 7682,
		    'decrement': 7683,
		    'increment wrap': 34055,
		    'decrement wrap': 34056,
		    'invert': 5386
		  };
	
		  var shaderType = {
		    'frag': GL_FRAGMENT_SHADER$1,
		    'vert': GL_VERTEX_SHADER$1
		  };
	
		  var orientationType = {
		    'cw': GL_CW,
		    'ccw': GL_CCW
		  };
	
		  function isBufferArgs(x) {
		    return Array.isArray(x) || isTypedArray(x) || isNDArrayLike(x);
		  }
	
		  // Make sure viewport is processed first
		  function sortState(state) {
		    return state.sort(function (a, b) {
		      if (a === S_VIEWPORT) {
		        return -1;
		      } else if (b === S_VIEWPORT) {
		        return 1;
		      }
		      return a < b ? -1 : 1;
		    });
		  }
	
		  function Declaration(thisDep, contextDep, propDep, append) {
		    this.thisDep = thisDep;
		    this.contextDep = contextDep;
		    this.propDep = propDep;
		    this.append = append;
		  }
	
		  function isStatic(decl) {
		    return decl && !(decl.thisDep || decl.contextDep || decl.propDep);
		  }
	
		  function createStaticDecl(append) {
		    return new Declaration(false, false, false, append);
		  }
	
		  function createDynamicDecl(dyn, append) {
		    var type = dyn.type;
		    if (type === DYN_FUNC$1) {
		      var numArgs = dyn.data.length;
		      return new Declaration(true, numArgs >= 1, numArgs >= 2, append);
		    } else if (type === DYN_THUNK) {
		      var data = dyn.data;
		      return new Declaration(data.thisDep, data.contextDep, data.propDep, append);
		    } else {
		      return new Declaration(type === DYN_STATE$1, type === DYN_CONTEXT$1, type === DYN_PROP$1, append);
		    }
		  }
	
		  var SCOPE_DECL = new Declaration(false, false, false, function () {});
	
		  function reglCore(gl, stringStore, extensions, limits, bufferState, elementState, textureState, framebufferState, uniformState, attributeState, shaderState, drawState, contextState, timer, config) {
		    var AttributeRecord = attributeState.Record;
	
		    var blendEquations = {
		      'add': 32774,
		      'subtract': 32778,
		      'reverse subtract': 32779
		    };
		    if (extensions.ext_blend_minmax) {
		      blendEquations.min = GL_MIN_EXT;
		      blendEquations.max = GL_MAX_EXT;
		    }
	
		    var extInstancing = extensions.angle_instanced_arrays;
		    var extDrawBuffers = extensions.webgl_draw_buffers;
	
		    // ===================================================
		    // ===================================================
		    // WEBGL STATE
		    // ===================================================
		    // ===================================================
		    var currentState = {
		      dirty: true,
		      profile: config.profile
		    };
		    var nextState = {};
		    var GL_STATE_NAMES = [];
		    var GL_FLAGS = {};
		    var GL_VARIABLES = {};
	
		    function propName(name) {
		      return name.replace('.', '_');
		    }
	
		    function stateFlag(sname, cap, init) {
		      var name = propName(sname);
		      GL_STATE_NAMES.push(sname);
		      nextState[name] = currentState[name] = !!init;
		      GL_FLAGS[name] = cap;
		    }
	
		    function stateVariable(sname, func, init) {
		      var name = propName(sname);
		      GL_STATE_NAMES.push(sname);
		      if (Array.isArray(init)) {
		        currentState[name] = init.slice();
		        nextState[name] = init.slice();
		      } else {
		        currentState[name] = nextState[name] = init;
		      }
		      GL_VARIABLES[name] = func;
		    }
	
		    // Dithering
		    stateFlag(S_DITHER, GL_DITHER);
	
		    // Blending
		    stateFlag(S_BLEND_ENABLE, GL_BLEND);
		    stateVariable(S_BLEND_COLOR, 'blendColor', [0, 0, 0, 0]);
		    stateVariable(S_BLEND_EQUATION, 'blendEquationSeparate', [GL_FUNC_ADD, GL_FUNC_ADD]);
		    stateVariable(S_BLEND_FUNC, 'blendFuncSeparate', [GL_ONE, GL_ZERO, GL_ONE, GL_ZERO]);
	
		    // Depth
		    stateFlag(S_DEPTH_ENABLE, GL_DEPTH_TEST, true);
		    stateVariable(S_DEPTH_FUNC, 'depthFunc', GL_LESS);
		    stateVariable(S_DEPTH_RANGE, 'depthRange', [0, 1]);
		    stateVariable(S_DEPTH_MASK, 'depthMask', true);
	
		    // Color mask
		    stateVariable(S_COLOR_MASK, S_COLOR_MASK, [true, true, true, true]);
	
		    // Face culling
		    stateFlag(S_CULL_ENABLE, GL_CULL_FACE);
		    stateVariable(S_CULL_FACE, 'cullFace', GL_BACK);
	
		    // Front face orientation
		    stateVariable(S_FRONT_FACE, S_FRONT_FACE, GL_CCW);
	
		    // Line width
		    stateVariable(S_LINE_WIDTH, S_LINE_WIDTH, 1);
	
		    // Polygon offset
		    stateFlag(S_POLYGON_OFFSET_ENABLE, GL_POLYGON_OFFSET_FILL);
		    stateVariable(S_POLYGON_OFFSET_OFFSET, 'polygonOffset', [0, 0]);
	
		    // Sample coverage
		    stateFlag(S_SAMPLE_ALPHA, GL_SAMPLE_ALPHA_TO_COVERAGE);
		    stateFlag(S_SAMPLE_ENABLE, GL_SAMPLE_COVERAGE);
		    stateVariable(S_SAMPLE_COVERAGE, 'sampleCoverage', [1, false]);
	
		    // Stencil
		    stateFlag(S_STENCIL_ENABLE, GL_STENCIL_TEST);
		    stateVariable(S_STENCIL_MASK, 'stencilMask', -1);
		    stateVariable(S_STENCIL_FUNC, 'stencilFunc', [GL_ALWAYS, 0, -1]);
		    stateVariable(S_STENCIL_OPFRONT, 'stencilOpSeparate', [GL_FRONT, GL_KEEP, GL_KEEP, GL_KEEP]);
		    stateVariable(S_STENCIL_OPBACK, 'stencilOpSeparate', [GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP]);
	
		    // Scissor
		    stateFlag(S_SCISSOR_ENABLE, GL_SCISSOR_TEST);
		    stateVariable(S_SCISSOR_BOX, 'scissor', [0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight]);
	
		    // Viewport
		    stateVariable(S_VIEWPORT, S_VIEWPORT, [0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight]);
	
		    // ===================================================
		    // ===================================================
		    // ENVIRONMENT
		    // ===================================================
		    // ===================================================
		    var sharedState = {
		      gl: gl,
		      context: contextState,
		      strings: stringStore,
		      next: nextState,
		      current: currentState,
		      draw: drawState,
		      elements: elementState,
		      buffer: bufferState,
		      shader: shaderState,
		      attributes: attributeState.state,
		      uniforms: uniformState,
		      framebuffer: framebufferState,
		      extensions: extensions,
	
		      timer: timer,
		      isBufferArgs: isBufferArgs
		    };
	
		    var sharedConstants = {
		      primTypes: primTypes,
		      compareFuncs: compareFuncs,
		      blendFuncs: blendFuncs,
		      blendEquations: blendEquations,
		      stencilOps: stencilOps,
		      glTypes: glTypes,
		      orientationType: orientationType
		    };
	
		    check$1.optional(function () {
		      sharedState.isArrayLike = isArrayLike;
		    });
	
		    if (extDrawBuffers) {
		      sharedConstants.backBuffer = [GL_BACK];
		      sharedConstants.drawBuffer = loop(limits.maxDrawbuffers, function (i) {
		        if (i === 0) {
		          return [0];
		        }
		        return loop(i, function (j) {
		          return GL_COLOR_ATTACHMENT0$1 + j;
		        });
		      });
		    }
	
		    var drawCallCounter = 0;
		    function createREGLEnvironment() {
		      var env = createEnvironment();
		      var link = env.link;
		      var global = env.global;
		      env.id = drawCallCounter++;
	
		      env.batchId = '0';
	
		      // link shared state
		      var SHARED = link(sharedState);
		      var shared = env.shared = {
		        props: 'a0'
		      };
		      Object.keys(sharedState).forEach(function (prop) {
		        shared[prop] = global.def(SHARED, '.', prop);
		      });
	
		      // Inject runtime assertion stuff for debug builds
		      check$1.optional(function () {
		        env.CHECK = link(check$1);
		        env.commandStr = check$1.guessCommand();
		        env.command = link(env.commandStr);
		        env.assert = function (block, pred, message) {
		          block('if(!(', pred, '))', this.CHECK, '.commandRaise(', link(message), ',', this.command, ');');
		        };
	
		        sharedConstants.invalidBlendCombinations = invalidBlendCombinations;
		      });
	
		      // Copy GL state variables over
		      var nextVars = env.next = {};
		      var currentVars = env.current = {};
		      Object.keys(GL_VARIABLES).forEach(function (variable) {
		        if (Array.isArray(currentState[variable])) {
		          nextVars[variable] = global.def(shared.next, '.', variable);
		          currentVars[variable] = global.def(shared.current, '.', variable);
		        }
		      });
	
		      // Initialize shared constants
		      var constants = env.constants = {};
		      Object.keys(sharedConstants).forEach(function (name) {
		        constants[name] = global.def(JSON.stringify(sharedConstants[name]));
		      });
	
		      // Helper function for calling a block
		      env.invoke = function (block, x) {
		        switch (x.type) {
		          case DYN_FUNC$1:
		            var argList = ['this', shared.context, shared.props, env.batchId];
		            return block.def(link(x.data), '.call(', argList.slice(0, Math.max(x.data.length + 1, 4)), ')');
		          case DYN_PROP$1:
		            return block.def(shared.props, x.data);
		          case DYN_CONTEXT$1:
		            return block.def(shared.context, x.data);
		          case DYN_STATE$1:
		            return block.def('this', x.data);
		          case DYN_THUNK:
		            x.data.append(env, block);
		            return x.data.ref;
		        }
		      };
	
		      env.attribCache = {};
	
		      var scopeAttribs = {};
		      env.scopeAttrib = function (name) {
		        var id = stringStore.id(name);
		        if (id in scopeAttribs) {
		          return scopeAttribs[id];
		        }
		        var binding = attributeState.scope[id];
		        if (!binding) {
		          binding = attributeState.scope[id] = new AttributeRecord();
		        }
		        var result = scopeAttribs[id] = link(binding);
		        return result;
		      };
	
		      return env;
		    }
	
		    // ===================================================
		    // ===================================================
		    // PARSING
		    // ===================================================
		    // ===================================================
		    function parseProfile(options) {
		      var staticOptions = options.static;
		      var dynamicOptions = options.dynamic;
	
		      var profileEnable;
		      if (S_PROFILE in staticOptions) {
		        var value = !!staticOptions[S_PROFILE];
		        profileEnable = createStaticDecl(function (env, scope) {
		          return value;
		        });
		        profileEnable.enable = value;
		      } else if (S_PROFILE in dynamicOptions) {
		        var dyn = dynamicOptions[S_PROFILE];
		        profileEnable = createDynamicDecl(dyn, function (env, scope) {
		          return env.invoke(scope, dyn);
		        });
		      }
	
		      return profileEnable;
		    }
	
		    function parseFramebuffer(options, env) {
		      var staticOptions = options.static;
		      var dynamicOptions = options.dynamic;
	
		      if (S_FRAMEBUFFER in staticOptions) {
		        var framebuffer = staticOptions[S_FRAMEBUFFER];
		        if (framebuffer) {
		          framebuffer = framebufferState.getFramebuffer(framebuffer);
		          check$1.command(framebuffer, 'invalid framebuffer object');
		          return createStaticDecl(function (env, block) {
		            var FRAMEBUFFER = env.link(framebuffer);
		            var shared = env.shared;
		            block.set(shared.framebuffer, '.next', FRAMEBUFFER);
		            var CONTEXT = shared.context;
		            block.set(CONTEXT, '.' + S_FRAMEBUFFER_WIDTH, FRAMEBUFFER + '.width');
		            block.set(CONTEXT, '.' + S_FRAMEBUFFER_HEIGHT, FRAMEBUFFER + '.height');
		            return FRAMEBUFFER;
		          });
		        } else {
		          return createStaticDecl(function (env, scope) {
		            var shared = env.shared;
		            scope.set(shared.framebuffer, '.next', 'null');
		            var CONTEXT = shared.context;
		            scope.set(CONTEXT, '.' + S_FRAMEBUFFER_WIDTH, CONTEXT + '.' + S_DRAWINGBUFFER_WIDTH);
		            scope.set(CONTEXT, '.' + S_FRAMEBUFFER_HEIGHT, CONTEXT + '.' + S_DRAWINGBUFFER_HEIGHT);
		            return 'null';
		          });
		        }
		      } else if (S_FRAMEBUFFER in dynamicOptions) {
		        var dyn = dynamicOptions[S_FRAMEBUFFER];
		        return createDynamicDecl(dyn, function (env, scope) {
		          var FRAMEBUFFER_FUNC = env.invoke(scope, dyn);
		          var shared = env.shared;
		          var FRAMEBUFFER_STATE = shared.framebuffer;
		          var FRAMEBUFFER = scope.def(FRAMEBUFFER_STATE, '.getFramebuffer(', FRAMEBUFFER_FUNC, ')');
	
		          check$1.optional(function () {
		            env.assert(scope, '!' + FRAMEBUFFER_FUNC + '||' + FRAMEBUFFER, 'invalid framebuffer object');
		          });
	
		          scope.set(FRAMEBUFFER_STATE, '.next', FRAMEBUFFER);
		          var CONTEXT = shared.context;
		          scope.set(CONTEXT, '.' + S_FRAMEBUFFER_WIDTH, FRAMEBUFFER + '?' + FRAMEBUFFER + '.width:' + CONTEXT + '.' + S_DRAWINGBUFFER_WIDTH);
		          scope.set(CONTEXT, '.' + S_FRAMEBUFFER_HEIGHT, FRAMEBUFFER + '?' + FRAMEBUFFER + '.height:' + CONTEXT + '.' + S_DRAWINGBUFFER_HEIGHT);
		          return FRAMEBUFFER;
		        });
		      } else {
		        return null;
		      }
		    }
	
		    function parseViewportScissor(options, framebuffer, env) {
		      var staticOptions = options.static;
		      var dynamicOptions = options.dynamic;
	
		      function parseBox(param) {
		        if (param in staticOptions) {
		          var box = staticOptions[param];
		          check$1.commandType(box, 'object', 'invalid ' + param, env.commandStr);
	
		          var isStatic = true;
		          var x = box.x | 0;
		          var y = box.y | 0;
		          var w, h;
		          if ('width' in box) {
		            w = box.width | 0;
		            check$1.command(w >= 0, 'invalid ' + param, env.commandStr);
		          } else {
		            isStatic = false;
		          }
		          if ('height' in box) {
		            h = box.height | 0;
		            check$1.command(h >= 0, 'invalid ' + param, env.commandStr);
		          } else {
		            isStatic = false;
		          }
	
		          return new Declaration(!isStatic && framebuffer && framebuffer.thisDep, !isStatic && framebuffer && framebuffer.contextDep, !isStatic && framebuffer && framebuffer.propDep, function (env, scope) {
		            var CONTEXT = env.shared.context;
		            var BOX_W = w;
		            if (!('width' in box)) {
		              BOX_W = scope.def(CONTEXT, '.', S_FRAMEBUFFER_WIDTH, '-', x);
		            }
		            var BOX_H = h;
		            if (!('height' in box)) {
		              BOX_H = scope.def(CONTEXT, '.', S_FRAMEBUFFER_HEIGHT, '-', y);
		            }
		            return [x, y, BOX_W, BOX_H];
		          });
		        } else if (param in dynamicOptions) {
		          var dynBox = dynamicOptions[param];
		          var result = createDynamicDecl(dynBox, function (env, scope) {
		            var BOX = env.invoke(scope, dynBox);
	
		            check$1.optional(function () {
		              env.assert(scope, BOX + '&&typeof ' + BOX + '==="object"', 'invalid ' + param);
		            });
	
		            var CONTEXT = env.shared.context;
		            var BOX_X = scope.def(BOX, '.x|0');
		            var BOX_Y = scope.def(BOX, '.y|0');
		            var BOX_W = scope.def('"width" in ', BOX, '?', BOX, '.width|0:', '(', CONTEXT, '.', S_FRAMEBUFFER_WIDTH, '-', BOX_X, ')');
		            var BOX_H = scope.def('"height" in ', BOX, '?', BOX, '.height|0:', '(', CONTEXT, '.', S_FRAMEBUFFER_HEIGHT, '-', BOX_Y, ')');
	
		            check$1.optional(function () {
		              env.assert(scope, BOX_W + '>=0&&' + BOX_H + '>=0', 'invalid ' + param);
		            });
	
		            return [BOX_X, BOX_Y, BOX_W, BOX_H];
		          });
		          if (framebuffer) {
		            result.thisDep = result.thisDep || framebuffer.thisDep;
		            result.contextDep = result.contextDep || framebuffer.contextDep;
		            result.propDep = result.propDep || framebuffer.propDep;
		          }
		          return result;
		        } else if (framebuffer) {
		          return new Declaration(framebuffer.thisDep, framebuffer.contextDep, framebuffer.propDep, function (env, scope) {
		            var CONTEXT = env.shared.context;
		            return [0, 0, scope.def(CONTEXT, '.', S_FRAMEBUFFER_WIDTH), scope.def(CONTEXT, '.', S_FRAMEBUFFER_HEIGHT)];
		          });
		        } else {
		          return null;
		        }
		      }
	
		      var viewport = parseBox(S_VIEWPORT);
	
		      if (viewport) {
		        var prevViewport = viewport;
		        viewport = new Declaration(viewport.thisDep, viewport.contextDep, viewport.propDep, function (env, scope) {
		          var VIEWPORT = prevViewport.append(env, scope);
		          var CONTEXT = env.shared.context;
		          scope.set(CONTEXT, '.' + S_VIEWPORT_WIDTH, VIEWPORT[2]);
		          scope.set(CONTEXT, '.' + S_VIEWPORT_HEIGHT, VIEWPORT[3]);
		          return VIEWPORT;
		        });
		      }
	
		      return {
		        viewport: viewport,
		        scissor_box: parseBox(S_SCISSOR_BOX)
		      };
		    }
	
		    function parseProgram(options) {
		      var staticOptions = options.static;
		      var dynamicOptions = options.dynamic;
	
		      function parseShader(name) {
		        if (name in staticOptions) {
		          var id = stringStore.id(staticOptions[name]);
		          check$1.optional(function () {
		            shaderState.shader(shaderType[name], id, check$1.guessCommand());
		          });
		          var result = createStaticDecl(function () {
		            return id;
		          });
		          result.id = id;
		          return result;
		        } else if (name in dynamicOptions) {
		          var dyn = dynamicOptions[name];
		          return createDynamicDecl(dyn, function (env, scope) {
		            var str = env.invoke(scope, dyn);
		            var id = scope.def(env.shared.strings, '.id(', str, ')');
		            check$1.optional(function () {
		              scope(env.shared.shader, '.shader(', shaderType[name], ',', id, ',', env.command, ');');
		            });
		            return id;
		          });
		        }
		        return null;
		      }
	
		      var frag = parseShader(S_FRAG);
		      var vert = parseShader(S_VERT);
	
		      var program = null;
		      var progVar;
		      if (isStatic(frag) && isStatic(vert)) {
		        program = shaderState.program(vert.id, frag.id);
		        progVar = createStaticDecl(function (env, scope) {
		          return env.link(program);
		        });
		      } else {
		        progVar = new Declaration(frag && frag.thisDep || vert && vert.thisDep, frag && frag.contextDep || vert && vert.contextDep, frag && frag.propDep || vert && vert.propDep, function (env, scope) {
		          var SHADER_STATE = env.shared.shader;
		          var fragId;
		          if (frag) {
		            fragId = frag.append(env, scope);
		          } else {
		            fragId = scope.def(SHADER_STATE, '.', S_FRAG);
		          }
		          var vertId;
		          if (vert) {
		            vertId = vert.append(env, scope);
		          } else {
		            vertId = scope.def(SHADER_STATE, '.', S_VERT);
		          }
		          var progDef = SHADER_STATE + '.program(' + vertId + ',' + fragId;
		          check$1.optional(function () {
		            progDef += ',' + env.command;
		          });
		          return scope.def(progDef + ')');
		        });
		      }
	
		      return {
		        frag: frag,
		        vert: vert,
		        progVar: progVar,
		        program: program
		      };
		    }
	
		    function parseDraw(options, env) {
		      var staticOptions = options.static;
		      var dynamicOptions = options.dynamic;
	
		      function parseElements() {
		        if (S_ELEMENTS in staticOptions) {
		          var elements = staticOptions[S_ELEMENTS];
		          if (isBufferArgs(elements)) {
		            elements = elementState.getElements(elementState.create(elements, true));
		          } else if (elements) {
		            elements = elementState.getElements(elements);
		            check$1.command(elements, 'invalid elements', env.commandStr);
		          }
		          var result = createStaticDecl(function (env, scope) {
		            if (elements) {
		              var result = env.link(elements);
		              env.ELEMENTS = result;
		              return result;
		            }
		            env.ELEMENTS = null;
		            return null;
		          });
		          result.value = elements;
		          return result;
		        } else if (S_ELEMENTS in dynamicOptions) {
		          var dyn = dynamicOptions[S_ELEMENTS];
		          return createDynamicDecl(dyn, function (env, scope) {
		            var shared = env.shared;
	
		            var IS_BUFFER_ARGS = shared.isBufferArgs;
		            var ELEMENT_STATE = shared.elements;
	
		            var elementDefn = env.invoke(scope, dyn);
		            var elements = scope.def('null');
		            var elementStream = scope.def(IS_BUFFER_ARGS, '(', elementDefn, ')');
	
		            var ifte = env.cond(elementStream).then(elements, '=', ELEMENT_STATE, '.createStream(', elementDefn, ');').else(elements, '=', ELEMENT_STATE, '.getElements(', elementDefn, ');');
	
		            check$1.optional(function () {
		              env.assert(ifte.else, '!' + elementDefn + '||' + elements, 'invalid elements');
		            });
	
		            scope.entry(ifte);
		            scope.exit(env.cond(elementStream).then(ELEMENT_STATE, '.destroyStream(', elements, ');'));
	
		            env.ELEMENTS = elements;
	
		            return elements;
		          });
		        }
	
		        return null;
		      }
	
		      var elements = parseElements();
	
		      function parsePrimitive() {
		        if (S_PRIMITIVE in staticOptions) {
		          var primitive = staticOptions[S_PRIMITIVE];
		          check$1.commandParameter(primitive, primTypes, 'invalid primitve', env.commandStr);
		          return createStaticDecl(function (env, scope) {
		            return primTypes[primitive];
		          });
		        } else if (S_PRIMITIVE in dynamicOptions) {
		          var dynPrimitive = dynamicOptions[S_PRIMITIVE];
		          return createDynamicDecl(dynPrimitive, function (env, scope) {
		            var PRIM_TYPES = env.constants.primTypes;
		            var prim = env.invoke(scope, dynPrimitive);
		            check$1.optional(function () {
		              env.assert(scope, prim + ' in ' + PRIM_TYPES, 'invalid primitive, must be one of ' + Object.keys(primTypes));
		            });
		            return scope.def(PRIM_TYPES, '[', prim, ']');
		          });
		        } else if (elements) {
		          if (isStatic(elements)) {
		            if (elements.value) {
		              return createStaticDecl(function (env, scope) {
		                return scope.def(env.ELEMENTS, '.primType');
		              });
		            } else {
		              return createStaticDecl(function () {
		                return GL_TRIANGLES$1;
		              });
		            }
		          } else {
		            return new Declaration(elements.thisDep, elements.contextDep, elements.propDep, function (env, scope) {
		              var elements = env.ELEMENTS;
		              return scope.def(elements, '?', elements, '.primType:', GL_TRIANGLES$1);
		            });
		          }
		        }
		        return null;
		      }
	
		      function parseParam(param, isOffset) {
		        if (param in staticOptions) {
		          var value = staticOptions[param] | 0;
		          check$1.command(!isOffset || value >= 0, 'invalid ' + param, env.commandStr);
		          return createStaticDecl(function (env, scope) {
		            if (isOffset) {
		              env.OFFSET = value;
		            }
		            return value;
		          });
		        } else if (param in dynamicOptions) {
		          var dynValue = dynamicOptions[param];
		          return createDynamicDecl(dynValue, function (env, scope) {
		            var result = env.invoke(scope, dynValue);
		            if (isOffset) {
		              env.OFFSET = result;
		              check$1.optional(function () {
		                env.assert(scope, result + '>=0', 'invalid ' + param);
		              });
		            }
		            return result;
		          });
		        } else if (isOffset && elements) {
		          return createStaticDecl(function (env, scope) {
		            env.OFFSET = '0';
		            return 0;
		          });
		        }
		        return null;
		      }
	
		      var OFFSET = parseParam(S_OFFSET, true);
	
		      function parseVertCount() {
		        if (S_COUNT in staticOptions) {
		          var count = staticOptions[S_COUNT] | 0;
		          check$1.command(typeof count === 'number' && count >= 0, 'invalid vertex count', env.commandStr);
		          return createStaticDecl(function () {
		            return count;
		          });
		        } else if (S_COUNT in dynamicOptions) {
		          var dynCount = dynamicOptions[S_COUNT];
		          return createDynamicDecl(dynCount, function (env, scope) {
		            var result = env.invoke(scope, dynCount);
		            check$1.optional(function () {
		              env.assert(scope, 'typeof ' + result + '==="number"&&' + result + '>=0&&' + result + '===(' + result + '|0)', 'invalid vertex count');
		            });
		            return result;
		          });
		        } else if (elements) {
		          if (isStatic(elements)) {
		            if (elements) {
		              if (OFFSET) {
		                return new Declaration(OFFSET.thisDep, OFFSET.contextDep, OFFSET.propDep, function (env, scope) {
		                  var result = scope.def(env.ELEMENTS, '.vertCount-', env.OFFSET);
	
		                  check$1.optional(function () {
		                    env.assert(scope, result + '>=0', 'invalid vertex offset/element buffer too small');
		                  });
	
		                  return result;
		                });
		              } else {
		                return createStaticDecl(function (env, scope) {
		                  return scope.def(env.ELEMENTS, '.vertCount');
		                });
		              }
		            } else {
		              var result = createStaticDecl(function () {
		                return -1;
		              });
		              check$1.optional(function () {
		                result.MISSING = true;
		              });
		              return result;
		            }
		          } else {
		            var variable = new Declaration(elements.thisDep || OFFSET.thisDep, elements.contextDep || OFFSET.contextDep, elements.propDep || OFFSET.propDep, function (env, scope) {
		              var elements = env.ELEMENTS;
		              if (env.OFFSET) {
		                return scope.def(elements, '?', elements, '.vertCount-', env.OFFSET, ':-1');
		              }
		              return scope.def(elements, '?', elements, '.vertCount:-1');
		            });
		            check$1.optional(function () {
		              variable.DYNAMIC = true;
		            });
		            return variable;
		          }
		        }
		        return null;
		      }
	
		      return {
		        elements: elements,
		        primitive: parsePrimitive(),
		        count: parseVertCount(),
		        instances: parseParam(S_INSTANCES, false),
		        offset: OFFSET
		      };
		    }
	
		    function parseGLState(options, env) {
		      var staticOptions = options.static;
		      var dynamicOptions = options.dynamic;
	
		      var STATE = {};
	
		      GL_STATE_NAMES.forEach(function (prop) {
		        var param = propName(prop);
	
		        function parseParam(parseStatic, parseDynamic) {
		          if (prop in staticOptions) {
		            var value = parseStatic(staticOptions[prop]);
		            STATE[param] = createStaticDecl(function () {
		              return value;
		            });
		          } else if (prop in dynamicOptions) {
		            var dyn = dynamicOptions[prop];
		            STATE[param] = createDynamicDecl(dyn, function (env, scope) {
		              return parseDynamic(env, scope, env.invoke(scope, dyn));
		            });
		          }
		        }
	
		        switch (prop) {
		          case S_CULL_ENABLE:
		          case S_BLEND_ENABLE:
		          case S_DITHER:
		          case S_STENCIL_ENABLE:
		          case S_DEPTH_ENABLE:
		          case S_SCISSOR_ENABLE:
		          case S_POLYGON_OFFSET_ENABLE:
		          case S_SAMPLE_ALPHA:
		          case S_SAMPLE_ENABLE:
		          case S_DEPTH_MASK:
		            return parseParam(function (value) {
		              check$1.commandType(value, 'boolean', prop, env.commandStr);
		              return value;
		            }, function (env, scope, value) {
		              check$1.optional(function () {
		                env.assert(scope, 'typeof ' + value + '==="boolean"', 'invalid flag ' + prop, env.commandStr);
		              });
		              return value;
		            });
	
		          case S_DEPTH_FUNC:
		            return parseParam(function (value) {
		              check$1.commandParameter(value, compareFuncs, 'invalid ' + prop, env.commandStr);
		              return compareFuncs[value];
		            }, function (env, scope, value) {
		              var COMPARE_FUNCS = env.constants.compareFuncs;
		              check$1.optional(function () {
		                env.assert(scope, value + ' in ' + COMPARE_FUNCS, 'invalid ' + prop + ', must be one of ' + Object.keys(compareFuncs));
		              });
		              return scope.def(COMPARE_FUNCS, '[', value, ']');
		            });
	
		          case S_DEPTH_RANGE:
		            return parseParam(function (value) {
		              check$1.command(isArrayLike(value) && value.length === 2 && typeof value[0] === 'number' && typeof value[1] === 'number' && value[0] <= value[1], 'depth range is 2d array', env.commandStr);
		              return value;
		            }, function (env, scope, value) {
		              check$1.optional(function () {
		                env.assert(scope, env.shared.isArrayLike + '(' + value + ')&&' + value + '.length===2&&' + 'typeof ' + value + '[0]==="number"&&' + 'typeof ' + value + '[1]==="number"&&' + value + '[0]<=' + value + '[1]', 'depth range must be a 2d array');
		              });
	
		              var Z_NEAR = scope.def('+', value, '[0]');
		              var Z_FAR = scope.def('+', value, '[1]');
		              return [Z_NEAR, Z_FAR];
		            });
	
		          case S_BLEND_FUNC:
		            return parseParam(function (value) {
		              check$1.commandType(value, 'object', 'blend.func', env.commandStr);
		              var srcRGB = 'srcRGB' in value ? value.srcRGB : value.src;
		              var srcAlpha = 'srcAlpha' in value ? value.srcAlpha : value.src;
		              var dstRGB = 'dstRGB' in value ? value.dstRGB : value.dst;
		              var dstAlpha = 'dstAlpha' in value ? value.dstAlpha : value.dst;
		              check$1.commandParameter(srcRGB, blendFuncs, param + '.srcRGB', env.commandStr);
		              check$1.commandParameter(srcAlpha, blendFuncs, param + '.srcAlpha', env.commandStr);
		              check$1.commandParameter(dstRGB, blendFuncs, param + '.dstRGB', env.commandStr);
		              check$1.commandParameter(dstAlpha, blendFuncs, param + '.dstAlpha', env.commandStr);
	
		              check$1.command(invalidBlendCombinations.indexOf(srcRGB + ', ' + dstRGB) === -1, 'unallowed blending combination (srcRGB, dstRGB) = (' + srcRGB + ', ' + dstRGB + ')', env.commandStr);
	
		              return [blendFuncs[srcRGB], blendFuncs[dstRGB], blendFuncs[srcAlpha], blendFuncs[dstAlpha]];
		            }, function (env, scope, value) {
		              var BLEND_FUNCS = env.constants.blendFuncs;
	
		              check$1.optional(function () {
		                env.assert(scope, value + '&&typeof ' + value + '==="object"', 'invalid blend func, must be an object');
		              });
	
		              function read(prefix, suffix) {
		                var func = scope.def('"', prefix, suffix, '" in ', value, '?', value, '.', prefix, suffix, ':', value, '.', prefix);
	
		                check$1.optional(function () {
		                  env.assert(scope, func + ' in ' + BLEND_FUNCS, 'invalid ' + prop + '.' + prefix + suffix + ', must be one of ' + Object.keys(blendFuncs));
		                });
	
		                return func;
		              }
	
		              var srcRGB = read('src', 'RGB');
		              var dstRGB = read('dst', 'RGB');
	
		              check$1.optional(function () {
		                var INVALID_BLEND_COMBINATIONS = env.constants.invalidBlendCombinations;
	
		                env.assert(scope, INVALID_BLEND_COMBINATIONS + '.indexOf(' + srcRGB + '+", "+' + dstRGB + ') === -1 ', 'unallowed blending combination for (srcRGB, dstRGB)');
		              });
	
		              var SRC_RGB = scope.def(BLEND_FUNCS, '[', srcRGB, ']');
		              var SRC_ALPHA = scope.def(BLEND_FUNCS, '[', read('src', 'Alpha'), ']');
		              var DST_RGB = scope.def(BLEND_FUNCS, '[', dstRGB, ']');
		              var DST_ALPHA = scope.def(BLEND_FUNCS, '[', read('dst', 'Alpha'), ']');
	
		              return [SRC_RGB, DST_RGB, SRC_ALPHA, DST_ALPHA];
		            });
	
		          case S_BLEND_EQUATION:
		            return parseParam(function (value) {
		              if (typeof value === 'string') {
		                check$1.commandParameter(value, blendEquations, 'invalid ' + prop, env.commandStr);
		                return [blendEquations[value], blendEquations[value]];
		              } else if (typeof value === 'object') {
		                check$1.commandParameter(value.rgb, blendEquations, prop + '.rgb', env.commandStr);
		                check$1.commandParameter(value.alpha, blendEquations, prop + '.alpha', env.commandStr);
		                return [blendEquations[value.rgb], blendEquations[value.alpha]];
		              } else {
		                check$1.commandRaise('invalid blend.equation', env.commandStr);
		              }
		            }, function (env, scope, value) {
		              var BLEND_EQUATIONS = env.constants.blendEquations;
	
		              var RGB = scope.def();
		              var ALPHA = scope.def();
	
		              var ifte = env.cond('typeof ', value, '==="string"');
	
		              check$1.optional(function () {
		                function checkProp(block, name, value) {
		                  env.assert(block, value + ' in ' + BLEND_EQUATIONS, 'invalid ' + name + ', must be one of ' + Object.keys(blendEquations));
		                }
		                checkProp(ifte.then, prop, value);
	
		                env.assert(ifte.else, value + '&&typeof ' + value + '==="object"', 'invalid ' + prop);
		                checkProp(ifte.else, prop + '.rgb', value + '.rgb');
		                checkProp(ifte.else, prop + '.alpha', value + '.alpha');
		              });
	
		              ifte.then(RGB, '=', ALPHA, '=', BLEND_EQUATIONS, '[', value, '];');
		              ifte.else(RGB, '=', BLEND_EQUATIONS, '[', value, '.rgb];', ALPHA, '=', BLEND_EQUATIONS, '[', value, '.alpha];');
	
		              scope(ifte);
	
		              return [RGB, ALPHA];
		            });
	
		          case S_BLEND_COLOR:
		            return parseParam(function (value) {
		              check$1.command(isArrayLike(value) && value.length === 4, 'blend.color must be a 4d array', env.commandStr);
		              return loop(4, function (i) {
		                return +value[i];
		              });
		            }, function (env, scope, value) {
		              check$1.optional(function () {
		                env.assert(scope, env.shared.isArrayLike + '(' + value + ')&&' + value + '.length===4', 'blend.color must be a 4d array');
		              });
		              return loop(4, function (i) {
		                return scope.def('+', value, '[', i, ']');
		              });
		            });
	
		          case S_STENCIL_MASK:
		            return parseParam(function (value) {
		              check$1.commandType(value, 'number', param, env.commandStr);
		              return value | 0;
		            }, function (env, scope, value) {
		              check$1.optional(function () {
		                env.assert(scope, 'typeof ' + value + '==="number"', 'invalid stencil.mask');
		              });
		              return scope.def(value, '|0');
		            });
	
		          case S_STENCIL_FUNC:
		            return parseParam(function (value) {
		              check$1.commandType(value, 'object', param, env.commandStr);
		              var cmp = value.cmp || 'keep';
		              var ref = value.ref || 0;
		              var mask = 'mask' in value ? value.mask : -1;
		              check$1.commandParameter(cmp, compareFuncs, prop + '.cmp', env.commandStr);
		              check$1.commandType(ref, 'number', prop + '.ref', env.commandStr);
		              check$1.commandType(mask, 'number', prop + '.mask', env.commandStr);
		              return [compareFuncs[cmp], ref, mask];
		            }, function (env, scope, value) {
		              var COMPARE_FUNCS = env.constants.compareFuncs;
		              check$1.optional(function () {
		                function assert() {
		                  env.assert(scope, Array.prototype.join.call(arguments, ''), 'invalid stencil.func');
		                }
		                assert(value + '&&typeof ', value, '==="object"');
		                assert('!("cmp" in ', value, ')||(', value, '.cmp in ', COMPARE_FUNCS, ')');
		              });
		              var cmp = scope.def('"cmp" in ', value, '?', COMPARE_FUNCS, '[', value, '.cmp]', ':', GL_KEEP);
		              var ref = scope.def(value, '.ref|0');
		              var mask = scope.def('"mask" in ', value, '?', value, '.mask|0:-1');
		              return [cmp, ref, mask];
		            });
	
		          case S_STENCIL_OPFRONT:
		          case S_STENCIL_OPBACK:
		            return parseParam(function (value) {
		              check$1.commandType(value, 'object', param, env.commandStr);
		              var fail = value.fail || 'keep';
		              var zfail = value.zfail || 'keep';
		              var zpass = value.zpass || 'keep';
		              check$1.commandParameter(fail, stencilOps, prop + '.fail', env.commandStr);
		              check$1.commandParameter(zfail, stencilOps, prop + '.zfail', env.commandStr);
		              check$1.commandParameter(zpass, stencilOps, prop + '.zpass', env.commandStr);
		              return [prop === S_STENCIL_OPBACK ? GL_BACK : GL_FRONT, stencilOps[fail], stencilOps[zfail], stencilOps[zpass]];
		            }, function (env, scope, value) {
		              var STENCIL_OPS = env.constants.stencilOps;
	
		              check$1.optional(function () {
		                env.assert(scope, value + '&&typeof ' + value + '==="object"', 'invalid ' + prop);
		              });
	
		              function read(name) {
		                check$1.optional(function () {
		                  env.assert(scope, '!("' + name + '" in ' + value + ')||' + '(' + value + '.' + name + ' in ' + STENCIL_OPS + ')', 'invalid ' + prop + '.' + name + ', must be one of ' + Object.keys(stencilOps));
		                });
	
		                return scope.def('"', name, '" in ', value, '?', STENCIL_OPS, '[', value, '.', name, ']:', GL_KEEP);
		              }
	
		              return [prop === S_STENCIL_OPBACK ? GL_BACK : GL_FRONT, read('fail'), read('zfail'), read('zpass')];
		            });
	
		          case S_POLYGON_OFFSET_OFFSET:
		            return parseParam(function (value) {
		              check$1.commandType(value, 'object', param, env.commandStr);
		              var factor = value.factor | 0;
		              var units = value.units | 0;
		              check$1.commandType(factor, 'number', param + '.factor', env.commandStr);
		              check$1.commandType(units, 'number', param + '.units', env.commandStr);
		              return [factor, units];
		            }, function (env, scope, value) {
		              check$1.optional(function () {
		                env.assert(scope, value + '&&typeof ' + value + '==="object"', 'invalid ' + prop);
		              });
	
		              var FACTOR = scope.def(value, '.factor|0');
		              var UNITS = scope.def(value, '.units|0');
	
		              return [FACTOR, UNITS];
		            });
	
		          case S_CULL_FACE:
		            return parseParam(function (value) {
		              var face = 0;
		              if (value === 'front') {
		                face = GL_FRONT;
		              } else if (value === 'back') {
		                face = GL_BACK;
		              }
		              check$1.command(!!face, param, env.commandStr);
		              return face;
		            }, function (env, scope, value) {
		              check$1.optional(function () {
		                env.assert(scope, value + '==="front"||' + value + '==="back"', 'invalid cull.face');
		              });
		              return scope.def(value, '==="front"?', GL_FRONT, ':', GL_BACK);
		            });
	
		          case S_LINE_WIDTH:
		            return parseParam(function (value) {
		              check$1.command(typeof value === 'number' && value >= limits.lineWidthDims[0] && value <= limits.lineWidthDims[1], 'invalid line width, must positive number between ' + limits.lineWidthDims[0] + ' and ' + limits.lineWidthDims[1], env.commandStr);
		              return value;
		            }, function (env, scope, value) {
		              check$1.optional(function () {
		                env.assert(scope, 'typeof ' + value + '==="number"&&' + value + '>=' + limits.lineWidthDims[0] + '&&' + value + '<=' + limits.lineWidthDims[1], 'invalid line width');
		              });
	
		              return value;
		            });
	
		          case S_FRONT_FACE:
		            return parseParam(function (value) {
		              check$1.commandParameter(value, orientationType, param, env.commandStr);
		              return orientationType[value];
		            }, function (env, scope, value) {
		              check$1.optional(function () {
		                env.assert(scope, value + '==="cw"||' + value + '==="ccw"', 'invalid frontFace, must be one of cw,ccw');
		              });
		              return scope.def(value + '==="cw"?' + GL_CW + ':' + GL_CCW);
		            });
	
		          case S_COLOR_MASK:
		            return parseParam(function (value) {
		              check$1.command(isArrayLike(value) && value.length === 4, 'color.mask must be length 4 array', env.commandStr);
		              return value.map(function (v) {
		                return !!v;
		              });
		            }, function (env, scope, value) {
		              check$1.optional(function () {
		                env.assert(scope, env.shared.isArrayLike + '(' + value + ')&&' + value + '.length===4', 'invalid color.mask');
		              });
		              return loop(4, function (i) {
		                return '!!' + value + '[' + i + ']';
		              });
		            });
	
		          case S_SAMPLE_COVERAGE:
		            return parseParam(function (value) {
		              check$1.command(typeof value === 'object' && value, param, env.commandStr);
		              var sampleValue = 'value' in value ? value.value : 1;
		              var sampleInvert = !!value.invert;
		              check$1.command(typeof sampleValue === 'number' && sampleValue >= 0 && sampleValue <= 1, 'sample.coverage.value must be a number between 0 and 1', env.commandStr);
		              return [sampleValue, sampleInvert];
		            }, function (env, scope, value) {
		              check$1.optional(function () {
		                env.assert(scope, value + '&&typeof ' + value + '==="object"', 'invalid sample.coverage');
		              });
		              var VALUE = scope.def('"value" in ', value, '?+', value, '.value:1');
		              var INVERT = scope.def('!!', value, '.invert');
		              return [VALUE, INVERT];
		            });
		        }
		      });
	
		      return STATE;
		    }
	
		    function parseUniforms(uniforms, env) {
		      var staticUniforms = uniforms.static;
		      var dynamicUniforms = uniforms.dynamic;
	
		      var UNIFORMS = {};
	
		      Object.keys(staticUniforms).forEach(function (name) {
		        var value = staticUniforms[name];
		        var result;
		        if (typeof value === 'number' || typeof value === 'boolean') {
		          result = createStaticDecl(function () {
		            return value;
		          });
		        } else if (typeof value === 'function') {
		          var reglType = value._reglType;
		          if (reglType === 'texture2d' || reglType === 'textureCube') {
		            result = createStaticDecl(function (env) {
		              return env.link(value);
		            });
		          } else if (reglType === 'framebuffer' || reglType === 'framebufferCube') {
		            check$1.command(value.color.length > 0, 'missing color attachment for framebuffer sent to uniform "' + name + '"', env.commandStr);
		            result = createStaticDecl(function (env) {
		              return env.link(value.color[0]);
		            });
		          } else {
		            check$1.commandRaise('invalid data for uniform "' + name + '"', env.commandStr);
		          }
		        } else if (isArrayLike(value)) {
		          result = createStaticDecl(function (env) {
		            var ITEM = env.global.def('[', loop(value.length, function (i) {
		              check$1.command(typeof value[i] === 'number' || typeof value[i] === 'boolean', 'invalid uniform ' + name, env.commandStr);
		              return value[i];
		            }), ']');
		            return ITEM;
		          });
		        } else {
		          check$1.commandRaise('invalid or missing data for uniform "' + name + '"', env.commandStr);
		        }
		        result.value = value;
		        UNIFORMS[name] = result;
		      });
	
		      Object.keys(dynamicUniforms).forEach(function (key) {
		        var dyn = dynamicUniforms[key];
		        UNIFORMS[key] = createDynamicDecl(dyn, function (env, scope) {
		          return env.invoke(scope, dyn);
		        });
		      });
	
		      return UNIFORMS;
		    }
	
		    function parseAttributes(attributes, env) {
		      var staticAttributes = attributes.static;
		      var dynamicAttributes = attributes.dynamic;
	
		      var attributeDefs = {};
	
		      Object.keys(staticAttributes).forEach(function (attribute) {
		        var value = staticAttributes[attribute];
		        var id = stringStore.id(attribute);
	
		        var record = new AttributeRecord();
		        if (isBufferArgs(value)) {
		          record.state = ATTRIB_STATE_POINTER;
		          record.buffer = bufferState.getBuffer(bufferState.create(value, GL_ARRAY_BUFFER$1, false, true));
		          record.type = 0;
		        } else {
		          var buffer = bufferState.getBuffer(value);
		          if (buffer) {
		            record.state = ATTRIB_STATE_POINTER;
		            record.buffer = buffer;
		            record.type = 0;
		          } else {
		            check$1.command(typeof value === 'object' && value, 'invalid data for attribute ' + attribute, env.commandStr);
		            if (value.constant) {
		              var constant = value.constant;
		              record.buffer = 'null';
		              record.state = ATTRIB_STATE_CONSTANT;
		              if (typeof constant === 'number') {
		                record.x = constant;
		              } else {
		                check$1.command(isArrayLike(constant) && constant.length > 0 && constant.length <= 4, 'invalid constant for attribute ' + attribute, env.commandStr);
		                CUTE_COMPONENTS.forEach(function (c, i) {
		                  if (i < constant.length) {
		                    record[c] = constant[i];
		                  }
		                });
		              }
		            } else {
		              if (isBufferArgs(value.buffer)) {
		                buffer = bufferState.getBuffer(bufferState.create(value.buffer, GL_ARRAY_BUFFER$1, false, true));
		              } else {
		                buffer = bufferState.getBuffer(value.buffer);
		              }
		              check$1.command(!!buffer, 'missing buffer for attribute "' + attribute + '"', env.commandStr);
	
		              var offset = value.offset | 0;
		              check$1.command(offset >= 0, 'invalid offset for attribute "' + attribute + '"', env.commandStr);
	
		              var stride = value.stride | 0;
		              check$1.command(stride >= 0 && stride < 256, 'invalid stride for attribute "' + attribute + '", must be integer betweeen [0, 255]', env.commandStr);
	
		              var size = value.size | 0;
		              check$1.command(!('size' in value) || size > 0 && size <= 4, 'invalid size for attribute "' + attribute + '", must be 1,2,3,4', env.commandStr);
	
		              var normalized = !!value.normalized;
	
		              var type = 0;
		              if ('type' in value) {
		                check$1.commandParameter(value.type, glTypes, 'invalid type for attribute ' + attribute, env.commandStr);
		                type = glTypes[value.type];
		              }
	
		              var divisor = value.divisor | 0;
		              if ('divisor' in value) {
		                check$1.command(divisor === 0 || extInstancing, 'cannot specify divisor for attribute "' + attribute + '", instancing not supported', env.commandStr);
		                check$1.command(divisor >= 0, 'invalid divisor for attribute "' + attribute + '"', env.commandStr);
		              }
	
		              check$1.optional(function () {
		                var command = env.commandStr;
	
		                var VALID_KEYS = ['buffer', 'offset', 'divisor', 'normalized', 'type', 'size', 'stride'];
	
		                Object.keys(value).forEach(function (prop) {
		                  check$1.command(VALID_KEYS.indexOf(prop) >= 0, 'unknown parameter "' + prop + '" for attribute pointer "' + attribute + '" (valid parameters are ' + VALID_KEYS + ')', command);
		                });
		              });
	
		              record.buffer = buffer;
		              record.state = ATTRIB_STATE_POINTER;
		              record.size = size;
		              record.normalized = normalized;
		              record.type = type || buffer.dtype;
		              record.offset = offset;
		              record.stride = stride;
		              record.divisor = divisor;
		            }
		          }
		        }
	
		        attributeDefs[attribute] = createStaticDecl(function (env, scope) {
		          var cache = env.attribCache;
		          if (id in cache) {
		            return cache[id];
		          }
		          var result = {
		            isStream: false
		          };
		          Object.keys(record).forEach(function (key) {
		            result[key] = record[key];
		          });
		          if (record.buffer) {
		            result.buffer = env.link(record.buffer);
		            result.type = result.type || result.buffer + '.dtype';
		          }
		          cache[id] = result;
		          return result;
		        });
		      });
	
		      Object.keys(dynamicAttributes).forEach(function (attribute) {
		        var dyn = dynamicAttributes[attribute];
	
		        function appendAttributeCode(env, block) {
		          var VALUE = env.invoke(block, dyn);
	
		          var shared = env.shared;
	
		          var IS_BUFFER_ARGS = shared.isBufferArgs;
		          var BUFFER_STATE = shared.buffer;
	
		          // Perform validation on attribute
		          check$1.optional(function () {
		            env.assert(block, VALUE + '&&(typeof ' + VALUE + '==="object"||typeof ' + VALUE + '==="function")&&(' + IS_BUFFER_ARGS + '(' + VALUE + ')||' + BUFFER_STATE + '.getBuffer(' + VALUE + ')||' + BUFFER_STATE + '.getBuffer(' + VALUE + '.buffer)||' + IS_BUFFER_ARGS + '(' + VALUE + '.buffer)||' + '("constant" in ' + VALUE + '&&(typeof ' + VALUE + '.constant==="number"||' + shared.isArrayLike + '(' + VALUE + '.constant))))', 'invalid dynamic attribute "' + attribute + '"');
		          });
	
		          // allocate names for result
		          var result = {
		            isStream: block.def(false)
		          };
		          var defaultRecord = new AttributeRecord();
		          defaultRecord.state = ATTRIB_STATE_POINTER;
		          Object.keys(defaultRecord).forEach(function (key) {
		            result[key] = block.def('' + defaultRecord[key]);
		          });
	
		          var BUFFER = result.buffer;
		          var TYPE = result.type;
		          block('if(', IS_BUFFER_ARGS, '(', VALUE, ')){', result.isStream, '=true;', BUFFER, '=', BUFFER_STATE, '.createStream(', GL_ARRAY_BUFFER$1, ',', VALUE, ');', TYPE, '=', BUFFER, '.dtype;', '}else{', BUFFER, '=', BUFFER_STATE, '.getBuffer(', VALUE, ');', 'if(', BUFFER, '){', TYPE, '=', BUFFER, '.dtype;', '}else if("constant" in ', VALUE, '){', result.state, '=', ATTRIB_STATE_CONSTANT, ';', 'if(typeof ' + VALUE + '.constant === "number"){', result[CUTE_COMPONENTS[0]], '=', VALUE, '.constant;', CUTE_COMPONENTS.slice(1).map(function (n) {
		            return result[n];
		          }).join('='), '=0;', '}else{', CUTE_COMPONENTS.map(function (name, i) {
		            return result[name] + '=' + VALUE + '.constant.length>=' + i + '?' + VALUE + '.constant[' + i + ']:0;';
		          }).join(''), '}}else{', 'if(', IS_BUFFER_ARGS, '(', VALUE, '.buffer)){', BUFFER, '=', BUFFER_STATE, '.createStream(', GL_ARRAY_BUFFER$1, ',', VALUE, '.buffer);', '}else{', BUFFER, '=', BUFFER_STATE, '.getBuffer(', VALUE, '.buffer);', '}', TYPE, '="type" in ', VALUE, '?', shared.glTypes, '[', VALUE, '.type]:', BUFFER, '.dtype;', result.normalized, '=!!', VALUE, '.normalized;');
		          function emitReadRecord(name) {
		            block(result[name], '=', VALUE, '.', name, '|0;');
		          }
		          emitReadRecord('size');
		          emitReadRecord('offset');
		          emitReadRecord('stride');
		          emitReadRecord('divisor');
	
		          block('}}');
	
		          block.exit('if(', result.isStream, '){', BUFFER_STATE, '.destroyStream(', BUFFER, ');', '}');
	
		          return result;
		        }
	
		        attributeDefs[attribute] = createDynamicDecl(dyn, appendAttributeCode);
		      });
	
		      return attributeDefs;
		    }
	
		    function parseContext(context) {
		      var staticContext = context.static;
		      var dynamicContext = context.dynamic;
		      var result = {};
	
		      Object.keys(staticContext).forEach(function (name) {
		        var value = staticContext[name];
		        result[name] = createStaticDecl(function (env, scope) {
		          if (typeof value === 'number' || typeof value === 'boolean') {
		            return '' + value;
		          } else {
		            return env.link(value);
		          }
		        });
		      });
	
		      Object.keys(dynamicContext).forEach(function (name) {
		        var dyn = dynamicContext[name];
		        result[name] = createDynamicDecl(dyn, function (env, scope) {
		          return env.invoke(scope, dyn);
		        });
		      });
	
		      return result;
		    }
	
		    function parseArguments(options, attributes, uniforms, context, env) {
		      var staticOptions = options.static;
		      var dynamicOptions = options.dynamic;
	
		      check$1.optional(function () {
		        var KEY_NAMES = [S_FRAMEBUFFER, S_VERT, S_FRAG, S_ELEMENTS, S_PRIMITIVE, S_OFFSET, S_COUNT, S_INSTANCES, S_PROFILE].concat(GL_STATE_NAMES);
	
		        function checkKeys(dict) {
		          Object.keys(dict).forEach(function (key) {
		            check$1.command(KEY_NAMES.indexOf(key) >= 0, 'unknown parameter "' + key + '"', env.commandStr);
		          });
		        }
	
		        checkKeys(staticOptions);
		        checkKeys(dynamicOptions);
		      });
	
		      var framebuffer = parseFramebuffer(options, env);
		      var viewportAndScissor = parseViewportScissor(options, framebuffer, env);
		      var draw = parseDraw(options, env);
		      var state = parseGLState(options, env);
		      var shader = parseProgram(options, env);
	
		      function copyBox(name) {
		        var defn = viewportAndScissor[name];
		        if (defn) {
		          state[name] = defn;
		        }
		      }
		      copyBox(S_VIEWPORT);
		      copyBox(propName(S_SCISSOR_BOX));
	
		      var dirty = Object.keys(state).length > 0;
	
		      var result = {
		        framebuffer: framebuffer,
		        draw: draw,
		        shader: shader,
		        state: state,
		        dirty: dirty
		      };
	
		      result.profile = parseProfile(options, env);
		      result.uniforms = parseUniforms(uniforms, env);
		      result.attributes = parseAttributes(attributes, env);
		      result.context = parseContext(context, env);
		      return result;
		    }
	
		    // ===================================================
		    // ===================================================
		    // COMMON UPDATE FUNCTIONS
		    // ===================================================
		    // ===================================================
		    function emitContext(env, scope, context) {
		      var shared = env.shared;
		      var CONTEXT = shared.context;
	
		      var contextEnter = env.scope();
	
		      Object.keys(context).forEach(function (name) {
		        scope.save(CONTEXT, '.' + name);
		        var defn = context[name];
		        contextEnter(CONTEXT, '.', name, '=', defn.append(env, scope), ';');
		      });
	
		      scope(contextEnter);
		    }
	
		    // ===================================================
		    // ===================================================
		    // COMMON DRAWING FUNCTIONS
		    // ===================================================
		    // ===================================================
		    function emitPollFramebuffer(env, scope, framebuffer, skipCheck) {
		      var shared = env.shared;
	
		      var GL = shared.gl;
		      var FRAMEBUFFER_STATE = shared.framebuffer;
		      var EXT_DRAW_BUFFERS;
		      if (extDrawBuffers) {
		        EXT_DRAW_BUFFERS = scope.def(shared.extensions, '.webgl_draw_buffers');
		      }
	
		      var constants = env.constants;
	
		      var DRAW_BUFFERS = constants.drawBuffer;
		      var BACK_BUFFER = constants.backBuffer;
	
		      var NEXT;
		      if (framebuffer) {
		        NEXT = framebuffer.append(env, scope);
		      } else {
		        NEXT = scope.def(FRAMEBUFFER_STATE, '.next');
		      }
	
		      if (!skipCheck) {
		        scope('if(', NEXT, '!==', FRAMEBUFFER_STATE, '.cur){');
		      }
		      scope('if(', NEXT, '){', GL, '.bindFramebuffer(', GL_FRAMEBUFFER$1, ',', NEXT, '.framebuffer);');
		      if (extDrawBuffers) {
		        scope(EXT_DRAW_BUFFERS, '.drawBuffersWEBGL(', DRAW_BUFFERS, '[', NEXT, '.colorAttachments.length]);');
		      }
		      scope('}else{', GL, '.bindFramebuffer(', GL_FRAMEBUFFER$1, ',null);');
		      if (extDrawBuffers) {
		        scope(EXT_DRAW_BUFFERS, '.drawBuffersWEBGL(', BACK_BUFFER, ');');
		      }
		      scope('}', FRAMEBUFFER_STATE, '.cur=', NEXT, ';');
		      if (!skipCheck) {
		        scope('}');
		      }
		    }
	
		    function emitPollState(env, scope, args) {
		      var shared = env.shared;
	
		      var GL = shared.gl;
	
		      var CURRENT_VARS = env.current;
		      var NEXT_VARS = env.next;
		      var CURRENT_STATE = shared.current;
		      var NEXT_STATE = shared.next;
	
		      var block = env.cond(CURRENT_STATE, '.dirty');
	
		      GL_STATE_NAMES.forEach(function (prop) {
		        var param = propName(prop);
		        if (param in args.state) {
		          return;
		        }
	
		        var NEXT, CURRENT;
		        if (param in NEXT_VARS) {
		          NEXT = NEXT_VARS[param];
		          CURRENT = CURRENT_VARS[param];
		          var parts = loop(currentState[param].length, function (i) {
		            return block.def(NEXT, '[', i, ']');
		          });
		          block(env.cond(parts.map(function (p, i) {
		            return p + '!==' + CURRENT + '[' + i + ']';
		          }).join('||')).then(GL, '.', GL_VARIABLES[param], '(', parts, ');', parts.map(function (p, i) {
		            return CURRENT + '[' + i + ']=' + p;
		          }).join(';'), ';'));
		        } else {
		          NEXT = block.def(NEXT_STATE, '.', param);
		          var ifte = env.cond(NEXT, '!==', CURRENT_STATE, '.', param);
		          block(ifte);
		          if (param in GL_FLAGS) {
		            ifte(env.cond(NEXT).then(GL, '.enable(', GL_FLAGS[param], ');').else(GL, '.disable(', GL_FLAGS[param], ');'), CURRENT_STATE, '.', param, '=', NEXT, ';');
		          } else {
		            ifte(GL, '.', GL_VARIABLES[param], '(', NEXT, ');', CURRENT_STATE, '.', param, '=', NEXT, ';');
		          }
		        }
		      });
		      if (Object.keys(args.state).length === 0) {
		        block(CURRENT_STATE, '.dirty=false;');
		      }
		      scope(block);
		    }
	
		    function emitSetOptions(env, scope, options, filter) {
		      var shared = env.shared;
		      var CURRENT_VARS = env.current;
		      var CURRENT_STATE = shared.current;
		      var GL = shared.gl;
		      sortState(Object.keys(options)).forEach(function (param) {
		        var defn = options[param];
		        if (filter && !filter(defn)) {
		          return;
		        }
		        var variable = defn.append(env, scope);
		        if (GL_FLAGS[param]) {
		          var flag = GL_FLAGS[param];
		          if (isStatic(defn)) {
		            if (variable) {
		              scope(GL, '.enable(', flag, ');');
		            } else {
		              scope(GL, '.disable(', flag, ');');
		            }
		          } else {
		            scope(env.cond(variable).then(GL, '.enable(', flag, ');').else(GL, '.disable(', flag, ');'));
		          }
		          scope(CURRENT_STATE, '.', param, '=', variable, ';');
		        } else if (isArrayLike(variable)) {
		          var CURRENT = CURRENT_VARS[param];
		          scope(GL, '.', GL_VARIABLES[param], '(', variable, ');', variable.map(function (v, i) {
		            return CURRENT + '[' + i + ']=' + v;
		          }).join(';'), ';');
		        } else {
		          scope(GL, '.', GL_VARIABLES[param], '(', variable, ');', CURRENT_STATE, '.', param, '=', variable, ';');
		        }
		      });
		    }
	
		    function injectExtensions(env, scope) {
		      if (extInstancing) {
		        env.instancing = scope.def(env.shared.extensions, '.angle_instanced_arrays');
		      }
		    }
	
		    function emitProfile(env, scope, args, useScope, incrementCounter) {
		      var shared = env.shared;
		      var STATS = env.stats;
		      var CURRENT_STATE = shared.current;
		      var TIMER = shared.timer;
		      var profileArg = args.profile;
	
		      function perfCounter() {
		        if (typeof performance === 'undefined') {
		          return 'Date.now()';
		        } else {
		          return 'performance.now()';
		        }
		      }
	
		      var CPU_START, QUERY_COUNTER;
		      function emitProfileStart(block) {
		        CPU_START = scope.def();
		        block(CPU_START, '=', perfCounter(), ';');
		        if (typeof incrementCounter === 'string') {
		          block(STATS, '.count+=', incrementCounter, ';');
		        } else {
		          block(STATS, '.count++;');
		        }
		        if (timer) {
		          if (useScope) {
		            QUERY_COUNTER = scope.def();
		            block(QUERY_COUNTER, '=', TIMER, '.getNumPendingQueries();');
		          } else {
		            block(TIMER, '.beginQuery(', STATS, ');');
		          }
		        }
		      }
	
		      function emitProfileEnd(block) {
		        block(STATS, '.cpuTime+=', perfCounter(), '-', CPU_START, ';');
		        if (timer) {
		          if (useScope) {
		            block(TIMER, '.pushScopeStats(', QUERY_COUNTER, ',', TIMER, '.getNumPendingQueries(),', STATS, ');');
		          } else {
		            block(TIMER, '.endQuery();');
		          }
		        }
		      }
	
		      function scopeProfile(value) {
		        var prev = scope.def(CURRENT_STATE, '.profile');
		        scope(CURRENT_STATE, '.profile=', value, ';');
		        scope.exit(CURRENT_STATE, '.profile=', prev, ';');
		      }
	
		      var USE_PROFILE;
		      if (profileArg) {
		        if (isStatic(profileArg)) {
		          if (profileArg.enable) {
		            emitProfileStart(scope);
		            emitProfileEnd(scope.exit);
		            scopeProfile('true');
		          } else {
		            scopeProfile('false');
		          }
		          return;
		        }
		        USE_PROFILE = profileArg.append(env, scope);
		        scopeProfile(USE_PROFILE);
		      } else {
		        USE_PROFILE = scope.def(CURRENT_STATE, '.profile');
		      }
	
		      var start = env.block();
		      emitProfileStart(start);
		      scope('if(', USE_PROFILE, '){', start, '}');
		      var end = env.block();
		      emitProfileEnd(end);
		      scope.exit('if(', USE_PROFILE, '){', end, '}');
		    }
	
		    function emitAttributes(env, scope, args, attributes, filter) {
		      var shared = env.shared;
	
		      function typeLength(x) {
		        switch (x) {
		          case GL_FLOAT_VEC2:
		          case GL_INT_VEC2:
		          case GL_BOOL_VEC2:
		            return 2;
		          case GL_FLOAT_VEC3:
		          case GL_INT_VEC3:
		          case GL_BOOL_VEC3:
		            return 3;
		          case GL_FLOAT_VEC4:
		          case GL_INT_VEC4:
		          case GL_BOOL_VEC4:
		            return 4;
		          default:
		            return 1;
		        }
		      }
	
		      function emitBindAttribute(ATTRIBUTE, size, record) {
		        var GL = shared.gl;
	
		        var LOCATION = scope.def(ATTRIBUTE, '.location');
		        var BINDING = scope.def(shared.attributes, '[', LOCATION, ']');
	
		        var STATE = record.state;
		        var BUFFER = record.buffer;
		        var CONST_COMPONENTS = [record.x, record.y, record.z, record.w];
	
		        var COMMON_KEYS = ['buffer', 'normalized', 'offset', 'stride'];
	
		        function emitBuffer() {
		          scope('if(!', BINDING, '.buffer){', GL, '.enableVertexAttribArray(', LOCATION, ');}');
	
		          var TYPE = record.type;
		          var SIZE;
		          if (!record.size) {
		            SIZE = size;
		          } else {
		            SIZE = scope.def(record.size, '||', size);
		          }
	
		          scope('if(', BINDING, '.type!==', TYPE, '||', BINDING, '.size!==', SIZE, '||', COMMON_KEYS.map(function (key) {
		            return BINDING + '.' + key + '!==' + record[key];
		          }).join('||'), '){', GL, '.bindBuffer(', GL_ARRAY_BUFFER$1, ',', BUFFER, '.buffer);', GL, '.vertexAttribPointer(', [LOCATION, SIZE, TYPE, record.normalized, record.stride, record.offset], ');', BINDING, '.type=', TYPE, ';', BINDING, '.size=', SIZE, ';', COMMON_KEYS.map(function (key) {
		            return BINDING + '.' + key + '=' + record[key] + ';';
		          }).join(''), '}');
	
		          if (extInstancing) {
		            var DIVISOR = record.divisor;
		            scope('if(', BINDING, '.divisor!==', DIVISOR, '){', env.instancing, '.vertexAttribDivisorANGLE(', [LOCATION, DIVISOR], ');', BINDING, '.divisor=', DIVISOR, ';}');
		          }
		        }
	
		        function emitConstant() {
		          scope('if(', BINDING, '.buffer){', GL, '.disableVertexAttribArray(', LOCATION, ');', '}if(', CUTE_COMPONENTS.map(function (c, i) {
		            return BINDING + '.' + c + '!==' + CONST_COMPONENTS[i];
		          }).join('||'), '){', GL, '.vertexAttrib4f(', LOCATION, ',', CONST_COMPONENTS, ');', CUTE_COMPONENTS.map(function (c, i) {
		            return BINDING + '.' + c + '=' + CONST_COMPONENTS[i] + ';';
		          }).join(''), '}');
		        }
	
		        if (STATE === ATTRIB_STATE_POINTER) {
		          emitBuffer();
		        } else if (STATE === ATTRIB_STATE_CONSTANT) {
		          emitConstant();
		        } else {
		          scope('if(', STATE, '===', ATTRIB_STATE_POINTER, '){');
		          emitBuffer();
		          scope('}else{');
		          emitConstant();
		          scope('}');
		        }
		      }
	
		      attributes.forEach(function (attribute) {
		        var name = attribute.name;
		        var arg = args.attributes[name];
		        var record;
		        if (arg) {
		          if (!filter(arg)) {
		            return;
		          }
		          record = arg.append(env, scope);
		        } else {
		          if (!filter(SCOPE_DECL)) {
		            return;
		          }
		          var scopeAttrib = env.scopeAttrib(name);
		          check$1.optional(function () {
		            env.assert(scope, scopeAttrib + '.state', 'missing attribute ' + name);
		          });
		          record = {};
		          Object.keys(new AttributeRecord()).forEach(function (key) {
		            record[key] = scope.def(scopeAttrib, '.', key);
		          });
		        }
		        emitBindAttribute(env.link(attribute), typeLength(attribute.info.type), record);
		      });
		    }
	
		    function emitUniforms(env, scope, args, uniforms, filter) {
		      var shared = env.shared;
		      var GL = shared.gl;
	
		      var infix;
		      for (var i = 0; i < uniforms.length; ++i) {
		        var uniform = uniforms[i];
		        var name = uniform.name;
		        var type = uniform.info.type;
		        var arg = args.uniforms[name];
		        var UNIFORM = env.link(uniform);
		        var LOCATION = UNIFORM + '.location';
	
		        var VALUE;
		        if (arg) {
		          if (!filter(arg)) {
		            continue;
		          }
		          if (isStatic(arg)) {
		            var value = arg.value;
		            check$1.command(value !== null && typeof value !== 'undefined', 'missing uniform "' + name + '"', env.commandStr);
		            if (type === GL_SAMPLER_2D || type === GL_SAMPLER_CUBE) {
		              check$1.command(typeof value === 'function' && (type === GL_SAMPLER_2D && (value._reglType === 'texture2d' || value._reglType === 'framebuffer') || type === GL_SAMPLER_CUBE && (value._reglType === 'textureCube' || value._reglType === 'framebufferCube')), 'invalid texture for uniform ' + name, env.commandStr);
		              var TEX_VALUE = env.link(value._texture || value.color[0]._texture);
		              scope(GL, '.uniform1i(', LOCATION, ',', TEX_VALUE + '.bind());');
		              scope.exit(TEX_VALUE, '.unbind();');
		            } else if (type === GL_FLOAT_MAT2 || type === GL_FLOAT_MAT3 || type === GL_FLOAT_MAT4) {
		              check$1.optional(function () {
		                check$1.command(isArrayLike(value), 'invalid matrix for uniform ' + name, env.commandStr);
		                check$1.command(type === GL_FLOAT_MAT2 && value.length === 4 || type === GL_FLOAT_MAT3 && value.length === 9 || type === GL_FLOAT_MAT4 && value.length === 16, 'invalid length for matrix uniform ' + name, env.commandStr);
		              });
		              var MAT_VALUE = env.global.def('new Float32Array([' + Array.prototype.slice.call(value) + '])');
		              var dim = 2;
		              if (type === GL_FLOAT_MAT3) {
		                dim = 3;
		              } else if (type === GL_FLOAT_MAT4) {
		                dim = 4;
		              }
		              scope(GL, '.uniformMatrix', dim, 'fv(', LOCATION, ',false,', MAT_VALUE, ');');
		            } else {
		              switch (type) {
		                case GL_FLOAT$7:
		                  check$1.commandType(value, 'number', 'uniform ' + name, env.commandStr);
		                  infix = '1f';
		                  break;
		                case GL_FLOAT_VEC2:
		                  check$1.command(isArrayLike(value) && value.length === 2, 'uniform ' + name, env.commandStr);
		                  infix = '2f';
		                  break;
		                case GL_FLOAT_VEC3:
		                  check$1.command(isArrayLike(value) && value.length === 3, 'uniform ' + name, env.commandStr);
		                  infix = '3f';
		                  break;
		                case GL_FLOAT_VEC4:
		                  check$1.command(isArrayLike(value) && value.length === 4, 'uniform ' + name, env.commandStr);
		                  infix = '4f';
		                  break;
		                case GL_BOOL:
		                  check$1.commandType(value, 'boolean', 'uniform ' + name, env.commandStr);
		                  infix = '1i';
		                  break;
		                case GL_INT$3:
		                  check$1.commandType(value, 'number', 'uniform ' + name, env.commandStr);
		                  infix = '1i';
		                  break;
		                case GL_BOOL_VEC2:
		                  check$1.command(isArrayLike(value) && value.length === 2, 'uniform ' + name, env.commandStr);
		                  infix = '2i';
		                  break;
		                case GL_INT_VEC2:
		                  check$1.command(isArrayLike(value) && value.length === 2, 'uniform ' + name, env.commandStr);
		                  infix = '2i';
		                  break;
		                case GL_BOOL_VEC3:
		                  check$1.command(isArrayLike(value) && value.length === 3, 'uniform ' + name, env.commandStr);
		                  infix = '3i';
		                  break;
		                case GL_INT_VEC3:
		                  check$1.command(isArrayLike(value) && value.length === 3, 'uniform ' + name, env.commandStr);
		                  infix = '3i';
		                  break;
		                case GL_BOOL_VEC4:
		                  check$1.command(isArrayLike(value) && value.length === 4, 'uniform ' + name, env.commandStr);
		                  infix = '4i';
		                  break;
		                case GL_INT_VEC4:
		                  check$1.command(isArrayLike(value) && value.length === 4, 'uniform ' + name, env.commandStr);
		                  infix = '4i';
		                  break;
		              }
		              scope(GL, '.uniform', infix, '(', LOCATION, ',', isArrayLike(value) ? Array.prototype.slice.call(value) : value, ');');
		            }
		            continue;
		          } else {
		            VALUE = arg.append(env, scope);
		          }
		        } else {
		          if (!filter(SCOPE_DECL)) {
		            continue;
		          }
		          VALUE = scope.def(shared.uniforms, '[', stringStore.id(name), ']');
		        }
	
		        if (type === GL_SAMPLER_2D) {
		          scope('if(', VALUE, '&&', VALUE, '._reglType==="framebuffer"){', VALUE, '=', VALUE, '.color[0];', '}');
		        } else if (type === GL_SAMPLER_CUBE) {
		          scope('if(', VALUE, '&&', VALUE, '._reglType==="framebufferCube"){', VALUE, '=', VALUE, '.color[0];', '}');
		        }
	
		        // perform type validation
		        check$1.optional(function () {
		          function check(pred, message) {
		            env.assert(scope, pred, 'bad data or missing for uniform "' + name + '".  ' + message);
		          }
	
		          function checkType(type) {
		            check('typeof ' + VALUE + '==="' + type + '"', 'invalid type, expected ' + type);
		          }
	
		          function checkVector(n, type) {
		            check(shared.isArrayLike + '(' + VALUE + ')&&' + VALUE + '.length===' + n, 'invalid vector, should have length ' + n, env.commandStr);
		          }
	
		          function checkTexture(target) {
		            check('typeof ' + VALUE + '==="function"&&' + VALUE + '._reglType==="texture' + (target === GL_TEXTURE_2D$2 ? '2d' : 'Cube') + '"', 'invalid texture type', env.commandStr);
		          }
	
		          switch (type) {
		            case GL_INT$3:
		              checkType('number');
		              break;
		            case GL_INT_VEC2:
		              checkVector(2, 'number');
		              break;
		            case GL_INT_VEC3:
		              checkVector(3, 'number');
		              break;
		            case GL_INT_VEC4:
		              checkVector(4, 'number');
		              break;
		            case GL_FLOAT$7:
		              checkType('number');
		              break;
		            case GL_FLOAT_VEC2:
		              checkVector(2, 'number');
		              break;
		            case GL_FLOAT_VEC3:
		              checkVector(3, 'number');
		              break;
		            case GL_FLOAT_VEC4:
		              checkVector(4, 'number');
		              break;
		            case GL_BOOL:
		              checkType('boolean');
		              break;
		            case GL_BOOL_VEC2:
		              checkVector(2, 'boolean');
		              break;
		            case GL_BOOL_VEC3:
		              checkVector(3, 'boolean');
		              break;
		            case GL_BOOL_VEC4:
		              checkVector(4, 'boolean');
		              break;
		            case GL_FLOAT_MAT2:
		              checkVector(4, 'number');
		              break;
		            case GL_FLOAT_MAT3:
		              checkVector(9, 'number');
		              break;
		            case GL_FLOAT_MAT4:
		              checkVector(16, 'number');
		              break;
		            case GL_SAMPLER_2D:
		              checkTexture(GL_TEXTURE_2D$2);
		              break;
		            case GL_SAMPLER_CUBE:
		              checkTexture(GL_TEXTURE_CUBE_MAP$1);
		              break;
		          }
		        });
	
		        var unroll = 1;
		        switch (type) {
		          case GL_SAMPLER_2D:
		          case GL_SAMPLER_CUBE:
		            var TEX = scope.def(VALUE, '._texture');
		            scope(GL, '.uniform1i(', LOCATION, ',', TEX, '.bind());');
		            scope.exit(TEX, '.unbind();');
		            continue;
	
		          case GL_INT$3:
		          case GL_BOOL:
		            infix = '1i';
		            break;
	
		          case GL_INT_VEC2:
		          case GL_BOOL_VEC2:
		            infix = '2i';
		            unroll = 2;
		            break;
	
		          case GL_INT_VEC3:
		          case GL_BOOL_VEC3:
		            infix = '3i';
		            unroll = 3;
		            break;
	
		          case GL_INT_VEC4:
		          case GL_BOOL_VEC4:
		            infix = '4i';
		            unroll = 4;
		            break;
	
		          case GL_FLOAT$7:
		            infix = '1f';
		            break;
	
		          case GL_FLOAT_VEC2:
		            infix = '2f';
		            unroll = 2;
		            break;
	
		          case GL_FLOAT_VEC3:
		            infix = '3f';
		            unroll = 3;
		            break;
	
		          case GL_FLOAT_VEC4:
		            infix = '4f';
		            unroll = 4;
		            break;
	
		          case GL_FLOAT_MAT2:
		            infix = 'Matrix2fv';
		            break;
	
		          case GL_FLOAT_MAT3:
		            infix = 'Matrix3fv';
		            break;
	
		          case GL_FLOAT_MAT4:
		            infix = 'Matrix4fv';
		            break;
		        }
	
		        scope(GL, '.uniform', infix, '(', LOCATION, ',');
		        if (infix.charAt(0) === 'M') {
		          var matSize = Math.pow(type - GL_FLOAT_MAT2 + 2, 2);
		          var STORAGE = env.global.def('new Float32Array(', matSize, ')');
		          scope('false,(Array.isArray(', VALUE, ')||', VALUE, ' instanceof Float32Array)?', VALUE, ':(', loop(matSize, function (i) {
		            return STORAGE + '[' + i + ']=' + VALUE + '[' + i + ']';
		          }), ',', STORAGE, ')');
		        } else if (unroll > 1) {
		          scope(loop(unroll, function (i) {
		            return VALUE + '[' + i + ']';
		          }));
		        } else {
		          scope(VALUE);
		        }
		        scope(');');
		      }
		    }
	
		    function emitDraw(env, outer, inner, args) {
		      var shared = env.shared;
		      var GL = shared.gl;
		      var DRAW_STATE = shared.draw;
	
		      var drawOptions = args.draw;
	
		      function emitElements() {
		        var defn = drawOptions.elements;
		        var ELEMENTS;
		        var scope = outer;
		        if (defn) {
		          if (defn.contextDep && args.contextDynamic || defn.propDep) {
		            scope = inner;
		          }
		          ELEMENTS = defn.append(env, scope);
		        } else {
		          ELEMENTS = scope.def(DRAW_STATE, '.', S_ELEMENTS);
		        }
		        if (ELEMENTS) {
		          scope('if(' + ELEMENTS + ')' + GL + '.bindBuffer(' + GL_ELEMENT_ARRAY_BUFFER$1 + ',' + ELEMENTS + '.buffer.buffer);');
		        }
		        return ELEMENTS;
		      }
	
		      function emitCount() {
		        var defn = drawOptions.count;
		        var COUNT;
		        var scope = outer;
		        if (defn) {
		          if (defn.contextDep && args.contextDynamic || defn.propDep) {
		            scope = inner;
		          }
		          COUNT = defn.append(env, scope);
		          check$1.optional(function () {
		            if (defn.MISSING) {
		              env.assert(outer, 'false', 'missing vertex count');
		            }
		            if (defn.DYNAMIC) {
		              env.assert(scope, COUNT + '>=0', 'missing vertex count');
		            }
		          });
		        } else {
		          COUNT = scope.def(DRAW_STATE, '.', S_COUNT);
		          check$1.optional(function () {
		            env.assert(scope, COUNT + '>=0', 'missing vertex count');
		          });
		        }
		        return COUNT;
		      }
	
		      var ELEMENTS = emitElements();
		      function emitValue(name) {
		        var defn = drawOptions[name];
		        if (defn) {
		          if (defn.contextDep && args.contextDynamic || defn.propDep) {
		            return defn.append(env, inner);
		          } else {
		            return defn.append(env, outer);
		          }
		        } else {
		          return outer.def(DRAW_STATE, '.', name);
		        }
		      }
	
		      var PRIMITIVE = emitValue(S_PRIMITIVE);
		      var OFFSET = emitValue(S_OFFSET);
	
		      var COUNT = emitCount();
		      if (typeof COUNT === 'number') {
		        if (COUNT === 0) {
		          return;
		        }
		      } else {
		        inner('if(', COUNT, '){');
		        inner.exit('}');
		      }
	
		      var INSTANCES, EXT_INSTANCING;
		      if (extInstancing) {
		        INSTANCES = emitValue(S_INSTANCES);
		        EXT_INSTANCING = env.instancing;
		      }
	
		      var ELEMENT_TYPE = ELEMENTS + '.type';
	
		      var elementsStatic = drawOptions.elements && isStatic(drawOptions.elements);
	
		      function emitInstancing() {
		        function drawElements() {
		          inner(EXT_INSTANCING, '.drawElementsInstancedANGLE(', [PRIMITIVE, COUNT, ELEMENT_TYPE, OFFSET + '<<((' + ELEMENT_TYPE + '-' + GL_UNSIGNED_BYTE$7 + ')>>1)', INSTANCES], ');');
		        }
	
		        function drawArrays() {
		          inner(EXT_INSTANCING, '.drawArraysInstancedANGLE(', [PRIMITIVE, OFFSET, COUNT, INSTANCES], ');');
		        }
	
		        if (ELEMENTS) {
		          if (!elementsStatic) {
		            inner('if(', ELEMENTS, '){');
		            drawElements();
		            inner('}else{');
		            drawArrays();
		            inner('}');
		          } else {
		            drawElements();
		          }
		        } else {
		          drawArrays();
		        }
		      }
	
		      function emitRegular() {
		        function drawElements() {
		          inner(GL + '.drawElements(' + [PRIMITIVE, COUNT, ELEMENT_TYPE, OFFSET + '<<((' + ELEMENT_TYPE + '-' + GL_UNSIGNED_BYTE$7 + ')>>1)'] + ');');
		        }
	
		        function drawArrays() {
		          inner(GL + '.drawArrays(' + [PRIMITIVE, OFFSET, COUNT] + ');');
		        }
	
		        if (ELEMENTS) {
		          if (!elementsStatic) {
		            inner('if(', ELEMENTS, '){');
		            drawElements();
		            inner('}else{');
		            drawArrays();
		            inner('}');
		          } else {
		            drawElements();
		          }
		        } else {
		          drawArrays();
		        }
		      }
	
		      if (extInstancing && (typeof INSTANCES !== 'number' || INSTANCES >= 0)) {
		        if (typeof INSTANCES === 'string') {
		          inner('if(', INSTANCES, '>0){');
		          emitInstancing();
		          inner('}else if(', INSTANCES, '<0){');
		          emitRegular();
		          inner('}');
		        } else {
		          emitInstancing();
		        }
		      } else {
		        emitRegular();
		      }
		    }
	
		    function createBody(emitBody, parentEnv, args, program, count) {
		      var env = createREGLEnvironment();
		      var scope = env.proc('body', count);
		      check$1.optional(function () {
		        env.commandStr = parentEnv.commandStr;
		        env.command = env.link(parentEnv.commandStr);
		      });
		      if (extInstancing) {
		        env.instancing = scope.def(env.shared.extensions, '.angle_instanced_arrays');
		      }
		      emitBody(env, scope, args, program);
		      return env.compile().body;
		    }
	
		    // ===================================================
		    // ===================================================
		    // DRAW PROC
		    // ===================================================
		    // ===================================================
		    function emitDrawBody(env, draw, args, program) {
		      injectExtensions(env, draw);
		      emitAttributes(env, draw, args, program.attributes, function () {
		        return true;
		      });
		      emitUniforms(env, draw, args, program.uniforms, function () {
		        return true;
		      });
		      emitDraw(env, draw, draw, args);
		    }
	
		    function emitDrawProc(env, args) {
		      var draw = env.proc('draw', 1);
	
		      injectExtensions(env, draw);
	
		      emitContext(env, draw, args.context);
		      emitPollFramebuffer(env, draw, args.framebuffer);
	
		      emitPollState(env, draw, args);
		      emitSetOptions(env, draw, args.state);
	
		      emitProfile(env, draw, args, false, true);
	
		      var program = args.shader.progVar.append(env, draw);
		      draw(env.shared.gl, '.useProgram(', program, '.program);');
	
		      if (args.shader.program) {
		        emitDrawBody(env, draw, args, args.shader.program);
		      } else {
		        var drawCache = env.global.def('{}');
		        var PROG_ID = draw.def(program, '.id');
		        var CACHED_PROC = draw.def(drawCache, '[', PROG_ID, ']');
		        draw(env.cond(CACHED_PROC).then(CACHED_PROC, '.call(this,a0);').else(CACHED_PROC, '=', drawCache, '[', PROG_ID, ']=', env.link(function (program) {
		          return createBody(emitDrawBody, env, args, program, 1);
		        }), '(', program, ');', CACHED_PROC, '.call(this,a0);'));
		      }
	
		      if (Object.keys(args.state).length > 0) {
		        draw(env.shared.current, '.dirty=true;');
		      }
		    }
	
		    // ===================================================
		    // ===================================================
		    // BATCH PROC
		    // ===================================================
		    // ===================================================
	
		    function emitBatchDynamicShaderBody(env, scope, args, program) {
		      env.batchId = 'a1';
	
		      injectExtensions(env, scope);
	
		      function all() {
		        return true;
		      }
	
		      emitAttributes(env, scope, args, program.attributes, all);
		      emitUniforms(env, scope, args, program.uniforms, all);
		      emitDraw(env, scope, scope, args);
		    }
	
		    function emitBatchBody(env, scope, args, program) {
		      injectExtensions(env, scope);
	
		      var contextDynamic = args.contextDep;
	
		      var BATCH_ID = scope.def();
		      var PROP_LIST = 'a0';
		      var NUM_PROPS = 'a1';
		      var PROPS = scope.def();
		      env.shared.props = PROPS;
		      env.batchId = BATCH_ID;
	
		      var outer = env.scope();
		      var inner = env.scope();
	
		      scope(outer.entry, 'for(', BATCH_ID, '=0;', BATCH_ID, '<', NUM_PROPS, ';++', BATCH_ID, '){', PROPS, '=', PROP_LIST, '[', BATCH_ID, '];', inner, '}', outer.exit);
	
		      function isInnerDefn(defn) {
		        return defn.contextDep && contextDynamic || defn.propDep;
		      }
	
		      function isOuterDefn(defn) {
		        return !isInnerDefn(defn);
		      }
	
		      if (args.needsContext) {
		        emitContext(env, inner, args.context);
		      }
		      if (args.needsFramebuffer) {
		        emitPollFramebuffer(env, inner, args.framebuffer);
		      }
		      emitSetOptions(env, inner, args.state, isInnerDefn);
	
		      if (args.profile && isInnerDefn(args.profile)) {
		        emitProfile(env, inner, args, false, true);
		      }
	
		      if (!program) {
		        var progCache = env.global.def('{}');
		        var PROGRAM = args.shader.progVar.append(env, inner);
		        var PROG_ID = inner.def(PROGRAM, '.id');
		        var CACHED_PROC = inner.def(progCache, '[', PROG_ID, ']');
		        inner(env.shared.gl, '.useProgram(', PROGRAM, '.program);', 'if(!', CACHED_PROC, '){', CACHED_PROC, '=', progCache, '[', PROG_ID, ']=', env.link(function (program) {
		          return createBody(emitBatchDynamicShaderBody, env, args, program, 2);
		        }), '(', PROGRAM, ');}', CACHED_PROC, '.call(this,a0[', BATCH_ID, '],', BATCH_ID, ');');
		      } else {
		        emitAttributes(env, outer, args, program.attributes, isOuterDefn);
		        emitAttributes(env, inner, args, program.attributes, isInnerDefn);
		        emitUniforms(env, outer, args, program.uniforms, isOuterDefn);
		        emitUniforms(env, inner, args, program.uniforms, isInnerDefn);
		        emitDraw(env, outer, inner, args);
		      }
		    }
	
		    function emitBatchProc(env, args) {
		      var batch = env.proc('batch', 2);
		      env.batchId = '0';
	
		      injectExtensions(env, batch);
	
		      // Check if any context variables depend on props
		      var contextDynamic = false;
		      var needsContext = true;
		      Object.keys(args.context).forEach(function (name) {
		        contextDynamic = contextDynamic || args.context[name].propDep;
		      });
		      if (!contextDynamic) {
		        emitContext(env, batch, args.context);
		        needsContext = false;
		      }
	
		      // framebuffer state affects framebufferWidth/height context vars
		      var framebuffer = args.framebuffer;
		      var needsFramebuffer = false;
		      if (framebuffer) {
		        if (framebuffer.propDep) {
		          contextDynamic = needsFramebuffer = true;
		        } else if (framebuffer.contextDep && contextDynamic) {
		          needsFramebuffer = true;
		        }
		        if (!needsFramebuffer) {
		          emitPollFramebuffer(env, batch, framebuffer);
		        }
		      } else {
		        emitPollFramebuffer(env, batch, null);
		      }
	
		      // viewport is weird because it can affect context vars
		      if (args.state.viewport && args.state.viewport.propDep) {
		        contextDynamic = true;
		      }
	
		      function isInnerDefn(defn) {
		        return defn.contextDep && contextDynamic || defn.propDep;
		      }
	
		      // set webgl options
		      emitPollState(env, batch, args);
		      emitSetOptions(env, batch, args.state, function (defn) {
		        return !isInnerDefn(defn);
		      });
	
		      if (!args.profile || !isInnerDefn(args.profile)) {
		        emitProfile(env, batch, args, false, 'a1');
		      }
	
		      // Save these values to args so that the batch body routine can use them
		      args.contextDep = contextDynamic;
		      args.needsContext = needsContext;
		      args.needsFramebuffer = needsFramebuffer;
	
		      // determine if shader is dynamic
		      var progDefn = args.shader.progVar;
		      if (progDefn.contextDep && contextDynamic || progDefn.propDep) {
		        emitBatchBody(env, batch, args, null);
		      } else {
		        var PROGRAM = progDefn.append(env, batch);
		        batch(env.shared.gl, '.useProgram(', PROGRAM, '.program);');
		        if (args.shader.program) {
		          emitBatchBody(env, batch, args, args.shader.program);
		        } else {
		          var batchCache = env.global.def('{}');
		          var PROG_ID = batch.def(PROGRAM, '.id');
		          var CACHED_PROC = batch.def(batchCache, '[', PROG_ID, ']');
		          batch(env.cond(CACHED_PROC).then(CACHED_PROC, '.call(this,a0,a1);').else(CACHED_PROC, '=', batchCache, '[', PROG_ID, ']=', env.link(function (program) {
		            return createBody(emitBatchBody, env, args, program, 2);
		          }), '(', PROGRAM, ');', CACHED_PROC, '.call(this,a0,a1);'));
		        }
		      }
	
		      if (Object.keys(args.state).length > 0) {
		        batch(env.shared.current, '.dirty=true;');
		      }
		    }
	
		    // ===================================================
		    // ===================================================
		    // SCOPE COMMAND
		    // ===================================================
		    // ===================================================
		    function emitScopeProc(env, args) {
		      var scope = env.proc('scope', 3);
		      env.batchId = 'a2';
	
		      var shared = env.shared;
		      var CURRENT_STATE = shared.current;
	
		      emitContext(env, scope, args.context);
	
		      if (args.framebuffer) {
		        args.framebuffer.append(env, scope);
		      }
	
		      sortState(Object.keys(args.state)).forEach(function (name) {
		        var defn = args.state[name];
		        var value = defn.append(env, scope);
		        if (isArrayLike(value)) {
		          value.forEach(function (v, i) {
		            scope.set(env.next[name], '[' + i + ']', v);
		          });
		        } else {
		          scope.set(shared.next, '.' + name, value);
		        }
		      });
	
		      emitProfile(env, scope, args, true, true);[S_ELEMENTS, S_OFFSET, S_COUNT, S_INSTANCES, S_PRIMITIVE].forEach(function (opt) {
		        var variable = args.draw[opt];
		        if (!variable) {
		          return;
		        }
		        scope.set(shared.draw, '.' + opt, '' + variable.append(env, scope));
		      });
	
		      Object.keys(args.uniforms).forEach(function (opt) {
		        scope.set(shared.uniforms, '[' + stringStore.id(opt) + ']', args.uniforms[opt].append(env, scope));
		      });
	
		      Object.keys(args.attributes).forEach(function (name) {
		        var record = args.attributes[name].append(env, scope);
		        var scopeAttrib = env.scopeAttrib(name);
		        Object.keys(new AttributeRecord()).forEach(function (prop) {
		          scope.set(scopeAttrib, '.' + prop, record[prop]);
		        });
		      });
	
		      function saveShader(name) {
		        var shader = args.shader[name];
		        if (shader) {
		          scope.set(shared.shader, '.' + name, shader.append(env, scope));
		        }
		      }
		      saveShader(S_VERT);
		      saveShader(S_FRAG);
	
		      if (Object.keys(args.state).length > 0) {
		        scope(CURRENT_STATE, '.dirty=true;');
		        scope.exit(CURRENT_STATE, '.dirty=true;');
		      }
	
		      scope('a1(', env.shared.context, ',a0,', env.batchId, ');');
		    }
	
		    function isDynamicObject(object) {
		      if (typeof object !== 'object' || isArrayLike(object)) {
		        return;
		      }
		      var props = Object.keys(object);
		      for (var i = 0; i < props.length; ++i) {
		        if (dynamic.isDynamic(object[props[i]])) {
		          return true;
		        }
		      }
		      return false;
		    }
	
		    function splatObject(env, options, name) {
		      var object = options.static[name];
		      if (!object || !isDynamicObject(object)) {
		        return;
		      }
	
		      var globals = env.global;
		      var keys = Object.keys(object);
		      var thisDep = false;
		      var contextDep = false;
		      var propDep = false;
		      var objectRef = env.global.def('{}');
		      keys.forEach(function (key) {
		        var value = object[key];
		        if (dynamic.isDynamic(value)) {
		          if (typeof value === 'function') {
		            value = object[key] = dynamic.unbox(value);
		          }
		          var deps = createDynamicDecl(value, null);
		          thisDep = thisDep || deps.thisDep;
		          propDep = propDep || deps.propDep;
		          contextDep = contextDep || deps.contextDep;
		        } else {
		          globals(objectRef, '.', key, '=');
		          switch (typeof value) {
		            case 'number':
		              globals(value);
		              break;
		            case 'string':
		              globals('"', value, '"');
		              break;
		            case 'object':
		              if (Array.isArray(value)) {
		                globals('[', value.join(), ']');
		              }
		              break;
		            default:
		              globals(env.link(value));
		              break;
		          }
		          globals(';');
		        }
		      });
	
		      function appendBlock(env, block) {
		        keys.forEach(function (key) {
		          var value = object[key];
		          if (!dynamic.isDynamic(value)) {
		            return;
		          }
		          var ref = env.invoke(block, value);
		          block(objectRef, '.', key, '=', ref, ';');
		        });
		      }
	
		      options.dynamic[name] = new dynamic.DynamicVariable(DYN_THUNK, {
		        thisDep: thisDep,
		        contextDep: contextDep,
		        propDep: propDep,
		        ref: objectRef,
		        append: appendBlock
		      });
		      delete options.static[name];
		    }
	
		    // ===========================================================================
		    // ===========================================================================
		    // MAIN DRAW COMMAND
		    // ===========================================================================
		    // ===========================================================================
		    function compileCommand(options, attributes, uniforms, context, stats) {
		      var env = createREGLEnvironment();
	
		      // link stats, so that we can easily access it in the program.
		      env.stats = env.link(stats);
	
		      // splat options and attributes to allow for dynamic nested properties
		      Object.keys(attributes.static).forEach(function (key) {
		        splatObject(env, attributes, key);
		      });
		      NESTED_OPTIONS.forEach(function (name) {
		        splatObject(env, options, name);
		      });
	
		      var args = parseArguments(options, attributes, uniforms, context, env);
	
		      emitDrawProc(env, args);
		      emitScopeProc(env, args);
		      emitBatchProc(env, args);
	
		      return env.compile();
		    }
	
		    // ===========================================================================
		    // ===========================================================================
		    // POLL / REFRESH
		    // ===========================================================================
		    // ===========================================================================
		    return {
		      next: nextState,
		      current: currentState,
		      procs: function () {
		        var env = createREGLEnvironment();
		        var poll = env.proc('poll');
		        var refresh = env.proc('refresh');
		        var common = env.block();
		        poll(common);
		        refresh(common);
	
		        var shared = env.shared;
		        var GL = shared.gl;
		        var NEXT_STATE = shared.next;
		        var CURRENT_STATE = shared.current;
	
		        common(CURRENT_STATE, '.dirty=false;');
	
		        emitPollFramebuffer(env, poll);
		        emitPollFramebuffer(env, refresh, null, true);
	
		        // Refresh updates all attribute state changes
		        var extInstancing = gl.getExtension('angle_instanced_arrays');
		        var INSTANCING;
		        if (extInstancing) {
		          INSTANCING = env.link(extInstancing);
		        }
		        for (var i = 0; i < limits.maxAttributes; ++i) {
		          var BINDING = refresh.def(shared.attributes, '[', i, ']');
		          var ifte = env.cond(BINDING, '.buffer');
		          ifte.then(GL, '.enableVertexAttribArray(', i, ');', GL, '.bindBuffer(', GL_ARRAY_BUFFER$1, ',', BINDING, '.buffer.buffer);', GL, '.vertexAttribPointer(', i, ',', BINDING, '.size,', BINDING, '.type,', BINDING, '.normalized,', BINDING, '.stride,', BINDING, '.offset);').else(GL, '.disableVertexAttribArray(', i, ');', GL, '.vertexAttrib4f(', i, ',', BINDING, '.x,', BINDING, '.y,', BINDING, '.z,', BINDING, '.w);', BINDING, '.buffer=null;');
		          refresh(ifte);
		          if (extInstancing) {
		            refresh(INSTANCING, '.vertexAttribDivisorANGLE(', i, ',', BINDING, '.divisor);');
		          }
		        }
	
		        Object.keys(GL_FLAGS).forEach(function (flag) {
		          var cap = GL_FLAGS[flag];
		          var NEXT = common.def(NEXT_STATE, '.', flag);
		          var block = env.block();
		          block('if(', NEXT, '){', GL, '.enable(', cap, ')}else{', GL, '.disable(', cap, ')}', CURRENT_STATE, '.', flag, '=', NEXT, ';');
		          refresh(block);
		          poll('if(', NEXT, '!==', CURRENT_STATE, '.', flag, '){', block, '}');
		        });
	
		        Object.keys(GL_VARIABLES).forEach(function (name) {
		          var func = GL_VARIABLES[name];
		          var init = currentState[name];
		          var NEXT, CURRENT;
		          var block = env.block();
		          block(GL, '.', func, '(');
		          if (isArrayLike(init)) {
		            var n = init.length;
		            NEXT = env.global.def(NEXT_STATE, '.', name);
		            CURRENT = env.global.def(CURRENT_STATE, '.', name);
		            block(loop(n, function (i) {
		              return NEXT + '[' + i + ']';
		            }), ');', loop(n, function (i) {
		              return CURRENT + '[' + i + ']=' + NEXT + '[' + i + '];';
		            }).join(''));
		            poll('if(', loop(n, function (i) {
		              return NEXT + '[' + i + ']!==' + CURRENT + '[' + i + ']';
		            }).join('||'), '){', block, '}');
		          } else {
		            NEXT = common.def(NEXT_STATE, '.', name);
		            CURRENT = common.def(CURRENT_STATE, '.', name);
		            block(NEXT, ');', CURRENT_STATE, '.', name, '=', NEXT, ';');
		            poll('if(', NEXT, '!==', CURRENT, '){', block, '}');
		          }
		          refresh(block);
		        });
	
		        return env.compile();
		      }(),
		      compile: compileCommand
		    };
		  }
	
		  function stats() {
		    return {
		      bufferCount: 0,
		      elementsCount: 0,
		      framebufferCount: 0,
		      shaderCount: 0,
		      textureCount: 0,
		      cubeCount: 0,
		      renderbufferCount: 0,
	
		      maxTextureUnits: 0
		    };
		  }
	
		  var GL_QUERY_RESULT_EXT = 0x8866;
		  var GL_QUERY_RESULT_AVAILABLE_EXT = 0x8867;
		  var GL_TIME_ELAPSED_EXT = 0x88BF;
	
		  var createTimer = function (gl, extensions) {
		    var extTimer = extensions.ext_disjoint_timer_query;
	
		    if (!extTimer) {
		      return null;
		    }
	
		    // QUERY POOL BEGIN
		    var queryPool = [];
		    function allocQuery() {
		      return queryPool.pop() || extTimer.createQueryEXT();
		    }
		    function freeQuery(query) {
		      queryPool.push(query);
		    }
		    // QUERY POOL END
	
		    var pendingQueries = [];
		    function beginQuery(stats) {
		      var query = allocQuery();
		      extTimer.beginQueryEXT(GL_TIME_ELAPSED_EXT, query);
		      pendingQueries.push(query);
		      pushScopeStats(pendingQueries.length - 1, pendingQueries.length, stats);
		    }
	
		    function endQuery() {
		      extTimer.endQueryEXT(GL_TIME_ELAPSED_EXT);
		    }
	
		    //
		    // Pending stats pool.
		    //
		    function PendingStats() {
		      this.startQueryIndex = -1;
		      this.endQueryIndex = -1;
		      this.sum = 0;
		      this.stats = null;
		    }
		    var pendingStatsPool = [];
		    function allocPendingStats() {
		      return pendingStatsPool.pop() || new PendingStats();
		    }
		    function freePendingStats(pendingStats) {
		      pendingStatsPool.push(pendingStats);
		    }
		    // Pending stats pool end
	
		    var pendingStats = [];
		    function pushScopeStats(start, end, stats) {
		      var ps = allocPendingStats();
		      ps.startQueryIndex = start;
		      ps.endQueryIndex = end;
		      ps.sum = 0;
		      ps.stats = stats;
		      pendingStats.push(ps);
		    }
	
		    // we should call this at the beginning of the frame,
		    // in order to update gpuTime
		    var timeSum = [];
		    var queryPtr = [];
		    function update() {
		      var ptr, i;
	
		      var n = pendingQueries.length;
		      if (n === 0) {
		        return;
		      }
	
		      // Reserve space
		      queryPtr.length = Math.max(queryPtr.length, n + 1);
		      timeSum.length = Math.max(timeSum.length, n + 1);
		      timeSum[0] = 0;
		      queryPtr[0] = 0;
	
		      // Update all pending timer queries
		      var queryTime = 0;
		      ptr = 0;
		      for (i = 0; i < pendingQueries.length; ++i) {
		        var query = pendingQueries[i];
		        if (extTimer.getQueryObjectEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT)) {
		          queryTime += extTimer.getQueryObjectEXT(query, GL_QUERY_RESULT_EXT);
		          freeQuery(query);
		        } else {
		          pendingQueries[ptr++] = query;
		        }
		        timeSum[i + 1] = queryTime;
		        queryPtr[i + 1] = ptr;
		      }
		      pendingQueries.length = ptr;
	
		      // Update all pending stat queries
		      ptr = 0;
		      for (i = 0; i < pendingStats.length; ++i) {
		        var stats = pendingStats[i];
		        var start = stats.startQueryIndex;
		        var end = stats.endQueryIndex;
		        stats.sum += timeSum[end] - timeSum[start];
		        var startPtr = queryPtr[start];
		        var endPtr = queryPtr[end];
		        if (endPtr === startPtr) {
		          stats.stats.gpuTime += stats.sum / 1e6;
		          freePendingStats(stats);
		        } else {
		          stats.startQueryIndex = startPtr;
		          stats.endQueryIndex = endPtr;
		          pendingStats[ptr++] = stats;
		        }
		      }
		      pendingStats.length = ptr;
		    }
	
		    return {
		      beginQuery: beginQuery,
		      endQuery: endQuery,
		      pushScopeStats: pushScopeStats,
		      update: update,
		      getNumPendingQueries: function () {
		        return pendingQueries.length;
		      },
		      clear: function () {
		        queryPool.push.apply(queryPool, pendingQueries);
		        for (var i = 0; i < queryPool.length; i++) {
		          extTimer.deleteQueryEXT(queryPool[i]);
		        }
		        pendingQueries.length = 0;
		        queryPool.length = 0;
		      },
		      restore: function () {
		        pendingQueries.length = 0;
		        queryPool.length = 0;
		      }
		    };
		  };
	
		  var GL_COLOR_BUFFER_BIT = 16384;
		  var GL_DEPTH_BUFFER_BIT = 256;
		  var GL_STENCIL_BUFFER_BIT = 1024;
	
		  var GL_ARRAY_BUFFER = 34962;
	
		  var CONTEXT_LOST_EVENT = 'webglcontextlost';
		  var CONTEXT_RESTORED_EVENT = 'webglcontextrestored';
	
		  var DYN_PROP = 1;
		  var DYN_CONTEXT = 2;
		  var DYN_STATE = 3;
	
		  function find(haystack, needle) {
		    for (var i = 0; i < haystack.length; ++i) {
		      if (haystack[i] === needle) {
		        return i;
		      }
		    }
		    return -1;
		  }
	
		  function wrapREGL(args) {
		    var config = parseArgs(args);
		    if (!config) {
		      return null;
		    }
	
		    var gl = config.gl;
		    var glAttributes = gl.getContextAttributes();
		    var contextLost = gl.isContextLost();
	
		    var extensionState = createExtensionCache(gl, config);
		    if (!extensionState) {
		      return null;
		    }
	
		    var stringStore = createStringStore();
		    var stats$$1 = stats();
		    var extensions = extensionState.extensions;
		    var timer = createTimer(gl, extensions);
	
		    var START_TIME = clock();
		    var WIDTH = gl.drawingBufferWidth;
		    var HEIGHT = gl.drawingBufferHeight;
	
		    var contextState = {
		      tick: 0,
		      time: 0,
		      viewportWidth: WIDTH,
		      viewportHeight: HEIGHT,
		      framebufferWidth: WIDTH,
		      framebufferHeight: HEIGHT,
		      drawingBufferWidth: WIDTH,
		      drawingBufferHeight: HEIGHT,
		      pixelRatio: config.pixelRatio
		    };
		    var uniformState = {};
		    var drawState = {
		      elements: null,
		      primitive: 4, // GL_TRIANGLES
		      count: -1,
		      offset: 0,
		      instances: -1
		    };
	
		    var limits = wrapLimits(gl, extensions);
		    var bufferState = wrapBufferState(gl, stats$$1, config);
		    var elementState = wrapElementsState(gl, extensions, bufferState, stats$$1);
		    var attributeState = wrapAttributeState(gl, extensions, limits, bufferState, stringStore);
		    var shaderState = wrapShaderState(gl, stringStore, stats$$1, config);
		    var textureState = createTextureSet(gl, extensions, limits, function () {
		      core.procs.poll();
		    }, contextState, stats$$1, config);
		    var renderbufferState = wrapRenderbuffers(gl, extensions, limits, stats$$1, config);
		    var framebufferState = wrapFBOState(gl, extensions, limits, textureState, renderbufferState, stats$$1);
		    var core = reglCore(gl, stringStore, extensions, limits, bufferState, elementState, textureState, framebufferState, uniformState, attributeState, shaderState, drawState, contextState, timer, config);
		    var readPixels = wrapReadPixels(gl, framebufferState, core.procs.poll, contextState, glAttributes, extensions);
	
		    var nextState = core.next;
		    var canvas = gl.canvas;
	
		    var rafCallbacks = [];
		    var lossCallbacks = [];
		    var restoreCallbacks = [];
		    var destroyCallbacks = [config.onDestroy];
	
		    var activeRAF = null;
		    function handleRAF() {
		      if (rafCallbacks.length === 0) {
		        if (timer) {
		          timer.update();
		        }
		        activeRAF = null;
		        return;
		      }
	
		      // schedule next animation frame
		      activeRAF = raf.next(handleRAF);
	
		      // poll for changes
		      poll();
	
		      // fire a callback for all pending rafs
		      for (var i = rafCallbacks.length - 1; i >= 0; --i) {
		        var cb = rafCallbacks[i];
		        if (cb) {
		          cb(contextState, null, 0);
		        }
		      }
	
		      // flush all pending webgl calls
		      gl.flush();
	
		      // poll GPU timers *after* gl.flush so we don't delay command dispatch
		      if (timer) {
		        timer.update();
		      }
		    }
	
		    function startRAF() {
		      if (!activeRAF && rafCallbacks.length > 0) {
		        activeRAF = raf.next(handleRAF);
		      }
		    }
	
		    function stopRAF() {
		      if (activeRAF) {
		        raf.cancel(handleRAF);
		        activeRAF = null;
		      }
		    }
	
		    function handleContextLoss(event) {
		      event.preventDefault();
	
		      // set context lost flag
		      contextLost = true;
	
		      // pause request animation frame
		      stopRAF();
	
		      // lose context
		      lossCallbacks.forEach(function (cb) {
		        cb();
		      });
		    }
	
		    function handleContextRestored(event) {
		      // clear error code
		      gl.getError();
	
		      // clear context lost flag
		      contextLost = false;
	
		      // refresh state
		      extensionState.restore();
		      shaderState.restore();
		      bufferState.restore();
		      textureState.restore();
		      renderbufferState.restore();
		      framebufferState.restore();
		      if (timer) {
		        timer.restore();
		      }
	
		      // refresh state
		      core.procs.refresh();
	
		      // restart RAF
		      startRAF();
	
		      // restore context
		      restoreCallbacks.forEach(function (cb) {
		        cb();
		      });
		    }
	
		    if (canvas) {
		      canvas.addEventListener(CONTEXT_LOST_EVENT, handleContextLoss, false);
		      canvas.addEventListener(CONTEXT_RESTORED_EVENT, handleContextRestored, false);
		    }
	
		    function destroy() {
		      rafCallbacks.length = 0;
		      stopRAF();
	
		      if (canvas) {
		        canvas.removeEventListener(CONTEXT_LOST_EVENT, handleContextLoss);
		        canvas.removeEventListener(CONTEXT_RESTORED_EVENT, handleContextRestored);
		      }
	
		      shaderState.clear();
		      framebufferState.clear();
		      renderbufferState.clear();
		      textureState.clear();
		      elementState.clear();
		      bufferState.clear();
	
		      if (timer) {
		        timer.clear();
		      }
	
		      destroyCallbacks.forEach(function (cb) {
		        cb();
		      });
		    }
	
		    function compileProcedure(options) {
		      check$1(!!options, 'invalid args to regl({...})');
		      check$1.type(options, 'object', 'invalid args to regl({...})');
	
		      function flattenNestedOptions(options) {
		        var result = extend({}, options);
		        delete result.uniforms;
		        delete result.attributes;
		        delete result.context;
	
		        if ('stencil' in result && result.stencil.op) {
		          result.stencil.opBack = result.stencil.opFront = result.stencil.op;
		          delete result.stencil.op;
		        }
	
		        function merge(name) {
		          if (name in result) {
		            var child = result[name];
		            delete result[name];
		            Object.keys(child).forEach(function (prop) {
		              result[name + '.' + prop] = child[prop];
		            });
		          }
		        }
		        merge('blend');
		        merge('depth');
		        merge('cull');
		        merge('stencil');
		        merge('polygonOffset');
		        merge('scissor');
		        merge('sample');
	
		        return result;
		      }
	
		      function separateDynamic(object) {
		        var staticItems = {};
		        var dynamicItems = {};
		        Object.keys(object).forEach(function (option) {
		          var value = object[option];
		          if (dynamic.isDynamic(value)) {
		            dynamicItems[option] = dynamic.unbox(value, option);
		          } else {
		            staticItems[option] = value;
		          }
		        });
		        return {
		          dynamic: dynamicItems,
		          static: staticItems
		        };
		      }
	
		      // Treat context variables separate from other dynamic variables
		      var context = separateDynamic(options.context || {});
		      var uniforms = separateDynamic(options.uniforms || {});
		      var attributes = separateDynamic(options.attributes || {});
		      var opts = separateDynamic(flattenNestedOptions(options));
	
		      var stats$$1 = {
		        gpuTime: 0.0,
		        cpuTime: 0.0,
		        count: 0
		      };
	
		      var compiled = core.compile(opts, attributes, uniforms, context, stats$$1);
	
		      var draw = compiled.draw;
		      var batch = compiled.batch;
		      var scope = compiled.scope;
	
		      // FIXME: we should modify code generation for batch commands so this
		      // isn't necessary
		      var EMPTY_ARRAY = [];
		      function reserve(count) {
		        while (EMPTY_ARRAY.length < count) {
		          EMPTY_ARRAY.push(null);
		        }
		        return EMPTY_ARRAY;
		      }
	
		      function REGLCommand(args, body) {
		        var i;
		        if (contextLost) {
		          check$1.raise('context lost');
		        }
		        if (typeof args === 'function') {
		          return scope.call(this, null, args, 0);
		        } else if (typeof body === 'function') {
		          if (typeof args === 'number') {
		            for (i = 0; i < args; ++i) {
		              scope.call(this, null, body, i);
		            }
		            return;
		          } else if (Array.isArray(args)) {
		            for (i = 0; i < args.length; ++i) {
		              scope.call(this, args[i], body, i);
		            }
		            return;
		          } else {
		            return scope.call(this, args, body, 0);
		          }
		        } else if (typeof args === 'number') {
		          if (args > 0) {
		            return batch.call(this, reserve(args | 0), args | 0);
		          }
		        } else if (Array.isArray(args)) {
		          if (args.length) {
		            return batch.call(this, args, args.length);
		          }
		        } else {
		          return draw.call(this, args);
		        }
		      }
	
		      return extend(REGLCommand, {
		        stats: stats$$1
		      });
		    }
	
		    var setFBO = framebufferState.setFBO = compileProcedure({
		      framebuffer: dynamic.define.call(null, DYN_PROP, 'framebuffer')
		    });
	
		    function clearImpl(_, options) {
		      var clearFlags = 0;
		      core.procs.poll();
	
		      var c = options.color;
		      if (c) {
		        gl.clearColor(+c[0] || 0, +c[1] || 0, +c[2] || 0, +c[3] || 0);
		        clearFlags |= GL_COLOR_BUFFER_BIT;
		      }
		      if ('depth' in options) {
		        gl.clearDepth(+options.depth);
		        clearFlags |= GL_DEPTH_BUFFER_BIT;
		      }
		      if ('stencil' in options) {
		        gl.clearStencil(options.stencil | 0);
		        clearFlags |= GL_STENCIL_BUFFER_BIT;
		      }
	
		      check$1(!!clearFlags, 'called regl.clear with no buffer specified');
		      gl.clear(clearFlags);
		    }
	
		    function clear(options) {
		      check$1(typeof options === 'object' && options, 'regl.clear() takes an object as input');
		      if ('framebuffer' in options) {
		        if (options.framebuffer && options.framebuffer_reglType === 'framebufferCube') {
		          for (var i = 0; i < 6; ++i) {
		            setFBO(extend({
		              framebuffer: options.framebuffer.faces[i]
		            }, options), clearImpl);
		          }
		        } else {
		          setFBO(options, clearImpl);
		        }
		      } else {
		        clearImpl(null, options);
		      }
		    }
	
		    function frame(cb) {
		      check$1.type(cb, 'function', 'regl.frame() callback must be a function');
		      rafCallbacks.push(cb);
	
		      function cancel() {
		        // FIXME:  should we check something other than equals cb here?
		        // what if a user calls frame twice with the same callback...
		        //
		        var i = find(rafCallbacks, cb);
		        check$1(i >= 0, 'cannot cancel a frame twice');
		        function pendingCancel() {
		          var index = find(rafCallbacks, pendingCancel);
		          rafCallbacks[index] = rafCallbacks[rafCallbacks.length - 1];
		          rafCallbacks.length -= 1;
		          if (rafCallbacks.length <= 0) {
		            stopRAF();
		          }
		        }
		        rafCallbacks[i] = pendingCancel;
		      }
	
		      startRAF();
	
		      return {
		        cancel: cancel
		      };
		    }
	
		    // poll viewport
		    function pollViewport() {
		      var viewport = nextState.viewport;
		      var scissorBox = nextState.scissor_box;
		      viewport[0] = viewport[1] = scissorBox[0] = scissorBox[1] = 0;
		      contextState.viewportWidth = contextState.framebufferWidth = contextState.drawingBufferWidth = viewport[2] = scissorBox[2] = gl.drawingBufferWidth;
		      contextState.viewportHeight = contextState.framebufferHeight = contextState.drawingBufferHeight = viewport[3] = scissorBox[3] = gl.drawingBufferHeight;
		    }
	
		    function poll() {
		      contextState.tick += 1;
		      contextState.time = now();
		      pollViewport();
		      core.procs.poll();
		    }
	
		    function refresh() {
		      pollViewport();
		      core.procs.refresh();
		      if (timer) {
		        timer.update();
		      }
		    }
	
		    function now() {
		      return (clock() - START_TIME) / 1000.0;
		    }
	
		    refresh();
	
		    function addListener(event, callback) {
		      check$1.type(callback, 'function', 'listener callback must be a function');
	
		      var callbacks;
		      switch (event) {
		        case 'frame':
		          return frame(callback);
		        case 'lost':
		          callbacks = lossCallbacks;
		          break;
		        case 'restore':
		          callbacks = restoreCallbacks;
		          break;
		        case 'destroy':
		          callbacks = destroyCallbacks;
		          break;
		        default:
		          check$1.raise('invalid event, must be one of frame,lost,restore,destroy');
		      }
	
		      callbacks.push(callback);
		      return {
		        cancel: function () {
		          for (var i = 0; i < callbacks.length; ++i) {
		            if (callbacks[i] === callback) {
		              callbacks[i] = callbacks[callbacks.length - 1];
		              callbacks.pop();
		              return;
		            }
		          }
		        }
		      };
		    }
	
		    var regl = extend(compileProcedure, {
		      // Clear current FBO
		      clear: clear,
	
		      // Short cuts for dynamic variables
		      prop: dynamic.define.bind(null, DYN_PROP),
		      context: dynamic.define.bind(null, DYN_CONTEXT),
		      this: dynamic.define.bind(null, DYN_STATE),
	
		      // executes an empty draw command
		      draw: compileProcedure({}),
	
		      // Resources
		      buffer: function (options) {
		        return bufferState.create(options, GL_ARRAY_BUFFER, false, false);
		      },
		      elements: function (options) {
		        return elementState.create(options, false);
		      },
		      texture: textureState.create2D,
		      cube: textureState.createCube,
		      renderbuffer: renderbufferState.create,
		      framebuffer: framebufferState.create,
		      framebufferCube: framebufferState.createCube,
	
		      // Expose context attributes
		      attributes: glAttributes,
	
		      // Frame rendering
		      frame: frame,
		      on: addListener,
	
		      // System limits
		      limits: limits,
		      hasExtension: function (name) {
		        return limits.extensions.indexOf(name.toLowerCase()) >= 0;
		      },
	
		      // Read pixels
		      read: readPixels,
	
		      // Destroy regl and all associated resources
		      destroy: destroy,
	
		      // Direct GL state manipulation
		      _gl: gl,
		      _refresh: refresh,
	
		      poll: function () {
		        poll();
		        if (timer) {
		          timer.update();
		        }
		      },
	
		      // Current time
		      now: now,
	
		      // regl Statistics Information
		      stats: stats$$1
		    });
	
		    config.onDone(null, regl);
	
		    return regl;
		  }
	
		  return wrapREGL;
		});
		//# sourceMappingURL=regl.js.map
	
	/***/ })
	/******/ ]);
	//# sourceMappingURL=clustergrammer2-alpha.node.js.map
	/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7).Buffer))

/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {

	/* WEBPACK VAR INJECTION */(function(global) {/*!
	 * The buffer module from node.js, for the browser.
	 *
	 * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
	 * @license  MIT
	 */
	/* eslint-disable no-proto */
	
	'use strict'
	
	var base64 = __webpack_require__(8)
	var ieee754 = __webpack_require__(9)
	var isArray = __webpack_require__(10)
	
	exports.Buffer = Buffer
	exports.SlowBuffer = SlowBuffer
	exports.INSPECT_MAX_BYTES = 50
	
	/**
	 * If `Buffer.TYPED_ARRAY_SUPPORT`:
	 *   === true    Use Uint8Array implementation (fastest)
	 *   === false   Use Object implementation (most compatible, even IE6)
	 *
	 * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
	 * Opera 11.6+, iOS 4.2+.
	 *
	 * Due to various browser bugs, sometimes the Object implementation will be used even
	 * when the browser supports typed arrays.
	 *
	 * Note:
	 *
	 *   - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
	 *     See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
	 *
	 *   - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
	 *
	 *   - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
	 *     incorrect length in some situations.
	
	 * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they
	 * get the Object implementation, which is slower but behaves correctly.
	 */
	Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined
	  ? global.TYPED_ARRAY_SUPPORT
	  : typedArraySupport()
	
	/*
	 * Export kMaxLength after typed array support is determined.
	 */
	exports.kMaxLength = kMaxLength()
	
	function typedArraySupport () {
	  try {
	    var arr = new Uint8Array(1)
	    arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}
	    return arr.foo() === 42 && // typed array instances can be augmented
	        typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
	        arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
	  } catch (e) {
	    return false
	  }
	}
	
	function kMaxLength () {
	  return Buffer.TYPED_ARRAY_SUPPORT
	    ? 0x7fffffff
	    : 0x3fffffff
	}
	
	function createBuffer (that, length) {
	  if (kMaxLength() < length) {
	    throw new RangeError('Invalid typed array length')
	  }
	  if (Buffer.TYPED_ARRAY_SUPPORT) {
	    // Return an augmented `Uint8Array` instance, for best performance
	    that = new Uint8Array(length)
	    that.__proto__ = Buffer.prototype
	  } else {
	    // Fallback: Return an object instance of the Buffer class
	    if (that === null) {
	      that = new Buffer(length)
	    }
	    that.length = length
	  }
	
	  return that
	}
	
	/**
	 * The Buffer constructor returns instances of `Uint8Array` that have their
	 * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
	 * `Uint8Array`, so the returned instances will have all the node `Buffer` methods
	 * and the `Uint8Array` methods. Square bracket notation works as expected -- it
	 * returns a single octet.
	 *
	 * The `Uint8Array` prototype remains unmodified.
	 */
	
	function Buffer (arg, encodingOrOffset, length) {
	  if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {
	    return new Buffer(arg, encodingOrOffset, length)
	  }
	
	  // Common case.
	  if (typeof arg === 'number') {
	    if (typeof encodingOrOffset === 'string') {
	      throw new Error(
	        'If encoding is specified then the first argument must be a string'
	      )
	    }
	    return allocUnsafe(this, arg)
	  }
	  return from(this, arg, encodingOrOffset, length)
	}
	
	Buffer.poolSize = 8192 // not used by this implementation
	
	// TODO: Legacy, not needed anymore. Remove in next major version.
	Buffer._augment = function (arr) {
	  arr.__proto__ = Buffer.prototype
	  return arr
	}
	
	function from (that, value, encodingOrOffset, length) {
	  if (typeof value === 'number') {
	    throw new TypeError('"value" argument must not be a number')
	  }
	
	  if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
	    return fromArrayBuffer(that, value, encodingOrOffset, length)
	  }
	
	  if (typeof value === 'string') {
	    return fromString(that, value, encodingOrOffset)
	  }
	
	  return fromObject(that, value)
	}
	
	/**
	 * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
	 * if value is a number.
	 * Buffer.from(str[, encoding])
	 * Buffer.from(array)
	 * Buffer.from(buffer)
	 * Buffer.from(arrayBuffer[, byteOffset[, length]])
	 **/
	Buffer.from = function (value, encodingOrOffset, length) {
	  return from(null, value, encodingOrOffset, length)
	}
	
	if (Buffer.TYPED_ARRAY_SUPPORT) {
	  Buffer.prototype.__proto__ = Uint8Array.prototype
	  Buffer.__proto__ = Uint8Array
	  if (typeof Symbol !== 'undefined' && Symbol.species &&
	      Buffer[Symbol.species] === Buffer) {
	    // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
	    Object.defineProperty(Buffer, Symbol.species, {
	      value: null,
	      configurable: true
	    })
	  }
	}
	
	function assertSize (size) {
	  if (typeof size !== 'number') {
	    throw new TypeError('"size" argument must be a number')
	  } else if (size < 0) {
	    throw new RangeError('"size" argument must not be negative')
	  }
	}
	
	function alloc (that, size, fill, encoding) {
	  assertSize(size)
	  if (size <= 0) {
	    return createBuffer(that, size)
	  }
	  if (fill !== undefined) {
	    // Only pay attention to encoding if it's a string. This
	    // prevents accidentally sending in a number that would
	    // be interpretted as a start offset.
	    return typeof encoding === 'string'
	      ? createBuffer(that, size).fill(fill, encoding)
	      : createBuffer(that, size).fill(fill)
	  }
	  return createBuffer(that, size)
	}
	
	/**
	 * Creates a new filled Buffer instance.
	 * alloc(size[, fill[, encoding]])
	 **/
	Buffer.alloc = function (size, fill, encoding) {
	  return alloc(null, size, fill, encoding)
	}
	
	function allocUnsafe (that, size) {
	  assertSize(size)
	  that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)
	  if (!Buffer.TYPED_ARRAY_SUPPORT) {
	    for (var i = 0; i < size; ++i) {
	      that[i] = 0
	    }
	  }
	  return that
	}
	
	/**
	 * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
	 * */
	Buffer.allocUnsafe = function (size) {
	  return allocUnsafe(null, size)
	}
	/**
	 * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
	 */
	Buffer.allocUnsafeSlow = function (size) {
	  return allocUnsafe(null, size)
	}
	
	function fromString (that, string, encoding) {
	  if (typeof encoding !== 'string' || encoding === '') {
	    encoding = 'utf8'
	  }
	
	  if (!Buffer.isEncoding(encoding)) {
	    throw new TypeError('"encoding" must be a valid string encoding')
	  }
	
	  var length = byteLength(string, encoding) | 0
	  that = createBuffer(that, length)
	
	  var actual = that.write(string, encoding)
	
	  if (actual !== length) {
	    // Writing a hex string, for example, that contains invalid characters will
	    // cause everything after the first invalid character to be ignored. (e.g.
	    // 'abxxcd' will be treated as 'ab')
	    that = that.slice(0, actual)
	  }
	
	  return that
	}
	
	function fromArrayLike (that, array) {
	  var length = array.length < 0 ? 0 : checked(array.length) | 0
	  that = createBuffer(that, length)
	  for (var i = 0; i < length; i += 1) {
	    that[i] = array[i] & 255
	  }
	  return that
	}
	
	function fromArrayBuffer (that, array, byteOffset, length) {
	  array.byteLength // this throws if `array` is not a valid ArrayBuffer
	
	  if (byteOffset < 0 || array.byteLength < byteOffset) {
	    throw new RangeError('\'offset\' is out of bounds')
	  }
	
	  if (array.byteLength < byteOffset + (length || 0)) {
	    throw new RangeError('\'length\' is out of bounds')
	  }
	
	  if (byteOffset === undefined && length === undefined) {
	    array = new Uint8Array(array)
	  } else if (length === undefined) {
	    array = new Uint8Array(array, byteOffset)
	  } else {
	    array = new Uint8Array(array, byteOffset, length)
	  }
	
	  if (Buffer.TYPED_ARRAY_SUPPORT) {
	    // Return an augmented `Uint8Array` instance, for best performance
	    that = array
	    that.__proto__ = Buffer.prototype
	  } else {
	    // Fallback: Return an object instance of the Buffer class
	    that = fromArrayLike(that, array)
	  }
	  return that
	}
	
	function fromObject (that, obj) {
	  if (Buffer.isBuffer(obj)) {
	    var len = checked(obj.length) | 0
	    that = createBuffer(that, len)
	
	    if (that.length === 0) {
	      return that
	    }
	
	    obj.copy(that, 0, 0, len)
	    return that
	  }
	
	  if (obj) {
	    if ((typeof ArrayBuffer !== 'undefined' &&
	        obj.buffer instanceof ArrayBuffer) || 'length' in obj) {
	      if (typeof obj.length !== 'number' || isnan(obj.length)) {
	        return createBuffer(that, 0)
	      }
	      return fromArrayLike(that, obj)
	    }
	
	    if (obj.type === 'Buffer' && isArray(obj.data)) {
	      return fromArrayLike(that, obj.data)
	    }
	  }
	
	  throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')
	}
	
	function checked (length) {
	  // Note: cannot use `length < kMaxLength()` here because that fails when
	  // length is NaN (which is otherwise coerced to zero.)
	  if (length >= kMaxLength()) {
	    throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
	                         'size: 0x' + kMaxLength().toString(16) + ' bytes')
	  }
	  return length | 0
	}
	
	function SlowBuffer (length) {
	  if (+length != length) { // eslint-disable-line eqeqeq
	    length = 0
	  }
	  return Buffer.alloc(+length)
	}
	
	Buffer.isBuffer = function isBuffer (b) {
	  return !!(b != null && b._isBuffer)
	}
	
	Buffer.compare = function compare (a, b) {
	  if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
	    throw new TypeError('Arguments must be Buffers')
	  }
	
	  if (a === b) return 0
	
	  var x = a.length
	  var y = b.length
	
	  for (var i = 0, len = Math.min(x, y); i < len; ++i) {
	    if (a[i] !== b[i]) {
	      x = a[i]
	      y = b[i]
	      break
	    }
	  }
	
	  if (x < y) return -1
	  if (y < x) return 1
	  return 0
	}
	
	Buffer.isEncoding = function isEncoding (encoding) {
	  switch (String(encoding).toLowerCase()) {
	    case 'hex':
	    case 'utf8':
	    case 'utf-8':
	    case 'ascii':
	    case 'latin1':
	    case 'binary':
	    case 'base64':
	    case 'ucs2':
	    case 'ucs-2':
	    case 'utf16le':
	    case 'utf-16le':
	      return true
	    default:
	      return false
	  }
	}
	
	Buffer.concat = function concat (list, length) {
	  if (!isArray(list)) {
	    throw new TypeError('"list" argument must be an Array of Buffers')
	  }
	
	  if (list.length === 0) {
	    return Buffer.alloc(0)
	  }
	
	  var i
	  if (length === undefined) {
	    length = 0
	    for (i = 0; i < list.length; ++i) {
	      length += list[i].length
	    }
	  }
	
	  var buffer = Buffer.allocUnsafe(length)
	  var pos = 0
	  for (i = 0; i < list.length; ++i) {
	    var buf = list[i]
	    if (!Buffer.isBuffer(buf)) {
	      throw new TypeError('"list" argument must be an Array of Buffers')
	    }
	    buf.copy(buffer, pos)
	    pos += buf.length
	  }
	  return buffer
	}
	
	function byteLength (string, encoding) {
	  if (Buffer.isBuffer(string)) {
	    return string.length
	  }
	  if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&
	      (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {
	    return string.byteLength
	  }
	  if (typeof string !== 'string') {
	    string = '' + string
	  }
	
	  var len = string.length
	  if (len === 0) return 0
	
	  // Use a for loop to avoid recursion
	  var loweredCase = false
	  for (;;) {
	    switch (encoding) {
	      case 'ascii':
	      case 'latin1':
	      case 'binary':
	        return len
	      case 'utf8':
	      case 'utf-8':
	      case undefined:
	        return utf8ToBytes(string).length
	      case 'ucs2':
	      case 'ucs-2':
	      case 'utf16le':
	      case 'utf-16le':
	        return len * 2
	      case 'hex':
	        return len >>> 1
	      case 'base64':
	        return base64ToBytes(string).length
	      default:
	        if (loweredCase) return utf8ToBytes(string).length // assume utf8
	        encoding = ('' + encoding).toLowerCase()
	        loweredCase = true
	    }
	  }
	}
	Buffer.byteLength = byteLength
	
	function slowToString (encoding, start, end) {
	  var loweredCase = false
	
	  // No need to verify that "this.length <= MAX_UINT32" since it's a read-only
	  // property of a typed array.
	
	  // This behaves neither like String nor Uint8Array in that we set start/end
	  // to their upper/lower bounds if the value passed is out of range.
	  // undefined is handled specially as per ECMA-262 6th Edition,
	  // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
	  if (start === undefined || start < 0) {
	    start = 0
	  }
	  // Return early if start > this.length. Done here to prevent potential uint32
	  // coercion fail below.
	  if (start > this.length) {
	    return ''
	  }
	
	  if (end === undefined || end > this.length) {
	    end = this.length
	  }
	
	  if (end <= 0) {
	    return ''
	  }
	
	  // Force coersion to uint32. This will also coerce falsey/NaN values to 0.
	  end >>>= 0
	  start >>>= 0
	
	  if (end <= start) {
	    return ''
	  }
	
	  if (!encoding) encoding = 'utf8'
	
	  while (true) {
	    switch (encoding) {
	      case 'hex':
	        return hexSlice(this, start, end)
	
	      case 'utf8':
	      case 'utf-8':
	        return utf8Slice(this, start, end)
	
	      case 'ascii':
	        return asciiSlice(this, start, end)
	
	      case 'latin1':
	      case 'binary':
	        return latin1Slice(this, start, end)
	
	      case 'base64':
	        return base64Slice(this, start, end)
	
	      case 'ucs2':
	      case 'ucs-2':
	      case 'utf16le':
	      case 'utf-16le':
	        return utf16leSlice(this, start, end)
	
	      default:
	        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
	        encoding = (encoding + '').toLowerCase()
	        loweredCase = true
	    }
	  }
	}
	
	// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect
	// Buffer instances.
	Buffer.prototype._isBuffer = true
	
	function swap (b, n, m) {
	  var i = b[n]
	  b[n] = b[m]
	  b[m] = i
	}
	
	Buffer.prototype.swap16 = function swap16 () {
	  var len = this.length
	  if (len % 2 !== 0) {
	    throw new RangeError('Buffer size must be a multiple of 16-bits')
	  }
	  for (var i = 0; i < len; i += 2) {
	    swap(this, i, i + 1)
	  }
	  return this
	}
	
	Buffer.prototype.swap32 = function swap32 () {
	  var len = this.length
	  if (len % 4 !== 0) {
	    throw new RangeError('Buffer size must be a multiple of 32-bits')
	  }
	  for (var i = 0; i < len; i += 4) {
	    swap(this, i, i + 3)
	    swap(this, i + 1, i + 2)
	  }
	  return this
	}
	
	Buffer.prototype.swap64 = function swap64 () {
	  var len = this.length
	  if (len % 8 !== 0) {
	    throw new RangeError('Buffer size must be a multiple of 64-bits')
	  }
	  for (var i = 0; i < len; i += 8) {
	    swap(this, i, i + 7)
	    swap(this, i + 1, i + 6)
	    swap(this, i + 2, i + 5)
	    swap(this, i + 3, i + 4)
	  }
	  return this
	}
	
	Buffer.prototype.toString = function toString () {
	  var length = this.length | 0
	  if (length === 0) return ''
	  if (arguments.length === 0) return utf8Slice(this, 0, length)
	  return slowToString.apply(this, arguments)
	}
	
	Buffer.prototype.equals = function equals (b) {
	  if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
	  if (this === b) return true
	  return Buffer.compare(this, b) === 0
	}
	
	Buffer.prototype.inspect = function inspect () {
	  var str = ''
	  var max = exports.INSPECT_MAX_BYTES
	  if (this.length > 0) {
	    str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')
	    if (this.length > max) str += ' ... '
	  }
	  return '<Buffer ' + str + '>'
	}
	
	Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
	  if (!Buffer.isBuffer(target)) {
	    throw new TypeError('Argument must be a Buffer')
	  }
	
	  if (start === undefined) {
	    start = 0
	  }
	  if (end === undefined) {
	    end = target ? target.length : 0
	  }
	  if (thisStart === undefined) {
	    thisStart = 0
	  }
	  if (thisEnd === undefined) {
	    thisEnd = this.length
	  }
	
	  if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
	    throw new RangeError('out of range index')
	  }
	
	  if (thisStart >= thisEnd && start >= end) {
	    return 0
	  }
	  if (thisStart >= thisEnd) {
	    return -1
	  }
	  if (start >= end) {
	    return 1
	  }
	
	  start >>>= 0
	  end >>>= 0
	  thisStart >>>= 0
	  thisEnd >>>= 0
	
	  if (this === target) return 0
	
	  var x = thisEnd - thisStart
	  var y = end - start
	  var len = Math.min(x, y)
	
	  var thisCopy = this.slice(thisStart, thisEnd)
	  var targetCopy = target.slice(start, end)
	
	  for (var i = 0; i < len; ++i) {
	    if (thisCopy[i] !== targetCopy[i]) {
	      x = thisCopy[i]
	      y = targetCopy[i]
	      break
	    }
	  }
	
	  if (x < y) return -1
	  if (y < x) return 1
	  return 0
	}
	
	// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
	// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
	//
	// Arguments:
	// - buffer - a Buffer to search
	// - val - a string, Buffer, or number
	// - byteOffset - an index into `buffer`; will be clamped to an int32
	// - encoding - an optional encoding, relevant is val is a string
	// - dir - true for indexOf, false for lastIndexOf
	function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
	  // Empty buffer means no match
	  if (buffer.length === 0) return -1
	
	  // Normalize byteOffset
	  if (typeof byteOffset === 'string') {
	    encoding = byteOffset
	    byteOffset = 0
	  } else if (byteOffset > 0x7fffffff) {
	    byteOffset = 0x7fffffff
	  } else if (byteOffset < -0x80000000) {
	    byteOffset = -0x80000000
	  }
	  byteOffset = +byteOffset  // Coerce to Number.
	  if (isNaN(byteOffset)) {
	    // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
	    byteOffset = dir ? 0 : (buffer.length - 1)
	  }
	
	  // Normalize byteOffset: negative offsets start from the end of the buffer
	  if (byteOffset < 0) byteOffset = buffer.length + byteOffset
	  if (byteOffset >= buffer.length) {
	    if (dir) return -1
	    else byteOffset = buffer.length - 1
	  } else if (byteOffset < 0) {
	    if (dir) byteOffset = 0
	    else return -1
	  }
	
	  // Normalize val
	  if (typeof val === 'string') {
	    val = Buffer.from(val, encoding)
	  }
	
	  // Finally, search either indexOf (if dir is true) or lastIndexOf
	  if (Buffer.isBuffer(val)) {
	    // Special case: looking for empty string/buffer always fails
	    if (val.length === 0) {
	      return -1
	    }
	    return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
	  } else if (typeof val === 'number') {
	    val = val & 0xFF // Search for a byte value [0-255]
	    if (Buffer.TYPED_ARRAY_SUPPORT &&
	        typeof Uint8Array.prototype.indexOf === 'function') {
	      if (dir) {
	        return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
	      } else {
	        return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
	      }
	    }
	    return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)
	  }
	
	  throw new TypeError('val must be string, number or Buffer')
	}
	
	function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
	  var indexSize = 1
	  var arrLength = arr.length
	  var valLength = val.length
	
	  if (encoding !== undefined) {
	    encoding = String(encoding).toLowerCase()
	    if (encoding === 'ucs2' || encoding === 'ucs-2' ||
	        encoding === 'utf16le' || encoding === 'utf-16le') {
	      if (arr.length < 2 || val.length < 2) {
	        return -1
	      }
	      indexSize = 2
	      arrLength /= 2
	      valLength /= 2
	      byteOffset /= 2
	    }
	  }
	
	  function read (buf, i) {
	    if (indexSize === 1) {
	      return buf[i]
	    } else {
	      return buf.readUInt16BE(i * indexSize)
	    }
	  }
	
	  var i
	  if (dir) {
	    var foundIndex = -1
	    for (i = byteOffset; i < arrLength; i++) {
	      if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
	        if (foundIndex === -1) foundIndex = i
	        if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
	      } else {
	        if (foundIndex !== -1) i -= i - foundIndex
	        foundIndex = -1
	      }
	    }
	  } else {
	    if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength
	    for (i = byteOffset; i >= 0; i--) {
	      var found = true
	      for (var j = 0; j < valLength; j++) {
	        if (read(arr, i + j) !== read(val, j)) {
	          found = false
	          break
	        }
	      }
	      if (found) return i
	    }
	  }
	
	  return -1
	}
	
	Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
	  return this.indexOf(val, byteOffset, encoding) !== -1
	}
	
	Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
	  return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
	}
	
	Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
	  return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
	}
	
	function hexWrite (buf, string, offset, length) {
	  offset = Number(offset) || 0
	  var remaining = buf.length - offset
	  if (!length) {
	    length = remaining
	  } else {
	    length = Number(length)
	    if (length > remaining) {
	      length = remaining
	    }
	  }
	
	  // must be an even number of digits
	  var strLen = string.length
	  if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')
	
	  if (length > strLen / 2) {
	    length = strLen / 2
	  }
	  for (var i = 0; i < length; ++i) {
	    var parsed = parseInt(string.substr(i * 2, 2), 16)
	    if (isNaN(parsed)) return i
	    buf[offset + i] = parsed
	  }
	  return i
	}
	
	function utf8Write (buf, string, offset, length) {
	  return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
	}
	
	function asciiWrite (buf, string, offset, length) {
	  return blitBuffer(asciiToBytes(string), buf, offset, length)
	}
	
	function latin1Write (buf, string, offset, length) {
	  return asciiWrite(buf, string, offset, length)
	}
	
	function base64Write (buf, string, offset, length) {
	  return blitBuffer(base64ToBytes(string), buf, offset, length)
	}
	
	function ucs2Write (buf, string, offset, length) {
	  return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
	}
	
	Buffer.prototype.write = function write (string, offset, length, encoding) {
	  // Buffer#write(string)
	  if (offset === undefined) {
	    encoding = 'utf8'
	    length = this.length
	    offset = 0
	  // Buffer#write(string, encoding)
	  } else if (length === undefined && typeof offset === 'string') {
	    encoding = offset
	    length = this.length
	    offset = 0
	  // Buffer#write(string, offset[, length][, encoding])
	  } else if (isFinite(offset)) {
	    offset = offset | 0
	    if (isFinite(length)) {
	      length = length | 0
	      if (encoding === undefined) encoding = 'utf8'
	    } else {
	      encoding = length
	      length = undefined
	    }
	  // legacy write(string, encoding, offset, length) - remove in v0.13
	  } else {
	    throw new Error(
	      'Buffer.write(string, encoding, offset[, length]) is no longer supported'
	    )
	  }
	
	  var remaining = this.length - offset
	  if (length === undefined || length > remaining) length = remaining
	
	  if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
	    throw new RangeError('Attempt to write outside buffer bounds')
	  }
	
	  if (!encoding) encoding = 'utf8'
	
	  var loweredCase = false
	  for (;;) {
	    switch (encoding) {
	      case 'hex':
	        return hexWrite(this, string, offset, length)
	
	      case 'utf8':
	      case 'utf-8':
	        return utf8Write(this, string, offset, length)
	
	      case 'ascii':
	        return asciiWrite(this, string, offset, length)
	
	      case 'latin1':
	      case 'binary':
	        return latin1Write(this, string, offset, length)
	
	      case 'base64':
	        // Warning: maxLength not taken into account in base64Write
	        return base64Write(this, string, offset, length)
	
	      case 'ucs2':
	      case 'ucs-2':
	      case 'utf16le':
	      case 'utf-16le':
	        return ucs2Write(this, string, offset, length)
	
	      default:
	        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
	        encoding = ('' + encoding).toLowerCase()
	        loweredCase = true
	    }
	  }
	}
	
	Buffer.prototype.toJSON = function toJSON () {
	  return {
	    type: 'Buffer',
	    data: Array.prototype.slice.call(this._arr || this, 0)
	  }
	}
	
	function base64Slice (buf, start, end) {
	  if (start === 0 && end === buf.length) {
	    return base64.fromByteArray(buf)
	  } else {
	    return base64.fromByteArray(buf.slice(start, end))
	  }
	}
	
	function utf8Slice (buf, start, end) {
	  end = Math.min(buf.length, end)
	  var res = []
	
	  var i = start
	  while (i < end) {
	    var firstByte = buf[i]
	    var codePoint = null
	    var bytesPerSequence = (firstByte > 0xEF) ? 4
	      : (firstByte > 0xDF) ? 3
	      : (firstByte > 0xBF) ? 2
	      : 1
	
	    if (i + bytesPerSequence <= end) {
	      var secondByte, thirdByte, fourthByte, tempCodePoint
	
	      switch (bytesPerSequence) {
	        case 1:
	          if (firstByte < 0x80) {
	            codePoint = firstByte
	          }
	          break
	        case 2:
	          secondByte = buf[i + 1]
	          if ((secondByte & 0xC0) === 0x80) {
	            tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
	            if (tempCodePoint > 0x7F) {
	              codePoint = tempCodePoint
	            }
	          }
	          break
	        case 3:
	          secondByte = buf[i + 1]
	          thirdByte = buf[i + 2]
	          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
	            tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
	            if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
	              codePoint = tempCodePoint
	            }
	          }
	          break
	        case 4:
	          secondByte = buf[i + 1]
	          thirdByte = buf[i + 2]
	          fourthByte = buf[i + 3]
	          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
	            tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
	            if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
	              codePoint = tempCodePoint
	            }
	          }
	      }
	    }
	
	    if (codePoint === null) {
	      // we did not generate a valid codePoint so insert a
	      // replacement char (U+FFFD) and advance only 1 byte
	      codePoint = 0xFFFD
	      bytesPerSequence = 1
	    } else if (codePoint > 0xFFFF) {
	      // encode to utf16 (surrogate pair dance)
	      codePoint -= 0x10000
	      res.push(codePoint >>> 10 & 0x3FF | 0xD800)
	      codePoint = 0xDC00 | codePoint & 0x3FF
	    }
	
	    res.push(codePoint)
	    i += bytesPerSequence
	  }
	
	  return decodeCodePointsArray(res)
	}
	
	// Based on http://stackoverflow.com/a/22747272/680742, the browser with
	// the lowest limit is Chrome, with 0x10000 args.
	// We go 1 magnitude less, for safety
	var MAX_ARGUMENTS_LENGTH = 0x1000
	
	function decodeCodePointsArray (codePoints) {
	  var len = codePoints.length
	  if (len <= MAX_ARGUMENTS_LENGTH) {
	    return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
	  }
	
	  // Decode in chunks to avoid "call stack size exceeded".
	  var res = ''
	  var i = 0
	  while (i < len) {
	    res += String.fromCharCode.apply(
	      String,
	      codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
	    )
	  }
	  return res
	}
	
	function asciiSlice (buf, start, end) {
	  var ret = ''
	  end = Math.min(buf.length, end)
	
	  for (var i = start; i < end; ++i) {
	    ret += String.fromCharCode(buf[i] & 0x7F)
	  }
	  return ret
	}
	
	function latin1Slice (buf, start, end) {
	  var ret = ''
	  end = Math.min(buf.length, end)
	
	  for (var i = start; i < end; ++i) {
	    ret += String.fromCharCode(buf[i])
	  }
	  return ret
	}
	
	function hexSlice (buf, start, end) {
	  var len = buf.length
	
	  if (!start || start < 0) start = 0
	  if (!end || end < 0 || end > len) end = len
	
	  var out = ''
	  for (var i = start; i < end; ++i) {
	    out += toHex(buf[i])
	  }
	  return out
	}
	
	function utf16leSlice (buf, start, end) {
	  var bytes = buf.slice(start, end)
	  var res = ''
	  for (var i = 0; i < bytes.length; i += 2) {
	    res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)
	  }
	  return res
	}
	
	Buffer.prototype.slice = function slice (start, end) {
	  var len = this.length
	  start = ~~start
	  end = end === undefined ? len : ~~end
	
	  if (start < 0) {
	    start += len
	    if (start < 0) start = 0
	  } else if (start > len) {
	    start = len
	  }
	
	  if (end < 0) {
	    end += len
	    if (end < 0) end = 0
	  } else if (end > len) {
	    end = len
	  }
	
	  if (end < start) end = start
	
	  var newBuf
	  if (Buffer.TYPED_ARRAY_SUPPORT) {
	    newBuf = this.subarray(start, end)
	    newBuf.__proto__ = Buffer.prototype
	  } else {
	    var sliceLen = end - start
	    newBuf = new Buffer(sliceLen, undefined)
	    for (var i = 0; i < sliceLen; ++i) {
	      newBuf[i] = this[i + start]
	    }
	  }
	
	  return newBuf
	}
	
	/*
	 * Need to make sure that buffer isn't trying to write out of bounds.
	 */
	function checkOffset (offset, ext, length) {
	  if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
	  if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
	}
	
	Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
	  offset = offset | 0
	  byteLength = byteLength | 0
	  if (!noAssert) checkOffset(offset, byteLength, this.length)
	
	  var val = this[offset]
	  var mul = 1
	  var i = 0
	  while (++i < byteLength && (mul *= 0x100)) {
	    val += this[offset + i] * mul
	  }
	
	  return val
	}
	
	Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
	  offset = offset | 0
	  byteLength = byteLength | 0
	  if (!noAssert) {
	    checkOffset(offset, byteLength, this.length)
	  }
	
	  var val = this[offset + --byteLength]
	  var mul = 1
	  while (byteLength > 0 && (mul *= 0x100)) {
	    val += this[offset + --byteLength] * mul
	  }
	
	  return val
	}
	
	Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 1, this.length)
	  return this[offset]
	}
	
	Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 2, this.length)
	  return this[offset] | (this[offset + 1] << 8)
	}
	
	Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 2, this.length)
	  return (this[offset] << 8) | this[offset + 1]
	}
	
	Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 4, this.length)
	
	  return ((this[offset]) |
	      (this[offset + 1] << 8) |
	      (this[offset + 2] << 16)) +
	      (this[offset + 3] * 0x1000000)
	}
	
	Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 4, this.length)
	
	  return (this[offset] * 0x1000000) +
	    ((this[offset + 1] << 16) |
	    (this[offset + 2] << 8) |
	    this[offset + 3])
	}
	
	Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
	  offset = offset | 0
	  byteLength = byteLength | 0
	  if (!noAssert) checkOffset(offset, byteLength, this.length)
	
	  var val = this[offset]
	  var mul = 1
	  var i = 0
	  while (++i < byteLength && (mul *= 0x100)) {
	    val += this[offset + i] * mul
	  }
	  mul *= 0x80
	
	  if (val >= mul) val -= Math.pow(2, 8 * byteLength)
	
	  return val
	}
	
	Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
	  offset = offset | 0
	  byteLength = byteLength | 0
	  if (!noAssert) checkOffset(offset, byteLength, this.length)
	
	  var i = byteLength
	  var mul = 1
	  var val = this[offset + --i]
	  while (i > 0 && (mul *= 0x100)) {
	    val += this[offset + --i] * mul
	  }
	  mul *= 0x80
	
	  if (val >= mul) val -= Math.pow(2, 8 * byteLength)
	
	  return val
	}
	
	Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 1, this.length)
	  if (!(this[offset] & 0x80)) return (this[offset])
	  return ((0xff - this[offset] + 1) * -1)
	}
	
	Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 2, this.length)
	  var val = this[offset] | (this[offset + 1] << 8)
	  return (val & 0x8000) ? val | 0xFFFF0000 : val
	}
	
	Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 2, this.length)
	  var val = this[offset + 1] | (this[offset] << 8)
	  return (val & 0x8000) ? val | 0xFFFF0000 : val
	}
	
	Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 4, this.length)
	
	  return (this[offset]) |
	    (this[offset + 1] << 8) |
	    (this[offset + 2] << 16) |
	    (this[offset + 3] << 24)
	}
	
	Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 4, this.length)
	
	  return (this[offset] << 24) |
	    (this[offset + 1] << 16) |
	    (this[offset + 2] << 8) |
	    (this[offset + 3])
	}
	
	Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 4, this.length)
	  return ieee754.read(this, offset, true, 23, 4)
	}
	
	Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 4, this.length)
	  return ieee754.read(this, offset, false, 23, 4)
	}
	
	Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 8, this.length)
	  return ieee754.read(this, offset, true, 52, 8)
	}
	
	Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
	  if (!noAssert) checkOffset(offset, 8, this.length)
	  return ieee754.read(this, offset, false, 52, 8)
	}
	
	function checkInt (buf, value, offset, ext, max, min) {
	  if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
	  if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
	  if (offset + ext > buf.length) throw new RangeError('Index out of range')
	}
	
	Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
	  value = +value
	  offset = offset | 0
	  byteLength = byteLength | 0
	  if (!noAssert) {
	    var maxBytes = Math.pow(2, 8 * byteLength) - 1
	    checkInt(this, value, offset, byteLength, maxBytes, 0)
	  }
	
	  var mul = 1
	  var i = 0
	  this[offset] = value & 0xFF
	  while (++i < byteLength && (mul *= 0x100)) {
	    this[offset + i] = (value / mul) & 0xFF
	  }
	
	  return offset + byteLength
	}
	
	Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
	  value = +value
	  offset = offset | 0
	  byteLength = byteLength | 0
	  if (!noAssert) {
	    var maxBytes = Math.pow(2, 8 * byteLength) - 1
	    checkInt(this, value, offset, byteLength, maxBytes, 0)
	  }
	
	  var i = byteLength - 1
	  var mul = 1
	  this[offset + i] = value & 0xFF
	  while (--i >= 0 && (mul *= 0x100)) {
	    this[offset + i] = (value / mul) & 0xFF
	  }
	
	  return offset + byteLength
	}
	
	Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
	  value = +value
	  offset = offset | 0
	  if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
	  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
	  this[offset] = (value & 0xff)
	  return offset + 1
	}
	
	function objectWriteUInt16 (buf, value, offset, littleEndian) {
	  if (value < 0) value = 0xffff + value + 1
	  for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {
	    buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
	      (littleEndian ? i : 1 - i) * 8
	  }
	}
	
	Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
	  value = +value
	  offset = offset | 0
	  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
	  if (Buffer.TYPED_ARRAY_SUPPORT) {
	    this[offset] = (value & 0xff)
	    this[offset + 1] = (value >>> 8)
	  } else {
	    objectWriteUInt16(this, value, offset, true)
	  }
	  return offset + 2
	}
	
	Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
	  value = +value
	  offset = offset | 0
	  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
	  if (Buffer.TYPED_ARRAY_SUPPORT) {
	    this[offset] = (value >>> 8)
	    this[offset + 1] = (value & 0xff)
	  } else {
	    objectWriteUInt16(this, value, offset, false)
	  }
	  return offset + 2
	}
	
	function objectWriteUInt32 (buf, value, offset, littleEndian) {
	  if (value < 0) value = 0xffffffff + value + 1
	  for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {
	    buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
	  }
	}
	
	Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
	  value = +value
	  offset = offset | 0
	  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
	  if (Buffer.TYPED_ARRAY_SUPPORT) {
	    this[offset + 3] = (value >>> 24)
	    this[offset + 2] = (value >>> 16)
	    this[offset + 1] = (value >>> 8)
	    this[offset] = (value & 0xff)
	  } else {
	    objectWriteUInt32(this, value, offset, true)
	  }
	  return offset + 4
	}
	
	Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
	  value = +value
	  offset = offset | 0
	  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
	  if (Buffer.TYPED_ARRAY_SUPPORT) {
	    this[offset] = (value >>> 24)
	    this[offset + 1] = (value >>> 16)
	    this[offset + 2] = (value >>> 8)
	    this[offset + 3] = (value & 0xff)
	  } else {
	    objectWriteUInt32(this, value, offset, false)
	  }
	  return offset + 4
	}
	
	Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
	  value = +value
	  offset = offset | 0
	  if (!noAssert) {
	    var limit = Math.pow(2, 8 * byteLength - 1)
	
	    checkInt(this, value, offset, byteLength, limit - 1, -limit)
	  }
	
	  var i = 0
	  var mul = 1
	  var sub = 0
	  this[offset] = value & 0xFF
	  while (++i < byteLength && (mul *= 0x100)) {
	    if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
	      sub = 1
	    }
	    this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
	  }
	
	  return offset + byteLength
	}
	
	Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
	  value = +value
	  offset = offset | 0
	  if (!noAssert) {
	    var limit = Math.pow(2, 8 * byteLength - 1)
	
	    checkInt(this, value, offset, byteLength, limit - 1, -limit)
	  }
	
	  var i = byteLength - 1
	  var mul = 1
	  var sub = 0
	  this[offset + i] = value & 0xFF
	  while (--i >= 0 && (mul *= 0x100)) {
	    if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
	      sub = 1
	    }
	    this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
	  }
	
	  return offset + byteLength
	}
	
	Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
	  value = +value
	  offset = offset | 0
	  if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
	  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
	  if (value < 0) value = 0xff + value + 1
	  this[offset] = (value & 0xff)
	  return offset + 1
	}
	
	Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
	  value = +value
	  offset = offset | 0
	  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
	  if (Buffer.TYPED_ARRAY_SUPPORT) {
	    this[offset] = (value & 0xff)
	    this[offset + 1] = (value >>> 8)
	  } else {
	    objectWriteUInt16(this, value, offset, true)
	  }
	  return offset + 2
	}
	
	Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
	  value = +value
	  offset = offset | 0
	  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
	  if (Buffer.TYPED_ARRAY_SUPPORT) {
	    this[offset] = (value >>> 8)
	    this[offset + 1] = (value & 0xff)
	  } else {
	    objectWriteUInt16(this, value, offset, false)
	  }
	  return offset + 2
	}
	
	Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
	  value = +value
	  offset = offset | 0
	  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
	  if (Buffer.TYPED_ARRAY_SUPPORT) {
	    this[offset] = (value & 0xff)
	    this[offset + 1] = (value >>> 8)
	    this[offset + 2] = (value >>> 16)
	    this[offset + 3] = (value >>> 24)
	  } else {
	    objectWriteUInt32(this, value, offset, true)
	  }
	  return offset + 4
	}
	
	Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
	  value = +value
	  offset = offset | 0
	  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
	  if (value < 0) value = 0xffffffff + value + 1
	  if (Buffer.TYPED_ARRAY_SUPPORT) {
	    this[offset] = (value >>> 24)
	    this[offset + 1] = (value >>> 16)
	    this[offset + 2] = (value >>> 8)
	    this[offset + 3] = (value & 0xff)
	  } else {
	    objectWriteUInt32(this, value, offset, false)
	  }
	  return offset + 4
	}
	
	function checkIEEE754 (buf, value, offset, ext, max, min) {
	  if (offset + ext > buf.length) throw new RangeError('Index out of range')
	  if (offset < 0) throw new RangeError('Index out of range')
	}
	
	function writeFloat (buf, value, offset, littleEndian, noAssert) {
	  if (!noAssert) {
	    checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
	  }
	  ieee754.write(buf, value, offset, littleEndian, 23, 4)
	  return offset + 4
	}
	
	Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
	  return writeFloat(this, value, offset, true, noAssert)
	}
	
	Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
	  return writeFloat(this, value, offset, false, noAssert)
	}
	
	function writeDouble (buf, value, offset, littleEndian, noAssert) {
	  if (!noAssert) {
	    checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
	  }
	  ieee754.write(buf, value, offset, littleEndian, 52, 8)
	  return offset + 8
	}
	
	Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
	  return writeDouble(this, value, offset, true, noAssert)
	}
	
	Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
	  return writeDouble(this, value, offset, false, noAssert)
	}
	
	// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
	Buffer.prototype.copy = function copy (target, targetStart, start, end) {
	  if (!start) start = 0
	  if (!end && end !== 0) end = this.length
	  if (targetStart >= target.length) targetStart = target.length
	  if (!targetStart) targetStart = 0
	  if (end > 0 && end < start) end = start
	
	  // Copy 0 bytes; we're done
	  if (end === start) return 0
	  if (target.length === 0 || this.length === 0) return 0
	
	  // Fatal error conditions
	  if (targetStart < 0) {
	    throw new RangeError('targetStart out of bounds')
	  }
	  if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')
	  if (end < 0) throw new RangeError('sourceEnd out of bounds')
	
	  // Are we oob?
	  if (end > this.length) end = this.length
	  if (target.length - targetStart < end - start) {
	    end = target.length - targetStart + start
	  }
	
	  var len = end - start
	  var i
	
	  if (this === target && start < targetStart && targetStart < end) {
	    // descending copy from end
	    for (i = len - 1; i >= 0; --i) {
	      target[i + targetStart] = this[i + start]
	    }
	  } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
	    // ascending copy from start
	    for (i = 0; i < len; ++i) {
	      target[i + targetStart] = this[i + start]
	    }
	  } else {
	    Uint8Array.prototype.set.call(
	      target,
	      this.subarray(start, start + len),
	      targetStart
	    )
	  }
	
	  return len
	}
	
	// Usage:
	//    buffer.fill(number[, offset[, end]])
	//    buffer.fill(buffer[, offset[, end]])
	//    buffer.fill(string[, offset[, end]][, encoding])
	Buffer.prototype.fill = function fill (val, start, end, encoding) {
	  // Handle string cases:
	  if (typeof val === 'string') {
	    if (typeof start === 'string') {
	      encoding = start
	      start = 0
	      end = this.length
	    } else if (typeof end === 'string') {
	      encoding = end
	      end = this.length
	    }
	    if (val.length === 1) {
	      var code = val.charCodeAt(0)
	      if (code < 256) {
	        val = code
	      }
	    }
	    if (encoding !== undefined && typeof encoding !== 'string') {
	      throw new TypeError('encoding must be a string')
	    }
	    if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
	      throw new TypeError('Unknown encoding: ' + encoding)
	    }
	  } else if (typeof val === 'number') {
	    val = val & 255
	  }
	
	  // Invalid ranges are not set to a default, so can range check early.
	  if (start < 0 || this.length < start || this.length < end) {
	    throw new RangeError('Out of range index')
	  }
	
	  if (end <= start) {
	    return this
	  }
	
	  start = start >>> 0
	  end = end === undefined ? this.length : end >>> 0
	
	  if (!val) val = 0
	
	  var i
	  if (typeof val === 'number') {
	    for (i = start; i < end; ++i) {
	      this[i] = val
	    }
	  } else {
	    var bytes = Buffer.isBuffer(val)
	      ? val
	      : utf8ToBytes(new Buffer(val, encoding).toString())
	    var len = bytes.length
	    for (i = 0; i < end - start; ++i) {
	      this[i + start] = bytes[i % len]
	    }
	  }
	
	  return this
	}
	
	// HELPER FUNCTIONS
	// ================
	
	var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g
	
	function base64clean (str) {
	  // Node strips out invalid characters like \n and \t from the string, base64-js does not
	  str = stringtrim(str).replace(INVALID_BASE64_RE, '')
	  // Node converts strings with length < 2 to ''
	  if (str.length < 2) return ''
	  // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
	  while (str.length % 4 !== 0) {
	    str = str + '='
	  }
	  return str
	}
	
	function stringtrim (str) {
	  if (str.trim) return str.trim()
	  return str.replace(/^\s+|\s+$/g, '')
	}
	
	function toHex (n) {
	  if (n < 16) return '0' + n.toString(16)
	  return n.toString(16)
	}
	
	function utf8ToBytes (string, units) {
	  units = units || Infinity
	  var codePoint
	  var length = string.length
	  var leadSurrogate = null
	  var bytes = []
	
	  for (var i = 0; i < length; ++i) {
	    codePoint = string.charCodeAt(i)
	
	    // is surrogate component
	    if (codePoint > 0xD7FF && codePoint < 0xE000) {
	      // last char was a lead
	      if (!leadSurrogate) {
	        // no lead yet
	        if (codePoint > 0xDBFF) {
	          // unexpected trail
	          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
	          continue
	        } else if (i + 1 === length) {
	          // unpaired lead
	          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
	          continue
	        }
	
	        // valid lead
	        leadSurrogate = codePoint
	
	        continue
	      }
	
	      // 2 leads in a row
	      if (codePoint < 0xDC00) {
	        if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
	        leadSurrogate = codePoint
	        continue
	      }
	
	      // valid surrogate pair
	      codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
	    } else if (leadSurrogate) {
	      // valid bmp char, but last char was a lead
	      if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
	    }
	
	    leadSurrogate = null
	
	    // encode utf8
	    if (codePoint < 0x80) {
	      if ((units -= 1) < 0) break
	      bytes.push(codePoint)
	    } else if (codePoint < 0x800) {
	      if ((units -= 2) < 0) break
	      bytes.push(
	        codePoint >> 0x6 | 0xC0,
	        codePoint & 0x3F | 0x80
	      )
	    } else if (codePoint < 0x10000) {
	      if ((units -= 3) < 0) break
	      bytes.push(
	        codePoint >> 0xC | 0xE0,
	        codePoint >> 0x6 & 0x3F | 0x80,
	        codePoint & 0x3F | 0x80
	      )
	    } else if (codePoint < 0x110000) {
	      if ((units -= 4) < 0) break
	      bytes.push(
	        codePoint >> 0x12 | 0xF0,
	        codePoint >> 0xC & 0x3F | 0x80,
	        codePoint >> 0x6 & 0x3F | 0x80,
	        codePoint & 0x3F | 0x80
	      )
	    } else {
	      throw new Error('Invalid code point')
	    }
	  }
	
	  return bytes
	}
	
	function asciiToBytes (str) {
	  var byteArray = []
	  for (var i = 0; i < str.length; ++i) {
	    // Node's code seems to be doing this and not & 0x7F..
	    byteArray.push(str.charCodeAt(i) & 0xFF)
	  }
	  return byteArray
	}
	
	function utf16leToBytes (str, units) {
	  var c, hi, lo
	  var byteArray = []
	  for (var i = 0; i < str.length; ++i) {
	    if ((units -= 2) < 0) break
	
	    c = str.charCodeAt(i)
	    hi = c >> 8
	    lo = c % 256
	    byteArray.push(lo)
	    byteArray.push(hi)
	  }
	
	  return byteArray
	}
	
	function base64ToBytes (str) {
	  return base64.toByteArray(base64clean(str))
	}
	
	function blitBuffer (src, dst, offset, length) {
	  for (var i = 0; i < length; ++i) {
	    if ((i + offset >= dst.length) || (i >= src.length)) break
	    dst[i + offset] = src[i]
	  }
	  return i
	}
	
	function isnan (val) {
	  return val !== val // eslint-disable-line no-self-compare
	}
	
	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))

/***/ }),
/* 8 */
/***/ (function(module, exports) {

	'use strict'
	
	exports.byteLength = byteLength
	exports.toByteArray = toByteArray
	exports.fromByteArray = fromByteArray
	
	var lookup = []
	var revLookup = []
	var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
	
	var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
	for (var i = 0, len = code.length; i < len; ++i) {
	  lookup[i] = code[i]
	  revLookup[code.charCodeAt(i)] = i
	}
	
	revLookup['-'.charCodeAt(0)] = 62
	revLookup['_'.charCodeAt(0)] = 63
	
	function placeHoldersCount (b64) {
	  var len = b64.length
	  if (len % 4 > 0) {
	    throw new Error('Invalid string. Length must be a multiple of 4')
	  }
	
	  // the number of equal signs (place holders)
	  // if there are two placeholders, than the two characters before it
	  // represent one byte
	  // if there is only one, then the three characters before it represent 2 bytes
	  // this is just a cheap hack to not do indexOf twice
	  return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0
	}
	
	function byteLength (b64) {
	  // base64 is 4/3 + up to two characters of the original data
	  return (b64.length * 3 / 4) - placeHoldersCount(b64)
	}
	
	function toByteArray (b64) {
	  var i, l, tmp, placeHolders, arr
	  var len = b64.length
	  placeHolders = placeHoldersCount(b64)
	
	  arr = new Arr((len * 3 / 4) - placeHolders)
	
	  // if there are placeholders, only get up to the last complete 4 chars
	  l = placeHolders > 0 ? len - 4 : len
	
	  var L = 0
	
	  for (i = 0; i < l; i += 4) {
	    tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]
	    arr[L++] = (tmp >> 16) & 0xFF
	    arr[L++] = (tmp >> 8) & 0xFF
	    arr[L++] = tmp & 0xFF
	  }
	
	  if (placeHolders === 2) {
	    tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)
	    arr[L++] = tmp & 0xFF
	  } else if (placeHolders === 1) {
	    tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)
	    arr[L++] = (tmp >> 8) & 0xFF
	    arr[L++] = tmp & 0xFF
	  }
	
	  return arr
	}
	
	function tripletToBase64 (num) {
	  return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]
	}
	
	function encodeChunk (uint8, start, end) {
	  var tmp
	  var output = []
	  for (var i = start; i < end; i += 3) {
	    tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
	    output.push(tripletToBase64(tmp))
	  }
	  return output.join('')
	}
	
	function fromByteArray (uint8) {
	  var tmp
	  var len = uint8.length
	  var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
	  var output = ''
	  var parts = []
	  var maxChunkLength = 16383 // must be multiple of 3
	
	  // go through the array every three bytes, we'll deal with trailing stuff later
	  for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
	    parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
	  }
	
	  // pad the end with zeros, but make sure to not forget the extra bytes
	  if (extraBytes === 1) {
	    tmp = uint8[len - 1]
	    output += lookup[tmp >> 2]
	    output += lookup[(tmp << 4) & 0x3F]
	    output += '=='
	  } else if (extraBytes === 2) {
	    tmp = (uint8[len - 2] << 8) + (uint8[len - 1])
	    output += lookup[tmp >> 10]
	    output += lookup[(tmp >> 4) & 0x3F]
	    output += lookup[(tmp << 2) & 0x3F]
	    output += '='
	  }
	
	  parts.push(output)
	
	  return parts.join('')
	}


/***/ }),
/* 9 */
/***/ (function(module, exports) {

	exports.read = function (buffer, offset, isLE, mLen, nBytes) {
	  var e, m
	  var eLen = nBytes * 8 - mLen - 1
	  var eMax = (1 << eLen) - 1
	  var eBias = eMax >> 1
	  var nBits = -7
	  var i = isLE ? (nBytes - 1) : 0
	  var d = isLE ? -1 : 1
	  var s = buffer[offset + i]
	
	  i += d
	
	  e = s & ((1 << (-nBits)) - 1)
	  s >>= (-nBits)
	  nBits += eLen
	  for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
	
	  m = e & ((1 << (-nBits)) - 1)
	  e >>= (-nBits)
	  nBits += mLen
	  for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
	
	  if (e === 0) {
	    e = 1 - eBias
	  } else if (e === eMax) {
	    return m ? NaN : ((s ? -1 : 1) * Infinity)
	  } else {
	    m = m + Math.pow(2, mLen)
	    e = e - eBias
	  }
	  return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
	}
	
	exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
	  var e, m, c
	  var eLen = nBytes * 8 - mLen - 1
	  var eMax = (1 << eLen) - 1
	  var eBias = eMax >> 1
	  var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
	  var i = isLE ? 0 : (nBytes - 1)
	  var d = isLE ? 1 : -1
	  var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
	
	  value = Math.abs(value)
	
	  if (isNaN(value) || value === Infinity) {
	    m = isNaN(value) ? 1 : 0
	    e = eMax
	  } else {
	    e = Math.floor(Math.log(value) / Math.LN2)
	    if (value * (c = Math.pow(2, -e)) < 1) {
	      e--
	      c *= 2
	    }
	    if (e + eBias >= 1) {
	      value += rt / c
	    } else {
	      value += rt * Math.pow(2, 1 - eBias)
	    }
	    if (value * c >= 2) {
	      e++
	      c /= 2
	    }
	
	    if (e + eBias >= eMax) {
	      m = 0
	      e = eMax
	    } else if (e + eBias >= 1) {
	      m = (value * c - 1) * Math.pow(2, mLen)
	      e = e + eBias
	    } else {
	      m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
	      e = 0
	    }
	  }
	
	  for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
	
	  e = (e << mLen) | m
	  eLen += mLen
	  for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
	
	  buffer[offset + i - d] |= s * 128
	}


/***/ }),
/* 10 */
/***/ (function(module, exports) {

	var toString = {}.toString;
	
	module.exports = Array.isArray || function (arr) {
	  return toString.call(arr) == '[object Array]';
	};


/***/ }),
/* 11 */
/***/ (function(module, exports) {

	function ini_hzome(root_id){
	
	  // save gene data to global variable
	  gene_data = {};
	
	  function get_mouseover(root_tip, gene_symbol){
	
	    // not sure if this is necessary
	    if ( d3.select(root_tip + '_row_tip').classed(gene_symbol) ){
	     get_request(root_tip, gene_symbol);
	    }
	
	  }
	
	  function get_request(root_tip, ini_gene_symbol){
	
	    var gene_symbol;
	    if (ini_gene_symbol.indexOf(' ') > 0){
	      gene_symbol = ini_gene_symbol.split(' ')[0];
	    } else if (ini_gene_symbol.indexOf('_') > 0){
	      gene_symbol = ini_gene_symbol.split('_')[0];
	    }
	    else {
	      gene_symbol = ini_gene_symbol;
	    }
	
	    var base_url = 'https://amp.pharm.mssm.edu/Harmonizome/api/1.0/gene/';
	    var url = base_url + gene_symbol;
	
	    $.get(url, function(data) {
	
	      data = JSON.parse(data);
	
	      // save data for repeated use
	      gene_data[gene_symbol] = {}
	      gene_data[gene_symbol].name = data.name;
	      gene_data[gene_symbol].description = data.description;
	
	      set_tooltip(data, root_tip, ini_gene_symbol);
	
	      return data;
	
	    });
	  }
	
	  function set_tooltip(data, root_tip, gene_symbol){
	
	    if (data.name != undefined){
	
	      d3.selectAll(root_tip + '_row_tip')
	        .html(function(){
	            var sym_name = gene_symbol + ': ' + data.name;
	            var full_html = '<p>' + sym_name + '</p>' +  '<p>' +
	              data.description + '</p>';
	            return full_html;
	        });
	    }
	  }
	
	
	  function gene_info(root_tip, gene_info){
	
	    var gene_symbol = gene_info.name;
	
	    if (_.has(gene_data, gene_symbol)){
	      var inst_data = gene_data[gene_symbol];
	      set_tooltip(inst_data, root_tip, gene_symbol);
	    } else{
	      setTimeout(get_mouseover, 250, root_tip, gene_symbol);
	    }
	
	  }
	
	  hzome = {}
	
	  hzome.gene_info = gene_info;
	  hzome.gene_data = gene_data;
	  hzome.get_mouseover = get_mouseover;
	  hzome.get_request = get_request;
	
	  return hzome;
	
	}
	
	module.exports = ini_hzome;

/***/ }),
/* 12 */
/***/ (function(module, exports) {

	function Enrichrgram(inst_cgm){
	
	  var inst_root = inst_cgm.params.root;
	
	  function enrichr_icon(){
	
	    var low_opacity = 0.7;
	    var high_opacity = 1.0;
	    var icon_size = 42;
	    var d3_tip_custom = inst_cgm.d3_tip_custom();
	
	    // var enrichr_description = 'Perform enrichment analysis on your gene-list <br>'+
	    //                           'using Enrichr to find biological information that is unique to your list.'
	    var enrichr_description = 'Perform enrichment analysis, using Enrichr, to find biological <br>'+
	                              'information specific to your set (or subset) of genes. <br><br>' +
	                              'Select a subset of genes for analysis by cropping the matrix using: the brush-cropping tool in the sidebar, or the crop buttons on the dendrogram.'
	    // d3-tooltip
	    var enr_tip = d3_tip_custom()
	      .attr('class', function(){
	        var root_tip_selector = inst_cgm.params.viz.root_tips.replace('.','');
	        var class_string = root_tip_selector + '_enr_tip d3-tip';
	        return class_string;
	      })
	      .direction('se')
	      .style('display', 'none')
	      .offset([-10,-5])
	      .html(function(d){
	        return enrichr_description;
	      });
	
	    var enr_logo = d3.select(inst_root+' .viz_svg').append("svg:image")
	     .attr('x', 50)
	     .attr('y', 2)
	     .attr('width', icon_size)
	     .attr('height', icon_size)
	     .attr("xlink:href", "https://amp.pharm.mssm.edu/Enrichr/images/enrichr-icon.png")
	     .style('opacity', low_opacity)
	     .classed('enrichr_logo', true)
	     .attr('id', function(){
	      var inst_id = 'enrichr_menu_button_' + inst_cgm.params.root.replace('#','');
	      return inst_id;
	     })
	     .on('click', function(){
	       toggle_enrichr_menu();
	     })
	     .on('mouseover', function(){
	
	      var is_showing = d3.select(inst_cgm.params.root+' .enrichr_menu')
	                         .classed('showing');
	
	      if (is_showing === false){
	        // show tooltip
	        d3.selectAll( inst_cgm.params.viz.root_tips + '_enr_tip')
	          .style('opacity', 1)
	          .style('display', 'block');
	
	         enr_tip.show();
	      }
	
	     })
	     .on('mouseout', function(){
	
	      // hide tooltip
	      d3.selectAll( inst_cgm.params.viz.root_tips + '_enr_tip')
	        .style('opacity', 0)
	        .style('display', 'block');
	
	       enr_tip.hide();
	     })
	     .call(enr_tip);
	
	    var enr_menu = d3.select(inst_cgm.params.root+' .viz_svg')
	      .append('g')
	      .classed('showing', false)
	      .classed('enrichr_menu', true)
	      .attr('transform', 'translate(85,40)')
	      .style('display', 'none');
	
	    enr_menu
	      .append('rect')
	      .classed('enr_menu_background', true)
	      .style('width', 475)
	      .style('height', 500)
	      .style('opacity', 0.95)
	      .style('fill', 'white')
	      .style('stroke', '#A3A3A3')
	      .style('stroke-width', '3px');
	
	    enr_menu
	      .append('text')
	      .attr('transform', 'translate(20,30)')
	      .attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
	      .style('font-size','18px')
	      .style('font-weight', 800)
	      .style('cursor', 'default')
	      .text('Choose Enrichr Library');
	
	    // clear results button
	    enr_menu
	      .append('text')
	      .classed('enr_menu_clear', true)
	      .attr('transform', 'translate(345, 30)')
	      .attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
	      .style('font-size','18px')
	      .style('font-weight', 800)
	      .style('cursor', 'default')
	      .text('Clear Results')
	      .style('fill', 'red')
	      .style('opacity', 0.75)
	      .style('display', 'none')
	      .on('click', function(){
	
	
	        // reset enrichr menu
	        toggle_enrichr_menu();
	
	        // clear enrichr results and run resizing
	        clear_enrichr_results(true);
	
	      })
	
	    var lib_section = enr_menu
	      .append('g')
	      .attr('transform', 'translate(20,60)')
	      .style('width', 460)
	      .style('height', 370)
	      .classed('enr_lib_section','true');
	
	    var possible_libraries = [
	      'ChEA_2016',
	      'KEA_2015',
	      'ENCODE_TF_ChIP-seq_2015',
	      'ENCODE_Histone_Modifications_2015',
	      'Disease_Perturbations_from_GEO_up',
	      'Disease_Perturbations_from_GEO_down',
	      'GO_Molecular_Function_2015',
	      'GO_Biological_Process_2015',
	      'GO_Cellular_Component_2015',
	      'Reactome_2016',
	      'KEGG_2016',
	      'MGI_Mammalian_Phenotype_Level_4',
	      'LINCS_L1000_Chem_Pert_up',
	      'LINCS_L1000_Chem_Pert_down',
	      ];
	
	    var vertical_space = 30;
	
	    enr_menu
	      .append('rect')
	      .classed('enr_menu_line', true)
	      .attr('height', '2px')
	      .attr('width', '435px')
	      .style('stroke-width', '3px')
	      .style('opacity', 0.3)
	      .style('fill','black')
	      .attr('transform', 'translate(20, 465)');
	
	    var enr_export_container = enr_menu
	      .append('g')
	      .classed('enr_export_container', true)
	      .attr('transform', 'translate(20, 487)');
	
	    enr_export_container
	      .append('text')
	      .style('font-size','16px')
	      .attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
	      .style('cursor', 'default')
	      .text('Export gene list to ');
	
	    enr_export_container
	      .append('text')
	      .style('font-size','16px')
	      .attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
	      .style('cursor', 'default')
	      .text('Enrichr')
	      .style('fill','#337ab7')
	      .attr('transform', 'translate(135, 0)')
	      .on('click', function(){
	
	        // get gene list and send to Enrichr
	        var gene_list = inst_cgm.params.network_data.row_nodes_names.join('\n');
	
	        var enrichr_info = {list: gene_list, description: 'Clustergrammer gene list' , popup: true};
	
	        // defined globally - will improve
	        enrich(enrichr_info);
	
	      })
	
	    var lib_groups = lib_section
	      .selectAll('g')
	      .data(possible_libraries)
	      .enter()
	      .append('g')
	      .attr('transform', function(d,i){
	        var vert =  i*vertical_space
	        var transform_string = 'translate(0,'+ vert+')';
	        return transform_string;
	      })
	
	    lib_groups
	      .append('circle')
	      .attr('cx', 10)
	      .attr('cy', -6)
	      .attr('r', 7)
	      .style('stroke', '#A3A3A3')
	      .style('stroke-width', '2px')
	      .style('fill','white')
	
	    lib_groups
	      .append('text')
	      .attr('transform', 'translate(25,0)')
	      .style('font-size','16px')
	      .attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
	      .style('cursor', 'default')
	      .text(function(d){
	        return d.replace(/_/g, ' ');
	      });
	
	    lib_groups
	      .on('click', function(d){
	
	        d3.select(inst_cgm.params.root+' .enr_lib_section')
	          .selectAll('g')
	          .select('circle')
	          .style('fill','white');
	
	        // indicate that library was selected
	        d3.select(this)
	          .select('circle')
	          .style('fill','red')
	
	        // turn on clear sign
	        d3.select(inst_cgm.params.root+' .enr_menu_clear')
	          .transition()
	          .delay(1000)
	          .style('display', 'block');
	
	        // request enrichment results from Enrichr
	        enr_obj.enrichr_rows(d, update_viz_callback, 10);
	
	        make_enr_wait_circle();
	        animate_wait();
	
	        setTimeout(toggle_enrichr_menu, 500);
	      })
	
	  }
	
	  function clear_enrichr_results(run_resize_viz){
	
	    d3.select(inst_cgm.params.root+ ' .enr_menu_clear')
	      .style('display', 'none');
	
	    // unselect library
	    d3.select(inst_cgm.params.root+' .enr_lib_section')
	      .selectAll('g')
	      .select('circle')
	      .style('fill','white');
	
	    // clear categories
	    inst_cgm.reset_cats(run_resize_viz);
	
	    // remove title and bars
	    d3.select(inst_cgm.params.root+' .enr_title').remove();
	    d3.selectAll(inst_cgm.params.root+' .enrichr_bars').remove();
	
	  }
	
	  function toggle_enrichr_menu(){
	
	    var enr_menu = d3.select(inst_cgm.params.root+' .enrichr_menu');
	
	    if (enr_menu.classed('showing') === false){
	
	      // show menu
	      ///////////////////////
	      enr_menu
	        .classed('showing', true)
	        .style('display', 'block');
	
	      d3.select(inst_cgm.params.root+' .enrichr_menu')
	        .style('opacity',0)
	        .transition()
	        .style('opacity',1)
	
	      d3.selectAll('.row_cat_super').style('display','none');
	
	      // hide tooltip
	      d3.selectAll( inst_cgm.params.viz.root_tips + '_enr_tip')
	        .style('opacity', 0)
	        .style('display', 'none');
	
	    } else {
	
	      // hide menu
	      ///////////////////////
	      setTimeout(function(){enr_menu.style('display', 'none');}, 1000)
	
	      d3.select(inst_cgm.params.root+' .enrichr_menu')
	        .classed('showing', false)
	        .style('opacity',1)
	        .transition()
	        .style('opacity',0)
	
	      d3.selectAll('.row_cat_super').style('display','block');
	    }
	
	  }
	
	  function get_enr_with_list(ini_gene_list, library, callback_function){
	
	    // clean gene list
	    var gene_list = []
	    _.each(ini_gene_list, function(gene_symbol){
	      if (gene_symbol.indexOf(' ') > 0){
	        gene_symbol = gene_symbol.split(' ')[0];
	      } else if (gene_symbol.indexOf('_') > 0){
	        gene_symbol = gene_symbol.split('_')[0];
	      }
	      gene_list.push(gene_symbol)
	    })
	
	    enr_obj.library = library;
	    enr_obj.gene_list = gene_list;
	
	    enr_obj.post_list(gene_list, function(){
	
	      if (typeof callback_function != 'undefined'){
	        enr_obj.get_enr(library, callback_function);
	      } else {
	        enr_obj.get_enr(library);
	      }
	
	    });
	  }
	
	  function post_list(gene_list, callback_function){
	
	    var gene_list_string = gene_list.join('\n');
	
	    var form = new FormData();
	    var response;
	
	    form.append("list", gene_list_string);
	
	    form.append("description", "clustergrammer");
	
	    var settings = {
	     "async": true,
	     "crossDomain": true,
	     "url": "https://amp.pharm.mssm.edu/Enrichr/addList",
	     "method": "POST",
	     "processData": false,
	     "contentType": false,
	     "mimeType": "multipart/form-data",
	     "data": form
	    }
	
	    if (typeof callback_function === 'undefined'){
	      callback_function = confirm_save;
	    }
	
	    $.ajax(settings)
	     .done(function(response){
	      response = JSON.parse(response);
	      enr_obj.user_list_id = response.userListId;
	
	      // make get request
	      setTimeout(callback_function, 500, response);
	      // callback_function(response);
	     });
	  }
	
	  function confirm_save(response){
	    console.log('saved user_list_id '+String(enr_obj.user_list_id));
	  }
	
	  function get_enr(library, callback_function){
	
	    if (enr_obj.user_list_id !== null){
	      var form = new FormData();
	
	      var base_url = 'https://amp.pharm.mssm.edu/Enrichr/enrich?';
	      var library_string = 'backgroundType=' + String(library);
	      var list_id_string = 'userListId=' + String(enr_obj.user_list_id);
	
	      var full_url = base_url + library_string + '&' + list_id_string;
	
	      // get request
	      var settings = {
	       "async": true,
	       "crossDomain": true,
	       "url": full_url,
	       "method": "GET",
	       "processData": false,
	       "contentType": false,
	       "mimeType": "multipart/form-data",
	       "data": form
	      }
	
	      $.ajax(settings)
	        .done(function (response, textStatus, jqXHR) {
	
	          response = JSON.parse(response);
	          enr_obj.enr_data = response;
	
	          // parse enr_data to cat_data format
	          /////////////////////////////////////
	          // enr_obj.cat_data = enr_obj.enr_data
	          enr_obj.enr_data_to_cats();
	
	          if (typeof callback_function != 'undefined'){
	            callback_function(enr_obj);
	          }
	          d3.select(inst_cgm.params.root+' .enr_wait_circle').remove();
	
	        })
	        .fail(function( jqXHR, textStatus, errorThrown ){
	
	          enr_obj.get_tries = enr_obj.get_tries + 1;
	
	          if (enr_obj.get_tries < 2){
	            // enr_obj.get_enr(library, callback_function);
	            setTimeout( enr_obj.get_enr, 500, library_string, callback_function )
	          } else {
	            console.log('did not get response from Enrichr - need to remove wait circle')
	            d3.select(inst_cgm.params.root+' .enr_wait_circle').remove();
	          }
	
	        });
	
	    } else {
	      console.log('no user_list_id defined')
	    }
	  }
	
	  function enrichr_rows(library, callback_function, num_terms){
	
	    // set up a variable number of terms
	
	    enr_obj.library = library;
	    var gene_list = inst_cgm.params.network_data.row_nodes_names;
	    enr_obj.get_enr_with_list(gene_list, library, callback_function)
	
	  }
	
	  function enr_data_to_cats(){
	
	    var library_name = _.keys(this.enr_data)[0];
	
	    var enr_terms = this.enr_data[library_name];
	
	    // keep the top 10 enriched terms
	    enr_terms = enr_terms.slice(0,10);
	
	    cat_data = []
	
	    _.each(enr_terms, function(inst_term){
	
	      inst_data = {};
	      inst_data['cat_title'] = inst_term[1];
	      inst_data['cats'] = [];
	      inst_data['pval'] = inst_term[2];
	
	      // keep the combined score
	      inst_data['combined_score'] = inst_term[4]
	
	      cat_details = {};
	      cat_details.cat_name = 'true';
	      cat_details.members = inst_term[5]
	
	      // there are only two categories for Enrichr: true/false
	      inst_data['cats'].push(cat_details)
	
	      cat_data.push(inst_data);
	    });
	
	    this.cat_data = cat_data;
	
	  }
	
	  function animate_wait() {
	
	    var repeat_time = 700;
	    var max_opacity = 0.8;
	    var min_opacity = 0.2
	
	    d3.select(inst_cgm.params.root+' .enr_wait_circle')
	      .transition()
	      .ease('linear')
	      .style('opacity', min_opacity)
	      .transition()
	      .ease('linear')
	      .duration(repeat_time)
	      .style('opacity', max_opacity)
	      .transition()
	      .ease('linear')
	      .duration(repeat_time)
	      .style('opacity', min_opacity)
	      .each("end", animate_wait);
	  }
	
	  function update_viz_callback(enr_obj){
	
	    inst_cgm.update_cats(enr_obj.cat_data);
	
	    d3.select(inst_cgm.params.root+' .enr_title').remove();
	
	    var enr_title = d3.select(inst_cgm.params.root+' .viz_svg')
	      .append('g')
	      .classed('enr_title', true)
	      .attr('transform', function(){
	
	        var trans = d3.select(inst_cgm.params.root+' .row_cat_label_container')
	                      .attr('transform').split('(')[1].split(')')[0];
	        x_offset = Number(trans.split(',')[0]) - 10;
	
	        return 'translate('+ String(x_offset)+', 0)';
	
	      });
	
	    enr_title
	      .append('rect')
	      .attr('width', inst_cgm.params.viz.cat_room.row)
	      .attr('height', 25)
	      .attr('fill', 'white');
	
	    var library_string = enr_obj.library.substring(0,40);
	    enr_title
	      .append('text')
	      .attr('transform', 'translate(0, 17)')
	      .text(library_string.replace(/_/g, ' '))
	      .style('font-size', '15px')
	      .attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif');
	
	    var extra_y_room = 1.25;
	    var unit_length = extra_y_room * inst_cgm.params.viz.cat_room.symbol_width;
	    var bar_width = unit_length * 0.9;
	
	    // Enrichr bars
	    ///////////////////////////////
	
	    d3.selectAll(inst_cgm.params.root+' .enrichr_bars').remove();
	
	    var bar_height = inst_cgm.params.viz.clust.margin.top - 35;
	    var max_score = enr_obj.cat_data[0].combined_score;
	    var bar_scale = d3.scale.linear()
	                      .domain([0, max_score])
	                      .range([0, bar_height]);
	
	    d3.select(inst_cgm.params.root+' .row_cat_label_bar_container')
	      .selectAll()
	      .data(inst_cgm.params.viz.all_cats.row)
	      .enter()
	      .append('rect')
	      .classed('enrichr_bars', true)
	      .attr('height', bar_width +'px')
	      .attr('fill', 'red')
	      .attr('width', function(d){
	
	        var enr_index = d.split('-')[1];
	        var inst_comb_score = enr_obj.cat_data[enr_index].combined_score;
	        var bar_lenth = bar_scale(inst_comb_score);
	        var bar_length_string = bar_lenth + 'px'
	        return bar_length_string;
	      })
	      .attr('opacity', 0.4)
	      .attr('transform', function(d){
	        var inst_y = unit_length * (parseInt( d.split('-')[1], 10 ) -0.75 );
	        return 'translate(0,'+inst_y+')';
	      })
	
	  }
	
	  function make_enr_wait_circle(){
	    var pos_x = 72;
	    var pos_y = 25;
	
	     var click_circle = d3.select(inst_cgm.params.root+' .viz_svg')
	        .append('circle')
	        .classed('enr_wait_circle', true)
	        .attr('cx',pos_x)
	        .attr('cy',pos_y)
	        .attr('r',23)
	        .style('stroke','#666666')
	        .style('stroke-width','3px')
	        .style('fill','white')
	        .style('fill-opacity',0)
	        .style('opacity', 0);
	  }
	
	  // example of how to check gene list
	  // http://amp.pharm.mssm.edu/Enrichr/view?userListId=1284420
	
	  var enr_obj = {};
	  enr_obj.user_list_id = null;
	  enr_obj.enr_data = null;
	  enr_obj.cat_data = null;
	  enr_obj.get_tries = 0;
	  enr_obj.library = null;
	  enr_obj.gene_list = null;
	
	  enr_obj.enrichr_icon = enrichr_icon;
	  enr_obj.post_list = post_list;
	  enr_obj.get_enr = get_enr;
	  enr_obj.get_enr_with_list = get_enr_with_list;
	  enr_obj.enrichr_rows = enrichr_rows;
	  enr_obj.enr_data_to_cats = enr_data_to_cats;
	  enr_obj.update_viz_callback = update_viz_callback;
	  enr_obj.clear_enrichr_results = clear_enrichr_results;
	
	  return enr_obj;
	
	}
	
	module.exports = Enrichrgram;

/***/ }),
/* 13 */
/***/ (function(module, exports, __webpack_require__) {

	module.exports = __webpack_require__.p + "f2c72c12e473db657b6f061871c24289.png";

/***/ }),
/* 14 */
/***/ (function(module, exports, __webpack_require__) {

	// style-loader: Adds some css to the DOM by adding a <style> tag
	
	// load the styles
	var content = __webpack_require__(15);
	if(typeof content === 'string') content = [[module.id, content, '']];
	// add the styles to the DOM
	var update = __webpack_require__(17)(content, {});
	if(content.locals) module.exports = content.locals;
	// Hot Module Replacement
	if(false) {
		// When the styles change, update the <style> tags
		if(!content.locals) {
			module.hot.accept("!!../node_modules/css-loader/index.js!./custom.css", function() {
				var newContent = require("!!../node_modules/css-loader/index.js!./custom.css");
				if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
				update(newContent);
			});
		}
		// When the module is disposed, remove the <style> tags
		module.hot.dispose(function() { update(); });
	}

/***/ }),
/* 15 */
/***/ (function(module, exports, __webpack_require__) {

	exports = module.exports = __webpack_require__(16)();
	// imports
	
	
	// module
	exports.push([module.id, "* {\n  -webkit-box-sizing: border-box;\n}\n\nbody{\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 1.428;\n  color: #333;\n  background-color: #fff;\n}\n\n/*.clust_icon{\n  float:left;\n  width: 33.3333333%;\n  padding-left: 15px;\n  padding-right: 15px;\n}*/\n\n.viz_medium_text{\n  width:99%;\n  margin-left: 5px;\n  margin-top: 3px;\n  margin-bottom: 3px;\n  color:#333;\n  text-align: justify;\n  font-size: 14px;\n  font-weight: 300;\n  padding-left: 0px;\n}\n\n.viz_large_text{\n  width:99%;\n  margin: 0 auto;\n  margin-top: 6px;\n  margin-bottom: 3px;\n  color:#333;\n  text-align: justify;\n  font-size: 16px;\n  font-weight: 300;\n  padding-left: 0px;\n}\n\n/* need to move d3-tip into stypes */\n.d3-tip {\n  line-height: 1.25;\n  font-weight: bold;\n  padding: 12px;\n  background: rgba(0, 0, 0, 0.8);\n  color: #fff;\n  border-radius: 2px;\n  max-width: 500px;\n}\n\n/* Style northward tooltips differently */\n.d3-tip.n:after {\n  margin: -1px 0 0 0;\n  top: 100%;\n  left: 0;\n}\n\n.noselect {\n    -webkit-touch-callout: none;\n    -webkit-user-select: none;\n    -khtml-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n}\n\n\n.icon_buttons{\n  color: #337ab7;\n}\n\n.sidebar_text{\n  font-weight: 300;\n  font-size: 12px;\n  line-height: 1.1;\n}\n\n.sidebar_button_text{\n  font-size: 13px;\n  font-weight: 300;\n}\n\n.btn{\n  padding-top:2px;\n  padding-bottom:2px;\n}\n\n.toggle_row_order{\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n\n.modal-backdrop{\n  display: none;\n}\n\n.modal-backdrop.fade{\n  display: none;\n}\n\n.modal-backdrop.in{\n  display: none;\n}\n\n/* sidebar tooltips */\n.sidebar_tooltip {\n    position: relative;\n    display: inline-block;\n}\n\n.sidebar_tooltip .sidebar_tooltip_text {\n    visibility: hidden;\n    width: 120px;\n    background: rgba(0, 0, 0, 1);\n    /*opacity: 0.95;*/\n    color: #fff;\n    text-align: center;\n    border-radius: 6px;\n    padding: 5px 0;\n\n    position: absolute;\n    z-index: 1000;\n    top:100%;\n    /*left:-400%;*/\n    font-size: 15px;\n    /*margin-left: 60px;*/\n    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n    font-size: 13px;\n    font-weight: bold;\n}\n\n.sidebar_tooltip:hover .sidebar_tooltip_text {\n    visibility: visible;\n}", ""]);
	
	// exports


/***/ }),
/* 16 */
/***/ (function(module, exports) {

	/*
		MIT License http://www.opensource.org/licenses/mit-license.php
		Author Tobias Koppers @sokra
	*/
	// css base code, injected by the css-loader
	module.exports = function() {
		var list = [];
	
		// return the list of modules as css string
		list.toString = function toString() {
			var result = [];
			for(var i = 0; i < this.length; i++) {
				var item = this[i];
				if(item[2]) {
					result.push("@media " + item[2] + "{" + item[1] + "}");
				} else {
					result.push(item[1]);
				}
			}
			return result.join("");
		};
	
		// import a list of modules into the list
		list.i = function(modules, mediaQuery) {
			if(typeof modules === "string")
				modules = [[null, modules, ""]];
			var alreadyImportedModules = {};
			for(var i = 0; i < this.length; i++) {
				var id = this[i][0];
				if(typeof id === "number")
					alreadyImportedModules[id] = true;
			}
			for(i = 0; i < modules.length; i++) {
				var item = modules[i];
				// skip already imported module
				// this implementation is not 100% perfect for weird media query combinations
				//  when a module is imported multiple times with different media queries.
				//  I hope this will never occur (Hey this way we have smaller bundles)
				if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) {
					if(mediaQuery && !item[2]) {
						item[2] = mediaQuery;
					} else if(mediaQuery) {
						item[2] = "(" + item[2] + ") and (" + mediaQuery + ")";
					}
					list.push(item);
				}
			}
		};
		return list;
	};


/***/ }),
/* 17 */
/***/ (function(module, exports, __webpack_require__) {

	/*
		MIT License http://www.opensource.org/licenses/mit-license.php
		Author Tobias Koppers @sokra
	*/
	var stylesInDom = {},
		memoize = function(fn) {
			var memo;
			return function () {
				if (typeof memo === "undefined") memo = fn.apply(this, arguments);
				return memo;
			};
		},
		isOldIE = memoize(function() {
			return /msie [6-9]\b/.test(self.navigator.userAgent.toLowerCase());
		}),
		getHeadElement = memoize(function () {
			return document.head || document.getElementsByTagName("head")[0];
		}),
		singletonElement = null,
		singletonCounter = 0,
		styleElementsInsertedAtTop = [];
	
	module.exports = function(list, options) {
		if(false) {
			if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
		}
	
		options = options || {};
		// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
		// tags it will allow on a page
		if (typeof options.singleton === "undefined") options.singleton = isOldIE();
	
		// By default, add <style> tags to the bottom of <head>.
		if (typeof options.insertAt === "undefined") options.insertAt = "bottom";
	
		var styles = listToStyles(list);
		addStylesToDom(styles, options);
	
		return function update(newList) {
			var mayRemove = [];
			for(var i = 0; i < styles.length; i++) {
				var item = styles[i];
				var domStyle = stylesInDom[item.id];
				domStyle.refs--;
				mayRemove.push(domStyle);
			}
			if(newList) {
				var newStyles = listToStyles(newList);
				addStylesToDom(newStyles, options);
			}
			for(var i = 0; i < mayRemove.length; i++) {
				var domStyle = mayRemove[i];
				if(domStyle.refs === 0) {
					for(var j = 0; j < domStyle.parts.length; j++)
						domStyle.parts[j]();
					delete stylesInDom[domStyle.id];
				}
			}
		};
	}
	
	function addStylesToDom(styles, options) {
		for(var i = 0; i < styles.length; i++) {
			var item = styles[i];
			var domStyle = stylesInDom[item.id];
			if(domStyle) {
				domStyle.refs++;
				for(var j = 0; j < domStyle.parts.length; j++) {
					domStyle.parts[j](item.parts[j]);
				}
				for(; j < item.parts.length; j++) {
					domStyle.parts.push(addStyle(item.parts[j], options));
				}
			} else {
				var parts = [];
				for(var j = 0; j < item.parts.length; j++) {
					parts.push(addStyle(item.parts[j], options));
				}
				stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts};
			}
		}
	}
	
	function listToStyles(list) {
		var styles = [];
		var newStyles = {};
		for(var i = 0; i < list.length; i++) {
			var item = list[i];
			var id = item[0];
			var css = item[1];
			var media = item[2];
			var sourceMap = item[3];
			var part = {css: css, media: media, sourceMap: sourceMap};
			if(!newStyles[id])
				styles.push(newStyles[id] = {id: id, parts: [part]});
			else
				newStyles[id].parts.push(part);
		}
		return styles;
	}
	
	function insertStyleElement(options, styleElement) {
		var head = getHeadElement();
		var lastStyleElementInsertedAtTop = styleElementsInsertedAtTop[styleElementsInsertedAtTop.length - 1];
		if (options.insertAt === "top") {
			if(!lastStyleElementInsertedAtTop) {
				head.insertBefore(styleElement, head.firstChild);
			} else if(lastStyleElementInsertedAtTop.nextSibling) {
				head.insertBefore(styleElement, lastStyleElementInsertedAtTop.nextSibling);
			} else {
				head.appendChild(styleElement);
			}
			styleElementsInsertedAtTop.push(styleElement);
		} else if (options.insertAt === "bottom") {
			head.appendChild(styleElement);
		} else {
			throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'.");
		}
	}
	
	function removeStyleElement(styleElement) {
		styleElement.parentNode.removeChild(styleElement);
		var idx = styleElementsInsertedAtTop.indexOf(styleElement);
		if(idx >= 0) {
			styleElementsInsertedAtTop.splice(idx, 1);
		}
	}
	
	function createStyleElement(options) {
		var styleElement = document.createElement("style");
		styleElement.type = "text/css";
		insertStyleElement(options, styleElement);
		return styleElement;
	}
	
	function createLinkElement(options) {
		var linkElement = document.createElement("link");
		linkElement.rel = "stylesheet";
		insertStyleElement(options, linkElement);
		return linkElement;
	}
	
	function addStyle(obj, options) {
		var styleElement, update, remove;
	
		if (options.singleton) {
			var styleIndex = singletonCounter++;
			styleElement = singletonElement || (singletonElement = createStyleElement(options));
			update = applyToSingletonTag.bind(null, styleElement, styleIndex, false);
			remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true);
		} else if(obj.sourceMap &&
			typeof URL === "function" &&
			typeof URL.createObjectURL === "function" &&
			typeof URL.revokeObjectURL === "function" &&
			typeof Blob === "function" &&
			typeof btoa === "function") {
			styleElement = createLinkElement(options);
			update = updateLink.bind(null, styleElement);
			remove = function() {
				removeStyleElement(styleElement);
				if(styleElement.href)
					URL.revokeObjectURL(styleElement.href);
			};
		} else {
			styleElement = createStyleElement(options);
			update = applyToTag.bind(null, styleElement);
			remove = function() {
				removeStyleElement(styleElement);
			};
		}
	
		update(obj);
	
		return function updateStyle(newObj) {
			if(newObj) {
				if(newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap)
					return;
				update(obj = newObj);
			} else {
				remove();
			}
		};
	}
	
	var replaceText = (function () {
		var textStore = [];
	
		return function (index, replacement) {
			textStore[index] = replacement;
			return textStore.filter(Boolean).join('\n');
		};
	})();
	
	function applyToSingletonTag(styleElement, index, remove, obj) {
		var css = remove ? "" : obj.css;
	
		if (styleElement.styleSheet) {
			styleElement.styleSheet.cssText = replaceText(index, css);
		} else {
			var cssNode = document.createTextNode(css);
			var childNodes = styleElement.childNodes;
			if (childNodes[index]) styleElement.removeChild(childNodes[index]);
			if (childNodes.length) {
				styleElement.insertBefore(cssNode, childNodes[index]);
			} else {
				styleElement.appendChild(cssNode);
			}
		}
	}
	
	function applyToTag(styleElement, obj) {
		var css = obj.css;
		var media = obj.media;
	
		if(media) {
			styleElement.setAttribute("media", media)
		}
	
		if(styleElement.styleSheet) {
			styleElement.styleSheet.cssText = css;
		} else {
			while(styleElement.firstChild) {
				styleElement.removeChild(styleElement.firstChild);
			}
			styleElement.appendChild(document.createTextNode(css));
		}
	}
	
	function updateLink(linkElement, obj) {
		var css = obj.css;
		var sourceMap = obj.sourceMap;
	
		if(sourceMap) {
			// http://stackoverflow.com/a/26603875
			css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */";
		}
	
		var blob = new Blob([css], { type: "text/css" });
	
		var oldSrc = linkElement.href;
	
		linkElement.href = URL.createObjectURL(blob);
	
		if(oldSrc)
			URL.revokeObjectURL(oldSrc);
	}


/***/ }),
/* 18 */
/***/ (function(module, exports) {

	module.exports = {"name":"clustergrammer_gl","version":"0.1.1","description":"clustergrammer_gl","author":"Nicolas Fernandez","license":"MIT","main":"src/index.js","repository":{"type":"git","url":"https://github.com/maayanlab/clustergrammer_gl.git"},"keywords":["jupyter","widgets","ipython","ipywidgets"],"scripts":{"prepublish":"webpack","test":"echo \"Error: no test specified\" && exit 1"},"devDependencies":{"css-loader":"^0.25.0","file-loader":"^0.10.0","json-loader":"^0.5.4","webpack":"^1.12.14"},"dependencies":{"clustergrammer":"v1.19.5","clustergrammer2-alpha":"0.1.2","d3":"^3.5.8","jupyter-js-widgets":"^1.1.1","underscore":"^1.8.3"}}

/***/ })
/******/ ])});;
//# sourceMappingURL=index.js.map