/* Minification failed. Returning unminified contents.
(10638,14-15): run-time error JS1003: Expected ':': ,
(10638,27-28): run-time error JS1003: Expected ':': ,
(10638,40-41): run-time error JS1003: Expected ':': ,
(10639,9-10): run-time error JS1003: Expected ':': }
(10712,18-19): run-time error JS1003: Expected ':': ,
(10712,31-32): run-time error JS1003: Expected ':': ,
(10712,44-45): run-time error JS1003: Expected ':': ,
(10713,13-14): run-time error JS1003: Expected ':': }
 */
(function() {
  var fetch, requests_cache, _ref,
    __slice = [].slice;

  if ((_ref = this.mx) == null) {
    this.mx = {};
  }

  requests_cache = {};

  fetch = function() {
    var args, cache_key, cached_request, descriptor, expires_at, name, now, options, result, scope, _ref1, _ref2;

    scope = arguments[0], name = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
    descriptor = scope.fetch_descriptors[name];
    if (descriptor == null) {
      return void 0;
    }
    options = _.takeRight(args);
    if (!(_.isObject(options) && !_.isArray(options))) {
      options = {};
    }
    cache_key = JSON.stringify([name, ((_ref1 = descriptor.cache_key) != null ? _ref1 : _.identity).apply(null, args), mx.locale()]);
    cached_request = requests_cache[cache_key];
    now = +(new Date);
    expires_at = options.expires_in != null ? now + options.expires_in : void 0;
    if (cached_request != null) {
      if (cached_request.state() === 'pending') {
        return cached_request;
      }
      if ((cached_request.expires_at != null) && (expires_at != null) && cached_request.expires_at > now) {
        return cached_request;
      }
      if (options.force !== true) {
        return cached_request;
      }
    }
    cached_request = new $.Deferred;
    result = {};

    
    scope.url_prefix = window.moex.iss.baseUrl;

    

      //console.log("> " + scope.url_prefix + descriptor.url.apply(descriptor, args));
    //console.log(">>>> descriptor: " + descriptor.url);
    //console.log(">>>> args: " + args);
    //console.log(">>>> " + descriptor.url.apply(descriptor, args));
    //jQuery.support.cors = true;
    $.ajax({
      url: scope.url_prefix + descriptor.url.apply(descriptor, args),
      data: $.extend((_ref2 = typeof descriptor.xhr_data === "function" ? descriptor.xhr_data.apply(descriptor, args) : void 0) != null ? _ref2 : {}, {
        'iss.meta': 'off',
        'lang': mx.I18n.locale
      }),
      cache: false,
      dataType: 'jsonp',
      xhrFields: {
        withCredentials: true
      }
    }).done(function (json, status, xhr) {
        // console.log("json:");
      return result.data = descriptor.parse(json, args);
    }).fail(function (xhr, status, error) {
        // console.log("error:" + error);
      return result.error = error;
    }).always(function(data_or_xhr, status, xhr_or_error) {
      var xhr;

      xhr = status === 'success' ? xhr_or_error : data_or_xhr;
      result['x-marker'] = xhr.getResponseHeader('X-MicexPassport-Marker');

      return cached_request.resolve(result);
    });
    return requests_cache[cache_key] = cached_request.promise({
      result: result,
      expires_at: expires_at
    });
  };

  $.extend(this.mx, {
    url: 'https://www.moex.com',
    fetch: fetch
  });

}).call(this);
;
/*! Kizzy - a cross-browser LocalStorage API
  * Copyright: Dustin Diaz 2011
  * https://github.com/ded/kizzy
  * License: MIT
  */

!function (win, doc, store) {

  function noop() {}

  var hasLocalStorage,
      html5 = 0,
      writeThrough = function () {
        return 1;
      };


  try {
    // HTML5 local storage
    hasLocalStorage = !!localStorage || !!globalStorage;
    if (!localStorage) {
      localStorage = globalStorage[store];
    }
    html5 = 1;
  } catch (ex1) {
    html5 = 0;
    // IE local storage
    try {
      // this try / if is required. trust me
      if (doc.documentElement.addBehavior) {
        html5 = 0;
        hasLocalStorage = 1;
        var dataStore = doc.documentElement;
        dataStore.addBehavior('#default#userData');
        dataStore.load(store);
        var xmlDoc = dataStore.xmlDocument;
        var xmlDocEl = xmlDoc.documentElement;
      }
    } catch (ex2) {
      hasLocalStorage = false;
    }
  }

  var setLocalStorage = noop,
      getLocalStorage = noop,
      removeLocalStorage = noop,
      clearLocalStorage = noop;

  if (hasLocalStorage) {
    setLocalStorage = html5 ? html5setLocalStorage : setUserData;
    getLocalStorage = html5 ? html5getLocalStorage : getUserData;
    removeLocalStorage = html5 ? html5removeLocalStorage : removeUserData;
    clearLocalStorage = html5 ? html5clearLocalStorage : clearUserData;

    writeThrough = function (inst) {
      try {
        var v = JSON.stringify(inst._);
        if( v == '{}' ) {
          removeLocalStorage(inst.ns);
        } else {
          setLocalStorage(inst.ns, v);
        }
        return 1;
      } catch (x) {
        return 0;
      }
    };
  }


  function time() {
    return +new Date();
  }

  function checkExpiry(inst, k) {
    if (inst._[k] && inst._[k].e && inst._[k].e < time()) {
      inst.remove(k);
    }
  }

  function isNumber(n) {
    return typeof n === 'number' && isFinite(n);
  }

  function html5getLocalStorage(k) {
    return localStorage[k];
  }

  function html5setLocalStorage(k, v) {
    localStorage[k] = v;
    return v;
  }

  function html5removeLocalStorage(k) {
    delete localStorage[k];
  }

  function html5clearLocalStorage() {
    localStorage.clear();
  }

  function getNodeByName(name) {
    var childNodes = xmlDocEl.childNodes,
        node,
        returnVal = null;

    for (var i = 0, len = childNodes.length; i < len; i++) {
      node = childNodes.item(i);
      if (node.getAttribute("key") == name) {
        returnVal = node;
        break;
      }
    }
    return returnVal;
  }

  function getUserData(name) {
    var node = getNodeByName(name);
    var returnVal = null;
    if (node) {
      returnVal = node.getAttribute("value");
    }
    return returnVal;
  }

  function setUserData(name, value) {
    var node = getNodeByName(name);
    if (!node) {
      node = xmlDoc.createNode(1, "item", "");
      node.setAttribute("key", name);
      node.setAttribute("value", value);
      xmlDocEl.appendChild(node);
    }
    else {
      node.setAttribute("value", value);
    }
    dataStore.save(store);
    return value;
  }

  function removeUserData(name) {
    getNodeByName(name) && xmlDocEl.removeChild(node);
    dataStore.save(store);
  }

  function clearUserData() {
    while (xmlDocEl.firstChild) {
      xmlDocEl.removeChild(xmlDocEl.firstChild);
    }
    dataStore.save(store);
  }

  function _Kizzy() {
    this._ = {};
  }

  _Kizzy.prototype = {

    set: function (k, v, optTtl) {
      this._[k] = {
        value: v,
        e: isNumber(optTtl) ? time() + optTtl : 0
      };
      writeThrough(this) || this.remove(k);
      return v;
    },

    get: function (k) {
      checkExpiry(this, k);
      return this._[k] ? this._[k].value : undefined;
    },

    remove: function (k) {
      delete this._[k];
      writeThrough(this);
    },

    clear: function () {
      this._ = {};
      writeThrough(this);
    },
    
    clearExpireds: function() {
      for( var k in this._ ) {
        checkExpiry(this,k);
      }
      writeThrough(this);
    }
  };

  function Kizzy(ns) {
    this.ns = ns;
    this._ = JSON.parse(getLocalStorage(ns) || '{}');
  }

  Kizzy.prototype = _Kizzy.prototype;

  function kizzy(ns) {
    return new Kizzy(ns);
  }

  kizzy.remove = removeLocalStorage;
  kizzy.clear = clearLocalStorage;

  win.kizzy = kizzy;

  typeof module !== 'undefined' && module.exports && (module.exports.cache = kizzy);

}(this, document, document.domain);
;
(function() {
  var datetime_format_pad, datetime_format_pads, datetime_formats, i18n, localize, replace_datetime_format_token, root, to_date, to_datetime, to_number, to_percentage, to_time, _base, _ref, _ref1;

  root = this;

  if ((_ref = root['mx']) == null) {
    root['mx'] = {};
  }

  if ((_ref1 = (_base = root['mx']).I18n) == null) {
    _base.I18n = {};
  }

  i18n = root['mx'].I18n;

  i18n.add_translations('ru', {
    date: {
      day_names: ['воскресение', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота']
    }
  });

  i18n.add_translations('en', {
    date: {
      day_names: ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']
    }
  });

  localize = function() {
    var options, value;

    options = arguments.length > 1 && $.isPlainObject(arguments[arguments.length - 1]) ? arguments[arguments.length - 1] : {};
    return value = arguments[0];
  };

  to_number = function(value, options) {
    if (options == null) {
      options = {};
    }
  };

  to_percentage = function(value, options) {
    if (options == null) {
      options = {};
    }
  };

  to_date = function(value, options) {
    if (options == null) {
      options = {};
    }
    return to_datetime(value, $.extend({
      format: i18n.translate('date.formats.default')
    }, options));
  };

  to_time = function(value, options) {
    if (options == null) {
      options = {};
    }
    return to_datetime(value, $.extend({
      format: i18n.translate('time.formats.default')
    }, options));
  };

  to_datetime = function(value, options) {
    if (options == null) {
      options = {};
    }
    if ($.type(value) !== 'date') {
      return value;
    }
    options = $.extend({
      format: [
        i18n.translate('date.formats.default', {
          locale: options.locale
        }), i18n.translate('time.formats.default', {
          locale: options.locale
        })
      ].join(' ')
    }, options);
    return replace_datetime_format_token(options.format, value, options);
  };

  replace_datetime_format_token = function(format, value, options) {
    var after, before, index, padding, part, _ref2;

    index = format.indexOf('%');
    if (index === -1) {
      return format;
    }
    _ref2 = [format.slice(0, index), format.slice(index + 1)], before = _ref2[0], after = _ref2[1];
    part = '';
    padding = '0';
    if (datetime_format_pads[after.charAt(0)] != null) {
      padding = datetime_format_pads[after.charAt(0)];
      after = after.slice(1);
    }
    if (datetime_formats[after.charAt(0)]) {
      part = datetime_formats[after.charAt(0)](value, padding, options);
      after = after.slice(1);
    }
    return [before, part, replace_datetime_format_token(after, value, options)].join('');
  };

  datetime_format_pads = {
    '-': '',
    '_': ' ',
    '0': '0'
  };

  datetime_format_pad = function(v, f, n) {
    return (new Array(n + 1).join(f) + v).slice(-n);
  };

  datetime_formats = {
    'A': function(v, p) {
      return i18n.translate('date.day_names')[v.getDay()];
    },
    'd': function(v, p) {
      return datetime_format_pad(v.getDate(), p, 2);
    },
    'H': function(v, p) {
      return datetime_format_pad(v.getHours(), p, 2);
    },
    'm': function(v, p) {
      return datetime_format_pad(v.getMonth() + 1, p, 2);
    },
    'M': function(v, p) {
      return datetime_format_pad(v.getMinutes(), p, 2);
    },
    'S': function(v, p) {
      return datetime_format_pad(v.getSeconds(), p, 2);
    },
    'y': function(v, p) {
      return datetime_format_pad(v.getYear(), p, 2);
    },
    'Y': function(v, p) {
      return datetime_format_pad(v.getFullYear(), p, 4);
    },
    '%': function() {
      return '%';
    }
  };

  $.extend(i18n, {
    localize: localize,
    l: localize,
    to_number: to_number,
    to_percentage: to_percentage,
    to_date: to_date,
    to_time: to_time,
    to_datetime: to_datetime
  });

}).call(this);
;
(function() {
  mx.I18n.add_translations('en', {
    number: {
      format: {
        separator: '.',
        delimiter: ','
      }
    },
    date: {
      formats: {
        "default": '%m/%d/%Y'
      }
    },
    time: {
      formats: {
        "default": '%H:%M:%S'
      }
    },
    csv: {
      separator_formats: [[';', ';'], [',', ',']],
      decimal_mark_formats: [[',', 'comma'], ['.', 'point']],
      date_formats: [['yyyymmdd', '%Y%m%d'], ['yymmdd', '%y%m%d'], ['ddmmyyyy', '%d%m%Y'], ['ddmmyy', '%d%m%y'], ['dd.mm.yyyy', '%d.%m.%Y'], ['dd.mm.yy', '%d.%m.%y'], ['dd/mm/yyyy', '%d/%m/%Y'], ['dd/mm/yy', '%d/%m/%y'], ['mm/dd/yyyy', '%m/%d/%Y'], ['mm/dd/yy', '%m/%d/%y']],
      time_formats: [['hhmmss', '%H%M%S'], ['hhmm', '%H%M'], ['hh:mm:ss', '%H:%M:%S'], ['hh:mm', '%H:%M']]
    }
  });

  mx.I18n.add_translations('ru', {
    number: {
      formats: {
        separator: ',',
        delimiter: ' '
      }
    },
    date: {
      formats: {
        "default": '%d.%m.%Y'
      }
    },
    time: {
      formats: {
        "default": '%H:%M:%S'
      }
    },
    csv: {
      separator_formats: [[';', ';'], [',', ',']],
      decimal_mark_formats: [[',', 'comma'], ['.', 'point']],
      date_formats: [['ггггммдд', '%Y%m%d'], ['ггммдд', '%y%m%d'], ['ддммгггг', '%d%m%Y'], ['ддммгг', '%d%m%y'], ['дд.мм.гггг', '%d.%m.%Y'], ['дд.мм.гг', '%d.%m.%y'], ['дд/мм/гггг', '%d/%m/%Y'], ['дд/мм/гг', '%d/%m/%y'], ['мм/дд/гггг', '%m/%d/%Y'], ['мм/дд/гг', '%m/%d/%y']],
      time_formats: [['ччммсс', '%H%M%S'], ['ччмм', '%H%M'], ['чч:мм:сс', '%H:%M:%S'], ['чч:мм', '%H:%M']]
    }
  });

}).call(this);
;
(function() {
  var cache, fields, known_data_types, make_csv_options_widget, make_market_history_url, month_names, toggle;

  cache = kizzy('csv-options');

  known_data_types = 'csv xml'.split(' ');

  make_market_history_url = function(engine, market, type, date) {
    var csv_options;

    csv_options = Object.keys(fields.mapping).map(function(key) {
      if (cache.get(key) != null) {
        return "" + fields.mapping[key] + "=" + (encodeURIComponent(cache.get(key)));
      } else {
        return void 0;
      }
    }).filter(function(value) {
      return !!value;
    }).join('&');
    csv_options = type === 'csv' && csv_options.length > 0 ? '&' + csv_options : '';
    return ("" + mx.url + "/iss/history/engines/" + engine + "/markets/" + market + "/securities." + type + "?date=" + (mx.I18n.to_date(date, {
      format: '%Y-%m-%d'
    })) + "&lang=" + mx.I18n.locale) + csv_options;
  };

  month_names = {
    ru: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"],
    en: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
  };

  fields = {
    order: ['separator_formats', 'decimal_mark_formats', 'date_formats', 'time_formats'],
    mapping: {
      separator_formats: 'iss.delimiter',
      decimal_mark_formats: 'iss.dp',
      date_formats: 'iss.df',
      time_formats: 'iss.tf'
    },
    ru: {
      separator_formats: 'Разделитель полей',
      decimal_mark_formats: 'Десятичный разделитель',
      date_formats: 'Формат даты',
      time_formats: 'Формат времени'
    },
    en: {
      separator_formats: 'Fields separator',
      decimal_mark_formats: 'Decimal mark',
      date_formats: 'Date format',
      time_formats: 'Time format'
    }
  };

  make_csv_options_widget = function() {
    var list;

    list = $('<dl>').addClass('csv-options');
    fields.order.forEach(function(field) {
      var select;

      $('<dt>').html(fields[mx.I18n.locale][field]).appendTo(list);
      select = $('<select>').attr('name', field);
      mx.I18n.t(['csv', field]).forEach(function(item) {
        return $('<option>').attr('value', item[1]).attr('selected', item[1] === cache.get(field)).html(item[0]).appendTo(select);
      });
      return $('<dd>').append(select).appendTo(list);
    });
    list.on('change', 'select', function(event) {
      return $('select', list).serializeArray().forEach(function(item) {
        return cache.set(item.name, item.value);
      });
    });
    return list.hide();
  };

  toggle = function(element) {
    return element.toggle('blind', {
      direction: 'vertical'
    }, 100);
  };

  $(document).on('click', '.table_container h4 a.market-history[data-market]', function(event) {
    var datepicker_element, element;

    event.preventDefault();
    element = $(this);
    datepicker_element = $('.datepicker', element.next('.down-slider'));
    if (!datepicker_element.hasClass('hasDatepicker')) {
      datepicker_element.datepicker({
        monthNames: month_names[mx.I18n.locale]
      });
    }
    return toggle(element.next('.down-slider'));
  });

  $(document).on('click', '.table_container h4 button[data-type]', function(event) {
    var date, el, engine, market, type, _ref;

    el = $(this);
    type = el.data('type');
    if (known_data_types.indexOf(type) < 0) {
      return;
    }
    _ref = $('a[data-market]', el.closest('h4')).data('market').split(':'), engine = _ref[0], market = _ref[1];
    date = $('.datepicker', el.closest('h4')).datepicker('getDate');
    return window.open(make_market_history_url(engine, market, type, date));
  });

  $(document).on('click', '.table_container h4 button.dropdown-toggle', function(event) {
    var csv_options, el;

    el = $(this);
    csv_options = $('.csv-options', el.closest('h4'));
    if (csv_options.length === 0) {
      csv_options = make_csv_options_widget().appendTo(el.closest('.down-slider-content'));
    }
    el.toggleClass('open');
    return toggle(csv_options);
  });

}).call(this);
;
(function() {
  var merge, root, scope, url_prefix,
    __slice = [].slice;

  root = this;

  if (root['mx'] == null) {
    root['mx'] = {};
  }

  if (!root['mx']['iss'])
      root['mx']['iss'] = {};
      
  /*if (!navigator.userAgent.match(/firefox/i))
  {
     root['mx']['iss'] = {};
  }*/
    
  scope = root['mx']['iss'];

  url_prefix = '/iss';

  if ($.support.cors) {
    url_prefix = mx.url + url_prefix;
  }

  merge = function(json) {
    var column, datum, index, item, _i, _j, _len, _len1, _ref, _ref1, _results;
    if (!(json && (json.data != null) && (json.columns != null))) {
      return [];
    }
    _ref = json.data;
    _results = [];
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      datum = _ref[_i];
      item = {};
      _ref1 = json.columns;
      for (index = _j = 0, _len1 = _ref1.length; _j < _len1; index = ++_j) {
        column = _ref1[index];
        item[column] = datum[index];
      }
      _results.push(item);
    }
    return _results;
  };

  $.extend(scope, {
    url_prefix: url_prefix,
    fetch: function() {
      return mx.fetch.apply(mx, [scope].concat(__slice.call(arguments)));
    },
    fetch_descriptors: {},
    merge_columns_and_data: merge
  });

}).call(this);
;
(function() {
  var $, fetch, keys, scope,
    __slice = [].slice;

  $ = jQuery;

  scope = this.mx.iss;

  keys = ['engines', 'markets', 'boards', 'boardgroups', 'durations'];

  fetch = function() {
    return scope.fetch.apply(scope, ['metadata'].concat(__slice.call(arguments)));
  };

  $.extend(scope, {
    metadata: fetch
  });

  $.extend(scope.fetch_descriptors, {
    metadata: {
      cache_key: function() {
        return "";
      },
      url: function() {
        return "/index.jsonp";
      },
      xhr_data: function() {
        return {
          'iss.only': keys.join(',')
        };
      },
      parse: function(json) {
        return keys.reduce((function(memo, key) {
          memo[key] = scope.merge_columns_and_data(json != null ? json[key] : void 0);
          return memo;
        }), {});
      }
    }
  });

}).call(this);
;
(function() {
  var d3_format_decimalPoint = ".", d3_format_thousandsSeparator = ",", d3_format_grouping = [ 3, 3 ];
  if (!Date.now) Date.now = function() {
    return +new Date();
  };
  try {
    document.createElement("div").style.setProperty("opacity", 0, "");
  } catch (error) {
    var d3_style_prototype = CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty;
    d3_style_prototype.setProperty = function(name, value, priority) {
      d3_style_setProperty.call(this, name, value + "", priority);
    };
  }
  d3 = {
    version: "3.0.4"
  };
  var π = Math.PI, ε = 1e-6, d3_radians = π / 180, d3_degrees = 180 / π;
  function d3_target(d) {
    return d.target;
  }
  function d3_source(d) {
    return d.source;
  }
  function d3_class(ctor, properties) {
    try {
      for (var key in properties) {
        Object.defineProperty(ctor.prototype, key, {
          value: properties[key],
          enumerable: false
        });
      }
    } catch (e) {
      ctor.prototype = properties;
    }
  }
  var d3_array = d3_arraySlice;
  function d3_arrayCopy(pseudoarray) {
    var i = -1, n = pseudoarray.length, array = [];
    while (++i < n) array.push(pseudoarray[i]);
    return array;
  }
  function d3_arraySlice(pseudoarray) {
    return Array.prototype.slice.call(pseudoarray);
  }
  try {
    d3_array(document.documentElement.childNodes)[0].nodeType;
  } catch (e) {
    d3_array = d3_arrayCopy;
  }
  var d3_arraySubclass = [].__proto__ ? function(array, prototype) {
    array.__proto__ = prototype;
  } : function(array, prototype) {
    for (var property in prototype) array[property] = prototype[property];
  };
  d3.map = function(object) {
    var map = new d3_Map();
    for (var key in object) map.set(key, object[key]);
    return map;
  };
  function d3_Map() {}
  d3_class(d3_Map, {
    has: function(key) {
      return d3_map_prefix + key in this;
    },
    get: function(key) {
      return this[d3_map_prefix + key];
    },
    set: function(key, value) {
      return this[d3_map_prefix + key] = value;
    },
    remove: function(key) {
      key = d3_map_prefix + key;
      return key in this && delete this[key];
    },
    keys: function() {
      var keys = [];
      this.forEach(function(key) {
        keys.push(key);
      });
      return keys;
    },
    values: function() {
      var values = [];
      this.forEach(function(key, value) {
        values.push(value);
      });
      return values;
    },
    entries: function() {
      var entries = [];
      this.forEach(function(key, value) {
        entries.push({
          key: key,
          value: value
        });
      });
      return entries;
    },
    forEach: function(f) {
      for (var key in this) {
        if (key.charCodeAt(0) === d3_map_prefixCode) {
          f.call(this, key.substring(1), this[key]);
        }
      }
    }
  });
  var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0);
  function d3_identity(d) {
    return d;
  }
  function d3_true() {
    return true;
  }
  function d3_functor(v) {
    return typeof v === "function" ? v : function() {
      return v;
    };
  }
  d3.functor = d3_functor;
  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 arguments.length ? target : value;
    };
  }
  d3.ascending = function(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.mean = function(array, f) {
    var n = array.length, a, m = 0, i = -1, j = 0;
    if (arguments.length === 1) {
      while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;
    } else {
      while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j;
    }
    return j ? m : undefined;
  };
  d3.median = function(array, f) {
    if (arguments.length > 1) array = array.map(f);
    array = array.filter(d3_number);
    return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined;
  };
  d3.min = function(array, f) {
    var i = -1, n = array.length, a, b;
    if (arguments.length === 1) {
      while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;
      while (++i < n) if ((b = array[i]) != null && a > b) a = b;
    } else {
      while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;
      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 && ((a = array[i]) == null || a != a)) a = undefined;
      while (++i < n) if ((b = array[i]) != null && b > a) a = b;
    } else {
      while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;
      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 && ((a = c = array[i]) == null || a != a)) a = c = undefined;
      while (++i < n) if ((b = array[i]) != null) {
        if (a > b) a = b;
        if (c < b) c = b;
      }
    } else {
      while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined;
      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 ];
  };
  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 n = arguments.length;
      if (n < 2) σ = 1;
      if (n < 1) µ = 0;
      var random = d3.random.normal();
      return function() {
        return Math.exp(µ + σ * random());
      };
    },
    irwinHall: function(m) {
      return function() {
        for (var s = 0, j = 0; j < m; j++) s += Math.random();
        return s / m;
      };
    }
  };
  function d3_number(x) {
    return x != null && !isNaN(x);
  }
  d3.sum = function(array, f) {
    var s = 0, n = array.length, a, i = -1;
    if (arguments.length === 1) {
      while (++i < n) if (!isNaN(a = +array[i])) s += a;
    } else {
      while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a;
    }
    return s;
  };
  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.shuffle = function(array) {
    var m = array.length, t, i;
    while (m) {
      i = Math.random() * m-- | 0;
      t = array[m], array[m] = array[i], array[i] = t;
    }
    return array;
  };
  d3.transpose = function(matrix) {
    return d3.zip.apply(d3, matrix);
  };
  d3.zip = function() {
    if (!(n = arguments.length)) return [];
    for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) {
      for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) {
        zip[j] = arguments[j][i];
      }
    }
    return zips;
  };
  function d3_zipLength(d) {
    return d.length;
  }
  d3.bisector = function(f) {
    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 (f.call(a, a[mid], mid) < x) 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 (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1;
        }
        return lo;
      }
    };
  };
  var d3_bisector = d3.bisector(function(d) {
    return d;
  });
  d3.bisectLeft = d3_bisector.left;
  d3.bisect = d3.bisectRight = d3_bisector.right;
  d3.nest = function() {
    var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
    function map(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, valuesByKey = new d3_Map(), values, o = {};
      while (++i < n) {
        if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
          values.push(object);
        } else {
          valuesByKey.set(keyValue, [ object ]);
        }
      }
      valuesByKey.forEach(function(keyValue, values) {
        o[keyValue] = map(values, depth);
      });
      return o;
    }
    function entries(map, depth) {
      if (depth >= keys.length) return map;
      var a = [], sortKey = sortKeys[depth++], key;
      for (key in map) {
        a.push({
          key: key,
          values: entries(map[key], depth)
        });
      }
      if (sortKey) a.sort(function(a, b) {
        return sortKey(a.key, b.key);
      });
      return a;
    }
    nest.map = function(array) {
      return map(array, 0);
    };
    nest.entries = function(array) {
      return entries(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.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.permute = function(array, indexes) {
    var permutes = [], i = -1, n = indexes.length;
    while (++i < n) permutes[i] = array[indexes[i]];
    return permutes;
  };
  d3.merge = function(arrays) {
    return Array.prototype.concat.apply([], arrays);
  };
  function d3_collapse(s) {
    return s.trim().replace(/\s+/g, " ");
  }
  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(Math.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;
  }
  d3.requote = function(s) {
    return s.replace(d3_requote_re, "\\$&");
  };
  var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
  d3.round = function(x, n) {
    return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);
  };
  d3.xhr = function(url, mimeType, callback) {
    var xhr = {}, dispatch = d3.dispatch("progress", "load", "error"), headers = {}, response = d3_identity, request = new (window.XDomainRequest && /^(http(s)?:)?\/\//.test(url) ? XDomainRequest : XMLHttpRequest)();
    "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() {
      request.readyState > 3 && respond();
    };
    function respond() {
      var s = request.status;
      !s && request.responseText || s >= 200 && s < 300 || s === 304 ? dispatch.load.call(xhr, response.call(xhr, request)) : 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.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 (callback != null) xhr.on("error", callback).on("load", function(request) {
        callback(null, request);
      });
      request.send(data == null ? null : data);
      return xhr;
    };
    xhr.abort = function() {
      request.abort();
      return xhr;
    };
    d3.rebind(xhr, dispatch, "on");
    if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, 
    mimeType = null;
    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;
  }
  d3.text = function() {
    return d3.xhr.apply(d3, arguments).response(d3_text);
  };
  function d3_text(request) {
    return request.responseText;
  }
  d3.json = function(url, callback) {
    return d3.xhr(url, "application/json", callback).response(d3_json);
  };
  function d3_json(request) {
    return JSON.parse(request.responseText);
  }
  d3.html = function(url, callback) {
    return d3.xhr(url, "text/html", callback).response(d3_html);
  };
  function d3_html(request) {
    var range = document.createRange();
    range.selectNode(document.body);
    return range.createContextualFragment(request.responseText);
  }
  d3.xml = function() {
    return d3.xhr.apply(d3, arguments).response(d3_xml);
  };
  function d3_xml(request) {
    return request.responseXML;
  }
  var d3_nsPrefix = {
    svg: "http://www.w3.org/2000/svg",
    xhtml: "http://www.w3.org/1999/xhtml",
    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.substring(0, i);
        name = name.substring(i + 1);
      }
      return d3_nsPrefix.hasOwnProperty(prefix) ? {
        space: d3_nsPrefix[prefix],
        local: name
      } : name;
    }
  };
  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.substring(i + 1);
      type = type.substring(0, i);
    }
    return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener);
  };
  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.format = function(specifier) {
    var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", basePrefix = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false;
    if (precision) precision = +precision.substring(1);
    if (zfill || fill === "0" && align === "=") {
      zfill = fill = "0";
      align = "=";
      if (comma) width -= Math.floor((width - 1) / 4);
    }
    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 (basePrefix) basePrefix = "0" + type.toLowerCase();

     case "c":
     case "d":
      integer = true;
      precision = 0;
      break;

     case "s":
      scale = -1;
      type = "r";
      break;
    }
    if (basePrefix === "#") basePrefix = "";
    if (type == "r" && !precision) type = "g";
    type = d3_format_types.get(type) || d3_format_typeDefault;
    var zcomma = zfill && comma;
    return function(value) {
      if (integer && value % 1) return "";
      var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign;
      if (scale < 0) {
        var prefix = d3.formatPrefix(value, precision);
        value = prefix.scale(value);
        suffix = prefix.symbol;
      } else {
        value *= scale;
      }
      value = type(value, precision);
      if (!zfill && comma) value = d3_format_group(value);
      var length = basePrefix.length + value.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : "";
      if (zcomma) value = d3_format_group(padding + value);
      if (d3_format_decimalPoint) value.replace(".", d3_format_decimalPoint);
      negative += basePrefix;
      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)) + suffix;
    };
  };
  var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/;
  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 d3.round(x, p = d3_format_precision(x, p)).toFixed(Math.max(0, Math.min(20, p)));
    }
  });
  function d3_format_precision(x, p) {
    return p - (x ? 1 + Math.floor(Math.log(x + Math.pow(10, 1 + Math.floor(Math.log(x) / Math.LN10) - p)) / Math.LN10) : 1);
  }
  function d3_format_typeDefault(x) {
    return x + "";
  }
  var d3_format_group = d3_identity;
  if (d3_format_grouping) {
    var d3_format_groupingLength = d3_format_grouping.length;
    d3_format_group = function(value) {
      var i = value.lastIndexOf("."), f = i >= 0 ? "." + value.substring(i + 1) : (i = value.length, 
      ""), t = [], j = 0, g = d3_format_grouping[0];
      while (i > 0 && g > 0) {
        t.push(value.substring(i -= g, i + g));
        g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength];
      }
      return t.reverse().join(d3_format_thousandsSeparator || "") + f;
    };
  }
  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) {
      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 <= 0 ? i + 1 : i - 1) / 3) * 3));
    }
    return d3_formatPrefixes[8 + i / 3];
  };
  function d3_formatPrefix(d, i) {
    var k = Math.pow(10, Math.abs(8 - i) * 3);
    return {
      scale: i > 8 ? function(d) {
        return d / k;
      } : function(d) {
        return d * k;
      },
      symbol: d
    };
  }
  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.substring(0, i) : name, m = i >= 0 ? name.substring(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, Array.prototype.slice.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 * π / 2);
  }
  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 / (2 * π) * 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) * 2 * π / 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.event = null;
  function d3_eventCancel() {
    d3.event.stopPropagation();
    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.transform = function(string) {
    var g = document.createElementNS(d3.ns.prefix.svg, "g");
    return (d3.transform = function(string) {
      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.interpolate = function(a, b) {
    var i = d3.interpolators.length, f;
    while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;
    return f;
  };
  d3.interpolateNumber = function(a, b) {
    b -= a;
    return function(t) {
      return a + b * t;
    };
  };
  d3.interpolateRound = function(a, b) {
    b -= a;
    return function(t) {
      return Math.round(a + b * t);
    };
  };
  d3.interpolateString = function(a, b) {
    var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o;
    d3_interpolate_number.lastIndex = 0;
    for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
      if (m.index) s.push(b.substring(s0, s1 = m.index));
      q.push({
        i: s.length,
        x: m[0]
      });
      s.push(null);
      s0 = d3_interpolate_number.lastIndex;
    }
    if (s0 < b.length) s.push(b.substring(s0));
    for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {
      o = q[i];
      if (o.x == m[0]) {
        if (o.i) {
          if (s[o.i + 1] == null) {
            s[o.i - 1] += o.x;
            s.splice(o.i, 1);
            for (j = i + 1; j < n; ++j) q[j].i--;
          } else {
            s[o.i - 1] += o.x + s[o.i + 1];
            s.splice(o.i, 2);
            for (j = i + 1; j < n; ++j) q[j].i -= 2;
          }
        } else {
          if (s[o.i + 1] == null) {
            s[o.i] = o.x;
          } else {
            s[o.i] = o.x + s[o.i + 1];
            s.splice(o.i + 1, 1);
            for (j = i + 1; j < n; ++j) q[j].i--;
          }
        }
        q.splice(i, 1);
        n--;
        i--;
      } else {
        o.x = d3.interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
      }
    }
    while (i < n) {
      o = q.pop();
      if (s[o.i + 1] == null) {
        s[o.i] = o.x;
      } else {
        s[o.i] = o.x + s[o.i + 1];
        s.splice(o.i + 1, 1);
      }
      n--;
    }
    if (s.length === 1) {
      return s[0] == null ? q[0].x : function() {
        return b;
      };
    }
    return function(t) {
      for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);
      return s.join("");
    };
  };
  d3.interpolateTransform = function(a, b) {
    var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale;
    if (ta[0] != tb[0] || ta[1] != tb[1]) {
      s.push("translate(", null, ",", null, ")");
      q.push({
        i: 1,
        x: d3.interpolateNumber(ta[0], tb[0])
      }, {
        i: 3,
        x: d3.interpolateNumber(ta[1], tb[1])
      });
    } else if (tb[0] || tb[1]) {
      s.push("translate(" + tb + ")");
    } else {
      s.push("");
    }
    if (ra != rb) {
      if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360;
      q.push({
        i: s.push(s.pop() + "rotate(", null, ")") - 2,
        x: d3.interpolateNumber(ra, rb)
      });
    } else if (rb) {
      s.push(s.pop() + "rotate(" + rb + ")");
    }
    if (wa != wb) {
      q.push({
        i: s.push(s.pop() + "skewX(", null, ")") - 2,
        x: d3.interpolateNumber(wa, wb)
      });
    } else if (wb) {
      s.push(s.pop() + "skewX(" + wb + ")");
    }
    if (ka[0] != kb[0] || ka[1] != kb[1]) {
      n = s.push(s.pop() + "scale(", null, ",", null, ")");
      q.push({
        i: n - 4,
        x: d3.interpolateNumber(ka[0], kb[0])
      }, {
        i: n - 2,
        x: d3.interpolateNumber(ka[1], kb[1])
      });
    } else if (kb[0] != 1 || kb[1] != 1) {
      s.push(s.pop() + "scale(" + kb + ")");
    }
    n = q.length;
    return function(t) {
      var i = -1, o;
      while (++i < n) s[(o = q[i]).i] = o.x(t);
      return s.join("");
    };
  };
  d3.interpolateRgb = function(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.interpolateHsl = function(a, b) {
    a = d3.hsl(a);
    b = d3.hsl(b);
    var h0 = a.h, s0 = a.s, l0 = a.l, h1 = b.h - h0, s1 = b.s - s0, l1 = b.l - l0;
    if (h1 > 180) h1 -= 360; else if (h1 < -180) h1 += 360;
    return function(t) {
      return d3_hsl_rgb(h0 + h1 * t, s0 + s1 * t, l0 + l1 * t) + "";
    };
  };
  d3.interpolateLab = function(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.interpolateHcl = function(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 (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.interpolateArray = function(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;
    };
  };
  d3.interpolateObject = function(a, b) {
    var i = {}, c = {}, k;
    for (k in a) {
      if (k in b) {
        i[k] = d3_interpolateByName(k)(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;
    };
  };
  var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
  function d3_interpolateByName(name) {
    return name == "transform" ? d3.interpolateTransform : d3.interpolate;
  }
  d3.interpolators = [ d3.interpolateObject, function(a, b) {
    return b instanceof Array && d3.interpolateArray(a, b);
  }, function(a, b) {
    return (typeof a === "string" || typeof b === "string") && d3.interpolateString(a + "", b + "");
  }, function(a, b) {
    return (typeof b === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Color) && d3.interpolateRgb(a, b);
  }, function(a, b) {
    return !isNaN(a = +a) && !isNaN(b = +b) && d3.interpolateNumber(a, b);
  } ];
  function d3_uninterpolateNumber(a, b) {
    b = b - (a = +a) ? 1 / (b - a) : 0;
    return function(x) {
      return (x - a) * b;
    };
  }
  function d3_uninterpolateClamp(a, b) {
    b = b - (a = +a) ? 1 / (b - a) : 0;
    return function(x) {
      return Math.max(0, Math.min(1, (x - a) * b));
    };
  }
  function d3_Color() {}
  d3_Color.prototype.toString = function() {
    return this.rgb() + "";
  };
  d3.rgb = function(r, g, b) {
    return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b);
  };
  function d3_rgb(r, g, b) {
    return new d3_Rgb(r, g, b);
  }
  function d3_Rgb(r, g, b) {
    this.r = r;
    this.g = g;
    this.b = b;
  }
  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 d3_rgb(i, i, i);
    if (r && r < i) r = i;
    if (g && g < i) g = i;
    if (b && b < i) b = i;
    return d3_rgb(Math.min(255, Math.floor(r / k)), Math.min(255, Math.floor(g / k)), Math.min(255, Math.floor(b / k)));
  };
  d3_rgbPrototype.darker = function(k) {
    k = Math.pow(.7, arguments.length ? k : 1);
    return d3_rgb(Math.floor(k * this.r), Math.floor(k * this.g), Math.floor(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, name;
    m1 = /([a-z]+)\((.*)\)/i.exec(format);
    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 (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b);
    if (format != null && format.charAt(0) === "#") {
      if (format.length === 4) {
        r = format.charAt(1);
        r += r;
        g = format.charAt(2);
        g += g;
        b = format.charAt(3);
        b += b;
      } else if (format.length === 7) {
        r = format.substring(1, 3);
        g = format.substring(3, 5);
        b = format.substring(5, 7);
      }
      r = parseInt(r, 16);
      g = parseInt(g, 16);
      b = parseInt(b, 16);
    }
    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 {
      s = h = 0;
    }
    return 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: "#f0f8ff",
    antiquewhite: "#faebd7",
    aqua: "#00ffff",
    aquamarine: "#7fffd4",
    azure: "#f0ffff",
    beige: "#f5f5dc",
    bisque: "#ffe4c4",
    black: "#000000",
    blanchedalmond: "#ffebcd",
    blue: "#0000ff",
    blueviolet: "#8a2be2",
    brown: "#a52a2a",
    burlywood: "#deb887",
    cadetblue: "#5f9ea0",
    chartreuse: "#7fff00",
    chocolate: "#d2691e",
    coral: "#ff7f50",
    cornflowerblue: "#6495ed",
    cornsilk: "#fff8dc",
    crimson: "#dc143c",
    cyan: "#00ffff",
    darkblue: "#00008b",
    darkcyan: "#008b8b",
    darkgoldenrod: "#b8860b",
    darkgray: "#a9a9a9",
    darkgreen: "#006400",
    darkgrey: "#a9a9a9",
    darkkhaki: "#bdb76b",
    darkmagenta: "#8b008b",
    darkolivegreen: "#556b2f",
    darkorange: "#ff8c00",
    darkorchid: "#9932cc",
    darkred: "#8b0000",
    darksalmon: "#e9967a",
    darkseagreen: "#8fbc8f",
    darkslateblue: "#483d8b",
    darkslategray: "#2f4f4f",
    darkslategrey: "#2f4f4f",
    darkturquoise: "#00ced1",
    darkviolet: "#9400d3",
    deeppink: "#ff1493",
    deepskyblue: "#00bfff",
    dimgray: "#696969",
    dimgrey: "#696969",
    dodgerblue: "#1e90ff",
    firebrick: "#b22222",
    floralwhite: "#fffaf0",
    forestgreen: "#228b22",
    fuchsia: "#ff00ff",
    gainsboro: "#dcdcdc",
    ghostwhite: "#f8f8ff",
    gold: "#ffd700",
    goldenrod: "#daa520",
    gray: "#808080",
    green: "#008000",
    greenyellow: "#adff2f",
    grey: "#808080",
    honeydew: "#f0fff0",
    hotpink: "#ff69b4",
    indianred: "#cd5c5c",
    indigo: "#4b0082",
    ivory: "#fffff0",
    khaki: "#f0e68c",
    lavender: "#e6e6fa",
    lavenderblush: "#fff0f5",
    lawngreen: "#7cfc00",
    lemonchiffon: "#fffacd",
    lightblue: "#add8e6",
    lightcoral: "#f08080",
    lightcyan: "#e0ffff",
    lightgoldenrodyellow: "#fafad2",
    lightgray: "#d3d3d3",
    lightgreen: "#90ee90",
    lightgrey: "#d3d3d3",
    lightpink: "#ffb6c1",
    lightsalmon: "#ffa07a",
    lightseagreen: "#20b2aa",
    lightskyblue: "#87cefa",
    lightslategray: "#778899",
    lightslategrey: "#778899",
    lightsteelblue: "#b0c4de",
    lightyellow: "#ffffe0",
    lime: "#00ff00",
    limegreen: "#32cd32",
    linen: "#faf0e6",
    magenta: "#ff00ff",
    maroon: "#800000",
    mediumaquamarine: "#66cdaa",
    mediumblue: "#0000cd",
    mediumorchid: "#ba55d3",
    mediumpurple: "#9370db",
    mediumseagreen: "#3cb371",
    mediumslateblue: "#7b68ee",
    mediumspringgreen: "#00fa9a",
    mediumturquoise: "#48d1cc",
    mediumvioletred: "#c71585",
    midnightblue: "#191970",
    mintcream: "#f5fffa",
    mistyrose: "#ffe4e1",
    moccasin: "#ffe4b5",
    navajowhite: "#ffdead",
    navy: "#000080",
    oldlace: "#fdf5e6",
    olive: "#808000",
    olivedrab: "#6b8e23",
    orange: "#ffa500",
    orangered: "#ff4500",
    orchid: "#da70d6",
    palegoldenrod: "#eee8aa",
    palegreen: "#98fb98",
    paleturquoise: "#afeeee",
    palevioletred: "#db7093",
    papayawhip: "#ffefd5",
    peachpuff: "#ffdab9",
    peru: "#cd853f",
    pink: "#ffc0cb",
    plum: "#dda0dd",
    powderblue: "#b0e0e6",
    purple: "#800080",
    red: "#ff0000",
    rosybrown: "#bc8f8f",
    royalblue: "#4169e1",
    saddlebrown: "#8b4513",
    salmon: "#fa8072",
    sandybrown: "#f4a460",
    seagreen: "#2e8b57",
    seashell: "#fff5ee",
    sienna: "#a0522d",
    silver: "#c0c0c0",
    skyblue: "#87ceeb",
    slateblue: "#6a5acd",
    slategray: "#708090",
    slategrey: "#708090",
    snow: "#fffafa",
    springgreen: "#00ff7f",
    steelblue: "#4682b4",
    tan: "#d2b48c",
    teal: "#008080",
    thistle: "#d8bfd8",
    tomato: "#ff6347",
    turquoise: "#40e0d0",
    violet: "#ee82ee",
    wheat: "#f5deb3",
    white: "#ffffff",
    whitesmoke: "#f5f5f5",
    yellow: "#ffff00",
    yellowgreen: "#9acd32"
  });
  d3_rgb_names.forEach(function(key, value) {
    d3_rgb_names.set(key, d3_rgb_parse(value, d3_rgb, d3_hsl_rgb));
  });
  d3.hsl = function(h, s, l) {
    return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l);
  };
  function d3_hsl(h, s, l) {
    return new d3_Hsl(h, s, l);
  }
  function d3_Hsl(h, s, l) {
    this.h = h;
    this.s = s;
    this.l = l;
  }
  var d3_hslPrototype = d3_Hsl.prototype = new d3_Color();
  d3_hslPrototype.brighter = function(k) {
    k = Math.pow(.7, arguments.length ? k : 1);
    return d3_hsl(this.h, this.s, this.l / k);
  };
  d3_hslPrototype.darker = function(k) {
    k = Math.pow(.7, arguments.length ? k : 1);
    return 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 = h % 360;
    if (h < 0) h += 360;
    s = 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 d3_rgb(vv(h + 120), vv(h), vv(h - 120));
  }
  d3.hcl = function(h, c, l) {
    return arguments.length === 1 ? h instanceof d3_Hcl ? 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) : d3_hcl(+h, +c, +l);
  };
  function d3_hcl(h, c, l) {
    return new d3_Hcl(h, c, l);
  }
  function d3_Hcl(h, c, l) {
    this.h = h;
    this.c = c;
    this.l = l;
  }
  var d3_hclPrototype = d3_Hcl.prototype = new d3_Color();
  d3_hclPrototype.brighter = function(k) {
    return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));
  };
  d3_hclPrototype.darker = function(k) {
    return 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) {
    return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
  }
  d3.lab = function(l, a, b) {
    return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b);
  };
  function d3_lab(l, a, b) {
    return new d3_Lab(l, a, b);
  }
  function d3_Lab(l, a, b) {
    this.l = l;
    this.a = a;
    this.b = 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 d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
  };
  d3_labPrototype.darker = function(k) {
    return 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 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 d3_hcl(Math.atan2(b, a) / π * 180, Math.sqrt(a * a + b * b), 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));
  }
  function d3_selection(groups) {
    d3_arraySubclass(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_selectRoot = document.documentElement, d3_selectMatcher = d3_selectRoot.matchesSelector || d3_selectRoot.webkitMatchesSelector || d3_selectRoot.mozMatchesSelector || d3_selectRoot.msMatchesSelector || d3_selectRoot.oMatchesSelector, d3_selectMatches = function(n, s) {
    return d3_selectMatcher.call(n, s);
  };
  if (typeof Sizzle === "function") {
    d3_select = function(s, n) {
      return Sizzle(s, n)[0] || null;
    };
    d3_selectAll = function(s, n) {
      return Sizzle.uniqueSort(Sizzle(s, n));
    };
    d3_selectMatches = Sizzle.matchesSelector;
  }
  var d3_selectionPrototype = [];
  d3.selection = function() {
    return d3_selectionRoot;
  };
  d3.selection.prototype = d3_selectionPrototype;
  d3_selectionPrototype.select = function(selector) {
    var subgroups = [], subgroup, subnode, group, node;
    if (typeof selector !== "function") 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));
          if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
        } else {
          subgroup.push(null);
        }
      }
    }
    return d3_selection(subgroups);
  };
  function d3_selection_selector(selector) {
    return function() {
      return d3_select(selector, this);
    };
  }
  d3_selectionPrototype.selectAll = function(selector) {
    var subgroups = [], subgroup, node;
    if (typeof selector !== "function") 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)));
          subgroup.parentNode = node;
        }
      }
    }
    return d3_selection(subgroups);
  };
  function d3_selection_selectorAll(selector) {
    return function() {
      return d3_selectAll(selector, this);
    };
  }
  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;
  }
  d3_selectionPrototype.classed = function(name, value) {
    if (arguments.length < 2) {
      if (typeof name === "string") {
        var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1;
        if (value = node.classList) {
          while (++i < n) if (!value.contains(name[i])) return false;
        } else {
          value = node.className;
          if (value.baseVal != null) value = value.baseVal;
          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_classed(name, value) {
    name = name.trim().split(/\s+/).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.className, cb = c.baseVal != null, cv = cb ? c.baseVal : c;
      if (value) {
        re.lastIndex = 0;
        if (!re.test(cv)) {
          cv = d3_collapse(cv + " " + name);
          if (cb) c.baseVal = cv; else node.className = cv;
        }
      } else if (cv) {
        cv = d3_collapse(cv.replace(re, " "));
        if (cb) c.baseVal = cv; else node.className = cv;
      }
    };
  }
  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) return getComputedStyle(this.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.ns.qualify(name);
    function append() {
      return this.appendChild(document.createElementNS(this.namespaceURI, name));
    }
    function appendNS() {
      return this.appendChild(document.createElementNS(name.space, name.local));
    }
    return this.select(name.local ? appendNS : append);
  };
  d3_selectionPrototype.insert = function(name, before) {
    name = d3.ns.qualify(name);
    function insert() {
      return this.insertBefore(document.createElementNS(this.namespaceURI, name), d3_select(before, this));
    }
    function insertNS() {
      return this.insertBefore(document.createElementNS(name.space, name.local), d3_select(before, this));
    }
    return this.select(name.local ? insertNS : insert);
  };
  d3_selectionPrototype.remove = function() {
    return this.each(function() {
      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(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue;
        for (i = -1; ++i < n; ) {
          keyValue = key.call(node = group[i], node.__data__, i);
          if (nodeByKeyValue.has(keyValue)) {
            exitNodes[i] = node;
          } else {
            nodeByKeyValue.set(keyValue, node);
          }
          keyValues.push(keyValue);
        }
        for (i = -1; ++i < m; ) {
          keyValue = key.call(groupData, nodeData = groupData[i], i);
          if (node = nodeByKeyValue.get(keyValue)) {
            updateNodes[i] = node;
            node.__data__ = nodeData;
          } else if (!dataByKeyValue.has(keyValue)) {
            enterNodes[i] = d3_selection_dataNode(nodeData);
          }
          dataByKeyValue.set(keyValue, nodeData);
          nodeByKeyValue.remove(keyValue);
        }
        for (i = -1; ++i < n; ) {
          if (nodeByKeyValue.has(keyValues[i])) {
            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)) {
          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 comparator(a && a.__data__, b && b.__data__);
    };
  }
  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(".");
    if (i > 0) type = type.substring(0, i);
    function onRemove() {
      var wrapper = this[name];
      if (wrapper) {
        this.removeEventListener(type, wrapper, wrapper.$);
        delete this[name];
      }
    }
    function onAdd() {
      var node = this, args = d3_array(arguments);
      onRemove.call(this);
      this.addEventListener(type, this[name] = wrapper, wrapper.$ = capture);
      wrapper._ = listener;
      function wrapper(e) {
        var o = d3.event;
        d3.event = e;
        args[0] = node.__data__;
        try {
          listener.apply(node, args);
        } finally {
          d3.event = o;
        }
      }
    }
    return listener ? onAdd : onRemove;
  }
  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.transition = function() {
    var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = Object.create(d3_transitionInherit);
    transition.time = Date.now();
    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, id, transition);
        subgroup.push(node);
      }
    }
    return d3_transition(subgroups, id);
  };
  var d3_selectionRoot = d3_selection([ [ document ] ]);
  d3_selectionRoot[0].parentNode = d3_selectRoot;
  d3.select = function(selector) {
    return typeof selector === "string" ? d3_selectionRoot.select(selector) : d3_selection([ [ selector ] ]);
  };
  d3.selectAll = function(selector) {
    return typeof selector === "string" ? d3_selectionRoot.selectAll(selector) : d3_selection([ d3_array(selector) ]);
  };
  function d3_selection_enter(selection) {
    d3_arraySubclass(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.insert = d3_selectionPrototype.insert;
  d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
  d3_selection_enterPrototype.node = d3_selectionPrototype.node;
  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));
          subnode.__data__ = node.__data__;
        } else {
          subgroup.push(null);
        }
      }
    }
    return d3_selection(subgroups);
  };
  function d3_transition(groups, id) {
    d3_arraySubclass(groups, d3_transitionPrototype);
    groups.id = id;
    return groups;
  }
  var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit = {
    ease: d3_ease_cubicInOut,
    delay: 0,
    duration: 250
  };
  d3_transitionPrototype.call = d3_selectionPrototype.call;
  d3_transitionPrototype.empty = d3_selectionPrototype.empty;
  d3_transitionPrototype.node = d3_selectionPrototype.node;
  d3.transition = function(selection) {
    return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition();
  };
  d3.transition.prototype = d3_transitionPrototype;
  function d3_transitionNode(node, i, id, inherit) {
    var lock = node.__transition__ || (node.__transition__ = {
      active: 0,
      count: 0
    }), transition = lock[id];
    if (!transition) {
      var time = inherit.time;
      transition = lock[id] = {
        tween: new d3_Map(),
        event: d3.dispatch("start", "end"),
        time: time,
        ease: inherit.ease,
        delay: inherit.delay,
        duration: inherit.duration
      };
      ++lock.count;
      d3.timer(function(elapsed) {
        var d = node.__data__, ease = transition.ease, event = transition.event, delay = transition.delay, duration = transition.duration, tweened = [];
        return delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time), 1;
        function start(elapsed) {
          if (lock.active > id) return stop();
          lock.active = id;
          event.start.call(node, d, i);
          transition.tween.forEach(function(key, value) {
            if (value = value.call(node, d, i)) {
              tweened.push(value);
            }
          });
          if (!tick(elapsed)) d3.timer(tick, 0, time);
          return 1;
        }
        function tick(elapsed) {
          if (lock.active !== id) return stop();
          var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length;
          while (n > 0) {
            tweened[--n].call(node, e);
          }
          if (t >= 1) {
            stop();
            event.end.call(node, d, i);
            return 1;
          }
        }
        function stop() {
          if (--lock.count) delete lock[id]; else delete node.__transition__;
          return 1;
        }
      }, 0, time);
      return transition;
    }
  }
  d3_transitionPrototype.select = function(selector) {
    var id = this.id, subgroups = [], subgroup, subnode, node;
    if (typeof selector !== "function") 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))) {
          if ("__data__" in node) subnode.__data__ = node.__data__;
          d3_transitionNode(subnode, i, id, node.__transition__[id]);
          subgroup.push(subnode);
        } else {
          subgroup.push(null);
        }
      }
    }
    return d3_transition(subgroups, id);
  };
  d3_transitionPrototype.selectAll = function(selector) {
    var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition;
    if (typeof selector !== "function") 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.__transition__[id];
          subnodes = selector.call(node, node.__data__, i);
          subgroups.push(subgroup = []);
          for (var k = -1, o = subnodes.length; ++k < o; ) {
            d3_transitionNode(subnode = subnodes[k], k, id, transition);
            subgroup.push(subnode);
          }
        }
      }
    }
    return d3_transition(subgroups, 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)) {
          subgroup.push(node);
        }
      }
    }
    return d3_transition(subgroups, this.id, this.time).ease(this.ease());
  };
  d3_transitionPrototype.attr = function(nameNS, value) {
    if (arguments.length < 2) {
      for (value in nameNS) this.attr(value, nameNS[value]);
      return this;
    }
    var interpolate = d3_interpolateByName(nameNS), name = d3.ns.qualify(nameNS);
    function attrNull() {
      this.removeAttribute(name);
    }
    function attrNullNS() {
      this.removeAttributeNS(name.space, name.local);
    }
    return d3_transition_tween(this, "attr." + nameNS, value, function(b) {
      function attrString() {
        var a = this.getAttribute(name), i;
        return a !== b && (i = interpolate(a, b), function(t) {
          this.setAttribute(name, i(t));
        });
      }
      function attrStringNS() {
        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 b == null ? name.local ? attrNullNS : attrNull : (b += "", name.local ? attrStringNS : attrString);
    });
  };
  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 = "";
    }
    var interpolate = d3_interpolateByName(name);
    function styleNull() {
      this.style.removeProperty(name);
    }
    return d3_transition_tween(this, "style." + name, value, function(b) {
      function styleString() {
        var a = getComputedStyle(this, null).getPropertyValue(name), i;
        return a !== b && (i = interpolate(a, b), function(t) {
          this.style.setProperty(name, i(t), priority);
        });
      }
      return b == null ? styleNull : (b += "", styleString);
    });
  };
  d3_transitionPrototype.styleTween = function(name, tween, priority) {
    if (arguments.length < 3) priority = "";
    return this.tween("style." + name, function(d, i) {
      var f = tween.call(this, d, i, getComputedStyle(this, null).getPropertyValue(name));
      return f && function(t) {
        this.style.setProperty(name, f(t), priority);
      };
    });
  };
  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() {
    return this.each("end.transition", function() {
      var p;
      if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this);
    });
  };
  d3_transitionPrototype.ease = function(value) {
    var id = this.id;
    if (arguments.length < 1) return this.node().__transition__[id].ease;
    if (typeof value !== "function") value = d3.ease.apply(d3, arguments);
    return d3_selection_each(this, function(node) {
      node.__transition__[id].ease = value;
    });
  };
  d3_transitionPrototype.delay = function(value) {
    var id = this.id;
    return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
      node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0;
    } : (value |= 0, function(node) {
      node.__transition__[id].delay = value;
    }));
  };
  d3_transitionPrototype.duration = function(value) {
    var id = this.id;
    return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
      node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j) | 0);
    } : (value = Math.max(1, value | 0), function(node) {
      node.__transition__[id].duration = value;
    }));
  };
  d3_transitionPrototype.each = function(type, listener) {
    var id = this.id;
    if (arguments.length < 2) {
      var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId;
      d3_transitionInheritId = id;
      d3_selection_each(this, function(node, i, j) {
        d3_transitionInherit = node.__transition__[id];
        type.call(node, node.__data__, i, j);
      });
      d3_transitionInherit = inherit;
      d3_transitionInheritId = inheritId;
    } else {
      d3_selection_each(this, function(node) {
        node.__transition__[id].event.on(type, listener);
      });
    }
    return this;
  };
  d3_transitionPrototype.transition = function() {
    var id0 = this.id, id1 = ++d3_transitionId, 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 = Object.create(node.__transition__[id0]);
          transition.delay += transition.duration;
          d3_transitionNode(node, i, id1, transition);
        }
        subgroup.push(node);
      }
    }
    return d3_transition(subgroups, id1);
  };
  d3_transitionPrototype.tween = function(name, tween) {
    var id = this.id;
    if (arguments.length < 2) return this.node().__transition__[id].tween.get(name);
    return d3_selection_each(this, tween == null ? function(node) {
      node.__transition__[id].tween.remove(name);
    } : function(node) {
      node.__transition__[id].tween.set(name, tween);
    });
  };
  function d3_transition_tween(groups, name, value, tween) {
    var id = groups.id;
    return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) {
      node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j)));
    } : (value = tween(value), function(node) {
      node.__transition__[id].tween.set(name, value);
    }));
  }
  var d3_timer_id = 0, d3_timer_byId = {}, d3_timer_queue = null, d3_timer_interval, d3_timer_timeout;
  d3.timer = function(callback, delay, then) {
    if (arguments.length < 3) {
      if (arguments.length < 2) delay = 0; else if (!isFinite(delay)) return;
      then = Date.now();
    }
    var timer = d3_timer_byId[callback.id];
    if (timer && timer.callback === callback) {
      timer.then = then;
      timer.delay = delay;
    } else d3_timer_byId[callback.id = ++d3_timer_id] = d3_timer_queue = {
      callback: callback,
      then: then,
      delay: delay,
      next: d3_timer_queue
    };
    if (!d3_timer_interval) {
      d3_timer_timeout = clearTimeout(d3_timer_timeout);
      d3_timer_interval = 1;
      d3_timer_frame(d3_timer_step);
    }
  };
  function d3_timer_step() {
    var elapsed, now = Date.now(), t1 = d3_timer_queue;
    while (t1) {
      elapsed = now - t1.then;
      if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed);
      t1 = t1.next;
    }
    var delay = d3_timer_flush() - 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() {
    var elapsed, now = Date.now(), t1 = d3_timer_queue;
    while (t1) {
      elapsed = now - t1.then;
      if (!t1.delay) t1.flush = t1.callback(elapsed);
      t1 = t1.next;
    }
    d3_timer_flush();
  };
  function d3_timer_flush() {
    var t0 = null, t1 = d3_timer_queue, then = Infinity;
    while (t1) {
      if (t1.flush) {
        delete d3_timer_byId[t1.callback.id];
        t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next;
      } else {
        then = Math.min(then, t1.then + t1.delay);
        t1 = (t0 = t1).next;
      }
    }
    return then;
  }
  var d3_timer_frame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
    setTimeout(callback, 17);
  };
  d3.mouse = function(container) {
    return d3_mousePoint(container, d3_eventSource());
  };
  var d3_mouse_bug44083 = /WebKit/.test(navigator.userAgent) ? -1 : 0;
  function d3_mousePoint(container, e) {
    var svg = container.ownerSVGElement || container;
    if (svg.createSVGPoint) {
      var point = svg.createSVGPoint();
      if (d3_mouse_bug44083 < 0 && (window.scrollX || window.scrollY)) {
        svg = d3.select(document.body).append("svg").style("position", "absolute").style("top", 0).style("left", 0);
        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.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;
    }) : [];
  };
  function d3_noop() {}
  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_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;
    }
    if (nice = nice(x1 - x0)) {
      domain[i0] = nice.floor(x0);
      domain[i1] = nice.ceil(x1);
    }
    return domain;
  }
  function d3_scale_niceDefault() {
    return Math;
  }
  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) {
      return d3_scale_linearTickFormat(domain, m);
    };
    scale.nice = function() {
      d3_scale_nice(domain, d3_scale_linearNice);
      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(dx) {
    dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1);
    return dx && {
      floor: function(x) {
        return Math.floor(x / dx) * dx;
      },
      ceil: function(x) {
        return Math.ceil(x / dx) * dx;
      }
    };
  }
  function d3_scale_linearTickRange(domain, m) {
    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) {
    return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f");
  }
  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_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.log = function() {
    return d3_scale_log(d3.scale.linear(), d3_scale_logp);
  };
  function d3_scale_log(linear, log) {
    var pow = log.pow;
    function scale(x) {
      return linear(log(x));
    }
    scale.invert = function(x) {
      return pow(linear.invert(x));
    };
    scale.domain = function(x) {
      if (!arguments.length) return linear.domain().map(pow);
      log = x[0] < 0 ? d3_scale_logn : d3_scale_logp;
      pow = log.pow;
      linear.domain(x.map(log));
      return scale;
    };
    scale.nice = function() {
      linear.domain(d3_scale_nice(linear.domain(), d3_scale_niceDefault));
      return scale;
    };
    scale.ticks = function() {
      var extent = d3_scaleExtent(linear.domain()), ticks = [];
      if (extent.every(isFinite)) {
        var i = Math.floor(extent[0]), j = Math.ceil(extent[1]), u = pow(extent[0]), v = pow(extent[1]);
        if (log === d3_scale_logn) {
          ticks.push(pow(i));
          for (;i++ < j; ) for (var k = 9; k > 0; k--) ticks.push(pow(i) * k);
        } else {
          for (;i < j; i++) for (var k = 1; k < 10; k++) ticks.push(pow(i) * k);
          ticks.push(pow(i));
        }
        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 < 2) format = d3_scale_logFormat;
      if (!arguments.length) return format;
      var k = Math.max(.1, n / scale.ticks().length), f = log === d3_scale_logn ? (e = -1e-12, 
      Math.floor) : (e = 1e-12, Math.ceil), e;
      return function(d) {
        return d / pow(f(log(d) + e)) <= k ? format(d) : "";
      };
    };
    scale.copy = function() {
      return d3_scale_log(linear.copy(), log);
    };
    return d3_scale_linearRebind(scale, linear);
  }
  var d3_scale_logFormat = d3.format(".0e");
  function d3_scale_logp(x) {
    return Math.log(x < 0 ? 0 : x) / Math.LN10;
  }
  function d3_scale_logn(x) {
    return -Math.log(x > 0 ? 0 : -x) / Math.LN10;
  }
  d3_scale_logp.pow = function(x) {
    return Math.pow(10, x);
  };
  d3_scale_logn.pow = function(x) {
    return -Math.pow(10, -x);
  };
  d3.scale.pow = function() {
    return d3_scale_pow(d3.scale.linear(), 1);
  };
  function d3_scale_pow(linear, exponent) {
    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 linear.domain().map(powb);
      linear.domain(x.map(powp));
      return scale;
    };
    scale.ticks = function(m) {
      return d3_scale_linearTicks(scale.domain(), m);
    };
    scale.tickFormat = function(m) {
      return d3_scale_linearTickFormat(scale.domain(), m);
    };
    scale.nice = function() {
      return scale.domain(d3_scale_nice(scale.domain(), d3_scale_linearNice));
    };
    scale.exponent = function(x) {
      if (!arguments.length) return exponent;
      var domain = scale.domain();
      powp = d3_scale_powPow(exponent = x);
      powb = d3_scale_powPow(1 / exponent);
      return scale.domain(domain);
    };
    scale.copy = function() {
      return d3_scale_pow(linear.copy(), exponent);
    };
    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) || index.set(x, domain.push(x))) - 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 = (stop - start) / (Math.max(1, domain.length - 1) + padding);
      range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);
      rangeBand = 0;
      ranger = {
        t: "rangePoints",
        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)), error = stop - start - (domain.length - padding) * step;
      range = steps(start + Math.round(error / 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 = [ "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf" ];
  var d3_category20 = [ "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5", "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5" ];
  var d3_category20b = [ "#393b79", "#5254a3", "#6b6ecf", "#9c9ede", "#637939", "#8ca252", "#b5cf6b", "#cedb9c", "#8c6d31", "#bd9e39", "#e7ba52", "#e7cb94", "#843c39", "#ad494a", "#d6616b", "#e7969c", "#7b4173", "#a55194", "#ce6dbd", "#de9ed6" ];
  var d3_category20c = [ "#3182bd", "#6baed6", "#9ecae1", "#c6dbef", "#e6550d", "#fd8d3c", "#fdae6b", "#fdd0a2", "#31a354", "#74c476", "#a1d99b", "#c7e9c0", "#756bb1", "#9e9ac8", "#bcbddc", "#dadaeb", "#636363", "#969696", "#bdbdbd", "#d9d9d9" ];
  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 NaN;
      return range[d3.bisect(thresholds, x)];
    }
    scale.domain = function(x) {
      if (!arguments.length) return domain;
      domain = x.filter(function(d) {
        return !isNaN(d);
      }).sort(d3.ascending);
      return rescale();
    };
    scale.range = function(x) {
      if (!arguments.length) return range;
      range = x;
      return rescale();
    };
    scale.quantiles = function() {
      return thresholds;
    };
    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.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) {
      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.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) {
      return d3_scale_linearTickFormat(domain, m);
    };
    identity.copy = function() {
      return d3_scale_identity(domain);
    };
    return identity;
  }
  d3.svg = {};
  d3.svg.arc = function() {
    var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
    function arc() {
      var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, 
      a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1);
      return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z";
    }
    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.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.centroid = function() {
      var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset;
      return [ Math.cos(a) * r, Math.sin(a) * r ];
    };
    return arc;
  };
  var d3_svg_arcOffset = -π / 2, d3_svg_arcMax = 2 * π - 1e-6;
  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_line(projection) {
    var x = d3_svg_lineX, y = d3_svg_lineY, 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);
  };
  function d3_svg_lineX(d) {
    return d[0];
  }
  function d3_svg_lineY(d) {
    return d[1];
  }
  var d3_svg_lineInterpolators = d3.map({
    linear: d3_svg_lineLinear,
    "linear-closed": d3_svg_lineLinearClosed,
    "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.join("L");
  }
  function d3_svg_lineLinearClosed(points) {
    return d3_svg_lineLinear(points) + "Z";
  }
  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, points.length - 1), d3_svg_lineCardinalTangents(points, tension));
  }
  function d3_svg_lineCardinalClosed(points, tension) {
    return points.length < 3 ? d3_svg_lineLinear(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 ];
    d3_svg_lineBasisBezier(path, px, py);
    while (++i < n) {
      pi = points[i];
      px.shift();
      px.push(pi[0]);
      py.shift();
      py.push(pi[1]);
      d3_svg_lineBasisBezier(path, px, py);
    }
    i = -1;
    while (++i < 2) {
      px.shift();
      px.push(pi[0]);
      py.shift();
      py.push(pi[1]);
      d3_svg_lineBasisBezier(path, px, py);
    }
    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 (Math.abs(d) < 1e-6) {
        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] + d3_svg_arcOffset;
      point[0] = r * Math.cos(a);
      point[1] = r * Math.sin(a);
    }
    return points;
  }
  function d3_svg_area(projection) {
    var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, 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) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset;
      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] + d3_svg_arcOffset;
      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.svg.axis = function() {
    var scale = d3.scale.linear(), orient = "bottom", tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0;
    function axis(g) {
      g.each(function() {
        var g = d3.select(this);
        var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_;
        var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", "g").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1);
        var tick = g.selectAll("g").data(ticks, String), tickEnter = tick.enter().insert("g", "path").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform;
        var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = d3.transition(path);
        var scale1 = scale.copy(), scale0 = this.__chart__ || scale1;
        this.__chart__ = scale1;
        path.enter().append("path").attr("class", "domain");
        tickEnter.append("line").attr("class", "tick");
        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");
        switch (orient) {
         case "bottom":
          {
            tickTransform = d3_svg_axisX;
            subtickEnter.attr("y2", tickMinorSize);
            subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize);
            lineEnter.attr("y2", tickMajorSize);
            textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding);
            lineUpdate.attr("x2", 0).attr("y2", tickMajorSize);
            textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding);
            text.attr("dy", ".71em").style("text-anchor", "middle");
            pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize);
            break;
          }

         case "top":
          {
            tickTransform = d3_svg_axisX;
            subtickEnter.attr("y2", -tickMinorSize);
            subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize);
            lineEnter.attr("y2", -tickMajorSize);
            textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding));
            lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize);
            textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding));
            text.attr("dy", "0em").style("text-anchor", "middle");
            pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize);
            break;
          }

         case "left":
          {
            tickTransform = d3_svg_axisY;
            subtickEnter.attr("x2", -tickMinorSize);
            subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0);
            lineEnter.attr("x2", -tickMajorSize);
            textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding));
            lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0);
            textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0);
            text.attr("dy", ".32em").style("text-anchor", "end");
            pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize);
            break;
          }

         case "right":
          {
            tickTransform = d3_svg_axisY;
            subtickEnter.attr("x2", tickMinorSize);
            subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0);
            lineEnter.attr("x2", tickMajorSize);
            textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding);
            lineUpdate.attr("x2", tickMajorSize).attr("y2", 0);
            textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0);
            text.attr("dy", ".32em").style("text-anchor", "start");
            pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize);
            break;
          }
        }
        if (scale.ticks) {
          tickEnter.call(tickTransform, scale0);
          tickUpdate.call(tickTransform, scale1);
          tickExit.call(tickTransform, scale1);
          subtickEnter.call(tickTransform, scale0);
          subtickUpdate.call(tickTransform, scale1);
          subtickExit.call(tickTransform, scale1);
        } else {
          var dx = scale1.rangeBand() / 2, x = function(d) {
            return scale1(d) + dx;
          };
          tickEnter.call(tickTransform, x);
          tickUpdate.call(tickTransform, x);
        }
      });
    }
    axis.scale = function(x) {
      if (!arguments.length) return scale;
      scale = x;
      return axis;
    };
    axis.orient = function(x) {
      if (!arguments.length) return orient;
      orient = x;
      return axis;
    };
    axis.ticks = function() {
      if (!arguments.length) return tickArguments_;
      tickArguments_ = 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, y) {
      if (!arguments.length) return tickMajorSize;
      var n = arguments.length - 1;
      tickMajorSize = +x;
      tickMinorSize = n > 1 ? +y : tickMajorSize;
      tickEndSize = n > 0 ? +arguments[n] : tickMajorSize;
      return axis;
    };
    axis.tickPadding = function(x) {
      if (!arguments.length) return tickPadding;
      tickPadding = +x;
      return axis;
    };
    axis.tickSubdivide = function(x) {
      if (!arguments.length) return tickSubdivide;
      tickSubdivide = +x;
      return axis;
    };
    return axis;
  };
  function d3_svg_axisX(selection, x) {
    selection.attr("transform", function(d) {
      return "translate(" + x(d) + ",0)";
    });
  }
  function d3_svg_axisY(selection, y) {
    selection.attr("transform", function(d) {
      return "translate(0," + y(d) + ")";
    });
  }
  function d3_svg_axisSubdivide(scale, ticks, m) {
    subticks = [];
    if (m && ticks.length > 1) {
      var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v;
      while (++i < n) {
        for (j = m; --j > 0; ) {
          if ((v = +ticks[i] - j * d) >= extent[0]) {
            subticks.push(v);
          }
        }
      }
      for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) {
        subticks.push(v);
      }
    }
    return subticks;
  }
  d3.svg.brush = function() {
    var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], extentDomain;
    function brush(g) {
      g.each(function() {
        var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e;
        g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart);
        bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair");
        fg.enter().append("rect").attr("class", "extent").style("cursor", "move");
        tz.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");
        tz.style("display", brush.empty() ? "none" : null);
        tz.exit().remove();
        if (x) {
          e = d3_scaleRange(x);
          bg.attr("x", e[0]).attr("width", e[1] - e[0]);
          redrawX(g);
        }
        if (y) {
          e = d3_scaleRange(y);
          bg.attr("y", e[0]).attr("height", e[1] - e[0]);
          redrawY(g);
        }
        redraw(g);
      });
    }
    function redraw(g) {
      g.selectAll(".resize").attr("transform", function(d) {
        return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")";
      });
    }
    function redrawX(g) {
      g.select(".extent").attr("x", extent[0][0]);
      g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]);
    }
    function redrawY(g) {
      g.select(".extent").attr("y", extent[0][1]);
      g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]);
    }
    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"), center, origin = mouse(), offset;
      var w = d3.select(window).on("mousemove.brush", brushmove).on("mouseup.brush", brushend).on("touchmove.brush", brushmove).on("touchend.brush", brushend).on("keydown.brush", keydown).on("keyup.brush", keyup);
      if (dragging) {
        origin[0] = extent[0][0] - origin[0];
        origin[1] = extent[0][1] - origin[1];
      } else if (resizing) {
        var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);
        offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ];
        origin[0] = extent[ex][0];
        origin[1] = extent[ey][1];
      } 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();
      d3_eventCancel();
      function mouse() {
        var touches = d3.event.changedTouches;
        return touches ? d3.touches(target, touches)[0] : d3.mouse(target);
      }
      function keydown() {
        if (d3.event.keyCode == 32) {
          if (!dragging) {
            center = null;
            origin[0] -= extent[1][0];
            origin[1] -= extent[1][1];
            dragging = 2;
          }
          d3_eventCancel();
        }
      }
      function keyup() {
        if (d3.event.keyCode == 32 && dragging == 2) {
          origin[0] += extent[1][0];
          origin[1] += extent[1][1];
          dragging = 0;
          d3_eventCancel();
        }
      }
      function brushmove() {
        var point = mouse(), moved = false;
        if (offset) {
          point[0] += offset[0];
          point[1] += offset[1];
        }
        if (!dragging) {
          if (d3.event.altKey) {
            if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ];
            origin[0] = extent[+(point[0] < center[0])][0];
            origin[1] = extent[+(point[1] < center[1])][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], size = extent[1][i] - extent[0][i], min, max;
        if (dragging) {
          r0 -= position;
          r1 -= size + position;
        }
        min = Math.max(r0, Math.min(r1, 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][i] !== min || extent[1][i] !== max) {
          extentDomain = null;
          extent[0][i] = min;
          extent[1][i] = 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);
        event_({
          type: "brushend"
        });
        d3_eventCancel();
      }
    }
    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.extent = function(z) {
      var x0, x1, y0, y1, t;
      if (!arguments.length) {
        z = extentDomain || extent;
        if (x) {
          x0 = z[0][0], x1 = z[1][0];
          if (!extentDomain) {
            x0 = extent[0][0], x1 = extent[1][0];
            if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);
            if (x1 < x0) t = x0, x0 = x1, x1 = t;
          }
        }
        if (y) {
          y0 = z[0][1], y1 = z[1][1];
          if (!extentDomain) {
            y0 = extent[0][1], y1 = extent[1][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 ];
      }
      extentDomain = [ [ 0, 0 ], [ 0, 0 ] ];
      if (x) {
        x0 = z[0], x1 = z[1];
        if (y) x0 = x0[0], x1 = x1[0];
        extentDomain[0][0] = x0, extentDomain[1][0] = x1;
        if (x.invert) x0 = x(x0), x1 = x(x1);
        if (x1 < x0) t = x0, x0 = x1, x1 = t;
        extent[0][0] = x0 | 0, extent[1][0] = x1 | 0;
      }
      if (y) {
        y0 = z[0], y1 = z[1];
        if (x) y0 = y0[1], y1 = y1[1];
        extentDomain[0][1] = y0, extentDomain[1][1] = y1;
        if (y.invert) y0 = y(y0), y1 = y(y1);
        if (y1 < y0) t = y0, y0 = y1, y1 = t;
        extent[0][1] = y0 | 0, extent[1][1] = y1 | 0;
      }
      return brush;
    };
    brush.clear = function() {
      extentDomain = null;
      extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0;
      return brush;
    };
    brush.empty = function() {
      return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][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" ], [] ];
  d3.behavior = {};
  d3.behavior.drag = function() {
    var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null;
    function drag() {
      this.on("mousedown.drag", mousedown).on("touchstart.drag", mousedown);
    }
    function mousedown() {
      var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null, offset, origin_ = point(), moved = 0;
      var w = d3.select(window).on(touchId != null ? "touchmove.drag-" + touchId : "mousemove.drag", dragmove).on(touchId != null ? "touchend.drag-" + touchId : "mouseup.drag", dragend, true);
      if (origin) {
        offset = origin.apply(target, arguments);
        offset = [ offset.x - origin_[0], offset.y - origin_[1] ];
      } else {
        offset = [ 0, 0 ];
      }
      if (touchId == null) d3_eventCancel();
      event_({
        type: "dragstart"
      });
      function point() {
        var p = target.parentNode;
        return touchId != null ? d3.touches(p).filter(function(p) {
          return p.identifier === touchId;
        })[0] : d3.mouse(p);
      }
      function dragmove() {
        if (!target.parentNode) return dragend();
        var p = point(), dx = p[0] - origin_[0], dy = p[1] - origin_[1];
        moved |= dx | dy;
        origin_ = p;
        d3_eventCancel();
        event_({
          type: "drag",
          x: p[0] + offset[0],
          y: p[1] + offset[1],
          dx: dx,
          dy: dy
        });
      }
      function dragend() {
        event_({
          type: "dragend"
        });
        if (moved) {
          d3_eventCancel();
          if (d3.event.target === eventTarget) w.on("click.drag", click, true);
        }
        w.on(touchId != null ? "touchmove.drag-" + touchId : "mousemove.drag", null).on(touchId != null ? "touchend.drag-" + touchId : "mouseup.drag", null);
      }
      function click() {
        d3_eventCancel();
        w.on("click.drag", null);
      }
    }
    drag.origin = function(x) {
      if (!arguments.length) return origin;
      origin = x;
      return drag;
    };
    return d3.rebind(drag, event, "on");
  };
  d3.behavior.zoom = function() {
    var translate = [ 0, 0 ], translate0, scale = 1, scale0, scaleExtent = d3_behavior_zoomInfinity, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1, touchtime;
    function zoom() {
      this.on("mousedown.zoom", mousedown).on("mousewheel.zoom", mousewheel).on("mousemove.zoom", mousemove).on("DOMMouseScroll.zoom", mousewheel).on("dblclick.zoom", dblclick).on("touchstart.zoom", touchstart).on("touchmove.zoom", touchmove).on("touchend.zoom", touchstart);
    }
    zoom.translate = function(x) {
      if (!arguments.length) return translate;
      translate = x.map(Number);
      rescale();
      return zoom;
    };
    zoom.scale = function(x) {
      if (!arguments.length) return scale;
      scale = +x;
      rescale();
      return zoom;
    };
    zoom.scaleExtent = function(x) {
      if (!arguments.length) return scaleExtent;
      scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number);
      return zoom;
    };
    zoom.x = function(z) {
      if (!arguments.length) return x1;
      x1 = z;
      x0 = z.copy();
      translate = [ 0, 0 ];
      scale = 1;
      return zoom;
    };
    zoom.y = function(z) {
      if (!arguments.length) return y1;
      y1 = z;
      y0 = z.copy();
      translate = [ 0, 0 ];
      scale = 1;
      return zoom;
    };
    function location(p) {
      return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ];
    }
    function point(l) {
      return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ];
    }
    function scaleTo(s) {
      scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
    }
    function translateTo(p, l) {
      l = point(l);
      translate[0] += p[0] - l[0];
      translate[1] += p[1] - l[1];
    }
    function rescale() {
      if (x1) x1.domain(x0.range().map(function(x) {
        return (x - translate[0]) / scale;
      }).map(x0.invert));
      if (y1) y1.domain(y0.range().map(function(y) {
        return (y - translate[1]) / scale;
      }).map(y0.invert));
    }
    function dispatch(event) {
      rescale();
      d3.event.preventDefault();
      event({
        type: "zoom",
        scale: scale,
        translate: translate
      });
    }
    function mousedown() {
      var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, moved = 0, w = d3.select(window).on("mousemove.zoom", mousemove).on("mouseup.zoom", mouseup), l = location(d3.mouse(target));
      window.focus();
      d3_eventCancel();
      function mousemove() {
        moved = 1;
        translateTo(d3.mouse(target), l);
        dispatch(event_);
      }
      function mouseup() {
        if (moved) d3_eventCancel();
        w.on("mousemove.zoom", null).on("mouseup.zoom", null);
        if (moved && d3.event.target === eventTarget) w.on("click.zoom", click, true);
      }
      function click() {
        d3_eventCancel();
        w.on("click.zoom", null);
      }
    }
    function mousewheel() {
      if (!translate0) translate0 = location(d3.mouse(this));
      scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale);
      translateTo(d3.mouse(this), translate0);
      dispatch(event.of(this, arguments));
    }
    function mousemove() {
      translate0 = null;
    }
    function dblclick() {
      var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2;
      scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1));
      translateTo(p, l);
      dispatch(event.of(this, arguments));
    }
    function touchstart() {
      var touches = d3.touches(this), now = Date.now();
      scale0 = scale;
      translate0 = {};
      touches.forEach(function(t) {
        translate0[t.identifier] = location(t);
      });
      d3_eventCancel();
      if (touches.length === 1) {
        if (now - touchtime < 500) {
          var p = touches[0], l = location(touches[0]);
          scaleTo(scale * 2);
          translateTo(p, l);
          dispatch(event.of(this, arguments));
        }
        touchtime = now;
      }
    }
    function touchmove() {
      var touches = d3.touches(this), p0 = touches[0], l0 = translate0[p0.identifier];
      if (p1 = touches[1]) {
        var p1, l1 = translate0[p1.identifier];
        p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];
        l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];
        scaleTo(d3.event.scale * scale0);
      }
      translateTo(p0, l0);
      touchtime = null;
      dispatch(event.of(this, arguments));
    }
    return d3.rebind(zoom, event, "on");
  };
  var d3_behavior_zoomDiv, d3_behavior_zoomInfinity = [ 0, Infinity ];
  function d3_behavior_zoomDelta() {
    if (!d3_behavior_zoomDiv) {
      d3_behavior_zoomDiv = d3.select("body").append("div").style("visibility", "hidden").style("top", 0).style("height", 0).style("width", 0).style("overflow-y", "scroll").append("div").style("height", "2000px").node().parentNode;
    }
    var e = d3.event, delta;
    try {
      d3_behavior_zoomDiv.scrollTop = 1e3;
      d3_behavior_zoomDiv.dispatchEvent(e);
      delta = 1e3 - d3_behavior_zoomDiv.scrollTop;
    } catch (error) {
      delta = e.wheelDelta || -e.detail * 5;
    }
    return delta;
  }
  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 = (2 * π - 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: (x - x0) / k
        };
        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"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, 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, dn = 1 / Math.sqrt(dx * dx + dy * dy);
          if ((x2 - x1) * dn < theta) {
            var k = quad.charge * dn * dn;
            node.px -= dx * k;
            node.py -= dy * k;
            return true;
          }
          if (quad.point && isFinite(dn)) {
            var k = quad.pointCharge * dn * dn;
            node.px -= dx * k;
            node.py -= dy * k;
          }
        }
        return !quad.charge;
      };
    }
    force.tick = function() {
      if ((alpha *= .99) < .005) {
        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));
          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 = d3_functor(x);
      return force;
    };
    force.distance = force.linkDistance;
    force.linkStrength = function(x) {
      if (!arguments.length) return linkStrength;
      linkStrength = d3_functor(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.gravity = function(x) {
      if (!arguments.length) return gravity;
      gravity = x;
      return force;
    };
    force.theta = function(x) {
      if (!arguments.length) return theta;
      theta = x;
      return force;
    };
    force.alpha = function(x) {
      if (!arguments.length) return alpha;
      if (alpha) {
        if (x > 0) alpha = x; else alpha = 0;
      } else if (x > 0) {
        event.start({
          type: "start",
          alpha: alpha = x
        });
        d3.timer(force.tick);
      }
      return force;
    };
    force.start = function() {
      var i, j, 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;
      }
      distances = [];
      strengths = [];
      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];
        distances[i] = linkDistance.call(this, o, i);
        strengths[i] = linkStrength.call(this, o, i);
        ++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;
      }
      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) {
        var neighbors = neighbor(i), j = -1, m = neighbors.length, x;
        while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x;
        return Math.random() * size;
      }
      function neighbor() {
        if (!neighbors) {
          neighbors = [];
          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);
          }
        }
        return neighbors[i];
      }
      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", d3_layout_forceDragstart).on("drag", dragmove).on("dragend", d3_layout_forceDragend);
      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 &= 1;
  }
  function d3_layout_forceMouseover(d) {
    d.fixed |= 4;
    d.px = d.x, d.py = d.y;
  }
  function d3_layout_forceMouseout(d) {
    d.fixed &= 3;
  }
  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;
  }
  function d3_layout_forceLinkDistance() {
    return 20;
  }
  function d3_layout_forceLinkStrength() {
    return 1;
  }
  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 = 2 * π;
    function pie(data) {
      var values = data.map(function(d, i) {
        return +value.call(pie, d, i);
      });
      var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle);
      var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - startAngle) / d3.sum(values);
      var index = d3.range(data.length);
      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]);
      });
      var arcs = [];
      index.forEach(function(i) {
        var d;
        arcs[i] = {
          data: data[i],
          value: d = values[i],
          startAngle: a,
          endAngle: a += d * k
        };
      });
      return arcs;
    }
    pie.value = function(x) {
      if (!arguments.length) return value;
      value = x;
      return pie;
    };
    pie.sort = function(x) {
      if (!arguments.length) return sort;
      sort = x;
      return pie;
    };
    pie.startAngle = function(x) {
      if (!arguments.length) return startAngle;
      startAngle = x;
      return pie;
    };
    pie.endAngle = function(x) {
      if (!arguments.length) return endAngle;
      endAngle = x;
      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) {
      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 n = series.length, m = series[0].length, 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.hierarchy = function() {
    var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue;
    function recurse(node, depth, nodes) {
      var childs = children.call(hierarchy, node, depth);
      node.depth = depth;
      nodes.push(node);
      if (childs && (n = childs.length)) {
        var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d;
        while (++i < n) {
          d = recurse(childs[i], j, nodes);
          d.parent = node;
          c.push(d);
          v += d.value;
        }
        if (sort) c.sort(sort);
        if (value) node.value = v;
      } else if (value) {
        node.value = +value.call(hierarchy, node, depth) || 0;
      }
      return node;
    }
    function revalue(node, depth) {
      var children = node.children, v = 0;
      if (children && (n = children.length)) {
        var i = -1, n, j = depth + 1;
        while (++i < n) v += revalue(children[i], j);
      } else if (value) {
        v = +value.call(hierarchy, node, depth) || 0;
      }
      if (value) node.value = v;
      return v;
    }
    function hierarchy(d) {
      var nodes = [];
      recurse(d, 0, nodes);
      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) {
      revalue(root, 0);
      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_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.pack = function() {
    var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ];
    function pack(d, i) {
      var nodes = hierarchy.call(this, d, i), root = nodes[0];
      root.x = 0;
      root.y = 0;
      d3_layout_treeVisitAfter(root, function(d) {
        d.r = Math.sqrt(d.value);
      });
      d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
      var w = size[0], h = size[1], k = Math.max(2 * root.r / w, 2 * root.r / h);
      if (padding > 0) {
        var dr = padding * k / 2;
        d3_layout_treeVisitAfter(root, function(d) {
          d.r += dr;
        });
        d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
        d3_layout_treeVisitAfter(root, function(d) {
          d.r -= dr;
        });
        k = Math.max(2 * root.r / w, 2 * root.r / h);
      }
      d3_layout_packTransform(root, w / 2, h / 2, 1 / k);
      return nodes;
    }
    pack.size = function(x) {
      if (!arguments.length) return size;
      size = x;
      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 dr * dr - dx * dx - dy * dy > .001;
  }
  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.cluster = function() {
    var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ];
    function cluster(d, i) {
      var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0;
      d3_layout_treeVisitAfter(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_treeVisitAfter(root, 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 size;
      size = x;
      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.tree = function() {
    var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ];
    function tree(d, i) {
      var nodes = hierarchy.call(this, d, i), root = nodes[0];
      function firstWalk(node, previousSibling) {
        var children = node.children, layout = node._tree;
        if (children && (n = children.length)) {
          var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1;
          while (++i < n) {
            child = children[i];
            firstWalk(child, previousChild);
            ancestor = apportion(child, previousChild, ancestor);
            previousChild = child;
          }
          d3_layout_treeShift(node);
          var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim);
          if (previousSibling) {
            layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
            layout.mod = layout.prelim - midpoint;
          } else {
            layout.prelim = midpoint;
          }
        } else {
          if (previousSibling) {
            layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
          }
        }
      }
      function secondWalk(node, x) {
        node.x = node._tree.prelim + x;
        var children = node.children;
        if (children && (n = children.length)) {
          var i = -1, n;
          x += node._tree.mod;
          while (++i < n) {
            secondWalk(children[i], x);
          }
        }
      }
      function apportion(node, previousSibling, ancestor) {
        if (previousSibling) {
          var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, 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._tree.ancestor = node;
            shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip);
            if (shift > 0) {
              d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift);
              sip += shift;
              sop += shift;
            }
            sim += vim._tree.mod;
            sip += vip._tree.mod;
            som += vom._tree.mod;
            sop += vop._tree.mod;
          }
          if (vim && !d3_layout_treeRight(vop)) {
            vop._tree.thread = vim;
            vop._tree.mod += sim - sop;
          }
          if (vip && !d3_layout_treeLeft(vom)) {
            vom._tree.thread = vip;
            vom._tree.mod += sip - som;
            ancestor = node;
          }
        }
        return ancestor;
      }
      d3_layout_treeVisitAfter(root, function(node, previousSibling) {
        node._tree = {
          ancestor: node,
          prelim: 0,
          mod: 0,
          change: 0,
          shift: 0,
          number: previousSibling ? previousSibling._tree.number + 1 : 0
        };
      });
      firstWalk(root);
      secondWalk(root, -root._tree.prelim);
      var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1;
      d3_layout_treeVisitAfter(root, function(node) {
        node.x = (node.x - x0) / (x1 - x0) * size[0];
        node.y = node.depth / y1 * size[1];
        delete node._tree;
      });
      return nodes;
    }
    tree.separation = function(x) {
      if (!arguments.length) return separation;
      separation = x;
      return tree;
    };
    tree.size = function(x) {
      if (!arguments.length) return size;
      size = x;
      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(node) {
    var children = node.children;
    return children && children.length ? children[0] : node._tree.thread;
  }
  function d3_layout_treeRight(node) {
    var children = node.children, n;
    return children && (n = children.length) ? children[n - 1] : node._tree.thread;
  }
  function d3_layout_treeSearch(node, compare) {
    var children = node.children;
    if (children && (n = children.length)) {
      var child, n, i = -1;
      while (++i < n) {
        if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
          node = child;
        }
      }
    }
    return node;
  }
  function d3_layout_treeRightmost(a, b) {
    return a.x - b.x;
  }
  function d3_layout_treeLeftmost(a, b) {
    return b.x - a.x;
  }
  function d3_layout_treeDeepest(a, b) {
    return a.depth - b.depth;
  }
  function d3_layout_treeVisitAfter(node, callback) {
    function visit(node, previousSibling) {
      var children = node.children;
      if (children && (n = children.length)) {
        var child, previousChild = null, i = -1, n;
        while (++i < n) {
          child = children[i];
          visit(child, previousChild);
          previousChild = child;
        }
      }
      callback(node, previousSibling);
    }
    visit(node, null);
  }
  function d3_layout_treeShift(node) {
    var shift = 0, change = 0, children = node.children, i = children.length, child;
    while (--i >= 0) {
      child = children[i]._tree;
      child.prelim += shift;
      child.mod += shift;
      shift += child.shift + (change += child.change);
    }
  }
  function d3_layout_treeMove(ancestor, node, shift) {
    ancestor = ancestor._tree;
    node = node._tree;
    var change = shift / (node.number - ancestor.number);
    ancestor.change += change;
    node.change -= change;
    node.shift += shift;
    node.prelim += shift;
    node.mod += shift;
  }
  function d3_layout_treeAncestor(vim, node, ancestor) {
    return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor;
  }
  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 = 0;
      root.y = 0;
      root.dx = size[0];
      root.dy = size[1];
      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
    };
  }
  function d3_dsv(delimiter, mimeType) {
    var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0);
    function dsv(url, callback) {
      return d3.xhr(url, mimeType, callback).response(response);
    }
    function response(request) {
      return dsv.parse(request.responseText);
    }
    dsv.parse = function(text) {
      var o;
      return dsv.parseRows(text, function(row) {
        if (o) return o(row);
        o = new Function("d", "return {" + row.map(function(name, i) {
          return JSON.stringify(name) + ": d[" + i + "]";
        }).join(",") + "}");
      });
    };
    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.substring(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.substring(j, I - k);
        }
        return text.substring(j);
      }
      while ((t = token()) !== EOF) {
        var a = [];
        while (t !== EOL && t !== EOF) {
          a.push(t);
          t = token();
        }
        if (f && !(a = f(a, n++))) continue;
        rows.push(a);
      }
      return rows;
    };
    dsv.format = 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");
  d3.geo = {};
  d3.geo.stream = function(object, listener) {
    if (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 (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) {
      var coordinate = object.coordinates;
      listener.point(coordinate[0], coordinate[1]);
    },
    MultiPoint: function(object, listener) {
      var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate;
      while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]);
    },
    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]);
    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();
  }
  function d3_geo_spherical(cartesian) {
    return [ Math.atan2(cartesian[1], cartesian[0]), Math.asin(Math.max(-1, Math.min(1, cartesian[2]))) ];
  }
  function d3_geo_sphericalEqual(a, b) {
    return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε;
  }
  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_resample(project) {
    var δ2 = .5, maxDepth = 16;
    function resample(stream) {
      var λ0, x0, y0, a0, b0, c0;
      var resample = {
        point: point,
        lineStart: lineStart,
        lineEnd: lineEnd,
        polygonStart: function() {
          stream.polygonStart();
          resample.lineStart = polygonLineStart;
        },
        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 polygonLineStart() {
        var λ00, φ00, x00, y00, a00, b00, c00;
        lineStart();
        resample.point = function(λ, φ) {
          linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
          resample.point = linePoint;
        };
        resample.lineEnd = function() {
          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 = Math.abs(Math.abs(c) - 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 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3) {
          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.albersUsa = function() {
    var lower48 = d3.geo.albers();
    var alaska = d3.geo.albers().rotate([ 160, 0 ]).center([ 0, 60 ]).parallels([ 55, 65 ]);
    var hawaii = d3.geo.albers().rotate([ 160, 0 ]).center([ 0, 20 ]).parallels([ 8, 18 ]);
    var puertoRico = d3.geo.albers().rotate([ 60, 0 ]).center([ 0, 10 ]).parallels([ 8, 18 ]);
    function albersUsa(coordinates) {
      return projection(coordinates)(coordinates);
    }
    function projection(point) {
      var lon = point[0], lat = point[1];
      return lat > 50 ? alaska : lon < -140 ? hawaii : lat < 21 ? puertoRico : lower48;
    }
    albersUsa.scale = function(x) {
      if (!arguments.length) return lower48.scale();
      lower48.scale(x);
      alaska.scale(x * .6);
      hawaii.scale(x);
      puertoRico.scale(x * 1.5);
      return albersUsa.translate(lower48.translate());
    };
    albersUsa.translate = function(x) {
      if (!arguments.length) return lower48.translate();
      var dz = lower48.scale(), dx = x[0], dy = x[1];
      lower48.translate(x);
      alaska.translate([ dx - .4 * dz, dy + .17 * dz ]);
      hawaii.translate([ dx - .19 * dz, dy + .2 * dz ]);
      puertoRico.translate([ dx + .58 * dz, dy + .43 * dz ]);
      return albersUsa;
    };
    return albersUsa.scale(lower48.scale());
  };
  function d3_geo_albers(φ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 albers(λ, φ) {
      var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n;
      return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ];
    }
    albers.invert = function(x, y) {
      var ρ0_y = ρ0 - y;
      return [ Math.atan2(x, ρ0_y) / n, Math.asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ];
    };
    return albers;
  }
  (d3.geo.albers = function() {
    var φ0 = 29.5 * d3_radians, φ1 = 45.5 * d3_radians, m = d3_geo_projectionMutator(d3_geo_albers), p = m(φ0, φ1);
    p.parallels = function(_) {
      if (!arguments.length) return [ φ0 * d3_degrees, φ1 * d3_degrees ];
      return m(φ0 = _[0] * d3_radians, φ1 = _[1] * d3_radians);
    };
    return p.rotate([ 98, 0 ]).center([ 0, 38 ]).scale(1e3);
  }).raw = d3_geo_albers;
  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;
  d3.geo.bounds = d3_geo_bounds(d3_identity);
  function d3_geo_bounds(projectStream) {
    var x0, y0, x1, y1;
    var bound = {
      point: boundPoint,
      lineStart: d3_noop,
      lineEnd: d3_noop,
      polygonStart: function() {
        bound.lineEnd = boundPolygonLineEnd;
      },
      polygonEnd: function() {
        bound.point = boundPoint;
      }
    };
    function boundPoint(x, y) {
      if (x < x0) x0 = x;
      if (x > x1) x1 = x;
      if (y < y0) y0 = y;
      if (y > y1) y1 = y;
    }
    function boundPolygonLineEnd() {
      bound.point = bound.lineEnd = d3_noop;
    }
    return function(feature) {
      y1 = x1 = -(x0 = y0 = Infinity);
      d3.geo.stream(feature, projectStream(bound));
      return [ [ x0, y0 ], [ x1, y1 ] ];
    };
  }
  d3.geo.centroid = function(object) {
    d3_geo_centroidDimension = d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
    d3.geo.stream(object, d3_geo_centroid);
    var m;
    if (d3_geo_centroidW && Math.abs(m = Math.sqrt(d3_geo_centroidX * d3_geo_centroidX + d3_geo_centroidY * d3_geo_centroidY + d3_geo_centroidZ * d3_geo_centroidZ)) > ε) {
      return [ Math.atan2(d3_geo_centroidY, d3_geo_centroidX) * d3_degrees, Math.asin(Math.max(-1, Math.min(1, d3_geo_centroidZ / m))) * d3_degrees ];
    }
  };
  var d3_geo_centroidDimension, d3_geo_centroidW, d3_geo_centroidX, d3_geo_centroidY, d3_geo_centroidZ;
  var d3_geo_centroid = {
    sphere: function() {
      if (d3_geo_centroidDimension < 2) {
        d3_geo_centroidDimension = 2;
        d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
      }
    },
    point: d3_geo_centroidPoint,
    lineStart: d3_geo_centroidLineStart,
    lineEnd: d3_geo_centroidLineEnd,
    polygonStart: function() {
      if (d3_geo_centroidDimension < 2) {
        d3_geo_centroidDimension = 2;
        d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
      }
      d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
    },
    polygonEnd: function() {
      d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
    }
  };
  function d3_geo_centroidPoint(λ, φ) {
    if (d3_geo_centroidDimension) return;
    ++d3_geo_centroidW;
    λ *= d3_radians;
    var cosφ = Math.cos(φ *= d3_radians);
    d3_geo_centroidX += (cosφ * Math.cos(λ) - d3_geo_centroidX) / d3_geo_centroidW;
    d3_geo_centroidY += (cosφ * Math.sin(λ) - d3_geo_centroidY) / d3_geo_centroidW;
    d3_geo_centroidZ += (Math.sin(φ) - d3_geo_centroidZ) / d3_geo_centroidW;
  }
  function d3_geo_centroidRingStart() {
    var λ00, φ00;
    d3_geo_centroidDimension = 1;
    d3_geo_centroidLineStart();
    d3_geo_centroidDimension = 2;
    var linePoint = d3_geo_centroid.point;
    d3_geo_centroid.point = function(λ, φ) {
      linePoint(λ00 = λ, φ00 = φ);
    };
    d3_geo_centroid.lineEnd = function() {
      d3_geo_centroid.point(λ00, φ00);
      d3_geo_centroidLineEnd();
      d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
    };
  }
  function d3_geo_centroidLineStart() {
    var x0, y0, z0;
    if (d3_geo_centroidDimension > 1) return;
    if (d3_geo_centroidDimension < 1) {
      d3_geo_centroidDimension = 1;
      d3_geo_centroidW = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
    }
    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;
    };
    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_centroidW += w;
      d3_geo_centroidX += w * (x0 + (x0 = x));
      d3_geo_centroidY += w * (y0 + (y0 = y));
      d3_geo_centroidZ += w * (z0 + (z0 = z));
    }
  }
  function d3_geo_centroidLineEnd() {
    d3_geo_centroid.point = d3_geo_centroidPoint;
  }
  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(radians, precision) {
    var cr = Math.cos(radians), sr = Math.sin(radians);
    return function(from, to, direction, listener) {
      if (from != null) {
        from = d3_geo_circleAngle(cr, from);
        to = d3_geo_circleAngle(cr, to);
        if (direction > 0 ? from < to : from > to) from += direction * 2 * π;
      } else {
        from = radians + direction * 2 * π;
        to = radians;
      }
      var point;
      for (var step = direction * precision, 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 = Math.acos(Math.max(-1, Math.min(1, -a[1])));
    return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
  }
  function d3_geo_clip(pointVisible, clipLine, interpolate) {
    return function(listener) {
      var line = clipLine(listener);
      var clip = {
        point: point,
        lineStart: lineStart,
        lineEnd: lineEnd,
        polygonStart: function() {
          clip.point = pointRing;
          clip.lineStart = ringStart;
          clip.lineEnd = ringEnd;
          invisible = false;
          invisibleArea = visibleArea = 0;
          segments = [];
          listener.polygonStart();
        },
        polygonEnd: function() {
          clip.point = point;
          clip.lineStart = lineStart;
          clip.lineEnd = lineEnd;
          segments = d3.merge(segments);
          if (segments.length) {
            d3_geo_clipPolygon(segments, interpolate, listener);
          } else if (visibleArea < -ε || invisible && invisibleArea < -ε) {
            listener.lineStart();
            interpolate(null, null, 1, listener);
            listener.lineEnd();
          }
          listener.polygonEnd();
          segments = null;
        },
        sphere: function() {
          listener.polygonStart();
          listener.lineStart();
          interpolate(null, null, 1, listener);
          listener.lineEnd();
          listener.polygonEnd();
        }
      };
      function point(λ, φ) {
        if (pointVisible(λ, φ)) listener.point(λ, φ);
      }
      function pointLine(λ, φ) {
        line.point(λ, φ);
      }
      function lineStart() {
        clip.point = pointLine;
        line.lineStart();
      }
      function lineEnd() {
        clip.point = point;
        line.lineEnd();
      }
      var segments, visibleArea, invisibleArea, invisible;
      var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), ring;
      function pointRing(λ, φ) {
        ringListener.point(λ, φ);
        ring.push([ λ, φ ]);
      }
      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;
        if (!n) {
          invisible = true;
          invisibleArea += d3_geo_clipAreaRing(ring, -1);
          ring = null;
          return;
        }
        ring = null;
        if (clean & 1) {
          segment = ringSegments[0];
          visibleArea += d3_geo_clipAreaRing(segment, 1);
          var n = segment.length - 1, i = -1, point;
          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_clipPolygon(segments, interpolate, listener) {
    var subject = [], clip = [];
    segments.forEach(function(segment) {
      var n = segment.length;
      if (n <= 1) return;
      var p0 = segment[0], p1 = segment[n - 1], a = {
        point: p0,
        points: segment,
        other: null,
        visited: false,
        entry: true,
        subject: true
      }, b = {
        point: p0,
        points: [ p0 ],
        other: a,
        visited: false,
        entry: false,
        subject: false
      };
      a.other = b;
      subject.push(a);
      clip.push(b);
      a = {
        point: p1,
        points: [ p1 ],
        other: null,
        visited: false,
        entry: false,
        subject: true
      };
      b = {
        point: p1,
        points: [ p1 ],
        other: a,
        visited: false,
        entry: true,
        subject: false
      };
      a.other = b;
      subject.push(a);
      clip.push(b);
    });
    clip.sort(d3_geo_clipSort);
    d3_geo_clipLinkCircular(subject);
    d3_geo_clipLinkCircular(clip);
    if (!subject.length) return;
    var start = subject[0], current, points, point;
    while (1) {
      current = start;
      while (current.visited) if ((current = current.next) === start) return;
      points = current.points;
      listener.lineStart();
      do {
        current.visited = current.other.visited = true;
        if (current.entry) {
          if (current.subject) {
            for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]);
          } else {
            interpolate(current.point, current.next.point, 1, listener);
          }
          current = current.next;
        } else {
          if (current.subject) {
            points = current.prev.points;
            for (var i = points.length; --i >= 0; ) listener.point((point = points[i])[0], point[1]);
          } else {
            interpolate(current.point, current.prev.point, -1, listener);
          }
          current = current.prev;
        }
        current = current.other;
        points = current.points;
      } while (!current.visited);
      listener.lineEnd();
    }
  }
  function d3_geo_clipLinkCircular(array) {
    if (!(n = array.length)) return;
    var n, i = 0, a = array[0], b;
    while (++i < n) {
      a.next = b = array[i];
      b.prev = a;
      a = b;
    }
    a.next = b = array[0];
    b.prev = a;
  }
  function d3_geo_clipSort(a, b) {
    return ((a = a.point)[0] < 0 ? a[1] - π / 2 - ε : π / 2 - a[1]) - ((b = b.point)[0] < 0 ? b[1] - π / 2 - ε : π / 2 - b[1]);
  }
  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;
      }
    };
  }
  function d3_geo_clipAreaRing(ring, invisible) {
    if (!(n = ring.length)) return 0;
    var n, i = 0, area = 0, p = ring[0], λ = p[0], φ = p[1], cosφ = Math.cos(φ), x0 = Math.atan2(invisible * Math.sin(λ) * cosφ, Math.sin(φ)), y0 = 1 - invisible * Math.cos(λ) * cosφ, x1 = x0, x, y;
    while (++i < n) {
      p = ring[i];
      cosφ = Math.cos(φ = p[1]);
      x = Math.atan2(invisible * Math.sin(λ = p[0]) * cosφ, Math.sin(φ));
      y = 1 - invisible * Math.cos(λ) * cosφ;
      if (Math.abs(y0 - 2) < ε && Math.abs(y - 2) < ε) continue;
      if (Math.abs(y) < ε || Math.abs(y0) < ε) {} else if (Math.abs(Math.abs(x - x0) - π) < ε) {
        if (y + y0 > 2) area += 4 * (x - x0);
      } else if (Math.abs(y0 - 2) < ε) area += 4 * (x - x1); else area += ((3 * π + x - x0) % (2 * π) - π) * (y0 + y);
      x1 = x0, x0 = x, y0 = y;
    }
    return area;
  }
  var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate);
  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λ = Math.abs(λ1 - λ0);
        if (Math.abs(dλ - π) < ε) {
          listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? π / 2 : -π / 2);
          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 (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
          if (Math.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 Math.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 * π / 2;
      listener.point(-π, φ);
      listener.point(0, φ);
      listener.point(π, φ);
      listener.point(π, 0);
      listener.point(π, -φ);
      listener.point(0, -φ);
      listener.point(-π, -φ);
      listener.point(-π, 0);
      listener.point(-π, φ);
    } else if (Math.abs(from[0] - to[0]) > ε) {
      var s = (from[0] < to[0] ? 1 : -1) * π;
      φ = direction * s / 2;
      listener.point(-s, φ);
      listener.point(0, φ);
      listener.point(s, φ);
    } else {
      listener.point(to[0], to[1]);
    }
  }
  function d3_geo_clipCircle(degrees) {
    var radians = degrees * d3_radians, cr = Math.cos(radians), interpolate = d3_geo_circleInterpolate(radians, 6 * d3_radians);
    return d3_geo_clip(visible, clipLine, interpolate);
    function visible(λ, φ) {
      return Math.cos(λ) * Math.cos(φ) > cr;
    }
    function clipLine(listener) {
      var point0, v0, v00, clean;
      return {
        lineStart: function() {
          v00 = v0 = false;
          clean = 1;
        },
        point: function(λ, φ) {
          var point1 = [ λ, φ ], point2, v = visible(λ, φ);
          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 (v0 = 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;
          }
          if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) listener.point(point1[0], point1[1]);
          point0 = point1;
        },
        lineEnd: function() {
          if (v0) listener.lineEnd();
          point0 = null;
        },
        clean: function() {
          return clean | (v00 && v0) << 1;
        }
      };
    }
    function intersect(a, b) {
      var pa = d3_geo_cartesian(a, 0), pb = d3_geo_cartesian(b, 0);
      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 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), t = Math.sqrt(w * w - uu * (d3_geo_cartesianDot(A, A) - 1)), q = d3_geo_cartesianScale(u, (-w - t) / uu);
      d3_geo_cartesianAdd(q, A);
      return d3_geo_spherical(q);
    }
  }
  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_geo_equirectangular(λ, φ) {
    return [ λ, φ ];
  }
  (d3.geo.equirectangular = function() {
    return d3_geo_projection(d3_geo_equirectangular).scale(250 / π);
  }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
  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;
  d3.geo.graticule = function() {
    var x1, x0, y1, y0, dx = 22.5, dy = dx, 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));
    }
    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 [ [ 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 [ dx, dy ];
      dx = +_[0], dy = +_[1];
      return graticule;
    };
    graticule.precision = function(_) {
      if (!arguments.length) return precision;
      precision = +_;
      x = d3_geo_graticuleX(y0, y1, precision);
      y = d3_geo_graticuleY(x0, x1, precision);
      return graticule;
    };
    return graticule.extent([ [ -180 + ε, -90 + ε ], [ 180 - ε, 90 - ε ] ]);
  };
  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 ];
      });
    };
  }
  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 = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)))), k = 1 / Math.sin(d);
    function interpolate(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_radians, Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_radians ];
    }
    interpolate.distance = d;
    return interpolate;
  }
  d3.geo.greatArc = function() {
    var source = d3_source, source_, target = d3_target, target_, precision = 6 * d3_radians, interpolate;
    function greatArc() {
      var p0 = source_ || source.apply(this, arguments), p1 = target_ || target.apply(this, arguments), i = interpolate || d3.geo.interpolate(p0, p1), t = 0, dt = precision / i.distance, coordinates = [ p0 ];
      while ((t += dt) < 1) coordinates.push(i(t));
      coordinates.push(p1);
      return {
        type: "LineString",
        coordinates: coordinates
      };
    }
    greatArc.distance = function() {
      return (interpolate || d3.geo.interpolate(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments))).distance;
    };
    greatArc.source = function(_) {
      if (!arguments.length) return source;
      source = _, source_ = typeof _ === "function" ? null : _;
      interpolate = source_ && target_ ? d3.geo.interpolate(source_, target_) : null;
      return greatArc;
    };
    greatArc.target = function(_) {
      if (!arguments.length) return target;
      target = _, target_ = typeof _ === "function" ? null : _;
      interpolate = source_ && target_ ? d3.geo.interpolate(source_, target_) : null;
      return greatArc;
    };
    greatArc.precision = function(_) {
      if (!arguments.length) return precision / d3_radians;
      precision = _ * d3_radians;
      return greatArc;
    };
    return greatArc;
  };
  function d3_geo_mercator(λ, φ) {
    return [ λ / (2 * π), Math.max(-.5, Math.min(+.5, Math.log(Math.tan(π / 4 + φ / 2)) / (2 * π))) ];
  }
  d3_geo_mercator.invert = function(x, y) {
    return [ 2 * π * x, 2 * Math.atan(Math.exp(2 * π * y)) - π / 2 ];
  };
  (d3.geo.mercator = function() {
    return d3_geo_projection(d3_geo_mercator).scale(500);
  }).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;
  d3.geo.path = function() {
    var pointRadius = 4.5, projection, context, projectStream, contextStream;
    function path(object) {
      if (object) d3.geo.stream(object, projectStream(contextStream.pointRadius(typeof pointRadius === "function" ? +pointRadius.apply(this, arguments) : pointRadius)));
      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_centroidDimension = d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
      d3.geo.stream(object, projectStream(d3_geo_pathCentroid));
      return d3_geo_centroidZ ? [ d3_geo_centroidX / d3_geo_centroidZ, d3_geo_centroidY / d3_geo_centroidZ ] : undefined;
    };
    path.bounds = function(object) {
      return d3_geo_bounds(projectStream)(object);
    };
    path.projection = function(_) {
      if (!arguments.length) return projection;
      projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity;
      return path;
    };
    path.context = function(_) {
      if (!arguments.length) return context;
      contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_);
      return path;
    };
    path.pointRadius = function(_) {
      if (!arguments.length) return pointRadius;
      pointRadius = typeof _ === "function" ? _ : +_;
      return path;
    };
    return path.projection(d3.geo.albersUsa()).context(null);
  };
  function d3_geo_pathCircle(radius) {
    return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + +2 * radius + "z";
  }
  function d3_geo_pathProjectStream(project) {
    var resample = d3_geo_resample(function(λ, φ) {
      return project([ λ * d3_degrees, φ * d3_degrees ]);
    });
    return function(stream) {
      stream = resample(stream);
      return {
        point: function(λ, φ) {
          stream.point(λ * d3_radians, φ * d3_radians);
        },
        sphere: function() {
          stream.sphere();
        },
        lineStart: function() {
          stream.lineStart();
        },
        lineEnd: function() {
          stream.lineEnd();
        },
        polygonStart: function() {
          stream.polygonStart();
        },
        polygonEnd: function() {
          stream.polygonEnd();
        }
      };
    };
  }
  function d3_geo_pathBuffer() {
    var pointCircle = d3_geo_pathCircle(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_pathCircle(_);
        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_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, y);
      context.arc(x, y, pointRadius, 0, 2 * π);
    }
    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;
  }
  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 += Math.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_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) {
    if (d3_geo_centroidDimension) return;
    d3_geo_centroidX += x;
    d3_geo_centroidY += y;
    ++d3_geo_centroidZ;
  }
  function d3_geo_pathCentroidLineStart() {
    var x0, y0;
    if (d3_geo_centroidDimension !== 1) {
      if (d3_geo_centroidDimension < 1) {
        d3_geo_centroidDimension = 1;
        d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
      } else return;
    }
    d3_geo_pathCentroid.point = function(x, y) {
      d3_geo_pathCentroid.point = nextPoint;
      x0 = x, y0 = y;
    };
    function nextPoint(x, y) {
      var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
      d3_geo_centroidX += z * (x0 + x) / 2;
      d3_geo_centroidY += z * (y0 + y) / 2;
      d3_geo_centroidZ += z;
      x0 = x, y0 = y;
    }
  }
  function d3_geo_pathCentroidLineEnd() {
    d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
  }
  function d3_geo_pathCentroidRingStart() {
    var x00, y00, x0, y0;
    if (d3_geo_centroidDimension < 2) {
      d3_geo_centroidDimension = 2;
      d3_geo_centroidX = d3_geo_centroidY = d3_geo_centroidZ = 0;
    }
    d3_geo_pathCentroid.point = function(x, y) {
      d3_geo_pathCentroid.point = nextPoint;
      x00 = x0 = x, y00 = y0 = y;
    };
    function nextPoint(x, y) {
      var z = y0 * x - x0 * y;
      d3_geo_centroidX += z * (x0 + x);
      d3_geo_centroidY += z * (y0 + y);
      d3_geo_centroidZ += z * 3;
      x0 = x, y0 = y;
    }
    d3_geo_pathCentroid.lineEnd = function() {
      nextPoint(x00, y00);
    };
  }
  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_areaRing;
  var d3_geo_area = {
    sphere: function() {
      d3_geo_areaSum += 4 * π;
    },
    point: d3_noop,
    lineStart: d3_noop,
    lineEnd: d3_noop,
    polygonStart: function() {
      d3_geo_areaRing = 0;
      d3_geo_area.lineStart = d3_geo_areaRingStart;
    },
    polygonEnd: function() {
      d3_geo_areaSum += d3_geo_areaRing < 0 ? 4 * π + d3_geo_areaRing : d3_geo_areaRing;
      d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
    }
  };
  function d3_geo_areaRingStart() {
    var λ00, φ00, λ1, λ0, φ0, cosφ0, sinφ0;
    d3_geo_area.point = function(λ, φ) {
      d3_geo_area.point = nextPoint;
      λ1 = λ0 = (λ00 = λ) * d3_radians, φ0 = (φ00 = φ) * d3_radians, cosφ0 = Math.cos(φ0), 
      sinφ0 = Math.sin(φ0);
    };
    function nextPoint(λ, φ) {
      λ *= d3_radians, φ *= d3_radians;
      if (Math.abs(Math.abs(φ0) - π / 2) < ε && Math.abs(Math.abs(φ) - π / 2) < ε) return;
      var cosφ = Math.cos(φ), sinφ = Math.sin(φ);
      if (Math.abs(φ0 - π / 2) < ε) d3_geo_areaRing += (λ - λ1) * 2; else {
        var dλ = λ - λ0, cosdλ = Math.cos(dλ), d = Math.atan2(Math.sqrt((d = cosφ * Math.sin(dλ)) * d + (d = cosφ0 * sinφ - sinφ0 * cosφ * cosdλ) * d), sinφ0 * sinφ + cosφ0 * cosφ * cosdλ), s = (d + π + φ0 + φ) / 4;
        d3_geo_areaRing += (dλ < 0 && dλ > -π || dλ > π ? -4 : 4) * Math.atan(Math.sqrt(Math.abs(Math.tan(s) * Math.tan(s - d / 2) * Math.tan(s - π / 4 - φ0 / 2) * Math.tan(s - π / 4 - φ / 2))));
      }
      λ1 = λ0, λ0 = λ, φ0 = φ, cosφ0 = cosφ, sinφ0 = sinφ;
    }
    d3_geo_area.lineEnd = function() {
      nextPoint(λ00, φ00);
    };
  }
  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, clip = d3_geo_clipAntimeridian, clipAngle = null;
    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(stream) {
      return d3_geo_projectionRadiansRotate(rotate, clip(projectResample(stream)));
    };
    projection.clipAngle = function(_) {
      if (!arguments.length) return clipAngle;
      clip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle(clipAngle = +_);
      return projection;
    };
    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 projection;
    }
    return function() {
      project = projectAt.apply(this, arguments);
      projection.invert = project.invert && invert;
      return reset();
    };
  }
  function d3_geo_projectionRadiansRotate(rotate, stream) {
    return {
      point: function(x, y) {
        y = rotate(x * d3_radians, y * d3_radians), x = y[0];
        stream.point(x > π ? x - 2 * π : x < -π ? x + 2 * π : x, y[1]);
      },
      sphere: function() {
        stream.sphere();
      },
      lineStart: function() {
        stream.lineStart();
      },
      lineEnd: function() {
        stream.lineEnd();
      },
      polygonStart: function() {
        stream.polygonStart();
      },
      polygonEnd: function() {
        stream.polygonEnd();
      }
    };
  }
  function d3_geo_rotation(δλ, δφ, δγ) {
    return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_equirectangular;
  }
  function d3_geo_forwardRotationλ(δλ) {
    return function(λ, φ) {
      return λ += δλ, [ λ > π ? λ - 2 * π : λ < -π ? λ + 2 * π : λ, φ ];
    };
  }
  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δφ), Math.asin(Math.max(-1, Math.min(1, 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δφ), Math.asin(Math.max(-1, Math.min(1, k * cosδφ - x * sinδφ))) ];
    };
    return rotation;
  }
  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_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;
  }
  d3.geom = {};
  d3.geom.hull = function(vertices) {
    if (vertices.length < 3) return [];
    var len = vertices.length, plen = len - 1, points = [], stack = [], i, j, h = 0, x1, y1, x2, y2, u, v, a, sp;
    for (i = 1; i < len; ++i) {
      if (vertices[i][1] < vertices[h][1]) {
        h = i;
      } else if (vertices[i][1] == vertices[h][1]) {
        h = vertices[i][0] < vertices[h][0] ? i : h;
      }
    }
    for (i = 0; i < len; ++i) {
      if (i === h) continue;
      y1 = vertices[i][1] - vertices[h][1];
      x1 = vertices[i][0] - vertices[h][0];
      points.push({
        angle: Math.atan2(y1, x1),
        index: i
      });
    }
    points.sort(function(a, b) {
      return a.angle - b.angle;
    });
    a = points[0].angle;
    v = points[0].index;
    u = 0;
    for (i = 1; i < plen; ++i) {
      j = points[i].index;
      if (a == points[i].angle) {
        x1 = vertices[v][0] - vertices[h][0];
        y1 = vertices[v][1] - vertices[h][1];
        x2 = vertices[j][0] - vertices[h][0];
        y2 = vertices[j][1] - vertices[h][1];
        if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) {
          points[i].index = -1;
        } else {
          points[u].index = -1;
          a = points[i].angle;
          u = i;
          v = j;
        }
      } else {
        a = points[i].angle;
        u = i;
        v = j;
      }
    }
    stack.push(h);
    for (i = 0, j = 0; i < 2; ++j) {
      if (points[j].index !== -1) {
        stack.push(points[j].index);
        i++;
      }
    }
    sp = stack.length;
    for (;j < plen; ++j) {
      if (points[j].index === -1) continue;
      while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) {
        --sp;
      }
      stack[sp++] = points[j].index;
    }
    var poly = [];
    for (i = 0; i < sp; ++i) {
      poly.push(vertices[stack[i]]);
    }
    return poly;
  };
  function d3_geom_hullCCW(i1, i2, i3, v) {
    var t, a, b, c, d, e, f;
    t = v[i1];
    a = t[0];
    b = t[1];
    t = v[i2];
    c = t[0];
    d = t[1];
    t = v[i3];
    e = t[0];
    f = t[1];
    return (f - b) * (c - a) - (d - b) * (e - a) > 0;
  }
  d3.geom.polygon = function(coordinates) {
    coordinates.area = function() {
      var i = 0, n = coordinates.length, area = coordinates[n - 1][1] * coordinates[0][0] - coordinates[n - 1][0] * coordinates[0][1];
      while (++i < n) {
        area += coordinates[i - 1][1] * coordinates[i][0] - coordinates[i - 1][0] * coordinates[i][1];
      }
      return area * .5;
    };
    coordinates.centroid = function(k) {
      var i = -1, n = coordinates.length, x = 0, y = 0, a, b = coordinates[n - 1], c;
      if (!arguments.length) k = -1 / (6 * coordinates.area());
      while (++i < n) {
        a = b;
        b = coordinates[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 ];
    };
    coordinates.clip = function(subject) {
      var input, i = -1, n = coordinates.length, j, m, a = coordinates[n - 1], b, c, d;
      while (++i < n) {
        input = subject.slice();
        subject.length = 0;
        b = coordinates[i];
        c = input[(m = input.length) - 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;
        }
        a = b;
      }
      return subject;
    };
    return coordinates;
  };
  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 ];
  }
  d3.geom.voronoi = function(vertices) {
    var polygons = vertices.map(function() {
      return [];
    }), Z = 1e6;
    d3_voronoi_tessellate(vertices, function(e) {
      var s1, s2, x1, x2, y1, y2;
      if (e.a === 1 && e.b >= 0) {
        s1 = e.ep.r;
        s2 = e.ep.l;
      } else {
        s1 = e.ep.l;
        s2 = e.ep.r;
      }
      if (e.a === 1) {
        y1 = s1 ? s1.y : -Z;
        x1 = e.c - e.b * y1;
        y2 = s2 ? s2.y : Z;
        x2 = e.c - e.b * y2;
      } else {
        x1 = s1 ? s1.x : -Z;
        y1 = e.c - e.a * x1;
        x2 = s2 ? s2.x : Z;
        y2 = e.c - e.a * x2;
      }
      var v1 = [ x1, y1 ], v2 = [ x2, y2 ];
      polygons[e.region.l.index].push(v1, v2);
      polygons[e.region.r.index].push(v1, v2);
    });
    polygons = polygons.map(function(polygon, i) {
      var cx = vertices[i][0], cy = vertices[i][1], angle = polygon.map(function(v) {
        return Math.atan2(v[0] - cx, v[1] - cy);
      });
      return d3.range(polygon.length).sort(function(a, b) {
        return angle[a] - angle[b];
      }).filter(function(d, i, order) {
        return !i || angle[d] - angle[order[i - 1]] > ε;
      }).map(function(d) {
        return polygon[d];
      });
    });
    polygons.forEach(function(polygon, i) {
      var n = polygon.length;
      if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]);
      if (n > 2) return;
      var p0 = vertices[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1;
      if (Math.abs(dy) < ε) {
        var y = y0 < y1 ? -Z : Z;
        polygon.push([ -Z, y ], [ Z, y ]);
      } else if (dx < ε) {
        var x = x0 < x1 ? -Z : Z;
        polygon.push([ x, -Z ], [ x, Z ]);
      } else {
        var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z = Math.abs(dy) - dx;
        if (Math.abs(z) < ε) {
          polygon.push([ dy < 0 ? y : -y, y ]);
        } else {
          if (z > 0) y *= -1;
          polygon.push([ -Z, y ], [ Z, y ]);
        }
      }
    });
    return polygons;
  };
  var d3_voronoi_opposite = {
    l: "r",
    r: "l"
  };
  function d3_voronoi_tessellate(vertices, callback) {
    var Sites = {
      list: vertices.map(function(v, i) {
        return {
          index: i,
          x: v[0],
          y: v[1]
        };
      }).sort(function(a, b) {
        return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0;
      }),
      bottomSite: null
    };
    var EdgeList = {
      list: [],
      leftEnd: null,
      rightEnd: null,
      init: function() {
        EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l");
        EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l");
        EdgeList.leftEnd.r = EdgeList.rightEnd;
        EdgeList.rightEnd.l = EdgeList.leftEnd;
        EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd);
      },
      createHalfEdge: function(edge, side) {
        return {
          edge: edge,
          side: side,
          vertex: null,
          l: null,
          r: null
        };
      },
      insert: function(lb, he) {
        he.l = lb;
        he.r = lb.r;
        lb.r.l = he;
        lb.r = he;
      },
      leftBound: function(p) {
        var he = EdgeList.leftEnd;
        do {
          he = he.r;
        } while (he != EdgeList.rightEnd && Geom.rightOf(he, p));
        he = he.l;
        return he;
      },
      del: function(he) {
        he.l.r = he.r;
        he.r.l = he.l;
        he.edge = null;
      },
      right: function(he) {
        return he.r;
      },
      left: function(he) {
        return he.l;
      },
      leftRegion: function(he) {
        return he.edge == null ? Sites.bottomSite : he.edge.region[he.side];
      },
      rightRegion: function(he) {
        return he.edge == null ? Sites.bottomSite : he.edge.region[d3_voronoi_opposite[he.side]];
      }
    };
    var Geom = {
      bisect: function(s1, s2) {
        var newEdge = {
          region: {
            l: s1,
            r: s2
          },
          ep: {
            l: null,
            r: null
          }
        };
        var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy;
        newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5;
        if (adx > ady) {
          newEdge.a = 1;
          newEdge.b = dy / dx;
          newEdge.c /= dx;
        } else {
          newEdge.b = 1;
          newEdge.a = dx / dy;
          newEdge.c /= dy;
        }
        return newEdge;
      },
      intersect: function(el1, el2) {
        var e1 = el1.edge, e2 = el2.edge;
        if (!e1 || !e2 || e1.region.r == e2.region.r) {
          return null;
        }
        var d = e1.a * e2.b - e1.b * e2.a;
        if (Math.abs(d) < 1e-10) {
          return null;
        }
        var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e;
        if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) {
          el = el1;
          e = e1;
        } else {
          el = el2;
          e = e2;
        }
        var rightOfSite = xint >= e.region.r.x;
        if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") {
          return null;
        }
        return {
          x: xint,
          y: yint
        };
      },
      rightOf: function(he, p) {
        var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x;
        if (rightOfSite && he.side === "l") {
          return 1;
        }
        if (!rightOfSite && he.side === "r") {
          return 0;
        }
        if (e.a === 1) {
          var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0;
          if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) {
            above = fast = dyp >= e.b * dxp;
          } else {
            above = p.x + p.y * e.b > e.c;
            if (e.b < 0) {
              above = !above;
            }
            if (!above) {
              fast = 1;
            }
          }
          if (!fast) {
            var dxs = topsite.x - e.region.l.x;
            above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b);
            if (e.b < 0) {
              above = !above;
            }
          }
        } else {
          var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y;
          above = t1 * t1 > t2 * t2 + t3 * t3;
        }
        return he.side === "l" ? above : !above;
      },
      endPoint: function(edge, side, site) {
        edge.ep[side] = site;
        if (!edge.ep[d3_voronoi_opposite[side]]) return;
        callback(edge);
      },
      distance: function(s, t) {
        var dx = s.x - t.x, dy = s.y - t.y;
        return Math.sqrt(dx * dx + dy * dy);
      }
    };
    var EventQueue = {
      list: [],
      insert: function(he, site, offset) {
        he.vertex = site;
        he.ystar = site.y + offset;
        for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) {
          var next = list[i];
          if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) {
            continue;
          } else {
            break;
          }
        }
        list.splice(i, 0, he);
      },
      del: function(he) {
        for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {}
        ls.splice(i, 1);
      },
      empty: function() {
        return EventQueue.list.length === 0;
      },
      nextEvent: function(he) {
        for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) {
          if (ls[i] == he) return ls[i + 1];
        }
        return null;
      },
      min: function() {
        var elem = EventQueue.list[0];
        return {
          x: elem.vertex.x,
          y: elem.ystar
        };
      },
      extractMin: function() {
        return EventQueue.list.shift();
      }
    };
    EdgeList.init();
    Sites.bottomSite = Sites.list.shift();
    var newSite = Sites.list.shift(), newIntStar;
    var lbnd, rbnd, llbnd, rrbnd, bisector;
    var bot, top, temp, p, v;
    var e, pm;
    while (true) {
      if (!EventQueue.empty()) {
        newIntStar = EventQueue.min();
      }
      if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) {
        lbnd = EdgeList.leftBound(newSite);
        rbnd = EdgeList.right(lbnd);
        bot = EdgeList.rightRegion(lbnd);
        e = Geom.bisect(bot, newSite);
        bisector = EdgeList.createHalfEdge(e, "l");
        EdgeList.insert(lbnd, bisector);
        p = Geom.intersect(lbnd, bisector);
        if (p) {
          EventQueue.del(lbnd);
          EventQueue.insert(lbnd, p, Geom.distance(p, newSite));
        }
        lbnd = bisector;
        bisector = EdgeList.createHalfEdge(e, "r");
        EdgeList.insert(lbnd, bisector);
        p = Geom.intersect(bisector, rbnd);
        if (p) {
          EventQueue.insert(bisector, p, Geom.distance(p, newSite));
        }
        newSite = Sites.list.shift();
      } else if (!EventQueue.empty()) {
        lbnd = EventQueue.extractMin();
        llbnd = EdgeList.left(lbnd);
        rbnd = EdgeList.right(lbnd);
        rrbnd = EdgeList.right(rbnd);
        bot = EdgeList.leftRegion(lbnd);
        top = EdgeList.rightRegion(rbnd);
        v = lbnd.vertex;
        Geom.endPoint(lbnd.edge, lbnd.side, v);
        Geom.endPoint(rbnd.edge, rbnd.side, v);
        EdgeList.del(lbnd);
        EventQueue.del(rbnd);
        EdgeList.del(rbnd);
        pm = "l";
        if (bot.y > top.y) {
          temp = bot;
          bot = top;
          top = temp;
          pm = "r";
        }
        e = Geom.bisect(bot, top);
        bisector = EdgeList.createHalfEdge(e, pm);
        EdgeList.insert(llbnd, bisector);
        Geom.endPoint(e, d3_voronoi_opposite[pm], v);
        p = Geom.intersect(llbnd, bisector);
        if (p) {
          EventQueue.del(llbnd);
          EventQueue.insert(llbnd, p, Geom.distance(p, bot));
        }
        p = Geom.intersect(bisector, rrbnd);
        if (p) {
          EventQueue.insert(bisector, p, Geom.distance(p, bot));
        }
      } else {
        break;
      }
    }
    for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) {
      callback(lbnd.edge);
    }
  }
  d3.geom.delaunay = function(vertices) {
    var edges = vertices.map(function() {
      return [];
    }), triangles = [];
    d3_voronoi_tessellate(vertices, function(e) {
      edges[e.region.l.index].push(vertices[e.region.r.index]);
    });
    edges.forEach(function(edge, i) {
      var v = vertices[i], cx = v[0], cy = v[1];
      edge.forEach(function(v) {
        v.angle = Math.atan2(v[0] - cx, v[1] - cy);
      });
      edge.sort(function(a, b) {
        return a.angle - b.angle;
      });
      for (var j = 0, m = edge.length - 1; j < m; j++) {
        triangles.push([ v, edge[j], edge[j + 1] ]);
      }
    });
    return triangles;
  };
  d3.geom.quadtree = function(points, x1, y1, x2, y2) {
    var p, i = -1, n = points.length;
    if (arguments.length < 5) {
      if (arguments.length === 3) {
        y2 = y1;
        x2 = x1;
        y1 = x1 = 0;
      } else {
        x1 = y1 = Infinity;
        x2 = y2 = -Infinity;
        while (++i < n) {
          p = points[i];
          if (p.x < x1) x1 = p.x;
          if (p.y < y1) y1 = p.y;
          if (p.x > x2) x2 = p.x;
          if (p.y > y2) y2 = p.y;
        }
      }
    }
    var dx = x2 - x1, dy = y2 - y1;
    if (dx > dy) y2 = y1 + dx; else x2 = x1 + dy;
    function insert(n, p, x1, y1, x2, y2) {
      if (isNaN(p.x) || isNaN(p.y)) return;
      if (n.leaf) {
        var v = n.point;
        if (v) {
          if (Math.abs(v.x - p.x) + Math.abs(v.y - p.y) < .01) {
            insertChild(n, p, x1, y1, x2, y2);
          } else {
            n.point = null;
            insertChild(n, v, x1, y1, x2, y2);
            insertChild(n, p, x1, y1, x2, y2);
          }
        } else {
          n.point = p;
        }
      } else {
        insertChild(n, p, x1, y1, x2, y2);
      }
    }
    function insertChild(n, p, x1, y1, x2, y2) {
      var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = p.x >= sx, bottom = p.y >= sy, i = (bottom << 1) + right;
      n.leaf = false;
      n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
      if (right) x1 = sx; else x2 = sx;
      if (bottom) y1 = sy; else y2 = sy;
      insert(n, p, x1, y1, x2, y2);
    }
    var root = d3_geom_quadtreeNode();
    root.add = function(p) {
      insert(root, p, x1, y1, x2, y2);
    };
    root.visit = function(f) {
      d3_geom_quadtreeVisit(f, root, x1, y1, x2, y2);
    };
    points.forEach(root.add);
    return root;
  };
  function d3_geom_quadtreeNode() {
    return {
      leaf: true,
      nodes: [],
      point: 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);
    }
  }
  d3.time = {};
  var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ];
  function d3_time_utc() {
    this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]);
  }
  d3_time_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;
  var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate = "%m/%d/%Y", d3_time_formatTime = "%H:%M:%S";
  var d3_time_days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
  d3.time.format = function(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.substring(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.substring(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
      }, 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 date = new d3_time();
      date.setFullYear(d.y, d.m, d.d);
      date.setHours(d.H, d.M, d.S, d.L);
      return date;
    };
    format.toString = function() {
      return template;
    };
    return format;
  };
  function d3_time_parse(date, template, string, j) {
    var c, p, i = 0, n = template.length, m = string.length;
    while (i < n) {
      if (j >= m) return -1;
      c = template.charCodeAt(i++);
      if (c === 37) {
        p = d3_time_parsers[template.charAt(i++)];
        if (!p || (j = p(date, string, j)) < 0) return -1;
      } else if (c != string.charCodeAt(j++)) {
        return -1;
      }
    }
    return j;
  }
  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_formatPad(value, fill, width) {
    value += "";
    var length = value.length;
    return length < width ? new Array(width - length + 1).join(fill) + value : value;
  }
  var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations);
  var d3_time_formatPads = {
    "-": "",
    _: " ",
    "0": "0"
  };
  var d3_time_formats = {
    a: function(d) {
      return d3_time_dayAbbreviations[d.getDay()];
    },
    A: function(d) {
      return d3_time_days[d.getDay()];
    },
    b: function(d) {
      return d3_time_monthAbbreviations[d.getMonth()];
    },
    B: function(d) {
      return d3_time_months[d.getMonth()];
    },
    c: d3.time.format(d3_time_formatDateTime),
    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 d.getHours() >= 12 ? "PM" : "AM";
    },
    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(d3_time_formatDate),
    X: d3.time.format(d3_time_formatTime),
    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,
    L: d3_time_parseMilliseconds,
    m: d3_time_parseMonthNumber,
    M: d3_time_parseMinutes,
    p: d3_time_parseAmPm,
    S: d3_time_parseSeconds,
    x: d3_time_parseLocaleDate,
    X: d3_time_parseLocaleTime,
    y: d3_time_parseYear,
    Y: d3_time_parseFullYear
  };
  function d3_time_parseWeekdayAbbrev(date, string, i) {
    d3_time_dayAbbrevRe.lastIndex = 0;
    var n = d3_time_dayAbbrevRe.exec(string.substring(i));
    return n ? i += n[0].length : -1;
  }
  function d3_time_parseWeekday(date, string, i) {
    d3_time_dayRe.lastIndex = 0;
    var n = d3_time_dayRe.exec(string.substring(i));
    return n ? i += n[0].length : -1;
  }
  function d3_time_parseMonthAbbrev(date, string, i) {
    d3_time_monthAbbrevRe.lastIndex = 0;
    var n = d3_time_monthAbbrevRe.exec(string.substring(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.substring(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_parseFullYear(date, string, i) {
    d3_time_numberRe.lastIndex = 0;
    var n = d3_time_numberRe.exec(string.substring(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.substring(i, i + 2));
    return n ? (date.y = d3_time_expandYear(+n[0]), i += n[0].length) : -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.substring(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.substring(i, i + 2));
    return n ? (date.d = +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.substring(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.substring(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.substring(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.substring(i, i + 3));
    return n ? (date.L = +n[0], i += n[0].length) : -1;
  }
  var d3_time_numberRe = /^\s*\d+/;
  function d3_time_parseAmPm(date, string, i) {
    var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase());
    return n == null ? -1 : (date.p = n, i);
  }
  var d3_time_amPmLookup = d3.map({
    am: 0,
    pm: 1
  });
  function d3_time_zone(d) {
    var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60;
    return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2);
  }
  d3.time.format.utc = function(template) {
    var local = d3.time.format(template);
    function format(date) {
      try {
        d3_time = d3_time_utc;
        var utc = new d3_time();
        utc._ = date;
        return local(utc);
      } finally {
        d3_time = Date;
      }
    }
    format.parse = function(string) {
      try {
        d3_time = d3_time_utc;
        var date = local.parse(string);
        return date && date._;
      } finally {
        d3_time = Date;
      }
    };
    format.toString = local.toString;
    return format;
  };
  var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");
  d3.time.format.iso = Date.prototype.toISOString ? 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;
  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_time(date - 1)), 1);
      return date;
    }
    function offset(date, k) {
      step(date = new d3_time(+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_time = d3_time_utc;
        var utc = new d3_time_utc();
        utc._ = t0;
        return range(utc, t1, dt);
      } finally {
        d3_time = 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_time = d3_time_utc;
        var utc = new d3_time_utc();
        utc._ = date;
        return method(utc, k)._;
      } finally {
        d3_time = Date;
      }
    };
  }
  d3.time.second = d3_time_interval(function(date) {
    return new d3_time(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_time(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_time((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.day = d3_time_interval(function(date) {
    var day = new d3_time(1970, 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);
  };
  d3_time_daySymbols.forEach(function(day, i) {
    day = day.toLowerCase();
    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;
  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;
  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;
  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;
    };
    scale.nice = function(m) {
      return scale.domain(d3_scale_nice(scale.domain(), function() {
        return m;
      }));
    };
    scale.ticks = function(m, k) {
      var extent = d3_time_scaleExtent(scale.domain());
      if (typeof m !== "function") {
        var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target);
        if (i == d3_time_scaleSteps.length) return methods.year(extent, m);
        if (!i) return linear.ticks(m).map(d3_time_scaleDate);
        if (Math.log(target / d3_time_scaleSteps[i - 1]) < Math.log(d3_time_scaleSteps[i] / target)) --i;
        m = methods[i];
        k = m[1];
        m = m[0].range;
      }
      return m(extent[0], new Date(+extent[1] + 1), k);
    };
    scale.tickFormat = function() {
      return format;
    };
    scale.copy = function() {
      return d3_time_scale(linear.copy(), methods, format);
    };
    return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
  }
  function d3_time_scaleExtent(domain) {
    var start = domain[0], stop = domain[domain.length - 1];
    return start < stop ? [ start, stop ] : [ stop, start ];
  }
  function d3_time_scaleDate(t) {
    return new Date(t);
  }
  function d3_time_scaleFormat(formats) {
    return function(date) {
      var i = formats.length - 1, f = formats[i];
      while (!f[1](date)) f = formats[--i];
      return f[0](date);
    };
  }
  function d3_time_scaleSetYear(y) {
    var d = new Date(y, 0, 1);
    d.setFullYear(y);
    return d;
  }
  function d3_time_scaleGetYear(d) {
    var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1);
    return y + (d - d0) / (d1 - d0);
  }
  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_scaleLocalFormats = [ [ d3.time.format("%Y"), d3_true ], [ d3.time.format("%B"), function(d) {
    return d.getMonth();
  } ], [ d3.time.format("%b %d"), function(d) {
    return d.getDate() != 1;
  } ], [ d3.time.format("%a %d"), function(d) {
    return d.getDay() && d.getDate() != 1;
  } ], [ d3.time.format("%I %p"), function(d) {
    return d.getHours();
  } ], [ d3.time.format("%I:%M"), function(d) {
    return d.getMinutes();
  } ], [ d3.time.format(":%S"), function(d) {
    return d.getSeconds();
  } ], [ d3.time.format(".%L"), function(d) {
    return d.getMilliseconds();
  } ] ];
  var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats);
  d3_time_scaleLocalMethods.year = function(extent, m) {
    return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear);
  };
  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_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), d3_true ], [ d3.time.format.utc("%B"), function(d) {
    return d.getUTCMonth();
  } ], [ d3.time.format.utc("%b %d"), function(d) {
    return d.getUTCDate() != 1;
  } ], [ d3.time.format.utc("%a %d"), function(d) {
    return d.getUTCDay() && d.getUTCDate() != 1;
  } ], [ d3.time.format.utc("%I %p"), function(d) {
    return d.getUTCHours();
  } ], [ d3.time.format.utc("%I:%M"), function(d) {
    return d.getUTCMinutes();
  } ], [ d3.time.format.utc(":%S"), function(d) {
    return d.getUTCSeconds();
  } ], [ d3.time.format.utc(".%L"), function(d) {
    return d.getUTCMilliseconds();
  } ] ];
  var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats);
  function d3_time_scaleUTCSetYear(y) {
    var d = new Date(Date.UTC(y, 0, 1));
    d.setUTCFullYear(y);
    return d;
  }
  function d3_time_scaleUTCGetYear(d) {
    var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1);
    return y + (d - d0) / (d1 - d0);
  }
  d3_time_scaleUTCMethods.year = function(extent, m) {
    return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear);
  };
  d3.time.scale.utc = function() {
    return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat);
  };
})();
;
(function() {
  var $, colorize_tickers, colors, default_precision_key, metadata, prepare_record, prepare_ticker, render_ticker, render_tickers, reorder_tickers, scope, securities_cache, set_tickers_states, tickers_cache, widget;

  $ = jQuery;

  scope = this.mx.chart;

  metadata = void 0;

  tickers_cache = {};

  securities_cache = {};

  default_precision_key = 'DECIMALS';

  colors = d3.scale.category20().domain(d3.range(20));

  prepare_ticker = function(ticker) {
    var board, id, _ref;

    _ref = ticker.split(':'), board = _ref[0], id = _ref[1];
    return [metadata.board(board), id];
  };

  prepare_record = function(record, columns) {
    var default_precision, precisions;

    columns = columns.hash('name');
    default_precision = record[default_precision_key];
    precisions = {};
    Object.keys(record).forEach(function(key) {
      var column, value, _ref;

      column = columns[key];
      if ((column != null) && column.type === 'number') {
        value = parseFloat(record[key]) || void 0;
        precisions[key] = (_ref = column.precision) != null ? _ref : default_precision;
        if (value != null) {
          return record[key] = parseFloat(value.toFixed(precisions[key]));
        }
      }
    });
    record.precisions = precisions;
    return record;
  };

  render_tickers = function(html, tickers) {
    var views;

    views = html.children('li.ticker');
    $.each(tickers, function(i, ticker) {
      var view;

      view = views.filter(function(i) {
        return $(views[i]).data('ticker') === ticker;
      });
      if (view.length === 0) {
        view = render_ticker(ticker);
      }
      if (view != null) {
        return html.append(view);
      }
    });
    views = html.children('li.ticker');
    return views.each(function(i, view) {
      view = $(view);
      if (tickers.indexOf(view.data('ticker')) < 0) {
        return view.remove();
      }
    });
  };

  render_ticker = function(ticker) {
    if (!((securities_cache[ticker] != null) && (tickers_cache[ticker] != null))) {
      return;
    }
    return ich.chart_instruments_ticker({
      ticker: ticker,
      id: securities_cache[ticker].SECID,
      group: tickers_cache[ticker][0].boardgroup.title
    });
  };

  reorder_tickers = function(html, tickers) {
    var views;

    views = html.children('li.ticker');
    return $.each(tickers, function(i, ticker) {
      return views.filter(function(i) {
        return $(views[i]).data('ticker') === ticker;
      }).appendTo(html);
    });
  };

  set_tickers_states = function(html, off_tickers) {
    var views;

    views = html.children('li.ticker').removeClass('off');
    return $.each(off_tickers, function(i, ticker) {
      return views.filter(function(i) {
        return $(views[i]).data('ticker') === ticker;
      }).addClass('off');
    });
  };

  colorize_tickers = function(html) {
    return $('> li.ticker > a.dropdown-toggle', html).each(function(i) {
      var item, offset;

      item = $(this);
      offset = item.parent().hasClass('off') ? 1 : 0;
      item.css('color', colors(i * 2 + offset));
      return item.children('\
        .caret').css('border-top-color', colors(i * 2 + offset));
    });
  };

  widget = function(options) {
    var add_ticker, container, deferred, html, off_tickers, ready, remove_ticker, render, ticker_present, tickers, toggle_ticker;

    if (options == null) {
      options = {};
    }
    container = $(options.container);
    if (container.length === 0) {
      container = void 0;
    }
    deferred = new $.Deferred;
    html = $('<ul>').addClass('nav nav-pills chart-tickers');
    if (metadata == null) {
      metadata = mx.data.metadata();
    }
    ready = $.when(metadata);
    tickers = [];
    off_tickers = [];
    ticker_present = function(ticker) {
      var board, id, _ref;

      _ref = ticker.split(':'), board = _ref[0], id = _ref[1];
      board = metadata.board(board);
      return tickers.some(function(item) {
        var b, i, _ref1;

        _ref1 = tickers_cache[item], b = _ref1[0], i = _ref1[1];
        return i === id && b.engine.name === board.engine.name && b.market.name === board.market.name;
      });
    };
    add_ticker = function(ticker) {
      var board, columns, id, security, _ref, _ref1, _ref2;

      if (ticker_present(ticker)) {
        return;
      }
      tickers.push(ticker);
      _ref1 = (_ref = tickers_cache[ticker]) != null ? _ref : tickers_cache[ticker] = prepare_ticker(ticker), board = _ref1[0], id = _ref1[1];
      security = (_ref2 = securities_cache[ticker]) != null ? _ref2 : mx.iss.security_marketdata(board.engine.name, board.market.name, board.id, id);
      columns = mx.iss.security_marketdata_columns(board.engine.name, board.market.name);
      return $.when(security, columns).then(function() {
        var _ref3;

        if ((_ref3 = securities_cache[ticker]) == null) {
          securities_cache[ticker] = prepare_record(security.result.data.security, columns.result.data);
        }
        return render();
      });
    };
    remove_ticker = function(ticker) {
      var ticker_index;

      ticker_index = tickers.indexOf(ticker);
      if (ticker_index < 0) {
        return;
      }
      tickers.splice(ticker_index, 1);
      return render();
    };
    toggle_ticker = function(ticker) {
      var off_ticker_index, ticker_index;

      ticker_index = tickers.indexOf(ticker);
      if (ticker_index < 0) {
        return;
      }
      off_ticker_index = off_tickers.indexOf(ticker);
      if (off_ticker_index < 0) {
        off_tickers.push(ticker);
      } else {
        off_tickers.splice(off_ticker_index, 1);
      }
      return render();
    };
    render = function() {
      if (container != null) {
        render_tickers(html, tickers);
        reorder_tickers(html, tickers);
        set_tickers_states(html, off_tickers);
        colorize_tickers(html);
        if (!$.contains(container, html)) {
          container.append(html);
          html.sortable({
            tolerance: 'pointer',
            start: function(event, ui) {
              return ui.helper.removeClass('open').blur();
            },
            update: function() {
              tickers = html.children('li.ticker').map(function(i, view) {
                return $(view).data('ticker');
              }).get();
              return render();
            }
          });
        }
      }
      return deferred.resolve();
    };
    ready.then(function() {
      if (options.ticker != null) {
        add_ticker(options.ticker);
      }
      html.on('chart:ticker:on chart:ticker:off', function(event, ticker) {
        return toggle_ticker(ticker);
      });
      html.on('chart:ticker:remove', function(event, ticker) {
        return remove_ticker(ticker);
      });
      return render();
    });
    return deferred.promise({
      tickers: function() {
        return tickers;
      },
      add_ticker: add_ticker,
      remove_ticker: remove_ticker
    });
  };

  $.extend(scope, {
    instruments_widget: widget
  });

  $(document).on('click', '.chart-tickers a[data-action]', function(event) {
    var action, container, el, ticker;

    event.stopPropagation();
    event.preventDefault();
    el = $(this);
    action = el.data('action');
    ticker = el.closest('li.ticker').data('ticker');
    container = el.closest('ul.chart-tickers');
    container.trigger("chart:ticker:" + action, ticker);
    return el.parent().click();
  });

}).call(this);
;
(function() {
  var $, metadata, scope, widget;

  $ = jQuery;

  scope = this.mx.chart;

  metadata = void 0;

  widget = function(options) {
    var container, deferred, html, ready, render, technicals;

    if (options == null) {
      options = {};
    }
    container = $(options.container);
    if (container.length === 0) {
      container = void 0;
    }
    deferred = new $.Deferred;
    if (metadata == null) {
      metadata = mx.data.metadata();
    }
    html = void 0;
    technicals = [];
    ready = $.when(metadat);
    render = function() {
      if (container != null) {
        $.noop;
        if (!$.contains(container, html)) {
          container.append(html);
        }
      }
      return deferred.resolve();
    };
    ready.then(function() {
      return render.resolve();
    });
    return deferred.promise({
      technicals: function() {
        return technicals;
      },
      html: function() {
        return html;
      }
    });
  };

  $.extend(scope, {
    technicals_widget: widget
  });

}).call(this);
;
(function() {
  var clear_menus, get_parent, global_selector, keydown, toggle;

  global_selector = '[data-toggle=dropdown]';

  clear_menus = function() {
    return $(global_selector).each(function() {
      return get_parent($(this)).removeClass('open');
    });
  };

  toggle = function() {
    var el, is_active, pa;

    el = $(this);
    if (el.is('.disabled, :disabled')) {
      return;
    }
    pa = get_parent(el);
    is_active = pa.hasClass('open');
    clear_menus();
    if (!is_active) {
      pa.toggleClass('open');
    }
    if (is_active) {
      el.blur();
    } else {
      el.focus();
    }
    return false;
  };

  keydown = function(e) {
    var el, is_active, pa;

    if (e.keyCode !== 27) {
      return;
    }
    e.preventDefault();
    e.stopPropagation();
    el = $(this);
    if (el.is('.disabled, :disabled')) {
      return;
    }
    pa = get_parent(el);
    is_active = pa.hasClass('open');
    if (!is_active || (is_active && e.keyCode === 27)) {
      if (e.keyCode === 27) {
        pa.find(global_selector).focus();
      }
      return el.click();
    }
  };

  get_parent = function(el) {
    return el.parent();
  };

  $(document).on('click.dropdown', clear_menus).on('click.dropdown', global_selector, toggle).on('keydown.dropdown', global_selector, keydown);

}).call(this);
;
/* ===========================================================
 * bootstrap-tooltip.js v2.2.2
 * http://twitter.github.com/bootstrap/javascript.html#tooltips
 * Inspired by the original jQuery.tipsy by Jason Frame
 * ===========================================================
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================== */



!function ($) {

  "use strict"; // jshint ;_;


 /* TOOLTIP PUBLIC CLASS DEFINITION
  * =============================== */

  var Tooltip = function (element, options) {
    this.init('tooltip', element, options)
  }

  Tooltip.prototype = {

    constructor: Tooltip

  , init: function (type, element, options) {
      var eventIn
        , eventOut

      this.type = type
      this.$element = $(element)
      this.options = this.getOptions(options)
      this.enabled = true

      if (this.options.trigger == 'click') {
        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
      } else if (this.options.trigger != 'manual') {
        eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
        eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
        this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
      }

      this.options.selector ?
        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
        this.fixTitle()
    }

  , getOptions: function (options) {
      options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())

      if (options.delay && typeof options.delay == 'number') {
        options.delay = {
          show: options.delay
        , hide: options.delay
        }
      }

      return options
    }

  , enter: function (e) {
      var self = $(e.currentTarget)[this.type](this._options).data(this.type)

      if (!self.options.delay || !self.options.delay.show) return self.show()

      clearTimeout(this.timeout)
      self.hoverState = 'in'
      this.timeout = setTimeout(function() {
        if (self.hoverState == 'in') self.show()
      }, self.options.delay.show)
    }

  , leave: function (e) {
      var self = $(e.currentTarget)[this.type](this._options).data(this.type)

      if (this.timeout) clearTimeout(this.timeout)
      if (!self.options.delay || !self.options.delay.hide) return self.hide()

      self.hoverState = 'out'
      this.timeout = setTimeout(function() {
        if (self.hoverState == 'out') self.hide()
      }, self.options.delay.hide)
    }

  , show: function () {
      var $tip
        , inside
        , pos
        , actualWidth
        , actualHeight
        , placement
        , tp

      if (this.hasContent() && this.enabled) {
        $tip = this.tip()
        this.setContent()

        if (this.options.animation) {
          $tip.addClass('fade')
        }

        placement = typeof this.options.placement == 'function' ?
          this.options.placement.call(this, $tip[0], this.$element[0]) :
          this.options.placement

        inside = /in/.test(placement)

        $tip
          .detach()
          .css({ top: 0, left: 0, display: 'block' })
          .insertAfter(this.$element)

        pos = this.getPosition(inside)

        actualWidth = $tip[0].offsetWidth
        actualHeight = $tip[0].offsetHeight

        switch (inside ? placement.split(' ')[1] : placement) {
          case 'bottom':
            tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
            break
          case 'top':
            tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
            break
          case 'left':
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
            break
          case 'right':
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
            break
        }

        $tip
          .offset(tp)
          .addClass(placement)
          .addClass('in')
      }
    }

  , setContent: function () {
      var $tip = this.tip()
        , title = this.getTitle()

      $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
      $tip.removeClass('fade in top bottom left right')
    }

  , hide: function () {
      var that = this
        , $tip = this.tip()

      $tip.removeClass('in')

      function removeWithAnimation() {
        var timeout = setTimeout(function () {
          $tip.off($.support.transition.end).detach()
        }, 500)

        $tip.one($.support.transition.end, function () {
          clearTimeout(timeout)
          $tip.detach()
        })
      }

      $.support.transition && this.$tip.hasClass('fade') ?
        removeWithAnimation() :
        $tip.detach()

      return this
    }

  , fixTitle: function () {
      var $e = this.$element
      if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
        $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
      }
    }

  , hasContent: function () {
      return this.getTitle()
    }

  , getPosition: function (inside) {
      return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
        width: this.$element[0].offsetWidth
      , height: this.$element[0].offsetHeight
      })
    }

  , getTitle: function () {
      var title
        , $e = this.$element
        , o = this.options

      title = $e.attr('data-original-title')
        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)

      return title
    }

  , tip: function () {
      return this.$tip = this.$tip || $(this.options.template)
    }

  , validate: function () {
      if (!this.$element[0].parentNode) {
        this.hide()
        this.$element = null
        this.options = null
      }
    }

  , enable: function () {
      this.enabled = true
    }

  , disable: function () {
      this.enabled = false
    }

  , toggleEnabled: function () {
      this.enabled = !this.enabled
    }

  , toggle: function (e) {
      var self = $(e.currentTarget)[this.type](this._options).data(this.type)
      self[self.tip().hasClass('in') ? 'hide' : 'show']()
    }

  , destroy: function () {
      this.hide().$element.off('.' + this.type).removeData(this.type)
    }

  }


 /* TOOLTIP PLUGIN DEFINITION
  * ========================= */

  var old = $.fn.tooltip

  $.fn.tooltip = function ( option ) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('tooltip')
        , options = typeof option == 'object' && option
      if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.tooltip.Constructor = Tooltip

  $.fn.tooltip.defaults = {
    animation: true
  , placement: 'top'
  , selector: false
  , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
  , trigger: 'hover'
  , title: ''
  , delay: 0
  , html: false
  }


 /* TOOLTIP NO CONFLICT
  * =================== */

  $.fn.tooltip.noConflict = function () {
    $.fn.tooltip = old
    return this
  }

}(window.jQuery);
;


/* ===========================================================
 * bootstrap-popover.js v2.2.2
 * http://twitter.github.com/bootstrap/javascript.html#popovers
 * ===========================================================
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =========================================================== */



!function ($) {

  "use strict"; // jshint ;_;


 /* POPOVER PUBLIC CLASS DEFINITION
  * =============================== */

  var Popover = function (element, options) {
    this.init('popover', element, options)
  }


  /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
     ========================================== */

  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {

    constructor: Popover

  , setContent: function () {
      var $tip = this.tip()
        , title = this.getTitle()
        , content = this.getContent()

      $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
      $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)

      $tip.removeClass('fade top bottom left right in')
    }

  , hasContent: function () {
      return this.getTitle() || this.getContent()
    }

  , getContent: function () {
      var content
        , $e = this.$element
        , o = this.options

      content = $e.attr('data-content')
        || (typeof o.content == 'function' ? o.content.call($e[0]) :  o.content)

      return content
    }

  , tip: function () {
      if (!this.$tip) {
        this.$tip = $(this.options.template)
      }
      return this.$tip
    }

  , destroy: function () {
      this.hide().$element.off('.' + this.type).removeData(this.type)
    }

  })


 /* POPOVER PLUGIN DEFINITION
  * ======================= */

  var old = $.fn.popover

  $.fn.popover = function (option) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('popover')
        , options = typeof option == 'object' && option
      if (!data) $this.data('popover', (data = new Popover(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.popover.Constructor = Popover

  $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
    placement: 'right'
  , trigger: 'click'
  , content: ''
  , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"></div></div></div>'
  })


 /* POPOVER NO CONFLICT
  * =================== */

  $.fn.popover.noConflict = function () {
    $.fn.popover = old
    return this
  }

}(window.jQuery);
;
/*!
ICanHaz.js version 0.10.2 -- by @HenrikJoreteg
More info at: http://icanhazjs.com
*/

(function () {
/*
  mustache.js — Logic-less templates in JavaScript

  See http://mustache.github.com/ for more info.
*/

var Mustache = function () {
  var _toString = Object.prototype.toString;

  Array.isArray = Array.isArray || function (obj) {
    return _toString.call(obj) == "[object Array]";
  }

  var _trim = String.prototype.trim, trim;

  if (_trim) {
    trim = function (text) {
      return text == null ? "" : _trim.call(text);
    }
  } else {
    var trimLeft, trimRight;

    // IE doesn't match non-breaking spaces with \s.
    if ((/\S/).test("\xA0")) {
      trimLeft = /^[\s\xA0]+/;
      trimRight = /[\s\xA0]+$/;
    } else {
      trimLeft = /^\s+/;
      trimRight = /\s+$/;
    }

    trim = function (text) {
      return text == null ? "" :
        text.toString().replace(trimLeft, "").replace(trimRight, "");
    }
  }

  var escapeMap = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': '&quot;',
    "'": '&#39;'
  };

  function escapeHTML(string) {
    return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) {
      return escapeMap[s] || s;
    });
  }

  var regexCache = {};
  var Renderer = function () {};

  Renderer.prototype = {
    otag: "{{",
    ctag: "}}",
    pragmas: {},
    buffer: [],
    pragmas_implemented: {
      "IMPLICIT-ITERATOR": true
    },
    context: {},

    render: function (template, context, partials, in_recursion) {
      // reset buffer & set context
      if (!in_recursion) {
        this.context = context;
        this.buffer = []; // TODO: make this non-lazy
      }

      // fail fast
      if (!this.includes("", template)) {
        if (in_recursion) {
          return template;
        } else {
          this.send(template);
          return;
        }
      }

      // get the pragmas together
      template = this.render_pragmas(template);

      // render the template
      var html = this.render_section(template, context, partials);

      // render_section did not find any sections, we still need to render the tags
      if (html === false) {
        html = this.render_tags(template, context, partials, in_recursion);
      }

      if (in_recursion) {
        return html;
      } else {
        this.sendLines(html);
      }
    },

    /*
      Sends parsed lines
    */
    send: function (line) {
      if (line !== "") {
        this.buffer.push(line);
      }
    },

    sendLines: function (text) {
      if (text) {
        var lines = text.split("\n");
        for (var i = 0; i < lines.length; i++) {
          this.send(lines[i]);
        }
      }
    },

    /*
      Looks for %PRAGMAS
    */
    render_pragmas: function (template) {
      // no pragmas
      if (!this.includes("%", template)) {
        return template;
      }

      var that = this;
      var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) {
        return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g");
      });

      return template.replace(regex, function (match, pragma, options) {
        if (!that.pragmas_implemented[pragma]) {
          throw({message:
            "This implementation of mustache doesn't understand the '" +
            pragma + "' pragma"});
        }
        that.pragmas[pragma] = {};
        if (options) {
          var opts = options.split("=");
          that.pragmas[pragma][opts[0]] = opts[1];
        }
        return "";
        // ignore unknown pragmas silently
      });
    },

    /*
      Tries to find a partial in the curent scope and render it
    */
    render_partial: function (name, context, partials) {
      name = trim(name);
      if (!partials || partials[name] === undefined) {
        throw({message: "unknown_partial '" + name + "'"});
      }
      if (!context || typeof context[name] != "object") {
        return this.render(partials[name], context, partials, true);
      }
      return this.render(partials[name], context[name], partials, true);
    },

    /*
      Renders inverted (^) and normal (#) sections
    */
    render_section: function (template, context, partials) {
      if (!this.includes("#", template) && !this.includes("^", template)) {
        // did not render anything, there were no sections
        return false;
      }

      var that = this;

      var regex = this.getCachedRegex("render_section", function (otag, ctag) {
        // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder
        return new RegExp(
          "^([\\s\\S]*?)" +         // all the crap at the beginning that is not {{*}} ($1)

          otag +                    // {{
          "(\\^|\\#)\\s*(.+)\\s*" + //  #foo (# == $2, foo == $3)
          ctag +                    // }}

          "\n*([\\s\\S]*?)" +       // between the tag ($2). leading newlines are dropped

          otag +                    // {{
          "\\/\\s*\\3\\s*" +        //  /foo (backreference to the opening tag).
          ctag +                    // }}

          "\\s*([\\s\\S]*)$",       // everything else in the string ($4). leading whitespace is dropped.

        "g");
      });


      // for each {{#foo}}{{/foo}} section do...
      return template.replace(regex, function (match, before, type, name, content, after) {
        // before contains only tags, no sections
        var renderedBefore = before ? that.render_tags(before, context, partials, true) : "",

        // after may contain both sections and tags, so use full rendering function
            renderedAfter = after ? that.render(after, context, partials, true) : "",

        // will be computed below
            renderedContent,

            value = that.find(name, context);

        if (type === "^") { // inverted section
          if (!value || Array.isArray(value) && value.length === 0) {
            // false or empty list, render it
            renderedContent = that.render(content, context, partials, true);
          } else {
            renderedContent = "";
          }
        } else if (type === "#") { // normal section
          if (Array.isArray(value)) { // Enumerable, Let's loop!
            renderedContent = that.map(value, function (row) {
              return that.render(content, that.create_context(row), partials, true);
            }).join("");
          } else if (that.is_object(value)) { // Object, Use it as subcontext!
            renderedContent = that.render(content, that.create_context(value),
              partials, true);
          } else if (typeof value == "function") {
            // higher order section
            renderedContent = value.call(context, content, function (text) {
              return that.render(text, context, partials, true);
            });
          } else if (value) { // boolean section
            renderedContent = that.render(content, context, partials, true);
          } else {
            renderedContent = "";
          }
        }

        return renderedBefore + renderedContent + renderedAfter;
      });
    },

    /*
      Replace {{foo}} and friends with values from our view
    */
    render_tags: function (template, context, partials, in_recursion) {
      // tit for tat
      var that = this;

      var new_regex = function () {
        return that.getCachedRegex("render_tags", function (otag, ctag) {
          return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g");
        });
      };

      var regex = new_regex();
      var tag_replace_callback = function (match, operator, name) {
        switch(operator) {
        case "!": // ignore comments
          return "";
        case "=": // set new delimiters, rebuild the replace regexp
          that.set_delimiters(name);
          regex = new_regex();
          return "";
        case ">": // render partial
          return that.render_partial(name, context, partials);
        case "{": // the triple mustache is unescaped
        case "&": // & operator is an alternative unescape method
          return that.find(name, context);
        default: // escape the value
          return escapeHTML(that.find(name, context));
        }
      };
      var lines = template.split("\n");
      for(var i = 0; i < lines.length; i++) {
        lines[i] = lines[i].replace(regex, tag_replace_callback, this);
        if (!in_recursion) {
          this.send(lines[i]);
        }
      }

      if (in_recursion) {
        return lines.join("\n");
      }
    },

    set_delimiters: function (delimiters) {
      var dels = delimiters.split(" ");
      this.otag = this.escape_regex(dels[0]);
      this.ctag = this.escape_regex(dels[1]);
    },

    escape_regex: function (text) {
      // thank you Simon Willison
      if (!arguments.callee.sRE) {
        var specials = [
          '/', '.', '*', '+', '?', '|',
          '(', ')', '[', ']', '{', '}', '\\'
        ];
        arguments.callee.sRE = new RegExp(
          '(\\' + specials.join('|\\') + ')', 'g'
        );
      }
      return text.replace(arguments.callee.sRE, '\\$1');
    },

    /*
      find `name` in current `context`. That is find me a value
      from the view object
    */
    find: function (name, context) {
      name = trim(name);

      // Checks whether a value is thruthy or false or 0
      function is_kinda_truthy(bool) {
        return bool === false || bool === 0 || bool;
      }

      var value;

      // check for dot notation eg. foo.bar
      if (name.match(/([a-z_]+)\./ig)) {
        var childValue = this.walk_context(name, context);
        if (is_kinda_truthy(childValue)) {
          value = childValue;
        }
      } else {
        if (is_kinda_truthy(context[name])) {
          value = context[name];
        } else if (is_kinda_truthy(this.context[name])) {
          value = this.context[name];
        }
      }

      if (typeof value == "function") {
        return value.apply(context);
      }
      if (value !== undefined) {
        return value;
      }
      // silently ignore unkown variables
      return "";
    },

    walk_context: function (name, context) {
      var path = name.split('.');
      // if the var doesn't exist in current context, check the top level context
      var value_context = (context[path[0]] != undefined) ? context : this.context;
      var value = value_context[path.shift()];
      while (value != undefined && path.length > 0) {
        value_context = value;
        value = value[path.shift()];
      }
      // if the value is a function, call it, binding the correct context
      if (typeof value == "function") {
        return value.apply(value_context);
      }
      return value;
    },

    // Utility methods

    /* includes tag */
    includes: function (needle, haystack) {
      return haystack.indexOf(this.otag + needle) != -1;
    },

    // by @langalex, support for arrays of strings
    create_context: function (_context) {
      if (this.is_object(_context)) {
        return _context;
      } else {
        var iterator = ".";
        if (this.pragmas["IMPLICIT-ITERATOR"]) {
          iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
        }
        var ctx = {};
        ctx[iterator] = _context;
        return ctx;
      }
    },

    is_object: function (a) {
      return a && typeof a == "object";
    },

    /*
      Why, why, why? Because IE. Cry, cry cry.
    */
    map: function (array, fn) {
      if (typeof array.map == "function") {
        return array.map(fn);
      } else {
        var r = [];
        var l = array.length;
        for(var i = 0; i < l; i++) {
          r.push(fn(array[i]));
        }
        return r;
      }
    },

    getCachedRegex: function (name, generator) {
      var byOtag = regexCache[this.otag];
      if (!byOtag) {
        byOtag = regexCache[this.otag] = {};
      }

      var byCtag = byOtag[this.ctag];
      if (!byCtag) {
        byCtag = byOtag[this.ctag] = {};
      }

      var regex = byCtag[name];
      if (!regex) {
        regex = byCtag[name] = generator(this.otag, this.ctag);
      }

      return regex;
    }
  };

  return({
    name: "mustache.js",
    version: "0.4.0",

    /*
      Turns a template and view into HTML
    */
    to_html: function (template, view, partials, send_fun) {
      var renderer = new Renderer();
      if (send_fun) {
        renderer.send = send_fun;
      }
      renderer.render(template, view || {}, partials);
      if (!send_fun) {
        return renderer.buffer.join("\n");
      }
    }
  });
}();
/*!
  ICanHaz.js -- by @HenrikJoreteg
*/
/*global  */
(function () {
    function trim(stuff) {
        if (''.trim) return stuff.trim();
        else return stuff.replace(/^\s+/, '').replace(/\s+$/, '');
    }

    // Establish the root object, `window` in the browser, or `global` on the server.
    var root = this;

    var ich = {
        VERSION: "0.10.2",
        templates: {},

        // grab jquery or zepto if it's there
        $: (typeof window !== 'undefined') ? window.jQuery || window.Zepto || null : null,

        // public function for adding templates
        // can take a name and template string arguments
        // or can take an object with name/template pairs
        // We're enforcing uniqueness to avoid accidental template overwrites.
        // If you want a different template, it should have a different name.
        addTemplate: function (name, templateString) {
            if (typeof name === 'object') {
                for (var template in name) {
                    this.addTemplate(template, name[template]);
                }
                return;
            }
            if (ich[name]) {
                console.error("Invalid name: " + name + ".");
            } else if (ich.templates[name]) {
                console.error("Template \"" + name + "  \" exists");
            } else {
                ich.templates[name] = templateString;
                ich[name] = function (data, raw) {
                    data = data || {};
                    var result = Mustache.to_html(ich.templates[name], data, ich.templates);
                    return (ich.$ && !raw) ? ich.$($.parseHTML(result)) : result;
                };
            }
        },

        // clears all retrieval functions and empties cache
        clearAll: function () {
            for (var key in ich.templates) {
                delete ich[key];
            }
            ich.templates = {};
        },

        // clears/grabs
        refresh: function () {
            ich.clearAll();
            ich.grabTemplates();
        },

        // grabs templates from the DOM and caches them.
        // Loop through and add templates.
        // Whitespace at beginning and end of all templates inside <script> tags will
        // be trimmed. If you want whitespace around a partial, add it in the parent,
        // not the partial. Or do it explicitly using <br/> or &nbsp;
        grabTemplates: function () {
            var i,
                l,
                scripts = document.getElementsByTagName('script'),
                script,
                trash = [];
            for (i = 0, l = scripts.length; i < l; i++) {
                script = scripts[i];
                if (script && script.innerHTML && script.id && (script.type === "text/html" || script.type === "text/x-icanhaz")) {
                    ich.addTemplate(script.id, trim(script.innerHTML));
                    trash.unshift(script);
                }
            }
            for (i = 0, l = trash.length; i < l; i++) {
                trash[i].parentNode.removeChild(trash[i]);
            }
        }
    };

    // Export the ICanHaz object for **Node.js**, with
    // backwards-compatibility for the old `require()` API. If we're in
    // the browser, add `ich` as a global object via a string identifier,
    // for Closure Compiler "advanced" mode.
    if (typeof exports !== 'undefined') {
        if (typeof module !== 'undefined' && module.exports) {
            exports = module.exports = ich;
        }
        exports.ich = ich;
    } else {
        root['ich'] = ich;
    }

    if (typeof document !== 'undefined') {
        if (ich.$) {
            ich.$(function () {
                ich.grabTemplates();
            });
        } else {
            document.addEventListener('DOMContentLoaded', function () {
                ich.grabTemplates();
            }, true);
        }
    }

})();
})();
;
/**
 * jquery.purr.js
 * Copyright (c) 2008 Net Perspective (net-perspective.com)
 * Licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php)
 * 
 * @author R.A. Ray
 * @projectDescription	jQuery plugin for dynamically displaying unobtrusive messages in the browser. Mimics the behavior of the MacOS program "Growl."
 * @version 0.1.0
 * 
 * @requires jquery.js (tested with 1.2.6)
 * 
 * @param fadeInSpeed 					int - Duration of fade in animation in miliseconds
 * 													default: 500
 *	@param fadeOutSpeed  				int - Duration of fade out animationin miliseconds
 														default: 500
 *	@param removeTimer  				int - Timeout, in miliseconds, before notice is removed once it is the top non-sticky notice in the list
 														default: 4000
 *	@param isSticky 						bool - Whether the notice should fade out on its own or wait to be manually closed
 														default: false
 *	@param usingTransparentPNG 	bool - Whether or not the notice is using transparent .png images in its styling
 														default: false
 */


( function( $ ) {
	
	$.purr = function ( notice, options )
	{ 
		// Convert notice to a jQuery object
		notice = $( notice );
		
		// Add a class to denote the notice as not sticky
		if ( !options.isSticky )
		{
			notice.addClass( 'not-sticky' );
		};
		
		// Get the container element from the page
		var cont = document.getElementById( 'purr-container' );
		
		// If the container doesn't yet exist, we need to create it
		if ( !cont )
		{
			cont = '<div id="purr-container"></div>';
		}
		
		// Convert cont to a jQuery object
		cont = $( cont );
		
		// Add the container to the page
		$( 'body' ).append( cont );
			
		notify();

		function notify ()
		{	
			// Set up the close button
			var close = document.createElement( 'a' );
			$( close ).attr(	
				{
					className: 'close',
					href: '#close',
					innerHTML: 'Close'
				}
			)
				.appendTo( notice )
					.click( function ()
						{
							removeNotice();
							
							return false;
						}
					);
			
			// Add the notice to the page and keep it hidden initially
			notice.appendTo( cont )
				.hide();
				
			//Fade in the notice we just added
			notice.fadeIn( options.fadeInSpeed );
			
			// Set up the removal interval for the added notice if that notice is not a sticky
			if ( !options.isSticky )
			{
				var topSpotInt = setInterval( function ()
				{
					// Check to see if our notice is the first non-sticky notice in the list
					if ( notice.prevAll( '.not-sticky' ).length == 0 )
					{ 
						// Stop checking once the condition is met
						clearInterval( topSpotInt );
						
						// Call the close action after the timeout set in options
						setTimeout( function ()
							{
								removeNotice();
							}, options.removeTimer
						);
					}
				}, 200 );	
			}
		}

		function removeNotice ()
		{
			// IE7 and earlier can't handle the combination of opacity and transparent pngs, so if we're using transparent pngs in our
			// notice style, we'll just skip the fading out.
			if ( false )
			{
				notice.css( { opacity: 0	} )
					.animate( 
						{ 
							height: '0px' 
						}, 
						{ 
							duration: options.fadeOutSpeed, 
							complete:  function ()
								{
									notice.remove();
								} 
							} 
					);
			}
			else
			{
				// Fade the object out before reducing its height to produce the sliding effect
				notice.animate( 
					{ 
						opacity: '0'
					}, 
					{ 
						duration: options.fadeOutSpeed, 
						complete: function () 
							{
								notice.animate(
									{
										height: '0px'
									},
									{
										duration: options.fadeOutSpeed,
										complete: function ()
											{
												notice.remove();
											}
									}
								);
							}
					} 
				);
			}
		};
	};
	
	$.fn.purr = function ( options )
	{
		options = options || {};
		options.fadeInSpeed = options.fadeInSpeed || 500;
		options.fadeOutSpeed = options.fadeOutSpeed || 500;
		options.removeTimer = options.removeTimer || 4000;
		options.isSticky = options.isSticky || false;
		options.usingTransparentPNG = options.usingTransparentPNG || false;
		
		this.each( function() 
			{
				new $.purr( this, options );
			}
		);
		
		return this;
	};
})( jQuery );

;
/*
    http://www.JSON.org/json2.js
    2011-10-19

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    See http://www.JSON.org/js.html


    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.


    This file creates a global JSON object containing two methods: stringify
    and parse.

        JSON.stringify(value, replacer, space)
            value       any JavaScript value, usually an object or array.

            replacer    an optional parameter that determines how object
                        values are stringified for objects. It can be a
                        function or an array of strings.

            space       an optional parameter that specifies the indentation
                        of nested structures. If it is omitted, the text will
                        be packed without extra whitespace. If it is a number,
                        it will specify the number of spaces to indent at each
                        level. If it is a string (such as '\t' or '&nbsp;'),
                        it contains the characters used to indent at each level.

            This method produces a JSON text from a JavaScript value.

            When an object value is found, if the object contains a toJSON
            method, its toJSON method will be called and the result will be
            stringified. A toJSON method does not serialize: it returns the
            value represented by the name/value pair that should be serialized,
            or undefined if nothing should be serialized. The toJSON method
            will be passed the key associated with the value, and this will be
            bound to the value

            For example, this would serialize Dates as ISO strings.

                Date.prototype.toJSON = function (key) {
                    function f(n) {
                        // Format integers to have at least two digits.
                        return n < 10 ? '0' + n : n;
                    }

                    return this.getUTCFullYear()   + '-' +
                         f(this.getUTCMonth() + 1) + '-' +
                         f(this.getUTCDate())      + 'T' +
                         f(this.getUTCHours())     + ':' +
                         f(this.getUTCMinutes())   + ':' +
                         f(this.getUTCSeconds())   + 'Z';
                };

            You can provide an optional replacer method. It will be passed the
            key and value of each member, with this bound to the containing
            object. The value that is returned from your method will be
            serialized. If your method returns undefined, then the member will
            be excluded from the serialization.

            If the replacer parameter is an array of strings, then it will be
            used to select the members to be serialized. It filters the results
            such that only members with keys listed in the replacer array are
            stringified.

            Values that do not have JSON representations, such as undefined or
            functions, will not be serialized. Such values in objects will be
            dropped; in arrays they will be replaced with null. You can use
            a replacer function to replace those with JSON values.
            JSON.stringify(undefined) returns undefined.

            The optional space parameter produces a stringification of the
            value that is filled with line breaks and indentation to make it
            easier to read.

            If the space parameter is a non-empty string, then that string will
            be used for indentation. If the space parameter is a number, then
            the indentation will be that many spaces.

            Example:

            text = JSON.stringify(['e', {pluribus: 'unum'}]);
            // text is '["e",{"pluribus":"unum"}]'


            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'

            text = JSON.stringify([new Date()], function (key, value) {
                return this[key] instanceof Date ?
                    'Date(' + this[key] + ')' : value;
            });
            // text is '["Date(---current time---)"]'


        JSON.parse(text, reviver)
            This method parses a JSON text to produce an object or array.
            It can throw a SyntaxError exception.

            The optional reviver parameter is a function that can filter and
            transform the results. It receives each of the keys and values,
            and its return value is used instead of the original value.
            If it returns what it received, then the structure is not modified.
            If it returns undefined then the member is deleted.

            Example:

            // Parse the text. Values that look like ISO date strings will
            // be converted to Date objects.

            myData = JSON.parse(text, function (key, value) {
                var a;
                if (typeof value === 'string') {
                    a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                    if (a) {
                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
                    }
                }
                return value;
            });

            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
                var d;
                if (typeof value === 'string' &&
                        value.slice(0, 5) === 'Date(' &&
                        value.slice(-1) === ')') {
                    d = new Date(value.slice(5, -1));
                    if (d) {
                        return d;
                    }
                }
                return value;
            });


    This is a reference implementation. You are free to copy, modify, or
    redistribute.
*/

/*jslint evil: true, regexp: true */

/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
    lastIndex, length, parse, prototype, push, replace, slice, stringify,
    test, toJSON, toString, valueOf
*/


// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

var JSON;
if (!JSON) {
    JSON = {};
}

(function () {
    'use strict';

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function (key) {

            return isFinite(this.valueOf())
                ? this.getUTCFullYear()     + '-' +
                    f(this.getUTCMonth() + 1) + '-' +
                    f(this.getUTCDate())      + 'T' +
                    f(this.getUTCHours())     + ':' +
                    f(this.getUTCMinutes())   + ':' +
                    f(this.getUTCSeconds())   + 'Z'
                : null;
        };

        String.prototype.toJSON      =
            Number.prototype.toJSON  =
            Boolean.prototype.toJSON = function (key) {
                return this.valueOf();
            };
    }

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        gap,
        indent,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        rep;


    function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

        escapable.lastIndex = 0;
        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
            var c = meta[a];
            return typeof c === 'string'
                ? c
                : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + string + '"';
    }


    function str(key, holder) {

// Produce a string from holder[key].

        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            mind = gap,
            partial,
            value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

        if (value && typeof value === 'object' &&
                typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }

// What happens next depends on the value's type.

        switch (typeof value) {
        case 'string':
            return quote(value);

        case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

            return isFinite(value) ? String(value) : 'null';

        case 'boolean':
        case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.

            return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.

        case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.

            if (!value) {
                return 'null';
            }

// Make an array to hold the partial results of stringifying this object value.

            gap += indent;
            partial = [];

// Is the value an array?

            if (Object.prototype.toString.apply(value) === '[object Array]') {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || 'null';
                }

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

                v = partial.length === 0
                    ? '[]'
                    : gap
                    ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
                    : '[' + partial.join(',') + ']';
                gap = mind;
                return v;
            }

// If the replacer is an array, use it to select the members to be stringified.

            if (rep && typeof rep === 'object') {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    if (typeof rep[i] === 'string') {
                        k = rep[i];
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            } else {

// Otherwise, iterate through all of the keys in the object.

                for (k in value) {
                    if (Object.prototype.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            }

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

            v = partial.length === 0
                ? '{}'
                : gap
                ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
                : '{' + partial.join(',') + '}';
            gap = mind;
            return v;
        }
    }

// If the JSON object does not yet have a stringify method, give it one.

    if (typeof JSON.stringify !== 'function') {
        JSON.stringify = function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

            var i;
            gap = '';
            indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.

            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }

// If the space parameter is a string, it will be used as the indent string.

            } else if (typeof space === 'string') {
                indent = space;
            }

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
                    (typeof replacer !== 'object' ||
                    typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.

            return str('', {'': value});
        };
    }


// If the JSON object does not yet have a parse method, give it one.

    if (typeof JSON.parse !== 'function') {
        JSON.parse = function (text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.

            var j;

            function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.

                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }


// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.

            text = String(text);
            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return '\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.

// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

            if (/^[\],:{}\s]*$/
                    .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
                        .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
                        .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                j = eval('(' + text + ')');

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.

                return typeof reviver === 'function'
                    ? walk({'': j}, '')
                    : j;
            }

// If the text is not JSON parseable, then a SyntaxError is thrown.

            throw new SyntaxError('JSON.parse');
        };
    }
}());
;
(function() {
  var root, scope, url_prefix,
    __slice = [].slice;

  root = this;

  if (root['mx'] == null) {
    root['mx'] = {};
  }

  root['mx']['cs'] = {};

  scope = root['mx']['cs'];

  url_prefix = '/cs';

  if ($.support.cors) {
    url_prefix = mx.url + url_prefix;
  }

  $.extend(scope, {
    url_prefix: url_prefix,
    fetch: function() {
      return mx.fetch.apply(mx, [scope].concat(__slice.call(arguments)));
    },
    fetch_descriptors: {}
  });

}).call(this);
;
(function() {
    var $, fetch, fetch_2, find_metadata, metadata, root, scope;

  root = this;

  scope = root['mx']['cs'];

  $ = jQuery;

  metadata = void 0;


  find_metadata = function(boardid) {
    var board;
    board = _.detect(metadata.boards, function(board) {
      return board.boardid === boardid;
    });
    return {
      engine: _.detect(metadata.engines, function(engine) {
        return engine.id === board.engine_id;
      }).name,
      market: _.detect(metadata.markets, function(market) {
        return market.market_id === board.market_id;
      }).market_name,
      group: board.board_group_id
    };
  };

  fetch = function(params, options) {
    var deferred;
    if (options == null) {
      options = {};
    }
    deferred = new $.Deferred;
    mx.iss.metadata().then(function(iss) {
      var board, board_group, data, engine, find_board_group, id, market, param_to_compare, params_to_compare, _ref, _ref1, _ref2, _ref3, _ref4;
      find_board_group = function(board) {
        var b;
        return _.first((function() {
          var _i, _len, _ref, _results;
          _ref = iss.boards;
          _results = [];
          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            b = _ref[_i];
            if (b.boardid === board) {
              _results.push(b.board_group_id);
            }
          }
          return _results;
        })());
      };
      data = {
        's1.type': (_ref = options.type) != null ? _ref : void 0,
        'interval': (_ref1 = options.interval) != null ? _ref1 : void 0,
        'period': (_ref2 = options.period) != null ? _ref2 : void 0,
        'candles': (_ref3 = options.candles) != null ? _ref3 : void 0
      };
      _ref4 = _.first(params), engine = _ref4.engine, market = _ref4.market, board = _ref4.board, id = _ref4.id;
      board_group = find_board_group(board);
      params_to_compare = (function() {
        var _i, _len, _ref5, _results;
        _ref5 = _.drop(params, 1);
        _results = [];
        for (_i = 0, _len = _ref5.length; _i < _len; _i++) {
          param_to_compare = _ref5[_i];
          _results.push([param_to_compare.engine, param_to_compare.market, find_board_group(param_to_compare.board), param_to_compare.id].join(':'));
        }
        return _results;
      })();
      if (_.size(params_to_compare) > 0) {
        data.compare = params_to_compare.join(',');
      }
      scope.url_prefix = window.moex.chartServerUrl;
      url = "" + scope.url_prefix + "/engines/" + engine + "/markets/" + market + "/boardgroups/" + board_group + "/securities/" + id + ".hs?callback=?"
      return $.ajax({
        url: url,
        data: data,
        dataType: 'jsonp'
			}).error(function (xhr, ajaxOptions, thrownError) {
        console.log("error:",{
          xhr, ajaxOptions, thrownError, url
        })
      })
      .then(function (json) {
        return deferred.resolve(json);
      });
    });
    return deferred.promise();
  };

  fetch_2 = function(param, options) {
		var deferred, all_data;
    if (options == null) {
      options = {};
    }
    deferred = new $.Deferred;
    all_data = {};
    if (metadata == null) {
      metadata = mx.data.metadata();
    }
    metadata.then(function() {
      var board, engine, id, market, query_data, technicals_params, _ref, boardgroup_id;
      _ref = param.split(':'), board = _ref[0], id = _ref[1];
      board = metadata.board(board);
      engine = board.engine.name;
      market = board.market.name;
      boardgroup_id = board.boardgroup_id;
      technicals_params = _.reduce(options.technicals, function(memo, technical, index) {
        var value, _i, _len, _ref1;
        _ref1 = technical.values;
        for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
          value = _ref1[_i];
          memo["indicator" + index + "." + value.name + ".value"] = value.value;
        }
        return memo;
      }, {});
      query_data = {
        's1.type': 'candles',
        'interval': options.interval,
        'period': options.period,
        'candles': options.candles,
        'indicators': _.map(options.technicals, 'id').join(',')
      };
      query_data = _.reduce(query_data, (function(container, value, key) {
        if (value != null) {
          container[key] = value;
        }
        return container;
      }), {});
			scope.url_prefix = window.moex.chartServerUrl;

			if (typeof options.prev_boards === 'undefined') {
				options.prev_boards = [];
			}
			if (options.prev_boards.indexOf(boardgroup_id) < 0) {
				options.prev_boards.push(boardgroup_id);
			}
			var index = 0;
			var tempResult = {};
			var deferreds = [];


			_.forEach(options.prev_boards, function (boardgroup_id) {
        url = "" + scope.url_prefix + "/engines/" + engine + "/markets/" + market + "/boardgroups/" + boardgroup_id + "/securities/" + id + ".hs"
				deferreds.push(
					$.ajax({
						url: url,
						data: $.extend(query_data, technicals_params),
						dataType: 'jsonp',
						async: true,
						cache: false,
						timeout: 3000
					}).error(function (xhr, ajaxOptions, thrownError) {
            console.log("error:",{
              xhr, ajaxOptions, thrownError, url
            })
          }).then(function (json) {
						tempResult[boardgroup_id] = json;
					})
				);
			});

			
		
			$.when.apply($, deferreds).always(function () {
				_.map(tempResult, function (json, key) {
					if (json != null) {
						var candles, key, value;
						if (json.candles != null) {
							candles = json.candles[0];
							var candles_data = candles.data
							var lines_data = _.map(candles.data, function (item) {
								return [item[0], item[4]];
							});
							if (all_data.candles && all_data.candles[0] && all_data.candles[0].candles_data) {
								candles.candles_data = all_data.candles[0].candles_data.concat(candles_data);
							} else {
								candles.candles_data = candles_data;
							}
							if (all_data.candles && all_data.candles[0] && all_data.candles[0].line_data) {
								candles.line_data = all_data.candles[0].line_data.concat(lines_data);
							} else {
								candles.line_data = candles_data;
							}
							delete json.candles[0].data;
						}
						if (all_data.volumes && all_data.volumes[0] && all_data.volumes[0].data && json.volumes && json.volumes[0]) {
							json.volumes[0].data = all_data.volumes[0].data.concat(json.volumes[0].data);
						}
						for (key in json) {
							value = json[key];
							all_data[key] = value;
						}
					}
				});
				deferred.resolve(all_data);
			});

		
			/* Code for getting data of current boardgoup
      $.ajax({
        url: "" + scope.url_prefix + "/engines/" + engine + "/markets/" + market + "/boardgroups/" + boardgroup_id + "/securities/" + id + ".hs",
        data: $.extend(query_data, technicals_params),
        dataType: 'jsonp'
			}).then(function (json) {
        var candles, key, value;
        if (json.candles != null) {
          candles = json.candles[0];
          candles.candles_data = candles.data;
          candles.line_data = _.map(candles.data, function(item) {
            return [item[0], item[4]];
          });
          delete json.candles[0].data;
        }
        for (key in json) {
          value = json[key];
          result[key] = value;
				}
				return deferred.resolve(result);
      });
			*/
		});
		// return deferred.promise(result);
		return deferred.promise(all_data);
  };

  $.extend(scope, {
    highstock: fetch,
    highstock_2: fetch_2
  });

}).call(this);
;
(function() {
  var $, fetch, root, scope,
    __slice = [].slice;

  root = this;

  scope = root['mx']['cs'];

  $ = jQuery;

  fetch = function() {
    var data, deferred;

    deferred = new $.Deferred;
    data = [];
    scope.url_prefix = window.moex.chartServerUrl;
    $.ajax({
      url: "" + scope.url_prefix + "/indicators.hs?callback=?",
      data: {
        lang: mx.I18n.locale
      },
      dataType: 'jsonp'
    }).then(function(json) {
      data.push.apply(data, json);
      return deferred.resolve(data);
    });

    return deferred.promise(data);
  };

  $.extend(scope, {
    technicals: fetch,
    technicals2: function() {
      return scope.fetch.apply(scope, ['chart_technicals'].concat(__slice.call(arguments)));
    }
  });

  $.extend(scope.fetch_descriptors, {
    chart_technicals: {
      url: function() {
        return "/indicators.hs";
      },
      parse: function(json) {
        return json;
      }
    }
  });

}).call(this);
;
$(document).ready(
    function () {

		var locales = {
			ru: {
				printChart: 'Распечатать график',
				downloadJPEG: 'Скачать в JPEG',
				downloadPDF: 'Скачать в PDF',
				downloadPNG: 'Скачать в PNG',
				downloadSVG: 'Скачать в SVG',
				loading: 'Загрузка ...',
				resetZoom: 'Сбросить зум',
				months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
				shortMonths: ['Янв', 'Фев', 'Март', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'],
				weekdays: ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"],
				numericSymbols: [' тыс', ' млн', ' млрд', ' трлн', 'P', 'E'],
				rangeSelectorFrom: "С",
				rangeSelectorTo: "По",
				rangeSelectorZoom: 'Масштаб'
			},
			en: {
				printChart: 'Print chart',
				downloadJPEG: 'Download JPEG',
				downloadPDF: 'Download PDF',
				downloadPNG: 'Download PNG',
				downloadSVG: 'Download SVG',
				loading: 'Downloading ...',
				resetZoom: 'Reset zoom',
				months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
				shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'June', 'July', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'],
				weekdays: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
				numericSymbols: [' th', ' mln', ' bln', ' trin', 'P', 'E']
			}
		};

		var setLocale = function (newLoc, oldLoc) {
			var loc = locales[newLoc];
			if (loc) {
				if (window.Highcharts) {
					Highcharts.setOptions({ lang: loc });
				}				
			}
        };

		if (window.mx) {
			//setLocale(window.mx.locale() || "ru");
			setLocale(window.moex.locale.urlSegment || "ru");
			window.mx.localeChanged(setLocale);
		}
		else {
			setLocale(window.moex.localizer.lang);
		}
    }
);;
(function() {
  var read_or_write_cache, root, scope;

  root = this;

  if (root['mx'] == null) {
    root['mx'] = {};
  }

  root['mx']['data'] = {};

  scope = root['mx']['data'];

  read_or_write_cache = function(name, key, value) {
    var cache;
    cache = kizzy(name);
    if (value != null) {
      return cache.set(key, value);
    } else {
      return cache.get(key);
    }
  };

  _.extend(scope, {
    caches: {
      table_filtered_columns: _.wrap(read_or_write_cache, function(f, key, value) {
        return f('data.table.filtered_columns', key, value);
      }),
      chart_instruments: _.wrap(read_or_write_cache, function(f, value) {
        return f('data.chart.instruments', '', value);
      })
    }
  });

}).call(this);
;
(function() {
  var $, cache, chart_cache, deferred, fetch, keys, root, scope, tables_cache;

  root = this;

  scope = root['mx']['data'];

  $ = jQuery;

  cache = kizzy('data.bootstrap');

  tables_cache = function() {
    return kizzy('data.table');
  };

  chart_cache = kizzy('data.chart.instruments');

  keys = ['indices', 'currencies'];

  deferred = new $.Deferred;

  fetch = function() {
    var bootstrap, metadata, ready;

    if (cache.get('complete')) {
      deferred.resolve();
      return deferred.promise();
    }
    bootstrap = mx.iss.bootstrap();
    metadata = mx.data.metadata();
    ready = $.when(bootstrap, metadata);
    ready.then(function() {
      var to_chart, to_table;

      to_table = function(ticker) {
        var board, key, value, values;

        board = metadata.board(ticker.BOARDID);
        key = "" + board.engine.name + ":" + board.market.name + ":securities";
        value = "" + board.id + ":" + ticker.SECID;
        values = tables_cache().get(key) || [];
        values.push(value);
        return tables_cache().set(key, values);
      };
      to_chart = function(ticker) {
        var key, value, values;

        key = "";
        value = {
          board: ticker.BOARDID,
          id: ticker.SECID
        };
        values = scope.caches.chart_instruments() || [];
        values.push(value);
        return scope.caches.chart_instruments(values);
      };
      keys.forEach(function(key) {
        var chart_empty;

        chart_empty = true;
        return bootstrap.data[key].forEach(function(ticker) {
          to_table(ticker);
          if (chart_empty) {
            to_chart(ticker);
          }
          return chart_empty = false;
        });
      });
      cache.set('complete', true);
      return deferred.resolve();
    });
    return deferred.promise();
  };

  $.extend(scope, {
    bootstrap: fetch
  });

}).call(this);
;
(function () {
    var $, cache, calculate_extremes, calculate_technicals_colors_indices, candles_yAxis_height, candles_yAxis_margin, create, create_candles, create_inline_technicals, create_separate_technicals, create_volumes, cs_to_hs_types, default_candles_series_options, default_candles_yAxis_options, default_chart_options, default_volumes_series_options, default_volumes_yAxis_options, default_xAxis_height, default_xAxis_margin, default_xAxis_options, fetch_chart_type, instrument_key, navigator_height, no_data, refresh_delay, render_point_for_tooltip, render_points_for_tooltip, render_tooltips, root, scope, scrollbar_height, update, update_candles, update_inline_technicals, update_separate_technicals, update_volumes, validate_instruments, volumes_yAxis_height, volumes_yAxis_margin, widget, istechch;
    var create_volumes_data, find_effective_instruments_size;
    var canv_prev, canvlen_prev, candle_interval_prev;

	root = this;

	scope = root['mx']['data'];

	$ = jQuery;

	cache = kizzy('data.chart');

	fetch_chart_type = 'candles';

	refresh_delay = 10 * 1000;

	cs_to_hs_types = {
		line: 'line',
		candles: 'candlestick',
		stockbar: 'ohlc',
		bar: 'column'
	};

    if ((window.ontouchstart == undefined) && (window.innerWidth > 1240)) {
        candles_yAxis_margin = 50;
    } else {
        candles_yAxis_margin = 130;
    }

	candles_yAxis_height = 440;

	volumes_yAxis_margin = 30;

	volumes_yAxis_height = 60;

	default_xAxis_margin = 5;

	default_xAxis_height = 25;

	navigator_height = 50;

	scrollbar_height = 15;

	default_chart_options = {
		chart: {
			alignTicks: false,
			spacingTop: 1,
			spacingLeft: 10,
			spacingRight: 10,
			spacingBottom: 1,//,
			//defaultSeriesType: "candlestick"
		},
		credits: {
		    enabled: false
		},

		rangeSelector: {
			enabled: false
		},
		navigator: {
			height: 50
		},
		scrollbar: {
			height: 15
		},
		tooltip: {
			crosshairs: true
		},
		plotOptions: {
			ohlc: {
				lineWidth: 2
			},
			scatter: {
				marker: {
					radius: 2,
					symbol: 'circle'
				}
			},
			series: {
			  gapSize: 60,
			  dataGrouping: {
			    enabled: false
			  }
			}
		}
	};

	default_candles_series_options = {
		//dataGrouping: {
		//	smoothed: false
		//}
	};

	var customAutoscaleTickPositioner = function ()
	{
	    //console.debug("tickPositioner dataMin: " + this.dataMin + " dataMax: " + this.dataMax);

	    this.nextMin = this.dataMin;
		this.nextMax = this.dataMax;

	    if (this.setExtremesFunc == null)
	    {
	        var self = this;

	        this.setExtremesFunc = setTimeout(function ()
	        {
				console.debug("tickPositioner.setExtremes dataMin: ", self.nextMin, " dataMax: ", self.nextMax);
				if (self.nextMin == undefined || self.nextMax == undefined)
					return;

	            self.setExtremes(self.nextMin, self.nextMax);
	            self.setExtremesFunc = null;
	        }, 300);
	    }
	};

	default_candles_yAxis_options = {
        lineWidth: 1,
        height: candles_yAxis_height,
        top: candles_yAxis_margin,
		//offset: 10,
        showEmpty: false,
	    //tickAmount: 11,
        //minPadding: -0.1,
        //minorTickLength: 5,
        //tickPixelInterval: 72,
        //tickPixelInterval: 10,
		//endOnTick:true,
        //type: 'logarithmic',
        tickPositioner: customAutoscaleTickPositioner
	};

	default_volumes_series_options = {
		//dataGrouping: {
		//	smoothed: false
	    //},
	    tickPositioner: customAutoscaleTickPositioner
	};

	default_volumes_yAxis_options = {
		lineWidth: 1,
		height: volumes_yAxis_height,
		top: candles_yAxis_margin + candles_yAxis_height + volumes_yAxis_margin,
		offset: 0,
		opposite: true,
		showEmpty: false,
		alignTicks: true,
		//maxPadding: -0.1,
	    //tickAmount: 3,
	    //tickInterval: 50000000,
	    //tickAmount: 20,
	    tickPixelInterval: 30,
		labels: {
		    align: 'left',
		    x: 3,
		    y: 4//,
		    //format: '{value:.,0f}'
		}
	};

	default_xAxis_options = {
		top: 0,
		offset: 0
	};

	no_data = function () {
		return $('<div>').addClass('no_data').html('Нет данных');
	};

	instrument_key = function (instrument) {
		return "" + instrument.board + ":" + instrument.id;
	};

	validate_instruments = function (instruments, data_sources) {
		var data_source, instrument, _i, _len;

		for (_i = 0, _len = instruments.length; _i < _len; _i++) {
		  instrument = instruments[_i];
		  data_source = data_sources[instrument_key(instrument)];
		  if (data_source.error_message != null) {
		    instrument.failure = data_source.error_message;
		  }
		  if (instrument.failure != null) {
		    instrument.disabled = true;
		  }
		}
		return instruments;
	};

    var lastValue = 0;
    var needBlink = false;

    find_effective_instruments_size = function (instruments) {

        var results = 0;
        for (var i = 0; i < instruments.length; i++)
            if (!instruments[i].disabled) results++;

        return results;
    };

	create_candles = function (data_sources, instruments, chart_type) {

		var candles, candles_data, candles_serie_options, effective_chart_type, effective_index, effective_instruments_size, index, instrument, series, yAxis, _i, _len;

		series = [];
		yAxis = [];
		effective_instruments_size = find_effective_instruments_size(instruments);

		effective_index = 0;
		for (index = _i = 0, _len = instruments.length; _i < _len; index = ++_i) {
			instrument = instruments[index];
			if (instrument.disabled === true) {
				continue;
			}
			effective_chart_type = effective_index > 0 || effective_instruments_size > 2 ? 'line' : chart_type;
			candles = _.first(data_sources[instrument_key(instrument)].candles);
			candles_data = candles["" + (effective_chart_type === 'line' ? 'line' : 'candles') + "_data"];

            //var a = function(){
            //    var b = candles_data[candles_data.length-1];
            //    return b;
            //};



            lastValue = candles_data[candles_data.length-1][0];
			candles_serie_options = $.extend(true, {}, default_candles_series_options, {
				id: "candles:" + index,
				name: instrument.title || instrument.id,
				color: scope.colors[index],
				type: cs_to_hs_types[effective_chart_type],
				data:  candles_data,
				yAxis: effective_instruments_size === 2 && effective_index === 1 ? 1 : 0,
                dataLabels:{
                    crop:false,
                    enabled: true,
                    useHTML: true,
                    //inside: true,
                    allowOverlap: false,
                    overflow: 'none',
                    y:0,
                    formatter: function()
                    {
                        if(this.point.x === lastValue)
                        {
                            return '<div class="chart_refresh_indicator" style="position: absolute; top: -7.6px;left: -13px;width: 25px;height: 25px;-webkit-border-radius: 25px;-moz-border-radius: 25px;border-radius: 25px;background: #9ad2e5; opacity: 0;"><div style="width: 7px;height: 7px; background: #0093c6; -webkit-border-radius: 25px;-moz-border-radius: 25px;border-radius: 25px; top:9px; left: 9px;position: absolute;"></div></div>';
                        }
                        return '';
                    }
                }
			});
			if (effective_instruments_size > 2) {
				$.extend(candles_serie_options, {
					compare: 'percent'
				});
			}

			addEmptyData(candles_serie_options.data);

			series.push(candles_serie_options);
			effective_index++;
		}

		//console.log("candles_data:");
		//console.log(candles_data);

		yAxis.push($.extend(true, {}, default_candles_yAxis_options, {
			opposite: true
		}));
		yAxis.push($.extend(true, {}, default_candles_yAxis_options));
		if (effective_instruments_size <= 2) {
			$.extend(yAxis[0], {
			    labels: {
			        align: 'left',
			        x: 3,
			        y: 4,
					style: {
						color: series[0].color
					},
					format: '{value:.,0f}',
					formatter: function () {
						return this.value;
					    //if (this.value >= 0) return this.value;
					}
				}
			});
		}
		if (effective_instruments_size === 2) {
		    $.extend(yAxis[1], {
		        labels: {
		            align: 'left',
		            x: 3,
		            y: 4,
					style: {
						color: series[1].color
					},
					format: '{value:.,0f}'
				}
			});
		}

		return {
			series: series,
			yAxis: yAxis,
			offset: candles_yAxis_margin + candles_yAxis_height
		};
	};

	update_candles = function (data_sources, instruments, chart_type, offset, options) {
		var candles, candles_data, effective_chart_type, effective_index, effective_instruments_size, index, instrument, _i, _len;

		effective_instruments_size = find_effective_instruments_size(instruments);

		effective_index = 0;
		for (index = _i = 0, _len = instruments.length; _i < _len; index = ++_i) {
			instrument = instruments[index];
			if (instrument.disabled === true) {
				continue;
			}
			effective_chart_type = effective_index > 0 || effective_instruments_size > 2 ? 'line' : chart_type;
			candles = _.first(data_sources[instrument_key(instrument)].candles);
			var candles_data_name = (effective_chart_type === 'line' ? 'line' : 'candles') + "_data";
			if (candles && candles[candles_data_name]) {
				candles_data = candles[candles_data_name];

				lastValue = candles_data[candles_data.length - 1][0];
				addEmptyData(candles_data);
				options.chart.series[effective_index + offset].setData(candles_data, false);
				effective_index++;
			}			
		}
		return effective_index;
	};

	create_volumes_info = function (data_source) {

	    var candles = _.first(data_source.candles);
	    var volumes = _.first(data_source.volumes);

	    var volumes_data = [];

	    volumes_data.type = volumes.type;

	    for (var i = 0; i < volumes.data.length; i += 1)
	        volumes_data.push(
                {
                    x: volumes.data[i][0],
                    y: volumes.data[i][1],
                    color: candles.candles_data[i][1] > candles.candles_data[i][4] ? '#FFAEC9' : '#9DECB5'
                });

	    return {
	        type: volumes.type,
            data: volumes_data
	    };
	};

	create_volumes = function (data_sources, instruments) {
	    var effective_index, effective_instruments_size, index, instrument, series, volumes, volumes_info, volumes_serie_options, yAxis, _i, _len;

		series = [];
		yAxis = [];
		yAxis.push($.extend(true, {}, default_volumes_yAxis_options));

		effective_instruments_size = find_effective_instruments_size(instruments);

		effective_index = 0;
		for (index = _i = 0, _len = instruments.length; _i < _len; index = ++_i) {

			instrument = instruments[index];
			if (effective_instruments_size > 2 && effective_index > 0) {
				break;
			}
			if (effective_index > 1) {
				break;
			}
			if (instrument.disabled === true) {
				continue;
			}

			volumes_info = create_volumes_info(data_sources[instrument_key(instrument)]);
            			
			volumes_serie_options = $.extend(true, {}, default_volumes_series_options, {
				id: "volumes:" + index,
				name: instrument.title || instrument.id,
				color: "#a4b0bf",
				type: cs_to_hs_types[volumes_info.type],
				data: volumes_info.data,
				yAxis: 2
			});

			addEmptyData(volumes_info.data);

			if (instruments && instruments[0] && !instruments[0].hideVolumes) {
				series.push(volumes_serie_options);
			}
			effective_index++;
		}


		return {
			series: series,
			yAxis: yAxis,
			offset: volumes_yAxis_margin + volumes_yAxis_height
		};
	};

	//добавление 5 пустых свечей в конец
	addEmptyData = function (data)
	{
		//var lastDate = data[data.length-1][0];
		//var interval = data[data.length-1][0] - data[data.length-2][0];
		//for(var index = 1; index < 6; index++)
		//{
		//	data.push([lastDate+interval*index, null, null, null, null]);
		//}
	};

	update_volumes = function (data_sources, instruments, offset, options) {
		var effective_index, effective_instruments_size, instrument, volumes, volumes_info, _i, _len;

		effective_instruments_size = find_effective_instruments_size(instruments);
		effective_index = 0;

		for (_i = 0, _len = instruments.length; _i < _len; _i++) {
			instrument = instruments[_i];
			if (effective_instruments_size > 2 && effective_index > 0) {
				break;
			}
			if (effective_index > 1) {
				break;
			}
			if (instrument.disabled === true) {
				continue;
			}

			volumes_info = create_volumes_info(data_sources[instrument_key(instrument)]);

			addEmptyData(volumes_info.data);

			options.chart.series[effective_index + offset].setData(volumes_info.data, false);

		    effective_index++;
		}
		return effective_index;
	};

	create_inline_technicals = function (data_sources, instruments, technicals, offset, options) {
		var data_source, effective_instrument, effective_instruments, index, instrument, serie, serie_options, series, technical, technical_index, total, yAxis, _i, _j, _len, _len1, _ref;

		series = [];
		yAxis = [];
		total = _.size(instruments);
		effective_instruments = (function () {
		    var _i, _len, _results;

		    _results = [];
		    for (_i = 0, _len = instruments.length; _i < _len; _i++) {
		        instrument = instruments[_i];
		        if (!instrument.disabled) {
		            _results.push(instrument);
		        }
		    }
		    return _results;
		})();
		technical_index = 0;
		if (_.size(effective_instruments) < 3) {
			effective_instrument = _.first(effective_instruments);
			data_source = data_sources[instrument_key(effective_instrument)].technicals;
			for (index = _i = 0, _len = data_source.length; _i < _len; index = ++_i) {
				technical = data_source[index];
				if (!technical.inline) {
					continue;
				}
				_ref = technical.data;
				for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
					serie = _ref[_j];
					serie_options = $.extend(true, {}, default_candles_series_options, {
						id: "inline technicals:" + technical_index,
						name: options.technicals_meta[technicals[index].id].title,
						color: scope.colors[total + technical_index],
						type: cs_to_hs_types[technical.type],
						data: serie,
						yAxis: 0
					});
					if (technicals[index].id === 'psar') {
						serie_options = $.extend(serie_options, {
							lineWidth: 0,
							marker: {
								enabled: true,
								radius: 2,
								symbol: 'circle'
							}
						});
					}
					addEmptyData(serie_options.data);
					series.push(serie_options);
				}
				technical_index++;
			}
		}
		return {
			series: series,
			yAxis: yAxis,
			offset: 0
		};
	};

	update_inline_technicals = function (data_sources, instruments, technicals, offset, options) {
		var data_source, effective_instrument, effective_instruments, effective_offset, instrument, serie, technical, _i, _j, _len, _len1, _ref;

		effective_offset = 0;
		effective_instruments = (function () {
		    var _i, _len, _results;

		    _results = [];
		    for (_i = 0, _len = instruments.length; _i < _len; _i++) {
		        instrument = instruments[_i];
		        if (!instrument.disabled) {
		            _results.push(instrument);
		            }
		            }
		    return _results;
		    })();
		if (_.size(effective_instruments) < 3) {
			effective_instrument = _.first(effective_instruments);
			data_source = data_sources[instrument_key(effective_instrument)].technicals;
			for (_i = 0, _len = data_source.length; _i < _len; _i++) {
				technical = data_source[_i];
				if (!!technical.inline) {
					_ref = technical.data;
					for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
						serie = _ref[_j];
						addEmptyData(serie);
						options.chart.series[effective_offset + offset].setData(serie, false);
						effective_offset++;
					}
				}
			}
		}
		return effective_offset;
	};

	create_separate_technicals = function (data_sources, instruments, technicals, offset, options) {
		var data_source, effective_index, effective_instrument, effective_offset, index, instrument, serie, serie_options, series, technical, technical_index, yAxis, yAxis_offset_index, _i, _j, _len, _len1, _ref, _ref1;

		series = [];
		yAxis = [];
		yAxis_offset_index = 3;
		effective_offset = 0;
		technical_index = 0;
		_ref = _.first((function () {
			var _i, _len, _results;

			_results = [];
			for (index = _i = 0, _len = instruments.length; _i < _len; index = ++_i) {
				instrument = instruments[index];
				if (!instrument.disabled) {
					_results.push([instrument, index]);
				}
			}
			return _results;
		})()), effective_instrument = _ref[0], effective_index = _ref[1];
		data_source = data_sources[instrument_key(effective_instrument)].technicals;
		for (index = _i = 0, _len = data_source.length; _i < _len; index = ++_i) {
			technical = data_source[index];
			if (technical.inline) {
				continue;
			}
			yAxis.push($.extend(true, {}, default_volumes_yAxis_options, {
				top: offset + effective_offset + volumes_yAxis_margin
			}));
			_ref1 = technical.data;
			for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
				serie = _ref1[_j];
				serie_options = $.extend(true, {}, default_candles_series_options, {
					id: "separate technicals:" + technical_index,
					name: options.technicals_meta[technicals[index].id].title,
					color: scope.colors[effective_index],
					type: cs_to_hs_types[technical.type],
					data: serie,
					yAxis: yAxis_offset_index + _.size(yAxis) - 1
				});

				addEmptyData(serie_options.data);
				series.push(serie_options);
			}
			effective_offset += volumes_yAxis_margin + volumes_yAxis_height;
			technical_index++;
		}
		return {
			series: series,
			yAxis: yAxis,
			offset: effective_offset
		};
	};

	update_separate_technicals = function (data_sources, instruments, technicals, offset, options) {
		var data_source, effective_instrument, effective_offset, instrument, serie, technical, _i, _j, _len, _len1, _ref;

		effective_offset = 0;		
		effective_instrument = _.first((function () {
			var _i, _len, _results;

			_results = [];
			for (_i = 0, _len = instruments.length; _i < _len; _i++) {
				instrument = instruments[_i];
				if (!instrument.disabled) {
					_results.push(instrument);
				}
			}
			return _results;
		})());
		data_source = data_sources[instrument_key(effective_instrument)].technicals;
		for (_i = 0, _len = data_source.length; _i < _len; _i++) {
			technical = data_source[_i];
			if (!technical.inline) {
				_ref = technical.data;
				for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
					serie = _ref[_j];
					addEmptyData(serie);
					options.chart.series[effective_offset + offset].setData(serie, false);
					effective_offset++;
				}
			}
		}
		return effective_offset;
	};

	/*calculate_extremes = function (chart, options) {
		var delta, max, min, _ref;
		_ref = _.first(chart.xAxis).getExtremes(), min = _ref.min, max = _ref.max;
		if (!options.left_lock && !options.right_lock) {
			if (options.min > min && options.min < max) {
				min = options.min;
			}
			if (options.max < max && options.max > min) {
				max = options.max;
			}
		} else if (options.left_lock && !options.right_lock) {
			delta = min - options.min;
			if (options.max + delta < max) {
				max = options.max + delta;
			}
		} else if (!options.left_lock && options.right_lock) {
			delta = max - options.max;
			if (options.min + delta > min) {
				min = options.min + delta;
			}
		}
		return {
			min: min,
			max: max
		};
	};*/

	create = function (container, data_sources, instruments, technicals, chart_type, options) {
	    var candles, chart, chart_options, inline_technicals, max, min, offset, separate_technicals, series, volumes, xAxis, yAxis, _ref;

		if (options == null) {
	        options = {};
	    }
	    series = [];
	    xAxis = [];
	    yAxis = [];
	    offset = 0;
	    /*
			CANDLES
		*/

	    options.instruments = instruments;
	    //console.info("options.instruments:", options.instruments);


	    candles = create_candles(data_sources, instruments, chart_type);
	    series.push.apply(series, candles.series);
	    yAxis.push.apply(yAxis, candles.yAxis);
	    offset += candles.offset;
	    /*
			VOLUMES
		*/

	    volumes = create_volumes(data_sources, instruments);
	    series.push.apply(series, volumes.series);
	    yAxis.push.apply(yAxis, volumes.yAxis);
	    offset += volumes.offset;
	    /*
			INLINE TECHNICALS
		*/

	    inline_technicals = create_inline_technicals(data_sources, instruments, technicals, offset, options);
	    series.push.apply(series, inline_technicals.series);
	    yAxis.push.apply(yAxis, inline_technicals.yAxis);
	    offset += inline_technicals.offset;
	    /*
			SEPARATE TECHNICALS
		*/

	    separate_technicals = create_separate_technicals(data_sources, instruments, technicals, offset, options);
	    series.push.apply(series, separate_technicals.series);
	    yAxis.push.apply(yAxis, separate_technicals.yAxis);
	    offset += separate_technicals.offset;
	    /*
			XAXIS
		*/

	    xAxis.push($.extend(true, {}, default_xAxis_options, {
	        height: offset + default_xAxis_margin,
	        events: {
	            setExtremes: options.on_extremes_change
	        }
	    }));
	    offset += default_xAxis_margin + default_xAxis_height;
	    /*
			NAVIGATOR
		*/

	    offset += navigator_height + scrollbar_height;
	    /*
			CHART
		*/

	    chart_options = $.extend(true, {}, default_chart_options, {
	        chart: {
	            renderTo: _.first(container),
	            height: offset,
	            some_events: options.some_events,
	            events: {
	                load: function() {
	                    showLastPointTooltip(this);
	                },
	                redraw: function() {
	                    if ($('.highcharts-container:hover').length == 0) {
	                        showLastPointTooltip(this);
	                    }
	                }
	            }
			},

			tooltip: {
	            formatter: function() {
	                return render_tooltips(this, options, instruments);
	            }
	        },

	        series: series,
	        xAxis: xAxis,
	        yAxis: yAxis


	    });

		if (options.chart != null) {
            $(window).off("resize", chartReflow);
	        options.chart.destroy();
	    }

        chart = new Highcharts.StockChart(chart_options);

        function chartReflow(event) {
            try {
                var c = event.data;
                c.reflow();
            }
            catch (err) {
                console.error(err);
                $(window).off(event);
            }
        }
        $(window).on("resize", chart, chartReflow);

	    var refM;
	    var minFirst;

	    var ordinalPositions = _.first(chart.xAxis).ordinalPositions;

	    refM = _.first(chart.xAxis).getExtremes(), min = refM.min, max = refM.max;

	    try {
	        switch (options.interval) {
	            //case 1: // минута
	            //    minFirst = getMinExtrem(_.first(chart.options.series).data, 1);
	                //break;
	                //case 10: // 10 минут
	                //    break;
	                //case 60: // час
	                //    break;
	                //case 24: // день
	                //    break;
	                //case 7: // неделя
	                //    break;
	                //case 31: // месяц
	                //    break;
					//case 4: // квартал
					//    minFirst = refM.max;
					//    break;
	            default:

	                //if (typeof ordinalPositions != "undefined") { minFirst = getMinExtrem(ordinalPositions, 0); }
	                //else {
					var data =  chart.options.series[0].data;
					minFirst = (data.length >= 60 ? data[data.length-60] : data[0])[0];
					//}
	                break;
	        }
	    }
	    catch(e) { minFirst = refM.min; }

	    _.first(chart.xAxis).setExtremes(minFirst, max, true, false);

	    return chart;
	};


	//function getMinExtrem(d, t) {
    //
	//    var posLength = d.length;
	//    var poslim = 80;
	//    var pos = 0;
    //
	//    if (poslim < posLength) {
	//        pos = posLength - poslim;
	//    } else {
	//        pos = 0;
	//    }
    //
	//    if (t == 1) {
	//        return _.first(d[pos - 1]);
	//    } else {
	//        return d[pos - 1];
	//    }
	//}

	function showLastPointTooltip(objHighStockchart) {
	    // show tooltip for last point   
	    var points = [];
	    if (objHighStockchart) {
	        for (var i = 0; i < objHighStockchart.series.length; i++)
	            points.push(objHighStockchart.series[i].points[objHighStockchart.series[i].points.length - 1]);

	        objHighStockchart.tooltip.refresh(points);
	    }
	}

	update = function (container, data_sources, instruments, technicals, chart_type, options) {		
		var chart, max, min, offset, _ref;

		if (options == null) {
			options = {};
		}
		chart = options.chart;
		offset = 0;

	    /*
			UPDATE CANDLES
		*/

		offset += update_candles(data_sources, instruments, chart_type, offset, options);
		/*
			UPDATE VOLUMES
		*/

		if (instruments && instruments[0] && !instruments[0].hideVolumes) {
			offset += update_volumes(data_sources, instruments, offset, options);
		}
		/*
			UPDATE INLINE TECHNICALS
		*/

		offset += update_inline_technicals(data_sources, instruments, technicals, offset, options);
		/*
			UPDATE SEPARATE TECHNICALS
		*/

		offset += update_separate_technicals(data_sources, instruments, technicals, offset, options);
		/*
			UPDATE CHART
		*/

		//_ref = calculate_extremes(chart, options), min = _ref.min, max = _ref.max;
		//_.first(chart.xAxis).setExtremes(min, max, true, false);
		chart.redraw();
		return chart;
	};

	calculate_technicals_colors_indices = function (technicals, instruments, data_sources) {
		var effective_instrument_index, index, inline_instrument_index, instrument, result, technical, total_instruments, _i, _len, _ref;

		total_instruments = _.size(instruments);
		if (total_instruments === 0) {
			return [];
		}
		effective_instrument_index = _.first((function () {
			var _i, _len, _results;

			_results = [];
			for (index = _i = 0, _len = instruments.length; _i < _len; index = ++_i) {
				instrument = instruments[index];
				if (!instrument.disabled) {
					_results.push(index);
				}
			}
			return _results;
		})());
		inline_instrument_index = 0;
		result = [];
		if (effective_instrument_index != null) {
			_ref = data_sources[instrument_key(instruments[effective_instrument_index])].technicals;
			for (_i = 0, _len = _ref.length; _i < _len; _i++) {
				technical = _ref[_i];
				if (technical.inline) {
					result.push(total_instruments + inline_instrument_index);
					inline_instrument_index++;
				} else {
					result.push(effective_instrument_index);
				}
			}
		}
		return result;
	};
    
	function ToLocalDate(inDate) {
	    var date = new Date();
	    date.setTime(inDate.valueOf() - 60000 * inDate.getTimezoneOffset());
	    return date;
	}
    
	render_tooltips = function (state, _options, instruments) {
		var date, offset, tooltip, __points;

		$('.tooltip', $('.highcharts-container')).remove();

		date = new Date(state.points[0].x);
		__points = _.reduce(state.points, function (memo, points) {
			var id, index, _base, _ref;

			_ref = points.series.options.id.split(':'), id = _ref[0], index = _ref[1];
			((_base = (memo[id] || (memo[id] = [])))[index] || (_base[index] = [])).push(points);
			return memo;
		}, {});

	    if (_options.interval == 4) {
	        date = ToLocalDate(date);
	    }

	    tooltip = $('<ul>').addClass('tooltip').css('top', 0).appendTo($('.highcharts-container'));
		if (_options != null && _options.interval != null && (_options.interval == 24 || _options.interval == 7 || _options.interval == 31 || _options.interval == 4)) {
			$('<li>').addClass('date').html(Highcharts.dateFormat('%d-%m-%Y', date)).appendTo(tooltip);
		} else {
			$('<li>').addClass('date').html(Highcharts.dateFormat('%d-%m-%Y %H:%M', date)).appendTo(tooltip);
		}

	    var currencyType = "";
	    var currencyElement = $('.mx-security-digest .change span:last-child');
		if (currencyElement)
			switch (currencyElement.text())
			{
				case "USD": currencyType = "&#36;"; break;
				case "EUR": currencyType = "&#8364;"; break;
				case "RUB": currencyType = "&#8381;"; break;
				default: currencyType = (currencyElement.html() == "&nbsp;" || currencyElement.text().length <= 0) ? "" : currencyElement.text();
			}
		if (currencyType.length === 0) {
			var elSO = $('.price'); // для ОнА
			if (elSO.length > 0) currencyType = (elSO[0].outerText).replace(/[^\p{Sc}]/gu, '');
		}

		_.each(__points['candles'], function (points) {
		    return render_points_for_tooltip(tooltip, points, __points['volumes'], currencyType, instruments);
		});
		_.each(__points['inline technicals'], function (points) {
			return render_points_for_tooltip(tooltip, points, _options);
		});
		/*offset = candles_yAxis_margin + candles_yAxis_height;
		tooltip = $('<ul>').addClass('tooltip').css('top', offset).appendTo($('.highcharts-container'));
		if (_options != null && _options.interval != null && (_options.interval == 24 || _options.interval == 7 || _options.interval == 31 || _options.interval == 4)) {
			$('<li>').addClass('date').html(Highcharts.dateFormat('%d-%m-%Y', date)).appendTo(tooltip);
		} else {
			$('<li>').addClass('date').html(Highcharts.dateFormat('%d-%m-%Y %H:%M', date)).appendTo(tooltip);
		}*/

		/*_.each(__points['volumes'], function (points) {
		    // console.log(points[0]);
			return render_points_for_tooltip(tooltip, points, _options);
		});*/
		offset = candles_yAxis_margin + candles_yAxis_height + volumes_yAxis_margin + volumes_yAxis_height;
		_.each(__points['separate technicals'], function (points, index) {
		    tooltip = $('<ul>').addClass('tooltip').css('top', offset + (volumes_yAxis_margin + volumes_yAxis_height) * index).appendTo($('.highcharts-container'));
			if (_options != null && _options.interval != null && (_options.interval == 24 || _options.interval == 7 || _options.interval == 31 || _options.interval == 4)) {
				$('<li>').addClass('date').html(Highcharts.dateFormat('%Y-%m-%d', date)).appendTo(tooltip);
			} else {
				$('<li>').addClass('date').html(Highcharts.dateFormat('%Y-%m-%d %H:%M', date)).appendTo(tooltip);
			}

			return render_points_for_tooltip(tooltip, points, _options);
		});
		return false;
	};

	render_points_for_tooltip = function (container, points, _options, currencyType, instruments) {
		var view;

		view = $('<li>').appendTo(container);
		if (points && points.length > 0) {
			$('<em>').html(points[0].series.name).css('color', points[0].series.color).appendTo(view);
			return _.each(points, function (point) {
				return render_point_for_tooltip(view, point, _options, currencyType, instruments);
			});
		}
		else {
			//console.log('if (points && points.length > 0) {');
		}
	};

	render_point_for_tooltip = function (container, point, _options, currencyType, instruments) {
		switch (point.series.type) {
			case 'line':
				if (instruments && instruments[0] && !instruments[0].hideVolumes) {
					var volumeLineTitle = (mx.I18n.locale == "ru") ? "Объём" : "Turnover";
					if (point.point.y != null && _options && typeof _options[0] != "undefined") {
						var volumeLine = _.filter(_options[0], function (item) { return item.x == point.point.x; });
						if (!volumeLine[0]) {
							volumeLine = _options[0];
						}
						var volumeLineValue = Highcharts.numberFormat(volumeLine[0].y, -1, ',', ' ') + "&nbsp;" + currencyType;
						return $('<span>').html(Highcharts.numberFormat(point.point.y, -1, ',', ' ') + ", <b>" + volumeLineTitle + "</b>: " + volumeLineValue).appendTo(container);
					}
				}

			    return $('<span>').html(Highcharts.numberFormat(point.point.y, -1, ',', ' ')).appendTo(container);

				//}
		    /*case 'column':
			    return $('<span>').html(Highcharts.numberFormat(point.point.y, -1, ',', ' ')).appendTo(container);*/
			case 'candlestick':
		    case 'ohlc':
		        return _.each(['open', 'high', 'low', 'close', 'turnover'], function (key) {
			        var name = "";
			        var value = 0.0;
			        if (mx.I18n.locale == "ru") {
			            switch (key) {
			                case "open":
			                    name = "Открытие";
			                    value = Highcharts.numberFormat(point.point[key], -1, ',', ' ');
			                    break;
			                case "high":
			                    name = "Макс.";
			                    value = Highcharts.numberFormat(point.point[key], -1, ',', ' ');
			                    break;
			                case "low":
			                    name = "Mин.";
			                    value = Highcharts.numberFormat(point.point[key], -1, ',', ' ');
			                    break;
			                case "close":
			                    name = "Закрытие";
			                    value = Highcharts.numberFormat(point.point[key], -1, ',', ' ');
			                    break;
										case "turnover":
											if (instruments && instruments[0] && !instruments[0].hideVolumes) {
			                    name = "<b>Объём</b>";
													if(point.point.y == null || !_options) break;
			                    var volumeDataRu = _.filter(_options[0], function (item) { return item.x == point.point.x; });
			                    value = Highcharts.numberFormat(volumeDataRu[0].y, -1, ',', ' ') + "&nbsp;" + currencyType;
											}
			                    break;
			            }
			        } else {
			            name = key;
			            switch (key) {
			                case "open":
			                case "high":
			                case "low":
			                case "close":
			                    value = Highcharts.numberFormat(point.point[key], -1, ',', ' ');
			                    break;
			                case "turnover":
											if (instruments && instruments[0] && !instruments[0].hideVolumes) {
												name = "<b>" + name + "</b>";
												var volumeDataEn = _.filter(_options[0], function (item) { return item.x == point.point.x; });
												value = Highcharts.numberFormat(volumeDataEn[0].y, -1, ',', ' ') + "&nbsp;" + currencyType;
											} else name = "";
			                    break;
			            }
							}
							if (name) return $('<span>').html(name + ': ' + value).appendTo(container);
							else return ;
				});
		}
	};

	widget = function (wrapper, options) {
		var cache_extremes, change_chart_candle_width, change_chart_type, change_instruments, change_technicals, chart, chart_candle_width, chart_candle_width_wrapper, chart_type, chart_type_wrapper, chart_wrapper, data_source_for_instrument, data_sources, deferred, delayed_render, instruments, instruments_wrapper, ready_for_render, refresh, refresh_timeout, render, should_rebuild, technicals, technicals_meta, technicals_wrapper;

		if (options == null) {
			options = {};
		}
		wrapper = $(wrapper);
		if (_.size(wrapper) === 0) {
			return;
		}

		////////////////////////
		//metadata = void 0;
		//if (metadata == null) {
		//    //alert('test');
		//    metadata = mx.data.metadata();
		//}
		//instruments = $.when(metadata);

		//instruments.then(function () {
		//    deferred.resolve();
		//    return {
		//        data: function () {
		//            return [{ 'board': 'TQBR', 'disabled': 'false', 'failure': 'undefined', 'id': 'SBER' }];
		//        }
		//    }
		//});
		////////////////////////
		deferred = new $.Deferred;
		chart_wrapper = $('.chart_wrapper', wrapper);
		chart_candle_width_wrapper = $('.chart_candle_widths_wrapper', wrapper);

		chart_type_wrapper = $('.chart_types_wrapper', wrapper);
		//instruments_wrapper = $('.instruments_wrapper', wrapper);
		technicals_wrapper = $('.technicals_wrapper', wrapper);
		chart_candle_width = mx.data.chart_candle_width(chart_candle_width_wrapper, options.id);
		chart_type = mx.data.chart_type(chart_type_wrapper);

		//mx.data.chart_instruments(instruments_wrapper);
		instruments = mx.data.chart_instruments(options.board, options.id, options.engine, options.hideVolumes);
		//instruments = [{ options.board, 'board': 'TQBR', 'disabled': 'false', 'failure': 'undefined', 'id': 'SBER' }];
		//instruments = 
		//{
		//    data: function () {
		//        return [{ 'board': 'TQBR', 'disabled': 'false', 'failure': 'undefined', 'id': 'SBER' }];
		//    }
		//}

		//instruments = [{ 'board': 'TQBR', 'disabled': 'false', 'failure': 'undefined', 'id': 'SBER' }];
		//return deferred.promise({
		//    data: function () {
		//        return instruments;
		//    }
		//});
		//instruments = [{ 'board': 'TQBR', 'disabled': 'false', 'failure': 'undefined', 'id': 'SBER' }];
		//alert('test');

		//console.info("instruments:", instruments);

		technicals = mx.data.chart_technicals(technicals_wrapper);
		data_sources = {};
		technicals_meta = {};
		should_rebuild = true;
		refresh_timeout = void 0;
		chart = void 0;
		ready_for_render = $.when(chart_candle_width, chart_type, instruments, technicals);
		render = function () {
			if (should_rebuild) {
				instruments.data().forEach(function (i) {
					if (i.failure != null) {
						i.disabled = false;
					}
					return i.failure = void 0;
				});
			}
			return $.when.apply($, _.values(data_sources)).then(function () {
				var cached_extremes, create_or_update, dataMax, dataMin, instrument, max, min, valid_instruments, validated_instruments, _ref;

				cached_extremes = cache.get('extremes');
				_ref = cached_extremes != null ? cached_extremes : chart != null ? _.first(chart.xAxis).getExtremes() : {}, min = _ref.min, max = _ref.max, dataMin = _ref.dataMin, dataMax = _ref.dataMax;
				create_or_update = (chart == null) || should_rebuild ? create : update;
				validated_instruments = /*instruments.data();*/ validate_instruments(instruments.data(), data_sources);
				//console.info("validated_instruments", validated_instruments);
				//console.info("validated_instruments:", validated_instruments);
				//valid_instruments = validated_instruments;

				valid_instruments = (function () {
					var _i, _len, _results;

					_results = [];
					for (_i = 0, _len = validated_instruments.length; _i < _len; _i++) {
						instrument = validated_instruments[_i];
						if (instrument.failure == null) {
                            _results.push(instrument);
						}
					}
					return _results;
				})();

				//console.info("validated_instruments:", validated_instruments);
				if (_.size(valid_instruments) > 0) {
					chart = create_or_update(chart_wrapper, data_sources, validated_instruments, technicals.data(), chart_type.data(), {
						chart: chart,
						min: min,
						max: max,
						left_lock: (min != null) && min === dataMin,
						right_lock: (max != null) && max === dataMax,
						on_extremes_change: cache_extremes,
						technicals_meta: technicals_meta,
						some_events: options.events,
						interval: chart_candle_width.data().interval,
						duration: chart_candle_width.data().duration//,
						//instruments: instruments
					});
					//chart_wrapper.parent().parent().show();
				} else {
					if (chart != null) {
						chart.destroy();
						chart = void 0;
					}
					chart_wrapper.css('height', '').html(no_data());
					//chart_wrapper.parent().parent().hide();
				}
				should_rebuild = false;
				$(window).trigger('chart:render:complete');
				return $(window).trigger('chart:indicators:colors', [calculate_technicals_colors_indices(technicals.data(), instruments.data(), data_sources)]);
			});
		};
		var _delayed_render_timeOut;
		delayed_render = function () {
			if (should_rebuild === true && chart) {
				chart.showLoading();
			}
			if (_delayed_render_timeOut) {
				clearTimeout(_delayed_render_timeOut);
			}
			_delayed_render_timeOut = setTimeout(render, 50);
		};
		cache_extremes = function (event) {
			var dataMax, dataMin, _ref;

			if (event.currentTarget) {
				_ref = event.currentTarget.getExtremes();
				dataMin = _ref.dataMin;
				dataMax = _ref.dataMax;
			}

			return cache.set('extremes', {
				min: event.min,
				max: event.max,
				dataMin: dataMin,
				dataMax: dataMax
			});
		};
		data_source_for_instrument = function (instrument) {
		    var duration, interval, period;

			interval = chart_candle_width.data().interval;
			duration = chart_candle_width.data().duration;
			//period = "" + (Math.ceil(duration / 120)) + "d";

       var result = mx.cs.highstock_2(instrument_key(instrument), {
					interval: interval,
					//period: period,
					candles: 500,
				 technicals: technicals.data(),
				 prev_boards: options.prev_boards
			 });
			return result;
		};


		function setisredr(ds)
		{
		    try {

		        if (ds != null) { //&& ds[0].candles != null && ds[0].candles.length > 0) {

		            var canv = _.takeRight(_.first(_.values(ds)).candles[0].candles_data);
		            var canvlen = _.first(_.values(ds)).candles[0].candles_data.length;

		            //console.log("<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>");

		            ////chart_candle_width
		            //console.log("<<<<<<<<<<<<<<<<<<chart_candle_width.data().interval>>>>>>>>>>>>>>>>>>>>>");
		            //console.log(chart_candle_width.data().interval);

		            //console.log(canv);
		            //console.log(canv_prev);
		            //console.log("---");
		            //console.log("canvlen: " + canvlen);
		            //console.log("canvlen_prev: " + canvlen_prev);
		            //console.log("<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>");

		            if (canv != null && canvlen != null && canv_prev != null && canvlen_prev != null) {

		                isredr = false;

		                for (var j = 0; j < canv.length; j++) {
		                    if (canvlen >= canvlen_prev && canv[j] != canv_prev[j]) {
		                        isredr = true;
		                    }
		                }

		                //console.log("isredr:" + isredr);
		            }

		            canv_prev = canv;
		            if (canvlen_prev == undefined || canvlen_prev < canvlen) {
		                canvlen_prev = canvlen;
		            }

		            if (candle_interval_prev != chart_candle_width.data().interval) {
		                isredr = true;
		                candle_interval_prev = chart_candle_width.data().interval;
		            }
		        }
		    } catch (e) {
		        isredr = true;
		    }
		}

	    var isredr = true;

	    refresh = function() {
            needBlink = true;
            clearTimeout(refresh_timeout);
	        data_sources = _.reduce(instruments.data(), function(memo, instrument) {
	            memo[instrument_key(instrument)] = data_source_for_instrument(instrument);
	            return memo;
	        }, {});

	        //$.when.apply($, _.values(data_sources)).then(function () {
	        //    setisredr(data_sources);
	        //});



	        return $.when.apply($, _.values(data_sources)).then(function () {

	            setisredr(data_sources);
	            if (isredr || istechch) delayed_render();

	            //console.log('_.values(data_sources)2');
	            //console.log(_.values(data_sources)[0]);
	            //setisredr(data_sources);
	            //delayed_render();
                _.delay(function(){$(".chart_refresh_indicator").addClass("chart_refresh_indicator_blink");}, 200);
                _.delay(function(){$(".chart_refresh_indicator").removeClass("chart_refresh_indicator_blink");}, 1200);
	            return refresh_timeout = _.delay(refresh, refresh_delay);
	        });

	    };
		change_chart_candle_width = function () {
			should_rebuild = true;
			return refresh();
		};
		change_chart_type = function () {
			should_rebuild = true;
			return delayed_render();
		};
		change_instruments = function (event, instruments, message) {
			var instrument, key, _i, _j, _len, _len1, _name, _ref, _ref1;

			switch (message) {
				case 'add':
					for (_i = 0, _len = instruments.length; _i < _len; _i++) {
						instrument = instruments[_i];
						if ((_ref = data_sources[_name = instrument_key(instrument)]) == null) {
							data_sources[_name] = data_source_for_instrument(instrument);
						}
					}
					break;
				case 'remove':
					_ref1 = _.difference(_.keys(data_sources), instruments.map(function (i) {
						return instrument_key(i);
					}));
					for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
						key = _ref1[_j];
						delete data_sources[key];
					}
			}
			should_rebuild = true;
			return delayed_render();
		};
		change_technicals = function () {
		    should_rebuild = true;
		    istechch = true;
			return refresh();
		};
		ready_for_render.then(function () {
		    istechch = false;
			$(window).on('chart:candle_width:changed', change_chart_candle_width);
			$(window).on('chart:type:changed', change_chart_type);
			$(window).on('chart:instruments:changed', change_instruments);
			$(window).on('chart:technicals:changed', change_technicals);
			technicals_meta = _.reduce(technicals.meta(), function (memo, item) {
				memo[item.id] = item;
				return memo;
			}, {});
			refresh();

			var _chart_candle_widths_wrapper = $('.chart_candle_widths_wrapper');
			_chart_candle_widths_wrapper.find('li[data-interval="5"]').remove();
			_chart_candle_widths_wrapper.find('li[data-interval="15"]').remove();
			_chart_candle_widths_wrapper.find('li[data-interval="30"]').remove();

			return deferred.resolve();
		});

		return deferred.promise();
	};

	$.extend(scope, {
		chart: widget
	});
}).call(this);
;
(function () {
	var $, cache, candle_widths, data, default_candle_width_interval, make_candle_widths_view, root, scope, widget;

	root = this;
	scope = root['mx']['data'];
	$ = jQuery;

	if (!window.moex.chartPeriod) {
		window.moex.chartPeriod = {
			name: 'data.chart.period',
			defaultInterval: 10,
			isDeposit: false
		};
	}

	cache = kizzy(window.moex.chartPeriod.name);
	data = void 0;
	candle_widths = [];
	default_candle_width_interval = window.moex.chartPeriod.defaultInterval;

	make_candle_widths_view = function (wrapper) {
		var candle_width, container, _i, _len;

		container = $('<ul>').attr({
			id: 'chart_candle_width'
		});
		for (_i = 0, _len = candle_widths.length; _i < _len; _i++) {
			candle_width = candle_widths[_i];
			if (window.moex.chartPeriod.isDeposit &&
				(candle_width.interval === 1 || candle_width.interval === 10 || candle_width.interval === 60)) {
				continue;
			}

			container.append($('<li>').attr({
				'data-interval': candle_width.interval,
				'data-duration': candle_width.duration
			}).html(candle_width.title));
		}
		wrapper.append(container);
		return container;
	};

	widget = function (wrapper, secId) {
		var broadcast, candle_width_changed, candle_widths_view, current_candle_width, deferred, ready_for_render, set_cached_candle_width, set_candle_width_by_interval, intervals, getIntervals;

		wrapper = $(wrapper);
		if (_.size(wrapper) === 0) {
			return;
		}
		current_candle_width = void 0;
		deferred = new $.Deferred;
		candle_widths_view = void 0;
		if (data == null) {
			data = mx.iss.metadata();
		}
		getIntervals = function () {
			var def = $.Deferred();

			var boardsUrl = "{iss}/securities/{sec}.json?_={time}"
				.replace("{iss}", window.moex.iss.baseUrl)
				.replace("{sec}", secId)
				.replace("{time}", (new Date()).toString());

			$.getJSON(boardsUrl, function (response) {
				var boards = response.boards;
				var columns = boards.columns;
				var is_primary = 0;
				var is_traded = 0;
				var i_market = 0;
				var i_engine = 0;
				var i_boardid = 0;
				var i_board_group_id = 0;
				for (var i = 0; i < columns.length; i++) {
					if (columns[i] === "is_primary") {
						is_primary = i;
					}
					else if (columns[i] === "is_traded") {
						is_traded = i;
					}
					else if (columns[i] === "market") {
						i_market = i;
					}
					else if (columns[i] === "engine") {
						i_engine = i;
					}
					else if (columns[i] === "boardid") {
						i_boardid = i;
					}
					else if (columns[i] === "board_group_id") {
						i_board_group_id = i;
					}
				}

				var market = '';
				var engine = '';
				var board_group_id = 0;
				var data = boards.data;
				for (var y = 0; y < data.length; y++) {
					var row = data[y];
					//if (row[is_traded] > 0 && row[is_primary] > 0) {
					if (row[is_primary] > 0) {
						market = row[i_market];
						engine = row[i_engine];
						board_group_id = row[i_board_group_id];
						break;
					}
				}

				var url = '{ISS}/engines/{engine}/markets/{market}/securities/{INDEX}/candleborders.json'
					.replace("{ISS}", window.moex.iss.baseUrl)
					.replace("{INDEX}", secId)
                    .replace("{engine}", engine)
					.replace("{market}", market);

				console.debug({
					url: url,
					market: market,
					engine: engine
				});

				$.getJSON(url, function (response) {
					intervals = response.borders.data || [];
					var valid = intervals.length > 0;

					if (!valid) {
						console.error('ISS ERROR! No valid candleborders for: ' + secId);
						intervals = [];
						var durations = [1, 10, 60, 24, 7, 31, 4];
						for (var i = 0; i < durations.length; i++) {
							intervals.push([
								moment((new Date()).setFullYear((new Date()).getFullYear() - 1)).format("YYYY-MM-DD hh:mm:ss"),
								moment((new Date()).setFullYear((new Date()).getFullYear() + 1)).format("YYYY-MM-DD hh:mm:ss"),
								durations[i],
								board_group_id
							]);
						}
					}

					// ���� �������� ������� �������� - �������� ������ �� ISS, ������� ������� ��������� ������� �������� ���
					let daysRow = intervals.find(function (val) { return val[2] === 24 });
					if (daysRow !== null) {
						let totalDays = moment(daysRow[1], 'YYYY-MM-DD hh:mm:ss').diff(moment(daysRow[0], 'YYYY-MM-DD hh:mm:ss'), 'days');

						if (totalDays < 7) { // ������
							let removeEl = intervals.find(function (val) { return val[2] === 7 });
							if (removeEl != null)
								intervals.splice(intervals.indexOf(removeEl), 1);
						}

						if (totalDays < 30) { // �����
							let removeEl = intervals.find(function (val) { return val[2] === 30 });
							if (removeEl != null)
								intervals.splice(intervals.indexOf(removeEl), 1);
						}

						if (totalDays < 31) { // ���� �����
							let removeEl = intervals.find(function (val) { return val[2] === 31 });
							if (removeEl != null)
								intervals.splice(intervals.indexOf(removeEl), 1);
						}

						if (totalDays < 90) { // �������
							let removeEl = intervals.find(function (val) { return val[2] === 4 });
							if (removeEl != null)
								intervals.splice(intervals.indexOf(removeEl), 1);
						}
					}

					/*console.log(intervals);
					var valid = false;
					var now = new Date();
					for (var i = 0; i < intervals.length; i++) {
						var row = intervals[i];
						for (var j = 0; j < 2; j++) {
							var date = moment(row[j], 'YYYY-MM-DD hh:mm:ss').toDate();
							if (date >= now) {
								valid = true;
							}
						}
					}*/

					def.resolve(intervals);
				});
			});

			return def.promise();
		};

		ready_for_render = $.when(data, getIntervals());
		candle_width_changed = true;
		broadcast = function () {
			if (deferred.state() !== 'resolved') {
				return;
			}
			if (!candle_width_changed) {
				return;
			}
			candle_width_changed = false;
			return $(window).trigger('chart:candle_width:changed', current_candle_width);
		};
		set_cached_candle_width = function () {
			var _ref, _ref1;

			return set_candle_width_by_interval((_ref = (_ref1 = cache.get('candle_width')) != null ? _ref1.interval : void 0) != null ? _ref : default_candle_width_interval);
		};
		set_candle_width_by_interval = function (interval) {
			var candle_width;

			if ((current_candle_width != null ? current_candle_width.interval : void 0) === interval) {
				return;
			}
			current_candle_width = _.first((function () {
				var _i, _len, _results, _intervals;

				_results = [];
				inervals = candle_widths.map(function (inter) {
					return inter.interval;
				})
				for (_i = 0, _len = candle_widths.length; _i < _len; _i++) {
					candle_width = candle_widths[_i];
					if (candle_width.interval === interval) {
						_results.push(candle_width);
					}
					else if (inervals.indexOf(interval) == -1) {
						_results.push(candle_width);
					}
				}
				return _results;
			})());

			$('li', candle_widths_view).removeClass('selected');
			$("li[data-interval=" + (interval || current_candle_width.interval) + "]", candle_widths_view).addClass('selected');
			cache.set('candle_width', current_candle_width);
			candle_width_changed = true;
			return broadcast();
		};

		ready_for_render.then(function () {
			var massInterv = intervals.map(function (interv) {
				return interv[2];
			});
            var widths = data.result.data.durations;
			candle_widths = widths.filter(function (obj) {
				return massInterv.indexOf(obj.interval) > -1;
			})


			candle_widths_view = make_candle_widths_view(wrapper);
			candle_widths_view.on('click', 'li', function (event) {
				return set_candle_width_by_interval($(this).data('interval'));
			});
			set_cached_candle_width();
			return deferred.resolve();
		});

		return deferred.promise({
			data: function () {
				return current_candle_width;
			}
		});
	};

	$.extend(scope, {
		chart_candle_width: widget
	});

}).call(this);
;
(function() {
  var $, background_colors, colors, root, scope;

  root = this;

  scope = root['mx']['data'];

  $ = jQuery;

  colors = ['#0093c6', '#009900', '#f1340f', '#939d00', '#9255ff', '#00967c', '#eb2b8f', '#ce5f00', '#ce5f00', '#a27b00'];

  background_colors = ['#00a7e1', '#00b50a', '#ff552a', '#a9b200', '#b270ff', '#00b196', '#ff50a9', '#ee7913', '#73ab00', '#bf9400'];

  $.extend(scope, {
    colors: colors,
    background_colors: background_colors
  });

}).call(this);
;
(function() {
  var $, make_instrument_view, make_instruments_wrapper, max_instruments, metadata, root, scope, widget;

  root = this;

  scope = root['mx']['data'];

  $ = jQuery;

  max_instruments = 5;

  metadata = void 0;

  //make_instruments_wrapper = function(wrapper) {
  //  var container;

  //  container = $('<ul>').attr('id', 'chart_instruments');
  //  wrapper.html(container);
  //  return container;
  //};

  //make_instrument_view = function(instrument, index, size) {
  //  var view;

  //  view = $('<li>').attr({
  //    'data-param': [instrument.board, instrument.id].join(':')
  //  }).css('background-color', scope.background_colors[index]).html(instrument.id + ' : ' + metadata.board(instrument.board).boardgroup.title).toggleClass('disabled', !!instrument.disabled);
  //  if (instrument.failure != null) {
  //    view.prepend($('<span>').addClass('failure').html('!'));
  //    view.attr('title', instrument.failure);
  //  }
  //  if (size > 1) {
  //    view.append($('<span>').addClass('remove')).addClass('removeable');
  //  }
  //  return view;
  //};

    widget = function (/*wrapper*/ board, id, engine, hideVolumes) {
      var add, add_cached, /*broadcast, */ deferred, del, instruments, instruments_changed, /*instruments_wrapper, */ ready_for_render, remove, render, reorder, should_be_enabled, sort_in_progress /*,  toggle_state */ /*,  update */;

    //wrapper = $(wrapper);
    //if (_.size(wrapper) === 0) {
    //  return;
    //}
    deferred = new $.Deferred;
    //instruments_wrapper = void 0;

    instruments = [{ 'board': board, 'disabled': 'false', 'failure': 'undefined', 'id': id, 'engine': engine, 'hideVolumes': hideVolumes }];

    instruments_changed = true;
    if (metadata == null) {
        //alert('test');
      metadata = mx.data.metadata();
    } 

    ready_for_render = $.when(metadata);
    sort_in_progress = false;
    //render = function() {
    //  var index, instrument, _i, _len, _results;

    //  if (sort_in_progress) {
    //    return;
    //  }
    //  //instruments_wrapper.empty();
    //  _results = [];
    //  //for (index = _i = 0, _len = instruments.length; _i < _len; index = ++_i) {
    //  //    instrument = instruments[index];
    //  //    console.info("instrument: ", instrument);
    //  //  _results.push(instruments_wrapper.append(make_instrument_view(instrument, index, _.size(instruments))));
    //  //}
    //  return _results;
    //};
    //update = function(message, data) {
    //  instruments_changed = true;
    //  scope.caches.chart_instruments(instruments);
    //  render();
    //  alert('test');
    //  //return broadcast(message, data);
    //};

    //broadcast = function (message, ticker) {

    //  //if (deferred.state() !== 'resolved') {
    //  //  return;
    //  //}
    //  //if (!instruments_changed) {
    //  //  return;
    //  //}
    //  //instruments_changed = false;
    //  //$(window).trigger('chart:instruments:changed', [instruments, message]);
    //  //if (message === 'add' || message === 'remove') {
    //  //  return $(window).trigger('chart:tickers', {
    //  //    ticker: [ticker.board, ticker.id].join(':'),
    //  //    message: message
    //  //  });
    //  //}
    //};
    //add_cached = function () {
    //    console.log('add_cached = function ()');
    //  var instrument, _i, _len, _ref, _results;

    //  _ref = scope.caches.chart_instruments() || [];
    //  _results = [];
    //  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
    //    instrument = _ref[_i];
    //    _results.push(add(instrument));
    //  }

    //    console.info("_ref:", _ref);

    //  return _results;
    //};
    //add = function(data) {
    //  var board, id, present, _ref;

    //  if (_.size(instruments) >= max_instruments) {
    //    return $(window).trigger('chart:tickers', {
    //      message: 'too many tickers',
    //      count: max_instruments
    //    });
    //  }
    //  if (_.isString(data)) {
    //    _ref = data.split(':'), board = _ref[0], id = _ref[1];
    //    data = {
    //      board: board,
    //      id: id
    //    };
    //  }
    //  board = metadata.board(data.board);
    //  present = instruments.filter(function(instrument) {
    //    return metadata.board(instrument.board).market.name === board.market.name && instrument.id === data.id;
    //  });
    //  if (present.length > 0) {
    //    return;
    //  }
    //  console.info("instruments.push(data)", data);

    //  instruments.push(data);
    //  return update('add', data);
    //};
    //del = function(data) {
    //  return remove(data);
    //};
    //remove = function(ticker) {
    //  var instrument;

    //  if (_.size(instruments) === 1) {
    //    return $(window).trigger('chart:tickers', {
    //      message: 'too little tickers'
    //    });
    //  }
    //  ticker = (function() {
    //    var board, id, _ref;

    //    _ref = ticker.split(':'), board = _ref[0], id = _ref[1];
    //    board = metadata.board(board);
    //    return [board, id];
    //  })();
    //  instrument = _.filter(instruments, function(instrument) {
    //    var board;

    //    board = metadata.board(instrument.board);
    //    return instrument.id === ticker[1] && board.market.name === ticker[0].market.name;
    //  })[0];
    //  if (instrument) {
    //    instruments = _.without(instruments, instrument);
    //    //update('remove', instrument);
    //  }
    //  if (should_be_enabled()) {
    //    return _.first(instruments).disabled = false;
    //  }
    //};
    //toggle_state = function(param) {
    //  var board, id, instrument, _ref;

    //  _ref = param.split(':'), board = _ref[0], id = _ref[1];
    //  board = metadata.board(board);
    //  instrument = _.first((function() {
    //    var _i, _len, _results;

    //    _results = [];
    //    for (_i = 0, _len = instruments.length; _i < _len; _i++) {
    //      instrument = instruments[_i];
    //      if (instrument.id === id && metadata.board(instrument.board).market.name === board.market.name) {
    //        _results.push(instrument);
    //      }
    //    }
    //    return _results;
    //  })());
    //  if (instrument == null) {
    //    return;
    //  }
    //  instrument.disabled = !instrument.disabled;
    //  if (should_be_enabled()) {
    //    instrument.disabled = false;
    //  }
    //  //return update('toggle state');
    //};
    //reorder = function() {
    //  var params;

    //  params = $('li', this).map(function() {
    //    return $(this).data('param');
    //  }).get();
    //  instruments = _.sortBy(instruments, function(instrument) {
    //    return _.indexOf(params, [instrument.board, instrument.id].join(':'));
    //  });
    //  sort_in_progress = false;
    //  //return update('reorder');
    //};
    //should_be_enabled = function() {
    //  var instrument;

    //  return _.size((function() {
    //    var _i, _len, _results;

    //    _results = [];
    //    for (_i = 0, _len = instruments.length; _i < _len; _i++) {
    //      instrument = instruments[_i];
    //      if (!instrument.disabled) {
    //        _results.push(instrument);
    //      }
    //    }
    //    return _results;
    //  })()) === 0;
    //};
    ready_for_render.then(function() {
      //instruments_wrapper = make_instruments_wrapper(wrapper);
      //console.info('add_cached()');
      //add_cached();
      //instruments_wrapper.on('click', 'li', function(event) {
      //  return toggle_state($(this).data('param'));
      //});
      //instruments_wrapper.on('click', 'li span', function(event) {
      //  return remove($(this).closest('li').data('param'));
      //});
      //$(window).on('security:to:chart', function (event, data) {
      //    console.log("$(window).on('security:to:chart'", data);
      //  return add(data);
      //});
      //$(window).on('security:from:chart', function(event, data) {
      //  return del(data);
      //});
      //$(window).on('chart:render:complete', function(event) {
      //  return render();
      //});
      //$(instruments_wrapper).sortable({
      //  axis: 'x',
      //  start: function() {
      //    return sort_in_progress = true;
      //  },
      //  update: reorder
      //});
      deferred.resolve();
      //return broadcast('init');
    });
    return deferred.promise({
        data: function () {
        return instruments;
      }
    });
  };

  $.extend(scope, {
    chart_instruments: widget
  });

}).call(this);
;
(function () {
	var $, cache, locales, make_anchors_view, make_factory_anchor_view, make_factory_child_view, make_input_view, make_select_view, make_technical_anchor_view, make_technical_child_view, make_text_input_view, max_identical_technicals, max_technicals, root, scope, serialize_view, technicals_descriptors, technicals_descriptors_hash, widget;

	root = this;

	scope = root['mx']['data'];

	$ = jQuery;

	cache = kizzy('data.chart.technicals');

	max_technicals = 10;

	max_identical_technicals = 3;

	technicals_descriptors = void 0;

	technicals_descriptors_hash = _.once(function () {
		return _.reduce(technicals_descriptors, function (memo, technical_descriptor) {
			memo[technical_descriptor.id] = technical_descriptor;
			return memo;
		}, {});
	});

	locales = {
		ru: {
			add_technical: 'Добавить индикатор',
			remove_technical: 'Удалить'
		},
		en: {
			add_technical: 'Add technical',
			remove_technical: 'Remove'
		}
	};

	serialize_view = function (view) {
		return $('input,select', view).serializeArray();
	};

	make_anchors_view = function (wrapper) {
		return $('<ul>').addClass('li_add_indicator anchors clearfix').appendTo(wrapper);
	};

	make_factory_anchor_view = function (wrapper) {		
		return $('<li>').addClass('anchor factory').html($('<span class="button_add_indicator">').html(locales[mx.locale()].add_technical)).appendTo(wrapper);
	};

	make_factory_child_view = function (anchor) {
		var descriptor, view, wrapper, _i, _len;

		view = $('<li>').addClass('child');
		wrapper = $('<ul>').addClass('factory clearfix').appendTo(view);
		for (_i = 0, _len = technicals_descriptors.length; _i < _len; _i++) {
			descriptor = technicals_descriptors[_i];
			wrapper.append($('<li>').data('id', descriptor.id).html($('<span>').html(descriptor.title)));
		}
		anchor.data('child', view);
		view.data('anchor', anchor).insertAfter(anchor);

		return view.hide();
	};

	make_technical_anchor_view = function (wrapper, id, values) {
		var descriptor, view;

		descriptor = _.first((function () {
			var _i, _len, _results;

			_results = [];
			for (_i = 0, _len = technicals_descriptors.length; _i < _len; _i++) {
				descriptor = technicals_descriptors[_i];
				if (descriptor.id === id) {
					_results.push(descriptor);
				}
			}
			return _results;
		})());
		if (descriptor == null) {
			return;
		}
		view = $('<li>').addClass('anchor technical').html($('<span>').html(descriptor.title)).insertBefore($('.anchor', wrapper).last());
		make_technical_child_view(view, descriptor, values);
		return view;
	};

	make_technical_child_view = function (anchor, descriptor, values) {
		var index, param, row, tbody, thead, view, wrapper, _i, _len, _ref, _ref1;

		view = $('<li>').addClass('child');
		wrapper = $('<ul>').addClass('technical clearfix').appendTo(view);
		wrapper.append($('<li>').html('<table><thead></thead><tbody></tbody></table>'));
		thead = $('thead', wrapper);
		tbody = $('tbody', wrapper);
		thead.append($('<tr>').append($('<td>').attr('colspan', 3).html(descriptor.description)));
		if (!_.isEmpty(descriptor.params)) {
			_ref = descriptor.params;
			for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
				param = _ref[index];
				row = $('<tr>').appendTo(tbody);
				row.append($('<th>').html(param.title));
				row.append($('<td>').addClass('value').append(make_input_view(param, (_ref1 = values[index]) != null ? _ref1.value : void 0)));
				row.append($('<td>').addClass('hint').html(param.description));
			}
		}		
		wrapper.append($('<li>').addClass('remove').html($('<span>').html(locales[mx.locale()].remove_technical)));
		view.insertAfter(anchor.siblings('.anchor').last());
		anchor.data('child', view);
		view.data('anchor', anchor);
		return view.hide();
	};

	make_input_view = function (param, value) {
		switch (param.value_type) {
			case 'integer':
			case 'float':
				return make_text_input_view(param, value);
			case 'select':
				return make_select_view(param, value);
		}
	};

	make_text_input_view = function (param, value) {
		return $('<input>').attr({
			type: 'text',
			name: param.id
		}).val(value != null ? value : param.value);
	};

	make_select_view = function (param, value) {
		var item, select, _i, _len, _ref;

		select = $('<select>').attr('name', param.id);
		_ref = eval(param.value_range);
		for (_i = 0, _len = _ref.length; _i < _len; _i++) {
			item = _ref[_i];
			select.append($('<option>').attr('value', item.id).html(item.title));
		}
		return select.val(value != null ? value : param.value);
	};

	widget = function (wrapper, options) {
		var add_cached_technicals, add_technical, anchors_view, broadcast, colorize, deferred, hide_child_view, ready_for_render, remove_technical_at, remove_technical_view, serialize, serialize_technical_view, show_child_view, technicals, technicals_changed, toggle_child_view_for_anchor, update_technicals_values;

		if (options == null) {
			options = {};
		}
		wrapper = $(wrapper);
		if (_.size(wrapper) === 0) {
			return;
		}
		technicals = [];
		deferred = new $.Deferred;
		anchors_view = null;
		if (technicals_descriptors == null) {
			technicals_descriptors = mx.cs.technicals();
		}
		ready_for_render = $.when(technicals_descriptors);
		technicals_changed = true;
		broadcast = function () {
			if (deferred.state() !== 'resolved') {
				return;
			}
			if (!technicals_changed) {
				return;
			}
			technicals_changed = false;
			return $(window).trigger('chart:technicals:changed', [technicals]);
		};
		add_cached_technicals = function () {
			var cached_technicals, technical, _i, _len, _results;

			cached_technicals = cache.get("technicals");
			if (cached_technicals == null) {
				return;
			}

			_results = [];
			for (_i = 0, _len = cached_technicals.length; _i < _len; _i++) {
				technical = cached_technicals[_i];
				_results.push(add_technical(technical.id, technical.values));
			}
			return _results;
		};
		add_technical = function (id, values) {
			var technical, view;

			if (values == null) {
				values = [];
			}
			if (_.size(technicals) >= max_technicals) {
				return;
			}
			if (_.size((function () {
				var _i, _len, _results;

				_results = [];
				for (_i = 0, _len = technicals.length; _i < _len; _i++) {
					technical = technicals[_i];
					if (technical.id === id) {
						_results.push(technical);
					}
				}
				return _results;
			})()) >= max_identical_technicals) {
				return;
			}
			view = make_technical_anchor_view(anchors_view, id, values);
			technicals.push({
				id: id,
				values: serialize_technical_view(view)
			});
			technicals_changed = true;
			cache.set("technicals", technicals);
			return broadcast();
		};
		remove_technical_at = function (index) {
			technicals = _.without(technicals, technicals[index]);
			remove_technical_view($('.anchor', wrapper).eq(index));
			technicals_changed = true;
			cache.set("technicals", technicals);
			return broadcast();
		};
		remove_technical_view = function (anchor) {
			var view;

			view = anchor.data('child');
			return hide_child_view(view, function () {
				anchor.remove();
				return view.remove();
			});
		};
		toggle_child_view_for_anchor = function (anchor) {
			var child;

			child = $(anchor.data('child'));
			if (_.size(child) === 0) {
				return;
			}
			if (child.is(':visible')) {
				return hide_child_view(child);
			} else {
				return show_child_view(child);
			}
		};
		show_child_view = function (view, callback) {
			var v, _i, _len, _ref;

			view = $(view);
			_ref = view.siblings('.child').not(view);
			for (_i = 0, _len = _ref.length; _i < _len; _i++) {
				v = _ref[_i];
				if ($(v).is(':visible')) {
					hide_child_view(v);
				}
			}
			if (view.data('anchor') != null) {
				view.data('anchor').addClass('active');
			}
			if (view.is(':hidden')) {
				return view.show('blind', {}, 'fast', callback);
			}
		};
		hide_child_view = function (view, callback) {
			view = $(view);
			if (view.data('anchor') != null) {
				view.data('anchor').removeClass('active');
			}
			if (view.is(':visible')) {
				return view.hide('blind', {}, 'fast', callback);
			}
		};
		serialize_technical_view = function (view) {
			return $('input,select', $(view).data('child')).serializeArray();
		};
		serialize = function () {
			var index, technical, technicals_views, _i, _len;

			technicals_views = $('li.technical', wrapper);
			for (index = _i = 0, _len = technicals.length; _i < _len; index = ++_i) {
				technical = technicals[index];
				technical.values = serialize_technical_view(technicals_views[index]);
			}
			technicals_changed = true;
			update_technicals_values();
			cache.set("technicals", technicals);
			return broadcast();
		};
		update_technicals_values = function () {
			var index, technical, technicals_views, view, _i, _len, _results;

			technicals_views = $('li.technical', wrapper);
			_results = [];
			for (index = _i = 0, _len = technicals.length; _i < _len; index = ++_i) {
				technical = technicals[index];
				view = $('span', technicals_views.eq(index));
				if (!_.isEmpty(technical.values)) {
					_results.push(view.html("" + (technicals_descriptors_hash()[technical.id].title) + " (" + (_.map(technical.values, 'value').join(', ')) + ")"));
				} else {
					_results.push(void 0);
				}
			}
			return _results;
		};
		colorize = function (colors_indices) {
			var color_index, index, technicals_views, _i, _len, _results;

			technicals_views = $('li.technical', wrapper);
			_results = [];
			for (index = _i = 0, _len = colors_indices.length; _i < _len; index = ++_i) {
				color_index = colors_indices[index];
				_results.push($('span', technicals_views[index]).css('border-color', scope.background_colors[color_index]));
			}
			return _results;
		};
		ready_for_render.then(function () {
			var factory_anchor_view;

			anchors_view = make_anchors_view(wrapper);
			factory_anchor_view = make_factory_anchor_view(anchors_view);

			make_factory_child_view(factory_anchor_view);
			add_cached_technicals();
			update_technicals_values();
			anchors_view.on('click', '.anchor', function () {
				return toggle_child_view_for_anchor($(this));
			});
			wrapper.on('click', 'ul.factory li', function () {
				add_technical($(this).data('id'));
				return update_technicals_values();
			});
			wrapper.on('click', 'ul.technical li.remove', function () {
				var anchor;

				anchor = $(this).closest('.child').data('anchor');
				return remove_technical_at($('.anchor', anchors_view).index(anchor));
			});
			wrapper.on('change', 'input, select', serialize);
			$(window).on('chart:indicators:colors', function (event, colors_indices) {
				return colorize(colors_indices);
			});
			return deferred.resolve();
		});
		return deferred.promise({
			data: function () {
				return technicals;
			},
			meta: function () {
				return technicals_descriptors;
			}
		});
	};

	$.extend(scope, {
		chart_technicals: widget
	});

}).call(this);
;
(function() {
  var $, cache, data, default_type, make_types_view, root, scope, widget;

  root = this;

  scope = root['mx']['data'];

  $ = jQuery;

  cache = kizzy('data.chart.type');

  data = [
    {
       id: 'line',
      title: (window.lang === 'en') ? 'Line' : 'Линия'
    },
    {
       id: 'candles',
      title: (window.lang === 'en') ? 'Candles' : 'Свечи'
    },
    {
       id: 'stockbar',
      title: (window.lang === 'en') ? 'Stockbar' : 'Бары'
    }
  ];

  default_type = 'candles';

  make_types_view = function(wrapper) {
    var container, item, _i, _len;

    container = $('<ul>').attr({
      id: 'chart_types'
    });
    for (_i = 0, _len = data.length; _i < _len; _i++) {
      item = data[_i];
      container.append($('<li>').attr('data-type', item.id).html($('<span>').html(item.title).attr('title', item.title)));
    }
    wrapper.append(container);
    return container;
  };

  widget = function(wrapper) {
    var broadcast, current_type, deferred, ready_for_render, set_cached_type, set_type, type_changed, types_view;

    wrapper = $(wrapper);
    if (_.size(wrapper) === 0) {
      return;
    }
    current_type = void 0;
    deferred = new $.Deferred;
    types_view = void 0;
    ready_for_render = $.when(true);
    type_changed = true;
    broadcast = function() {
      if (deferred.state() !== 'resolved') {
        return;
      }
      if (!type_changed) {
        return;
      }
      type_changed = false;
      return $(window).trigger('chart:type:changed', current_type);
    };
    set_cached_type = function() {
      var _ref;

      return set_type((_ref = cache.get('type')) != null ? _ref : default_type);
    };
    set_type = function(type) {
      if (current_type === type) {
        return;
      }
      current_type = type;
      $('li', types_view).removeClass('selected');
      $("li[data-type=" + current_type + "]", types_view).addClass('selected');
      cache.set('type', current_type);
      type_changed = true;
      return broadcast();
    };
    ready_for_render.then(function() {
      var types;

      types = data;
      types_view = make_types_view(wrapper, types);
      types_view.on('click', 'li', function(event) {
        return set_type($(this).data('type'));
      });
      set_cached_type();
      return deferred.resolve();
    });
    return deferred.promise({
      data: function() {
        return current_type;
      }
    });
  };

  $.extend(scope, {
    chart_type: widget
  });

}).call(this);
;
(function() {
  var $, boardgroups, boardgroups_hash, boards, boards_hash, data, engines, engines_hash, mappings, markets, markets_hash, metadata, populate_data, prepare_ticker, prepared_tickers, scope;

  $ = jQuery;

  scope = this.mx.data;

  data = void 0;

  mappings = {
    engines: {
      id: 'id',
      name: 'name',
      title: 'title'
    },
    markets: {
      id: 'market_id',
      name: 'market_name',
      title: 'market_title',
      engine_id: 'trade_engine_id'
    },
    boards: {
      id: 'boardid',
      title: 'board_title',
      trading: function(record) {
        return !!record.is_traded;
      },
      candles: function(record) {
        return !!record.has_candles;
      },
      market_id: 'market_id',
      engine_id: 'engine_id',
      boardgroup_id: 'board_group_id'
    },
    boardgroups: {
      id: 'board_group_id',
      "default": function(record) {
        return !!record.is_default;
      },
      market_id: 'market_id',
      name: 'name',
      title: 'title'
    }
  };

  engines = void 0;

  engines_hash = void 0;

  markets = void 0;

  markets_hash = void 0;

  boards = void 0;

  boards_hash = void 0;

  boardgroups = void 0;

  boardgroups_hash = void 0;

  prepared_tickers = {};

  prepare_ticker = function(ticker) {
    var board, id, _ref;

    alert('prepare_ticker');

    _ref = ticker.split(':'), board = _ref[0], id = _ref[1];
    board = scope.metadata().board(board);
    return {
      id: id,
      board: board,
      boardgroup: board.boardgroup,
      market: board.market,
      engine: board.engine,
      toString: function() {
        return "" + id + ":" + board.id;
      }
    };
  };

  populate_data = function(mapping, data) {
    var array, hash;

    hash = _.reduce(data, function(memo, record) {
      memo[record[mapping.id]] = _.reduce(mapping, (function(memo, value, key) {
        memo[key] = _.isFunction(value) ? value(record) : record[value];
        return memo;
      }), {});
      return memo;
    }, {});
    array = _.map(data, function(record) {
      return hash[record[mapping.id]];
    });
    return [array, hash];
  };

  metadata = function() {
    var deferred, ready;
    deferred = new $.Deferred;
    if (data == null)
    {
      // console.log('test');
      data = mx.iss.metadata();
    }
;

    ready = $.when(data);
    ready.then(function() {
      var _ref, _ref1, _ref2, _ref3;

      /*console.log('test1');
      console.log(JSON.stringify(data));
      console.log(data.result.data.engines);
      console.log('test2');*/

      //console.log(JSON.stringify(mappings));
      //console.info("data.result.data.engines", data.result.data.engines);
      
      _ref = populate_data(mappings.engines, data.result.data.engines), engines = _ref[0], engines_hash = _ref[1];
      _ref1 = populate_data(mappings.markets, data.result.data.markets), markets = _ref1[0], markets_hash = _ref1[1];
      _ref2 = populate_data(mappings.boards, data.result.data.boards), boards = _ref2[0], boards_hash = _ref2[1];
      _ref3 = populate_data(mappings.boardgroups, data.result.data.boardgroups), boardgroups = _ref3[0], boardgroups_hash = _ref3[1];
      _.each(markets_hash, function(market) {
        return market.engine = engines_hash[market.engine_id];
      });
      _.each(boards_hash, function(board) {
        board.market = markets_hash[board.market_id];
        board.engine = engines_hash[board.engine_id];
        return board.boardgroup = boardgroups_hash[board.boardgroup_id];
      });
      return deferred.resolve();
    });
    return deferred.promise({
      engines: function() {
        return engines;
      },
      engine: function(id) {
        return engines_hash[id];
      },
      markets: function() {
        return markets;
      },
      market: function(id) {
        return markets_hash[id];
      },
      boards: function() {
        return boards;
      },
      board: function(id) {
        return boards_hash[id];
      },
      ticker: function(ticker) {
        var _ref;
        return (_ref = prepared_tickers[ticker]) != null ? _ref : prepared_tickers[ticker] = prepare_ticker(ticker);
      }
    });
  };

  $.extend(scope, {
    metadata: _.once(metadata)
  });

}).call(this);
;
(function() {
  var $, number_with_delimiter, number_with_precision, prepare_marketdata_record, render_marketdata_record_number_value, render_marketdata_record_value, root, scope;

  root = this;

  scope = root['mx']['data'];

  $ = jQuery;

  number_with_delimiter = function(value, options) {
    var delimiter, fractional, integer, separator, _ref, _ref1, _ref2;

    if (options == null) {
      options = {};
    }
    if (!((value != null) || _.isNumber(value))) {
      return value;
    }
    delimiter = (_ref = options.delimiter) != null ? _ref : mx.locales.number.precision.format.delimiter[mx.locale()];
    separator = (_ref1 = options.separator) != null ? _ref1 : mx.locales.number.precision.format.separator[mx.locale()];
    _ref2 = value.toString().split('.'), integer = _ref2[0], fractional = _ref2[1];
    integer = integer.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + delimiter);
    return _.compact([integer, fractional]).join(separator);
  };

  number_with_precision = function(value, options) {
    var precision, _ref;

    if (options == null) {
      options = {};
    }
    if (!((value != null) || _.isNumber(value))) {
      return value;
    }
    precision = (_ref = options.precision) != null ? _ref : 2;
    return number_with_delimiter(value.toFixed(precision), options);
  };

  prepare_marketdata_record = function(record, columns) {
    var column, default_precision, id, name, trending_column, value;

    if (record == null) {
      return record;
    }
    record.precisions = {};
    record.trends = {};
    default_precision = record.DECIMALS;
    for (name in record) {
      value = record[name];
      column = _.find(columns, function(column) {
        return column.name === name;
      });
      if (column == null) {
        continue;
      }
      record[name] = (function() {
        var _ref;

        switch (column.type) {
          case 'number':
            record.precisions[name] = !!column.has_percent ? 2 : (_ref = column.precision) != null ? _ref : default_precision;
            if (value != null) {
              return parseFloat(new Number(value).toFixed(record.precisions[name]));
            } else {
              return value;
            }
            break;
          default:
            return value;
        }
      })();
    }
    for (id in columns) {
      column = columns[id];
      if (column.trend_by != null) {
        trending_column = columns[column.trend_by];
        if (trending_column != null) {
          record.trends[column.name] = {
            value: record[trending_column.name],
            self: column === trending_column
          };
        }
      }
    }
    return record;
  };

  render_marketdata_record_value = function(name, record, column) {
    switch (column.type) {
      case 'number':
        return render_marketdata_record_number_value(name, record, column);
      default:
        return record[name];
    }
  };

  render_marketdata_record_number_value = function(name, record, column) {
    var value, value_for_render;

    value = record[name];
    if (value == null) {
      return value;
    }
    value_for_render = number_with_precision(value, {
      precision: record.precisions[name]
    });
    if (!!column.is_signed && value > 0) {
      value_for_render = '+' + value_for_render;
    }
    if (!!column.has_percent) {
      value_for_render = value_for_render + '%';
    }
    return value_for_render;
  };

  $.extend(scope, {
    utils: {
      prepare_marketdata_record: prepare_marketdata_record,
      render_marketdata_record_value: render_marketdata_record_value,
      number_with_delimiter: number_with_delimiter,
      number_with_precision: number_with_precision
    }
  });

}).call(this);
;
(function() {
  var $, handle_chart_tickers_messages, handle_table_tickers_messages, notification_options, root;

  root = this;

  $ = jQuery;

  handle_table_tickers_messages = true;

  handle_chart_tickers_messages = true;

  notification_options = {
    fadeInSpeed: 250,
    fadeOutSpeed: 250,
    removeTimer: 2000
  };

  $(window).on('table:tickers', function(event, memo) {
    var action, notice;
    if (!handle_table_tickers_messages) {
      return;
    }
    action = (function() {
      switch (memo.message) {
        case 'add':
          return 'добавлен в таблицу';
        case 'remove':
          return 'удален из таблицы';
      }
    })();
    notice = ich.notification({
      message: "Инструмент " + memo.ticker + " " + action
    });
    return notice.purr(notification_options);
  });

  $(window).on('chart:tickers', function(event, memo) {
    var message, notice;
    if (!handle_table_tickers_messages) {
      return;
    }
    message = (function() {
      switch (memo.message) {
        case 'add':
          return "Инструмент " + memo.ticker + " добавлен на график";
        case 'remove':
          return "Инструмент " + memo.ticker + " убран с графика";
        case 'too many tickers':
          return "Превышен лимит инструментов на графике — " + memo.count;
        case 'too little tickers':
          return "На графике должен оставаться хотя бы 1 инструмент";
        default:
          return "Неизвестное сообщение";
      }
    })();
    notice = ich.notification({
      message: message
    });
    return notice.purr(notification_options);
  });

}).call(this);
;
(function() {
  var root, scope, widget;

  root = this;

  if (root.shared == null) {
    root.shared = {};
  }

  scope = root.shared;

  widget = function(container) {
    var activate, content, contents, on_activate, self, tab, tabs;
    container = $(container);
    if (container.length === 0) {
      return;
    }
    on_activate = new $.Callbacks;
    self = {};
    if (container) {
      tabs = $('> ul > li', container);
    }
    if (container) {
      contents = $('> div', container);
    }
    tab = function(key) {
      return $(tabs.get().filter(function(t) {
        return $(t).data('key') === key;
      })[0]);
    };
    content = function(key) {
      return $(contents.get().filter(function(c) {
        return $(c).data('key') === key;
      })[0]);
    };
    activate = function(key) {
      var c, t;
      t = tab(key);
      if (t.length === 0) {
        return;
      }
      if (t.hasClass('tab') && !t.hasClass('current')) {
        tabs.not(t).removeClass('current');
        t.addClass('current');
        c = content(key);
        if (c.length === 0) {
          return;
        }
        contents.not(c).hide();
        c.show();
      }
      on_activate.fire(key);
      return self;
    };
    container.on('click', '> ul > li > a', function(event) {
      event.preventDefault();
      return activate($(this).closest('li').data('key'));
    });
    $.extend(self, {
      on_activate: function(callback) {
        return on_activate.add(callback);
      },
      activate: activate,
      tab: tab,
      content: content
    });
    return self;
  };

  $.extend(scope, {
    tabs: widget
  });

}).call(this);
;
(function() {
  var cache, done, fail, fetch, full_name, full_name_or_nickname, links, localized_links, localized_sites, prune, render_links, render_sites, root, scope, sites, t, toggle_sites, url, widget;

  root = this;

  if (root.shared == null) {
    root.shared = {};
  }

  scope = root.shared;

  url = '/cu';

  if ($.support.cors) {
    url = window.moex.passport.baseUrl + url;
  }

  links = ['login', 'registration', 'user'];

  sites = ['passport', 'services', 'logout'];

  localized_links = {
    ru: {
      login: {
        title: 'Вход',
        onclick: 'window.keycloak.login()',
        href: '#'
      },
      registration: {
        title: 'Регистрация',
        href: window.moex.passport.registrationUrl
      },
      user: {
        title: '',
        href: '#'
      }
    },
    en: {
      login: {
        title: 'Login',
        onclick: 'window.keycloak.login()',
        href: '#'
      },
      registration: {
        title: 'Registration',
        href: window.moex.passport.registrationEnUrl
      },
      user: {
        title: '',
        href: '#'
      }
    }
  };

  localized_sites = {
    ru: {
      passport: {
        title: 'Настройки',
        href: window.moex.passport.profileUrl
      },
      services: {
        title: 'Управление платными услугами',
        href: window.moex.baseUrl + window.moex.moexOrders.cultures.ru.productsUrl
      },
      logout: {
        title: 'Выход из системы',
        onclick: 'window.keycloak.logout()',
        href: '#'
      }
    },
    en: {
      passport: {
        title: 'Settings',
        href: window.moex.passport.profileEnUrl
      },
      services: {
        title: 'Paid services management',
        href: window.moex.baseUrl + window.moex.moexOrders.cultures.en.productsUrl
      },
      logout: {
        title: 'Logout',
        onclick: 'window.keycloak.logout()',
        href: '#'
      }
    }
  };

  cache = kizzy('shared:user');

  if (!String.prototype.trimRight) {
    String.prototype.trimRight = function() {
      return this.replace(/\s+$/, '');
    };
  }

  t = function(c) {
    if (c.toUpperCase() !== c.toLowerCase()) {
      return 'A';
    } else {
      return ' ';
    }
  };

  prune = function(string, length, spacer) {
    var template;
    if (string == null) {
      return string;
    }
    length = ~~length;
    if (spacer == null) {
      spacer = '...';
    }
    if (string.length <= length) {
      return string;
    }
    template = string.slice(0, length + 1).replace(/.(?=\W*\w*$)/g, t);
    template = template.slice(template.length - 2).match(/\w\w/) ? template.replace(/\s+\S+$/, '') : template.slice(0, template.length - 1).trimRight();
    if ((template + spacer).length > string.length) {
      return string;
    } else {
      return string.slice(0, template.length) + spacer;
    }
  };

  fetch = function() {
    var deferred, result;
    deferred = new $.Deferred;
    result = {};
    $.ajax({
      url: url,
        dataType: 'json',
        crossDomain: true,
      xhrFields: {
        withCredentials: true
      }
    }).done(function(json) {
      result.data = json;
      return result.error = false;
    }).fail(function(xhr, error) {
      return result.error = true;
    }).always(function() {
      return deferred.resolve(result);
    });
    return deferred.promise({
      result: result
    });
  };

  full_name = function(data) {
    return [data.last_name, data.first_name, data.middle_name].join(' ').trim();
  };

  full_name_or_nickname = function(data) {
    return full_name(data) || data.nickname;
  };

  render_links = function(container) {
    var list;
    list = $('<ul>').addClass('auth_user_links').appendTo(container);
    links.forEach(function(link) {
      var item, link_data;
      item = $('<li>').addClass(link).appendTo(list).hide();
      link_data = localized_links[mx.I18n.locale][link];
      if (link_data.onclick) {
        return $('<a>').attr('href', '#').attr('onclick', link_data.onclick).html(link_data.title).appendTo(item);
      } else {
        return $('<a>').attr('href', link_data.href).html(link_data.title).appendTo(item);
      }
    });
    $('li.user a', list).html(cache.get('name'));
    return list;
  };

  render_sites = function(id, container) {
    var html, list;
    html = $('<div>').attr('id', id).addClass('auth_sites_links').appendTo(container).hide();
    list = $('<ul>').appendTo(html);
    sites.forEach(function(site) {
      var item, site_data;
      item = $('<li>').addClass(site).appendTo(list);
      site_data = localized_sites[mx.I18n.locale][site];
      if (site_data.onclick) {
        return $('<a>').attr('href', '#').attr('onclick', site_data.onclick).html(site_data.title).appendTo(item);
      } else {
        return $('<a>').attr('href', site_data.href).html(site_data.title).appendTo(item);
      }
    });
    return html;
  };

  done = function(user_data, container) {
    cache.set('name', full_name_or_nickname(user_data));
    $('li.user a', container).html(prune(cache.get('name'), 32));
    $('li.login, li.registration', container).hide();
    return $('li.user', container).show();
  };

  fail = function(container) {
    $('li.login, li.registration', container).show();
    return $('li.user', container).hide();
  };

  toggle_sites = function(sites, links) {
    var links_height, links_offset, links_width, sites_height, sites_width;
    if (sites.is(':hidden')) {
      links_offset = links.offset();
      links_width = links.outerWidth();
      links_height = links.outerHeight();
      sites.show();
      sites_width = sites.innerWidth();
      sites_height = sites.outerHeight();
      sites.offset({
        top: links_offset.top + links_height,
        left: links_offset.left + links_width - sites_width
      });
      sites.hide();
    }
    return sites.toggle();
  };

  widget = function(container) {
    var reload;
    container = $(container);
    if (container.length === 0) {
      return;
    }
    links = render_links(container);
    sites = render_sites(container.attr('id') + '_sites_links', $('body'));
    reload = function() {
      var user;
      user = fetch();
      return user.then(function() {
        user = user.result;
        if (user.error) {
          return fail(container);
        } else {
          return done(user.data, container);
        }
      });
    };
    container.on('click', 'li.user a', function(event) {
      event.preventDefault();
      event.stopPropagation();
      return toggle_sites(sites, links);
    });
    $(window).on('click', function() {
      if (sites.is(':visible')) {
        return sites.hide();
      }
    });
    return reload();
  };

  $.extend(scope, {
    user: widget
  });

}).call(this);
;
(function() {
  var $, fetch, root, scope,
    __slice = [].slice;

  root = this;

  scope = root['mx']['iss'];

  $ = jQuery;

  fetch = function() {
    return scope.fetch.apply(scope, ['security_marketdata'].concat(__slice.call(arguments)));
  };

  $.extend(scope, {
    security_marketdata: fetch
  });

  $.extend(scope.fetch_descriptors, {
    security_marketdata: {
      cache_key: function(engine, market, board, id) {
        return "" + engine + ":" + market + ":" + board + ":" + id;
      },
      url: function(engine, market, board, id) {
        return "/engines/" + engine + "/markets/" + market + "/boards/" + board + "/securities/" + id + ".json";
      },
      xhr_data: function() {
        return {
          'iss.only': 'securities,marketdata,dataversion'
        };
      },
      parse: function(json) {
        return {
          security: scope.merge_columns_and_data(json != null ? json.securities : void 0)[0],
          marketdata: scope.merge_columns_and_data(json != null ? json.marketdata : void 0)[0],
          dataversion: scope.merge_columns_and_data(json != null ? json.dataversion : void 0)[0]
        };
      }
    }
  });

}).call(this);
;
(function() {
  var $, fetch, root, scope;

  root = this;

  scope = root['mx']['iss'];

  $ = jQuery;

  fetch = function(ticker) {
    var data, deferred;

    deferred = new $.Deferred;
    data = [];
    scope.url_prefix = window.moex.iss.baseUrl;
    $.ajax({
      url: "" + scope.url_prefix + "/securitygroups.jsonp?callback=?",
      data: {
        'iss.meta': 'off',
        'iss.only': 'securitygroups',
        'lang': window.location.href.indexOf('/ru/') !== -1 ? 'ru' : 'en'
      },
      dataType: 'jsonp'
    }).then(function(json) {
      data.push.apply(data, scope.merge_columns_and_data(json != null ? json.securitygroups : void 0));
      return deferred.resolve(data);
    });
    return deferred.promise({
      data: data
    });
  };

  $.extend(scope, {
    security_groups: fetch
  });

}).call(this);
;
(function() {
  var $, fetch, root, scope;

  root = this;

  scope = root['mx']['iss'];

  $ = jQuery;

  fetch = function(query, options) {
    var data, deferred, xhr;

    if (options == null) {
      options = {};
    }
    deferred = new $.Deferred;
    data = [];
    options.group_by || (options.group_by = '');
    options.is_traded || (options.is_traded = '');
    scope.url_prefix = window.moex.iss.baseUrl;
    xhr = $.ajax({
      url: "" + scope.url_prefix + "/securities.json",
      data: {
        q: query,
        group_by: options.group_by,
        is_trading: options.is_traded,
        'iss.meta': 'off',
        'iss.only': 'securities',
        'lang': window.location.href.indexOf('/ru/') !== -1 ? 'ru' : 'en'
      },
      dataType: 'json'
    }).done(function(json) {
      data.push.apply(data, scope.merge_columns_and_data(json != null ? json.securities : void 0));
      return deferred.resolve(data);
    });
    return deferred.promise({
      data: data,
      xhr: xhr,
      query: query
    });
  };

  $.extend(scope, {
    quote_search: fetch
  });

}).call(this);
;
(function() {
  var $, fetch, root, scope;

  root = this;

  scope = root['mx']['iss'];

  $ = jQuery;

  fetch = function(ticker, options) {
    var data, deferred;

    if (options == null) {
      options = {};
    }
    deferred = new $.Deferred;
    data = [];
    scope.url_prefix = window.moex.iss.baseUrl;
    $.ajax({
      url: "" + scope.url_prefix + "/securities/" + ticker + "/boards.json",
      data: {
        is_trading: options.is_traded ? options.is_traded : '',
        'iss.meta': 'off',
        'iss.only': 'boards'
      },
      dataType: 'json'
    }).then(function(json) {
      data.push.apply(data, scope.merge_columns_and_data(json != null ? json.boards : void 0));
      return deferred.resolve(data);
    });
    return deferred.promise({
      data: data
    });
  };

  $.extend(scope, {
    security_boards: fetch
  });

}).call(this);
;
(function() {
  var $, fetch, root, scope;

  root = this;

  scope = root['mx']['iss'];

  $ = jQuery;

  fetch = function(options) {
    var data, deferred;

    if (options === null || options === undefined) {
      options = {};
    }
    deferred = new $.Deferred;
    data = [];
    $.ajax({
      url: window.moex.iss.baseUrl + "/index.json",
      data: {
        'iss.meta': 'off',
        'iss.only': 'markets',
        lang: options.lang !== undefined ? options.lang : mx.lang,
      },
      dataType: 'json'
    }).then(function(json) {
      data.push.apply(data, scope.merge_columns_and_data(json != null ? json.markets : void 0));
      return deferred.resolve(data);
    });
    return deferred.promise({
      data: data
    });
  };

  $.extend(scope, {
    index_markets: fetch
  });

}).call(this);
;
(function() {
  var $, KEY_ESC, add_or_remove_table_ticker, add_ticker_to_table, calculate_result_view_max_height, clear_search_results, collect_groups, make_filter_view, make_result_view, metadata, metadata_boards_hash, metadata_engines_hash, metadata_markets_hash, populate_metadata_boards_hash, populate_security_groups_hash, query_threshold, remove_ticker_from_table, render_boards, render_date, render_results, root, scope, search_delay, securities_cache, securities_keys, security_groups, security_groups_hash, set_boards_statuses, set_primary_boards, toggle_security_boards, toggle_ticker_in_table, widget;

  root = this;

  scope = root['mx']['data'];

  $ = jQuery;

  security_groups = void 0;

  security_groups_hash = void 0;

  metadata = void 0;

  metadata_engines_hash = void 0;

  metadata_markets_hash = void 0;

  metadata_boards_hash = void 0;
    
  securities_cache = function() {
    return kizzy('data.table');
  };

  KEY_ESC = 27;

  search_delay = 250;

  query_threshold = 3;

  widject_options = { lang: window.location.href.indexOf('/ru/') !== -1 ? 'ru' : 'en' };

  securities_keys = function() {
    return _.map(metadata.markets(), function(market) {
      return "" + market.engine.name + ":" + market.name + ":securities";
    });
  };

  render_date = function(string) {
    var date, f;

    date = new Date(Date.parse(string));
    f = function(n) {
      if (n < 10) {
        return "0" + n;
      } else {
        return n;
      }
    };
    return "" + (f(date.getDate())) + "." + (f(date.getMonth() + 1)) + "." + (date.getFullYear());
  };

  populate_security_groups_hash = function() {
    return security_groups_hash = _.reduce(security_groups.data, function(memo, item) {
      memo[item.name] = item;
      return memo;
    }, {});
  };

  populate_metadata_boards_hash = function() {
    return metadata_boards_hash = _.reduce(metadata.boards, function(memo, item) {
      memo[item.boardid] = item;
      return memo;
    }, {});
  };

  make_filter_view = function(container) {
    var view;

    view = $('<div>').addClass('filter');
    return view.appendTo(container);
  };

  make_result_view = function(container) {
    var view;

    view = $('<ul>').addClass('results').appendTo(container);
    calculate_result_view_max_height(view);
    return view;
  };

  calculate_result_view_max_height = function(view) {
    return view.css('max-height', $(window).height() - view.offset().top - 20);
  };

  clear_search_results = function(container) {
    return container.empty();
  };

  collect_groups = function(data) {
      return _.reduce(_.uniqBy(_.map(data, function (record) {
      return record.group;
    })), function(memo, id) {
      var _ref;

      memo.push({
        id: id,
        title: (_ref = security_groups_hash[id]) != null ? _ref.title : void 0
      });
      return memo;
    }, []);
  };

  render_results = function(container, data, options) {
    var groups;
    var notShowGroups = ["eurobond"];//["stock_qnv", "stock_gcc", "basket"];
    if (options && options.lang)
        widject_options.lang = options.lang;
    
    clear_search_results(container);

    //Эти не показываем, фильтруем
    var filterSecIds = ["RTSUSDCUR", "SRATE_USD_1M", "SRATE_USD_1W", "SRATE_USD_1Y", "SRATE_USD_2M", "SRATE_USD_2W", "SRATE_USD_3M","SRATE_USD_6M", "SRATE_USD_9M","SRATE_USD_ON"];
    data = _.filter(data, function(record)
    {
        return !_.includes(filterSecIds, record.secid) && !_.includes(notShowGroups, record.group);
    });

    groups = collect_groups(data);
    _.each(groups, function(group) {


    group.records = _.filter(data, function(record) {
        return record.group === group.id;
    });

    _.each(data, function (record) {

        var boardId = record.marketprice_boardid != null ? record.marketprice_boardid : record.primary_boardid;

        record.has_other = !_.includes(["MXBD", "RFUD", "RTSI", "BKT", "FOB"], boardId);
        record.boards = [];
        var notShowGroups = ["stock_qnv", "stock_gcc", "basket"];
        if (_.includes(notShowGroups, record.group))
            return record.boards;

        var board = metadata.board(boardId);
        var cur = {};

        record.link = cur.link = get_record_link(record.group, record.secid, boardId);
        var t = $.extend(cur,board);
        return record.boards.push(t);
    });
         
    });
    container.show();
    container.append(ich.query_search_results({
      groups: groups
    }));
    set_primary_boards(container);
    return set_boards_statuses(container);
  };
  
  var _lang = window.location.href.indexOf('/ru/') !== -1 ? 'ru' : 'en';

  get_record_link = function (group, secid, board) {
      switch (group) {
          case "currency_selt":
          case "currency_metal":{
              return "/" + _lang + "/issue/" + secid + "/" + board;
          }
          case "futures_forts":
          case "futures_options":
          case "commodity_futures": {
              return "/" + _lang + "/contract.aspx?code=" + secid;
          }
          case "stock_shares":
          case "stock_bonds":
          case "stock_dr":
          case "eurobond":
          case "stock_ppif":
          case "stock_etf":{
              return "/" + _lang + "/issue.aspx?board=" + board + "&code=" + secid;
          }
          case "stock_index":
              return "/" + _lang + "/index/" + secid;
          default:
              return "";
      }
  }
  render_boards = function(container, data) {
    var boards;
    var group = container.parents('.security').siblings('.group').data('id');
    boards = _.chain(data).reject(function(board) {
      return !board.is_traded;
    }).map(function (board) {
        var current = metadata.board(board.boardid);
        if (current && current != null) {
            current.link = get_record_link(group, board.secid, board.boardid);
        }
        return current;
    }).value();
    container.append(ich.query_search_results_boards({
      boards: boards
    }));
    return set_boards_statuses(container);
  };

  set_primary_boards = function(container) {
    return _.each($('li.security', container), function(security) {
      security = $(security);
      return _.each($('li.board', security), function(board) {
        board = $(board);
        if (board.data('id') === security.data('primary-board-id')) {
          return board.addClass('primary');
        }
      });
    });
  };

  set_boards_statuses = function(container) {
    var caches;

    caches = _.chain(securities_keys()).map(function(key) {
      return securities_cache().get(key);
    }).compact().flatten().value();
    return _.each($('li.board', container), function(board) {
      var security;

      board = $(board);
      security = board.closest('li.security');
      return board.toggleClass('active', _.includes(caches, [board.data('id'), security.data('id')].join(':')));
    });
  };

  toggle_security_boards = function (element) {
    if (element.data('boards-loaded') === true) {
      return element.toggleClass('primary');
    } else {
      if (element.data('boards-loaded') != null) {
        return;
      }
      element.data('boards-loaded', false);
      return mx.iss.security_boards(element.data('id')).done(function (data) {
          render_boards($('ul.boards', element), _.reject(data, function (board) {
          return board.boardid === element.data('primary-board-id');
        }));
        element.data('boards-loaded', true);
        return toggle_security_boards(element);
      });
    }
  };

  toggle_ticker_in_table = function(element) {
    var board_id, security_id;

    board_id = element.data('id');
    security_id = element.closest('li.security').data('id');
    if (element.hasClass('active')) {
      return remove_ticker_from_table(board_id, security_id);
    } else {
      return add_ticker_to_table(board_id, security_id);
    }
  };

  add_ticker_to_table = function(board_id, security_id) {
    return add_or_remove_table_ticker("add", board_id, security_id);
  };

  remove_ticker_from_table = function(board_id, security_id) {
    return add_or_remove_table_ticker("remove", board_id, security_id);
  };

  add_or_remove_table_ticker = function(method, board_id, security_id) {
    var board;

    board = metadata.board(board_id);
    return $(window).trigger("global:table:security:" + method + ":" + board.engine.name + ":" + board.market.name, {
      ticker: "" + board_id + ":" + security_id
    });
  };

  widget = function(container, options) {
    var close_button, filter_markets, filter_view, observe_query_input, observe_window_keyboard_events, performed_query, performed_search, query_input_view, ready, result_view, search, search_timeout;

    if (options == null) {
      options = {};
    }
    container = $(container);
    if (container.length === 0) {
      return;
    }
    query_input_view = void 0;
    filter_view = void 0;
    result_view = void 0;
    close_button = $('td.clear', container);
    search_timeout = void 0;
    performed_query = void 0;
    performed_search = void 0;
    if (metadata == null) {
      metadata = mx.data.metadata();
    }
    if (security_groups == null) {
      security_groups = mx.iss.security_groups();
    }
    filter_markets = scope.quote_search_filter_markets();
    ready = $.when(metadata, security_groups, filter_markets);
    search = function(query) {
      performed_query = query;
      performed_search = mx.iss.quote_search(performed_query, {
        group_by: 'group',
        is_traded: 1
      });
      return performed_search.done(function() {
        if (query === performed_search.query) {
          return render_results(result_view, performed_search.data,options);
        }
      });
    };
    observe_window_keyboard_events = function(event) {
      switch (event.keyCode) {
        case KEY_ESC:
          if (query_input_view.is(':focus')) {
            return query_input_view.blur();
          } else {
            return query_input_view.select();
          }
      }
    };
    observe_query_input = function() {
      var query;

      query = $.trim(query_input_view.val());
      clearTimeout(search_timeout);
      close_button.toggle(query.length > 0);
      if (query.length < query_threshold) {
          result_view.hide()
        clear_search_results(result_view);
        performed_query = void 0;
        return;
      }
      if (performed_query === query) {

      } else {
        return search_timeout = _.delay(search, search_delay, query);
      }
    };
    return ready.then(function() {
      populate_security_groups_hash();
      populate_metadata_boards_hash();
      query_input_view = $('input[type=text]', container);
      filter_view = make_filter_view(container);
      result_view = make_result_view(container);
      filter_view.append(filter_markets.view());
      result_view.hide();

      $(window).on('keyup', observe_window_keyboard_events);
      $(window).on('resize', function() {
        return calculate_result_view_max_height(result_view);
      });
      query_input_view.on('keyup', observe_query_input);
      close_button.on('click', function() {
        query_input_view.val('');
        return observe_query_input();
      });
      result_view.on('click', 'li.security > p.links a', function(event) {
        event.preventDefault();
        return toggle_security_boards($(this).closest('li.security'));
      });
      //result_view.on('click', 'li.board a', function(event) {
      //  event.preventDefault();
      //  return toggle_ticker_in_table($(this).closest('li.board'));
      //});
      return $(window).on('global:table:security:added global:table:security:removed', function() {
        return _.defer(set_boards_statuses, result_view);
      });
    });
  };

  $.extend(scope, {
    quote_search: widget
  });

}).call(this);
;
(function() {
  var $, cache, make_market_view, make_view, metadata, root, scope, widget;

  root = this;

  scope = root['mx']['data'];

  $ = jQuery;

  metadata = void 0;

  cache = kizzy('data.quote_search.filter_markets');

  make_view = function(values) {
    var view;

    view = $('<ul>').addClass('markets clearfix');
    _.each(metadata.markets, function(market) {
      return make_market_view(market, view, values);
    });
    return view;
  };

  make_market_view = function(market, container, values) {
    var checkbox, key, label, view;

    view = $('<li>');
    label = $('<label>').html(market.market_title);
    key = [market.trade_engine_name, market.market_name].join(':');
    checkbox = $('<input>').attr('type', 'checkbox').attr('checked', _.isEmpty(values) || _.includes(values, key)).val(key).prependTo(label);
    return view.append(label).appendTo(container);
  };

  widget = function() {
    var cache_key, check_markets_margins, deferred, ready, update, update_filter_markets_cache, view;

    deferred = new $.Deferred;
    cache_key = '';
    view = void 0;
    if (metadata == null) {
      metadata = mx.iss.metadata();
    }
    ready = $.when(metadata);
    update = function(values) {
      return cache.set(cache_key, values);
    };
    update_filter_markets_cache = function() {
      update(_.map($('input:checked', view), function(checkbox) {
        return $(checkbox).val();
      }));
      return check_markets_margins();
    };
    check_markets_margins = function() {
      var checked_markets;

      checked_markets = $('input:checked', view);
      if (checked_markets.length === 1) {
        return checked_markets.attr('disabled', true);
      } else {
        return checked_markets.attr('disabled', false);
      }
    };
    ready.then(function() {
      view = make_view(cache.get(cache_key) || []);
      check_markets_margins();
      view.on('change', 'input', update_filter_markets_cache);
      return deferred.resolve();
    });
    return deferred.promise({
      view: function() {
        return view;
      },
      values: function() {
        return cache.get(cache_key);
      }
    });
  };

  $.extend(scope, {
    quote_search_filter_markets: widget
  });

}).call(this);
;
