diff --git a/dist/frappe-charts.min.js b/dist/frappe-charts.min.js index de860e4..77e7987 100644 --- a/dist/frappe-charts.min.js +++ b/dist/frappe-charts.min.js @@ -1,2775 +1,2 @@ -var Chart = (function () { -'use strict'; - -var asyncGenerator = function () { - function AwaitValue(value) { - this.value = value; - } - - function AsyncGenerator(gen) { - var front, back; - - function send(key, arg) { - return new Promise(function (resolve, reject) { - var request = { - key: key, - arg: arg, - resolve: resolve, - reject: reject, - next: null - }; - - if (back) { - back = back.next = request; - } else { - front = back = request; - resume(key, arg); - } - }); - } - - function resume(key, arg) { - try { - var result = gen[key](arg); - var value = result.value; - - if (value instanceof AwaitValue) { - Promise.resolve(value.value).then(function (arg) { - resume("next", arg); - }, function (arg) { - resume("throw", arg); - }); - } else { - settle(result.done ? "return" : "normal", result.value); - } - } catch (err) { - settle("throw", err); - } - } - - function settle(type, value) { - switch (type) { - case "return": - front.resolve({ - value: value, - done: true - }); - break; - - case "throw": - front.reject(value); - break; - - default: - front.resolve({ - value: value, - done: false - }); - break; - } - - front = front.next; - - if (front) { - resume(front.key, front.arg); - } else { - back = null; - } - } - - this._invoke = send; - - if (typeof gen.return !== "function") { - this.return = undefined; - } - } - - if (typeof Symbol === "function" && Symbol.asyncIterator) { - AsyncGenerator.prototype[Symbol.asyncIterator] = function () { - return this; - }; - } - - AsyncGenerator.prototype.next = function (arg) { - return this._invoke("next", arg); - }; - - AsyncGenerator.prototype.throw = function (arg) { - return this._invoke("throw", arg); - }; - - AsyncGenerator.prototype.return = function (arg) { - return this._invoke("return", arg); - }; - - return { - wrap: function (fn) { - return function () { - return new AsyncGenerator(fn.apply(this, arguments)); - }; - }, - await: function (value) { - return new AwaitValue(value); - } - }; -}(); - - - - - -var classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -}; - -var createClass = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -}(); - - - - - - - -var get = function get(object, property, receiver) { - if (object === null) object = Function.prototype; - var desc = Object.getOwnPropertyDescriptor(object, property); - - if (desc === undefined) { - var parent = Object.getPrototypeOf(object); - - if (parent === null) { - return undefined; - } else { - return get(parent, property, receiver); - } - } else if ("value" in desc) { - return desc.value; - } else { - var getter = desc.get; - - if (getter === undefined) { - return undefined; - } - - return getter.call(receiver); - } -}; - -var inherits = function (subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - } - - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: false, - writable: true, - configurable: true - } - }); - if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; -}; - - - - - - - - - - - -var possibleConstructorReturn = function (self, call) { - if (!self) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - - return call && (typeof call === "object" || typeof call === "function") ? call : self; -}; - - - - - -var slicedToArray = function () { - function sliceIterator(arr, i) { - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"]) _i["return"](); - } finally { - if (_d) throw _e; - } - } - - return _arr; - } - - return function (arr, i) { - if (Array.isArray(arr)) { - return arr; - } else if (Symbol.iterator in Object(arr)) { - return sliceIterator(arr, i); - } else { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - }; -}(); - - - - - - - - - - - - - -var toConsumableArray = function (arr) { - if (Array.isArray(arr)) { - for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - - return arr2; - } else { - return Array.from(arr); - } -}; - -function $(expr, con) { - return typeof expr === "string" ? (con || document).querySelector(expr) : expr || null; -} - -$.findNodeIndex = function (node) { - var i = 0; - while (node.previousSibling) { - node = node.previousSibling; - i++; - } - return i; -}; - -$.create = function (tag, o) { - var element = document.createElement(tag); - - for (var i in o) { - var val = o[i]; - - if (i === "inside") { - $(val).appendChild(element); - } else if (i === "around") { - var ref = $(val); - ref.parentNode.insertBefore(element, ref); - element.appendChild(ref); - } else if (i in element) { - element[i] = val; - } else { - element.setAttribute(i, val); - } - } - - return element; -}; - -$.createSVG = function (tag, o) { - var element = document.createElementNS("http://www.w3.org/2000/svg", tag); - - for (var i in o) { - var val = o[i]; - - if (i === "inside") { - $(val).appendChild(element); - } else if (i === "around") { - var ref = $(val); - ref.parentNode.insertBefore(element, ref); - element.appendChild(ref); - } else { - if (i === "className") { - i = "class"; - } - if (i === "innerHTML") { - element['textContent'] = val; - } else { - element.setAttribute(i, val); - } - } - } - - return element; -}; - -$.runSVGAnimation = function (svg_container, elements) { - // let parent = elements[0][0]['unit'].parentNode; - - var new_elements = []; - var anim_elements = []; - - elements.map(function (element) { - var obj = element[0]; - var parent = obj.unit.parentNode; - // let index = let findNodeIndex(obj.unit); - - var anim_element = void 0, - new_element = void 0; - - element[0] = obj.unit; - - var _$$animateSVG = $.animateSVG.apply($, toConsumableArray(element)); - - var _$$animateSVG2 = slicedToArray(_$$animateSVG, 2); - - anim_element = _$$animateSVG2[0]; - new_element = _$$animateSVG2[1]; - - - new_elements.push(new_element); - anim_elements.push([anim_element, parent]); - - parent.replaceChild(anim_element, obj.unit); - - if (obj.array) { - obj.array[obj.index] = new_element; - } else { - obj.object[obj.key] = new_element; - } - }); - - var anim_svg = svg_container.cloneNode(true); - - anim_elements.map(function (anim_element, i) { - anim_element[1].replaceChild(new_elements[i], anim_element[0]); - elements[i][0] = new_elements[i]; - }); - - return anim_svg; -}; - -$.animateSVG = function (element, props, dur) { - var easing_type = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "linear"; - var type = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : undefined; - var old_values = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {}; - - var easing = { - ease: "0.25 0.1 0.25 1", - linear: "0 0 1 1", - // easein: "0.42 0 1 1", - easein: "0.1 0.8 0.2 1", - easeout: "0 0 0.58 1", - easeinout: "0.42 0 0.58 1" - }; - - var anim_element = element.cloneNode(true); - var new_element = element.cloneNode(true); - - for (var attributeName in props) { - var animate_element = void 0; - if (attributeName === 'transform') { - animate_element = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform"); - } else { - animate_element = document.createElementNS("http://www.w3.org/2000/svg", "animate"); - } - var current_value = old_values[attributeName] || element.getAttribute(attributeName); - var value = props[attributeName]; - - var anim_attr = { - attributeName: attributeName, - from: current_value, - to: value, - begin: "0s", - dur: dur / 1000 + "s", - values: current_value + ";" + value, - keySplines: easing[easing_type], - keyTimes: "0;1", - calcMode: "spline", - fill: 'freeze' - }; - - if (type) { - anim_attr["type"] = type; - } - - for (var i in anim_attr) { - animate_element.setAttribute(i, anim_attr[i]); - } - - anim_element.appendChild(animate_element); - - if (type) { - new_element.setAttribute(attributeName, "translate(" + value + ")"); - } else { - new_element.setAttribute(attributeName, value); - } - } - - return [anim_element, new_element]; -}; - -$.offset = function (element) { - var rect = element.getBoundingClientRect(); - return { - // https://stackoverflow.com/a/7436602/6495043 - // rect.top varies with scroll, so we add whatever has been - // scrolled to it to get absolute distance from actual page top - top: rect.top + (document.documentElement.scrollTop || document.body.scrollTop), - left: rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft) - }; -}; - -$.isElementInViewport = function (el) { - // Although straightforward: https://stackoverflow.com/a/7557433/6495043 - var rect = el.getBoundingClientRect(); - - return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */ - rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */ - ; -}; - -$.bind = function (element, o) { - if (element) { - for (var event in o) { - var callback = o[event]; - - event.split(/\s+/).forEach(function (event) { - element.addEventListener(event, callback); - }); - } - } -}; - -$.unbind = function (element, o) { - if (element) { - for (var event in o) { - var callback = o[event]; - - event.split(/\s+/).forEach(function (event) { - element.removeEventListener(event, callback); - }); - } - } -}; - -$.fire = function (target, type, properties) { - var evt = document.createEvent("HTMLEvents"); - - evt.initEvent(type, true, true); - - for (var j in properties) { - evt[j] = properties[j]; - } - - return target.dispatchEvent(evt); -}; - -function float_2(d) { - return parseFloat(d.toFixed(2)); -} - -function arrays_equal(arr1, arr2) { - if (arr1.length !== arr2.length) return false; - var are_equal = true; - arr1.map(function (d, i) { - if (arr2[i] !== d) are_equal = false; - }); - return are_equal; -} - -var Chart = function () { - function Chart(_ref) { - var _ref$parent = _ref.parent, - parent = _ref$parent === undefined ? "" : _ref$parent, - _ref$height = _ref.height, - height = _ref$height === undefined ? 240 : _ref$height, - _ref$title = _ref.title, - title = _ref$title === undefined ? '' : _ref$title, - _ref$subtitle = _ref.subtitle, - subtitle = _ref$subtitle === undefined ? '' : _ref$subtitle, - _ref$data = _ref.data, - data = _ref$data === undefined ? {} : _ref$data, - _ref$format_lambdas = _ref.format_lambdas, - format_lambdas = _ref$format_lambdas === undefined ? {} : _ref$format_lambdas, - _ref$summary = _ref.summary, - summary = _ref$summary === undefined ? [] : _ref$summary, - _ref$is_navigable = _ref.is_navigable, - is_navigable = _ref$is_navigable === undefined ? 0 : _ref$is_navigable, - _ref$type = _ref.type, - type = _ref$type === undefined ? '' : _ref$type; - classCallCheck(this, Chart); - - if (Object.getPrototypeOf(this) === Chart.prototype) { - if (type === 'line') { - return new LineChart(arguments[0]); - } else if (type === 'bar') { - return new BarChart(arguments[0]); - } else if (type === 'percentage') { - return new PercentageChart(arguments[0]); - } else if (type === 'heatmap') { - return new HeatMap(arguments[0]); - } else { - return new LineChart(arguments[0]); - } - } - - this.raw_chart_args = arguments[0]; - - this.parent = document.querySelector(parent); - this.title = title; - this.subtitle = subtitle; - - this.data = data; - this.format_lambdas = format_lambdas; - - this.specific_values = data.specific_values || []; - this.summary = summary; - - this.is_navigable = is_navigable; - if (this.is_navigable) { - this.current_index = 0; - } - - this.chart_types = ['line', 'bar', 'percentage', 'heatmap']; - - this.set_margins(height); - } - - createClass(Chart, [{ - key: 'get_different_chart', - value: function get_different_chart(type) { - if (!this.chart_types.includes(type)) { - console.error('\'' + type + '\' is not a valid chart type.'); - } - if (type === this.type) return; - - // Only across compatible types - var compatible_types = { - bar: ['line', 'percentage'], - line: ['bar', 'percentage'], - percentage: ['bar', 'line'], - heatmap: [] - }; - - if (!compatible_types[this.type].includes(type)) { - console.error('\'' + this.type + '\' chart cannot be converted to a \'' + type + '\' chart.'); - } - - // Okay, this is anticlimactic - // this function will need to actually be 'change_chart_type(type)' - // that will update only the required elements, but for now ... - return new Chart({ - parent: this.raw_chart_args.parent, - data: this.raw_chart_args.data, - type: type, - height: this.raw_chart_args.height - }); - } - }, { - key: 'set_margins', - value: function set_margins(height) { - this.base_height = height; - this.height = height - 40; - this.translate_x = 60; - this.translate_y = 10; - } - }, { - key: 'setup', - value: function setup() { - this.bind_window_events(); - this.refresh(true); - } - }, { - key: 'bind_window_events', - value: function bind_window_events() { - var _this = this; - - window.addEventListener('resize', function () { - return _this.refresh(); - }); - window.addEventListener('orientationchange', function () { - return _this.refresh(); - }); - } - }, { - key: 'refresh', - value: function refresh() { - var init = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; - - this.setup_base_values(); - this.set_width(); - - this.setup_container(); - this.setup_components(); - - this.setup_values(); - this.setup_utils(); - - this.make_graph_components(init); - this.make_tooltip(); - - if (this.summary.length > 0) { - this.show_custom_summary(); - } else { - this.show_summary(); - } - - if (this.is_navigable) { - this.setup_navigation(init); - } - } - }, { - key: 'set_width', - value: function set_width() { - var _this2 = this; - - var special_values_width = 0; - this.specific_values.map(function (val) { - if (_this2.get_strwidth(val.title) > special_values_width) { - special_values_width = _this2.get_strwidth(val.title) - 40; - } - }); - this.base_width = this.parent.offsetWidth - special_values_width; - this.width = this.base_width - this.translate_x * 2; - } - }, { - key: 'setup_base_values', - value: function setup_base_values() {} - }, { - key: 'setup_container', - value: function setup_container() { - this.container = $.create('div', { - className: 'chart-container', - innerHTML: '
' + this.title + '
\n\t\t\t\t
' + this.subtitle + '
\n\t\t\t\t
\n\t\t\t\t
' - }); - - // Chart needs a dedicated parent element - this.parent.innerHTML = ''; - this.parent.appendChild(this.container); - - this.chart_wrapper = this.container.querySelector('.frappe-chart'); - this.stats_wrapper = this.container.querySelector('.graph-stats-container'); - - this.make_chart_area(); - this.make_draw_area(); - } - }, { - key: 'make_chart_area', - value: function make_chart_area() { - this.svg = $.createSVG('svg', { - className: 'chart', - inside: this.chart_wrapper, - width: this.base_width, - height: this.base_height - }); - - this.svg_defs = $.createSVG('defs', { - inside: this.svg - }); - - return this.svg; - } - }, { - key: 'make_draw_area', - value: function make_draw_area() { - this.draw_area = $.createSVG("g", { - className: this.type + '-chart', - inside: this.svg, - transform: 'translate(' + this.translate_x + ', ' + this.translate_y + ')' - }); - } - }, { - key: 'setup_components', - value: function setup_components() {} - }, { - key: 'make_tooltip', - value: function make_tooltip() { - this.tip = new SvgTip({ - parent: this.chart_wrapper - }); - this.bind_tooltip(); - } - }, { - key: 'show_summary', - value: function show_summary() {} - }, { - key: 'show_custom_summary', - value: function show_custom_summary() { - var _this3 = this; - - this.summary.map(function (d) { - var stats = $.create('div', { - className: 'stats', - innerHTML: '' + d.title + ': ' + d.value + '' - }); - _this3.stats_wrapper.appendChild(stats); - }); - } - }, { - key: 'setup_navigation', - value: function setup_navigation() { - var _this4 = this; - - var init = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; - - this.make_overlay(); - - if (init) { - this.bind_overlay(); - - document.addEventListener('keydown', function (e) { - if ($.isElementInViewport(_this4.chart_wrapper)) { - e = e || window.event; - - if (e.keyCode == '37') { - _this4.on_left_arrow(); - } else if (e.keyCode == '39') { - _this4.on_right_arrow(); - } else if (e.keyCode == '38') { - _this4.on_up_arrow(); - } else if (e.keyCode == '40') { - _this4.on_down_arrow(); - } else if (e.keyCode == '13') { - _this4.on_enter_key(); - } - } - }); - } - } - }, { - key: 'make_overlay', - value: function make_overlay() {} - }, { - key: 'bind_overlay', - value: function bind_overlay() {} - }, { - key: 'on_left_arrow', - value: function on_left_arrow() {} - }, { - key: 'on_right_arrow', - value: function on_right_arrow() {} - }, { - key: 'on_up_arrow', - value: function on_up_arrow() {} - }, { - key: 'on_down_arrow', - value: function on_down_arrow() {} - }, { - key: 'on_enter_key', - value: function on_enter_key() {} - }, { - key: 'get_data_point', - value: function get_data_point() { - var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.current_index; - - // check for length - var data_point = { - index: index - }; - var y = this.y[0]; - ['svg_units', 'y_tops', 'values'].map(function (key) { - var data_key = key.slice(0, key.length - 1); - data_point[data_key] = y[key][index]; - }); - data_point.label = this.x[index]; - return data_point; - } - }, { - key: 'update_current_data_point', - value: function update_current_data_point(index) { - if (index < 0) index = 0; - if (index >= this.x.length) index = this.x.length - 1; - if (index === this.current_index) return; - this.current_index = index; - $.fire(this.parent, "data-select", this.get_data_point()); - } - - // Helpers - - }, { - key: 'get_strwidth', - value: function get_strwidth(string) { - return string.length * 8; - } - - // Objects - - }, { - key: 'setup_utils', - value: function setup_utils() {} - }]); - return Chart; -}(); - -var AxisChart = function (_Chart) { - inherits(AxisChart, _Chart); - - function AxisChart(args) { - classCallCheck(this, AxisChart); - - var _this5 = possibleConstructorReturn(this, (AxisChart.__proto__ || Object.getPrototypeOf(AxisChart)).call(this, args)); - - _this5.x = _this5.data.labels; - _this5.y = _this5.data.datasets; - - _this5.get_y_label = _this5.format_lambdas.y_label; - _this5.get_y_tooltip = _this5.format_lambdas.y_tooltip; - _this5.get_x_tooltip = _this5.format_lambdas.x_tooltip; - - _this5.colors = ['green', 'blue', 'violet', 'red', 'orange', 'yellow', 'light-blue', 'light-green', 'purple', 'magenta']; - - _this5.zero_line = _this5.height; - return _this5; - } - - createClass(AxisChart, [{ - key: 'setup_values', - value: function setup_values() { - this.data.datasets.map(function (d) { - d.values = d.values.map(function (val) { - return !isNaN(val) ? val : 0; - }); - }); - this.setup_x(); - this.setup_y(); - } - }, { - key: 'setup_x', - value: function setup_x() { - var _this6 = this; - - this.set_avg_unit_width_and_x_offset(); - - if (this.x_axis_positions) { - this.x_old_axis_positions = this.x_axis_positions.slice(); - } - this.x_axis_positions = this.x.map(function (d, i) { - return float_2(_this6.x_offset + i * _this6.avg_unit_width); - }); - - if (!this.x_old_axis_positions) { - this.x_old_axis_positions = this.x_axis_positions.slice(); - } - } - }, { - key: 'setup_y', - value: function setup_y() { - if (this.y_axis_values) { - this.y_old_axis_values = this.y_axis_values.slice(); - } - - var values = this.get_all_y_values(); - - if (this.y_sums && this.y_sums.length > 0) { - values = values.concat(this.y_sums); - } - - this.y_axis_values = this.get_y_axis_points(values); - - if (!this.y_old_axis_values) { - this.y_old_axis_values = this.y_axis_values.slice(); - } - - var y_pts = this.y_axis_values; - var value_range = y_pts[y_pts.length - 1] - y_pts[0]; - - if (this.multiplier) this.old_multiplier = this.multiplier; - this.multiplier = this.height / value_range; - if (!this.old_multiplier) this.old_multiplier = this.multiplier; - - var zero_index = y_pts.indexOf(0); - var interval = y_pts[1] - y_pts[0]; - var interval_height = interval * this.multiplier; - - if (this.zero_line) this.old_zero_line = this.zero_line; - this.zero_line = this.height - zero_index * interval_height; - if (!this.old_zero_line) this.old_zero_line = this.zero_line; - } - }, { - key: 'setup_components', - value: function setup_components() { - get(AxisChart.prototype.__proto__ || Object.getPrototypeOf(AxisChart.prototype), 'setup_components', this).call(this); - this.setup_marker_components(); - this.setup_aggregation_components(); - this.setup_graph_components(); - } - }, { - key: 'setup_marker_components', - value: function setup_marker_components() { - this.y_axis_group = $.createSVG('g', { className: 'y axis', inside: this.draw_area }); - this.x_axis_group = $.createSVG('g', { className: 'x axis', inside: this.draw_area }); - this.specific_y_group = $.createSVG('g', { className: 'specific axis', inside: this.draw_area }); - } - }, { - key: 'setup_aggregation_components', - value: function setup_aggregation_components() { - this.sum_group = $.createSVG('g', { className: 'data-points', inside: this.draw_area }); - this.average_group = $.createSVG('g', { className: 'chart-area', inside: this.draw_area }); - } - }, { - key: 'setup_graph_components', - value: function setup_graph_components() { - var _this7 = this; - - this.svg_units_groups = []; - this.y.map(function (d, i) { - _this7.svg_units_groups[i] = $.createSVG('g', { - className: 'data-points data-points-' + i, - inside: _this7.draw_area - }); - }); - } - }, { - key: 'make_graph_components', - value: function make_graph_components() { - var init = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; - - this.make_y_axis(); - this.make_x_axis(); - this.draw_graph(init); - this.make_y_specifics(); - } - - // make VERTICAL lines for x values - - }, { - key: 'make_x_axis', - value: function make_x_axis() { - var _this8 = this; - - var animate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; - - var start_at = void 0, - height = void 0, - text_start_at = void 0, - axis_line_class = ''; - if (this.x_axis_mode === 'span') { - // long spanning lines - start_at = -7; - height = this.height + 15; - text_start_at = this.height + 25; - } else if (this.x_axis_mode === 'tick') { - // short label lines - start_at = this.height; - height = 6; - text_start_at = 9; - axis_line_class = 'x-axis-label'; - } - - this.x_axis_group.setAttribute('transform', 'translate(0,' + start_at + ')'); - - if (animate) { - this.make_anim_x_axis(height, text_start_at, axis_line_class); - return; - } - - this.x_axis_group.textContent = ''; - this.x.map(function (point, i) { - _this8.x_axis_group.appendChild(_this8.make_x_line(height, text_start_at, point, 'x-value-text', axis_line_class, _this8.x_axis_positions[i])); - }); - } - - // make HORIZONTAL lines for y values - - }, { - key: 'make_y_axis', - value: function make_y_axis() { - var _this9 = this; - - var animate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; - - if (animate) { - this.make_anim_y_axis(); - this.make_anim_y_specifics(); - return; - } - - var _get_y_axis_line_prop = this.get_y_axis_line_props(), - _get_y_axis_line_prop2 = slicedToArray(_get_y_axis_line_prop, 4), - width = _get_y_axis_line_prop2[0], - text_end_at = _get_y_axis_line_prop2[1], - axis_line_class = _get_y_axis_line_prop2[2], - start_at = _get_y_axis_line_prop2[3]; - - this.y_axis_group.textContent = ''; - this.y_axis_values.map(function (value, i) { - _this9.y_axis_group.appendChild(_this9.make_y_line(start_at, width, text_end_at, value, 'y-value-text', axis_line_class, _this9.zero_line - value * _this9.multiplier, value === 0 && i !== 0 // Non-first Zero line - )); - }); - } - }, { - key: 'get_y_axis_line_props', - value: function get_y_axis_line_props() { - var specific = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; - - if (specific) { - return [this.width, this.width + 5, 'specific-value', 0]; - } - var width = void 0, - text_end_at = -9, - axis_line_class = '', - start_at = 0; - if (this.y_axis_mode === 'span') { - // long spanning lines - width = this.width + 6; - start_at = -6; - } else if (this.y_axis_mode === 'tick') { - // short label lines - width = -6; - axis_line_class = 'y-axis-label'; - } - - return [width, text_end_at, axis_line_class, start_at]; - } - }, { - key: 'draw_graph', - value: function draw_graph() { - var _this10 = this; - - var init = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; - - if (init) { - this.draw_new_graph_and_animate(); - return; - } - this.y.map(function (d, i) { - d.svg_units = []; - _this10.make_path && _this10.make_path(d, i, _this10.x_axis_positions, d.y_tops, d.color || _this10.colors[i]); - _this10.make_new_units(d, i); - }); - } - }, { - key: 'draw_new_graph_and_animate', - value: function draw_new_graph_and_animate() { - var _this11 = this; - - var data = []; - this.y.map(function (d, i) { - // Anim: Don't draw initial values, store them and update later - d.y_tops = new Array(d.values.length).fill(_this11.zero_line); // no value - data.push({ values: d.values }); - d.svg_units = []; - - _this11.make_path && _this11.make_path(d, i, _this11.x_axis_positions, d.y_tops, d.color || _this11.colors[i]); - _this11.make_new_units(d, i); - }); - - setTimeout(function () { - _this11.update_values(data); - }, 350); - } - }, { - key: 'setup_navigation', - value: function setup_navigation(init) { - var _this12 = this; - - // Hack: defer nav till initial update_values - setTimeout(function () { - get(AxisChart.prototype.__proto__ || Object.getPrototypeOf(AxisChart.prototype), 'setup_navigation', _this12).call(_this12, init); - }, 500); - } - }, { - key: 'make_new_units', - value: function make_new_units(d, i) { - this.make_new_units_for_dataset(this.x_axis_positions, d.y_tops, d.color || this.colors[i], i, this.y.length); - } - }, { - key: 'make_new_units_for_dataset', - value: function make_new_units_for_dataset(x_values, y_values, color, dataset_index, no_of_datasets, group, array, unit) { - var _this13 = this; - - if (!group) group = this.svg_units_groups[dataset_index]; - if (!array) array = this.y[dataset_index].svg_units; - if (!unit) unit = this.unit_args; - - group.textContent = ''; - array.length = 0; - - y_values.map(function (y, i) { - var data_unit = _this13.draw[unit.type](x_values[i], y, unit.args, color, dataset_index, no_of_datasets); - group.appendChild(data_unit); - array.push(data_unit); - }); - } - }, { - key: 'make_y_specifics', - value: function make_y_specifics() { - var _this14 = this; - - this.specific_y_group.textContent = ''; - this.specific_values.map(function (d) { - _this14.specific_y_group.appendChild(_this14.make_y_line(0, _this14.width, _this14.width + 5, d.title.toUpperCase(), 'specific-value', 'specific-value', _this14.zero_line - d.value * _this14.multiplier, false, d.line_type)); - }); - } - }, { - key: 'bind_tooltip', - value: function bind_tooltip() { - var _this15 = this; - - // TODO: could be in tooltip itself, as it is a given functionality for its parent - this.chart_wrapper.addEventListener('mousemove', function (e) { - var offset = $.offset(_this15.chart_wrapper); - var relX = e.pageX - offset.left - _this15.translate_x; - var relY = e.pageY - offset.top - _this15.translate_y; - - if (relY < _this15.height + _this15.translate_y * 2) { - _this15.map_tooltip_x_position_and_show(relX); - } else { - _this15.tip.hide_tip(); - } - }); - } - }, { - key: 'map_tooltip_x_position_and_show', - value: function map_tooltip_x_position_and_show(relX) { - var _this16 = this; - - for (var i = this.x_axis_positions.length - 1; i >= 0; i--) { - var x_val = this.x_axis_positions[i]; - // let delta = i === 0 ? this.avg_unit_width : x_val - this.x_axis_positions[i-1]; - if (relX > x_val - this.avg_unit_width / 2) { - var x = x_val + this.translate_x; - var y = this.y_min_tops[i] + this.translate_y; - - var title = this.x.formatted && this.x.formatted.length > 0 ? this.x.formatted[i] : this.x[i]; - var values = this.y.map(function (set$$1, j) { - return { - title: set$$1.title, - value: set$$1.formatted ? set$$1.formatted[i] : set$$1.values[i], - color: set$$1.color || _this16.colors[j] - }; - }); - - // TODO: upside-down tooltips for negative values? - this.tip.set_values(x, y, title, '', values); - this.tip.show_tip(); - break; - } - } - } - - // API - - }, { - key: 'show_sums', - value: function show_sums() { - var _this17 = this; - - this.updating = true; - - this.y_sums = new Array(this.x_axis_positions.length).fill(0); - this.y.map(function (d) { - d.values.map(function (value, i) { - _this17.y_sums[i] += value; - }); - }); - - // Remake y axis, animate - this.update_values(); - - // Then make sum units, don't animate - this.sum_units = []; - - this.make_new_units_for_dataset(this.x_axis_positions, this.y_sums.map(function (val) { - return float_2(_this17.zero_line - val * _this17.multiplier); - }), 'light-grey', 0, 1, this.sum_group, this.sum_units); - - // this.make_path && this.make_path(d, i, old_x, old_y, d.color || this.colors[i]); - - this.updating = false; - } - }, { - key: 'hide_sums', - value: function hide_sums() { - if (this.updating) return; - this.y_sums = []; - this.sum_group.textContent = ''; - this.sum_units = []; - this.update_values(); - } - }, { - key: 'show_average', - value: function show_average() { - var _this18 = this; - - this.old_specific_values = this.specific_values.slice(); - this.y.map(function (d, i) { - var sum = 0; - d.values.map(function (e) { - sum += e; - }); - var average = sum / d.values.length; - - _this18.specific_values.push({ - title: "AVG" + " " + (i + 1), - line_type: "dashed", - value: average, - auto: 1 - }); - }); - - this.update_values(); - } - }, { - key: 'hide_average', - value: function hide_average() { - var _this19 = this; - - this.old_specific_values = this.specific_values.slice(); - - var indices_to_remove = []; - this.specific_values.map(function (d, i) { - if (d.auto) indices_to_remove.unshift(i); - }); - - indices_to_remove.map(function (index) { - _this19.specific_values.splice(index, 1); - }); - - this.update_values(); - } - }, { - key: 'update_values', - value: function update_values(new_y, new_x) { - var _this20 = this; - - if (!new_x) { - new_x = this.x; - } - this.elements_to_animate = []; - this.updating = true; - - this.old_x_values = this.x.slice(); - this.old_y_axis_tops = this.y.map(function (d) { - return d.y_tops.slice(); - }); - - this.old_y_values = this.y.map(function (d) { - return d.values; - }); - - this.no_of_extra_pts = new_x.length - this.x.length; - - // Just update values prop, setup_x/y() will do the rest - if (new_y) this.y.map(function (d, i) { - d.values = new_y[i].values; - }); - if (new_x) this.x = new_x; - - this.setup_x(); - this.setup_y(); - - // Animate only if positions have changed - if (!arrays_equal(this.x_old_axis_positions, this.x_axis_positions)) { - this.make_x_axis(true); - setTimeout(function () { - if (!_this20.updating) _this20.make_x_axis(); - }, 300); - } - - if (!arrays_equal(this.y_old_axis_values, this.y_axis_values) || this.old_specific_values && !arrays_equal(this.old_specific_values, this.specific_values)) { - - this.make_y_axis(true); - setTimeout(function () { - if (!_this20.updating) { - _this20.make_y_axis(); - _this20.make_y_specifics(); - } - }, 300); - } - - // Change in data, so calculate dependencies - this.calc_y_dependencies(); - - this.animate_graphs(); - - // Trigger animation with the animatable elements in this.elements_to_animate - this.run_animation(); - - this.updating = false; - } - }, { - key: 'add_data_point', - value: function add_data_point(y_point, x_point) { - var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.x.length; - - var new_y = this.y.map(function (data_set) { - return { values: data_set.values }; - }); - new_y.map(function (d, i) { - d.values.splice(index, 0, y_point[i]); - }); - var new_x = this.x.slice(); - new_x.splice(index, 0, x_point); - - this.update_values(new_y, new_x); - } - }, { - key: 'remove_data_point', - value: function remove_data_point() { - var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.x.length - 1; - - if (this.x.length < 3) return; - - var new_y = this.y.map(function (data_set) { - return { values: data_set.values }; - }); - new_y.map(function (d) { - d.values.splice(index, 1); - }); - var new_x = this.x.slice(); - new_x.splice(index, 1); - - this.update_values(new_y, new_x); - } - }, { - key: 'run_animation', - value: function run_animation() { - var _this21 = this; - - var anim_svg = $.runSVGAnimation(this.svg, this.elements_to_animate); - - if (this.svg.parentNode == this.chart_wrapper) { - this.chart_wrapper.removeChild(this.svg); - this.chart_wrapper.appendChild(anim_svg); - } - - // Replace the new svg (data has long been replaced) - setTimeout(function () { - if (anim_svg.parentNode == _this21.chart_wrapper) { - _this21.chart_wrapper.removeChild(anim_svg); - _this21.chart_wrapper.appendChild(_this21.svg); - } - }, 200); - } - }, { - key: 'animate_graphs', - value: function animate_graphs() { - var _this22 = this; - - this.y.map(function (d, i) { - // Pre-prep, equilize no of positions between old and new - var _calc_old_and_new_pos = _this22.calc_old_and_new_postions(d, i), - _calc_old_and_new_pos2 = slicedToArray(_calc_old_and_new_pos, 4), - old_x = _calc_old_and_new_pos2[0], - old_y = _calc_old_and_new_pos2[1], - new_x = _calc_old_and_new_pos2[2], - new_y = _calc_old_and_new_pos2[3]; - - if (_this22.no_of_extra_pts >= 0) { - _this22.make_path && _this22.make_path(d, i, old_x, old_y, d.color || _this22.colors[i]); - _this22.make_new_units_for_dataset(old_x, old_y, d.color || _this22.colors[i], i, _this22.y.length); - } - d.path && _this22.animate_path(d, i, old_x, old_y, new_x, new_y); - _this22.animate_units(d, i, old_x, old_y, new_x, new_y); - }); - - // TODO: replace with real units - setTimeout(function () { - _this22.y.map(function (d, i) { - _this22.make_path && _this22.make_path(d, i, _this22.x_axis_positions, d.y_tops, d.color || _this22.colors[i]); - _this22.make_new_units(d, i); - }); - }, 300); - } - }, { - key: 'animate_path', - value: function animate_path(d, i, old_x, old_y, new_x, new_y) { - // Animate path - var new_points_list = new_y.map(function (y, i) { - return new_x[i] + ',' + y; - }); - var new_path_str = new_points_list.join("L"); - - var path_args = [{ unit: d.path, object: d, key: 'path' }, { d: "M" + new_path_str }, 250, "easein"]; - this.elements_to_animate.push(path_args); - - // Animate region - if (d.region_path) { - var reg_start_pt = '0,' + this.zero_line + 'L'; - var reg_end_pt = 'L' + this.width + ',' + this.zero_line; - - var region_args = [{ unit: d.region_path, object: d, key: 'region_path' }, { d: "M" + reg_start_pt + new_path_str + reg_end_pt }, 250, "easein"]; - this.elements_to_animate.push(region_args); - } - } - }, { - key: 'animate_units', - value: function animate_units(d, index, old_x, old_y, new_x, new_y) { - var _this23 = this; - - var type = this.unit_args.type; - - d.svg_units.map(function (unit, i) { - _this23.elements_to_animate.push(_this23.animate[type]({ unit: unit, array: d.svg_units, index: i }, // unit, with info to replace where it came from in the data - new_x[i], new_y[i], index)); - }); - } - }, { - key: 'calc_old_and_new_postions', - value: function calc_old_and_new_postions(d, i) { - var old_x = this.x_old_axis_positions.slice(); - var new_x = this.x_axis_positions.slice(); - - var old_y = this.old_y_axis_tops[i].slice(); - var new_y = d.y_tops.slice(); - - var last_old_x_pos = old_x[old_x.length - 1]; - var last_old_y_pos = old_y[old_y.length - 1]; - - var last_new_x_pos = new_x[new_x.length - 1]; - var last_new_y_pos = new_y[new_y.length - 1]; - - if (this.no_of_extra_pts >= 0) { - // First substitute current path with a squiggled one (looking the same but - // having more points at end), - // then animate to stretch it later to new points - // (new points already have more points) - - // Hence, the extra end points will correspond to current(old) positions - var filler_x = new Array(Math.abs(this.no_of_extra_pts)).fill(last_old_x_pos); - var filler_y = new Array(Math.abs(this.no_of_extra_pts)).fill(last_old_y_pos); - - old_x = old_x.concat(filler_x); - old_y = old_y.concat(filler_y); - } else { - // Just modify the new points to have extra points - // with the same position at end - var _filler_x = new Array(Math.abs(this.no_of_extra_pts)).fill(last_new_x_pos); - var _filler_y = new Array(Math.abs(this.no_of_extra_pts)).fill(last_new_y_pos); - - new_x = new_x.concat(_filler_x); - new_y = new_y.concat(_filler_y); - } - - return [old_x, old_y, new_x, new_y]; - } - }, { - key: 'make_anim_x_axis', - value: function make_anim_x_axis(height, text_start_at, axis_line_class) { - var _this24 = this; - - // Animate X AXIS to account for more or less axis lines - - var old_pos = this.x_old_axis_positions; - var new_pos = this.x_axis_positions; - - var old_vals = this.old_x_values; - var new_vals = this.x; - - var last_line_pos = old_pos[old_pos.length - 1]; - - var add_and_animate_line = function add_and_animate_line(value, old_pos, new_pos) { - var x_line = _this24.make_x_line(height, text_start_at, value, // new value - 'x-value-text', axis_line_class, old_pos // old position - ); - _this24.x_axis_group.appendChild(x_line); - - _this24.elements_to_animate && _this24.elements_to_animate.push([{ unit: x_line, array: [0], index: 0 }, { transform: new_pos + ', 0' }, 250, "easein", "translate", { transform: old_pos + ', 0' }]); - }; - - this.x_axis_group.textContent = ''; - - this.make_new_axis_anim_lines(old_pos, new_pos, old_vals, new_vals, last_line_pos, add_and_animate_line); - } - }, { - key: 'make_anim_y_axis', - value: function make_anim_y_axis() { - var _this25 = this; - - // Animate Y AXIS to account for more or less axis lines - - var old_pos = this.y_old_axis_values.map(function (value) { - return _this25.zero_line - value * _this25.multiplier; - }); - var new_pos = this.y_axis_values.map(function (value) { - return _this25.zero_line - value * _this25.multiplier; - }); - - var old_vals = this.y_old_axis_values; - var new_vals = this.y_axis_values; - - var last_line_pos = old_pos[old_pos.length - 1]; - - this.y_axis_group.textContent = ''; - - this.make_new_axis_anim_lines(old_pos, new_pos, old_vals, new_vals, last_line_pos, this.add_and_animate_y_line.bind(this), this.y_axis_group); - } - }, { - key: 'make_anim_y_specifics', - value: function make_anim_y_specifics() { - var _this26 = this; - - this.specific_y_group.textContent = ''; - this.specific_values.map(function (d) { - _this26.add_and_animate_y_line(d.title, _this26.old_zero_line - d.value * _this26.old_multiplier, _this26.zero_line - d.value * _this26.multiplier, 0, _this26.specific_y_group, d.line_type, true); - }); - } - }, { - key: 'make_new_axis_anim_lines', - value: function make_new_axis_anim_lines(old_pos, new_pos, old_vals, new_vals, last_line_pos, add_and_animate_line, group) { - var superimposed_positions = void 0, - superimposed_values = void 0; - var no_of_extras = new_vals.length - old_vals.length; - if (no_of_extras > 0) { - // More axis are needed - // First make only the superimposed (same position) ones - // Add in the extras at the end later - superimposed_positions = new_pos.slice(0, old_pos.length); - superimposed_values = new_vals.slice(0, old_vals.length); - } else { - // Axis have to be reduced - // Fake it by moving all current extra axis to the last position - // You'll need filler positions and values in the new arrays - var filler_vals = new Array(Math.abs(no_of_extras)).fill(""); - superimposed_values = new_vals.concat(filler_vals); - - var filler_pos = new Array(Math.abs(no_of_extras)).fill(last_line_pos); - superimposed_positions = new_pos.concat(filler_pos); - } - - superimposed_values.map(function (value, i) { - add_and_animate_line(value, old_pos[i], superimposed_positions[i], i, group); - }); - - if (no_of_extras > 0) { - // Add in extra axis in the end - // and then animate to new positions - var extra_values = new_vals.slice(old_vals.length); - var extra_positions = new_pos.slice(old_pos.length); - - extra_values.map(function (value, i) { - add_and_animate_line(value, last_line_pos, extra_positions[i], i, group); - }); - } - } - }, { - key: 'make_x_line', - value: function make_x_line(height, text_start_at, point, label_class, axis_line_class, x_pos) { - var allowed_space = this.avg_unit_width * 1.5; - - if (this.get_strwidth(point) > allowed_space) { - var allowed_letters = allowed_space / 8; - point = point.slice(0, allowed_letters - 3) + " ..."; - } - - var line = $.createSVG('line', { - x1: 0, - x2: 0, - y1: 0, - y2: height - }); - - var text = $.createSVG('text', { - className: label_class, - x: 0, - y: text_start_at, - dy: '.71em', - innerHTML: point - }); - - var x_level = $.createSVG('g', { - className: 'tick ' + axis_line_class, - transform: 'translate(' + x_pos + ', 0)' - }); - - x_level.appendChild(line); - x_level.appendChild(text); - - return x_level; - } - }, { - key: 'make_y_line', - value: function make_y_line(start_at, width, text_end_at, point, label_class, axis_line_class, y_pos) { - var darker = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false; - var line_type = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : ""; - - var line = $.createSVG('line', { - className: line_type === "dashed" ? "dashed" : "", - x1: start_at, - x2: width, - y1: 0, - y2: 0 - }); - - var text = $.createSVG('text', { - className: label_class, - x: text_end_at, - y: 0, - dy: '.32em', - innerHTML: point + "" - }); - - var y_level = $.createSVG('g', { - className: 'tick ' + axis_line_class, - transform: 'translate(0, ' + y_pos + ')' - }); - - if (darker) { - line.style.stroke = "rgba(27, 31, 35, 0.6)"; - } - - y_level.appendChild(line); - y_level.appendChild(text); - - return y_level; - } - }, { - key: 'add_and_animate_y_line', - value: function add_and_animate_y_line(value, old_pos, new_pos, i, group, type) { - var specific = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false; - - var _get_y_axis_line_prop3 = this.get_y_axis_line_props(specific), - _get_y_axis_line_prop4 = slicedToArray(_get_y_axis_line_prop3, 4), - width = _get_y_axis_line_prop4[0], - text_end_at = _get_y_axis_line_prop4[1], - axis_line_class = _get_y_axis_line_prop4[2], - start_at = _get_y_axis_line_prop4[3]; - - var axis_label_class = !specific ? 'y-value-text' : 'specific-value'; - value = !specific ? value : (value + "").toUpperCase(); - var y_line = this.make_y_line(start_at, width, text_end_at, value, axis_label_class, axis_line_class, old_pos, // old position - value === 0 && i !== 0, // Non-first Zero line - type); - - group.appendChild(y_line); - - this.elements_to_animate && this.elements_to_animate.push([{ unit: y_line, array: [0], index: 0 }, { transform: '0, ' + new_pos }, 250, "easein", "translate", { transform: '0, ' + old_pos }]); - } - }, { - key: 'get_y_axis_points', - value: function get_y_axis_points(array) { - var _this27 = this; - - //*** Where the magic happens *** - - // Calculates best-fit y intervals from given values - // and returns the interval array - - // TODO: Fractions - - var max_bound = void 0, - min_bound = void 0, - pos_no_of_parts = void 0, - neg_no_of_parts = void 0, - part_size = void 0; // eslint-disable-line no-unused-vars - - // Critical values - var max_val = parseInt(Math.max.apply(Math, toConsumableArray(array))); - var min_val = parseInt(Math.min.apply(Math, toConsumableArray(array))); - if (min_val >= 0) { - min_val = 0; - } - - var get_params = function get_params(value1, value2) { - var bound1 = void 0, - bound2 = void 0, - no_of_parts_1 = void 0, - no_of_parts_2 = void 0, - interval_size = void 0; - if ((value1 + "").length <= 1) { - bound1 = 10; - no_of_parts_1 = 5; - } else { - var _calc_upper_bound_and = _this27.calc_upper_bound_and_no_of_parts(value1); - - var _calc_upper_bound_and2 = slicedToArray(_calc_upper_bound_and, 2); - - bound1 = _calc_upper_bound_and2[0]; - no_of_parts_1 = _calc_upper_bound_and2[1]; - } - - interval_size = bound1 / no_of_parts_1; - no_of_parts_2 = _this27.calc_no_of_parts(value2, interval_size); - bound2 = no_of_parts_2 * interval_size; - - return [bound1, bound2, no_of_parts_1, no_of_parts_2, interval_size]; - }; - - var abs_min_val = min_val * -1; - if (abs_min_val <= max_val) { - var _get_params = get_params(max_val, abs_min_val); - // Get the positive region intervals - // then calc negative ones accordingly - - - var _get_params2 = slicedToArray(_get_params, 5); - - min_bound = _get_params2[1]; - pos_no_of_parts = _get_params2[2]; - neg_no_of_parts = _get_params2[3]; - part_size = _get_params2[4]; - - if (abs_min_val === 0) { - min_bound = 0;neg_no_of_parts = 0; - } - } else { - var _get_params3 = get_params(abs_min_val, max_val); - // Get the negative region here first - - - var _get_params4 = slicedToArray(_get_params3, 5); - - min_bound = _get_params4[0]; - neg_no_of_parts = _get_params4[2]; - pos_no_of_parts = _get_params4[3]; - part_size = _get_params4[4]; - } - - // Make both region parts even - if (pos_no_of_parts % 2 !== 0 && neg_no_of_parts > 0) pos_no_of_parts++; - if (neg_no_of_parts % 2 !== 0) { - // every increase in no_of_parts entails an increase in corresponding bound - // except here, it happens implicitly after every calc_no_of_parts() call - neg_no_of_parts++; - min_bound += part_size; - } - - var no_of_parts = pos_no_of_parts + neg_no_of_parts; - if (no_of_parts > 5) { - no_of_parts /= 2; - part_size *= 2; - } - - return this.get_intervals(-1 * min_bound, part_size, no_of_parts); - } - }, { - key: 'get_intervals', - value: function get_intervals(start, interval_size, count) { - var intervals = []; - for (var i = 0; i <= count; i++) { - intervals.push(start); - start += interval_size; - } - return intervals; - } - }, { - key: 'calc_upper_bound_and_no_of_parts', - value: function calc_upper_bound_and_no_of_parts(max_val) { - // Given a positive value, calculates a nice-number upper bound - // and a consequent optimal number of parts - - var part_size = Math.pow(10, (max_val + "").length - 1); - var no_of_parts = this.calc_no_of_parts(max_val, part_size); - - // Use it to get a nice even upper bound - var upper_bound = part_size * no_of_parts; - - return [upper_bound, no_of_parts]; - } - }, { - key: 'calc_no_of_parts', - value: function calc_no_of_parts(value, divisor) { - // value should be a positive number, divisor should be greater than 0 - // returns an even no of parts - var no_of_parts = Math.ceil(value / divisor); - if (no_of_parts % 2 !== 0) no_of_parts++; // Make it an even number - - return no_of_parts; - } - }, { - key: 'get_optimal_no_of_parts', - value: function get_optimal_no_of_parts(no_of_parts) { - // aka Divide by 2 if too large - return no_of_parts < 5 ? no_of_parts : no_of_parts / 2; - } - }, { - key: 'set_avg_unit_width_and_x_offset', - value: function set_avg_unit_width_and_x_offset() { - // Set the ... you get it - this.avg_unit_width = this.width / (this.x.length - 1); - this.x_offset = 0; - } - }, { - key: 'get_all_y_values', - value: function get_all_y_values() { - var all_values = []; - - // Add in all the y values in the datasets - this.y.map(function (d) { - all_values = all_values.concat(d.values); - }); - - // Add in all the specific values - return all_values.concat(this.specific_values.map(function (d) { - return d.value; - })); - } - }, { - key: 'calc_y_dependencies', - value: function calc_y_dependencies() { - var _this28 = this; - - this.y_min_tops = new Array(this.x_axis_positions.length).fill(9999); - this.y.map(function (d) { - d.y_tops = d.values.map(function (val) { - return float_2(_this28.zero_line - val * _this28.multiplier); - }); - d.y_tops.map(function (y_top, i) { - if (y_top < _this28.y_min_tops[i]) { - _this28.y_min_tops[i] = y_top; - } - }); - }); - } - }, { - key: 'get_bar_height_and_y_attr', - value: function get_bar_height_and_y_attr(y_top) { - var height = void 0, - y = void 0; - if (y_top <= this.zero_line) { - height = this.zero_line - y_top; - y = y_top; - - // In case of invisible bars - if (height === 0) { - height = this.height * 0.01; - y -= height; - } - } else { - height = y_top - this.zero_line; - y = this.zero_line; - - // In case of invisible bars - if (height === 0) { - height = this.height * 0.01; - } - } - - return [height, y]; - } - }, { - key: 'setup_utils', - value: function setup_utils() { - var _this29 = this; - - this.draw = { - 'bar': function bar(x, y_top, args, color, index, no_of_datasets) { - var total_width = _this29.avg_unit_width - args.space_width; - var start_x = x - total_width / 2; - - var width = total_width / no_of_datasets; - var current_x = start_x + width * index; - - var _get_bar_height_and_y = _this29.get_bar_height_and_y_attr(y_top), - _get_bar_height_and_y2 = slicedToArray(_get_bar_height_and_y, 2), - height = _get_bar_height_and_y2[0], - y = _get_bar_height_and_y2[1]; - - return $.createSVG('rect', { - className: 'bar mini fill ' + color, - x: current_x, - y: y, - width: width, - height: height - }); - }, - 'dot': function dot(x, y, args, color) { - return $.createSVG('circle', { - className: 'fill ' + color, - cx: x, - cy: y, - r: args.radius - }); - } - }; - - this.animate = { - 'bar': function bar(bar_obj, x, y_top, index) { - var start = x - _this29.avg_unit_width / 4; - var width = _this29.avg_unit_width / 2 / _this29.y.length; - - var _get_bar_height_and_y3 = _this29.get_bar_height_and_y_attr(y_top), - _get_bar_height_and_y4 = slicedToArray(_get_bar_height_and_y3, 2), - height = _get_bar_height_and_y4[0], - y = _get_bar_height_and_y4[1]; - - x = start + width * index; - - return [bar_obj, { width: width, height: height, x: x, y: y }, 250, "easein"]; - // bar.animate({height: args.new_height, y: y_top}, 250, mina.easein); - }, - 'dot': function dot(dot_obj, x, y_top) { - return [dot_obj, { cx: x, cy: y_top }, 300, "easein"]; - // dot.animate({cy: y_top}, 250, mina.easein); - } - }; - } - }]); - return AxisChart; -}(Chart); - -var BarChart = function (_AxisChart) { - inherits(BarChart, _AxisChart); - - function BarChart(args) { - classCallCheck(this, BarChart); - - var _this30 = possibleConstructorReturn(this, (BarChart.__proto__ || Object.getPrototypeOf(BarChart)).call(this, args)); - - _this30.type = 'bar'; - _this30.x_axis_mode = args.x_axis_mode || 'tick'; - _this30.y_axis_mode = args.y_axis_mode || 'span'; - _this30.setup(); - return _this30; - } - - createClass(BarChart, [{ - key: 'setup_values', - value: function setup_values() { - get(BarChart.prototype.__proto__ || Object.getPrototypeOf(BarChart.prototype), 'setup_values', this).call(this); - this.x_offset = this.avg_unit_width; - this.unit_args = { - type: 'bar', - args: { - space_width: this.avg_unit_width / 2 - } - }; - } - }, { - key: 'make_overlay', - value: function make_overlay() { - // Just make one out of the first element - var index = this.x.length - 1; - var unit = this.y[0].svg_units[index]; - this.update_current_data_point(index); - - if (this.overlay) { - this.overlay.parentNode.removeChild(this.overlay); - } - - this.overlay = unit.cloneNode(); - this.overlay.style.fill = '#000000'; - this.overlay.style.opacity = '0.4'; - this.draw_area.appendChild(this.overlay); - } - }, { - key: 'bind_overlay', - value: function bind_overlay() { - var _this31 = this; - - // on event, update overlay - this.parent.addEventListener('data-select', function (e) { - _this31.update_overlay(e.svg_unit); - }); - } - }, { - key: 'update_overlay', - value: function update_overlay(unit) { - var _this32 = this; - - var attributes = []; - Object.keys(unit.attributes).map(function (index) { - attributes.push(unit.attributes[index]); - }); - - attributes.filter(function (attr) { - return attr.specified; - }).map(function (attr) { - _this32.overlay.setAttribute(attr.name, attr.nodeValue); - }); - } - }, { - key: 'on_left_arrow', - value: function on_left_arrow() { - this.update_current_data_point(this.current_index - 1); - } - }, { - key: 'on_right_arrow', - value: function on_right_arrow() { - this.update_current_data_point(this.current_index + 1); - } - }, { - key: 'set_avg_unit_width_and_x_offset', - value: function set_avg_unit_width_and_x_offset() { - this.avg_unit_width = this.width / (this.x.length + 1); - this.x_offset = this.avg_unit_width; - } - }]); - return BarChart; -}(AxisChart); - -var LineChart = function (_AxisChart2) { - inherits(LineChart, _AxisChart2); - - function LineChart(args) { - classCallCheck(this, LineChart); - - var _this33 = possibleConstructorReturn(this, (LineChart.__proto__ || Object.getPrototypeOf(LineChart)).call(this, args)); - - if (Object.getPrototypeOf(_this33) !== LineChart.prototype) { - return possibleConstructorReturn(_this33); - } - - _this33.type = 'line'; - _this33.region_fill = args.region_fill; - _this33.x_axis_mode = args.x_axis_mode || 'span'; - _this33.y_axis_mode = args.y_axis_mode || 'span'; - - _this33.setup(); - return _this33; - } - - createClass(LineChart, [{ - key: 'setup_graph_components', - value: function setup_graph_components() { - this.setup_path_groups(); - get(LineChart.prototype.__proto__ || Object.getPrototypeOf(LineChart.prototype), 'setup_graph_components', this).call(this); - } - }, { - key: 'setup_path_groups', - value: function setup_path_groups() { - var _this34 = this; - - this.paths_groups = []; - this.y.map(function (d, i) { - _this34.paths_groups[i] = $.createSVG('g', { - className: 'path-group path-group-' + i, - inside: _this34.draw_area - }); - }); - } - }, { - key: 'setup_values', - value: function setup_values() { - get(LineChart.prototype.__proto__ || Object.getPrototypeOf(LineChart.prototype), 'setup_values', this).call(this); - this.unit_args = { - type: 'dot', - args: { radius: 8 } - }; - } - }, { - key: 'make_paths', - value: function make_paths() { - var _this35 = this; - - this.y.map(function (d, i) { - _this35.make_path(d, i, _this35.x_axis_positions, d.y_tops, d.color || _this35.colors[i]); - }); - } - }, { - key: 'make_path', - value: function make_path(d, i, x_positions, y_positions, color) { - var points_list = y_positions.map(function (y, i) { - return x_positions[i] + ',' + y; - }); - var points_str = points_list.join("L"); - - this.paths_groups[i].textContent = ''; - - d.path = $.createSVG('path', { - inside: this.paths_groups[i], - className: 'stroke ' + color, - d: "M" + points_str - }); - - if (this.region_fill) { - var gradient_id = 'path-fill-gradient' + '-' + color; - - this.gradient_def = $.createSVG('linearGradient', { - inside: this.svg_defs, - id: gradient_id, - x1: 0, - x2: 0, - y1: 0, - y2: 1 - }); - - var set_gradient_stop = function set_gradient_stop(grad_elem, offset, color, opacity) { - $.createSVG('stop', { - 'className': 'stop-color ' + color, - 'inside': grad_elem, - 'offset': offset, - 'stop-opacity': opacity - }); - }; - - set_gradient_stop(this.gradient_def, "0%", color, 0.4); - set_gradient_stop(this.gradient_def, "50%", color, 0.2); - set_gradient_stop(this.gradient_def, "100%", color, 0); - - d.region_path = $.createSVG('path', { - inside: this.paths_groups[i], - className: 'region-fill', - d: "M" + ('0,' + this.zero_line + 'L') + points_str + ('L' + this.width + ',' + this.zero_line) - }); - - d.region_path.style.stroke = "none"; - d.region_path.style.fill = 'url(#' + gradient_id + ')'; - } - } - }]); - return LineChart; -}(AxisChart); - -var PercentageChart = function (_Chart2) { - inherits(PercentageChart, _Chart2); - - function PercentageChart(args) { - classCallCheck(this, PercentageChart); - - var _this36 = possibleConstructorReturn(this, (PercentageChart.__proto__ || Object.getPrototypeOf(PercentageChart)).call(this, args)); - - _this36.type = 'percentage'; - - _this36.get_y_label = _this36.format_lambdas.y_label; - _this36.get_x_tooltip = _this36.format_lambdas.x_tooltip; - _this36.get_y_tooltip = _this36.format_lambdas.y_tooltip; - - _this36.max_slices = 10; - _this36.max_legend_points = 6; - - _this36.colors = args.colors; - - if (!_this36.colors || _this36.colors.length < _this36.data.labels.length) { - _this36.colors = ['light-blue', 'blue', 'violet', 'red', 'orange', 'yellow', 'green', 'light-green', 'purple', 'magenta']; - } - - _this36.setup(); - return _this36; - } - - createClass(PercentageChart, [{ - key: 'make_chart_area', - value: function make_chart_area() { - this.chart_wrapper.className += ' ' + 'graph-focus-margin'; - this.chart_wrapper.style.marginTop = '45px'; - - this.stats_wrapper.className += ' ' + 'graph-focus-margin'; - this.stats_wrapper.style.marginBottom = '30px'; - this.stats_wrapper.style.paddingTop = '0px'; - } - }, { - key: 'make_draw_area', - value: function make_draw_area() { - this.chart_div = $.create('div', { - className: 'div', - inside: this.chart_wrapper, - width: this.base_width, - height: this.base_height - }); - - this.chart = $.create('div', { - className: 'progress-chart', - inside: this.chart_div - }); - } - }, { - key: 'setup_components', - value: function setup_components() { - this.percentage_bar = $.create('div', { - className: 'progress', - inside: this.chart - }); - } - }, { - key: 'setup_values', - value: function setup_values() { - var _this37 = this; - - this.slice_totals = []; - var all_totals = this.data.labels.map(function (d, i) { - var total = 0; - _this37.data.datasets.map(function (e) { - total += e.values[i]; - }); - return [total, d]; - }).filter(function (d) { - return d[0] > 0; - }); // keep only positive results - - var totals = all_totals; - - if (all_totals.length > this.max_slices) { - all_totals.sort(function (a, b) { - return b[0] - a[0]; - }); - - totals = all_totals.slice(0, this.max_slices - 1); - var others = all_totals.slice(this.max_slices - 1); - - var sum_of_others = 0; - others.map(function (d) { - sum_of_others += d[0]; - }); - - totals.push([sum_of_others, 'Rest']); - - this.colors[this.max_slices - 1] = 'grey'; - } - - this.labels = []; - totals.map(function (d) { - _this37.slice_totals.push(d[0]); - _this37.labels.push(d[1]); - }); - - this.legend_totals = this.slice_totals.slice(0, this.max_legend_points); - } - }, { - key: 'setup_utils', - value: function setup_utils() {} - }, { - key: 'make_graph_components', - value: function make_graph_components() { - var _this38 = this; - - this.grand_total = this.slice_totals.reduce(function (a, b) { - return a + b; - }, 0); - this.slices = []; - this.slice_totals.map(function (total, i) { - var slice = $.create('div', { - className: 'progress-bar background ' + _this38.colors[i], - style: 'width: ' + total * 100 / _this38.grand_total + '%', - inside: _this38.percentage_bar - }); - _this38.slices.push(slice); - }); - } - }, { - key: 'bind_tooltip', - value: function bind_tooltip() { - var _this39 = this; - - this.slices.map(function (slice, i) { - slice.addEventListener('mouseenter', function () { - var g_off = $.offset(_this39.chart_wrapper), - p_off = $.offset(slice); - - var x = p_off.left - g_off.left + slice.offsetWidth / 2; - var y = p_off.top - g_off.top - 6; - var title = (_this39.formatted_labels && _this39.formatted_labels.length > 0 ? _this39.formatted_labels[i] : _this39.labels[i]) + ': '; - var percent = (_this39.slice_totals[i] * 100 / _this39.grand_total).toFixed(1); - - _this39.tip.set_values(x, y, title, percent + "%"); - _this39.tip.show_tip(); - }); - }); - } - }, { - key: 'show_summary', - value: function show_summary() { - var _this40 = this; - - var x_values = this.formatted_labels && this.formatted_labels.length > 0 ? this.formatted_labels : this.labels; - this.legend_totals.map(function (d, i) { - if (d) { - var stats = $.create('div', { - className: 'stats', - inside: _this40.stats_wrapper - }); - stats.innerHTML = '\n\t\t\t\t\t' + x_values[i] + ':\n\t\t\t\t\t' + d + '\n\t\t\t\t'; - } - }); - } - }]); - return PercentageChart; -}(Chart); - -var HeatMap = function (_Chart3) { - inherits(HeatMap, _Chart3); - - function HeatMap(_ref2) { - var _ref2$start = _ref2.start, - start = _ref2$start === undefined ? '' : _ref2$start, - _ref2$domain = _ref2.domain, - domain = _ref2$domain === undefined ? '' : _ref2$domain, - _ref2$subdomain = _ref2.subdomain, - subdomain = _ref2$subdomain === undefined ? '' : _ref2$subdomain, - _ref2$data = _ref2.data, - data = _ref2$data === undefined ? {} : _ref2$data, - _ref2$discrete_domain = _ref2.discrete_domains, - discrete_domains = _ref2$discrete_domain === undefined ? 0 : _ref2$discrete_domain, - _ref2$count_label = _ref2.count_label, - count_label = _ref2$count_label === undefined ? '' : _ref2$count_label; - classCallCheck(this, HeatMap); - - var _this41 = possibleConstructorReturn(this, (HeatMap.__proto__ || Object.getPrototypeOf(HeatMap)).call(this, arguments[0])); - - _this41.type = 'heatmap'; - - _this41.domain = domain; - _this41.subdomain = subdomain; - _this41.data = data; - _this41.discrete_domains = discrete_domains; - _this41.count_label = count_label; - - var today = new Date(); - _this41.start = start || _this41.add_days(today, 365); - - _this41.legend_colors = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127']; - - _this41.translate_x = 0; - _this41.setup(); - return _this41; - } - - createClass(HeatMap, [{ - key: 'setup_base_values', - value: function setup_base_values() { - this.today = new Date(); - - if (!this.start) { - this.start = new Date(); - this.start.setFullYear(this.start.getFullYear() - 1); - } - this.first_week_start = new Date(this.start.toDateString()); - this.last_week_start = new Date(this.today.toDateString()); - if (this.first_week_start.getDay() !== 7) { - this.add_days(this.first_week_start, -1 * this.first_week_start.getDay()); - } - if (this.last_week_start.getDay() !== 7) { - this.add_days(this.last_week_start, -1 * this.last_week_start.getDay()); - } - this.no_of_cols = this.get_weeks_between(this.first_week_start + '', this.last_week_start + '') + 1; - } - }, { - key: 'set_width', - value: function set_width() { - this.base_width = this.no_of_cols * 12; - - if (this.discrete_domains) { - this.base_width += 12 * 12; - } - } - }, { - key: 'setup_components', - value: function setup_components() { - this.domain_label_group = $.createSVG("g", { - className: "domain-label-group chart-label", - inside: this.draw_area - }); - this.data_groups = $.createSVG("g", { - className: "data-groups", - inside: this.draw_area, - transform: 'translate(0, 20)' - }); - } - }, { - key: 'setup_values', - value: function setup_values() { - this.domain_label_group.textContent = ''; - this.data_groups.textContent = ''; - this.distribution = this.get_distribution(this.data, this.legend_colors); - this.month_names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; - - this.render_all_weeks_and_store_x_values(this.no_of_cols); - } - }, { - key: 'render_all_weeks_and_store_x_values', - value: function render_all_weeks_and_store_x_values(no_of_weeks) { - var current_week_sunday = new Date(this.first_week_start); - this.week_col = 0; - this.current_month = current_week_sunday.getMonth(); - - this.months = [this.current_month + '']; - this.month_weeks = {}, this.month_start_points = []; - this.month_weeks[this.current_month] = 0; - this.month_start_points.push(13); - - for (var i = 0; i < no_of_weeks; i++) { - var data_group = void 0, - month_change = 0; - var day = new Date(current_week_sunday); - - var _get_week_squares_gro = this.get_week_squares_group(day, this.week_col); - - var _get_week_squares_gro2 = slicedToArray(_get_week_squares_gro, 2); - - data_group = _get_week_squares_gro2[0]; - month_change = _get_week_squares_gro2[1]; - - this.data_groups.appendChild(data_group); - this.week_col += 1 + parseInt(this.discrete_domains && month_change); - this.month_weeks[this.current_month]++; - if (month_change) { - this.current_month = (this.current_month + 1) % 12; - this.months.push(this.current_month + ''); - this.month_weeks[this.current_month] = 1; - } - this.add_days(current_week_sunday, 7); - } - this.render_month_labels(); - } - }, { - key: 'get_week_squares_group', - value: function get_week_squares_group(current_date, index) { - var no_of_weekdays = 7; - var square_side = 10; - var cell_padding = 2; - var step = 1; - - var month_change = 0; - var week_col_change = 0; - - var data_group = $.createSVG("g", { - className: "data-group", - inside: this.data_groups - }); - - for (var y = 0, i = 0; i < no_of_weekdays; i += step, y += square_side + cell_padding) { - var data_value = 0; - var color_index = 0; - - var timestamp = Math.floor(current_date.getTime() / 1000).toFixed(1); - - if (this.data[timestamp]) { - data_value = this.data[timestamp]; - color_index = this.get_max_checkpoint(data_value, this.distribution); - } - - if (this.data[Math.round(timestamp)]) { - data_value = this.data[Math.round(timestamp)]; - color_index = this.get_max_checkpoint(data_value, this.distribution); - } - - var x = 13 + (index + week_col_change) * 12; - - $.createSVG("rect", { - className: 'day', - inside: data_group, - x: x, - y: y, - width: square_side, - height: square_side, - fill: this.legend_colors[color_index], - 'data-date': this.get_dd_mm_yyyy(current_date), - 'data-value': data_value, - 'data-day': current_date.getDay() - }); - - var next_date = new Date(current_date); - this.add_days(next_date, 1); - if (next_date.getMonth() - current_date.getMonth()) { - month_change = 1; - if (this.discrete_domains) { - week_col_change = 1; - } - - this.month_start_points.push(13 + (index + week_col_change) * 12); - } - current_date = next_date; - } - - return [data_group, month_change]; - } - }, { - key: 'render_month_labels', - value: function render_month_labels() { - var _this42 = this; - - // this.first_month_label = 1; - // if (this.first_week_start.getDate() > 8) { - // this.first_month_label = 0; - // } - // this.last_month_label = 1; - - // let first_month = this.months.shift(); - // let first_month_start = this.month_start_points.shift(); - // render first month if - - // let last_month = this.months.pop(); - // let last_month_start = this.month_start_points.pop(); - // render last month if - - this.months.shift(); - this.month_start_points.shift(); - this.months.pop(); - this.month_start_points.pop(); - - this.month_start_points.map(function (start, i) { - var month_name = _this42.month_names[_this42.months[i]].substring(0, 3); - - $.createSVG('text', { - className: 'y-value-text', - inside: _this42.domain_label_group, - x: start + 12, - y: 10, - dy: '.32em', - innerHTML: month_name - }); - }); - } - }, { - key: 'make_graph_components', - value: function make_graph_components() { - Array.prototype.slice.call(this.container.querySelectorAll('.graph-stats-container, .sub-title, .title')).map(function (d) { - d.style.display = 'None'; - }); - this.chart_wrapper.style.marginTop = '0px'; - this.chart_wrapper.style.paddingTop = '0px'; - } - }, { - key: 'bind_tooltip', - value: function bind_tooltip() { - var _this43 = this; - - Array.prototype.slice.call(document.querySelectorAll(".data-group .day")).map(function (el) { - el.addEventListener('mouseenter', function (e) { - var count = e.target.getAttribute('data-value'); - var date_parts = e.target.getAttribute('data-date').split('-'); - - var month = _this43.month_names[parseInt(date_parts[1]) - 1].substring(0, 3); - - var g_off = _this43.chart_wrapper.getBoundingClientRect(), - p_off = e.target.getBoundingClientRect(); - - var width = parseInt(e.target.getAttribute('width')); - var x = p_off.left - g_off.left + (width + 2) / 2; - var y = p_off.top - g_off.top - (width + 2) / 2; - var value = count + ' ' + _this43.count_label; - var name = ' on ' + month + ' ' + date_parts[0] + ', ' + date_parts[2]; - - _this43.tip.set_values(x, y, name, value, [], 1); - _this43.tip.show_tip(); - }); - }); - } - }, { - key: 'update', - value: function update(data) { - this.data = data; - this.setup_values(); - this.bind_tooltip(); - } - }, { - key: 'get_distribution', - value: function get_distribution() { - var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - var mapper_array = arguments[1]; - - var data_values = Object.keys(data).map(function (key) { - return data[key]; - }); - var data_max_value = Math.max.apply(Math, toConsumableArray(data_values)); - - var distribution_step = 1 / (mapper_array.length - 1); - var distribution = []; - - mapper_array.map(function (color, i) { - var checkpoint = data_max_value * (distribution_step * i); - distribution.push(checkpoint); - }); - - return distribution; - } - }, { - key: 'get_max_checkpoint', - value: function get_max_checkpoint(value, distribution) { - return distribution.filter(function (d, i) { - if (i === 1) { - return distribution[0] < value; - } - return d <= value; - }).length - 1; - } - - // TODO: date utils, move these out - - // https://stackoverflow.com/a/11252167/6495043 - - }, { - key: 'treat_as_utc', - value: function treat_as_utc(date_str) { - var result = new Date(date_str); - result.setMinutes(result.getMinutes() - result.getTimezoneOffset()); - return result; - } - }, { - key: 'get_dd_mm_yyyy', - value: function get_dd_mm_yyyy(date) { - var dd = date.getDate(); - var mm = date.getMonth() + 1; // getMonth() is zero-based - return [(dd > 9 ? '' : '0') + dd, (mm > 9 ? '' : '0') + mm, date.getFullYear()].join('-'); - } - }, { - key: 'get_weeks_between', - value: function get_weeks_between(start_date_str, end_date_str) { - return Math.ceil(this.get_days_between(start_date_str, end_date_str) / 7); - } - }, { - key: 'get_days_between', - value: function get_days_between(start_date_str, end_date_str) { - var milliseconds_per_day = 24 * 60 * 60 * 1000; - return (this.treat_as_utc(end_date_str) - this.treat_as_utc(start_date_str)) / milliseconds_per_day; - } - - // mutates - - }, { - key: 'add_days', - value: function add_days(date, number_of_days) { - date.setDate(date.getDate() + number_of_days); - } - }, { - key: 'get_month_name', - value: function get_month_name() {} - }]); - return HeatMap; -}(Chart); - -var SvgTip = function () { - function SvgTip(_ref3) { - var _ref3$parent = _ref3.parent, - parent = _ref3$parent === undefined ? null : _ref3$parent; - classCallCheck(this, SvgTip); - - this.parent = parent; - this.title_name = ''; - this.title_value = ''; - this.list_values = []; - this.title_value_first = 0; - - this.x = 0; - this.y = 0; - - this.top = 0; - this.left = 0; - - this.setup(); - } - - createClass(SvgTip, [{ - key: 'setup', - value: function setup() { - this.make_tooltip(); - } - }, { - key: 'refresh', - value: function refresh() { - this.fill(); - this.calc_position(); - // this.show_tip(); - } - }, { - key: 'make_tooltip', - value: function make_tooltip() { - var _this44 = this; - - this.container = $.create('div', { - inside: this.parent, - className: 'graph-svg-tip comparison', - innerHTML: '\n\t\t\t\t\n\t\t\t\t
' - }); - this.hide_tip(); - - this.title = this.container.querySelector('.title'); - this.data_point_list = this.container.querySelector('.data-point-list'); - - this.parent.addEventListener('mouseleave', function () { - _this44.hide_tip(); - }); - } - }, { - key: 'fill', - value: function fill() { - var _this45 = this; - - var title = void 0; - if (this.title_value_first) { - title = '' + this.title_value + '' + this.title_name; - } else { - title = this.title_name + '' + this.title_value + ''; - } - this.title.innerHTML = title; - this.data_point_list.innerHTML = ''; - - this.list_values.map(function (set$$1) { - var li = $.create('li', { - className: 'border-top ' + (set$$1.color || 'black'), - innerHTML: '' + (set$$1.value ? set$$1.value : '') + '\n\t\t\t\t\t' + (set$$1.title ? set$$1.title : '') - }); - - _this45.data_point_list.appendChild(li); - }); - } - }, { - key: 'calc_position', - value: function calc_position() { - this.top = this.y - this.container.offsetHeight; - this.left = this.x - this.container.offsetWidth / 2; - var max_left = this.parent.offsetWidth - this.container.offsetWidth; - - var pointer = this.container.querySelector('.svg-pointer'); - - if (this.left < 0) { - pointer.style.left = 'calc(50% - ' + -1 * this.left + 'px)'; - this.left = 0; - } else if (this.left > max_left) { - var delta = this.left - max_left; - pointer.style.left = 'calc(50% + ' + delta + 'px)'; - this.left = max_left; - } else { - pointer.style.left = '50%'; - } - } - }, { - key: 'set_values', - value: function set_values(x, y) { - var title_name = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ''; - var title_value = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ''; - var list_values = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : []; - var title_value_first = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0; - - this.title_name = title_name; - this.title_value = title_value; - this.list_values = list_values; - this.x = x; - this.y = y; - this.title_value_first = title_value_first; - this.refresh(); - } - }, { - key: 'hide_tip', - value: function hide_tip() { - this.container.style.top = '0px'; - this.container.style.left = '0px'; - this.container.style.opacity = '0'; - } - }, { - key: 'show_tip', - value: function show_tip() { - this.container.style.top = this.top + 'px'; - this.container.style.left = this.left + 'px'; - this.container.style.opacity = '1'; - } - }]); - return SvgTip; -}(); - -return Chart; - -}()); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJhcHBlLWNoYXJ0cy5taW4uanMiLCJzb3VyY2VzIjpbIi4uL3NyYy9kb20uanMiLCIuLi9zcmMvdXRpbHMuanMiLCIuLi9zcmMvY2hhcnRzLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uICQoZXhwciwgY29uKSB7XG5cdHJldHVybiB0eXBlb2YgZXhwciA9PT0gXCJzdHJpbmdcIj8gKGNvbiB8fCBkb2N1bWVudCkucXVlcnlTZWxlY3RvcihleHByKSA6IGV4cHIgfHwgbnVsbDtcbn1cblxuJC5maW5kTm9kZUluZGV4ID0gKG5vZGUpID0+XG57XG5cdHZhciBpID0gMDtcblx0d2hpbGUgKG5vZGUucHJldmlvdXNTaWJsaW5nKSB7XG5cdFx0bm9kZSA9IG5vZGUucHJldmlvdXNTaWJsaW5nO1xuXHRcdGkrKztcblx0fVxuXHRyZXR1cm4gaTtcbn07XG5cbiQuY3JlYXRlID0gKHRhZywgbykgPT4ge1xuXHR2YXIgZWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodGFnKTtcblxuXHRmb3IgKHZhciBpIGluIG8pIHtcblx0XHR2YXIgdmFsID0gb1tpXTtcblxuXHRcdGlmIChpID09PSBcImluc2lkZVwiKSB7XG5cdFx0XHQkKHZhbCkuYXBwZW5kQ2hpbGQoZWxlbWVudCk7XG5cdFx0fVxuXHRcdGVsc2UgaWYgKGkgPT09IFwiYXJvdW5kXCIpIHtcblx0XHRcdHZhciByZWYgPSAkKHZhbCk7XG5cdFx0XHRyZWYucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoZWxlbWVudCwgcmVmKTtcblx0XHRcdGVsZW1lbnQuYXBwZW5kQ2hpbGQocmVmKTtcblx0XHR9XG5cdFx0ZWxzZSBpZiAoaSBpbiBlbGVtZW50KSB7XG5cdFx0XHRlbGVtZW50W2ldID0gdmFsO1xuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdGVsZW1lbnQuc2V0QXR0cmlidXRlKGksIHZhbCk7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIGVsZW1lbnQ7XG59O1xuXG4kLmNyZWF0ZVNWRyA9ICh0YWcsIG8pID0+IHtcblx0dmFyIGVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50TlMoXCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiLCB0YWcpO1xuXG5cdGZvciAodmFyIGkgaW4gbykge1xuXHRcdHZhciB2YWwgPSBvW2ldO1xuXG5cdFx0aWYgKGkgPT09IFwiaW5zaWRlXCIpIHtcblx0XHRcdCQodmFsKS5hcHBlbmRDaGlsZChlbGVtZW50KTtcblx0XHR9XG5cdFx0ZWxzZSBpZiAoaSA9PT0gXCJhcm91bmRcIikge1xuXHRcdFx0dmFyIHJlZiA9ICQodmFsKTtcblx0XHRcdHJlZi5wYXJlbnROb2RlLmluc2VydEJlZm9yZShlbGVtZW50LCByZWYpO1xuXHRcdFx0ZWxlbWVudC5hcHBlbmRDaGlsZChyZWYpO1xuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdGlmKGkgPT09IFwiY2xhc3NOYW1lXCIpIHsgaSA9IFwiY2xhc3NcIjsgfVxuXHRcdFx0aWYoaSA9PT0gXCJpbm5lckhUTUxcIikge1xuXHRcdFx0XHRlbGVtZW50Wyd0ZXh0Q29udGVudCddID0gdmFsO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0ZWxlbWVudC5zZXRBdHRyaWJ1dGUoaSwgdmFsKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gZWxlbWVudDtcbn07XG5cbiQucnVuU1ZHQW5pbWF0aW9uID0gKHN2Z19jb250YWluZXIsIGVsZW1lbnRzKSA9PiB7XG5cdC8vIGxldCBwYXJlbnQgPSBlbGVtZW50c1swXVswXVsndW5pdCddLnBhcmVudE5vZGU7XG5cblx0bGV0IG5ld19lbGVtZW50cyA9IFtdO1xuXHRsZXQgYW5pbV9lbGVtZW50cyA9IFtdO1xuXG5cdGVsZW1lbnRzLm1hcChlbGVtZW50ID0+IHtcblx0XHRsZXQgb2JqID0gZWxlbWVudFswXTtcblx0XHRsZXQgcGFyZW50ID0gb2JqLnVuaXQucGFyZW50Tm9kZTtcblx0XHQvLyBsZXQgaW5kZXggPSBsZXQgZmluZE5vZGVJbmRleChvYmoudW5pdCk7XG5cblx0XHRsZXQgYW5pbV9lbGVtZW50LCBuZXdfZWxlbWVudDtcblxuXHRcdGVsZW1lbnRbMF0gPSBvYmoudW5pdDtcblxuXHRcdFthbmltX2VsZW1lbnQsIG5ld19lbGVtZW50XSA9ICQuYW5pbWF0ZVNWRyguLi5lbGVtZW50KTtcblxuXHRcdG5ld19lbGVtZW50cy5wdXNoKG5ld19lbGVtZW50KTtcblx0XHRhbmltX2VsZW1lbnRzLnB1c2goW2FuaW1fZWxlbWVudCwgcGFyZW50XSk7XG5cblx0XHRwYXJlbnQucmVwbGFjZUNoaWxkKGFuaW1fZWxlbWVudCwgb2JqLnVuaXQpO1xuXG5cdFx0aWYob2JqLmFycmF5KSB7XG5cdFx0XHRvYmouYXJyYXlbb2JqLmluZGV4XSA9IG5ld19lbGVtZW50O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRvYmoub2JqZWN0W29iai5rZXldID0gbmV3X2VsZW1lbnQ7XG5cdFx0fVxuXHR9KTtcblxuXHRsZXQgYW5pbV9zdmcgPSBzdmdfY29udGFpbmVyLmNsb25lTm9kZSh0cnVlKTtcblxuXHRhbmltX2VsZW1lbnRzLm1hcCgoYW5pbV9lbGVtZW50LCBpKSA9PiB7XG5cdFx0YW5pbV9lbGVtZW50WzFdLnJlcGxhY2VDaGlsZChuZXdfZWxlbWVudHNbaV0sIGFuaW1fZWxlbWVudFswXSk7XG5cdFx0ZWxlbWVudHNbaV1bMF0gPSBuZXdfZWxlbWVudHNbaV07XG5cdH0pO1xuXG5cdHJldHVybiBhbmltX3N2Zztcbn07XG5cbiQuYW5pbWF0ZVNWRyA9IChlbGVtZW50LCBwcm9wcywgZHVyLCBlYXNpbmdfdHlwZT1cImxpbmVhclwiLCB0eXBlPXVuZGVmaW5lZCwgb2xkX3ZhbHVlcz17fSkgPT4ge1xuXHRsZXQgZWFzaW5nID0ge1xuXHRcdGVhc2U6IFwiMC4yNSAwLjEgMC4yNSAxXCIsXG5cdFx0bGluZWFyOiBcIjAgMCAxIDFcIixcblx0XHQvLyBlYXNlaW46IFwiMC40MiAwIDEgMVwiLFxuXHRcdGVhc2VpbjogXCIwLjEgMC44IDAuMiAxXCIsXG5cdFx0ZWFzZW91dDogXCIwIDAgMC41OCAxXCIsXG5cdFx0ZWFzZWlub3V0OiBcIjAuNDIgMCAwLjU4IDFcIlxuXHR9O1xuXG5cdGxldCBhbmltX2VsZW1lbnQgPSBlbGVtZW50LmNsb25lTm9kZSh0cnVlKTtcblx0bGV0IG5ld19lbGVtZW50ID0gZWxlbWVudC5jbG9uZU5vZGUodHJ1ZSk7XG5cblx0Zm9yKHZhciBhdHRyaWJ1dGVOYW1lIGluIHByb3BzKSB7XG5cdFx0bGV0IGFuaW1hdGVfZWxlbWVudDtcblx0XHRpZihhdHRyaWJ1dGVOYW1lID09PSAndHJhbnNmb3JtJykge1xuXHRcdFx0YW5pbWF0ZV9lbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKFwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiwgXCJhbmltYXRlVHJhbnNmb3JtXCIpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRhbmltYXRlX2VsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50TlMoXCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiLCBcImFuaW1hdGVcIik7XG5cdFx0fVxuXHRcdGxldCBjdXJyZW50X3ZhbHVlID0gb2xkX3ZhbHVlc1thdHRyaWJ1dGVOYW1lXSB8fCBlbGVtZW50LmdldEF0dHJpYnV0ZShhdHRyaWJ1dGVOYW1lKTtcblx0XHRsZXQgdmFsdWUgPSBwcm9wc1thdHRyaWJ1dGVOYW1lXTtcblxuXHRcdGxldCBhbmltX2F0dHIgPSB7XG5cdFx0XHRhdHRyaWJ1dGVOYW1lOiBhdHRyaWJ1dGVOYW1lLFxuXHRcdFx0ZnJvbTogY3VycmVudF92YWx1ZSxcblx0XHRcdHRvOiB2YWx1ZSxcblx0XHRcdGJlZ2luOiBcIjBzXCIsXG5cdFx0XHRkdXI6IGR1ci8xMDAwICsgXCJzXCIsXG5cdFx0XHR2YWx1ZXM6IGN1cnJlbnRfdmFsdWUgKyBcIjtcIiArIHZhbHVlLFxuXHRcdFx0a2V5U3BsaW5lczogZWFzaW5nW2Vhc2luZ190eXBlXSxcblx0XHRcdGtleVRpbWVzOiBcIjA7MVwiLFxuXHRcdFx0Y2FsY01vZGU6IFwic3BsaW5lXCIsXG5cdFx0XHRmaWxsOiAnZnJlZXplJ1xuXHRcdH07XG5cblx0XHRpZih0eXBlKSB7XG5cdFx0XHRhbmltX2F0dHJbXCJ0eXBlXCJdID0gdHlwZTtcblx0XHR9XG5cblx0XHRmb3IgKHZhciBpIGluIGFuaW1fYXR0cikge1xuXHRcdFx0YW5pbWF0ZV9lbGVtZW50LnNldEF0dHJpYnV0ZShpLCBhbmltX2F0dHJbaV0pO1xuXHRcdH1cblxuXHRcdGFuaW1fZWxlbWVudC5hcHBlbmRDaGlsZChhbmltYXRlX2VsZW1lbnQpO1xuXG5cdFx0aWYodHlwZSkge1xuXHRcdFx0bmV3X2VsZW1lbnQuc2V0QXR0cmlidXRlKGF0dHJpYnV0ZU5hbWUsIGB0cmFuc2xhdGUoJHt2YWx1ZX0pYCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdG5ld19lbGVtZW50LnNldEF0dHJpYnV0ZShhdHRyaWJ1dGVOYW1lLCB2YWx1ZSk7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIFthbmltX2VsZW1lbnQsIG5ld19lbGVtZW50XTtcbn07XG5cbiQub2Zmc2V0ID0gKGVsZW1lbnQpID0+IHtcblx0bGV0IHJlY3QgPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXHRyZXR1cm4ge1xuXHRcdC8vIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS83NDM2NjAyLzY0OTUwNDNcblx0XHQvLyByZWN0LnRvcCB2YXJpZXMgd2l0aCBzY3JvbGwsIHNvIHdlIGFkZCB3aGF0ZXZlciBoYXMgYmVlblxuXHRcdC8vIHNjcm9sbGVkIHRvIGl0IHRvIGdldCBhYnNvbHV0ZSBkaXN0YW5jZSBmcm9tIGFjdHVhbCBwYWdlIHRvcFxuXHRcdHRvcDogcmVjdC50b3AgKyAoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbFRvcCB8fCBkb2N1bWVudC5ib2R5LnNjcm9sbFRvcCksXG5cdFx0bGVmdDogcmVjdC5sZWZ0ICsgKGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxMZWZ0IHx8IGRvY3VtZW50LmJvZHkuc2Nyb2xsTGVmdClcblx0fTtcbn07XG5cbiQuaXNFbGVtZW50SW5WaWV3cG9ydCA9IChlbCkgPT4ge1xuXHQvLyBBbHRob3VnaCBzdHJhaWdodGZvcndhcmQ6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS83NTU3NDMzLzY0OTUwNDNcblx0dmFyIHJlY3QgPSBlbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcblxuXHRyZXR1cm4gKFxuXHRcdHJlY3QudG9wID49IDAgJiZcbiAgICAgICAgcmVjdC5sZWZ0ID49IDAgJiZcbiAgICAgICAgcmVjdC5ib3R0b20gPD0gKHdpbmRvdy5pbm5lckhlaWdodCB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50SGVpZ2h0KSAmJiAvKm9yICQod2luZG93KS5oZWlnaHQoKSAqL1xuICAgICAgICByZWN0LnJpZ2h0IDw9ICh3aW5kb3cuaW5uZXJXaWR0aCB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50V2lkdGgpIC8qb3IgJCh3aW5kb3cpLndpZHRoKCkgKi9cblx0KTtcbn07XG5cbiQuYmluZCA9IChlbGVtZW50LCBvKSA9PiB7XG5cdGlmIChlbGVtZW50KSB7XG5cdFx0Zm9yICh2YXIgZXZlbnQgaW4gbykge1xuXHRcdFx0dmFyIGNhbGxiYWNrID0gb1tldmVudF07XG5cblx0XHRcdGV2ZW50LnNwbGl0KC9cXHMrLykuZm9yRWFjaChmdW5jdGlvbiAoZXZlbnQpIHtcblx0XHRcdFx0ZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKGV2ZW50LCBjYWxsYmFjayk7XG5cdFx0XHR9KTtcblx0XHR9XG5cdH1cbn07XG5cbiQudW5iaW5kID0gKGVsZW1lbnQsIG8pID0+IHtcblx0aWYgKGVsZW1lbnQpIHtcblx0XHRmb3IgKHZhciBldmVudCBpbiBvKSB7XG5cdFx0XHR2YXIgY2FsbGJhY2sgPSBvW2V2ZW50XTtcblxuXHRcdFx0ZXZlbnQuc3BsaXQoL1xccysvKS5mb3JFYWNoKGZ1bmN0aW9uKGV2ZW50KSB7XG5cdFx0XHRcdGVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudCwgY2FsbGJhY2spO1xuXHRcdFx0fSk7XG5cdFx0fVxuXHR9XG59O1xuXG4kLmZpcmUgPSAodGFyZ2V0LCB0eXBlLCBwcm9wZXJ0aWVzKSA9PiB7XG5cdHZhciBldnQgPSBkb2N1bWVudC5jcmVhdGVFdmVudChcIkhUTUxFdmVudHNcIik7XG5cblx0ZXZ0LmluaXRFdmVudCh0eXBlLCB0cnVlLCB0cnVlICk7XG5cblx0Zm9yICh2YXIgaiBpbiBwcm9wZXJ0aWVzKSB7XG5cdFx0ZXZ0W2pdID0gcHJvcGVydGllc1tqXTtcblx0fVxuXG5cdHJldHVybiB0YXJnZXQuZGlzcGF0Y2hFdmVudChldnQpO1xufTtcbiIsImV4cG9ydCBmdW5jdGlvbiBmbG9hdF8yKGQpIHtcblx0cmV0dXJuIHBhcnNlRmxvYXQoZC50b0ZpeGVkKDIpKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGFycmF5c19lcXVhbChhcnIxLCBhcnIyKSB7XG5cdGlmKGFycjEubGVuZ3RoICE9PSBhcnIyLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuXHRsZXQgYXJlX2VxdWFsID0gdHJ1ZTtcblx0YXJyMS5tYXAoKGQsIGkpID0+IHtcblx0XHRpZihhcnIyW2ldICE9PSBkKSBhcmVfZXF1YWwgPSBmYWxzZTtcblx0fSk7XG5cdHJldHVybiBhcmVfZXF1YWw7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzaHVmZmxlKGFycmF5KSB7XG5cdC8vIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8yNDUwOTc2LzY0OTUwNDNcblx0Ly8gQXdlc29tZW5lc3M6IGh0dHBzOi8vYm9zdC5vY2tzLm9yZy9taWtlL3NodWZmbGUvXG5cblx0dmFyIGN1cnJlbnRJbmRleCA9IGFycmF5Lmxlbmd0aCwgdGVtcG9yYXJ5VmFsdWUsIHJhbmRvbUluZGV4O1xuXG5cdC8vIFdoaWxlIHRoZXJlIHJlbWFpbiBlbGVtZW50cyB0byBzaHVmZmxlLi4uXG5cdHdoaWxlICgwICE9PSBjdXJyZW50SW5kZXgpIHtcblxuXHRcdC8vIFBpY2sgYSByZW1haW5pbmcgZWxlbWVudC4uLlxuXHRcdHJhbmRvbUluZGV4ID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogY3VycmVudEluZGV4KTtcblx0XHRjdXJyZW50SW5kZXggLT0gMTtcblxuXHRcdC8vIEFuZCBzd2FwIGl0IHdpdGggdGhlIGN1cnJlbnQgZWxlbWVudC5cblx0XHR0ZW1wb3JhcnlWYWx1ZSA9IGFycmF5W2N1cnJlbnRJbmRleF07XG5cdFx0YXJyYXlbY3VycmVudEluZGV4XSA9IGFycmF5W3JhbmRvbUluZGV4XTtcblx0XHRhcnJheVtyYW5kb21JbmRleF0gPSB0ZW1wb3JhcnlWYWx1ZTtcblx0fVxuXG5cdHJldHVybiBhcnJheTtcbn1cbiIsImltcG9ydCAkIGZyb20gJy4vZG9tJztcbmltcG9ydCB7IGZsb2F0XzIsIGFycmF5c19lcXVhbCB9IGZyb20gJy4vdXRpbHMnO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBDaGFydCB7XG5cdGNvbnN0cnVjdG9yKHtcblx0XHRwYXJlbnQgPSBcIlwiLFxuXHRcdGhlaWdodCA9IDI0MCxcblxuXHRcdHRpdGxlID0gJycsIHN1YnRpdGxlID0gJycsXG5cblx0XHRkYXRhID0ge30sXG5cdFx0Zm9ybWF0X2xhbWJkYXMgPSB7fSxcblxuXHRcdHN1bW1hcnkgPSBbXSxcblxuXHRcdGlzX25hdmlnYWJsZSA9IDAsXG5cblx0XHR0eXBlID0gJydcblx0fSkge1xuXHRcdGlmKE9iamVjdC5nZXRQcm90b3R5cGVPZih0aGlzKSA9PT0gQ2hhcnQucHJvdG90eXBlKSB7XG5cdFx0XHRpZih0eXBlID09PSAnbGluZScpIHtcblx0XHRcdFx0cmV0dXJuIG5ldyBMaW5lQ2hhcnQoYXJndW1lbnRzWzBdKTtcblx0XHRcdH0gZWxzZSBpZih0eXBlID09PSAnYmFyJykge1xuXHRcdFx0XHRyZXR1cm4gbmV3IEJhckNoYXJ0KGFyZ3VtZW50c1swXSk7XG5cdFx0XHR9IGVsc2UgaWYodHlwZSA9PT0gJ3BlcmNlbnRhZ2UnKSB7XG5cdFx0XHRcdHJldHVybiBuZXcgUGVyY2VudGFnZUNoYXJ0KGFyZ3VtZW50c1swXSk7XG5cdFx0XHR9IGVsc2UgaWYodHlwZSA9PT0gJ2hlYXRtYXAnKSB7XG5cdFx0XHRcdHJldHVybiBuZXcgSGVhdE1hcChhcmd1bWVudHNbMF0pO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmV0dXJuIG5ldyBMaW5lQ2hhcnQoYXJndW1lbnRzWzBdKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLnJhd19jaGFydF9hcmdzID0gYXJndW1lbnRzWzBdO1xuXG5cdFx0dGhpcy5wYXJlbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHBhcmVudCk7XG5cdFx0dGhpcy50aXRsZSA9IHRpdGxlO1xuXHRcdHRoaXMuc3VidGl0bGUgPSBzdWJ0aXRsZTtcblxuXHRcdHRoaXMuZGF0YSA9IGRhdGE7XG5cdFx0dGhpcy5mb3JtYXRfbGFtYmRhcyA9IGZvcm1hdF9sYW1iZGFzO1xuXG5cdFx0dGhpcy5zcGVjaWZpY192YWx1ZXMgPSBkYXRhLnNwZWNpZmljX3ZhbHVlcyB8fCBbXTtcblx0XHR0aGlzLnN1bW1hcnkgPSBzdW1tYXJ5O1xuXG5cdFx0dGhpcy5pc19uYXZpZ2FibGUgPSBpc19uYXZpZ2FibGU7XG5cdFx0aWYodGhpcy5pc19uYXZpZ2FibGUpIHtcblx0XHRcdHRoaXMuY3VycmVudF9pbmRleCA9IDA7XG5cdFx0fVxuXG5cdFx0dGhpcy5jaGFydF90eXBlcyA9IFsnbGluZScsICdiYXInLCAncGVyY2VudGFnZScsICdoZWF0bWFwJ107XG5cblx0XHR0aGlzLnNldF9tYXJnaW5zKGhlaWdodCk7XG5cdH1cblxuXHRnZXRfZGlmZmVyZW50X2NoYXJ0KHR5cGUpIHtcblx0XHRpZighdGhpcy5jaGFydF90eXBlcy5pbmNsdWRlcyh0eXBlKSkge1xuXHRcdFx0Y29uc29sZS5lcnJvcihgJyR7dHlwZX0nIGlzIG5vdCBhIHZhbGlkIGNoYXJ0IHR5cGUuYCk7XG5cdFx0fVxuXHRcdGlmKHR5cGUgPT09IHRoaXMudHlwZSkgcmV0dXJuO1xuXG5cdFx0Ly8gT25seSBhY3Jvc3MgY29tcGF0aWJsZSB0eXBlc1xuXHRcdGxldCBjb21wYXRpYmxlX3R5cGVzID0ge1xuXHRcdFx0YmFyOiBbJ2xpbmUnLCAncGVyY2VudGFnZSddLFxuXHRcdFx0bGluZTogWydiYXInLCAncGVyY2VudGFnZSddLFxuXHRcdFx0cGVyY2VudGFnZTogWydiYXInLCAnbGluZSddLFxuXHRcdFx0aGVhdG1hcDogW11cblx0XHR9O1xuXG5cdFx0aWYoIWNvbXBhdGlibGVfdHlwZXNbdGhpcy50eXBlXS5pbmNsdWRlcyh0eXBlKSkge1xuXHRcdFx0Y29uc29sZS5lcnJvcihgJyR7dGhpcy50eXBlfScgY2hhcnQgY2Fubm90IGJlIGNvbnZlcnRlZCB0byBhICcke3R5cGV9JyBjaGFydC5gKTtcblx0XHR9XG5cblx0XHQvLyBPa2F5LCB0aGlzIGlzIGFudGljbGltYWN0aWNcblx0XHQvLyB0aGlzIGZ1bmN0aW9uIHdpbGwgbmVlZCB0byBhY3R1YWxseSBiZSAnY2hhbmdlX2NoYXJ0X3R5cGUodHlwZSknXG5cdFx0Ly8gdGhhdCB3aWxsIHVwZGF0ZSBvbmx5IHRoZSByZXF1aXJlZCBlbGVtZW50cywgYnV0IGZvciBub3cgLi4uXG5cdFx0cmV0dXJuIG5ldyBDaGFydCh7XG5cdFx0XHRwYXJlbnQ6IHRoaXMucmF3X2NoYXJ0X2FyZ3MucGFyZW50LFxuXHRcdFx0ZGF0YTogdGhpcy5yYXdfY2hhcnRfYXJncy5kYXRhLFxuXHRcdFx0dHlwZTogdHlwZSxcblx0XHRcdGhlaWdodDogdGhpcy5yYXdfY2hhcnRfYXJncy5oZWlnaHRcblx0XHR9KTtcblx0fVxuXG5cdHNldF9tYXJnaW5zKGhlaWdodCkge1xuXHRcdHRoaXMuYmFzZV9oZWlnaHQgPSBoZWlnaHQ7XG5cdFx0dGhpcy5oZWlnaHQgPSBoZWlnaHQgLSA0MDtcblx0XHR0aGlzLnRyYW5zbGF0ZV94ID0gNjA7XG5cdFx0dGhpcy50cmFuc2xhdGVfeSA9IDEwO1xuXHR9XG5cblx0c2V0dXAoKSB7XG5cdFx0dGhpcy5iaW5kX3dpbmRvd19ldmVudHMoKTtcblx0XHR0aGlzLnJlZnJlc2godHJ1ZSk7XG5cdH1cblxuXHRiaW5kX3dpbmRvd19ldmVudHMoKSB7XG5cdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHRoaXMucmVmcmVzaCgpKTtcblx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignb3JpZW50YXRpb25jaGFuZ2UnLCAoKSA9PiB0aGlzLnJlZnJlc2goKSk7XG5cdH1cblxuXHRyZWZyZXNoKGluaXQ9ZmFsc2UpIHtcblx0XHR0aGlzLnNldHVwX2Jhc2VfdmFsdWVzKCk7XG5cdFx0dGhpcy5zZXRfd2lkdGgoKTtcblxuXHRcdHRoaXMuc2V0dXBfY29udGFpbmVyKCk7XG5cdFx0dGhpcy5zZXR1cF9jb21wb25lbnRzKCk7XG5cblx0XHR0aGlzLnNldHVwX3ZhbHVlcygpO1xuXHRcdHRoaXMuc2V0dXBfdXRpbHMoKTtcblxuXHRcdHRoaXMubWFrZV9ncmFwaF9jb21wb25lbnRzKGluaXQpO1xuXHRcdHRoaXMubWFrZV90b29sdGlwKCk7XG5cblx0XHRpZih0aGlzLnN1bW1hcnkubGVuZ3RoID4gMCkge1xuXHRcdFx0dGhpcy5zaG93X2N1c3RvbV9zdW1tYXJ5KCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuc2hvd19zdW1tYXJ5KCk7XG5cdFx0fVxuXG5cdFx0aWYodGhpcy5pc19uYXZpZ2FibGUpIHtcblx0XHRcdHRoaXMuc2V0dXBfbmF2aWdhdGlvbihpbml0KTtcblx0XHR9XG5cdH1cblxuXHRzZXRfd2lkdGgoKSB7XG5cdFx0bGV0IHNwZWNpYWxfdmFsdWVzX3dpZHRoID0gMDtcblx0XHR0aGlzLnNwZWNpZmljX3ZhbHVlcy5tYXAodmFsID0+IHtcblx0XHRcdGlmKHRoaXMuZ2V0X3N0cndpZHRoKHZhbC50aXRsZSkgPiBzcGVjaWFsX3ZhbHVlc193aWR0aCkge1xuXHRcdFx0XHRzcGVjaWFsX3ZhbHVlc193aWR0aCA9IHRoaXMuZ2V0X3N0cndpZHRoKHZhbC50aXRsZSkgLSA0MDtcblx0XHRcdH1cblx0XHR9KTtcblx0XHR0aGlzLmJhc2Vfd2lkdGggPSB0aGlzLnBhcmVudC5vZmZzZXRXaWR0aCAtIHNwZWNpYWxfdmFsdWVzX3dpZHRoO1xuXHRcdHRoaXMud2lkdGggPSB0aGlzLmJhc2Vfd2lkdGggLSB0aGlzLnRyYW5zbGF0ZV94ICogMjtcblx0fVxuXG5cdHNldHVwX2Jhc2VfdmFsdWVzKCkge31cblxuXHRzZXR1cF9jb250YWluZXIoKSB7XG5cdFx0dGhpcy5jb250YWluZXIgPSAkLmNyZWF0ZSgnZGl2Jywge1xuXHRcdFx0Y2xhc3NOYW1lOiAnY2hhcnQtY29udGFpbmVyJyxcblx0XHRcdGlubmVySFRNTDogYDxoNiBjbGFzcz1cInRpdGxlXCIgc3R5bGU9XCJtYXJnaW4tdG9wOiAxNXB4O1wiPiR7dGhpcy50aXRsZX08L2g2PlxuXHRcdFx0XHQ8aDYgY2xhc3M9XCJzdWItdGl0bGUgdXBwZXJjYXNlXCI+JHt0aGlzLnN1YnRpdGxlfTwvaDY+XG5cdFx0XHRcdDxkaXYgY2xhc3M9XCJmcmFwcGUtY2hhcnQgZ3JhcGhpY3NcIj48L2Rpdj5cblx0XHRcdFx0PGRpdiBjbGFzcz1cImdyYXBoLXN0YXRzLWNvbnRhaW5lclwiPjwvZGl2PmBcblx0XHR9KTtcblxuXHRcdC8vIENoYXJ0IG5lZWRzIGEgZGVkaWNhdGVkIHBhcmVudCBlbGVtZW50XG5cdFx0dGhpcy5wYXJlbnQuaW5uZXJIVE1MID0gJyc7XG5cdFx0dGhpcy5wYXJlbnQuYXBwZW5kQ2hpbGQodGhpcy5jb250YWluZXIpO1xuXG5cdFx0dGhpcy5jaGFydF93cmFwcGVyID0gdGhpcy5jb250YWluZXIucXVlcnlTZWxlY3RvcignLmZyYXBwZS1jaGFydCcpO1xuXHRcdHRoaXMuc3RhdHNfd3JhcHBlciA9IHRoaXMuY29udGFpbmVyLnF1ZXJ5U2VsZWN0b3IoJy5ncmFwaC1zdGF0cy1jb250YWluZXInKTtcblxuXHRcdHRoaXMubWFrZV9jaGFydF9hcmVhKCk7XG5cdFx0dGhpcy5tYWtlX2RyYXdfYXJlYSgpO1xuXHR9XG5cblx0bWFrZV9jaGFydF9hcmVhKCkge1xuXHRcdHRoaXMuc3ZnID0gJC5jcmVhdGVTVkcoJ3N2ZycsIHtcblx0XHRcdGNsYXNzTmFtZTogJ2NoYXJ0Jyxcblx0XHRcdGluc2lkZTogdGhpcy5jaGFydF93cmFwcGVyLFxuXHRcdFx0d2lkdGg6IHRoaXMuYmFzZV93aWR0aCxcblx0XHRcdGhlaWdodDogdGhpcy5iYXNlX2hlaWdodFxuXHRcdH0pO1xuXG5cdFx0dGhpcy5zdmdfZGVmcyA9ICQuY3JlYXRlU1ZHKCdkZWZzJywge1xuXHRcdFx0aW5zaWRlOiB0aGlzLnN2Zyxcblx0XHR9KTtcblxuXHRcdHJldHVybiB0aGlzLnN2Zztcblx0fVxuXG5cdG1ha2VfZHJhd19hcmVhKCkge1xuXHRcdHRoaXMuZHJhd19hcmVhID0gJC5jcmVhdGVTVkcoXCJnXCIsIHtcblx0XHRcdGNsYXNzTmFtZTogdGhpcy50eXBlICsgJy1jaGFydCcsXG5cdFx0XHRpbnNpZGU6IHRoaXMuc3ZnLFxuXHRcdFx0dHJhbnNmb3JtOiBgdHJhbnNsYXRlKCR7dGhpcy50cmFuc2xhdGVfeH0sICR7dGhpcy50cmFuc2xhdGVfeX0pYFxuXHRcdH0pO1xuXHR9XG5cblx0c2V0dXBfY29tcG9uZW50cygpIHsgfVxuXG5cdG1ha2VfdG9vbHRpcCgpIHtcblx0XHR0aGlzLnRpcCA9IG5ldyBTdmdUaXAoe1xuXHRcdFx0cGFyZW50OiB0aGlzLmNoYXJ0X3dyYXBwZXIsXG5cdFx0fSk7XG5cdFx0dGhpcy5iaW5kX3Rvb2x0aXAoKTtcblx0fVxuXG5cblx0c2hvd19zdW1tYXJ5KCkge31cblx0c2hvd19jdXN0b21fc3VtbWFyeSgpIHtcblx0XHR0aGlzLnN1bW1hcnkubWFwKGQgPT4ge1xuXHRcdFx0bGV0IHN0YXRzID0gJC5jcmVhdGUoJ2RpdicsIHtcblx0XHRcdFx0Y2xhc3NOYW1lOiAnc3RhdHMnLFxuXHRcdFx0XHRpbm5lckhUTUw6IGA8c3BhbiBjbGFzcz1cImluZGljYXRvciAke2QuY29sb3J9XCI+JHtkLnRpdGxlfTogJHtkLnZhbHVlfTwvc3Bhbj5gXG5cdFx0XHR9KTtcblx0XHRcdHRoaXMuc3RhdHNfd3JhcHBlci5hcHBlbmRDaGlsZChzdGF0cyk7XG5cdFx0fSk7XG5cdH1cblxuXHRzZXR1cF9uYXZpZ2F0aW9uKGluaXQ9ZmFsc2UpIHtcblx0XHR0aGlzLm1ha2Vfb3ZlcmxheSgpO1xuXG5cdFx0aWYoaW5pdCkge1xuXHRcdFx0dGhpcy5iaW5kX292ZXJsYXkoKTtcblxuXHRcdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIChlKSA9PiB7XG5cdFx0XHRcdGlmKCQuaXNFbGVtZW50SW5WaWV3cG9ydCh0aGlzLmNoYXJ0X3dyYXBwZXIpKSB7XG5cdFx0XHRcdFx0ZSA9IGUgfHwgd2luZG93LmV2ZW50O1xuXG5cdFx0XHRcdFx0aWYgKGUua2V5Q29kZSA9PSAnMzcnKSB7XG5cdFx0XHRcdFx0XHR0aGlzLm9uX2xlZnRfYXJyb3coKTtcblx0XHRcdFx0XHR9IGVsc2UgaWYgKGUua2V5Q29kZSA9PSAnMzknKSB7XG5cdFx0XHRcdFx0XHR0aGlzLm9uX3JpZ2h0X2Fycm93KCk7XG5cdFx0XHRcdFx0fSBlbHNlIGlmIChlLmtleUNvZGUgPT0gJzM4Jykge1xuXHRcdFx0XHRcdFx0dGhpcy5vbl91cF9hcnJvdygpO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoZS5rZXlDb2RlID09ICc0MCcpIHtcblx0XHRcdFx0XHRcdHRoaXMub25fZG93bl9hcnJvdygpO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoZS5rZXlDb2RlID09ICcxMycpIHtcblx0XHRcdFx0XHRcdHRoaXMub25fZW50ZXJfa2V5KCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHR9XG5cdH1cblxuXHRtYWtlX292ZXJsYXkoKSB7fVxuXHRiaW5kX292ZXJsYXkoKSB7fVxuXG5cdG9uX2xlZnRfYXJyb3coKSB7fVxuXHRvbl9yaWdodF9hcnJvdygpIHt9XG5cdG9uX3VwX2Fycm93KCkge31cblx0b25fZG93bl9hcnJvdygpIHt9XG5cdG9uX2VudGVyX2tleSgpIHt9XG5cblx0Z2V0X2RhdGFfcG9pbnQoaW5kZXg9dGhpcy5jdXJyZW50X2luZGV4KSB7XG5cdFx0Ly8gY2hlY2sgZm9yIGxlbmd0aFxuXHRcdGxldCBkYXRhX3BvaW50ID0ge1xuXHRcdFx0aW5kZXg6IGluZGV4XG5cdFx0fTtcblx0XHRsZXQgeSA9IHRoaXMueVswXTtcblx0XHRbJ3N2Z191bml0cycsICd5X3RvcHMnLCAndmFsdWVzJ10ubWFwKGtleSA9PiB7XG5cdFx0XHRsZXQgZGF0YV9rZXkgPSBrZXkuc2xpY2UoMCwga2V5Lmxlbmd0aC0xKTtcblx0XHRcdGRhdGFfcG9pbnRbZGF0YV9rZXldID0geVtrZXldW2luZGV4XTtcblx0XHR9KTtcblx0XHRkYXRhX3BvaW50LmxhYmVsID0gdGhpcy54W2luZGV4XTtcblx0XHRyZXR1cm4gZGF0YV9wb2ludDtcblx0fVxuXG5cdHVwZGF0ZV9jdXJyZW50X2RhdGFfcG9pbnQoaW5kZXgpIHtcblx0XHRpZihpbmRleCA8IDApIGluZGV4ID0gMDtcblx0XHRpZihpbmRleCA+PSB0aGlzLngubGVuZ3RoKSBpbmRleCA9IHRoaXMueC5sZW5ndGggLSAxO1xuXHRcdGlmKGluZGV4ID09PSB0aGlzLmN1cnJlbnRfaW5kZXgpIHJldHVybjtcblx0XHR0aGlzLmN1cnJlbnRfaW5kZXggPSBpbmRleDtcblx0XHQkLmZpcmUodGhpcy5wYXJlbnQsIFwiZGF0YS1zZWxlY3RcIiwgdGhpcy5nZXRfZGF0YV9wb2ludCgpKTtcblx0fVxuXG5cdC8vIEhlbHBlcnNcblx0Z2V0X3N0cndpZHRoKHN0cmluZykge1xuXHRcdHJldHVybiBzdHJpbmcubGVuZ3RoICogODtcblx0fVxuXG5cdC8vIE9iamVjdHNcblx0c2V0dXBfdXRpbHMoKSB7IH1cbn1cblxuY2xhc3MgQXhpc0NoYXJ0IGV4dGVuZHMgQ2hhcnQge1xuXHRjb25zdHJ1Y3RvcihhcmdzKSB7XG5cdFx0c3VwZXIoYXJncyk7XG5cblx0XHR0aGlzLnggPSB0aGlzLmRhdGEubGFiZWxzO1xuXHRcdHRoaXMueSA9IHRoaXMuZGF0YS5kYXRhc2V0cztcblxuXHRcdHRoaXMuZ2V0X3lfbGFiZWwgPSB0aGlzLmZvcm1hdF9sYW1iZGFzLnlfbGFiZWw7XG5cdFx0dGhpcy5nZXRfeV90b29sdGlwID0gdGhpcy5mb3JtYXRfbGFtYmRhcy55X3Rvb2x0aXA7XG5cdFx0dGhpcy5nZXRfeF90b29sdGlwID0gdGhpcy5mb3JtYXRfbGFtYmRhcy54X3Rvb2x0aXA7XG5cblx0XHR0aGlzLmNvbG9ycyA9IFsnZ3JlZW4nLCAnYmx1ZScsICd2aW9sZXQnLCAncmVkJywgJ29yYW5nZScsXG5cdFx0XHQneWVsbG93JywgJ2xpZ2h0LWJsdWUnLCAnbGlnaHQtZ3JlZW4nLCAncHVycGxlJywgJ21hZ2VudGEnXTtcblxuXHRcdHRoaXMuemVyb19saW5lID0gdGhpcy5oZWlnaHQ7XG5cdH1cblxuXHRzZXR1cF92YWx1ZXMoKSB7XG5cdFx0dGhpcy5kYXRhLmRhdGFzZXRzLm1hcChkID0+IHtcblx0XHRcdGQudmFsdWVzID0gZC52YWx1ZXMubWFwKHZhbCA9PiAoIWlzTmFOKHZhbCkgPyB2YWwgOiAwKSk7XG5cdFx0fSk7XG5cdFx0dGhpcy5zZXR1cF94KCk7XG5cdFx0dGhpcy5zZXR1cF95KCk7XG5cdH1cblxuXHRzZXR1cF94KCkge1xuXHRcdHRoaXMuc2V0X2F2Z191bml0X3dpZHRoX2FuZF94X29mZnNldCgpO1xuXG5cdFx0aWYodGhpcy54X2F4aXNfcG9zaXRpb25zKSB7XG5cdFx0XHR0aGlzLnhfb2xkX2F4aXNfcG9zaXRpb25zID0gIHRoaXMueF9heGlzX3Bvc2l0aW9ucy5zbGljZSgpO1xuXHRcdH1cblx0XHR0aGlzLnhfYXhpc19wb3NpdGlvbnMgPSB0aGlzLngubWFwKChkLCBpKSA9PlxuXHRcdFx0ZmxvYXRfMih0aGlzLnhfb2Zmc2V0ICsgaSAqIHRoaXMuYXZnX3VuaXRfd2lkdGgpKTtcblxuXHRcdGlmKCF0aGlzLnhfb2xkX2F4aXNfcG9zaXRpb25zKSB7XG5cdFx0XHR0aGlzLnhfb2xkX2F4aXNfcG9zaXRpb25zID0gdGhpcy54X2F4aXNfcG9zaXRpb25zLnNsaWNlKCk7XG5cdFx0fVxuXHR9XG5cblx0c2V0dXBfeSgpIHtcblx0XHRpZih0aGlzLnlfYXhpc192YWx1ZXMpIHtcblx0XHRcdHRoaXMueV9vbGRfYXhpc192YWx1ZXMgPSAgdGhpcy55X2F4aXNfdmFsdWVzLnNsaWNlKCk7XG5cdFx0fVxuXG5cdFx0bGV0IHZhbHVlcyA9IHRoaXMuZ2V0X2FsbF95X3ZhbHVlcygpO1xuXG5cdFx0aWYodGhpcy55X3N1bXMgJiYgdGhpcy55X3N1bXMubGVuZ3RoID4gMCkge1xuXHRcdFx0dmFsdWVzID0gdmFsdWVzLmNvbmNhdCh0aGlzLnlfc3Vtcyk7XG5cdFx0fVxuXG5cdFx0dGhpcy55X2F4aXNfdmFsdWVzID0gdGhpcy5nZXRfeV9heGlzX3BvaW50cyh2YWx1ZXMpO1xuXG5cdFx0aWYoIXRoaXMueV9vbGRfYXhpc192YWx1ZXMpIHtcblx0XHRcdHRoaXMueV9vbGRfYXhpc192YWx1ZXMgPSB0aGlzLnlfYXhpc192YWx1ZXMuc2xpY2UoKTtcblx0XHR9XG5cblx0XHRjb25zdCB5X3B0cyA9IHRoaXMueV9heGlzX3ZhbHVlcztcblx0XHRjb25zdCB2YWx1ZV9yYW5nZSA9IHlfcHRzW3lfcHRzLmxlbmd0aC0xXSAtIHlfcHRzWzBdO1xuXG5cdFx0aWYodGhpcy5tdWx0aXBsaWVyKSB0aGlzLm9sZF9tdWx0aXBsaWVyID0gdGhpcy5tdWx0aXBsaWVyO1xuXHRcdHRoaXMubXVsdGlwbGllciA9IHRoaXMuaGVpZ2h0IC8gdmFsdWVfcmFuZ2U7XG5cdFx0aWYoIXRoaXMub2xkX211bHRpcGxpZXIpIHRoaXMub2xkX211bHRpcGxpZXIgPSB0aGlzLm11bHRpcGxpZXI7XG5cblx0XHRjb25zdCB6ZXJvX2luZGV4ID0geV9wdHMuaW5kZXhPZigwKTtcblx0XHRjb25zdCBpbnRlcnZhbCA9IHlfcHRzWzFdIC0geV9wdHNbMF07XG5cdFx0Y29uc3QgaW50ZXJ2YWxfaGVpZ2h0ID0gaW50ZXJ2YWwgKiB0aGlzLm11bHRpcGxpZXI7XG5cblx0XHRpZih0aGlzLnplcm9fbGluZSkgdGhpcy5vbGRfemVyb19saW5lID0gdGhpcy56ZXJvX2xpbmU7XG5cdFx0dGhpcy56ZXJvX2xpbmUgPSB0aGlzLmhlaWdodCAtICh6ZXJvX2luZGV4ICogaW50ZXJ2YWxfaGVpZ2h0KTtcblx0XHRpZighdGhpcy5vbGRfemVyb19saW5lKSB0aGlzLm9sZF96ZXJvX2xpbmUgPSB0aGlzLnplcm9fbGluZTtcblx0fVxuXG5cdHNldHVwX2NvbXBvbmVudHMoKSB7XG5cdFx0c3VwZXIuc2V0dXBfY29tcG9uZW50cygpO1xuXHRcdHRoaXMuc2V0dXBfbWFya2VyX2NvbXBvbmVudHMoKTtcblx0XHR0aGlzLnNldHVwX2FnZ3JlZ2F0aW9uX2NvbXBvbmVudHMoKTtcblx0XHR0aGlzLnNldHVwX2dyYXBoX2NvbXBvbmVudHMoKTtcblx0fVxuXG5cdHNldHVwX21hcmtlcl9jb21wb25lbnRzKCkge1xuXHRcdHRoaXMueV9heGlzX2dyb3VwID0gJC5jcmVhdGVTVkcoJ2cnLCB7Y2xhc3NOYW1lOiAneSBheGlzJywgaW5zaWRlOiB0aGlzLmRyYXdfYXJlYX0pO1xuXHRcdHRoaXMueF9heGlzX2dyb3VwID0gJC5jcmVhdGVTVkcoJ2cnLCB7Y2xhc3NOYW1lOiAneCBheGlzJywgaW5zaWRlOiB0aGlzLmRyYXdfYXJlYX0pO1xuXHRcdHRoaXMuc3BlY2lmaWNfeV9ncm91cCA9ICQuY3JlYXRlU1ZHKCdnJywge2NsYXNzTmFtZTogJ3NwZWNpZmljIGF4aXMnLCBpbnNpZGU6IHRoaXMuZHJhd19hcmVhfSk7XG5cdH1cblxuXHRzZXR1cF9hZ2dyZWdhdGlvbl9jb21wb25lbnRzKCkge1xuXHRcdHRoaXMuc3VtX2dyb3VwID0gJC5jcmVhdGVTVkcoJ2cnLCB7Y2xhc3NOYW1lOiAnZGF0YS1wb2ludHMnLCBpbnNpZGU6IHRoaXMuZHJhd19hcmVhfSk7XG5cdFx0dGhpcy5hdmVyYWdlX2dyb3VwID0gJC5jcmVhdGVTVkcoJ2cnLCB7Y2xhc3NOYW1lOiAnY2hhcnQtYXJlYScsIGluc2lkZTogdGhpcy5kcmF3X2FyZWF9KTtcblx0fVxuXG5cdHNldHVwX2dyYXBoX2NvbXBvbmVudHMoKSB7XG5cdFx0dGhpcy5zdmdfdW5pdHNfZ3JvdXBzID0gW107XG5cdFx0dGhpcy55Lm1hcCgoZCwgaSkgPT4ge1xuXHRcdFx0dGhpcy5zdmdfdW5pdHNfZ3JvdXBzW2ldID0gJC5jcmVhdGVTVkcoJ2cnLCB7XG5cdFx0XHRcdGNsYXNzTmFtZTogJ2RhdGEtcG9pbnRzIGRhdGEtcG9pbnRzLScgKyBpLFxuXHRcdFx0XHRpbnNpZGU6IHRoaXMuZHJhd19hcmVhXG5cdFx0XHR9KTtcblx0XHR9KTtcblx0fVxuXG5cdG1ha2VfZ3JhcGhfY29tcG9uZW50cyhpbml0PWZhbHNlKSB7XG5cdFx0dGhpcy5tYWtlX3lfYXhpcygpO1xuXHRcdHRoaXMubWFrZV94X2F4aXMoKTtcblx0XHR0aGlzLmRyYXdfZ3JhcGgoaW5pdCk7XG5cdFx0dGhpcy5tYWtlX3lfc3BlY2lmaWNzKCk7XG5cdH1cblxuXHQvLyBtYWtlIFZFUlRJQ0FMIGxpbmVzIGZvciB4IHZhbHVlc1xuXHRtYWtlX3hfYXhpcyhhbmltYXRlPWZhbHNlKSB7XG5cdFx0bGV0IHN0YXJ0X2F0LCBoZWlnaHQsIHRleHRfc3RhcnRfYXQsIGF4aXNfbGluZV9jbGFzcyA9ICcnO1xuXHRcdGlmKHRoaXMueF9heGlzX21vZGUgPT09ICdzcGFuJykge1x0XHQvLyBsb25nIHNwYW5uaW5nIGxpbmVzXG5cdFx0XHRzdGFydF9hdCA9IC03O1xuXHRcdFx0aGVpZ2h0ID0gdGhpcy5oZWlnaHQgKyAxNTtcblx0XHRcdHRleHRfc3RhcnRfYXQgPSB0aGlzLmhlaWdodCArIDI1O1xuXHRcdH0gZWxzZSBpZih0aGlzLnhfYXhpc19tb2RlID09PSAndGljaycpe1x0Ly8gc2hvcnQgbGFiZWwgbGluZXNcblx0XHRcdHN0YXJ0X2F0ID0gdGhpcy5oZWlnaHQ7XG5cdFx0XHRoZWlnaHQgPSA2O1xuXHRcdFx0dGV4dF9zdGFydF9hdCA9IDk7XG5cdFx0XHRheGlzX2xpbmVfY2xhc3MgPSAneC1heGlzLWxhYmVsJztcblx0XHR9XG5cblx0XHR0aGlzLnhfYXhpc19ncm91cC5zZXRBdHRyaWJ1dGUoJ3RyYW5zZm9ybScsIGB0cmFuc2xhdGUoMCwke3N0YXJ0X2F0fSlgKTtcblxuXHRcdGlmKGFuaW1hdGUpIHtcblx0XHRcdHRoaXMubWFrZV9hbmltX3hfYXhpcyhoZWlnaHQsIHRleHRfc3RhcnRfYXQsIGF4aXNfbGluZV9jbGFzcyk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy54X2F4aXNfZ3JvdXAudGV4dENvbnRlbnQgPSAnJztcblx0XHR0aGlzLngubWFwKChwb2ludCwgaSkgPT4ge1xuXHRcdFx0dGhpcy54X2F4aXNfZ3JvdXAuYXBwZW5kQ2hpbGQoXG5cdFx0XHRcdHRoaXMubWFrZV94X2xpbmUoXG5cdFx0XHRcdFx0aGVpZ2h0LFxuXHRcdFx0XHRcdHRleHRfc3RhcnRfYXQsXG5cdFx0XHRcdFx0cG9pbnQsXG5cdFx0XHRcdFx0J3gtdmFsdWUtdGV4dCcsXG5cdFx0XHRcdFx0YXhpc19saW5lX2NsYXNzLFxuXHRcdFx0XHRcdHRoaXMueF9heGlzX3Bvc2l0aW9uc1tpXVxuXHRcdFx0XHQpXG5cdFx0XHQpO1xuXHRcdH0pO1xuXHR9XG5cblx0Ly8gbWFrZSBIT1JJWk9OVEFMIGxpbmVzIGZvciB5IHZhbHVlc1xuXHRtYWtlX3lfYXhpcyhhbmltYXRlPWZhbHNlKSB7XG5cdFx0aWYoYW5pbWF0ZSkge1xuXHRcdFx0dGhpcy5tYWtlX2FuaW1feV9heGlzKCk7XG5cdFx0XHR0aGlzLm1ha2VfYW5pbV95X3NwZWNpZmljcygpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGxldCBbd2lkdGgsIHRleHRfZW5kX2F0LCBheGlzX2xpbmVfY2xhc3MsIHN0YXJ0X2F0XSA9IHRoaXMuZ2V0X3lfYXhpc19saW5lX3Byb3BzKCk7XG5cblx0XHR0aGlzLnlfYXhpc19ncm91cC50ZXh0Q29udGVudCA9ICcnO1xuXHRcdHRoaXMueV9heGlzX3ZhbHVlcy5tYXAoKHZhbHVlLCBpKSA9PiB7XG5cdFx0XHR0aGlzLnlfYXhpc19ncm91cC5hcHBlbmRDaGlsZChcblx0XHRcdFx0dGhpcy5tYWtlX3lfbGluZShcblx0XHRcdFx0XHRzdGFydF9hdCxcblx0XHRcdFx0XHR3aWR0aCxcblx0XHRcdFx0XHR0ZXh0X2VuZF9hdCxcblx0XHRcdFx0XHR2YWx1ZSxcblx0XHRcdFx0XHQneS12YWx1ZS10ZXh0Jyxcblx0XHRcdFx0XHRheGlzX2xpbmVfY2xhc3MsXG5cdFx0XHRcdFx0dGhpcy56ZXJvX2xpbmUgLSB2YWx1ZSAqIHRoaXMubXVsdGlwbGllcixcblx0XHRcdFx0XHQodmFsdWUgPT09IDAgJiYgaSAhPT0gMCkgLy8gTm9uLWZpcnN0IFplcm8gbGluZVxuXHRcdFx0XHQpXG5cdFx0XHQpO1xuXHRcdH0pO1xuXHR9XG5cblx0Z2V0X3lfYXhpc19saW5lX3Byb3BzKHNwZWNpZmljPWZhbHNlKSB7XG5cdFx0aWYoc3BlY2lmaWMpIHtcblx0XHRcdHJldHVyblt0aGlzLndpZHRoLCB0aGlzLndpZHRoICsgNSwgJ3NwZWNpZmljLXZhbHVlJywgMF07XG5cdFx0fVxuXHRcdGxldCB3aWR0aCwgdGV4dF9lbmRfYXQgPSAtOSwgYXhpc19saW5lX2NsYXNzID0gJycsIHN0YXJ0X2F0ID0gMDtcblx0XHRpZih0aGlzLnlfYXhpc19tb2RlID09PSAnc3BhbicpIHtcdFx0Ly8gbG9uZyBzcGFubmluZyBsaW5lc1xuXHRcdFx0d2lkdGggPSB0aGlzLndpZHRoICsgNjtcblx0XHRcdHN0YXJ0X2F0ID0gLTY7XG5cdFx0fSBlbHNlIGlmKHRoaXMueV9heGlzX21vZGUgPT09ICd0aWNrJyl7XHQvLyBzaG9ydCBsYWJlbCBsaW5lc1xuXHRcdFx0d2lkdGggPSAtNjtcblx0XHRcdGF4aXNfbGluZV9jbGFzcyA9ICd5LWF4aXMtbGFiZWwnO1xuXHRcdH1cblxuXHRcdHJldHVybiBbd2lkdGgsIHRleHRfZW5kX2F0LCBheGlzX2xpbmVfY2xhc3MsIHN0YXJ0X2F0XTtcblx0fVxuXG5cdGRyYXdfZ3JhcGgoaW5pdD1mYWxzZSkge1xuXHRcdGlmKGluaXQpIHtcblx0XHRcdHRoaXMuZHJhd19uZXdfZ3JhcGhfYW5kX2FuaW1hdGUoKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0dGhpcy55Lm1hcCgoZCwgaSkgPT4ge1xuXHRcdFx0ZC5zdmdfdW5pdHMgPSBbXTtcblx0XHRcdHRoaXMubWFrZV9wYXRoICYmIHRoaXMubWFrZV9wYXRoKGQsIGksIHRoaXMueF9heGlzX3Bvc2l0aW9ucywgZC55X3RvcHMsIGQuY29sb3IgfHwgdGhpcy5jb2xvcnNbaV0pO1xuXHRcdFx0dGhpcy5tYWtlX25ld191bml0cyhkLCBpKTtcblx0XHR9KTtcblx0fVxuXG5cdGRyYXdfbmV3X2dyYXBoX2FuZF9hbmltYXRlKCkge1xuXHRcdGxldCBkYXRhID0gW107XG5cdFx0dGhpcy55Lm1hcCgoZCwgaSkgPT4ge1xuXHRcdFx0Ly8gQW5pbTogRG9uJ3QgZHJhdyBpbml0aWFsIHZhbHVlcywgc3RvcmUgdGhlbSBhbmQgdXBkYXRlIGxhdGVyXG5cdFx0XHRkLnlfdG9wcyA9IG5ldyBBcnJheShkLnZhbHVlcy5sZW5ndGgpLmZpbGwodGhpcy56ZXJvX2xpbmUpOyAvLyBubyB2YWx1ZVxuXHRcdFx0ZGF0YS5wdXNoKHt2YWx1ZXM6IGQudmFsdWVzfSk7XG5cdFx0XHRkLnN2Z191bml0cyA9IFtdO1xuXG5cdFx0XHR0aGlzLm1ha2VfcGF0aCAmJiB0aGlzLm1ha2VfcGF0aChkLCBpLCB0aGlzLnhfYXhpc19wb3NpdGlvbnMsIGQueV90b3BzLCBkLmNvbG9yIHx8IHRoaXMuY29sb3JzW2ldKTtcblx0XHRcdHRoaXMubWFrZV9uZXdfdW5pdHMoZCwgaSk7XG5cdFx0fSk7XG5cblx0XHRzZXRUaW1lb3V0KCgpID0+IHtcblx0XHRcdHRoaXMudXBkYXRlX3ZhbHVlcyhkYXRhKTtcblx0XHR9LCAzNTApO1xuXHR9XG5cblx0c2V0dXBfbmF2aWdhdGlvbihpbml0KSB7XG5cdFx0Ly8gSGFjazogZGVmZXIgbmF2IHRpbGwgaW5pdGlhbCB1cGRhdGVfdmFsdWVzXG5cdFx0c2V0VGltZW91dCgoKSA9PiB7XG5cdFx0XHRzdXBlci5zZXR1cF9uYXZpZ2F0aW9uKGluaXQpO1xuXHRcdH0sIDUwMCk7XG5cdH1cblxuXHRtYWtlX25ld191bml0cyhkLCBpKSB7XG5cdFx0dGhpcy5tYWtlX25ld191bml0c19mb3JfZGF0YXNldChcblx0XHRcdHRoaXMueF9heGlzX3Bvc2l0aW9ucyxcblx0XHRcdGQueV90b3BzLFxuXHRcdFx0ZC5jb2xvciB8fCB0aGlzLmNvbG9yc1tpXSxcblx0XHRcdGksXG5cdFx0XHR0aGlzLnkubGVuZ3RoXG5cdFx0KTtcblx0fVxuXG5cdG1ha2VfbmV3X3VuaXRzX2Zvcl9kYXRhc2V0KHhfdmFsdWVzLCB5X3ZhbHVlcywgY29sb3IsIGRhdGFzZXRfaW5kZXgsIG5vX29mX2RhdGFzZXRzLCBncm91cCwgYXJyYXksIHVuaXQpIHtcblx0XHRpZighZ3JvdXApIGdyb3VwID0gdGhpcy5zdmdfdW5pdHNfZ3JvdXBzW2RhdGFzZXRfaW5kZXhdO1xuXHRcdGlmKCFhcnJheSkgYXJyYXkgPSB0aGlzLnlbZGF0YXNldF9pbmRleF0uc3ZnX3VuaXRzO1xuXHRcdGlmKCF1bml0KSB1bml0ID0gdGhpcy51bml0X2FyZ3M7XG5cblx0XHRncm91cC50ZXh0Q29udGVudCA9ICcnO1xuXHRcdGFycmF5Lmxlbmd0aCA9IDA7XG5cblx0XHR5X3ZhbHVlcy5tYXAoKHksIGkpID0+IHtcblx0XHRcdGxldCBkYXRhX3VuaXQgPSB0aGlzLmRyYXdbdW5pdC50eXBlXShcblx0XHRcdFx0eF92YWx1ZXNbaV0sXG5cdFx0XHRcdHksXG5cdFx0XHRcdHVuaXQuYXJncyxcblx0XHRcdFx0Y29sb3IsXG5cdFx0XHRcdGRhdGFzZXRfaW5kZXgsXG5cdFx0XHRcdG5vX29mX2RhdGFzZXRzXG5cdFx0XHQpO1xuXHRcdFx0Z3JvdXAuYXBwZW5kQ2hpbGQoZGF0YV91bml0KTtcblx0XHRcdGFycmF5LnB1c2goZGF0YV91bml0KTtcblx0XHR9KTtcblx0fVxuXG5cdG1ha2VfeV9zcGVjaWZpY3MoKSB7XG5cdFx0dGhpcy5zcGVjaWZpY195X2dyb3VwLnRleHRDb250ZW50ID0gJyc7XG5cdFx0dGhpcy5zcGVjaWZpY192YWx1ZXMubWFwKGQgPT4ge1xuXHRcdFx0dGhpcy5zcGVjaWZpY195X2dyb3VwLmFwcGVuZENoaWxkKFxuXHRcdFx0XHR0aGlzLm1ha2VfeV9saW5lKFxuXHRcdFx0XHRcdDAsXG5cdFx0XHRcdFx0dGhpcy53aWR0aCxcblx0XHRcdFx0XHR0aGlzLndpZHRoICsgNSxcblx0XHRcdFx0XHRkLnRpdGxlLnRvVXBwZXJDYXNlKCksXG5cdFx0XHRcdFx0J3NwZWNpZmljLXZhbHVlJyxcblx0XHRcdFx0XHQnc3BlY2lmaWMtdmFsdWUnLFxuXHRcdFx0XHRcdHRoaXMuemVyb19saW5lIC0gZC52YWx1ZSAqIHRoaXMubXVsdGlwbGllcixcblx0XHRcdFx0XHRmYWxzZSxcblx0XHRcdFx0XHRkLmxpbmVfdHlwZVxuXHRcdFx0XHQpXG5cdFx0XHQpO1xuXHRcdH0pO1xuXHR9XG5cblx0YmluZF90b29sdGlwKCkge1xuXHRcdC8vIFRPRE86IGNvdWxkIGJlIGluIHRvb2x0aXAgaXRzZWxmLCBhcyBpdCBpcyBhIGdpdmVuIGZ1bmN0aW9uYWxpdHkgZm9yIGl0cyBwYXJlbnRcblx0XHR0aGlzLmNoYXJ0X3dyYXBwZXIuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgKGUpID0+IHtcblx0XHRcdGxldCBvZmZzZXQgPSAkLm9mZnNldCh0aGlzLmNoYXJ0X3dyYXBwZXIpO1xuXHRcdFx0bGV0IHJlbFggPSBlLnBhZ2VYIC0gb2Zmc2V0LmxlZnQgLSB0aGlzLnRyYW5zbGF0ZV94O1xuXHRcdFx0bGV0IHJlbFkgPSBlLnBhZ2VZIC0gb2Zmc2V0LnRvcCAtIHRoaXMudHJhbnNsYXRlX3k7XG5cblx0XHRcdGlmKHJlbFkgPCB0aGlzLmhlaWdodCArIHRoaXMudHJhbnNsYXRlX3kgKiAyKSB7XG5cdFx0XHRcdHRoaXMubWFwX3Rvb2x0aXBfeF9wb3NpdGlvbl9hbmRfc2hvdyhyZWxYKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMudGlwLmhpZGVfdGlwKCk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblxuXHRtYXBfdG9vbHRpcF94X3Bvc2l0aW9uX2FuZF9zaG93KHJlbFgpIHtcblx0XHRmb3IodmFyIGk9dGhpcy54X2F4aXNfcG9zaXRpb25zLmxlbmd0aCAtIDE7IGkgPj0gMCA7IGktLSkge1xuXHRcdFx0bGV0IHhfdmFsID0gdGhpcy54X2F4aXNfcG9zaXRpb25zW2ldO1xuXHRcdFx0Ly8gbGV0IGRlbHRhID0gaSA9PT0gMCA/IHRoaXMuYXZnX3VuaXRfd2lkdGggOiB4X3ZhbCAtIHRoaXMueF9heGlzX3Bvc2l0aW9uc1tpLTFdO1xuXHRcdFx0aWYocmVsWCA+IHhfdmFsIC0gdGhpcy5hdmdfdW5pdF93aWR0aC8yKSB7XG5cdFx0XHRcdGxldCB4ID0geF92YWwgKyB0aGlzLnRyYW5zbGF0ZV94O1xuXHRcdFx0XHRsZXQgeSA9IHRoaXMueV9taW5fdG9wc1tpXSArIHRoaXMudHJhbnNsYXRlX3k7XG5cblx0XHRcdFx0bGV0IHRpdGxlID0gdGhpcy54LmZvcm1hdHRlZCAmJiB0aGlzLnguZm9ybWF0dGVkLmxlbmd0aD4wXG5cdFx0XHRcdFx0PyB0aGlzLnguZm9ybWF0dGVkW2ldIDogdGhpcy54W2ldO1xuXHRcdFx0XHRsZXQgdmFsdWVzID0gdGhpcy55Lm1hcCgoc2V0LCBqKSA9PiB7XG5cdFx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHRcdHRpdGxlOiBzZXQudGl0bGUsXG5cdFx0XHRcdFx0XHR2YWx1ZTogc2V0LmZvcm1hdHRlZCA/IHNldC5mb3JtYXR0ZWRbaV0gOiBzZXQudmFsdWVzW2ldLFxuXHRcdFx0XHRcdFx0Y29sb3I6IHNldC5jb2xvciB8fCB0aGlzLmNvbG9yc1tqXSxcblx0XHRcdFx0XHR9O1xuXHRcdFx0XHR9KTtcblxuXHRcdFx0XHQvLyBUT0RPOiB1cHNpZGUtZG93biB0b29sdGlwcyBmb3IgbmVnYXRpdmUgdmFsdWVzP1xuXHRcdFx0XHR0aGlzLnRpcC5zZXRfdmFsdWVzKHgsIHksIHRpdGxlLCAnJywgdmFsdWVzKTtcblx0XHRcdFx0dGhpcy50aXAuc2hvd190aXAoKTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0Ly8gQVBJXG5cdHNob3dfc3VtcygpIHtcblx0XHR0aGlzLnVwZGF0aW5nID0gdHJ1ZTtcblxuXHRcdHRoaXMueV9zdW1zID0gbmV3IEFycmF5KHRoaXMueF9heGlzX3Bvc2l0aW9ucy5sZW5ndGgpLmZpbGwoMCk7XG5cdFx0dGhpcy55Lm1hcChkID0+IHtcblx0XHRcdGQudmFsdWVzLm1hcCggKHZhbHVlLCBpKSA9PiB7XG5cdFx0XHRcdHRoaXMueV9zdW1zW2ldICs9IHZhbHVlO1xuXHRcdFx0fSk7XG5cdFx0fSk7XG5cblx0XHQvLyBSZW1ha2UgeSBheGlzLCBhbmltYXRlXG5cdFx0dGhpcy51cGRhdGVfdmFsdWVzKCk7XG5cblx0XHQvLyBUaGVuIG1ha2Ugc3VtIHVuaXRzLCBkb24ndCBhbmltYXRlXG5cdFx0dGhpcy5zdW1fdW5pdHMgPSBbXTtcblxuXHRcdHRoaXMubWFrZV9uZXdfdW5pdHNfZm9yX2RhdGFzZXQoXG5cdFx0XHR0aGlzLnhfYXhpc19wb3NpdGlvbnMsXG5cdFx0XHR0aGlzLnlfc3Vtcy5tYXAoIHZhbCA9PiBmbG9hdF8yKHRoaXMuemVyb19saW5lIC0gdmFsICogdGhpcy5tdWx0aXBsaWVyKSksXG5cdFx0XHQnbGlnaHQtZ3JleScsXG5cdFx0XHQwLFxuXHRcdFx0MSxcblx0XHRcdHRoaXMuc3VtX2dyb3VwLFxuXHRcdFx0dGhpcy5zdW1fdW5pdHNcblx0XHQpO1xuXG5cdFx0Ly8gdGhpcy5tYWtlX3BhdGggJiYgdGhpcy5tYWtlX3BhdGgoZCwgaSwgb2xkX3gsIG9sZF95LCBkLmNvbG9yIHx8IHRoaXMuY29sb3JzW2ldKTtcblxuXHRcdHRoaXMudXBkYXRpbmcgPSBmYWxzZTtcblx0fVxuXG5cdGhpZGVfc3VtcygpIHtcblx0XHRpZih0aGlzLnVwZGF0aW5nKSByZXR1cm47XG5cdFx0dGhpcy55X3N1bXMgPSBbXTtcblx0XHR0aGlzLnN1bV9ncm91cC50ZXh0Q29udGVudCA9ICcnO1xuXHRcdHRoaXMuc3VtX3VuaXRzID0gW107XG5cdFx0dGhpcy51cGRhdGVfdmFsdWVzKCk7XG5cdH1cblxuXHRzaG93X2F2ZXJhZ2UoKSB7XG5cdFx0dGhpcy5vbGRfc3BlY2lmaWNfdmFsdWVzID0gdGhpcy5zcGVjaWZpY192YWx1ZXMuc2xpY2UoKTtcblx0XHR0aGlzLnkubWFwKChkLCBpKSA9PiB7XG5cdFx0XHRsZXQgc3VtID0gMDtcblx0XHRcdGQudmFsdWVzLm1hcChlID0+IHtzdW0rPWU7fSk7XG5cdFx0XHRsZXQgYXZlcmFnZSA9IHN1bS9kLnZhbHVlcy5sZW5ndGg7XG5cblx0XHRcdHRoaXMuc3BlY2lmaWNfdmFsdWVzLnB1c2goe1xuXHRcdFx0XHR0aXRsZTogXCJBVkdcIiArIFwiIFwiICsgKGkrMSksXG5cdFx0XHRcdGxpbmVfdHlwZTogXCJkYXNoZWRcIixcblx0XHRcdFx0dmFsdWU6IGF2ZXJhZ2UsXG5cdFx0XHRcdGF1dG86IDFcblx0XHRcdH0pO1xuXHRcdH0pO1xuXG5cdFx0dGhpcy51cGRhdGVfdmFsdWVzKCk7XG5cdH1cblxuXHRoaWRlX2F2ZXJhZ2UoKSB7XG5cdFx0dGhpcy5vbGRfc3BlY2lmaWNfdmFsdWVzID0gdGhpcy5zcGVjaWZpY192YWx1ZXMuc2xpY2UoKTtcblxuXHRcdGxldCBpbmRpY2VzX3RvX3JlbW92ZSA9IFtdO1xuXHRcdHRoaXMuc3BlY2lmaWNfdmFsdWVzLm1hcCgoZCwgaSkgPT4ge1xuXHRcdFx0aWYoZC5hdXRvKSBpbmRpY2VzX3RvX3JlbW92ZS51bnNoaWZ0KGkpO1xuXHRcdH0pO1xuXG5cdFx0aW5kaWNlc190b19yZW1vdmUubWFwKGluZGV4ID0+IHtcblx0XHRcdHRoaXMuc3BlY2lmaWNfdmFsdWVzLnNwbGljZShpbmRleCwgMSk7XG5cdFx0fSk7XG5cblx0XHR0aGlzLnVwZGF0ZV92YWx1ZXMoKTtcblx0fVxuXG5cdHVwZGF0ZV92YWx1ZXMobmV3X3ksIG5ld194KSB7XG5cdFx0aWYoIW5ld194KSB7XG5cdFx0XHRuZXdfeCA9IHRoaXMueDtcblx0XHR9XG5cdFx0dGhpcy5lbGVtZW50c190b19hbmltYXRlID0gW107XG5cdFx0dGhpcy51cGRhdGluZyA9IHRydWU7XG5cblx0XHR0aGlzLm9sZF94X3ZhbHVlcyA9IHRoaXMueC5zbGljZSgpO1xuXHRcdHRoaXMub2xkX3lfYXhpc190b3BzID0gdGhpcy55Lm1hcChkID0+IGQueV90b3BzLnNsaWNlKCkpO1xuXG5cdFx0dGhpcy5vbGRfeV92YWx1ZXMgPSB0aGlzLnkubWFwKGQgPT4gZC52YWx1ZXMpO1xuXG5cdFx0dGhpcy5ub19vZl9leHRyYV9wdHMgPSBuZXdfeC5sZW5ndGggLSB0aGlzLngubGVuZ3RoO1xuXG5cdFx0Ly8gSnVzdCB1cGRhdGUgdmFsdWVzIHByb3AsIHNldHVwX3gveSgpIHdpbGwgZG8gdGhlIHJlc3Rcblx0XHRpZihuZXdfeSkgdGhpcy55Lm1hcCgoZCwgaSkgPT4ge2QudmFsdWVzID0gbmV3X3lbaV0udmFsdWVzO30pO1xuXHRcdGlmKG5ld194KSB0aGlzLnggPSBuZXdfeDtcblxuXHRcdHRoaXMuc2V0dXBfeCgpO1xuXHRcdHRoaXMuc2V0dXBfeSgpO1xuXG5cdFx0Ly8gQW5pbWF0ZSBvbmx5IGlmIHBvc2l0aW9ucyBoYXZlIGNoYW5nZWRcblx0XHRpZighYXJyYXlzX2VxdWFsKHRoaXMueF9vbGRfYXhpc19wb3NpdGlvbnMsIHRoaXMueF9heGlzX3Bvc2l0aW9ucykpIHtcblx0XHRcdHRoaXMubWFrZV94X2F4aXModHJ1ZSk7XG5cdFx0XHRzZXRUaW1lb3V0KCgpID0+IHtcblx0XHRcdFx0aWYoIXRoaXMudXBkYXRpbmcpIHRoaXMubWFrZV94X2F4aXMoKTtcblx0XHRcdH0sIDMwMCk7XG5cdFx0fVxuXG5cdFx0aWYoIWFycmF5c19lcXVhbCh0aGlzLnlfb2xkX2F4aXNfdmFsdWVzLCB0aGlzLnlfYXhpc192YWx1ZXMpIHx8XG5cdFx0XHQodGhpcy5vbGRfc3BlY2lmaWNfdmFsdWVzICYmXG5cdFx0XHQhYXJyYXlzX2VxdWFsKHRoaXMub2xkX3NwZWNpZmljX3ZhbHVlcywgdGhpcy5zcGVjaWZpY192YWx1ZXMpKSkge1xuXG5cdFx0XHR0aGlzLm1ha2VfeV9heGlzKHRydWUpO1xuXHRcdFx0c2V0VGltZW91dCgoKSA9PiB7XG5cdFx0XHRcdGlmKCF0aGlzLnVwZGF0aW5nKSB7XG5cdFx0XHRcdFx0dGhpcy5tYWtlX3lfYXhpcygpO1xuXHRcdFx0XHRcdHRoaXMubWFrZV95X3NwZWNpZmljcygpO1xuXHRcdFx0XHR9XG5cdFx0XHR9LCAzMDApO1xuXHRcdH1cblxuXHRcdC8vIENoYW5nZSBpbiBkYXRhLCBzbyBjYWxjdWxhdGUgZGVwZW5kZW5jaWVzXG5cdFx0dGhpcy5jYWxjX3lfZGVwZW5kZW5jaWVzKCk7XG5cblx0XHR0aGlzLmFuaW1hdGVfZ3JhcGhzKCk7XG5cblx0XHQvLyBUcmlnZ2VyIGFuaW1hdGlvbiB3aXRoIHRoZSBhbmltYXRhYmxlIGVsZW1lbnRzIGluIHRoaXMuZWxlbWVudHNfdG9fYW5pbWF0ZVxuXHRcdHRoaXMucnVuX2FuaW1hdGlvbigpO1xuXG5cdFx0dGhpcy51cGRhdGluZyA9IGZhbHNlO1xuXHR9XG5cblx0YWRkX2RhdGFfcG9pbnQoeV9wb2ludCwgeF9wb2ludCwgaW5kZXg9dGhpcy54Lmxlbmd0aCkge1xuXHRcdGxldCBuZXdfeSA9IHRoaXMueS5tYXAoZGF0YV9zZXQgPT4geyByZXR1cm4ge3ZhbHVlczpkYXRhX3NldC52YWx1ZXN9OyB9KTtcblx0XHRuZXdfeS5tYXAoKGQsIGkpID0+IHsgZC52YWx1ZXMuc3BsaWNlKGluZGV4LCAwLCB5X3BvaW50W2ldKTsgfSk7XG5cdFx0bGV0IG5ld194ID0gdGhpcy54LnNsaWNlKCk7XG5cdFx0bmV3X3guc3BsaWNlKGluZGV4LCAwLCB4X3BvaW50KTtcblxuXHRcdHRoaXMudXBkYXRlX3ZhbHVlcyhuZXdfeSwgbmV3X3gpO1xuXHR9XG5cblx0cmVtb3ZlX2RhdGFfcG9pbnQoaW5kZXggPSB0aGlzLngubGVuZ3RoLTEpIHtcblx0XHRpZih0aGlzLngubGVuZ3RoIDwgMykgcmV0dXJuO1xuXG5cdFx0bGV0IG5ld195ID0gdGhpcy55Lm1hcChkYXRhX3NldCA9PiB7IHJldHVybiB7dmFsdWVzOmRhdGFfc2V0LnZhbHVlc307IH0pO1xuXHRcdG5ld195Lm1hcCgoZCkgPT4geyBkLnZhbHVlcy5zcGxpY2UoaW5kZXgsIDEpOyB9KTtcblx0XHRsZXQgbmV3X3ggPSB0aGlzLnguc2xpY2UoKTtcblx0XHRuZXdfeC5zcGxpY2UoaW5kZXgsIDEpO1xuXG5cdFx0dGhpcy51cGRhdGVfdmFsdWVzKG5ld195LCBuZXdfeCk7XG5cdH1cblxuXHRydW5fYW5pbWF0aW9uKCkge1xuXHRcdGxldCBhbmltX3N2ZyA9ICQucnVuU1ZHQW5pbWF0aW9uKHRoaXMuc3ZnLCB0aGlzLmVsZW1lbnRzX3RvX2FuaW1hdGUpO1xuXG5cdFx0aWYodGhpcy5zdmcucGFyZW50Tm9kZSA9PSB0aGlzLmNoYXJ0X3dyYXBwZXIpIHtcblx0XHRcdHRoaXMuY2hhcnRfd3JhcHBlci5yZW1vdmVDaGlsZCh0aGlzLnN2Zyk7XG5cdFx0XHR0aGlzLmNoYXJ0X3dyYXBwZXIuYXBwZW5kQ2hpbGQoYW5pbV9zdmcpO1xuXG5cdFx0fVxuXG5cdFx0Ly8gUmVwbGFjZSB0aGUgbmV3IHN2ZyAoZGF0YSBoYXMgbG9uZyBiZWVuIHJlcGxhY2VkKVxuXHRcdHNldFRpbWVvdXQoKCkgPT4ge1xuXHRcdFx0aWYoYW5pbV9zdmcucGFyZW50Tm9kZSA9PSB0aGlzLmNoYXJ0X3dyYXBwZXIpIHtcblx0XHRcdFx0dGhpcy5jaGFydF93cmFwcGVyLnJlbW92ZUNoaWxkKGFuaW1fc3ZnKTtcblx0XHRcdFx0dGhpcy5jaGFydF93cmFwcGVyLmFwcGVuZENoaWxkKHRoaXMuc3ZnKTtcblx0XHRcdH1cblx0XHR9LCAyMDApO1xuXHR9XG5cblx0YW5pbWF0ZV9ncmFwaHMoKSB7XG5cdFx0dGhpcy55Lm1hcCgoZCwgaSkgPT4ge1xuXHRcdFx0Ly8gUHJlLXByZXAsIGVxdWlsaXplIG5vIG9mIHBvc2l0aW9ucyBiZXR3ZWVuIG9sZCBhbmQgbmV3XG5cdFx0XHRsZXQgW29sZF94LCBvbGRfeSwgbmV3X3gsIG5ld195XSA9IHRoaXMuY2FsY19vbGRfYW5kX25ld19wb3N0aW9ucyhkLCBpKTtcblx0XHRcdGlmKHRoaXMubm9fb2ZfZXh0cmFfcHRzID49IDApIHtcblx0XHRcdFx0dGhpcy5tYWtlX3BhdGggJiYgdGhpcy5tYWtlX3BhdGgoZCwgaSwgb2xkX3gsIG9sZF95LCBkLmNvbG9yIHx8IHRoaXMuY29sb3JzW2ldKTtcblx0XHRcdFx0dGhpcy5tYWtlX25ld191bml0c19mb3JfZGF0YXNldChvbGRfeCwgb2xkX3ksIGQuY29sb3IgfHwgdGhpcy5jb2xvcnNbaV0sIGksIHRoaXMueS5sZW5ndGgpO1xuXHRcdFx0fVxuXHRcdFx0ZC5wYXRoICYmIHRoaXMuYW5pbWF0ZV9wYXRoKGQsIGksIG9sZF94LCBvbGRfeSwgbmV3X3gsIG5ld195KTtcblx0XHRcdHRoaXMuYW5pbWF0ZV91bml0cyhkLCBpLCBvbGRfeCwgb2xkX3ksIG5ld194LCBuZXdfeSk7XG5cdFx0fSk7XG5cblx0XHQvLyBUT0RPOiByZXBsYWNlIHdpdGggcmVhbCB1bml0c1xuXHRcdHNldFRpbWVvdXQoKCkgPT4ge1xuXHRcdFx0dGhpcy55Lm1hcCgoZCwgaSkgPT4ge1xuXHRcdFx0XHR0aGlzLm1ha2VfcGF0aCAmJiB0aGlzLm1ha2VfcGF0aChkLCBpLCB0aGlzLnhfYXhpc19wb3NpdGlvbnMsIGQueV90b3BzLCBkLmNvbG9yIHx8IHRoaXMuY29sb3JzW2ldKTtcblx0XHRcdFx0dGhpcy5tYWtlX25ld191bml0cyhkLCBpKTtcblx0XHRcdH0pO1xuXHRcdH0sIDMwMCk7XG5cdH1cblxuXHRhbmltYXRlX3BhdGgoZCwgaSwgb2xkX3gsIG9sZF95LCBuZXdfeCwgbmV3X3kpIHtcblx0XHQvLyBBbmltYXRlIHBhdGhcblx0XHRjb25zdCBuZXdfcG9pbnRzX2xpc3QgPSBuZXdfeS5tYXAoKHksIGkpID0+IChuZXdfeFtpXSArICcsJyArIHkpKTtcblx0XHRjb25zdCBuZXdfcGF0aF9zdHIgPSBuZXdfcG9pbnRzX2xpc3Quam9pbihcIkxcIik7XG5cblx0XHRjb25zdCBwYXRoX2FyZ3MgPSBbe3VuaXQ6IGQucGF0aCwgb2JqZWN0OiBkLCBrZXk6ICdwYXRoJ30sIHtkOlwiTVwiK25ld19wYXRoX3N0cn0sIDI1MCwgXCJlYXNlaW5cIl07XG5cdFx0dGhpcy5lbGVtZW50c190b19hbmltYXRlLnB1c2gocGF0aF9hcmdzKTtcblxuXHRcdC8vIEFuaW1hdGUgcmVnaW9uXG5cdFx0aWYoZC5yZWdpb25fcGF0aCkge1xuXHRcdFx0bGV0IHJlZ19zdGFydF9wdCA9IGAwLCR7dGhpcy56ZXJvX2xpbmV9TGA7XG5cdFx0XHRsZXQgcmVnX2VuZF9wdCA9IGBMJHt0aGlzLndpZHRofSwke3RoaXMuemVyb19saW5lfWA7XG5cblx0XHRcdGNvbnN0IHJlZ2lvbl9hcmdzID0gW1xuXHRcdFx0XHR7dW5pdDogZC5yZWdpb25fcGF0aCwgb2JqZWN0OiBkLCBrZXk6ICdyZWdpb25fcGF0aCd9LFxuXHRcdFx0XHR7ZDpcIk1cIiArIHJlZ19zdGFydF9wdCArIG5ld19wYXRoX3N0ciArIHJlZ19lbmRfcHR9LFxuXHRcdFx0XHQyNTAsXG5cdFx0XHRcdFwiZWFzZWluXCJcblx0XHRcdF07XG5cdFx0XHR0aGlzLmVsZW1lbnRzX3RvX2FuaW1hdGUucHVzaChyZWdpb25fYXJncyk7XG5cdFx0fVxuXHR9XG5cblx0YW5pbWF0ZV91bml0cyhkLCBpbmRleCwgb2xkX3gsIG9sZF95LCBuZXdfeCwgbmV3X3kpIHtcblx0XHRsZXQgdHlwZSA9IHRoaXMudW5pdF9hcmdzLnR5cGU7XG5cblx0XHRkLnN2Z191bml0cy5tYXAoKHVuaXQsIGkpID0+IHtcblx0XHRcdHRoaXMuZWxlbWVudHNfdG9fYW5pbWF0ZS5wdXNoKHRoaXMuYW5pbWF0ZVt0eXBlXShcblx0XHRcdFx0e3VuaXQ6dW5pdCwgYXJyYXk6ZC5zdmdfdW5pdHMsIGluZGV4OiBpfSwgLy8gdW5pdCwgd2l0aCBpbmZvIHRvIHJlcGxhY2Ugd2hlcmUgaXQgY2FtZSBmcm9tIGluIHRoZSBkYXRhXG5cdFx0XHRcdG5ld194W2ldLFxuXHRcdFx0XHRuZXdfeVtpXSxcblx0XHRcdFx0aW5kZXhcblx0XHRcdCkpO1xuXHRcdH0pO1xuXHR9XG5cblx0Y2FsY19vbGRfYW5kX25ld19wb3N0aW9ucyhkLCBpKSB7XG5cdFx0bGV0IG9sZF94ID0gdGhpcy54X29sZF9heGlzX3Bvc2l0aW9ucy5zbGljZSgpO1xuXHRcdGxldCBuZXdfeCA9IHRoaXMueF9heGlzX3Bvc2l0aW9ucy5zbGljZSgpO1xuXG5cdFx0bGV0IG9sZF95ID0gdGhpcy5vbGRfeV9heGlzX3RvcHNbaV0uc2xpY2UoKTtcblx0XHRsZXQgbmV3X3kgPSBkLnlfdG9wcy5zbGljZSgpO1xuXG5cdFx0Y29uc3QgbGFzdF9vbGRfeF9wb3MgPSBvbGRfeFtvbGRfeC5sZW5ndGggLSAxXTtcblx0XHRjb25zdCBsYXN0X29sZF95X3BvcyA9IG9sZF95W29sZF95Lmxlbmd0aCAtIDFdO1xuXG5cdFx0Y29uc3QgbGFzdF9uZXdfeF9wb3MgPSBuZXdfeFtuZXdfeC5sZW5ndGggLSAxXTtcblx0XHRjb25zdCBsYXN0X25ld195X3BvcyA9IG5ld195W25ld195Lmxlbmd0aCAtIDFdO1xuXG5cdFx0aWYodGhpcy5ub19vZl9leHRyYV9wdHMgPj0gMCkge1xuXHRcdFx0Ly8gRmlyc3Qgc3Vic3RpdHV0ZSBjdXJyZW50IHBhdGggd2l0aCBhIHNxdWlnZ2xlZCBvbmUgKGxvb2tpbmcgdGhlIHNhbWUgYnV0XG5cdFx0XHQvLyBoYXZpbmcgbW9yZSBwb2ludHMgYXQgZW5kKSxcblx0XHRcdC8vIHRoZW4gYW5pbWF0ZSB0byBzdHJldGNoIGl0IGxhdGVyIHRvIG5ldyBwb2ludHNcblx0XHRcdC8vIChuZXcgcG9pbnRzIGFscmVhZHkgaGF2ZSBtb3JlIHBvaW50cylcblxuXHRcdFx0Ly8gSGVuY2UsIHRoZSBleHRyYSBlbmQgcG9pbnRzIHdpbGwgY29ycmVzcG9uZCB0byBjdXJyZW50KG9sZCkgcG9zaXRpb25zXG5cdFx0XHRsZXQgZmlsbGVyX3ggPSBuZXcgQXJyYXkoTWF0aC5hYnModGhpcy5ub19vZl9leHRyYV9wdHMpKS5maWxsKGxhc3Rfb2xkX3hfcG9zKTtcblx0XHRcdGxldCBmaWxsZXJfeSA9IG5ldyBBcnJheShNYXRoLmFicyh0aGlzLm5vX29mX2V4dHJhX3B0cykpLmZpbGwobGFzdF9vbGRfeV9wb3MpO1xuXG5cdFx0XHRvbGRfeCA9IG9sZF94LmNvbmNhdChmaWxsZXJfeCk7XG5cdFx0XHRvbGRfeSA9IG9sZF95LmNvbmNhdChmaWxsZXJfeSk7XG5cblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gSnVzdCBtb2RpZnkgdGhlIG5ldyBwb2ludHMgdG8gaGF2ZSBleHRyYSBwb2ludHNcblx0XHRcdC8vIHdpdGggdGhlIHNhbWUgcG9zaXRpb24gYXQgZW5kXG5cdFx0XHRsZXQgZmlsbGVyX3ggPSBuZXcgQXJyYXkoTWF0aC5hYnModGhpcy5ub19vZl9leHRyYV9wdHMpKS5maWxsKGxhc3RfbmV3X3hfcG9zKTtcblx0XHRcdGxldCBmaWxsZXJfeSA9IG5ldyBBcnJheShNYXRoLmFicyh0aGlzLm5vX29mX2V4dHJhX3B0cykpLmZpbGwobGFzdF9uZXdfeV9wb3MpO1xuXG5cdFx0XHRuZXdfeCA9IG5ld194LmNvbmNhdChmaWxsZXJfeCk7XG5cdFx0XHRuZXdfeSA9IG5ld195LmNvbmNhdChmaWxsZXJfeSk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIFtvbGRfeCwgb2xkX3ksIG5ld194LCBuZXdfeV07XG5cdH1cblxuXHRtYWtlX2FuaW1feF9heGlzKGhlaWdodCwgdGV4dF9zdGFydF9hdCwgYXhpc19saW5lX2NsYXNzKSB7XG5cdFx0Ly8gQW5pbWF0ZSBYIEFYSVMgdG8gYWNjb3VudCBmb3IgbW9yZSBvciBsZXNzIGF4aXMgbGluZXNcblxuXHRcdGNvbnN0IG9sZF9wb3MgPSB0aGlzLnhfb2xkX2F4aXNfcG9zaXRpb25zO1xuXHRcdGNvbnN0IG5ld19wb3MgPSB0aGlzLnhfYXhpc19wb3NpdGlvbnM7XG5cblx0XHRjb25zdCBvbGRfdmFscyA9IHRoaXMub2xkX3hfdmFsdWVzO1xuXHRcdGNvbnN0IG5ld192YWxzID0gdGhpcy54O1xuXG5cdFx0Y29uc3QgbGFzdF9saW5lX3BvcyA9IG9sZF9wb3Nbb2xkX3Bvcy5sZW5ndGggLSAxXTtcblxuXHRcdGxldCBhZGRfYW5kX2FuaW1hdGVfbGluZSA9ICh2YWx1ZSwgb2xkX3BvcywgbmV3X3BvcykgPT4ge1xuXHRcdFx0Y29uc3QgeF9saW5lID0gdGhpcy5tYWtlX3hfbGluZShcblx0XHRcdFx0aGVpZ2h0LFxuXHRcdFx0XHR0ZXh0X3N0YXJ0X2F0LFxuXHRcdFx0XHR2YWx1ZSwgLy8gbmV3IHZhbHVlXG5cdFx0XHRcdCd4LXZhbHVlLXRleHQnLFxuXHRcdFx0XHRheGlzX2xpbmVfY2xhc3MsXG5cdFx0XHRcdG9sZF9wb3MgLy8gb2xkIHBvc2l0aW9uXG5cdFx0XHQpO1xuXHRcdFx0dGhpcy54X2F4aXNfZ3JvdXAuYXBwZW5kQ2hpbGQoeF9saW5lKTtcblxuXHRcdFx0dGhpcy5lbGVtZW50c190b19hbmltYXRlICYmIHRoaXMuZWxlbWVudHNfdG9fYW5pbWF0ZS5wdXNoKFtcblx0XHRcdFx0e3VuaXQ6IHhfbGluZSwgYXJyYXk6IFswXSwgaW5kZXg6IDB9LFxuXHRcdFx0XHR7dHJhbnNmb3JtOiBgJHsgbmV3X3BvcyB9LCAwYH0sXG5cdFx0XHRcdDI1MCxcblx0XHRcdFx0XCJlYXNlaW5cIixcblx0XHRcdFx0XCJ0cmFuc2xhdGVcIixcblx0XHRcdFx0e3RyYW5zZm9ybTogYCR7IG9sZF9wb3MgfSwgMGB9XG5cdFx0XHRdKTtcblx0XHR9O1xuXG5cdFx0dGhpcy54X2F4aXNfZ3JvdXAudGV4dENvbnRlbnQgPSAnJztcblxuXHRcdHRoaXMubWFrZV9uZXdfYXhpc19hbmltX2xpbmVzKFxuXHRcdFx0b2xkX3Bvcyxcblx0XHRcdG5ld19wb3MsXG5cdFx0XHRvbGRfdmFscyxcblx0XHRcdG5ld192YWxzLFxuXHRcdFx0bGFzdF9saW5lX3Bvcyxcblx0XHRcdGFkZF9hbmRfYW5pbWF0ZV9saW5lXG5cdFx0KTtcblx0fVxuXG5cdG1ha2VfYW5pbV95X2F4aXMoKSB7XG5cdFx0Ly8gQW5pbWF0ZSBZIEFYSVMgdG8gYWNjb3VudCBmb3IgbW9yZSBvciBsZXNzIGF4aXMgbGluZXNcblxuXHRcdGNvbnN0IG9sZF9wb3MgPSB0aGlzLnlfb2xkX2F4aXNfdmFsdWVzLm1hcCh2YWx1ZSA9PlxuXHRcdFx0dGhpcy56ZXJvX2xpbmUgLSB2YWx1ZSAqIHRoaXMubXVsdGlwbGllcik7XG5cdFx0Y29uc3QgbmV3X3BvcyA9IHRoaXMueV9heGlzX3ZhbHVlcy5tYXAodmFsdWUgPT5cblx0XHRcdHRoaXMuemVyb19saW5lIC0gdmFsdWUgKiB0aGlzLm11bHRpcGxpZXIpO1xuXG5cdFx0Y29uc3Qgb2xkX3ZhbHMgPSB0aGlzLnlfb2xkX2F4aXNfdmFsdWVzO1xuXHRcdGNvbnN0IG5ld192YWxzID0gdGhpcy55X2F4aXNfdmFsdWVzO1xuXG5cdFx0Y29uc3QgbGFzdF9saW5lX3BvcyA9IG9sZF9wb3Nbb2xkX3Bvcy5sZW5ndGggLSAxXTtcblxuXHRcdHRoaXMueV9heGlzX2dyb3VwLnRleHRDb250ZW50ID0gJyc7XG5cblx0XHR0aGlzLm1ha2VfbmV3X2F4aXNfYW5pbV9saW5lcyhcblx0XHRcdG9sZF9wb3MsXG5cdFx0XHRuZXdfcG9zLFxuXHRcdFx0b2xkX3ZhbHMsXG5cdFx0XHRuZXdfdmFscyxcblx0XHRcdGxhc3RfbGluZV9wb3MsXG5cdFx0XHR0aGlzLmFkZF9hbmRfYW5pbWF0ZV95X2xpbmUuYmluZCh0aGlzKSxcblx0XHRcdHRoaXMueV9heGlzX2dyb3VwXG5cdFx0KTtcblx0fVxuXG5cdG1ha2VfYW5pbV95X3NwZWNpZmljcygpIHtcblx0XHR0aGlzLnNwZWNpZmljX3lfZ3JvdXAudGV4dENvbnRlbnQgPSAnJztcblx0XHR0aGlzLnNwZWNpZmljX3ZhbHVlcy5tYXAoKGQpID0+IHtcblx0XHRcdHRoaXMuYWRkX2FuZF9hbmltYXRlX3lfbGluZShcblx0XHRcdFx0ZC50aXRsZSxcblx0XHRcdFx0dGhpcy5vbGRfemVyb19saW5lIC0gZC52YWx1ZSAqIHRoaXMub2xkX211bHRpcGxpZXIsXG5cdFx0XHRcdHRoaXMuemVyb19saW5lIC0gZC52YWx1ZSAqIHRoaXMubXVsdGlwbGllcixcblx0XHRcdFx0MCxcblx0XHRcdFx0dGhpcy5zcGVjaWZpY195X2dyb3VwLFxuXHRcdFx0XHRkLmxpbmVfdHlwZSxcblx0XHRcdFx0dHJ1ZVxuXHRcdFx0KTtcblx0XHR9KTtcblx0fVxuXG5cdG1ha2VfbmV3X2F4aXNfYW5pbV9saW5lcyhvbGRfcG9zLCBuZXdfcG9zLCBvbGRfdmFscywgbmV3X3ZhbHMsIGxhc3RfbGluZV9wb3MsIGFkZF9hbmRfYW5pbWF0ZV9saW5lLCBncm91cCkge1xuXHRcdGxldCBzdXBlcmltcG9zZWRfcG9zaXRpb25zLCBzdXBlcmltcG9zZWRfdmFsdWVzO1xuXHRcdGxldCBub19vZl9leHRyYXMgPSBuZXdfdmFscy5sZW5ndGggLSBvbGRfdmFscy5sZW5ndGg7XG5cdFx0aWYobm9fb2ZfZXh0cmFzID4gMCkge1xuXHRcdFx0Ly8gTW9yZSBheGlzIGFyZSBuZWVkZWRcblx0XHRcdC8vIEZpcnN0IG1ha2Ugb25seSB0aGUgc3VwZXJpbXBvc2VkIChzYW1lIHBvc2l0aW9uKSBvbmVzXG5cdFx0XHQvLyBBZGQgaW4gdGhlIGV4dHJhcyBhdCB0aGUgZW5kIGxhdGVyXG5cdFx0XHRzdXBlcmltcG9zZWRfcG9zaXRpb25zID0gbmV3X3Bvcy5zbGljZSgwLCBvbGRfcG9zLmxlbmd0aCk7XG5cdFx0XHRzdXBlcmltcG9zZWRfdmFsdWVzID0gbmV3X3ZhbHMuc2xpY2UoMCwgb2xkX3ZhbHMubGVuZ3RoKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gQXhpcyBoYXZlIHRvIGJlIHJlZHVjZWRcblx0XHRcdC8vIEZha2UgaXQgYnkgbW92aW5nIGFsbCBjdXJyZW50IGV4dHJhIGF4aXMgdG8gdGhlIGxhc3QgcG9zaXRpb25cblx0XHRcdC8vIFlvdSdsbCBuZWVkIGZpbGxlciBwb3NpdGlvbnMgYW5kIHZhbHVlcyBpbiB0aGUgbmV3IGFycmF5c1xuXHRcdFx0Y29uc3QgZmlsbGVyX3ZhbHMgPSBuZXcgQXJyYXkoTWF0aC5hYnMobm9fb2ZfZXh0cmFzKSkuZmlsbChcIlwiKTtcblx0XHRcdHN1cGVyaW1wb3NlZF92YWx1ZXMgPSBuZXdfdmFscy5jb25jYXQoZmlsbGVyX3ZhbHMpO1xuXG5cdFx0XHRjb25zdCBmaWxsZXJfcG9zID0gbmV3IEFycmF5KE1hdGguYWJzKG5vX29mX2V4dHJhcykpLmZpbGwobGFzdF9saW5lX3Bvcyk7XG5cdFx0XHRzdXBlcmltcG9zZWRfcG9zaXRpb25zID0gbmV3X3Bvcy5jb25jYXQoZmlsbGVyX3Bvcyk7XG5cdFx0fVxuXG5cdFx0c3VwZXJpbXBvc2VkX3ZhbHVlcy5tYXAoKHZhbHVlLCBpKSA9PiB7XG5cdFx0XHRhZGRfYW5kX2FuaW1hdGVfbGluZSh2YWx1ZSwgb2xkX3Bvc1tpXSwgc3VwZXJpbXBvc2VkX3Bvc2l0aW9uc1tpXSwgaSwgZ3JvdXApO1xuXHRcdH0pO1xuXG5cdFx0aWYobm9fb2ZfZXh0cmFzID4gMCkge1xuXHRcdFx0Ly8gQWRkIGluIGV4dHJhIGF4aXMgaW4gdGhlIGVuZFxuXHRcdFx0Ly8gYW5kIHRoZW4gYW5pbWF0ZSB0byBuZXcgcG9zaXRpb25zXG5cdFx0XHRjb25zdCBleHRyYV92YWx1ZXMgPSBuZXdfdmFscy5zbGljZShvbGRfdmFscy5sZW5ndGgpO1xuXHRcdFx0Y29uc3QgZXh0cmFfcG9zaXRpb25zID0gbmV3X3Bvcy5zbGljZShvbGRfcG9zLmxlbmd0aCk7XG5cblx0XHRcdGV4dHJhX3ZhbHVlcy5tYXAoKHZhbHVlLCBpKSA9PiB7XG5cdFx0XHRcdGFkZF9hbmRfYW5pbWF0ZV9saW5lKHZhbHVlLCBsYXN0X2xpbmVfcG9zLCBleHRyYV9wb3NpdGlvbnNbaV0sIGksIGdyb3VwKTtcblx0XHRcdH0pO1xuXHRcdH1cblx0fVxuXG5cdG1ha2VfeF9saW5lKGhlaWdodCwgdGV4dF9zdGFydF9hdCwgcG9pbnQsIGxhYmVsX2NsYXNzLCBheGlzX2xpbmVfY2xhc3MsIHhfcG9zKSB7XG5cdFx0bGV0IGFsbG93ZWRfc3BhY2UgPSB0aGlzLmF2Z191bml0X3dpZHRoICogMS41O1xuXG5cdFx0aWYodGhpcy5nZXRfc3Ryd2lkdGgocG9pbnQpID4gYWxsb3dlZF9zcGFjZSkge1xuXHRcdFx0bGV0IGFsbG93ZWRfbGV0dGVycyA9IGFsbG93ZWRfc3BhY2UgLyA4O1xuXHRcdFx0cG9pbnQgPSBwb2ludC5zbGljZSgwLCBhbGxvd2VkX2xldHRlcnMtMykgKyBcIiAuLi5cIjtcblx0XHR9XG5cblx0XHRsZXQgbGluZSA9ICQuY3JlYXRlU1ZHKCdsaW5lJywge1xuXHRcdFx0eDE6IDAsXG5cdFx0XHR4MjogMCxcblx0XHRcdHkxOiAwLFxuXHRcdFx0eTI6IGhlaWdodFxuXHRcdH0pO1xuXG5cdFx0bGV0IHRleHQgPSAkLmNyZWF0ZVNWRygndGV4dCcsIHtcblx0XHRcdGNsYXNzTmFtZTogbGFiZWxfY2xhc3MsXG5cdFx0XHR4OiAwLFxuXHRcdFx0eTogdGV4dF9zdGFydF9hdCxcblx0XHRcdGR5OiAnLjcxZW0nLFxuXHRcdFx0aW5uZXJIVE1MOiBwb2ludFxuXHRcdH0pO1xuXG5cdFx0bGV0IHhfbGV2ZWwgPSAkLmNyZWF0ZVNWRygnZycsIHtcblx0XHRcdGNsYXNzTmFtZTogYHRpY2sgJHtheGlzX2xpbmVfY2xhc3N9YCxcblx0XHRcdHRyYW5zZm9ybTogYHRyYW5zbGF0ZSgkeyB4X3BvcyB9LCAwKWBcblx0XHR9KTtcblxuXHRcdHhfbGV2ZWwuYXBwZW5kQ2hpbGQobGluZSk7XG5cdFx0eF9sZXZlbC5hcHBlbmRDaGlsZCh0ZXh0KTtcblxuXHRcdHJldHVybiB4X2xldmVsO1xuXHR9XG5cblx0bWFrZV95X2xpbmUoc3RhcnRfYXQsIHdpZHRoLCB0ZXh0X2VuZF9hdCwgcG9pbnQsIGxhYmVsX2NsYXNzLCBheGlzX2xpbmVfY2xhc3MsIHlfcG9zLCBkYXJrZXI9ZmFsc2UsIGxpbmVfdHlwZT1cIlwiKSB7XG5cdFx0bGV0IGxpbmUgPSAkLmNyZWF0ZVNWRygnbGluZScsIHtcblx0XHRcdGNsYXNzTmFtZTogbGluZV90eXBlID09PSBcImRhc2hlZFwiID8gXCJkYXNoZWRcIjogXCJcIixcblx0XHRcdHgxOiBzdGFydF9hdCxcblx0XHRcdHgyOiB3aWR0aCxcblx0XHRcdHkxOiAwLFxuXHRcdFx0eTI6IDBcblx0XHR9KTtcblxuXHRcdGxldCB0ZXh0ID0gJC5jcmVhdGVTVkcoJ3RleHQnLCB7XG5cdFx0XHRjbGFzc05hbWU6IGxhYmVsX2NsYXNzLFxuXHRcdFx0eDogdGV4dF9lbmRfYXQsXG5cdFx0XHR5OiAwLFxuXHRcdFx0ZHk6ICcuMzJlbScsXG5cdFx0XHRpbm5lckhUTUw6IHBvaW50K1wiXCJcblx0XHR9KTtcblxuXHRcdGxldCB5X2xldmVsID0gJC5jcmVhdGVTVkcoJ2cnLCB7XG5cdFx0XHRjbGFzc05hbWU6IGB0aWNrICR7YXhpc19saW5lX2NsYXNzfWAsXG5cdFx0XHR0cmFuc2Zvcm06IGB0cmFuc2xhdGUoMCwgJHt5X3Bvc30pYFxuXHRcdH0pO1xuXG5cdFx0aWYoZGFya2VyKSB7XG5cdFx0XHRsaW5lLnN0eWxlLnN0cm9rZSA9IFwicmdiYSgyNywgMzEsIDM1LCAwLjYpXCI7XG5cdFx0fVxuXG5cdFx0eV9sZXZlbC5hcHBlbmRDaGlsZChsaW5lKTtcblx0XHR5X2xldmVsLmFwcGVuZENoaWxkKHRleHQpO1xuXG5cdFx0cmV0dXJuIHlfbGV2ZWw7XG5cdH1cblxuXHRhZGRfYW5kX2FuaW1hdGVfeV9saW5lKHZhbHVlLCBvbGRfcG9zLCBuZXdfcG9zLCBpLCBncm91cCwgdHlwZSwgc3BlY2lmaWM9ZmFsc2UpIHtcblx0XHRsZXQgW3dpZHRoLCB0ZXh0X2VuZF9hdCwgYXhpc19saW5lX2NsYXNzLCBzdGFydF9hdF0gPSB0aGlzLmdldF95X2F4aXNfbGluZV9wcm9wcyhzcGVjaWZpYyk7XG5cdFx0bGV0IGF4aXNfbGFiZWxfY2xhc3MgPSAhc3BlY2lmaWMgPyAneS12YWx1ZS10ZXh0JyA6ICdzcGVjaWZpYy12YWx1ZSc7XG5cdFx0dmFsdWUgPSAhc3BlY2lmaWMgPyB2YWx1ZSA6ICh2YWx1ZStcIlwiKS50b1VwcGVyQ2FzZSgpO1xuXHRcdGNvbnN0IHlfbGluZSA9IHRoaXMubWFrZV95X2xpbmUoXG5cdFx0XHRzdGFydF9hdCxcblx0XHRcdHdpZHRoLFxuXHRcdFx0dGV4dF9lbmRfYXQsXG5cdFx0XHR2YWx1ZSxcblx0XHRcdGF4aXNfbGFiZWxfY2xhc3MsXG5cdFx0XHRheGlzX2xpbmVfY2xhc3MsXG5cdFx0XHRvbGRfcG9zLCAgLy8gb2xkIHBvc2l0aW9uXG5cdFx0XHQodmFsdWUgPT09IDAgJiYgaSAhPT0gMCksIC8vIE5vbi1maXJzdCBaZXJvIGxpbmVcblx0XHRcdHR5cGVcblx0XHQpO1xuXG5cdFx0Z3JvdXAuYXBwZW5kQ2hpbGQoeV9saW5lKTtcblxuXHRcdHRoaXMuZWxlbWVudHNfdG9fYW5pbWF0ZSAmJiB0aGlzLmVsZW1lbnRzX3RvX2FuaW1hdGUucHVzaChbXG5cdFx0XHR7dW5pdDogeV9saW5lLCBhcnJheTogWzBdLCBpbmRleDogMH0sXG5cdFx0XHR7dHJhbnNmb3JtOiBgMCwgJHsgbmV3X3BvcyB9YH0sXG5cdFx0XHQyNTAsXG5cdFx0XHRcImVhc2VpblwiLFxuXHRcdFx0XCJ0cmFuc2xhdGVcIixcblx0XHRcdHt0cmFuc2Zvcm06IGAwLCAkeyBvbGRfcG9zIH1gfVxuXHRcdF0pO1xuXHR9XG5cblx0Z2V0X3lfYXhpc19wb2ludHMoYXJyYXkpIHtcblx0XHQvLyoqKiBXaGVyZSB0aGUgbWFnaWMgaGFwcGVucyAqKipcblxuXHRcdC8vIENhbGN1bGF0ZXMgYmVzdC1maXQgeSBpbnRlcnZhbHMgZnJvbSBnaXZlbiB2YWx1ZXNcblx0XHQvLyBhbmQgcmV0dXJucyB0aGUgaW50ZXJ2YWwgYXJyYXlcblxuXHRcdC8vIFRPRE86IEZyYWN0aW9uc1xuXG5cdFx0bGV0IG1heF9ib3VuZCwgbWluX2JvdW5kLCBwb3Nfbm9fb2ZfcGFydHMsIG5lZ19ub19vZl9wYXJ0cywgcGFydF9zaXplOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzXG5cblx0XHQvLyBDcml0aWNhbCB2YWx1ZXNcblx0XHRsZXQgbWF4X3ZhbCA9IHBhcnNlSW50KE1hdGgubWF4KC4uLmFycmF5KSk7XG5cdFx0bGV0IG1pbl92YWwgPSBwYXJzZUludChNYXRoLm1pbiguLi5hcnJheSkpO1xuXHRcdGlmKG1pbl92YWwgPj0gMCkge1xuXHRcdFx0bWluX3ZhbCA9IDA7XG5cdFx0fVxuXG5cdFx0bGV0IGdldF9wYXJhbXMgPSAodmFsdWUxLCB2YWx1ZTIpID0+IHtcblx0XHRcdGxldCBib3VuZDEsIGJvdW5kMiwgbm9fb2ZfcGFydHNfMSwgbm9fb2ZfcGFydHNfMiwgaW50ZXJ2YWxfc2l6ZTtcblx0XHRcdGlmKCh2YWx1ZTErXCJcIikubGVuZ3RoIDw9IDEpIHtcblx0XHRcdFx0W2JvdW5kMSwgbm9fb2ZfcGFydHNfMV0gPSBbMTAsIDVdO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0W2JvdW5kMSwgbm9fb2ZfcGFydHNfMV0gPSB0aGlzLmNhbGNfdXBwZXJfYm91bmRfYW5kX25vX29mX3BhcnRzKHZhbHVlMSk7XG5cdFx0XHR9XG5cblx0XHRcdGludGVydmFsX3NpemUgPSBib3VuZDEgLyBub19vZl9wYXJ0c18xO1xuXHRcdFx0bm9fb2ZfcGFydHNfMiA9IHRoaXMuY2FsY19ub19vZl9wYXJ0cyh2YWx1ZTIsIGludGVydmFsX3NpemUpO1xuXHRcdFx0Ym91bmQyID0gbm9fb2ZfcGFydHNfMiAqIGludGVydmFsX3NpemU7XG5cblx0XHRcdHJldHVybiBbYm91bmQxLCBib3VuZDIsIG5vX29mX3BhcnRzXzEsIG5vX29mX3BhcnRzXzIsIGludGVydmFsX3NpemVdO1xuXHRcdH07XG5cblx0XHRjb25zdCBhYnNfbWluX3ZhbCA9IG1pbl92YWwgKiAtMTtcblx0XHRpZihhYnNfbWluX3ZhbCA8PSBtYXhfdmFsKSB7XG5cdFx0XHQvLyBHZXQgdGhlIHBvc2l0aXZlIHJlZ2lvbiBpbnRlcnZhbHNcblx0XHRcdC8vIHRoZW4gY2FsYyBuZWdhdGl2ZSBvbmVzIGFjY29yZGluZ2x5XG5cdFx0XHRbbWF4X2JvdW5kLCBtaW5fYm91bmQsIHBvc19ub19vZl9wYXJ0cywgbmVnX25vX29mX3BhcnRzLCBwYXJ0X3NpemVdXG5cdFx0XHRcdD0gZ2V0X3BhcmFtcyhtYXhfdmFsLCBhYnNfbWluX3ZhbCk7XG5cdFx0XHRpZihhYnNfbWluX3ZhbCA9PT0gMCkge1xuXHRcdFx0XHRtaW5fYm91bmQgPSAwOyBuZWdfbm9fb2ZfcGFydHMgPSAwO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBHZXQgdGhlIG5lZ2F0aXZlIHJlZ2lvbiBoZXJlIGZpcnN0XG5cdFx0XHRbbWluX2JvdW5kLCBtYXhfYm91bmQsIG5lZ19ub19vZl9wYXJ0cywgcG9zX25vX29mX3BhcnRzLCBwYXJ0X3NpemVdXG5cdFx0XHRcdD0gZ2V0X3BhcmFtcyhhYnNfbWluX3ZhbCwgbWF4X3ZhbCk7XG5cdFx0fVxuXG5cdFx0Ly8gTWFrZSBib3RoIHJlZ2lvbiBwYXJ0cyBldmVuXG5cdFx0aWYocG9zX25vX29mX3BhcnRzICUgMiAhPT0gMCAmJiBuZWdfbm9fb2ZfcGFydHMgPiAwKSBwb3Nfbm9fb2ZfcGFydHMrKztcblx0XHRpZihuZWdfbm9fb2ZfcGFydHMgJSAyICE9PSAwKSB7XG5cdFx0XHQvLyBldmVyeSBpbmNyZWFzZSBpbiBub19vZl9wYXJ0cyBlbnRhaWxzIGFuIGluY3JlYXNlIGluIGNvcnJlc3BvbmRpbmcgYm91bmRcblx0XHRcdC8vIGV4Y2VwdCBoZXJlLCBpdCBoYXBwZW5zIGltcGxpY2l0bHkgYWZ0ZXIgZXZlcnkgY2FsY19ub19vZl9wYXJ0cygpIGNhbGxcblx0XHRcdG5lZ19ub19vZl9wYXJ0cysrO1xuXHRcdFx0bWluX2JvdW5kICs9IHBhcnRfc2l6ZTtcblx0XHR9XG5cblx0XHRsZXQgbm9fb2ZfcGFydHMgPSBwb3Nfbm9fb2ZfcGFydHMgKyBuZWdfbm9fb2ZfcGFydHM7XG5cdFx0aWYobm9fb2ZfcGFydHMgPiA1KSB7XG5cdFx0XHRub19vZl9wYXJ0cyAvPSAyO1xuXHRcdFx0cGFydF9zaXplICo9IDI7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuZ2V0X2ludGVydmFscyhcblx0XHRcdCgtMSkgKiBtaW5fYm91bmQsXG5cdFx0XHRwYXJ0X3NpemUsXG5cdFx0XHRub19vZl9wYXJ0c1xuXHRcdCk7XG5cdH1cblxuXHRnZXRfaW50ZXJ2YWxzKHN0YXJ0LCBpbnRlcnZhbF9zaXplLCBjb3VudCkge1xuXHRcdGxldCBpbnRlcnZhbHMgPSBbXTtcblx0XHRmb3IodmFyIGkgPSAwOyBpIDw9IGNvdW50OyBpKyspe1xuXHRcdFx0aW50ZXJ2YWxzLnB1c2goc3RhcnQpO1xuXHRcdFx0c3RhcnQgKz0gaW50ZXJ2YWxfc2l6ZTtcblx0XHR9XG5cdFx0cmV0dXJuIGludGVydmFscztcblx0fVxuXG5cdGNhbGNfdXBwZXJfYm91bmRfYW5kX25vX29mX3BhcnRzKG1heF92YWwpIHtcblx0XHQvLyBHaXZlbiBhIHBvc2l0aXZlIHZhbHVlLCBjYWxjdWxhdGVzIGEgbmljZS1udW1iZXIgdXBwZXIgYm91bmRcblx0XHQvLyBhbmQgYSBjb25zZXF1ZW50IG9wdGltYWwgbnVtYmVyIG9mIHBhcnRzXG5cblx0XHRjb25zdCBwYXJ0X3NpemUgPSBNYXRoLnBvdygxMCwgKChtYXhfdmFsK1wiXCIpLmxlbmd0aCAtIDEpKTtcblx0XHRjb25zdCBub19vZl9wYXJ0cyA9IHRoaXMuY2FsY19ub19vZl9wYXJ0cyhtYXhfdmFsLCBwYXJ0X3NpemUpO1xuXG5cdFx0Ly8gVXNlIGl0IHRvIGdldCBhIG5pY2UgZXZlbiB1cHBlciBib3VuZFxuXHRcdGNvbnN0IHVwcGVyX2JvdW5kID0gcGFydF9zaXplICogbm9fb2ZfcGFydHM7XG5cblx0XHRyZXR1cm4gW3VwcGVyX2JvdW5kLCBub19vZl9wYXJ0c107XG5cdH1cblxuXHRjYWxjX25vX29mX3BhcnRzKHZhbHVlLCBkaXZpc29yKSB7XG5cdFx0Ly8gdmFsdWUgc2hvdWxkIGJlIGEgcG9zaXRpdmUgbnVtYmVyLCBkaXZpc29yIHNob3VsZCBiZSBncmVhdGVyIHRoYW4gMFxuXHRcdC8vIHJldHVybnMgYW4gZXZlbiBubyBvZiBwYXJ0c1xuXHRcdGxldCBub19vZl9wYXJ0cyA9IE1hdGguY2VpbCh2YWx1ZSAvIGRpdmlzb3IpO1xuXHRcdGlmKG5vX29mX3BhcnRzICUgMiAhPT0gMCkgbm9fb2ZfcGFydHMrKzsgLy8gTWFrZSBpdCBhbiBldmVuIG51bWJlclxuXG5cdFx0cmV0dXJuIG5vX29mX3BhcnRzO1xuXHR9XG5cblx0Z2V0X29wdGltYWxfbm9fb2ZfcGFydHMobm9fb2ZfcGFydHMpIHtcblx0XHQvLyBha2EgRGl2aWRlIGJ5IDIgaWYgdG9vIGxhcmdlXG5cdFx0cmV0dXJuIChub19vZl9wYXJ0cyA8IDUpID8gbm9fb2ZfcGFydHMgOiBub19vZl9wYXJ0cyAvIDI7XG5cdH1cblxuXHRzZXRfYXZnX3VuaXRfd2lkdGhfYW5kX3hfb2Zmc2V0KCkge1xuXHRcdC8vIFNldCB0aGUgLi4uIHlvdSBnZXQgaXRcblx0XHR0aGlzLmF2Z191bml0X3dpZHRoID0gdGhpcy53aWR0aC8odGhpcy54Lmxlbmd0aCAtIDEpO1xuXHRcdHRoaXMueF9vZmZzZXQgPSAwO1xuXHR9XG5cblx0Z2V0X2FsbF95X3ZhbHVlcygpIHtcblx0XHRsZXQgYWxsX3ZhbHVlcyA9IFtdO1xuXG5cdFx0Ly8gQWRkIGluIGFsbCB0aGUgeSB2YWx1ZXMgaW4gdGhlIGRhdGFzZXRzXG5cdFx0dGhpcy55Lm1hcChkID0+IHtcblx0XHRcdGFsbF92YWx1ZXMgPSBhbGxfdmFsdWVzLmNvbmNhdChkLnZhbHVlcyk7XG5cdFx0fSk7XG5cblx0XHQvLyBBZGQgaW4gYWxsIHRoZSBzcGVjaWZpYyB2YWx1ZXNcblx0XHRyZXR1cm4gYWxsX3ZhbHVlcy5jb25jYXQodGhpcy5zcGVjaWZpY192YWx1ZXMubWFwKGQgPT4gZC52YWx1ZSkpO1xuXHR9XG5cblx0Y2FsY195X2RlcGVuZGVuY2llcygpIHtcblx0XHR0aGlzLnlfbWluX3RvcHMgPSBuZXcgQXJyYXkodGhpcy54X2F4aXNfcG9zaXRpb25zLmxlbmd0aCkuZmlsbCg5OTk5KTtcblx0XHR0aGlzLnkubWFwKGQgPT4ge1xuXHRcdFx0ZC55X3RvcHMgPSBkLnZhbHVlcy5tYXAoIHZhbCA9PiBmbG9hdF8yKHRoaXMuemVyb19saW5lIC0gdmFsICogdGhpcy5tdWx0aXBsaWVyKSk7XG5cdFx0XHRkLnlfdG9wcy5tYXAoICh5X3RvcCwgaSkgPT4ge1xuXHRcdFx0XHRpZih5X3RvcCA8IHRoaXMueV9taW5fdG9wc1tpXSkge1xuXHRcdFx0XHRcdHRoaXMueV9taW5fdG9wc1tpXSA9IHlfdG9wO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHR9KTtcblx0fVxuXG5cdGdldF9iYXJfaGVpZ2h0X2FuZF95X2F0dHIoeV90b3ApIHtcblx0XHRsZXQgaGVpZ2h0LCB5O1xuXHRcdGlmICh5X3RvcCA8PSB0aGlzLnplcm9fbGluZSkge1xuXHRcdFx0aGVpZ2h0ID0gdGhpcy56ZXJvX2xpbmUgLSB5X3RvcDtcblx0XHRcdHkgPSB5X3RvcDtcblxuXHRcdFx0Ly8gSW4gY2FzZSBvZiBpbnZpc2libGUgYmFyc1xuXHRcdFx0aWYoaGVpZ2h0ID09PSAwKSB7XG5cdFx0XHRcdGhlaWdodCA9IHRoaXMuaGVpZ2h0ICogMC4wMTtcblx0XHRcdFx0eSAtPSBoZWlnaHQ7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGhlaWdodCA9IHlfdG9wIC0gdGhpcy56ZXJvX2xpbmU7XG5cdFx0XHR5ID0gdGhpcy56ZXJvX2xpbmU7XG5cblx0XHRcdC8vIEluIGNhc2Ugb2YgaW52aXNpYmxlIGJhcnNcblx0XHRcdGlmKGhlaWdodCA9PT0gMCkge1xuXHRcdFx0XHRoZWlnaHQgPSB0aGlzLmhlaWdodCAqIDAuMDE7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIFtoZWlnaHQsIHldO1xuXHR9XG5cblx0c2V0dXBfdXRpbHMoKSB7XG5cdFx0dGhpcy5kcmF3ID0ge1xuXHRcdFx0J2Jhcic6ICh4LCB5X3RvcCwgYXJncywgY29sb3IsIGluZGV4LCBub19vZl9kYXRhc2V0cykgPT4ge1xuXHRcdFx0XHRsZXQgdG90YWxfd2lkdGggPSB0aGlzLmF2Z191bml0X3dpZHRoIC0gYXJncy5zcGFjZV93aWR0aDtcblx0XHRcdFx0bGV0IHN0YXJ0X3ggPSB4IC0gdG90YWxfd2lkdGgvMjtcblxuXHRcdFx0XHRsZXQgd2lkdGggPSB0b3RhbF93aWR0aCAvIG5vX29mX2RhdGFzZXRzO1xuXHRcdFx0XHRsZXQgY3VycmVudF94ID0gc3RhcnRfeCArIHdpZHRoICogaW5kZXg7XG5cblx0XHRcdFx0bGV0IFtoZWlnaHQsIHldID0gdGhpcy5nZXRfYmFyX2hlaWdodF9hbmRfeV9hdHRyKHlfdG9wKTtcblxuXHRcdFx0XHRyZXR1cm4gJC5jcmVhdGVTVkcoJ3JlY3QnLCB7XG5cdFx0XHRcdFx0Y2xhc3NOYW1lOiBgYmFyIG1pbmkgZmlsbCAke2NvbG9yfWAsXG5cdFx0XHRcdFx0eDogY3VycmVudF94LFxuXHRcdFx0XHRcdHk6IHksXG5cdFx0XHRcdFx0d2lkdGg6IHdpZHRoLFxuXHRcdFx0XHRcdGhlaWdodDogaGVpZ2h0XG5cdFx0XHRcdH0pO1xuXG5cdFx0XHR9LFxuXHRcdFx0J2RvdCc6ICh4LCB5LCBhcmdzLCBjb2xvcikgPT4ge1xuXHRcdFx0XHRyZXR1cm4gJC5jcmVhdGVTVkcoJ2NpcmNsZScsIHtcblx0XHRcdFx0XHRjbGFzc05hbWU6IGBmaWxsICR7Y29sb3J9YCxcblx0XHRcdFx0XHRjeDogeCxcblx0XHRcdFx0XHRjeTogeSxcblx0XHRcdFx0XHRyOiBhcmdzLnJhZGl1c1xuXHRcdFx0XHR9KTtcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0dGhpcy5hbmltYXRlID0ge1xuXHRcdFx0J2Jhcic6IChiYXJfb2JqLCB4LCB5X3RvcCwgaW5kZXgpID0+IHtcblx0XHRcdFx0bGV0IHN0YXJ0ID0geCAtIHRoaXMuYXZnX3VuaXRfd2lkdGgvNDtcblx0XHRcdFx0bGV0IHdpZHRoID0gKHRoaXMuYXZnX3VuaXRfd2lkdGgvMikvdGhpcy55Lmxlbmd0aDtcblx0XHRcdFx0bGV0IFtoZWlnaHQsIHldID0gdGhpcy5nZXRfYmFyX2hlaWdodF9hbmRfeV9hdHRyKHlfdG9wKTtcblxuXHRcdFx0XHR4ID0gc3RhcnQgKyAod2lkdGggKiBpbmRleCk7XG5cblx0XHRcdFx0cmV0dXJuIFtiYXJfb2JqLCB7d2lkdGg6IHdpZHRoLCBoZWlnaHQ6IGhlaWdodCwgeDogeCwgeTogeX0sIDI1MCwgXCJlYXNlaW5cIl07XG5cdFx0XHRcdC8vIGJhci5hbmltYXRlKHtoZWlnaHQ6IGFyZ3MubmV3X2hlaWdodCwgeTogeV90b3B9LCAyNTAsIG1pbmEuZWFzZWluKTtcblx0XHRcdH0sXG5cdFx0XHQnZG90JzogKGRvdF9vYmosIHgsIHlfdG9wKSA9PiB7XG5cdFx0XHRcdHJldHVybiBbZG90X29iaiwge2N4OiB4LCBjeTogeV90b3B9LCAzMDAsIFwiZWFzZWluXCJdO1xuXHRcdFx0XHQvLyBkb3QuYW5pbWF0ZSh7Y3k6IHlfdG9wfSwgMjUwLCBtaW5hLmVhc2Vpbik7XG5cdFx0XHR9XG5cdFx0fTtcblx0fVxufVxuXG5jbGFzcyBCYXJDaGFydCBleHRlbmRzIEF4aXNDaGFydCB7XG5cdGNvbnN0cnVjdG9yKGFyZ3MpIHtcblx0XHRzdXBlcihhcmdzKTtcblxuXHRcdHRoaXMudHlwZSA9ICdiYXInO1xuXHRcdHRoaXMueF9heGlzX21vZGUgPSBhcmdzLnhfYXhpc19tb2RlIHx8ICd0aWNrJztcblx0XHR0aGlzLnlfYXhpc19tb2RlID0gYXJncy55X2F4aXNfbW9kZSB8fCAnc3Bhbic7XG5cdFx0dGhpcy5zZXR1cCgpO1xuXHR9XG5cblx0c2V0dXBfdmFsdWVzKCkge1xuXHRcdHN1cGVyLnNldHVwX3ZhbHVlcygpO1xuXHRcdHRoaXMueF9vZmZzZXQgPSB0aGlzLmF2Z191bml0X3dpZHRoO1xuXHRcdHRoaXMudW5pdF9hcmdzID0ge1xuXHRcdFx0dHlwZTogJ2JhcicsXG5cdFx0XHRhcmdzOiB7XG5cdFx0XHRcdHNwYWNlX3dpZHRoOiB0aGlzLmF2Z191bml0X3dpZHRoLzIsXG5cdFx0XHR9XG5cdFx0fTtcblx0fVxuXG5cdG1ha2Vfb3ZlcmxheSgpIHtcblx0XHQvLyBKdXN0IG1ha2Ugb25lIG91dCBvZiB0aGUgZmlyc3QgZWxlbWVudFxuXHRcdGxldCBpbmRleCA9IHRoaXMueC5sZW5ndGggLSAxO1xuXHRcdGxldCB1bml0ID0gdGhpcy55WzBdLnN2Z191bml0c1tpbmRleF07XG5cdFx0dGhpcy51cGRhdGVfY3VycmVudF9kYXRhX3BvaW50KGluZGV4KTtcblxuXHRcdGlmKHRoaXMub3ZlcmxheSkge1xuXHRcdFx0dGhpcy5vdmVybGF5LnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodGhpcy5vdmVybGF5KTtcblx0XHR9XG5cblx0XHR0aGlzLm92ZXJsYXkgPSB1bml0LmNsb25lTm9kZSgpO1xuXHRcdHRoaXMub3ZlcmxheS5zdHlsZS5maWxsID0gJyMwMDAwMDAnO1xuXHRcdHRoaXMub3ZlcmxheS5zdHlsZS5vcGFjaXR5ID0gJzAuNCc7XG5cdFx0dGhpcy5kcmF3X2FyZWEuYXBwZW5kQ2hpbGQodGhpcy5vdmVybGF5KTtcblx0fVxuXG5cdGJpbmRfb3ZlcmxheSgpIHtcblx0XHQvLyBvbiBldmVudCwgdXBkYXRlIG92ZXJsYXlcblx0XHR0aGlzLnBhcmVudC5hZGRFdmVudExpc3RlbmVyKCdkYXRhLXNlbGVjdCcsIChlKSA9PiB7XG5cdFx0XHR0aGlzLnVwZGF0ZV9vdmVybGF5KGUuc3ZnX3VuaXQpO1xuXHRcdH0pO1xuXHR9XG5cblx0dXBkYXRlX292ZXJsYXkodW5pdCkge1xuXHRcdGxldCBhdHRyaWJ1dGVzID0gW107XG5cdFx0T2JqZWN0LmtleXModW5pdC5hdHRyaWJ1dGVzKS5tYXAoaW5kZXggPT4ge1xuXHRcdFx0YXR0cmlidXRlcy5wdXNoKHVuaXQuYXR0cmlidXRlc1tpbmRleF0pO1xuXHRcdH0pO1xuXG5cdFx0YXR0cmlidXRlcy5maWx0ZXIoYXR0ciA9PiBhdHRyLnNwZWNpZmllZCkubWFwKGF0dHIgPT4ge1xuXHRcdFx0dGhpcy5vdmVybGF5LnNldEF0dHJpYnV0ZShhdHRyLm5hbWUsIGF0dHIubm9kZVZhbHVlKTtcblx0XHR9KTtcblx0fVxuXG5cdG9uX2xlZnRfYXJyb3coKSB7XG5cdFx0dGhpcy51cGRhdGVfY3VycmVudF9kYXRhX3BvaW50KHRoaXMuY3VycmVudF9pbmRleCAtIDEpO1xuXHR9XG5cblx0b25fcmlnaHRfYXJyb3coKSB7XG5cdFx0dGhpcy51cGRhdGVfY3VycmVudF9kYXRhX3BvaW50KHRoaXMuY3VycmVudF9pbmRleCArIDEpO1xuXHR9XG5cblx0c2V0X2F2Z191bml0X3dpZHRoX2FuZF94X29mZnNldCgpIHtcblx0XHR0aGlzLmF2Z191bml0X3dpZHRoID0gdGhpcy53aWR0aC8odGhpcy54Lmxlbmd0aCArIDEpO1xuXHRcdHRoaXMueF9vZmZzZXQgPSB0aGlzLmF2Z191bml0X3dpZHRoO1xuXHR9XG59XG5cbmNsYXNzIExpbmVDaGFydCBleHRlbmRzIEF4aXNDaGFydCB7XG5cdGNvbnN0cnVjdG9yKGFyZ3MpIHtcblx0XHRzdXBlcihhcmdzKTtcblx0XHRpZihPYmplY3QuZ2V0UHJvdG90eXBlT2YodGhpcykgIT09IExpbmVDaGFydC5wcm90b3R5cGUpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLnR5cGUgPSAnbGluZSc7XG5cdFx0dGhpcy5yZWdpb25fZmlsbCA9IGFyZ3MucmVnaW9uX2ZpbGw7XG5cdFx0dGhpcy54X2F4aXNfbW9kZSA9IGFyZ3MueF9heGlzX21vZGUgfHwgJ3NwYW4nO1xuXHRcdHRoaXMueV9heGlzX21vZGUgPSBhcmdzLnlfYXhpc19tb2RlIHx8ICdzcGFuJztcblxuXHRcdHRoaXMuc2V0dXAoKTtcblx0fVxuXG5cdHNldHVwX2dyYXBoX2NvbXBvbmVudHMoKSB7XG5cdFx0dGhpcy5zZXR1cF9wYXRoX2dyb3VwcygpO1xuXHRcdHN1cGVyLnNldHVwX2dyYXBoX2NvbXBvbmVudHMoKTtcblx0fVxuXG5cdHNldHVwX3BhdGhfZ3JvdXBzKCkge1xuXHRcdHRoaXMucGF0aHNfZ3JvdXBzID0gW107XG5cdFx0dGhpcy55Lm1hcCgoZCwgaSkgPT4ge1xuXHRcdFx0dGhpcy5wYXRoc19ncm91cHNbaV0gPSAkLmNyZWF0ZVNWRygnZycsIHtcblx0XHRcdFx0Y2xhc3NOYW1lOiAncGF0aC1ncm91cCBwYXRoLWdyb3VwLScgKyBpLFxuXHRcdFx0XHRpbnNpZGU6IHRoaXMuZHJhd19hcmVhXG5cdFx0XHR9KTtcblx0XHR9KTtcblx0fVxuXG5cdHNldHVwX3ZhbHVlcygpIHtcblx0XHRzdXBlci5zZXR1cF92YWx1ZXMoKTtcblx0XHR0aGlzLnVuaXRfYXJncyA9IHtcblx0XHRcdHR5cGU6ICdkb3QnLFxuXHRcdFx0YXJnczogeyByYWRpdXM6IDggfVxuXHRcdH07XG5cdH1cblxuXHRtYWtlX3BhdGhzKCkge1xuXHRcdHRoaXMueS5tYXAoKGQsIGkpID0+IHtcblx0XHRcdHRoaXMubWFrZV9wYXRoKGQsIGksIHRoaXMueF9heGlzX3Bvc2l0aW9ucywgZC55X3RvcHMsIGQuY29sb3IgfHwgdGhpcy5jb2xvcnNbaV0pO1xuXHRcdH0pO1xuXHR9XG5cblx0bWFrZV9wYXRoKGQsIGksIHhfcG9zaXRpb25zLCB5X3Bvc2l0aW9ucywgY29sb3IpIHtcblx0XHRsZXQgcG9pbnRzX2xpc3QgPSB5X3Bvc2l0aW9ucy5tYXAoKHksIGkpID0+ICh4X3Bvc2l0aW9uc1tpXSArICcsJyArIHkpKTtcblx0XHRsZXQgcG9pbnRzX3N0ciA9IHBvaW50c19saXN0LmpvaW4oXCJMXCIpO1xuXG5cdFx0dGhpcy5wYXRoc19ncm91cHNbaV0udGV4dENvbnRlbnQgPSAnJztcblxuXHRcdGQucGF0aCA9ICQuY3JlYXRlU1ZHKCdwYXRoJywge1xuXHRcdFx0aW5zaWRlOiB0aGlzLnBhdGhzX2dyb3Vwc1tpXSxcblx0XHRcdGNsYXNzTmFtZTogYHN0cm9rZSAke2NvbG9yfWAsXG5cdFx0XHRkOiBcIk1cIitwb2ludHNfc3RyXG5cdFx0fSk7XG5cblx0XHRpZih0aGlzLnJlZ2lvbl9maWxsKSB7XG5cdFx0XHRsZXQgZ3JhZGllbnRfaWQgPSdwYXRoLWZpbGwtZ3JhZGllbnQnICsgJy0nICsgY29sb3I7XG5cblx0XHRcdHRoaXMuZ3JhZGllbnRfZGVmID0gJC5jcmVhdGVTVkcoJ2xpbmVhckdyYWRpZW50Jywge1xuXHRcdFx0XHRpbnNpZGU6IHRoaXMuc3ZnX2RlZnMsXG5cdFx0XHRcdGlkOiBncmFkaWVudF9pZCxcblx0XHRcdFx0eDE6IDAsXG5cdFx0XHRcdHgyOiAwLFxuXHRcdFx0XHR5MTogMCxcblx0XHRcdFx0eTI6IDFcblx0XHRcdH0pO1xuXG5cdFx0XHRsZXQgc2V0X2dyYWRpZW50X3N0b3AgPSAoZ3JhZF9lbGVtLCBvZmZzZXQsIGNvbG9yLCBvcGFjaXR5KSA9PiB7XG5cdFx0XHRcdCQuY3JlYXRlU1ZHKCdzdG9wJywge1xuXHRcdFx0XHRcdCdjbGFzc05hbWUnOiAnc3RvcC1jb2xvciAnICsgY29sb3IsXG5cdFx0XHRcdFx0J2luc2lkZSc6IGdyYWRfZWxlbSxcblx0XHRcdFx0XHQnb2Zmc2V0Jzogb2Zmc2V0LFxuXHRcdFx0XHRcdCdzdG9wLW9wYWNpdHknOiBvcGFjaXR5XG5cdFx0XHRcdH0pO1xuXHRcdFx0fTtcblxuXHRcdFx0c2V0X2dyYWRpZW50X3N0b3AodGhpcy5ncmFkaWVudF9kZWYsIFwiMCVcIiwgY29sb3IsIDAuNCk7XG5cdFx0XHRzZXRfZ3JhZGllbnRfc3RvcCh0aGlzLmdyYWRpZW50X2RlZiwgXCI1MCVcIiwgY29sb3IsIDAuMik7XG5cdFx0XHRzZXRfZ3JhZGllbnRfc3RvcCh0aGlzLmdyYWRpZW50X2RlZiwgXCIxMDAlXCIsIGNvbG9yLCAwKTtcblxuXHRcdFx0ZC5yZWdpb25fcGF0aCA9ICQuY3JlYXRlU1ZHKCdwYXRoJywge1xuXHRcdFx0XHRpbnNpZGU6IHRoaXMucGF0aHNfZ3JvdXBzW2ldLFxuXHRcdFx0XHRjbGFzc05hbWU6IGByZWdpb24tZmlsbGAsXG5cdFx0XHRcdGQ6IFwiTVwiICsgYDAsJHt0aGlzLnplcm9fbGluZX1MYCArIHBvaW50c19zdHIgKyBgTCR7dGhpcy53aWR0aH0sJHt0aGlzLnplcm9fbGluZX1gLFxuXHRcdFx0fSk7XG5cblx0XHRcdGQucmVnaW9uX3BhdGguc3R5bGUuc3Ryb2tlID0gXCJub25lXCI7XG5cdFx0XHRkLnJlZ2lvbl9wYXRoLnN0eWxlLmZpbGwgPSBgdXJsKCMke2dyYWRpZW50X2lkfSlgO1xuXHRcdH1cblx0fVxufVxuXG5jbGFzcyBQZXJjZW50YWdlQ2hhcnQgZXh0ZW5kcyBDaGFydCB7XG5cdGNvbnN0cnVjdG9yKGFyZ3MpIHtcblx0XHRzdXBlcihhcmdzKTtcblx0XHR0aGlzLnR5cGUgPSAncGVyY2VudGFnZSc7XG5cblx0XHR0aGlzLmdldF95X2xhYmVsID0gdGhpcy5mb3JtYXRfbGFtYmRhcy55X2xhYmVsO1xuXHRcdHRoaXMuZ2V0X3hfdG9vbHRpcCA9IHRoaXMuZm9ybWF0X2xhbWJkYXMueF90b29sdGlwO1xuXHRcdHRoaXMuZ2V0X3lfdG9vbHRpcCA9IHRoaXMuZm9ybWF0X2xhbWJkYXMueV90b29sdGlwO1xuXG5cdFx0dGhpcy5tYXhfc2xpY2VzID0gMTA7XG5cdFx0dGhpcy5tYXhfbGVnZW5kX3BvaW50cyA9IDY7XG5cblx0XHR0aGlzLmNvbG9ycyA9IGFyZ3MuY29sb3JzO1xuXG5cdFx0aWYoIXRoaXMuY29sb3JzIHx8IHRoaXMuY29sb3JzLmxlbmd0aCA8IHRoaXMuZGF0YS5sYWJlbHMubGVuZ3RoKSB7XG5cdFx0XHR0aGlzLmNvbG9ycyA9IFsnbGlnaHQtYmx1ZScsICdibHVlJywgJ3Zpb2xldCcsICdyZWQnLCAnb3JhbmdlJyxcblx0XHRcdFx0J3llbGxvdycsICdncmVlbicsICdsaWdodC1ncmVlbicsICdwdXJwbGUnLCAnbWFnZW50YSddO1xuXHRcdH1cblxuXHRcdHRoaXMuc2V0dXAoKTtcblx0fVxuXG5cdG1ha2VfY2hhcnRfYXJlYSgpIHtcblx0XHR0aGlzLmNoYXJ0X3dyYXBwZXIuY2xhc3NOYW1lICs9ICcgJyArICdncmFwaC1mb2N1cy1tYXJnaW4nO1xuXHRcdHRoaXMuY2hhcnRfd3JhcHBlci5zdHlsZS5tYXJnaW5Ub3AgPSAnNDVweCc7XG5cblx0XHR0aGlzLnN0YXRzX3dyYXBwZXIuY2xhc3NOYW1lICs9ICcgJyArICdncmFwaC1mb2N1cy1tYXJnaW4nO1xuXHRcdHRoaXMuc3RhdHNfd3JhcHBlci5zdHlsZS5tYXJnaW5Cb3R0b20gPSAnMzBweCc7XG5cdFx0dGhpcy5zdGF0c193cmFwcGVyLnN0eWxlLnBhZGRpbmdUb3AgPSAnMHB4Jztcblx0fVxuXG5cdG1ha2VfZHJhd19hcmVhKCkge1xuXHRcdHRoaXMuY2hhcnRfZGl2ID0gJC5jcmVhdGUoJ2RpdicsIHtcblx0XHRcdGNsYXNzTmFtZTogJ2RpdicsXG5cdFx0XHRpbnNpZGU6IHRoaXMuY2hhcnRfd3JhcHBlcixcblx0XHRcdHdpZHRoOiB0aGlzLmJhc2Vfd2lkdGgsXG5cdFx0XHRoZWlnaHQ6IHRoaXMuYmFzZV9oZWlnaHRcblx0XHR9KTtcblxuXHRcdHRoaXMuY2hhcnQgPSAkLmNyZWF0ZSgnZGl2Jywge1xuXHRcdFx0Y2xhc3NOYW1lOiAncHJvZ3Jlc3MtY2hhcnQnLFxuXHRcdFx0aW5zaWRlOiB0aGlzLmNoYXJ0X2RpdlxuXHRcdH0pO1xuXHR9XG5cblx0c2V0dXBfY29tcG9uZW50cygpIHtcblx0XHR0aGlzLnBlcmNlbnRhZ2VfYmFyID0gJC5jcmVhdGUoJ2RpdicsIHtcblx0XHRcdGNsYXNzTmFtZTogJ3Byb2dyZXNzJyxcblx0XHRcdGluc2lkZTogdGhpcy5jaGFydFxuXHRcdH0pO1xuXHR9XG5cblx0c2V0dXBfdmFsdWVzKCkge1xuXHRcdHRoaXMuc2xpY2VfdG90YWxzID0gW107XG5cdFx0bGV0IGFsbF90b3RhbHMgPSB0aGlzLmRhdGEubGFiZWxzLm1hcCgoZCwgaSkgPT4ge1xuXHRcdFx0bGV0IHRvdGFsID0gMDtcblx0XHRcdHRoaXMuZGF0YS5kYXRhc2V0cy5tYXAoZSA9PiB7XG5cdFx0XHRcdHRvdGFsICs9IGUudmFsdWVzW2ldO1xuXHRcdFx0fSk7XG5cdFx0XHRyZXR1cm4gW3RvdGFsLCBkXTtcblx0XHR9KS5maWx0ZXIoZCA9PiB7IHJldHVybiBkWzBdID4gMDsgfSk7IC8vIGtlZXAgb25seSBwb3NpdGl2ZSByZXN1bHRzXG5cblx0XHRsZXQgdG90YWxzID0gYWxsX3RvdGFscztcblxuXHRcdGlmKGFsbF90b3RhbHMubGVuZ3RoID4gdGhpcy5tYXhfc2xpY2VzKSB7XG5cdFx0XHRhbGxfdG90YWxzLnNvcnQoKGEsIGIpID0+IHsgcmV0dXJuIGJbMF0gLSBhWzBdOyB9KTtcblxuXHRcdFx0dG90YWxzID0gYWxsX3RvdGFscy5zbGljZSgwLCB0aGlzLm1heF9zbGljZXMtMSk7XG5cdFx0XHRsZXQgb3RoZXJzID0gYWxsX3RvdGFscy5zbGljZSh0aGlzLm1heF9zbGljZXMtMSk7XG5cblx0XHRcdGxldCBzdW1fb2Zfb3RoZXJzID0gMDtcblx0XHRcdG90aGVycy5tYXAoZCA9PiB7c3VtX29mX290aGVycyArPSBkWzBdO30pO1xuXG5cdFx0XHR0b3RhbHMucHVzaChbc3VtX29mX290aGVycywgJ1Jlc3QnXSk7XG5cblx0XHRcdHRoaXMuY29sb3JzW3RoaXMubWF4X3NsaWNlcy0xXSA9ICdncmV5Jztcblx0XHR9XG5cblx0XHR0aGlzLmxhYmVscyA9IFtdO1xuXHRcdHRvdGFscy5tYXAoZCA9PiB7XG5cdFx0XHR0aGlzLnNsaWNlX3RvdGFscy5wdXNoKGRbMF0pO1xuXHRcdFx0dGhpcy5sYWJlbHMucHVzaChkWzFdKTtcblx0XHR9KTtcblxuXHRcdHRoaXMubGVnZW5kX3RvdGFscyA9IHRoaXMuc2xpY2VfdG90YWxzLnNsaWNlKDAsIHRoaXMubWF4X2xlZ2VuZF9wb2ludHMpO1xuXHR9XG5cblx0c2V0dXBfdXRpbHMoKSB7IH1cblxuXHRtYWtlX2dyYXBoX2NvbXBvbmVudHMoKSB7XG5cdFx0dGhpcy5ncmFuZF90b3RhbCA9IHRoaXMuc2xpY2VfdG90YWxzLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApO1xuXHRcdHRoaXMuc2xpY2VzID0gW107XG5cdFx0dGhpcy5zbGljZV90b3RhbHMubWFwKCh0b3RhbCwgaSkgPT4ge1xuXHRcdFx0bGV0IHNsaWNlID0gJC5jcmVhdGUoJ2RpdicsIHtcblx0XHRcdFx0Y2xhc3NOYW1lOiBgcHJvZ3Jlc3MtYmFyIGJhY2tncm91bmQgJHt0aGlzLmNvbG9yc1tpXX1gLFxuXHRcdFx0XHRzdHlsZTogYHdpZHRoOiAke3RvdGFsKjEwMC90aGlzLmdyYW5kX3RvdGFsfSVgLFxuXHRcdFx0XHRpbnNpZGU6IHRoaXMucGVyY2VudGFnZV9iYXJcblx0XHRcdH0pO1xuXHRcdFx0dGhpcy5zbGljZXMucHVzaChzbGljZSk7XG5cdFx0fSk7XG5cdH1cblxuXHRiaW5kX3Rvb2x0aXAoKSB7XG5cdFx0dGhpcy5zbGljZXMubWFwKChzbGljZSwgaSkgPT4ge1xuXHRcdFx0c2xpY2UuYWRkRXZlbnRMaXN0ZW5lcignbW91c2VlbnRlcicsICgpID0+IHtcblx0XHRcdFx0bGV0IGdfb2ZmID0gJC5vZmZzZXQodGhpcy5jaGFydF93cmFwcGVyKSwgcF9vZmYgPSAkLm9mZnNldChzbGljZSk7XG5cblx0XHRcdFx0bGV0IHggPSBwX29mZi5sZWZ0IC0gZ19vZmYubGVmdCArIHNsaWNlLm9mZnNldFdpZHRoLzI7XG5cdFx0XHRcdGxldCB5ID0gcF9vZmYudG9wIC0gZ19vZmYudG9wIC0gNjtcblx0XHRcdFx0bGV0IHRpdGxlID0gKHRoaXMuZm9ybWF0dGVkX2xhYmVscyAmJiB0aGlzLmZvcm1hdHRlZF9sYWJlbHMubGVuZ3RoPjBcblx0XHRcdFx0XHQ/IHRoaXMuZm9ybWF0dGVkX2xhYmVsc1tpXSA6IHRoaXMubGFiZWxzW2ldKSArICc6ICc7XG5cdFx0XHRcdGxldCBwZXJjZW50ID0gKHRoaXMuc2xpY2VfdG90YWxzW2ldKjEwMC90aGlzLmdyYW5kX3RvdGFsKS50b0ZpeGVkKDEpO1xuXG5cdFx0XHRcdHRoaXMudGlwLnNldF92YWx1ZXMoeCwgeSwgdGl0bGUsIHBlcmNlbnQgKyBcIiVcIik7XG5cdFx0XHRcdHRoaXMudGlwLnNob3dfdGlwKCk7XG5cdFx0XHR9KTtcblx0XHR9KTtcblx0fVxuXG5cdHNob3dfc3VtbWFyeSgpIHtcblx0XHRsZXQgeF92YWx1ZXMgPSB0aGlzLmZvcm1hdHRlZF9sYWJlbHMgJiYgdGhpcy5mb3JtYXR0ZWRfbGFiZWxzLmxlbmd0aCA+IDBcblx0XHRcdD8gdGhpcy5mb3JtYXR0ZWRfbGFiZWxzIDogdGhpcy5sYWJlbHM7XG5cdFx0dGhpcy5sZWdlbmRfdG90YWxzLm1hcCgoZCwgaSkgPT4ge1xuXHRcdFx0aWYoZCkge1xuXHRcdFx0XHRsZXQgc3RhdHMgPSAkLmNyZWF0ZSgnZGl2Jywge1xuXHRcdFx0XHRcdGNsYXNzTmFtZTogJ3N0YXRzJyxcblx0XHRcdFx0XHRpbnNpZGU6IHRoaXMuc3RhdHNfd3JhcHBlclxuXHRcdFx0XHR9KTtcblx0XHRcdFx0c3RhdHMuaW5uZXJIVE1MID0gYDxzcGFuIGNsYXNzPVwiaW5kaWNhdG9yICR7dGhpcy5jb2xvcnNbaV19XCI+XG5cdFx0XHRcdFx0PHNwYW4gY2xhc3M9XCJ0ZXh0LW11dGVkXCI+JHt4X3ZhbHVlc1tpXX06PC9zcGFuPlxuXHRcdFx0XHRcdCR7ZH1cblx0XHRcdFx0PC9zcGFuPmA7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cbn1cblxuY2xhc3MgSGVhdE1hcCBleHRlbmRzIENoYXJ0IHtcblx0Y29uc3RydWN0b3Ioe1xuXHRcdHN0YXJ0ID0gJycsXG5cdFx0ZG9tYWluID0gJycsXG5cdFx0c3ViZG9tYWluID0gJycsXG5cdFx0ZGF0YSA9IHt9LFxuXHRcdGRpc2NyZXRlX2RvbWFpbnMgPSAwLFxuXHRcdGNvdW50X2xhYmVsID0gJydcblx0fSkge1xuXHRcdHN1cGVyKGFyZ3VtZW50c1swXSk7XG5cblx0XHR0aGlzLnR5cGUgPSAnaGVhdG1hcCc7XG5cblx0XHR0aGlzLmRvbWFpbiA9IGRvbWFpbjtcblx0XHR0aGlzLnN1YmRvbWFpbiA9IHN1YmRvbWFpbjtcblx0XHR0aGlzLmRhdGEgPSBkYXRhO1xuXHRcdHRoaXMuZGlzY3JldGVfZG9tYWlucyA9IGRpc2NyZXRlX2RvbWFpbnM7XG5cdFx0dGhpcy5jb3VudF9sYWJlbCA9IGNvdW50X2xhYmVsO1xuXG5cdFx0bGV0IHRvZGF5ID0gbmV3IERhdGUoKTtcblx0XHR0aGlzLnN0YXJ0ID0gc3RhcnQgfHwgdGhpcy5hZGRfZGF5cyh0b2RheSwgMzY1KTtcblxuXHRcdHRoaXMubGVnZW5kX2NvbG9ycyA9IFsnI2ViZWRmMCcsICcjYzZlNDhiJywgJyM3YmM5NmYnLCAnIzIzOWEzYicsICcjMTk2MTI3J107XG5cblx0XHR0aGlzLnRyYW5zbGF0ZV94ID0gMDtcblx0XHR0aGlzLnNldHVwKCk7XG5cdH1cblxuXHRzZXR1cF9iYXNlX3ZhbHVlcygpIHtcblx0XHR0aGlzLnRvZGF5ID0gbmV3IERhdGUoKTtcblxuXHRcdGlmKCF0aGlzLnN0YXJ0KSB7XG5cdFx0XHR0aGlzLnN0YXJ0ID0gbmV3IERhdGUoKTtcblx0XHRcdHRoaXMuc3RhcnQuc2V0RnVsbFllYXIoIHRoaXMuc3RhcnQuZ2V0RnVsbFllYXIoKSAtIDEgKTtcblx0XHR9XG5cdFx0dGhpcy5maXJzdF93ZWVrX3N0YXJ0ID0gbmV3IERhdGUodGhpcy5zdGFydC50b0RhdGVTdHJpbmcoKSk7XG5cdFx0dGhpcy5sYXN0X3dlZWtfc3RhcnQgPSBuZXcgRGF0ZSh0aGlzLnRvZGF5LnRvRGF0ZVN0cmluZygpKTtcblx0XHRpZih0aGlzLmZpcnN0X3dlZWtfc3RhcnQuZ2V0RGF5KCkgIT09IDcpIHtcblx0XHRcdHRoaXMuYWRkX2RheXModGhpcy5maXJzdF93ZWVrX3N0YXJ0LCAoLTEpICogdGhpcy5maXJzdF93ZWVrX3N0YXJ0LmdldERheSgpKTtcblx0XHR9XG5cdFx0aWYodGhpcy5sYXN0X3dlZWtfc3RhcnQuZ2V0RGF5KCkgIT09IDcpIHtcblx0XHRcdHRoaXMuYWRkX2RheXModGhpcy5sYXN0X3dlZWtfc3RhcnQsICgtMSkgKiB0aGlzLmxhc3Rfd2Vla19zdGFydC5nZXREYXkoKSk7XG5cdFx0fVxuXHRcdHRoaXMubm9fb2ZfY29scyA9IHRoaXMuZ2V0X3dlZWtzX2JldHdlZW4odGhpcy5maXJzdF93ZWVrX3N0YXJ0ICsgJycsIHRoaXMubGFzdF93ZWVrX3N0YXJ0ICsgJycpICsgMTtcblx0fVxuXG5cdHNldF93aWR0aCgpIHtcblx0XHR0aGlzLmJhc2Vfd2lkdGggPSAodGhpcy5ub19vZl9jb2xzKSAqIDEyO1xuXG5cdFx0aWYodGhpcy5kaXNjcmV0ZV9kb21haW5zKSB7XG5cdFx0XHR0aGlzLmJhc2Vfd2lkdGggKz0gKDEyICogMTIpO1xuXHRcdH1cblx0fVxuXG5cdHNldHVwX2NvbXBvbmVudHMoKSB7XG5cdFx0dGhpcy5kb21haW5fbGFiZWxfZ3JvdXAgPSAkLmNyZWF0ZVNWRyhcImdcIiwge1xuXHRcdFx0Y2xhc3NOYW1lOiBcImRvbWFpbi1sYWJlbC1ncm91cCBjaGFydC1sYWJlbFwiLFxuXHRcdFx0aW5zaWRlOiB0aGlzLmRyYXdfYXJlYVxuXHRcdH0pO1xuXHRcdHRoaXMuZGF0YV9ncm91cHMgPSAkLmNyZWF0ZVNWRyhcImdcIiwge1xuXHRcdFx0Y2xhc3NOYW1lOiBcImRhdGEtZ3JvdXBzXCIsXG5cdFx0XHRpbnNpZGU6IHRoaXMuZHJhd19hcmVhLFxuXHRcdFx0dHJhbnNmb3JtOiBgdHJhbnNsYXRlKDAsIDIwKWBcblx0XHR9KTtcblx0fVxuXG5cdHNldHVwX3ZhbHVlcygpIHtcblx0XHR0aGlzLmRvbWFpbl9sYWJlbF9ncm91cC50ZXh0Q29udGVudCA9ICcnO1xuXHRcdHRoaXMuZGF0YV9ncm91cHMudGV4dENvbnRlbnQgPSAnJztcblx0XHR0aGlzLmRpc3RyaWJ1dGlvbiA9IHRoaXMuZ2V0X2Rpc3RyaWJ1dGlvbih0aGlzLmRhdGEsIHRoaXMubGVnZW5kX2NvbG9ycyk7XG5cdFx0dGhpcy5tb250aF9uYW1lcyA9IFtcIkphbnVhcnlcIiwgXCJGZWJydWFyeVwiLCBcIk1hcmNoXCIsIFwiQXByaWxcIiwgXCJNYXlcIiwgXCJKdW5lXCIsXG5cdFx0XHRcIkp1bHlcIiwgXCJBdWd1c3RcIiwgXCJTZXB0ZW1iZXJcIiwgXCJPY3RvYmVyXCIsIFwiTm92ZW1iZXJcIiwgXCJEZWNlbWJlclwiXG5cdFx0XTtcblxuXHRcdHRoaXMucmVuZGVyX2FsbF93ZWVrc19hbmRfc3RvcmVfeF92YWx1ZXModGhpcy5ub19vZl9jb2xzKTtcblx0fVxuXG5cdHJlbmRlcl9hbGxfd2Vla3NfYW5kX3N0b3JlX3hfdmFsdWVzKG5vX29mX3dlZWtzKSB7XG5cdFx0bGV0IGN1cnJlbnRfd2Vla19zdW5kYXkgPSBuZXcgRGF0ZSh0aGlzLmZpcnN0X3dlZWtfc3RhcnQpO1xuXHRcdHRoaXMud2Vla19jb2wgPSAwO1xuXHRcdHRoaXMuY3VycmVudF9tb250aCA9IGN1cnJlbnRfd2Vla19zdW5kYXkuZ2V0TW9udGgoKTtcblxuXHRcdHRoaXMubW9udGhzID0gW3RoaXMuY3VycmVudF9tb250aCArICcnXTtcblx0XHR0aGlzLm1vbnRoX3dlZWtzID0ge30sIHRoaXMubW9udGhfc3RhcnRfcG9pbnRzID0gW107XG5cdFx0dGhpcy5tb250aF93ZWVrc1t0aGlzLmN1cnJlbnRfbW9udGhdID0gMDtcblx0XHR0aGlzLm1vbnRoX3N0YXJ0X3BvaW50cy5wdXNoKDEzKTtcblxuXHRcdGZvcih2YXIgaSA9IDA7IGkgPCBub19vZl93ZWVrczsgaSsrKSB7XG5cdFx0XHRsZXQgZGF0YV9ncm91cCwgbW9udGhfY2hhbmdlID0gMDtcblx0XHRcdGxldCBkYXkgPSBuZXcgRGF0ZShjdXJyZW50X3dlZWtfc3VuZGF5KTtcblxuXHRcdFx0W2RhdGFfZ3JvdXAsIG1vbnRoX2NoYW5nZV0gPSB0aGlzLmdldF93ZWVrX3NxdWFyZXNfZ3JvdXAoZGF5LCB0aGlzLndlZWtfY29sKTtcblx0XHRcdHRoaXMuZGF0YV9ncm91cHMuYXBwZW5kQ2hpbGQoZGF0YV9ncm91cCk7XG5cdFx0XHR0aGlzLndlZWtfY29sICs9IDEgKyBwYXJzZUludCh0aGlzLmRpc2NyZXRlX2RvbWFpbnMgJiYgbW9udGhfY2hhbmdlKTtcblx0XHRcdHRoaXMubW9udGhfd2Vla3NbdGhpcy5jdXJyZW50X21vbnRoXSsrO1xuXHRcdFx0aWYobW9udGhfY2hhbmdlKSB7XG5cdFx0XHRcdHRoaXMuY3VycmVudF9tb250aCA9ICh0aGlzLmN1cnJlbnRfbW9udGggKyAxKSAlIDEyO1xuXHRcdFx0XHR0aGlzLm1vbnRocy5wdXNoKHRoaXMuY3VycmVudF9tb250aCArICcnKTtcblx0XHRcdFx0dGhpcy5tb250aF93ZWVrc1t0aGlzLmN1cnJlbnRfbW9udGhdID0gMTtcblx0XHRcdH1cblx0XHRcdHRoaXMuYWRkX2RheXMoY3VycmVudF93ZWVrX3N1bmRheSwgNyk7XG5cdFx0fVxuXHRcdHRoaXMucmVuZGVyX21vbnRoX2xhYmVscygpO1xuXHR9XG5cblx0Z2V0X3dlZWtfc3F1YXJlc19ncm91cChjdXJyZW50X2RhdGUsIGluZGV4KSB7XG5cdFx0Y29uc3Qgbm9fb2Zfd2Vla2RheXMgPSA3O1xuXHRcdGNvbnN0IHNxdWFyZV9zaWRlID0gMTA7XG5cdFx0Y29uc3QgY2VsbF9wYWRkaW5nID0gMjtcblx0XHRjb25zdCBzdGVwID0gMTtcblxuXHRcdGxldCBtb250aF9jaGFuZ2UgPSAwO1xuXHRcdGxldCB3ZWVrX2NvbF9jaGFuZ2UgPSAwO1xuXG5cdFx0bGV0IGRhdGFfZ3JvdXAgPSAkLmNyZWF0ZVNWRyhcImdcIiwge1xuXHRcdFx0Y2xhc3NOYW1lOiBcImRhdGEtZ3JvdXBcIixcblx0XHRcdGluc2lkZTogdGhpcy5kYXRhX2dyb3Vwc1xuXHRcdH0pO1xuXG5cdFx0Zm9yKHZhciB5ID0gMCwgaSA9IDA7IGkgPCBub19vZl93ZWVrZGF5czsgaSArPSBzdGVwLCB5ICs9IChzcXVhcmVfc2lkZSArIGNlbGxfcGFkZGluZykpIHtcblx0XHRcdGxldCBkYXRhX3ZhbHVlID0gMDtcblx0XHRcdGxldCBjb2xvcl9pbmRleCA9IDA7XG5cblx0XHRcdGxldCB0aW1lc3RhbXAgPSBNYXRoLmZsb29yKGN1cnJlbnRfZGF0ZS5nZXRUaW1lKCkvMTAwMCkudG9GaXhlZCgxKTtcblxuXHRcdFx0aWYodGhpcy5kYXRhW3RpbWVzdGFtcF0pIHtcblx0XHRcdFx0ZGF0YV92YWx1ZSA9IHRoaXMuZGF0YVt0aW1lc3RhbXBdO1xuXHRcdFx0XHRjb2xvcl9pbmRleCA9IHRoaXMuZ2V0X21heF9jaGVja3BvaW50KGRhdGFfdmFsdWUsIHRoaXMuZGlzdHJpYnV0aW9uKTtcblx0XHRcdH1cblxuXHRcdFx0aWYodGhpcy5kYXRhW01hdGgucm91bmQodGltZXN0YW1wKV0pIHtcblx0XHRcdFx0ZGF0YV92YWx1ZSA9IHRoaXMuZGF0YVtNYXRoLnJvdW5kKHRpbWVzdGFtcCldO1xuXHRcdFx0XHRjb2xvcl9pbmRleCA9IHRoaXMuZ2V0X21heF9jaGVja3BvaW50KGRhdGFfdmFsdWUsIHRoaXMuZGlzdHJpYnV0aW9uKTtcblx0XHRcdH1cblxuXHRcdFx0bGV0IHggPSAxMyArIChpbmRleCArIHdlZWtfY29sX2NoYW5nZSkgKiAxMjtcblxuXHRcdFx0JC5jcmVhdGVTVkcoXCJyZWN0XCIsIHtcblx0XHRcdFx0Y2xhc3NOYW1lOiAnZGF5Jyxcblx0XHRcdFx0aW5zaWRlOiBkYXRhX2dyb3VwLFxuXHRcdFx0XHR4OiB4LFxuXHRcdFx0XHR5OiB5LFxuXHRcdFx0XHR3aWR0aDogc3F1YXJlX3NpZGUsXG5cdFx0XHRcdGhlaWdodDogc3F1YXJlX3NpZGUsXG5cdFx0XHRcdGZpbGw6ICB0aGlzLmxlZ2VuZF9jb2xvcnNbY29sb3JfaW5kZXhdLFxuXHRcdFx0XHQnZGF0YS1kYXRlJzogdGhpcy5nZXRfZGRfbW1feXl5eShjdXJyZW50X2RhdGUpLFxuXHRcdFx0XHQnZGF0YS12YWx1ZSc6IGRhdGFfdmFsdWUsXG5cdFx0XHRcdCdkYXRhLWRheSc6IGN1cnJlbnRfZGF0ZS5nZXREYXkoKVxuXHRcdFx0fSk7XG5cblx0XHRcdGxldCBuZXh0X2RhdGUgPSBuZXcgRGF0ZShjdXJyZW50X2RhdGUpO1xuXHRcdFx0dGhpcy5hZGRfZGF5cyhuZXh0X2RhdGUsIDEpO1xuXHRcdFx0aWYobmV4dF9kYXRlLmdldE1vbnRoKCkgLSBjdXJyZW50X2RhdGUuZ2V0TW9udGgoKSkge1xuXHRcdFx0XHRtb250aF9jaGFuZ2UgPSAxO1xuXHRcdFx0XHRpZih0aGlzLmRpc2NyZXRlX2RvbWFpbnMpIHtcblx0XHRcdFx0XHR3ZWVrX2NvbF9jaGFuZ2UgPSAxO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0dGhpcy5tb250aF9zdGFydF9wb2ludHMucHVzaCgxMyArIChpbmRleCArIHdlZWtfY29sX2NoYW5nZSkgKiAxMik7XG5cdFx0XHR9XG5cdFx0XHRjdXJyZW50X2RhdGUgPSBuZXh0X2RhdGU7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIFtkYXRhX2dyb3VwLCBtb250aF9jaGFuZ2VdO1xuXHR9XG5cblx0cmVuZGVyX21vbnRoX2xhYmVscygpIHtcblx0XHQvLyB0aGlzLmZpcnN0X21vbnRoX2xhYmVsID0gMTtcblx0XHQvLyBpZiAodGhpcy5maXJzdF93ZWVrX3N0YXJ0LmdldERhdGUoKSA+IDgpIHtcblx0XHQvLyBcdHRoaXMuZmlyc3RfbW9udGhfbGFiZWwgPSAwO1xuXHRcdC8vIH1cblx0XHQvLyB0aGlzLmxhc3RfbW9udGhfbGFiZWwgPSAxO1xuXG5cdFx0Ly8gbGV0IGZpcnN0X21vbnRoID0gdGhpcy5tb250aHMuc2hpZnQoKTtcblx0XHQvLyBsZXQgZmlyc3RfbW9udGhfc3RhcnQgPSB0aGlzLm1vbnRoX3N0YXJ0X3BvaW50cy5zaGlmdCgpO1xuXHRcdC8vIHJlbmRlciBmaXJzdCBtb250aCBpZlxuXG5cdFx0Ly8gbGV0IGxhc3RfbW9udGggPSB0aGlzLm1vbnRocy5wb3AoKTtcblx0XHQvLyBsZXQgbGFzdF9tb250aF9zdGFydCA9IHRoaXMubW9udGhfc3RhcnRfcG9pbnRzLnBvcCgpO1xuXHRcdC8vIHJlbmRlciBsYXN0IG1vbnRoIGlmXG5cblx0XHR0aGlzLm1vbnRocy5zaGlmdCgpO1xuXHRcdHRoaXMubW9udGhfc3RhcnRfcG9pbnRzLnNoaWZ0KCk7XG5cdFx0dGhpcy5tb250aHMucG9wKCk7XG5cdFx0dGhpcy5tb250aF9zdGFydF9wb2ludHMucG9wKCk7XG5cblx0XHR0aGlzLm1vbnRoX3N0YXJ0X3BvaW50cy5tYXAoKHN0YXJ0LCBpKSA9PiB7XG5cdFx0XHRsZXQgbW9udGhfbmFtZSA9ICB0aGlzLm1vbnRoX25hbWVzW3RoaXMubW9udGhzW2ldXS5zdWJzdHJpbmcoMCwgMyk7XG5cblx0XHRcdCQuY3JlYXRlU1ZHKCd0ZXh0Jywge1xuXHRcdFx0XHRjbGFzc05hbWU6ICd5LXZhbHVlLXRleHQnLFxuXHRcdFx0XHRpbnNpZGU6IHRoaXMuZG9tYWluX2xhYmVsX2dyb3VwLFxuXHRcdFx0XHR4OiBzdGFydCArIDEyLFxuXHRcdFx0XHR5OiAxMCxcblx0XHRcdFx0ZHk6ICcuMzJlbScsXG5cdFx0XHRcdGlubmVySFRNTDogbW9udGhfbmFtZVxuXHRcdFx0fSk7XG5cblx0XHR9KTtcblx0fVxuXG5cdG1ha2VfZ3JhcGhfY29tcG9uZW50cygpIHtcblx0XHRBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChcblx0XHRcdHRoaXMuY29udGFpbmVyLnF1ZXJ5U2VsZWN0b3JBbGwoJy5ncmFwaC1zdGF0cy1jb250YWluZXIsIC5zdWItdGl0bGUsIC50aXRsZScpXG5cdFx0KS5tYXAoZCA9PiB7XG5cdFx0XHRkLnN0eWxlLmRpc3BsYXkgPSAnTm9uZSc7XG5cdFx0fSk7XG5cdFx0dGhpcy5jaGFydF93cmFwcGVyLnN0eWxlLm1hcmdpblRvcCA9ICcwcHgnO1xuXHRcdHRoaXMuY2hhcnRfd3JhcHBlci5zdHlsZS5wYWRkaW5nVG9wID0gJzBweCc7XG5cdH1cblxuXHRiaW5kX3Rvb2x0aXAoKSB7XG5cdFx0QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoXG5cdFx0XHRkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKFwiLmRhdGEtZ3JvdXAgLmRheVwiKVxuXHRcdCkubWFwKGVsID0+IHtcblx0XHRcdGVsLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlZW50ZXInLCAoZSkgPT4ge1xuXHRcdFx0XHRsZXQgY291bnQgPSBlLnRhcmdldC5nZXRBdHRyaWJ1dGUoJ2RhdGEtdmFsdWUnKTtcblx0XHRcdFx0bGV0IGRhdGVfcGFydHMgPSBlLnRhcmdldC5nZXRBdHRyaWJ1dGUoJ2RhdGEtZGF0ZScpLnNwbGl0KCctJyk7XG5cblx0XHRcdFx0bGV0IG1vbnRoID0gdGhpcy5tb250aF9uYW1lc1twYXJzZUludChkYXRlX3BhcnRzWzFdKS0xXS5zdWJzdHJpbmcoMCwgMyk7XG5cblx0XHRcdFx0bGV0IGdfb2ZmID0gdGhpcy5jaGFydF93cmFwcGVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLCBwX29mZiA9IGUudGFyZ2V0LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXG5cdFx0XHRcdGxldCB3aWR0aCA9IHBhcnNlSW50KGUudGFyZ2V0LmdldEF0dHJpYnV0ZSgnd2lkdGgnKSk7XG5cdFx0XHRcdGxldCB4ID0gcF9vZmYubGVmdCAtIGdfb2ZmLmxlZnQgKyAod2lkdGgrMikvMjtcblx0XHRcdFx0bGV0IHkgPSBwX29mZi50b3AgLSBnX29mZi50b3AgLSAod2lkdGgrMikvMjtcblx0XHRcdFx0bGV0IHZhbHVlID0gY291bnQgKyAnICcgKyB0aGlzLmNvdW50X2xhYmVsO1xuXHRcdFx0XHRsZXQgbmFtZSA9ICcgb24gJyArIG1vbnRoICsgJyAnICsgZGF0ZV9wYXJ0c1swXSArICcsICcgKyBkYXRlX3BhcnRzWzJdO1xuXG5cdFx0XHRcdHRoaXMudGlwLnNldF92YWx1ZXMoeCwgeSwgbmFtZSwgdmFsdWUsIFtdLCAxKTtcblx0XHRcdFx0dGhpcy50aXAuc2hvd190aXAoKTtcblx0XHRcdH0pO1xuXHRcdH0pO1xuXHR9XG5cblx0dXBkYXRlKGRhdGEpIHtcblx0XHR0aGlzLmRhdGEgPSBkYXRhO1xuXHRcdHRoaXMuc2V0dXBfdmFsdWVzKCk7XG5cdFx0dGhpcy5iaW5kX3Rvb2x0aXAoKTtcblx0fVxuXG5cdGdldF9kaXN0cmlidXRpb24oZGF0YT17fSwgbWFwcGVyX2FycmF5KSB7XG5cdFx0bGV0IGRhdGFfdmFsdWVzID0gT2JqZWN0LmtleXMoZGF0YSkubWFwKGtleSA9PiBkYXRhW2tleV0pO1xuXHRcdGxldCBkYXRhX21heF92YWx1ZSA9IE1hdGgubWF4KC4uLmRhdGFfdmFsdWVzKTtcblxuXHRcdGxldCBkaXN0cmlidXRpb25fc3RlcCA9IDEgLyAobWFwcGVyX2FycmF5Lmxlbmd0aCAtIDEpO1xuXHRcdGxldCBkaXN0cmlidXRpb24gPSBbXTtcblxuXHRcdG1hcHBlcl9hcnJheS5tYXAoKGNvbG9yLCBpKSA9PiB7XG5cdFx0XHRsZXQgY2hlY2twb2ludCA9IGRhdGFfbWF4X3ZhbHVlICogKGRpc3RyaWJ1dGlvbl9zdGVwICogaSk7XG5cdFx0XHRkaXN0cmlidXRpb24ucHVzaChjaGVja3BvaW50KTtcblx0XHR9KTtcblxuXHRcdHJldHVybiBkaXN0cmlidXRpb247XG5cdH1cblxuXHRnZXRfbWF4X2NoZWNrcG9pbnQodmFsdWUsIGRpc3RyaWJ1dGlvbikge1xuXHRcdHJldHVybiBkaXN0cmlidXRpb24uZmlsdGVyKChkLCBpKSA9PiB7XG5cdFx0XHRpZihpID09PSAxKSB7XG5cdFx0XHRcdHJldHVybiBkaXN0cmlidXRpb25bMF0gPCB2YWx1ZTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBkIDw9IHZhbHVlO1xuXHRcdH0pLmxlbmd0aCAtIDE7XG5cdH1cblxuXHQvLyBUT0RPOiBkYXRlIHV0aWxzLCBtb3ZlIHRoZXNlIG91dFxuXG5cdC8vIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8xMTI1MjE2Ny82NDk1MDQzXG5cdHRyZWF0X2FzX3V0YyhkYXRlX3N0cikge1xuXHRcdGxldCByZXN1bHQgPSBuZXcgRGF0ZShkYXRlX3N0cik7XG5cdFx0cmVzdWx0LnNldE1pbnV0ZXMocmVzdWx0LmdldE1pbnV0ZXMoKSAtIHJlc3VsdC5nZXRUaW1lem9uZU9mZnNldCgpKTtcblx0XHRyZXR1cm4gcmVzdWx0O1xuXHR9XG5cblx0Z2V0X2RkX21tX3l5eXkoZGF0ZSkge1xuXHRcdGxldCBkZCA9IGRhdGUuZ2V0RGF0ZSgpO1xuXHRcdGxldCBtbSA9IGRhdGUuZ2V0TW9udGgoKSArIDE7IC8vIGdldE1vbnRoKCkgaXMgemVyby1iYXNlZFxuXHRcdHJldHVybiBbXG5cdFx0XHQoZGQ+OSA/ICcnIDogJzAnKSArIGRkLFxuXHRcdFx0KG1tPjkgPyAnJyA6ICcwJykgKyBtbSxcblx0XHRcdGRhdGUuZ2V0RnVsbFllYXIoKVxuXHRcdF0uam9pbignLScpO1xuXHR9XG5cblx0Z2V0X3dlZWtzX2JldHdlZW4oc3RhcnRfZGF0ZV9zdHIsIGVuZF9kYXRlX3N0cikge1xuXHRcdHJldHVybiBNYXRoLmNlaWwodGhpcy5nZXRfZGF5c19iZXR3ZWVuKHN0YXJ0X2RhdGVfc3RyLCBlbmRfZGF0ZV9zdHIpIC8gNyk7XG5cdH1cblxuXHRnZXRfZGF5c19iZXR3ZWVuKHN0YXJ0X2RhdGVfc3RyLCBlbmRfZGF0ZV9zdHIpIHtcblx0XHRsZXQgbWlsbGlzZWNvbmRzX3Blcl9kYXkgPSAyNCAqIDYwICogNjAgKiAxMDAwO1xuXHRcdHJldHVybiAodGhpcy50cmVhdF9hc191dGMoZW5kX2RhdGVfc3RyKSAtIHRoaXMudHJlYXRfYXNfdXRjKHN0YXJ0X2RhdGVfc3RyKSkgLyBtaWxsaXNlY29uZHNfcGVyX2RheTtcblx0fVxuXG5cdC8vIG11dGF0ZXNcblx0YWRkX2RheXMoZGF0ZSwgbnVtYmVyX29mX2RheXMpIHtcblx0XHRkYXRlLnNldERhdGUoZGF0ZS5nZXREYXRlKCkgKyBudW1iZXJfb2ZfZGF5cyk7XG5cdH1cblxuXHRnZXRfbW9udGhfbmFtZSgpIHt9XG59XG5cbmNsYXNzIFN2Z1RpcCB7XG5cdGNvbnN0cnVjdG9yKHtcblx0XHRwYXJlbnQgPSBudWxsXG5cdH0pIHtcblx0XHR0aGlzLnBhcmVudCA9IHBhcmVudDtcblx0XHR0aGlzLnRpdGxlX25hbWUgPSAnJztcblx0XHR0aGlzLnRpdGxlX3ZhbHVlID0gJyc7XG5cdFx0dGhpcy5saXN0X3ZhbHVlcyA9IFtdO1xuXHRcdHRoaXMudGl0bGVfdmFsdWVfZmlyc3QgPSAwO1xuXG5cdFx0dGhpcy54ID0gMDtcblx0XHR0aGlzLnkgPSAwO1xuXG5cdFx0dGhpcy50b3AgPSAwO1xuXHRcdHRoaXMubGVmdCA9IDA7XG5cblx0XHR0aGlzLnNldHVwKCk7XG5cdH1cblxuXHRzZXR1cCgpIHtcblx0XHR0aGlzLm1ha2VfdG9vbHRpcCgpO1xuXHR9XG5cblx0cmVmcmVzaCgpIHtcblx0XHR0aGlzLmZpbGwoKTtcblx0XHR0aGlzLmNhbGNfcG9zaXRpb24oKTtcblx0XHQvLyB0aGlzLnNob3dfdGlwKCk7XG5cdH1cblxuXHRtYWtlX3Rvb2x0aXAoKSB7XG5cdFx0dGhpcy5jb250YWluZXIgPSAkLmNyZWF0ZSgnZGl2Jywge1xuXHRcdFx0aW5zaWRlOiB0aGlzLnBhcmVudCxcblx0XHRcdGNsYXNzTmFtZTogJ2dyYXBoLXN2Zy10aXAgY29tcGFyaXNvbicsXG5cdFx0XHRpbm5lckhUTUw6IGA8c3BhbiBjbGFzcz1cInRpdGxlXCI+PC9zcGFuPlxuXHRcdFx0XHQ8dWwgY2xhc3M9XCJkYXRhLXBvaW50LWxpc3RcIj48L3VsPlxuXHRcdFx0XHQ8ZGl2IGNsYXNzPVwic3ZnLXBvaW50ZXJcIj48L2Rpdj5gXG5cdFx0fSk7XG5cdFx0dGhpcy5oaWRlX3RpcCgpO1xuXG5cdFx0dGhpcy50aXRsZSA9IHRoaXMuY29udGFpbmVyLnF1ZXJ5U2VsZWN0b3IoJy50aXRsZScpO1xuXHRcdHRoaXMuZGF0YV9wb2ludF9saXN0ID0gdGhpcy5jb250YWluZXIucXVlcnlTZWxlY3RvcignLmRhdGEtcG9pbnQtbGlzdCcpO1xuXG5cdFx0dGhpcy5wYXJlbnQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2VsZWF2ZScsICgpID0+IHtcblx0XHRcdHRoaXMuaGlkZV90aXAoKTtcblx0XHR9KTtcblx0fVxuXG5cdGZpbGwoKSB7XG5cdFx0bGV0IHRpdGxlO1xuXHRcdGlmKHRoaXMudGl0bGVfdmFsdWVfZmlyc3QpIHtcblx0XHRcdHRpdGxlID0gYDxzdHJvbmc+JHt0aGlzLnRpdGxlX3ZhbHVlfTwvc3Ryb25nPiR7dGhpcy50aXRsZV9uYW1lfWA7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRpdGxlID0gYCR7dGhpcy50aXRsZV9uYW1lfTxzdHJvbmc+JHt0aGlzLnRpdGxlX3ZhbHVlfTwvc3Ryb25nPmA7XG5cdFx0fVxuXHRcdHRoaXMudGl0bGUuaW5uZXJIVE1MID0gdGl0bGU7XG5cdFx0dGhpcy5kYXRhX3BvaW50X2xpc3QuaW5uZXJIVE1MID0gJyc7XG5cblx0XHR0aGlzLmxpc3RfdmFsdWVzLm1hcCgoc2V0KSA9PiB7XG5cdFx0XHRsZXQgbGkgPSAkLmNyZWF0ZSgnbGknLCB7XG5cdFx0XHRcdGNsYXNzTmFtZTogYGJvcmRlci10b3AgJHtzZXQuY29sb3IgfHwgJ2JsYWNrJ31gLFxuXHRcdFx0XHRpbm5lckhUTUw6IGA8c3Ryb25nIHN0eWxlPVwiZGlzcGxheTogYmxvY2s7XCI+JHtzZXQudmFsdWUgPyBzZXQudmFsdWUgOiAnJyB9PC9zdHJvbmc+XG5cdFx0XHRcdFx0JHtzZXQudGl0bGUgPyBzZXQudGl0bGUgOiAnJyB9YFxuXHRcdFx0fSk7XG5cblx0XHRcdHRoaXMuZGF0YV9wb2ludF9saXN0LmFwcGVuZENoaWxkKGxpKTtcblx0XHR9KTtcblx0fVxuXG5cdGNhbGNfcG9zaXRpb24oKSB7XG5cdFx0dGhpcy50b3AgPSB0aGlzLnkgLSB0aGlzLmNvbnRhaW5lci5vZmZzZXRIZWlnaHQ7XG5cdFx0dGhpcy5sZWZ0ID0gdGhpcy54IC0gdGhpcy5jb250YWluZXIub2Zmc2V0V2lkdGgvMjtcblx0XHRsZXQgbWF4X2xlZnQgPSB0aGlzLnBhcmVudC5vZmZzZXRXaWR0aCAtIHRoaXMuY29udGFpbmVyLm9mZnNldFdpZHRoO1xuXG5cdFx0bGV0IHBvaW50ZXIgPSB0aGlzLmNvbnRhaW5lci5xdWVyeVNlbGVjdG9yKCcuc3ZnLXBvaW50ZXInKTtcblxuXHRcdGlmKHRoaXMubGVmdCA8IDApIHtcblx0XHRcdHBvaW50ZXIuc3R5bGUubGVmdCA9IGBjYWxjKDUwJSAtICR7LTEgKiB0aGlzLmxlZnR9cHgpYDtcblx0XHRcdHRoaXMubGVmdCA9IDA7XG5cdFx0fSBlbHNlIGlmKHRoaXMubGVmdCA+IG1heF9sZWZ0KSB7XG5cdFx0XHRsZXQgZGVsdGEgPSB0aGlzLmxlZnQgLSBtYXhfbGVmdDtcblx0XHRcdHBvaW50ZXIuc3R5bGUubGVmdCA9IGBjYWxjKDUwJSArICR7ZGVsdGF9cHgpYDtcblx0XHRcdHRoaXMubGVmdCA9IG1heF9sZWZ0O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRwb2ludGVyLnN0eWxlLmxlZnQgPSBgNTAlYDtcblx0XHR9XG5cdH1cblxuXHRzZXRfdmFsdWVzKHgsIHksIHRpdGxlX25hbWUgPSAnJywgdGl0bGVfdmFsdWUgPSAnJywgbGlzdF92YWx1ZXMgPSBbXSwgdGl0bGVfdmFsdWVfZmlyc3QgPSAwKSB7XG5cdFx0dGhpcy50aXRsZV9uYW1lID0gdGl0bGVfbmFtZTtcblx0XHR0aGlzLnRpdGxlX3ZhbHVlID0gdGl0bGVfdmFsdWU7XG5cdFx0dGhpcy5saXN0X3ZhbHVlcyA9IGxpc3RfdmFsdWVzO1xuXHRcdHRoaXMueCA9IHg7XG5cdFx0dGhpcy55ID0geTtcblx0XHR0aGlzLnRpdGxlX3ZhbHVlX2ZpcnN0ID0gdGl0bGVfdmFsdWVfZmlyc3Q7XG5cdFx0dGhpcy5yZWZyZXNoKCk7XG5cdH1cblxuXHRoaWRlX3RpcCgpIHtcblx0XHR0aGlzLmNvbnRhaW5lci5zdHlsZS50b3AgPSAnMHB4Jztcblx0XHR0aGlzLmNvbnRhaW5lci5zdHlsZS5sZWZ0ID0gJzBweCc7XG5cdFx0dGhpcy5jb250YWluZXIuc3R5bGUub3BhY2l0eSA9ICcwJztcblx0fVxuXG5cdHNob3dfdGlwKCkge1xuXHRcdHRoaXMuY29udGFpbmVyLnN0eWxlLnRvcCA9IHRoaXMudG9wICsgJ3B4Jztcblx0XHR0aGlzLmNvbnRhaW5lci5zdHlsZS5sZWZ0ID0gdGhpcy5sZWZ0ICsgJ3B4Jztcblx0XHR0aGlzLmNvbnRhaW5lci5zdHlsZS5vcGFjaXR5ID0gJzEnO1xuXHR9XG59XG4iXSwibmFtZXMiOlsiJCIsImV4cHIiLCJjb24iLCJkb2N1bWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJmaW5kTm9kZUluZGV4Iiwibm9kZSIsImkiLCJwcmV2aW91c1NpYmxpbmciLCJjcmVhdGUiLCJ0YWciLCJvIiwiZWxlbWVudCIsImNyZWF0ZUVsZW1lbnQiLCJ2YWwiLCJhcHBlbmRDaGlsZCIsInJlZiIsInBhcmVudE5vZGUiLCJpbnNlcnRCZWZvcmUiLCJzZXRBdHRyaWJ1dGUiLCJjcmVhdGVTVkciLCJjcmVhdGVFbGVtZW50TlMiLCJydW5TVkdBbmltYXRpb24iLCJzdmdfY29udGFpbmVyIiwiZWxlbWVudHMiLCJuZXdfZWxlbWVudHMiLCJhbmltX2VsZW1lbnRzIiwibWFwIiwib2JqIiwicGFyZW50IiwidW5pdCIsImFuaW1fZWxlbWVudCIsIm5ld19lbGVtZW50IiwiYW5pbWF0ZVNWRyIsInB1c2giLCJyZXBsYWNlQ2hpbGQiLCJhcnJheSIsImluZGV4Iiwib2JqZWN0Iiwia2V5IiwiYW5pbV9zdmciLCJjbG9uZU5vZGUiLCJwcm9wcyIsImR1ciIsImVhc2luZ190eXBlIiwidHlwZSIsInVuZGVmaW5lZCIsIm9sZF92YWx1ZXMiLCJlYXNpbmciLCJhdHRyaWJ1dGVOYW1lIiwiYW5pbWF0ZV9lbGVtZW50IiwiY3VycmVudF92YWx1ZSIsImdldEF0dHJpYnV0ZSIsInZhbHVlIiwiYW5pbV9hdHRyIiwib2Zmc2V0IiwicmVjdCIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsInRvcCIsImRvY3VtZW50RWxlbWVudCIsInNjcm9sbFRvcCIsImJvZHkiLCJsZWZ0Iiwic2Nyb2xsTGVmdCIsImlzRWxlbWVudEluVmlld3BvcnQiLCJlbCIsImJvdHRvbSIsIndpbmRvdyIsImlubmVySGVpZ2h0IiwiY2xpZW50SGVpZ2h0IiwicmlnaHQiLCJpbm5lcldpZHRoIiwiY2xpZW50V2lkdGgiLCJiaW5kIiwiZXZlbnQiLCJjYWxsYmFjayIsInNwbGl0IiwiZm9yRWFjaCIsImFkZEV2ZW50TGlzdGVuZXIiLCJ1bmJpbmQiLCJyZW1vdmVFdmVudExpc3RlbmVyIiwiZmlyZSIsInRhcmdldCIsInByb3BlcnRpZXMiLCJldnQiLCJjcmVhdGVFdmVudCIsImluaXRFdmVudCIsImoiLCJkaXNwYXRjaEV2ZW50IiwiZmxvYXRfMiIsImQiLCJwYXJzZUZsb2F0IiwidG9GaXhlZCIsImFycmF5c19lcXVhbCIsImFycjEiLCJhcnIyIiwibGVuZ3RoIiwiYXJlX2VxdWFsIiwiQ2hhcnQiLCJoZWlnaHQiLCJ0aXRsZSIsInN1YnRpdGxlIiwiZGF0YSIsImZvcm1hdF9sYW1iZGFzIiwic3VtbWFyeSIsImlzX25hdmlnYWJsZSIsIk9iamVjdCIsImdldFByb3RvdHlwZU9mIiwicHJvdG90eXBlIiwiTGluZUNoYXJ0IiwiYXJndW1lbnRzIiwiQmFyQ2hhcnQiLCJQZXJjZW50YWdlQ2hhcnQiLCJIZWF0TWFwIiwicmF3X2NoYXJ0X2FyZ3MiLCJzcGVjaWZpY192YWx1ZXMiLCJjdXJyZW50X2luZGV4IiwiY2hhcnRfdHlwZXMiLCJzZXRfbWFyZ2lucyIsImluY2x1ZGVzIiwiZXJyb3IiLCJjb21wYXRpYmxlX3R5cGVzIiwiYmFzZV9oZWlnaHQiLCJ0cmFuc2xhdGVfeCIsInRyYW5zbGF0ZV95IiwiYmluZF93aW5kb3dfZXZlbnRzIiwicmVmcmVzaCIsImluaXQiLCJzZXR1cF9iYXNlX3ZhbHVlcyIsInNldF93aWR0aCIsInNldHVwX2NvbnRhaW5lciIsInNldHVwX2NvbXBvbmVudHMiLCJzZXR1cF92YWx1ZXMiLCJzZXR1cF91dGlscyIsIm1ha2VfZ3JhcGhfY29tcG9uZW50cyIsIm1ha2VfdG9vbHRpcCIsInNob3dfY3VzdG9tX3N1bW1hcnkiLCJzaG93X3N1bW1hcnkiLCJzZXR1cF9uYXZpZ2F0aW9uIiwic3BlY2lhbF92YWx1ZXNfd2lkdGgiLCJnZXRfc3Ryd2lkdGgiLCJiYXNlX3dpZHRoIiwib2Zmc2V0V2lkdGgiLCJ3aWR0aCIsImNvbnRhaW5lciIsImlubmVySFRNTCIsImNoYXJ0X3dyYXBwZXIiLCJzdGF0c193cmFwcGVyIiwibWFrZV9jaGFydF9hcmVhIiwibWFrZV9kcmF3X2FyZWEiLCJzdmciLCJzdmdfZGVmcyIsImRyYXdfYXJlYSIsInRpcCIsIlN2Z1RpcCIsImJpbmRfdG9vbHRpcCIsInN0YXRzIiwiY29sb3IiLCJtYWtlX292ZXJsYXkiLCJiaW5kX292ZXJsYXkiLCJlIiwia2V5Q29kZSIsIm9uX2xlZnRfYXJyb3ciLCJvbl9yaWdodF9hcnJvdyIsIm9uX3VwX2Fycm93Iiwib25fZG93bl9hcnJvdyIsIm9uX2VudGVyX2tleSIsImRhdGFfcG9pbnQiLCJ5IiwiZGF0YV9rZXkiLCJzbGljZSIsImxhYmVsIiwieCIsImdldF9kYXRhX3BvaW50Iiwic3RyaW5nIiwiQXhpc0NoYXJ0IiwiYXJncyIsImxhYmVscyIsImRhdGFzZXRzIiwiZ2V0X3lfbGFiZWwiLCJ5X2xhYmVsIiwiZ2V0X3lfdG9vbHRpcCIsInlfdG9vbHRpcCIsImdldF94X3Rvb2x0aXAiLCJ4X3Rvb2x0aXAiLCJjb2xvcnMiLCJ6ZXJvX2xpbmUiLCJ2YWx1ZXMiLCJpc05hTiIsInNldHVwX3giLCJzZXR1cF95Iiwic2V0X2F2Z191bml0X3dpZHRoX2FuZF94X29mZnNldCIsInhfYXhpc19wb3NpdGlvbnMiLCJ4X29sZF9heGlzX3Bvc2l0aW9ucyIsInhfb2Zmc2V0IiwiYXZnX3VuaXRfd2lkdGgiLCJ5X2F4aXNfdmFsdWVzIiwieV9vbGRfYXhpc192YWx1ZXMiLCJnZXRfYWxsX3lfdmFsdWVzIiwieV9zdW1zIiwiY29uY2F0IiwiZ2V0X3lfYXhpc19wb2ludHMiLCJ5X3B0cyIsInZhbHVlX3JhbmdlIiwibXVsdGlwbGllciIsIm9sZF9tdWx0aXBsaWVyIiwiemVyb19pbmRleCIsImluZGV4T2YiLCJpbnRlcnZhbCIsImludGVydmFsX2hlaWdodCIsIm9sZF96ZXJvX2xpbmUiLCJzZXR1cF9tYXJrZXJfY29tcG9uZW50cyIsInNldHVwX2FnZ3JlZ2F0aW9uX2NvbXBvbmVudHMiLCJzZXR1cF9ncmFwaF9jb21wb25lbnRzIiwieV9heGlzX2dyb3VwIiwiY2xhc3NOYW1lIiwiaW5zaWRlIiwieF9heGlzX2dyb3VwIiwic3BlY2lmaWNfeV9ncm91cCIsInN1bV9ncm91cCIsImF2ZXJhZ2VfZ3JvdXAiLCJzdmdfdW5pdHNfZ3JvdXBzIiwibWFrZV95X2F4aXMiLCJtYWtlX3hfYXhpcyIsImRyYXdfZ3JhcGgiLCJtYWtlX3lfc3BlY2lmaWNzIiwiYW5pbWF0ZSIsInN0YXJ0X2F0IiwidGV4dF9zdGFydF9hdCIsImF4aXNfbGluZV9jbGFzcyIsInhfYXhpc19tb2RlIiwibWFrZV9hbmltX3hfYXhpcyIsInRleHRDb250ZW50IiwicG9pbnQiLCJtYWtlX3hfbGluZSIsIm1ha2VfYW5pbV95X2F4aXMiLCJtYWtlX2FuaW1feV9zcGVjaWZpY3MiLCJnZXRfeV9heGlzX2xpbmVfcHJvcHMiLCJ0ZXh0X2VuZF9hdCIsIm1ha2VfeV9saW5lIiwic3BlY2lmaWMiLCJ5X2F4aXNfbW9kZSIsImRyYXdfbmV3X2dyYXBoX2FuZF9hbmltYXRlIiwic3ZnX3VuaXRzIiwibWFrZV9wYXRoIiwieV90b3BzIiwibWFrZV9uZXdfdW5pdHMiLCJBcnJheSIsImZpbGwiLCJ1cGRhdGVfdmFsdWVzIiwibWFrZV9uZXdfdW5pdHNfZm9yX2RhdGFzZXQiLCJ4X3ZhbHVlcyIsInlfdmFsdWVzIiwiZGF0YXNldF9pbmRleCIsIm5vX29mX2RhdGFzZXRzIiwiZ3JvdXAiLCJ1bml0X2FyZ3MiLCJkYXRhX3VuaXQiLCJkcmF3IiwidG9VcHBlckNhc2UiLCJsaW5lX3R5cGUiLCJyZWxYIiwicGFnZVgiLCJyZWxZIiwicGFnZVkiLCJtYXBfdG9vbHRpcF94X3Bvc2l0aW9uX2FuZF9zaG93IiwiaGlkZV90aXAiLCJ4X3ZhbCIsInlfbWluX3RvcHMiLCJmb3JtYXR0ZWQiLCJzZXQiLCJzZXRfdmFsdWVzIiwic2hvd190aXAiLCJ1cGRhdGluZyIsInN1bV91bml0cyIsIm9sZF9zcGVjaWZpY192YWx1ZXMiLCJzdW0iLCJhdmVyYWdlIiwiaW5kaWNlc190b19yZW1vdmUiLCJhdXRvIiwidW5zaGlmdCIsInNwbGljZSIsIm5ld195IiwibmV3X3giLCJlbGVtZW50c190b19hbmltYXRlIiwib2xkX3hfdmFsdWVzIiwib2xkX3lfYXhpc190b3BzIiwib2xkX3lfdmFsdWVzIiwibm9fb2ZfZXh0cmFfcHRzIiwiY2FsY195X2RlcGVuZGVuY2llcyIsImFuaW1hdGVfZ3JhcGhzIiwicnVuX2FuaW1hdGlvbiIsInlfcG9pbnQiLCJ4X3BvaW50IiwiZGF0YV9zZXQiLCJyZW1vdmVDaGlsZCIsImNhbGNfb2xkX2FuZF9uZXdfcG9zdGlvbnMiLCJvbGRfeCIsIm9sZF95IiwicGF0aCIsImFuaW1hdGVfcGF0aCIsImFuaW1hdGVfdW5pdHMiLCJuZXdfcG9pbnRzX2xpc3QiLCJuZXdfcGF0aF9zdHIiLCJqb2luIiwicGF0aF9hcmdzIiwicmVnaW9uX3BhdGgiLCJyZWdfc3RhcnRfcHQiLCJyZWdfZW5kX3B0IiwicmVnaW9uX2FyZ3MiLCJsYXN0X29sZF94X3BvcyIsImxhc3Rfb2xkX3lfcG9zIiwibGFzdF9uZXdfeF9wb3MiLCJsYXN0X25ld195X3BvcyIsImZpbGxlcl94IiwiTWF0aCIsImFicyIsImZpbGxlcl95Iiwib2xkX3BvcyIsIm5ld19wb3MiLCJvbGRfdmFscyIsIm5ld192YWxzIiwibGFzdF9saW5lX3BvcyIsImFkZF9hbmRfYW5pbWF0ZV9saW5lIiwieF9saW5lIiwidHJhbnNmb3JtIiwibWFrZV9uZXdfYXhpc19hbmltX2xpbmVzIiwiYWRkX2FuZF9hbmltYXRlX3lfbGluZSIsInN1cGVyaW1wb3NlZF9wb3NpdGlvbnMiLCJzdXBlcmltcG9zZWRfdmFsdWVzIiwibm9fb2ZfZXh0cmFzIiwiZmlsbGVyX3ZhbHMiLCJmaWxsZXJfcG9zIiwiZXh0cmFfdmFsdWVzIiwiZXh0cmFfcG9zaXRpb25zIiwibGFiZWxfY2xhc3MiLCJ4X3BvcyIsImFsbG93ZWRfc3BhY2UiLCJhbGxvd2VkX2xldHRlcnMiLCJsaW5lIiwidGV4dCIsInhfbGV2ZWwiLCJ5X3BvcyIsImRhcmtlciIsInlfbGV2ZWwiLCJzdHlsZSIsInN0cm9rZSIsImF4aXNfbGFiZWxfY2xhc3MiLCJ5X2xpbmUiLCJtYXhfYm91bmQiLCJtaW5fYm91bmQiLCJwb3Nfbm9fb2ZfcGFydHMiLCJuZWdfbm9fb2ZfcGFydHMiLCJwYXJ0X3NpemUiLCJtYXhfdmFsIiwicGFyc2VJbnQiLCJtYXgiLCJtaW5fdmFsIiwibWluIiwiZ2V0X3BhcmFtcyIsInZhbHVlMSIsInZhbHVlMiIsImJvdW5kMSIsImJvdW5kMiIsIm5vX29mX3BhcnRzXzEiLCJub19vZl9wYXJ0c18yIiwiaW50ZXJ2YWxfc2l6ZSIsImNhbGNfdXBwZXJfYm91bmRfYW5kX25vX29mX3BhcnRzIiwiY2FsY19ub19vZl9wYXJ0cyIsImFic19taW5fdmFsIiwibm9fb2ZfcGFydHMiLCJnZXRfaW50ZXJ2YWxzIiwic3RhcnQiLCJjb3VudCIsImludGVydmFscyIsInBvdyIsInVwcGVyX2JvdW5kIiwiZGl2aXNvciIsImNlaWwiLCJhbGxfdmFsdWVzIiwieV90b3AiLCJ0b3RhbF93aWR0aCIsInNwYWNlX3dpZHRoIiwic3RhcnRfeCIsImN1cnJlbnRfeCIsImdldF9iYXJfaGVpZ2h0X2FuZF95X2F0dHIiLCJyYWRpdXMiLCJiYXJfb2JqIiwiZG90X29iaiIsImN4IiwiY3kiLCJzZXR1cCIsInVwZGF0ZV9jdXJyZW50X2RhdGFfcG9pbnQiLCJvdmVybGF5Iiwib3BhY2l0eSIsInVwZGF0ZV9vdmVybGF5Iiwic3ZnX3VuaXQiLCJhdHRyaWJ1dGVzIiwia2V5cyIsImZpbHRlciIsImF0dHIiLCJzcGVjaWZpZWQiLCJuYW1lIiwibm9kZVZhbHVlIiwicmVnaW9uX2ZpbGwiLCJzZXR1cF9wYXRoX2dyb3VwcyIsInBhdGhzX2dyb3VwcyIsInhfcG9zaXRpb25zIiwieV9wb3NpdGlvbnMiLCJwb2ludHNfbGlzdCIsInBvaW50c19zdHIiLCJncmFkaWVudF9pZCIsImdyYWRpZW50X2RlZiIsInNldF9ncmFkaWVudF9zdG9wIiwiZ3JhZF9lbGVtIiwibWF4X3NsaWNlcyIsIm1heF9sZWdlbmRfcG9pbnRzIiwibWFyZ2luVG9wIiwibWFyZ2luQm90dG9tIiwicGFkZGluZ1RvcCIsImNoYXJ0X2RpdiIsImNoYXJ0IiwicGVyY2VudGFnZV9iYXIiLCJzbGljZV90b3RhbHMiLCJhbGxfdG90YWxzIiwidG90YWwiLCJ0b3RhbHMiLCJzb3J0IiwiYSIsImIiLCJvdGhlcnMiLCJzdW1fb2Zfb3RoZXJzIiwibGVnZW5kX3RvdGFscyIsImdyYW5kX3RvdGFsIiwicmVkdWNlIiwic2xpY2VzIiwiZ19vZmYiLCJwX29mZiIsImZvcm1hdHRlZF9sYWJlbHMiLCJwZXJjZW50IiwiZG9tYWluIiwic3ViZG9tYWluIiwiZGlzY3JldGVfZG9tYWlucyIsImNvdW50X2xhYmVsIiwidG9kYXkiLCJEYXRlIiwiYWRkX2RheXMiLCJsZWdlbmRfY29sb3JzIiwic2V0RnVsbFllYXIiLCJnZXRGdWxsWWVhciIsImZpcnN0X3dlZWtfc3RhcnQiLCJ0b0RhdGVTdHJpbmciLCJsYXN0X3dlZWtfc3RhcnQiLCJnZXREYXkiLCJub19vZl9jb2xzIiwiZ2V0X3dlZWtzX2JldHdlZW4iLCJkb21haW5fbGFiZWxfZ3JvdXAiLCJkYXRhX2dyb3VwcyIsImRpc3RyaWJ1dGlvbiIsImdldF9kaXN0cmlidXRpb24iLCJtb250aF9uYW1lcyIsInJlbmRlcl9hbGxfd2Vla3NfYW5kX3N0b3JlX3hfdmFsdWVzIiwibm9fb2Zfd2Vla3MiLCJjdXJyZW50X3dlZWtfc3VuZGF5Iiwid2Vla19jb2wiLCJjdXJyZW50X21vbnRoIiwiZ2V0TW9udGgiLCJtb250aHMiLCJtb250aF93ZWVrcyIsIm1vbnRoX3N0YXJ0X3BvaW50cyIsImRhdGFfZ3JvdXAiLCJtb250aF9jaGFuZ2UiLCJkYXkiLCJnZXRfd2Vla19zcXVhcmVzX2dyb3VwIiwicmVuZGVyX21vbnRoX2xhYmVscyIsImN1cnJlbnRfZGF0ZSIsIm5vX29mX3dlZWtkYXlzIiwic3F1YXJlX3NpZGUiLCJjZWxsX3BhZGRpbmciLCJzdGVwIiwid2Vla19jb2xfY2hhbmdlIiwiZGF0YV92YWx1ZSIsImNvbG9yX2luZGV4IiwidGltZXN0YW1wIiwiZmxvb3IiLCJnZXRUaW1lIiwiZ2V0X21heF9jaGVja3BvaW50Iiwicm91bmQiLCJnZXRfZGRfbW1feXl5eSIsIm5leHRfZGF0ZSIsInNoaWZ0IiwicG9wIiwibW9udGhfbmFtZSIsInN1YnN0cmluZyIsImNhbGwiLCJxdWVyeVNlbGVjdG9yQWxsIiwiZGlzcGxheSIsImRhdGVfcGFydHMiLCJtb250aCIsIm1hcHBlcl9hcnJheSIsImRhdGFfdmFsdWVzIiwiZGF0YV9tYXhfdmFsdWUiLCJkaXN0cmlidXRpb25fc3RlcCIsImNoZWNrcG9pbnQiLCJkYXRlX3N0ciIsInJlc3VsdCIsInNldE1pbnV0ZXMiLCJnZXRNaW51dGVzIiwiZ2V0VGltZXpvbmVPZmZzZXQiLCJkYXRlIiwiZGQiLCJnZXREYXRlIiwibW0iLCJzdGFydF9kYXRlX3N0ciIsImVuZF9kYXRlX3N0ciIsImdldF9kYXlzX2JldHdlZW4iLCJtaWxsaXNlY29uZHNfcGVyX2RheSIsInRyZWF0X2FzX3V0YyIsIm51bWJlcl9vZl9kYXlzIiwic2V0RGF0ZSIsInRpdGxlX25hbWUiLCJ0aXRsZV92YWx1ZSIsImxpc3RfdmFsdWVzIiwidGl0bGVfdmFsdWVfZmlyc3QiLCJjYWxjX3Bvc2l0aW9uIiwiZGF0YV9wb2ludF9saXN0IiwibGkiLCJvZmZzZXRIZWlnaHQiLCJtYXhfbGVmdCIsInBvaW50ZXIiLCJkZWx0YSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQWUsU0FBU0EsQ0FBVCxDQUFXQyxJQUFYLEVBQWlCQyxHQUFqQixFQUFzQjtRQUM3QixPQUFPRCxJQUFQLEtBQWdCLFFBQWhCLEdBQTBCLENBQUNDLE9BQU9DLFFBQVIsRUFBa0JDLGFBQWxCLENBQWdDSCxJQUFoQyxDQUExQixHQUFrRUEsUUFBUSxJQUFqRjs7O0FBR0RE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 +var Chart=function(){"use strict";function t(t,e){return"string"==typeof t?(e||document).querySelector(t):t||null}function e(t){return parseFloat(t.toFixed(2))}function i(t,e){if(t.length!==e.length)return!1;var i=!0;return t.map(function(t,a){e[a]!==t&&(i=!1)}),i}!function(){function t(t){this.value=t}function e(e){function i(s,n){try{var r=e[s](n),o=r.value;o instanceof t?Promise.resolve(o.value).then(function(t){i("next",t)},function(t){i("throw",t)}):a(r.done?"return":"normal",r.value)}catch(t){a("throw",t)}}function a(t,e){switch(t){case"return":s.resolve({value:e,done:!0});break;case"throw":s.reject(e);break;default:s.resolve({value:e,done:!1})}(s=s.next)?i(s.key,s.arg):n=null}var s,n;this._invoke=function(t,e){return new Promise(function(a,r){var o={key:t,arg:e,resolve:a,reject:r,next:null};n?n=n.next=o:(s=n=o,i(t,e))})},"function"!=typeof e.return&&(this.return=void 0)}"function"==typeof Symbol&&Symbol.asyncIterator&&(e.prototype[Symbol.asyncIterator]=function(){return this}),e.prototype.next=function(t){return this._invoke("next",t)},e.prototype.throw=function(t){return this._invoke("throw",t)},e.prototype.return=function(t){return this._invoke("return",t)}}();var a=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},s=function(){function t(t,e){for(var i=0;i3&&void 0!==arguments[3]?arguments[3]:"linear",s=arguments.length>4&&void 0!==arguments[4]?arguments[4]:void 0,n=arguments.length>5&&void 0!==arguments[5]?arguments[5]:{},r={ease:"0.25 0.1 0.25 1",linear:"0 0 1 1",easein:"0.1 0.8 0.2 1",easeout:"0 0 0.58 1",easeinout:"0.42 0 0.58 1"},o=t.cloneNode(!0),_=t.cloneNode(!0);for(var l in e){var h=void 0;h="transform"===l?document.createElementNS("http://www.w3.org/2000/svg","animateTransform"):document.createElementNS("http://www.w3.org/2000/svg","animate");var u=n[l]||t.getAttribute(l),c=e[l],p={attributeName:l,from:u,to:c,begin:"0s",dur:i/1e3+"s",values:u+";"+c,keySplines:r[a],keyTimes:"0;1",calcMode:"spline",fill:"freeze"};s&&(p.type=s);for(var d in p)h.setAttribute(d,p[d]);o.appendChild(h),s?_.setAttribute(l,"translate("+c+")"):_.setAttribute(l,c)}return[o,_]},t.offset=function(t){var e=t.getBoundingClientRect();return{top:e.top+(document.documentElement.scrollTop||document.body.scrollTop),left:e.left+(document.documentElement.scrollLeft||document.body.scrollLeft)}},t.isElementInViewport=function(t){var e=t.getBoundingClientRect();return e.top>=0&&e.left>=0&&e.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&e.right<=(window.innerWidth||document.documentElement.clientWidth)},t.bind=function(t,e){if(t)for(var i in e){var a=e[i];i.split(/\s+/).forEach(function(e){t.addEventListener(e,a)})}},t.unbind=function(t,e){if(t)for(var i in e){var a=e[i];i.split(/\s+/).forEach(function(e){t.removeEventListener(e,a)})}},t.fire=function(t,e,i){var a=document.createEvent("HTMLEvents");a.initEvent(e,!0,!0);for(var s in i)a[s]=i[s];return t.dispatchEvent(a)};var h=function(){function e(t){var i=t.parent,s=void 0===i?null:i;a(this,e),this.parent=s,this.title_name="",this.title_value="",this.list_values=[],this.title_value_first=0,this.x=0,this.y=0,this.top=0,this.left=0,this.setup()}return s(e,[{key:"setup",value:function(){this.make_tooltip()}},{key:"refresh",value:function(){this.fill(),this.calc_position()}},{key:"make_tooltip",value:function(){var e=this;this.container=t.create("div",{inside:this.parent,className:"graph-svg-tip comparison",innerHTML:'\n\t\t\t\t\n\t\t\t\t
'}),this.hide_tip(),this.title=this.container.querySelector(".title"),this.data_point_list=this.container.querySelector(".data-point-list"),this.parent.addEventListener("mouseleave",function(){e.hide_tip()})}},{key:"fill",value:function(){var e=this,i=void 0;i=this.title_value_first?""+this.title_value+""+this.title_name:this.title_name+""+this.title_value+"",this.title.innerHTML=i,this.data_point_list.innerHTML="",this.list_values.map(function(i){var a=t.create("li",{className:"border-top "+(i.color||"black"),innerHTML:''+(i.value?i.value:"")+"\n\t\t\t\t\t"+(i.title?i.title:"")});e.data_point_list.appendChild(a)})}},{key:"calc_position",value:function(){this.top=this.y-this.container.offsetHeight,this.left=this.x-this.container.offsetWidth/2;var t=this.parent.offsetWidth-this.container.offsetWidth,e=this.container.querySelector(".svg-pointer");if(this.left<0)e.style.left="calc(50% - "+-1*this.left+"px)",this.left=0;else if(this.left>t){var i=this.left-t;e.style.left="calc(50% + "+i+"px)",this.left=t}else e.style.left="50%"}},{key:"set_values",value:function(t,e){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"",s=arguments.length>4&&void 0!==arguments[4]?arguments[4]:[],n=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0;this.title_name=i,this.title_value=a,this.list_values=s,this.x=t,this.y=e,this.title_value_first=n,this.refresh()}},{key:"hide_tip",value:function(){this.container.style.top="0px",this.container.style.left="0px",this.container.style.opacity="0"}},{key:"show_tip",value:function(){this.container.style.top=this.top+"px",this.container.style.left=this.left+"px",this.container.style.opacity="1"}}]),e}(),u=function(){function e(t){var i=t.parent,s=void 0===i?"":i,n=t.height,r=void 0===n?240:n,o=t.title,_=void 0===o?"":o,l=t.subtitle,h=void 0===l?"":l,u=t.data,c=void 0===u?{}:u,p=t.format_lambdas,d=void 0===p?{}:p,v=t.summary,f=void 0===v?[]:v,y=t.is_navigable,m=void 0===y?0:y;a(this,e),this.raw_chart_args=arguments[0],this.parent=document.querySelector(s),this.title=_,this.subtitle=h,this.data=c,this.format_lambdas=d,this.specific_values=c.specific_values||[],this.summary=f,this.is_navigable=m,this.is_navigable&&(this.current_index=0),this.chart_types=["line","bar","percentage","heatmap"],this.set_margins(r)}return s(e,[{key:"get_different_chart",value:function(t){if(this.chart_types.includes(t)||console.error("'"+t+"' is not a valid chart type."),t!==this.type){return{bar:["line","percentage"],line:["bar","percentage"],percentage:["bar","line"],heatmap:[]}[this.type].includes(t)||console.error("'"+this.type+"' chart cannot be converted to a '"+t+"' chart."),new e({parent:this.raw_chart_args.parent,data:this.raw_chart_args.data,type:t,height:this.raw_chart_args.height})}}},{key:"set_margins",value:function(t){this.base_height=t,this.height=t-40,this.translate_x=60,this.translate_y=10}},{key:"setup",value:function(){this.bind_window_events(),this.refresh(!0)}},{key:"bind_window_events",value:function(){var t=this;window.addEventListener("resize",function(){return t.refresh()}),window.addEventListener("orientationchange",function(){return t.refresh()})}},{key:"refresh",value:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.setup_base_values(),this.set_width(),this.setup_container(),this.setup_components(),this.setup_values(),this.setup_utils(),this.make_graph_components(t),this.make_tooltip(),this.summary.length>0?this.show_custom_summary():this.show_summary(),this.is_navigable&&this.setup_navigation(t)}},{key:"set_width",value:function(){var t=this,e=0;this.specific_values.map(function(i){t.get_strwidth(i.title)>e&&(e=t.get_strwidth(i.title)-40)}),this.base_width=this.parent.offsetWidth-e,this.width=this.base_width-2*this.translate_x}},{key:"setup_base_values",value:function(){}},{key:"setup_container",value:function(){this.container=t.create("div",{className:"chart-container",innerHTML:'
'+this.title+'
\n\t\t\t\t
'+this.subtitle+'
\n\t\t\t\t
\n\t\t\t\t
'}),this.parent.innerHTML="",this.parent.appendChild(this.container),this.chart_wrapper=this.container.querySelector(".frappe-chart"),this.stats_wrapper=this.container.querySelector(".graph-stats-container"),this.make_chart_area(),this.make_draw_area()}},{key:"make_chart_area",value:function(){return this.svg=t.createSVG("svg",{className:"chart",inside:this.chart_wrapper,width:this.base_width,height:this.base_height}),this.svg_defs=t.createSVG("defs",{inside:this.svg}),this.svg}},{key:"make_draw_area",value:function(){this.draw_area=t.createSVG("g",{className:this.type+"-chart",inside:this.svg,transform:"translate("+this.translate_x+", "+this.translate_y+")"})}},{key:"setup_components",value:function(){}},{key:"make_tooltip",value:function(){this.tip=new h({parent:this.chart_wrapper}),this.bind_tooltip()}},{key:"show_summary",value:function(){}},{key:"show_custom_summary",value:function(){var e=this;this.summary.map(function(i){var a=t.create("div",{className:"stats",innerHTML:''+i.title+": "+i.value+""});e.stats_wrapper.appendChild(a)})}},{key:"setup_navigation",value:function(){var e=this,i=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.make_overlay(),i&&(this.bind_overlay(),document.addEventListener("keydown",function(i){t.isElementInViewport(e.chart_wrapper)&&("37"==(i=i||window.event).keyCode?e.on_left_arrow():"39"==i.keyCode?e.on_right_arrow():"38"==i.keyCode?e.on_up_arrow():"40"==i.keyCode?e.on_down_arrow():"13"==i.keyCode&&e.on_enter_key())}))}},{key:"make_overlay",value:function(){}},{key:"bind_overlay",value:function(){}},{key:"on_left_arrow",value:function(){}},{key:"on_right_arrow",value:function(){}},{key:"on_up_arrow",value:function(){}},{key:"on_down_arrow",value:function(){}},{key:"on_enter_key",value:function(){}},{key:"get_data_point",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.current_index,e={index:t},i=this.y[0];return["svg_units","y_tops","values"].map(function(a){var s=a.slice(0,a.length-1);e[s]=i[a][t]}),e.label=this.x[t],e}},{key:"update_current_data_point",value:function(e){e<0&&(e=0),e>=this.x.length&&(e=this.x.length-1),e!==this.current_index&&(this.current_index=e,t.fire(this.parent,"data-select",this.get_data_point()))}},{key:"get_strwidth",value:function(t){return 8*t.length}},{key:"setup_utils",value:function(){}}]),e}(),c=function(h){function c(t){a(this,c);var e=o(this,(c.__proto__||Object.getPrototypeOf(c)).call(this,t));return e.x=e.data.labels,e.y=e.data.datasets,e.get_y_label=e.format_lambdas.y_label,e.get_y_tooltip=e.format_lambdas.y_tooltip,e.get_x_tooltip=e.format_lambdas.x_tooltip,e.colors=["green","blue","violet","red","orange","yellow","light-blue","light-green","purple","magenta"],e.zero_line=e.height,e}return r(c,u),s(c,[{key:"setup_values",value:function(){this.data.datasets.map(function(t){t.values=t.values.map(function(t){return isNaN(t)?0:t})}),this.setup_x(),this.setup_y()}},{key:"setup_x",value:function(){var t=this;this.set_avg_unit_width_and_x_offset(),this.x_axis_positions&&(this.x_old_axis_positions=this.x_axis_positions.slice()),this.x_axis_positions=this.x.map(function(i,a){return e(t.x_offset+a*t.avg_unit_width)}),this.x_old_axis_positions||(this.x_old_axis_positions=this.x_axis_positions.slice())}},{key:"setup_y",value:function(){this.y_axis_values&&(this.y_old_axis_values=this.y_axis_values.slice());var t=this.get_all_y_values();this.y_sums&&this.y_sums.length>0&&(t=t.concat(this.y_sums)),this.y_axis_values=this.get_y_axis_points(t),this.y_old_axis_values||(this.y_old_axis_values=this.y_axis_values.slice());var e=this.y_axis_values,i=e[e.length-1]-e[0];this.multiplier&&(this.old_multiplier=this.multiplier),this.multiplier=this.height/i,this.old_multiplier||(this.old_multiplier=this.multiplier);var a=e.indexOf(0),s=(e[1]-e[0])*this.multiplier;this.zero_line&&(this.old_zero_line=this.zero_line),this.zero_line=this.height-a*s,this.old_zero_line||(this.old_zero_line=this.zero_line)}},{key:"setup_components",value:function(){n(c.prototype.__proto__||Object.getPrototypeOf(c.prototype),"setup_components",this).call(this),this.setup_marker_components(),this.setup_aggregation_components(),this.setup_graph_components()}},{key:"setup_marker_components",value:function(){this.y_axis_group=t.createSVG("g",{className:"y axis",inside:this.draw_area}),this.x_axis_group=t.createSVG("g",{className:"x axis",inside:this.draw_area}),this.specific_y_group=t.createSVG("g",{className:"specific axis",inside:this.draw_area})}},{key:"setup_aggregation_components",value:function(){this.sum_group=t.createSVG("g",{className:"data-points",inside:this.draw_area}),this.average_group=t.createSVG("g",{className:"chart-area",inside:this.draw_area})}},{key:"setup_graph_components",value:function(){var e=this;this.svg_units_groups=[],this.y.map(function(i,a){e.svg_units_groups[a]=t.createSVG("g",{className:"data-points data-points-"+a,inside:e.draw_area})})}},{key:"make_graph_components",value:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.make_y_axis(),this.make_x_axis(),this.draw_graph(t),this.make_y_specifics()}},{key:"make_x_axis",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],i=void 0,a=void 0,s=void 0,n="";"span"===this.x_axis_mode?(i=-7,a=this.height+15,s=this.height+25):"tick"===this.x_axis_mode&&(i=this.height,a=6,s=9,n="x-axis-label"),this.x_axis_group.setAttribute("transform","translate(0,"+i+")"),e?this.make_anim_x_axis(a,s,n):(this.x_axis_group.textContent="",this.x.map(function(e,i){t.x_axis_group.appendChild(t.make_x_line(a,s,e,"x-value-text",n,t.x_axis_positions[i]))}))}},{key:"make_y_axis",value:function(){var t=this;if(arguments.length>0&&void 0!==arguments[0]&&arguments[0])return this.make_anim_y_axis(),void this.make_anim_y_specifics();var e=this.get_y_axis_line_props(),i=_(e,4),a=i[0],s=i[1],n=i[2],r=i[3];this.y_axis_group.textContent="",this.y_axis_values.map(function(e,i){t.y_axis_group.appendChild(t.make_y_line(r,a,s,e,"y-value-text",n,t.zero_line-e*t.multiplier,0===e&&0!==i))})}},{key:"get_y_axis_line_props",value:function(){if(arguments.length>0&&void 0!==arguments[0]&&arguments[0])return[this.width,this.width+5,"specific-value",0];var t=void 0,e="",i=0;return"span"===this.y_axis_mode?(t=this.width+6,i=-6):"tick"===this.y_axis_mode&&(t=-6,e="y-axis-label"),[t,-9,e,i]}},{key:"draw_graph",value:function(){var t=this;arguments.length>0&&void 0!==arguments[0]&&arguments[0]?this.draw_new_graph_and_animate():this.y.map(function(e,i){e.svg_units=[],t.make_path&&t.make_path(e,i,t.x_axis_positions,e.y_tops,e.color||t.colors[i]),t.make_new_units(e,i)})}},{key:"draw_new_graph_and_animate",value:function(){var t=this,e=[];this.y.map(function(i,a){i.y_tops=new Array(i.values.length).fill(t.zero_line),e.push({values:i.values}),i.svg_units=[],t.make_path&&t.make_path(i,a,t.x_axis_positions,i.y_tops,i.color||t.colors[a]),t.make_new_units(i,a)}),setTimeout(function(){t.update_values(e)},350)}},{key:"setup_navigation",value:function(t){var e=this;setTimeout(function(){n(c.prototype.__proto__||Object.getPrototypeOf(c.prototype),"setup_navigation",e).call(e,t)},500)}},{key:"make_new_units",value:function(t,e){this.make_new_units_for_dataset(this.x_axis_positions,t.y_tops,t.color||this.colors[e],e,this.y.length)}},{key:"make_new_units_for_dataset",value:function(t,e,i,a,s,n,r,o){var _=this;n||(n=this.svg_units_groups[a]),r||(r=this.y[a].svg_units),o||(o=this.unit_args),n.textContent="",r.length=0,e.map(function(e,l){var h=_.draw[o.type](t[l],e,o.args,i,a,s);n.appendChild(h),r.push(h)})}},{key:"make_y_specifics",value:function(){var t=this;this.specific_y_group.textContent="",this.specific_values.map(function(e){t.specific_y_group.appendChild(t.make_y_line(0,t.width,t.width+5,e.title.toUpperCase(),"specific-value","specific-value",t.zero_line-e.value*t.multiplier,!1,e.line_type))})}},{key:"bind_tooltip",value:function(){var e=this;this.chart_wrapper.addEventListener("mousemove",function(i){var a=t.offset(e.chart_wrapper),s=i.pageX-a.left-e.translate_x;i.pageY-a.top-e.translate_y=0;i--){var a=this.x_axis_positions[i];if(t>a-this.avg_unit_width/2){var s=a+this.translate_x,n=this.y_min_tops[i]+this.translate_y,r=this.x.formatted&&this.x.formatted.length>0?this.x.formatted[i]:this.x[i],o=this.y.map(function(t,a){return{title:t.title,value:t.formatted?t.formatted[i]:t.values[i],color:t.color||e.colors[a]}});this.tip.set_values(s,n,r,"",o),this.tip.show_tip();break}}}},{key:"show_sums",value:function(){var t=this;this.updating=!0,this.y_sums=new Array(this.x_axis_positions.length).fill(0),this.y.map(function(e){e.values.map(function(e,i){t.y_sums[i]+=e})}),this.update_values(),this.sum_units=[],this.make_new_units_for_dataset(this.x_axis_positions,this.y_sums.map(function(i){return e(t.zero_line-i*t.multiplier)}),"light-grey",0,1,this.sum_group,this.sum_units),this.updating=!1}},{key:"hide_sums",value:function(){this.updating||(this.y_sums=[],this.sum_group.textContent="",this.sum_units=[],this.update_values())}},{key:"show_average",value:function(){var t=this;this.old_specific_values=this.specific_values.slice(),this.y.map(function(e,i){var a=0;e.values.map(function(t){a+=t});var s=a/e.values.length;t.specific_values.push({title:"AVG "+(i+1),line_type:"dashed",value:s,auto:1})}),this.update_values()}},{key:"hide_average",value:function(){var t=this;this.old_specific_values=this.specific_values.slice();var e=[];this.specific_values.map(function(t,i){t.auto&&e.unshift(i)}),e.map(function(e){t.specific_values.splice(e,1)}),this.update_values()}},{key:"update_values",value:function(t,e){var a=this;e||(e=this.x),this.elements_to_animate=[],this.updating=!0,this.old_x_values=this.x.slice(),this.old_y_axis_tops=this.y.map(function(t){return t.y_tops.slice()}),this.old_y_values=this.y.map(function(t){return t.values}),this.no_of_extra_pts=e.length-this.x.length,t&&this.y.map(function(e,i){e.values=t[i].values}),e&&(this.x=e),this.setup_x(),this.setup_y(),i(this.x_old_axis_positions,this.x_axis_positions)||(this.make_x_axis(!0),setTimeout(function(){a.updating||a.make_x_axis()},300)),(!i(this.y_old_axis_values,this.y_axis_values)||this.old_specific_values&&!i(this.old_specific_values,this.specific_values))&&(this.make_y_axis(!0),setTimeout(function(){a.updating||(a.make_y_axis(),a.make_y_specifics())},300)),this.calc_y_dependencies(),this.animate_graphs(),this.run_animation(),this.updating=!1}},{key:"add_data_point",value:function(t,e){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.x.length,a=this.y.map(function(t){return{values:t.values}});a.map(function(e,a){e.values.splice(i,0,t[a])});var s=this.x.slice();s.splice(i,0,e),this.update_values(a,s)}},{key:"remove_data_point",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.x.length-1;if(!(this.x.length<3)){var e=this.y.map(function(t){return{values:t.values}});e.map(function(e){e.values.splice(t,1)});var i=this.x.slice();i.splice(t,1),this.update_values(e,i)}}},{key:"run_animation",value:function(){var e=this,i=t.runSVGAnimation(this.svg,this.elements_to_animate);this.svg.parentNode==this.chart_wrapper&&(this.chart_wrapper.removeChild(this.svg),this.chart_wrapper.appendChild(i)),setTimeout(function(){i.parentNode==e.chart_wrapper&&(e.chart_wrapper.removeChild(i),e.chart_wrapper.appendChild(e.svg))},200)}},{key:"animate_graphs",value:function(){var t=this;this.y.map(function(e,i){var a=t.calc_old_and_new_postions(e,i),s=_(a,4),n=s[0],r=s[1],o=s[2],l=s[3];t.no_of_extra_pts>=0&&(t.make_path&&t.make_path(e,i,n,r,e.color||t.colors[i]),t.make_new_units_for_dataset(n,r,e.color||t.colors[i],i,t.y.length)),e.path&&t.animate_path(e,i,n,r,o,l),t.animate_units(e,i,n,r,o,l)}),setTimeout(function(){t.y.map(function(e,i){t.make_path&&t.make_path(e,i,t.x_axis_positions,e.y_tops,e.color||t.colors[i]),t.make_new_units(e,i)})},300)}},{key:"animate_path",value:function(t,e,i,a,s,n){var r=n.map(function(t,e){return s[e]+","+t}).join("L"),o=[{unit:t.path,object:t,key:"path"},{d:"M"+r},250,"easein"];if(this.elements_to_animate.push(o),t.region_path){var _="0,"+this.zero_line+"L",l="L"+this.width+","+this.zero_line,h=[{unit:t.region_path,object:t,key:"region_path"},{d:"M"+_+r+l},250,"easein"];this.elements_to_animate.push(h)}}},{key:"animate_units",value:function(t,e,i,a,s,n){var r=this,o=this.unit_args.type;t.svg_units.map(function(i,a){r.elements_to_animate.push(r.animate[o]({unit:i,array:t.svg_units,index:a},s[a],n[a],e))})}},{key:"calc_old_and_new_postions",value:function(t,e){var i=this.x_old_axis_positions.slice(),a=this.x_axis_positions.slice(),s=this.old_y_axis_tops[e].slice(),n=t.y_tops.slice(),r=i[i.length-1],o=s[s.length-1],_=a[a.length-1],l=n[n.length-1];if(this.no_of_extra_pts>=0){var h=new Array(Math.abs(this.no_of_extra_pts)).fill(r),u=new Array(Math.abs(this.no_of_extra_pts)).fill(o);i=i.concat(h),s=s.concat(u)}else{var c=new Array(Math.abs(this.no_of_extra_pts)).fill(_),p=new Array(Math.abs(this.no_of_extra_pts)).fill(l);a=a.concat(c),n=n.concat(p)}return[i,s,a,n]}},{key:"make_anim_x_axis",value:function(t,e,i){var a=this,s=this.x_old_axis_positions,n=this.x_axis_positions,r=this.old_x_values,o=this.x,_=s[s.length-1];this.x_axis_group.textContent="",this.make_new_axis_anim_lines(s,n,r,o,_,function(s,n,r){var o=a.make_x_line(t,e,s,"x-value-text",i,n);a.x_axis_group.appendChild(o),a.elements_to_animate&&a.elements_to_animate.push([{unit:o,array:[0],index:0},{transform:r+", 0"},250,"easein","translate",{transform:n+", 0"}])})}},{key:"make_anim_y_axis",value:function(){var t=this,e=this.y_old_axis_values.map(function(e){return t.zero_line-e*t.multiplier}),i=this.y_axis_values.map(function(e){return t.zero_line-e*t.multiplier}),a=this.y_old_axis_values,s=this.y_axis_values,n=e[e.length-1];this.y_axis_group.textContent="",this.make_new_axis_anim_lines(e,i,a,s,n,this.add_and_animate_y_line.bind(this),this.y_axis_group)}},{key:"make_anim_y_specifics",value:function(){var t=this;this.specific_y_group.textContent="",this.specific_values.map(function(e){t.add_and_animate_y_line(e.title,t.old_zero_line-e.value*t.old_multiplier,t.zero_line-e.value*t.multiplier,0,t.specific_y_group,e.line_type,!0)})}},{key:"make_new_axis_anim_lines",value:function(t,e,i,a,s,n,r){var o=void 0,_=void 0,l=a.length-i.length;if(l>0)o=e.slice(0,t.length),_=a.slice(0,i.length);else{var h=new Array(Math.abs(l)).fill("");_=a.concat(h);var u=new Array(Math.abs(l)).fill(s);o=e.concat(u)}if(_.map(function(e,i){n(e,t[i],o[i],i,r)}),l>0){var c=a.slice(i.length),p=e.slice(t.length);c.map(function(t,e){n(t,s,p[e],e,r)})}}},{key:"make_x_line",value:function(e,i,a,s,n,r){var o=1.5*this.avg_unit_width;if(this.get_strwidth(a)>o){var _=o/8;a=a.slice(0,_-3)+" ..."}var l=t.createSVG("line",{x1:0,x2:0,y1:0,y2:e}),h=t.createSVG("text",{className:s,x:0,y:i,dy:".71em",innerHTML:a}),u=t.createSVG("g",{className:"tick "+n,transform:"translate("+r+", 0)"});return u.appendChild(l),u.appendChild(h),u}},{key:"make_y_line",value:function(e,i,a,s,n,r,o){var _=arguments.length>7&&void 0!==arguments[7]&&arguments[7],l=arguments.length>8&&void 0!==arguments[8]?arguments[8]:"",h=t.createSVG("line",{className:"dashed"===l?"dashed":"",x1:e,x2:i,y1:0,y2:0}),u=t.createSVG("text",{className:n,x:a,y:0,dy:".32em",innerHTML:s+""}),c=t.createSVG("g",{className:"tick "+r,transform:"translate(0, "+o+")"});return _&&(h.style.stroke="rgba(27, 31, 35, 0.6)"),c.appendChild(h),c.appendChild(u),c}},{key:"add_and_animate_y_line",value:function(t,e,i,a,s,n){var r=arguments.length>6&&void 0!==arguments[6]&&arguments[6],o=this.get_y_axis_line_props(r),l=_(o,4),h=l[0],u=l[1],c=l[2],p=l[3],d=r?"specific-value":"y-value-text";t=r?(t+"").toUpperCase():t;var v=this.make_y_line(p,h,u,t,d,c,e,0===t&&0!==a,n);s.appendChild(v),this.elements_to_animate&&this.elements_to_animate.push([{unit:v,array:[0],index:0},{transform:"0, "+i},250,"easein","translate",{transform:"0, "+e}])}},{key:"get_y_axis_points",value:function(t){var e=this,i=void 0,a=void 0,s=void 0,n=void 0,r=parseInt(Math.max.apply(Math,l(t))),o=parseInt(Math.min.apply(Math,l(t)));o>=0&&(o=0);var h=function(t,i){var a=void 0,s=void 0,n=void 0,r=void 0,o=void 0;if((t+"").length<=1)a=10,n=5;else{var l=e.calc_upper_bound_and_no_of_parts(t),h=_(l,2);a=h[0],n=h[1]}return o=a/n,r=e.calc_no_of_parts(i,o),s=r*o,[a,s,n,r,o]},u=-1*o;if(u<=r){var c=h(r,u),p=_(c,5);i=p[1],a=p[2],s=p[3],n=p[4],0===u&&(i=0,s=0)}else{var d=h(u,r),v=_(d,5);i=v[0],s=v[2],a=v[3],n=v[4]}a%2!=0&&s>0&&a++,s%2!=0&&(s++,i+=n);var f=a+s;return f>5&&(f/=2,n*=2),this.get_intervals(-1*i,n,f)}},{key:"get_intervals",value:function(t,e,i){for(var a=[],s=0;s<=i;s++)a.push(t),t+=e;return a}},{key:"calc_upper_bound_and_no_of_parts",value:function(t){var e=Math.pow(10,(t+"").length-1),i=this.calc_no_of_parts(t,e);return[e*i,i]}},{key:"calc_no_of_parts",value:function(t,e){var i=Math.ceil(t/e);return i%2!=0&&i++,i}},{key:"get_optimal_no_of_parts",value:function(t){return t<5?t:t/2}},{key:"set_avg_unit_width_and_x_offset",value:function(){this.avg_unit_width=this.width/(this.x.length-1),this.x_offset=0}},{key:"get_all_y_values",value:function(){var t=[];return this.y.map(function(e){t=t.concat(e.values)}),t.concat(this.specific_values.map(function(t){return t.value}))}},{key:"calc_y_dependencies",value:function(){var t=this;this.y_min_tops=new Array(this.x_axis_positions.length).fill(9999),this.y.map(function(i){i.y_tops=i.values.map(function(i){return e(t.zero_line-i*t.multiplier)}),i.y_tops.map(function(e,i){e0}),i=e;if(e.length>this.max_slices){e.sort(function(t,e){return e[0]-t[0]}),i=e.slice(0,this.max_slices-1);var a=0;e.slice(this.max_slices-1).map(function(t){a+=t[0]}),i.push([a,"Rest"]),this.colors[this.max_slices-1]="grey"}this.labels=[],i.map(function(e){t.slice_totals.push(e[0]),t.labels.push(e[1])}),this.legend_totals=this.slice_totals.slice(0,this.max_legend_points)}},{key:"setup_utils",value:function(){}},{key:"make_graph_components",value:function(){var e=this;this.grand_total=this.slice_totals.reduce(function(t,e){return t+e},0),this.slices=[],this.slice_totals.map(function(i,a){var s=t.create("div",{className:"progress-bar background "+e.colors[a],style:"width: "+100*i/e.grand_total+"%",inside:e.percentage_bar});e.slices.push(s)})}},{key:"bind_tooltip",value:function(){var e=this;this.slices.map(function(i,a){i.addEventListener("mouseenter",function(){var s=t.offset(e.chart_wrapper),n=t.offset(i),r=n.left-s.left+i.offsetWidth/2,o=n.top-s.top-6,_=(e.formatted_labels&&e.formatted_labels.length>0?e.formatted_labels[a]:e.labels[a])+": ",l=(100*e.slice_totals[a]/e.grand_total).toFixed(1);e.tip.set_values(r,o,_,l+"%"),e.tip.show_tip()})})}},{key:"show_summary",value:function(){var e=this,i=this.formatted_labels&&this.formatted_labels.length>0?this.formatted_labels:this.labels;this.legend_totals.map(function(a,s){a&&(t.create("div",{className:"stats",inside:e.stats_wrapper}).innerHTML='\n\t\t\t\t\t'+i[s]+":\n\t\t\t\t\t"+a+"\n\t\t\t\t")})}}]),i}(),f=function(e){function i(t){var e=t.start,s=void 0===e?"":e,n=t.domain,r=void 0===n?"":n,_=t.subdomain,l=void 0===_?"":_,h=t.data,u=void 0===h?{}:h,c=t.discrete_domains,p=void 0===c?0:c,d=t.count_label,v=void 0===d?"":d;a(this,i);var f=o(this,(i.__proto__||Object.getPrototypeOf(i)).call(this,arguments[0]));f.type="heatmap",f.domain=r,f.subdomain=l,f.data=u,f.discrete_domains=p,f.count_label=v;var y=new Date;return f.start=s||f.add_days(y,365),f.legend_colors=["#ebedf0","#c6e48b","#7bc96f","#239a3b","#196127"],f.translate_x=0,f.setup(),f}return r(i,u),s(i,[{key:"setup_base_values",value:function(){this.today=new Date,this.start||(this.start=new Date,this.start.setFullYear(this.start.getFullYear()-1)),this.first_week_start=new Date(this.start.toDateString()),this.last_week_start=new Date(this.today.toDateString()),7!==this.first_week_start.getDay()&&this.add_days(this.first_week_start,-1*this.first_week_start.getDay()),7!==this.last_week_start.getDay()&&this.add_days(this.last_week_start,-1*this.last_week_start.getDay()),this.no_of_cols=this.get_weeks_between(this.first_week_start+"",this.last_week_start+"")+1}},{key:"set_width",value:function(){this.base_width=12*this.no_of_cols,this.discrete_domains&&(this.base_width+=144)}},{key:"setup_components",value:function(){this.domain_label_group=t.createSVG("g",{className:"domain-label-group chart-label",inside:this.draw_area}),this.data_groups=t.createSVG("g",{className:"data-groups",inside:this.draw_area,transform:"translate(0, 20)"})}},{key:"setup_values",value:function(){this.domain_label_group.textContent="",this.data_groups.textContent="",this.distribution=this.get_distribution(this.data,this.legend_colors),this.month_names=["January","February","March","April","May","June","July","August","September","October","November","December"],this.render_all_weeks_and_store_x_values(this.no_of_cols)}},{key:"render_all_weeks_and_store_x_values",value:function(t){var e=new Date(this.first_week_start);this.week_col=0,this.current_month=e.getMonth(),this.months=[this.current_month+""],this.month_weeks={},this.month_start_points=[],this.month_weeks[this.current_month]=0,this.month_start_points.push(13);for(var i=0;i0&&void 0!==arguments[0]?arguments[0]:{},e=arguments[1],i=Object.keys(t).map(function(e){return t[e]}),a=Math.max.apply(Math,l(i)),s=1/(e.length-1),n=[];return e.map(function(t,e){var i=a*(s*e);n.push(i)}),n}},{key:"get_max_checkpoint",value:function(t,e){return e.filter(function(i,a){return 1===a?e[0]9?"":"0")+e,(i>9?"":"0")+i,t.getFullYear()].join("-")}},{key:"get_weeks_between",value:function(t,e){return Math.ceil(this.get_days_between(t,e)/7)}},{key:"get_days_between",value:function(t,e){return(this.treat_as_utc(e)-this.treat_as_utc(t))/864e5}},{key:"add_days",value:function(t,e){t.setDate(t.getDate()+e)}},{key:"get_month_name",value:function(){}}]),i}();return function t(e){return a(this,t),"line"===e.type?new d(arguments[0]):"bar"===e.type?new p(arguments[0]):"percentage"===e.type?new v(arguments[0]):"heatmap"===e.type?new f(arguments[0]):new d(arguments[0])}}(); +//# sourceMappingURL=frappe-charts.min.js.map diff --git a/dist/frappe-charts.min.js.map b/dist/frappe-charts.min.js.map new file mode 100644 index 0000000..115e7d5 --- /dev/null +++ b/dist/frappe-charts.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"frappe-charts.min.js","sources":["../src/scripts/helpers/dom.js","../src/scripts/helpers/utils.js","../src/scripts/objects/SvgTip.js","../src/scripts/charts/BaseChart.js","../src/scripts/charts/AxisChart.js","../src/scripts/charts/BarChart.js","../src/scripts/charts/LineChart.js","../src/scripts/charts/PercentageChart.js","../src/scripts/charts/Heatmap.js","../src/scripts/charts.js"],"sourcesContent":["export default function $(expr, con) {\n\treturn typeof expr === \"string\"? (con || document).querySelector(expr) : expr || null;\n}\n\n$.findNodeIndex = (node) =>\n{\n\tvar i = 0;\n\twhile (node.previousSibling) {\n\t\tnode = node.previousSibling;\n\t\ti++;\n\t}\n\treturn i;\n};\n\n$.create = (tag, o) => {\n\tvar element = document.createElement(tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\t\t}\n\t\telse if (i in element) {\n\t\t\telement[i] = val;\n\t\t}\n\t\telse {\n\t\t\telement.setAttribute(i, val);\n\t\t}\n\t}\n\n\treturn element;\n};\n\n$.createSVG = (tag, o) => {\n\tvar element = document.createElementNS(\"http://www.w3.org/2000/svg\", tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\t\t}\n\t\telse {\n\t\t\tif(i === \"className\") { i = \"class\"; }\n\t\t\tif(i === \"innerHTML\") {\n\t\t\t\telement['textContent'] = val;\n\t\t\t} else {\n\t\t\t\telement.setAttribute(i, val);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn element;\n};\n\n$.runSVGAnimation = (svg_container, elements) => {\n\t// let parent = elements[0][0]['unit'].parentNode;\n\n\tlet new_elements = [];\n\tlet anim_elements = [];\n\n\telements.map(element => {\n\t\tlet obj = element[0];\n\t\tlet parent = obj.unit.parentNode;\n\t\t// let index = let findNodeIndex(obj.unit);\n\n\t\tlet anim_element, new_element;\n\n\t\telement[0] = obj.unit;\n\n\t\t[anim_element, new_element] = $.animateSVG(...element);\n\n\t\tnew_elements.push(new_element);\n\t\tanim_elements.push([anim_element, parent]);\n\n\t\tparent.replaceChild(anim_element, obj.unit);\n\n\t\tif(obj.array) {\n\t\t\tobj.array[obj.index] = new_element;\n\t\t} else {\n\t\t\tobj.object[obj.key] = new_element;\n\t\t}\n\t});\n\n\tlet anim_svg = svg_container.cloneNode(true);\n\n\tanim_elements.map((anim_element, i) => {\n\t\tanim_element[1].replaceChild(new_elements[i], anim_element[0]);\n\t\telements[i][0] = new_elements[i];\n\t});\n\n\treturn anim_svg;\n};\n\n$.animateSVG = (element, props, dur, easing_type=\"linear\", type=undefined, old_values={}) => {\n\tlet easing = {\n\t\tease: \"0.25 0.1 0.25 1\",\n\t\tlinear: \"0 0 1 1\",\n\t\t// easein: \"0.42 0 1 1\",\n\t\teasein: \"0.1 0.8 0.2 1\",\n\t\teaseout: \"0 0 0.58 1\",\n\t\teaseinout: \"0.42 0 0.58 1\"\n\t};\n\n\tlet anim_element = element.cloneNode(true);\n\tlet new_element = element.cloneNode(true);\n\n\tfor(var attributeName in props) {\n\t\tlet animate_element;\n\t\tif(attributeName === 'transform') {\n\t\t\tanimate_element = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animateTransform\");\n\t\t} else {\n\t\t\tanimate_element = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animate\");\n\t\t}\n\t\tlet current_value = old_values[attributeName] || element.getAttribute(attributeName);\n\t\tlet value = props[attributeName];\n\n\t\tlet anim_attr = {\n\t\t\tattributeName: attributeName,\n\t\t\tfrom: current_value,\n\t\t\tto: value,\n\t\t\tbegin: \"0s\",\n\t\t\tdur: dur/1000 + \"s\",\n\t\t\tvalues: current_value + \";\" + value,\n\t\t\tkeySplines: easing[easing_type],\n\t\t\tkeyTimes: \"0;1\",\n\t\t\tcalcMode: \"spline\",\n\t\t\tfill: 'freeze'\n\t\t};\n\n\t\tif(type) {\n\t\t\tanim_attr[\"type\"] = type;\n\t\t}\n\n\t\tfor (var i in anim_attr) {\n\t\t\tanimate_element.setAttribute(i, anim_attr[i]);\n\t\t}\n\n\t\tanim_element.appendChild(animate_element);\n\n\t\tif(type) {\n\t\t\tnew_element.setAttribute(attributeName, `translate(${value})`);\n\t\t} else {\n\t\t\tnew_element.setAttribute(attributeName, value);\n\t\t}\n\t}\n\n\treturn [anim_element, new_element];\n};\n\n$.offset = (element) => {\n\tlet rect = element.getBoundingClientRect();\n\treturn {\n\t\t// https://stackoverflow.com/a/7436602/6495043\n\t\t// rect.top varies with scroll, so we add whatever has been\n\t\t// scrolled to it to get absolute distance from actual page top\n\t\ttop: rect.top + (document.documentElement.scrollTop || document.body.scrollTop),\n\t\tleft: rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft)\n\t};\n};\n\n$.isElementInViewport = (el) => {\n\t// Although straightforward: https://stackoverflow.com/a/7557433/6495043\n\tvar rect = el.getBoundingClientRect();\n\n\treturn (\n\t\trect.top >= 0 &&\n rect.left >= 0 &&\n rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */\n rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */\n\t);\n};\n\n$.bind = (element, o) => {\n\tif (element) {\n\t\tfor (var event in o) {\n\t\t\tvar callback = o[event];\n\n\t\t\tevent.split(/\\s+/).forEach(function (event) {\n\t\t\t\telement.addEventListener(event, callback);\n\t\t\t});\n\t\t}\n\t}\n};\n\n$.unbind = (element, o) => {\n\tif (element) {\n\t\tfor (var event in o) {\n\t\t\tvar callback = o[event];\n\n\t\t\tevent.split(/\\s+/).forEach(function(event) {\n\t\t\t\telement.removeEventListener(event, callback);\n\t\t\t});\n\t\t}\n\t}\n};\n\n$.fire = (target, type, properties) => {\n\tvar evt = document.createEvent(\"HTMLEvents\");\n\n\tevt.initEvent(type, true, true );\n\n\tfor (var j in properties) {\n\t\tevt[j] = properties[j];\n\t}\n\n\treturn target.dispatchEvent(evt);\n};\n","export function float_2(d) {\n\treturn parseFloat(d.toFixed(2));\n}\n\nexport function arrays_equal(arr1, arr2) {\n\tif(arr1.length !== arr2.length) return false;\n\tlet are_equal = true;\n\tarr1.map((d, i) => {\n\t\tif(arr2[i] !== d) are_equal = false;\n\t});\n\treturn are_equal;\n}\n\nexport function shuffle(array) {\n\t// https://stackoverflow.com/a/2450976/6495043\n\t// Awesomeness: https://bost.ocks.org/mike/shuffle/\n\n\tvar currentIndex = array.length, temporaryValue, randomIndex;\n\n\t// While there remain elements to shuffle...\n\twhile (0 !== currentIndex) {\n\n\t\t// Pick a remaining element...\n\t\trandomIndex = Math.floor(Math.random() * currentIndex);\n\t\tcurrentIndex -= 1;\n\n\t\t// And swap it with the current element.\n\t\ttemporaryValue = array[currentIndex];\n\t\tarray[currentIndex] = array[randomIndex];\n\t\tarray[randomIndex] = temporaryValue;\n\t}\n\n\treturn array;\n}\n","import $ from '../helpers/dom';\n\nexport default class SvgTip {\n\tconstructor({\n\t\tparent = null\n\t}) {\n\t\tthis.parent = parent;\n\t\tthis.title_name = '';\n\t\tthis.title_value = '';\n\t\tthis.list_values = [];\n\t\tthis.title_value_first = 0;\n\n\t\tthis.x = 0;\n\t\tthis.y = 0;\n\n\t\tthis.top = 0;\n\t\tthis.left = 0;\n\n\t\tthis.setup();\n\t}\n\n\tsetup() {\n\t\tthis.make_tooltip();\n\t}\n\n\trefresh() {\n\t\tthis.fill();\n\t\tthis.calc_position();\n\t\t// this.show_tip();\n\t}\n\n\tmake_tooltip() {\n\t\tthis.container = $.create('div', {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'graph-svg-tip comparison',\n\t\t\tinnerHTML: `\n\t\t\t\t
    \n\t\t\t\t
    `\n\t\t});\n\t\tthis.hide_tip();\n\n\t\tthis.title = this.container.querySelector('.title');\n\t\tthis.data_point_list = this.container.querySelector('.data-point-list');\n\n\t\tthis.parent.addEventListener('mouseleave', () => {\n\t\t\tthis.hide_tip();\n\t\t});\n\t}\n\n\tfill() {\n\t\tlet title;\n\t\tif(this.title_value_first) {\n\t\t\ttitle = `${this.title_value}${this.title_name}`;\n\t\t} else {\n\t\t\ttitle = `${this.title_name}${this.title_value}`;\n\t\t}\n\t\tthis.title.innerHTML = title;\n\t\tthis.data_point_list.innerHTML = '';\n\n\t\tthis.list_values.map((set) => {\n\t\t\tlet li = $.create('li', {\n\t\t\t\tclassName: `border-top ${set.color || 'black'}`,\n\t\t\t\tinnerHTML: `${set.value ? set.value : '' }\n\t\t\t\t\t${set.title ? set.title : '' }`\n\t\t\t});\n\n\t\t\tthis.data_point_list.appendChild(li);\n\t\t});\n\t}\n\n\tcalc_position() {\n\t\tthis.top = this.y - this.container.offsetHeight;\n\t\tthis.left = this.x - this.container.offsetWidth/2;\n\t\tlet max_left = this.parent.offsetWidth - this.container.offsetWidth;\n\n\t\tlet pointer = this.container.querySelector('.svg-pointer');\n\n\t\tif(this.left < 0) {\n\t\t\tpointer.style.left = `calc(50% - ${-1 * this.left}px)`;\n\t\t\tthis.left = 0;\n\t\t} else if(this.left > max_left) {\n\t\t\tlet delta = this.left - max_left;\n\t\t\tpointer.style.left = `calc(50% + ${delta}px)`;\n\t\t\tthis.left = max_left;\n\t\t} else {\n\t\t\tpointer.style.left = `50%`;\n\t\t}\n\t}\n\n\tset_values(x, y, title_name = '', title_value = '', list_values = [], title_value_first = 0) {\n\t\tthis.title_name = title_name;\n\t\tthis.title_value = title_value;\n\t\tthis.list_values = list_values;\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.title_value_first = title_value_first;\n\t\tthis.refresh();\n\t}\n\n\thide_tip() {\n\t\tthis.container.style.top = '0px';\n\t\tthis.container.style.left = '0px';\n\t\tthis.container.style.opacity = '0';\n\t}\n\n\tshow_tip() {\n\t\tthis.container.style.top = this.top + 'px';\n\t\tthis.container.style.left = this.left + 'px';\n\t\tthis.container.style.opacity = '1';\n\t}\n}\n","import SvgTip from '../objects/SvgTip';\nimport $ from '../helpers/dom';\n\nexport default class BaseChart {\n\tconstructor({\n\t\tparent = \"\",\n\t\theight = 240,\n\n\t\ttitle = '', subtitle = '',\n\n\t\tdata = {},\n\t\tformat_lambdas = {},\n\n\t\tsummary = [],\n\n\t\tis_navigable = 0,\n\n\t\ttype = '' // eslint-disable-line no-unused-vars\n\t}) {\n\t\tthis.raw_chart_args = arguments[0];\n\n\t\tthis.parent = document.querySelector(parent);\n\t\tthis.title = title;\n\t\tthis.subtitle = subtitle;\n\n\t\tthis.data = data;\n\t\tthis.format_lambdas = format_lambdas;\n\n\t\tthis.specific_values = data.specific_values || [];\n\t\tthis.summary = summary;\n\n\t\tthis.is_navigable = is_navigable;\n\t\tif(this.is_navigable) {\n\t\t\tthis.current_index = 0;\n\t\t}\n\n\t\tthis.chart_types = ['line', 'bar', 'percentage', 'heatmap'];\n\n\t\tthis.set_margins(height);\n\t}\n\n\tget_different_chart(type) {\n\t\tif(!this.chart_types.includes(type)) {\n\t\t\tconsole.error(`'${type}' is not a valid chart type.`);\n\t\t}\n\t\tif(type === this.type) return;\n\n\t\t// Only across compatible types\n\t\tlet compatible_types = {\n\t\t\tbar: ['line', 'percentage'],\n\t\t\tline: ['bar', 'percentage'],\n\t\t\tpercentage: ['bar', 'line'],\n\t\t\theatmap: []\n\t\t};\n\n\t\tif(!compatible_types[this.type].includes(type)) {\n\t\t\tconsole.error(`'${this.type}' chart cannot be converted to a '${type}' chart.`);\n\t\t}\n\n\t\t// Okay, this is anticlimactic\n\t\t// this function will need to actually be 'change_chart_type(type)'\n\t\t// that will update only the required elements, but for now ...\n\t\treturn new BaseChart({\n\t\t\tparent: this.raw_chart_args.parent,\n\t\t\tdata: this.raw_chart_args.data,\n\t\t\ttype: type,\n\t\t\theight: this.raw_chart_args.height\n\t\t});\n\t}\n\n\tset_margins(height) {\n\t\tthis.base_height = height;\n\t\tthis.height = height - 40;\n\t\tthis.translate_x = 60;\n\t\tthis.translate_y = 10;\n\t}\n\n\tsetup() {\n\t\tthis.bind_window_events();\n\t\tthis.refresh(true);\n\t}\n\n\tbind_window_events() {\n\t\twindow.addEventListener('resize', () => this.refresh());\n\t\twindow.addEventListener('orientationchange', () => this.refresh());\n\t}\n\n\trefresh(init=false) {\n\t\tthis.setup_base_values();\n\t\tthis.set_width();\n\n\t\tthis.setup_container();\n\t\tthis.setup_components();\n\n\t\tthis.setup_values();\n\t\tthis.setup_utils();\n\n\t\tthis.make_graph_components(init);\n\t\tthis.make_tooltip();\n\n\t\tif(this.summary.length > 0) {\n\t\t\tthis.show_custom_summary();\n\t\t} else {\n\t\t\tthis.show_summary();\n\t\t}\n\n\t\tif(this.is_navigable) {\n\t\t\tthis.setup_navigation(init);\n\t\t}\n\t}\n\n\tset_width() {\n\t\tlet special_values_width = 0;\n\t\tthis.specific_values.map(val => {\n\t\t\tif(this.get_strwidth(val.title) > special_values_width) {\n\t\t\t\tspecial_values_width = this.get_strwidth(val.title) - 40;\n\t\t\t}\n\t\t});\n\t\tthis.base_width = this.parent.offsetWidth - special_values_width;\n\t\tthis.width = this.base_width - this.translate_x * 2;\n\t}\n\n\tsetup_base_values() {}\n\n\tsetup_container() {\n\t\tthis.container = $.create('div', {\n\t\t\tclassName: 'chart-container',\n\t\t\tinnerHTML: `
    ${this.title}
    \n\t\t\t\t
    ${this.subtitle}
    \n\t\t\t\t
    \n\t\t\t\t
    `\n\t\t});\n\n\t\t// Chart needs a dedicated parent element\n\t\tthis.parent.innerHTML = '';\n\t\tthis.parent.appendChild(this.container);\n\n\t\tthis.chart_wrapper = this.container.querySelector('.frappe-chart');\n\t\tthis.stats_wrapper = this.container.querySelector('.graph-stats-container');\n\n\t\tthis.make_chart_area();\n\t\tthis.make_draw_area();\n\t}\n\n\tmake_chart_area() {\n\t\tthis.svg = $.createSVG('svg', {\n\t\t\tclassName: 'chart',\n\t\t\tinside: this.chart_wrapper,\n\t\t\twidth: this.base_width,\n\t\t\theight: this.base_height\n\t\t});\n\n\t\tthis.svg_defs = $.createSVG('defs', {\n\t\t\tinside: this.svg,\n\t\t});\n\n\t\treturn this.svg;\n\t}\n\n\tmake_draw_area() {\n\t\tthis.draw_area = $.createSVG(\"g\", {\n\t\t\tclassName: this.type + '-chart',\n\t\t\tinside: this.svg,\n\t\t\ttransform: `translate(${this.translate_x}, ${this.translate_y})`\n\t\t});\n\t}\n\n\tsetup_components() { }\n\n\tmake_tooltip() {\n\t\tthis.tip = new SvgTip({\n\t\t\tparent: this.chart_wrapper,\n\t\t});\n\t\tthis.bind_tooltip();\n\t}\n\n\n\tshow_summary() {}\n\tshow_custom_summary() {\n\t\tthis.summary.map(d => {\n\t\t\tlet stats = $.create('div', {\n\t\t\t\tclassName: 'stats',\n\t\t\t\tinnerHTML: `${d.title}: ${d.value}`\n\t\t\t});\n\t\t\tthis.stats_wrapper.appendChild(stats);\n\t\t});\n\t}\n\n\tsetup_navigation(init=false) {\n\t\tthis.make_overlay();\n\n\t\tif(init) {\n\t\t\tthis.bind_overlay();\n\n\t\t\tdocument.addEventListener('keydown', (e) => {\n\t\t\t\tif($.isElementInViewport(this.chart_wrapper)) {\n\t\t\t\t\te = e || window.event;\n\n\t\t\t\t\tif (e.keyCode == '37') {\n\t\t\t\t\t\tthis.on_left_arrow();\n\t\t\t\t\t} else if (e.keyCode == '39') {\n\t\t\t\t\t\tthis.on_right_arrow();\n\t\t\t\t\t} else if (e.keyCode == '38') {\n\t\t\t\t\t\tthis.on_up_arrow();\n\t\t\t\t\t} else if (e.keyCode == '40') {\n\t\t\t\t\t\tthis.on_down_arrow();\n\t\t\t\t\t} else if (e.keyCode == '13') {\n\t\t\t\t\t\tthis.on_enter_key();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tmake_overlay() {}\n\tbind_overlay() {}\n\n\ton_left_arrow() {}\n\ton_right_arrow() {}\n\ton_up_arrow() {}\n\ton_down_arrow() {}\n\ton_enter_key() {}\n\n\tget_data_point(index=this.current_index) {\n\t\t// check for length\n\t\tlet data_point = {\n\t\t\tindex: index\n\t\t};\n\t\tlet y = this.y[0];\n\t\t['svg_units', 'y_tops', 'values'].map(key => {\n\t\t\tlet data_key = key.slice(0, key.length-1);\n\t\t\tdata_point[data_key] = y[key][index];\n\t\t});\n\t\tdata_point.label = this.x[index];\n\t\treturn data_point;\n\t}\n\n\tupdate_current_data_point(index) {\n\t\tif(index < 0) index = 0;\n\t\tif(index >= this.x.length) index = this.x.length - 1;\n\t\tif(index === this.current_index) return;\n\t\tthis.current_index = index;\n\t\t$.fire(this.parent, \"data-select\", this.get_data_point());\n\t}\n\n\t// Helpers\n\tget_strwidth(string) {\n\t\treturn string.length * 8;\n\t}\n\n\t// Objects\n\tsetup_utils() { }\n}\n","import $ from '../helpers/dom';\nimport { float_2, arrays_equal } from '../helpers/utils';\nimport BaseChart from './BaseChart';\n\nexport default class AxisChart extends BaseChart {\n\tconstructor(args) {\n\t\tsuper(args);\n\n\t\tthis.x = this.data.labels;\n\t\tthis.y = this.data.datasets;\n\n\t\tthis.get_y_label = this.format_lambdas.y_label;\n\t\tthis.get_y_tooltip = this.format_lambdas.y_tooltip;\n\t\tthis.get_x_tooltip = this.format_lambdas.x_tooltip;\n\n\t\tthis.colors = ['green', 'blue', 'violet', 'red', 'orange',\n\t\t\t'yellow', 'light-blue', 'light-green', 'purple', 'magenta'];\n\n\t\tthis.zero_line = this.height;\n\t}\n\n\tsetup_values() {\n\t\tthis.data.datasets.map(d => {\n\t\t\td.values = d.values.map(val => (!isNaN(val) ? val : 0));\n\t\t});\n\t\tthis.setup_x();\n\t\tthis.setup_y();\n\t}\n\n\tsetup_x() {\n\t\tthis.set_avg_unit_width_and_x_offset();\n\n\t\tif(this.x_axis_positions) {\n\t\t\tthis.x_old_axis_positions = this.x_axis_positions.slice();\n\t\t}\n\t\tthis.x_axis_positions = this.x.map((d, i) =>\n\t\t\tfloat_2(this.x_offset + i * this.avg_unit_width));\n\n\t\tif(!this.x_old_axis_positions) {\n\t\t\tthis.x_old_axis_positions = this.x_axis_positions.slice();\n\t\t}\n\t}\n\n\tsetup_y() {\n\t\tif(this.y_axis_values) {\n\t\t\tthis.y_old_axis_values = this.y_axis_values.slice();\n\t\t}\n\n\t\tlet values = this.get_all_y_values();\n\n\t\tif(this.y_sums && this.y_sums.length > 0) {\n\t\t\tvalues = values.concat(this.y_sums);\n\t\t}\n\n\t\tthis.y_axis_values = this.get_y_axis_points(values);\n\n\t\tif(!this.y_old_axis_values) {\n\t\t\tthis.y_old_axis_values = this.y_axis_values.slice();\n\t\t}\n\n\t\tconst y_pts = this.y_axis_values;\n\t\tconst value_range = y_pts[y_pts.length-1] - y_pts[0];\n\n\t\tif(this.multiplier) this.old_multiplier = this.multiplier;\n\t\tthis.multiplier = this.height / value_range;\n\t\tif(!this.old_multiplier) this.old_multiplier = this.multiplier;\n\n\t\tconst zero_index = y_pts.indexOf(0);\n\t\tconst interval = y_pts[1] - y_pts[0];\n\t\tconst interval_height = interval * this.multiplier;\n\n\t\tif(this.zero_line) this.old_zero_line = this.zero_line;\n\t\tthis.zero_line = this.height - (zero_index * interval_height);\n\t\tif(!this.old_zero_line) this.old_zero_line = this.zero_line;\n\t}\n\n\tsetup_components() {\n\t\tsuper.setup_components();\n\t\tthis.setup_marker_components();\n\t\tthis.setup_aggregation_components();\n\t\tthis.setup_graph_components();\n\t}\n\n\tsetup_marker_components() {\n\t\tthis.y_axis_group = $.createSVG('g', {className: 'y axis', inside: this.draw_area});\n\t\tthis.x_axis_group = $.createSVG('g', {className: 'x axis', inside: this.draw_area});\n\t\tthis.specific_y_group = $.createSVG('g', {className: 'specific axis', inside: this.draw_area});\n\t}\n\n\tsetup_aggregation_components() {\n\t\tthis.sum_group = $.createSVG('g', {className: 'data-points', inside: this.draw_area});\n\t\tthis.average_group = $.createSVG('g', {className: 'chart-area', inside: this.draw_area});\n\t}\n\n\tsetup_graph_components() {\n\t\tthis.svg_units_groups = [];\n\t\tthis.y.map((d, i) => {\n\t\t\tthis.svg_units_groups[i] = $.createSVG('g', {\n\t\t\t\tclassName: 'data-points data-points-' + i,\n\t\t\t\tinside: this.draw_area\n\t\t\t});\n\t\t});\n\t}\n\n\tmake_graph_components(init=false) {\n\t\tthis.make_y_axis();\n\t\tthis.make_x_axis();\n\t\tthis.draw_graph(init);\n\t\tthis.make_y_specifics();\n\t}\n\n\t// make VERTICAL lines for x values\n\tmake_x_axis(animate=false) {\n\t\tlet start_at, height, text_start_at, axis_line_class = '';\n\t\tif(this.x_axis_mode === 'span') {\t\t// long spanning lines\n\t\t\tstart_at = -7;\n\t\t\theight = this.height + 15;\n\t\t\ttext_start_at = this.height + 25;\n\t\t} else if(this.x_axis_mode === 'tick'){\t// short label lines\n\t\t\tstart_at = this.height;\n\t\t\theight = 6;\n\t\t\ttext_start_at = 9;\n\t\t\taxis_line_class = 'x-axis-label';\n\t\t}\n\n\t\tthis.x_axis_group.setAttribute('transform', `translate(0,${start_at})`);\n\n\t\tif(animate) {\n\t\t\tthis.make_anim_x_axis(height, text_start_at, axis_line_class);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.x_axis_group.textContent = '';\n\t\tthis.x.map((point, i) => {\n\t\t\tthis.x_axis_group.appendChild(\n\t\t\t\tthis.make_x_line(\n\t\t\t\t\theight,\n\t\t\t\t\ttext_start_at,\n\t\t\t\t\tpoint,\n\t\t\t\t\t'x-value-text',\n\t\t\t\t\taxis_line_class,\n\t\t\t\t\tthis.x_axis_positions[i]\n\t\t\t\t)\n\t\t\t);\n\t\t});\n\t}\n\n\t// make HORIZONTAL lines for y values\n\tmake_y_axis(animate=false) {\n\t\tif(animate) {\n\t\t\tthis.make_anim_y_axis();\n\t\t\tthis.make_anim_y_specifics();\n\t\t\treturn;\n\t\t}\n\n\t\tlet [width, text_end_at, axis_line_class, start_at] = this.get_y_axis_line_props();\n\n\t\tthis.y_axis_group.textContent = '';\n\t\tthis.y_axis_values.map((value, i) => {\n\t\t\tthis.y_axis_group.appendChild(\n\t\t\t\tthis.make_y_line(\n\t\t\t\t\tstart_at,\n\t\t\t\t\twidth,\n\t\t\t\t\ttext_end_at,\n\t\t\t\t\tvalue,\n\t\t\t\t\t'y-value-text',\n\t\t\t\t\taxis_line_class,\n\t\t\t\t\tthis.zero_line - value * this.multiplier,\n\t\t\t\t\t(value === 0 && i !== 0) // Non-first Zero line\n\t\t\t\t)\n\t\t\t);\n\t\t});\n\t}\n\n\tget_y_axis_line_props(specific=false) {\n\t\tif(specific) {\n\t\t\treturn[this.width, this.width + 5, 'specific-value', 0];\n\t\t}\n\t\tlet width, text_end_at = -9, axis_line_class = '', start_at = 0;\n\t\tif(this.y_axis_mode === 'span') {\t\t// long spanning lines\n\t\t\twidth = this.width + 6;\n\t\t\tstart_at = -6;\n\t\t} else if(this.y_axis_mode === 'tick'){\t// short label lines\n\t\t\twidth = -6;\n\t\t\taxis_line_class = 'y-axis-label';\n\t\t}\n\n\t\treturn [width, text_end_at, axis_line_class, start_at];\n\t}\n\n\tdraw_graph(init=false) {\n\t\tif(init) {\n\t\t\tthis.draw_new_graph_and_animate();\n\t\t\treturn;\n\t\t}\n\t\tthis.y.map((d, i) => {\n\t\t\td.svg_units = [];\n\t\t\tthis.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);\n\t\t\tthis.make_new_units(d, i);\n\t\t});\n\t}\n\n\tdraw_new_graph_and_animate() {\n\t\tlet data = [];\n\t\tthis.y.map((d, i) => {\n\t\t\t// Anim: Don't draw initial values, store them and update later\n\t\t\td.y_tops = new Array(d.values.length).fill(this.zero_line); // no value\n\t\t\tdata.push({values: d.values});\n\t\t\td.svg_units = [];\n\n\t\t\tthis.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);\n\t\t\tthis.make_new_units(d, i);\n\t\t});\n\n\t\tsetTimeout(() => {\n\t\t\tthis.update_values(data);\n\t\t}, 350);\n\t}\n\n\tsetup_navigation(init) {\n\t\t// Hack: defer nav till initial update_values\n\t\tsetTimeout(() => {\n\t\t\tsuper.setup_navigation(init);\n\t\t}, 500);\n\t}\n\n\tmake_new_units(d, i) {\n\t\tthis.make_new_units_for_dataset(\n\t\t\tthis.x_axis_positions,\n\t\t\td.y_tops,\n\t\t\td.color || this.colors[i],\n\t\t\ti,\n\t\t\tthis.y.length\n\t\t);\n\t}\n\n\tmake_new_units_for_dataset(x_values, y_values, color, dataset_index, no_of_datasets, group, array, unit) {\n\t\tif(!group) group = this.svg_units_groups[dataset_index];\n\t\tif(!array) array = this.y[dataset_index].svg_units;\n\t\tif(!unit) unit = this.unit_args;\n\n\t\tgroup.textContent = '';\n\t\tarray.length = 0;\n\n\t\ty_values.map((y, i) => {\n\t\t\tlet data_unit = this.draw[unit.type](\n\t\t\t\tx_values[i],\n\t\t\t\ty,\n\t\t\t\tunit.args,\n\t\t\t\tcolor,\n\t\t\t\tdataset_index,\n\t\t\t\tno_of_datasets\n\t\t\t);\n\t\t\tgroup.appendChild(data_unit);\n\t\t\tarray.push(data_unit);\n\t\t});\n\t}\n\n\tmake_y_specifics() {\n\t\tthis.specific_y_group.textContent = '';\n\t\tthis.specific_values.map(d => {\n\t\t\tthis.specific_y_group.appendChild(\n\t\t\t\tthis.make_y_line(\n\t\t\t\t\t0,\n\t\t\t\t\tthis.width,\n\t\t\t\t\tthis.width + 5,\n\t\t\t\t\td.title.toUpperCase(),\n\t\t\t\t\t'specific-value',\n\t\t\t\t\t'specific-value',\n\t\t\t\t\tthis.zero_line - d.value * this.multiplier,\n\t\t\t\t\tfalse,\n\t\t\t\t\td.line_type\n\t\t\t\t)\n\t\t\t);\n\t\t});\n\t}\n\n\tbind_tooltip() {\n\t\t// TODO: could be in tooltip itself, as it is a given functionality for its parent\n\t\tthis.chart_wrapper.addEventListener('mousemove', (e) => {\n\t\t\tlet offset = $.offset(this.chart_wrapper);\n\t\t\tlet relX = e.pageX - offset.left - this.translate_x;\n\t\t\tlet relY = e.pageY - offset.top - this.translate_y;\n\n\t\t\tif(relY < this.height + this.translate_y * 2) {\n\t\t\t\tthis.map_tooltip_x_position_and_show(relX);\n\t\t\t} else {\n\t\t\t\tthis.tip.hide_tip();\n\t\t\t}\n\t\t});\n\t}\n\n\tmap_tooltip_x_position_and_show(relX) {\n\t\tfor(var i=this.x_axis_positions.length - 1; i >= 0 ; i--) {\n\t\t\tlet x_val = this.x_axis_positions[i];\n\t\t\t// let delta = i === 0 ? this.avg_unit_width : x_val - this.x_axis_positions[i-1];\n\t\t\tif(relX > x_val - this.avg_unit_width/2) {\n\t\t\t\tlet x = x_val + this.translate_x;\n\t\t\t\tlet y = this.y_min_tops[i] + this.translate_y;\n\n\t\t\t\tlet title = this.x.formatted && this.x.formatted.length>0\n\t\t\t\t\t? this.x.formatted[i] : this.x[i];\n\t\t\t\tlet values = this.y.map((set, j) => {\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttitle: set.title,\n\t\t\t\t\t\tvalue: set.formatted ? set.formatted[i] : set.values[i],\n\t\t\t\t\t\tcolor: set.color || this.colors[j],\n\t\t\t\t\t};\n\t\t\t\t});\n\n\t\t\t\t// TODO: upside-down tooltips for negative values?\n\t\t\t\tthis.tip.set_values(x, y, title, '', values);\n\t\t\t\tthis.tip.show_tip();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// API\n\tshow_sums() {\n\t\tthis.updating = true;\n\n\t\tthis.y_sums = new Array(this.x_axis_positions.length).fill(0);\n\t\tthis.y.map(d => {\n\t\t\td.values.map( (value, i) => {\n\t\t\t\tthis.y_sums[i] += value;\n\t\t\t});\n\t\t});\n\n\t\t// Remake y axis, animate\n\t\tthis.update_values();\n\n\t\t// Then make sum units, don't animate\n\t\tthis.sum_units = [];\n\n\t\tthis.make_new_units_for_dataset(\n\t\t\tthis.x_axis_positions,\n\t\t\tthis.y_sums.map( val => float_2(this.zero_line - val * this.multiplier)),\n\t\t\t'light-grey',\n\t\t\t0,\n\t\t\t1,\n\t\t\tthis.sum_group,\n\t\t\tthis.sum_units\n\t\t);\n\n\t\t// this.make_path && this.make_path(d, i, old_x, old_y, d.color || this.colors[i]);\n\n\t\tthis.updating = false;\n\t}\n\n\thide_sums() {\n\t\tif(this.updating) return;\n\t\tthis.y_sums = [];\n\t\tthis.sum_group.textContent = '';\n\t\tthis.sum_units = [];\n\t\tthis.update_values();\n\t}\n\n\tshow_average() {\n\t\tthis.old_specific_values = this.specific_values.slice();\n\t\tthis.y.map((d, i) => {\n\t\t\tlet sum = 0;\n\t\t\td.values.map(e => {sum+=e;});\n\t\t\tlet average = sum/d.values.length;\n\n\t\t\tthis.specific_values.push({\n\t\t\t\ttitle: \"AVG\" + \" \" + (i+1),\n\t\t\t\tline_type: \"dashed\",\n\t\t\t\tvalue: average,\n\t\t\t\tauto: 1\n\t\t\t});\n\t\t});\n\n\t\tthis.update_values();\n\t}\n\n\thide_average() {\n\t\tthis.old_specific_values = this.specific_values.slice();\n\n\t\tlet indices_to_remove = [];\n\t\tthis.specific_values.map((d, i) => {\n\t\t\tif(d.auto) indices_to_remove.unshift(i);\n\t\t});\n\n\t\tindices_to_remove.map(index => {\n\t\t\tthis.specific_values.splice(index, 1);\n\t\t});\n\n\t\tthis.update_values();\n\t}\n\n\tupdate_values(new_y, new_x) {\n\t\tif(!new_x) {\n\t\t\tnew_x = this.x;\n\t\t}\n\t\tthis.elements_to_animate = [];\n\t\tthis.updating = true;\n\n\t\tthis.old_x_values = this.x.slice();\n\t\tthis.old_y_axis_tops = this.y.map(d => d.y_tops.slice());\n\n\t\tthis.old_y_values = this.y.map(d => d.values);\n\n\t\tthis.no_of_extra_pts = new_x.length - this.x.length;\n\n\t\t// Just update values prop, setup_x/y() will do the rest\n\t\tif(new_y) this.y.map((d, i) => {d.values = new_y[i].values;});\n\t\tif(new_x) this.x = new_x;\n\n\t\tthis.setup_x();\n\t\tthis.setup_y();\n\n\t\t// Animate only if positions have changed\n\t\tif(!arrays_equal(this.x_old_axis_positions, this.x_axis_positions)) {\n\t\t\tthis.make_x_axis(true);\n\t\t\tsetTimeout(() => {\n\t\t\t\tif(!this.updating) this.make_x_axis();\n\t\t\t}, 300);\n\t\t}\n\n\t\tif(!arrays_equal(this.y_old_axis_values, this.y_axis_values) ||\n\t\t\t(this.old_specific_values &&\n\t\t\t!arrays_equal(this.old_specific_values, this.specific_values))) {\n\n\t\t\tthis.make_y_axis(true);\n\t\t\tsetTimeout(() => {\n\t\t\t\tif(!this.updating) {\n\t\t\t\t\tthis.make_y_axis();\n\t\t\t\t\tthis.make_y_specifics();\n\t\t\t\t}\n\t\t\t}, 300);\n\t\t}\n\n\t\t// Change in data, so calculate dependencies\n\t\tthis.calc_y_dependencies();\n\n\t\tthis.animate_graphs();\n\n\t\t// Trigger animation with the animatable elements in this.elements_to_animate\n\t\tthis.run_animation();\n\n\t\tthis.updating = false;\n\t}\n\n\tadd_data_point(y_point, x_point, index=this.x.length) {\n\t\tlet new_y = this.y.map(data_set => { return {values:data_set.values}; });\n\t\tnew_y.map((d, i) => { d.values.splice(index, 0, y_point[i]); });\n\t\tlet new_x = this.x.slice();\n\t\tnew_x.splice(index, 0, x_point);\n\n\t\tthis.update_values(new_y, new_x);\n\t}\n\n\tremove_data_point(index = this.x.length-1) {\n\t\tif(this.x.length < 3) return;\n\n\t\tlet new_y = this.y.map(data_set => { return {values:data_set.values}; });\n\t\tnew_y.map((d) => { d.values.splice(index, 1); });\n\t\tlet new_x = this.x.slice();\n\t\tnew_x.splice(index, 1);\n\n\t\tthis.update_values(new_y, new_x);\n\t}\n\n\trun_animation() {\n\t\tlet anim_svg = $.runSVGAnimation(this.svg, this.elements_to_animate);\n\n\t\tif(this.svg.parentNode == this.chart_wrapper) {\n\t\t\tthis.chart_wrapper.removeChild(this.svg);\n\t\t\tthis.chart_wrapper.appendChild(anim_svg);\n\n\t\t}\n\n\t\t// Replace the new svg (data has long been replaced)\n\t\tsetTimeout(() => {\n\t\t\tif(anim_svg.parentNode == this.chart_wrapper) {\n\t\t\t\tthis.chart_wrapper.removeChild(anim_svg);\n\t\t\t\tthis.chart_wrapper.appendChild(this.svg);\n\t\t\t}\n\t\t}, 200);\n\t}\n\n\tanimate_graphs() {\n\t\tthis.y.map((d, i) => {\n\t\t\t// Pre-prep, equilize no of positions between old and new\n\t\t\tlet [old_x, old_y, new_x, new_y] = this.calc_old_and_new_postions(d, i);\n\t\t\tif(this.no_of_extra_pts >= 0) {\n\t\t\t\tthis.make_path && this.make_path(d, i, old_x, old_y, d.color || this.colors[i]);\n\t\t\t\tthis.make_new_units_for_dataset(old_x, old_y, d.color || this.colors[i], i, this.y.length);\n\t\t\t}\n\t\t\td.path && this.animate_path(d, i, old_x, old_y, new_x, new_y);\n\t\t\tthis.animate_units(d, i, old_x, old_y, new_x, new_y);\n\t\t});\n\n\t\t// TODO: replace with real units\n\t\tsetTimeout(() => {\n\t\t\tthis.y.map((d, i) => {\n\t\t\t\tthis.make_path && this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);\n\t\t\t\tthis.make_new_units(d, i);\n\t\t\t});\n\t\t}, 300);\n\t}\n\n\tanimate_path(d, i, old_x, old_y, new_x, new_y) {\n\t\t// Animate path\n\t\tconst new_points_list = new_y.map((y, i) => (new_x[i] + ',' + y));\n\t\tconst new_path_str = new_points_list.join(\"L\");\n\n\t\tconst path_args = [{unit: d.path, object: d, key: 'path'}, {d:\"M\"+new_path_str}, 250, \"easein\"];\n\t\tthis.elements_to_animate.push(path_args);\n\n\t\t// Animate region\n\t\tif(d.region_path) {\n\t\t\tlet reg_start_pt = `0,${this.zero_line}L`;\n\t\t\tlet reg_end_pt = `L${this.width},${this.zero_line}`;\n\n\t\t\tconst region_args = [\n\t\t\t\t{unit: d.region_path, object: d, key: 'region_path'},\n\t\t\t\t{d:\"M\" + reg_start_pt + new_path_str + reg_end_pt},\n\t\t\t\t250,\n\t\t\t\t\"easein\"\n\t\t\t];\n\t\t\tthis.elements_to_animate.push(region_args);\n\t\t}\n\t}\n\n\tanimate_units(d, index, old_x, old_y, new_x, new_y) {\n\t\tlet type = this.unit_args.type;\n\n\t\td.svg_units.map((unit, i) => {\n\t\t\tthis.elements_to_animate.push(this.animate[type](\n\t\t\t\t{unit:unit, array:d.svg_units, index: i}, // unit, with info to replace where it came from in the data\n\t\t\t\tnew_x[i],\n\t\t\t\tnew_y[i],\n\t\t\t\tindex\n\t\t\t));\n\t\t});\n\t}\n\n\tcalc_old_and_new_postions(d, i) {\n\t\tlet old_x = this.x_old_axis_positions.slice();\n\t\tlet new_x = this.x_axis_positions.slice();\n\n\t\tlet old_y = this.old_y_axis_tops[i].slice();\n\t\tlet new_y = d.y_tops.slice();\n\n\t\tconst last_old_x_pos = old_x[old_x.length - 1];\n\t\tconst last_old_y_pos = old_y[old_y.length - 1];\n\n\t\tconst last_new_x_pos = new_x[new_x.length - 1];\n\t\tconst last_new_y_pos = new_y[new_y.length - 1];\n\n\t\tif(this.no_of_extra_pts >= 0) {\n\t\t\t// First substitute current path with a squiggled one (looking the same but\n\t\t\t// having more points at end),\n\t\t\t// then animate to stretch it later to new points\n\t\t\t// (new points already have more points)\n\n\t\t\t// Hence, the extra end points will correspond to current(old) positions\n\t\t\tlet filler_x = new Array(Math.abs(this.no_of_extra_pts)).fill(last_old_x_pos);\n\t\t\tlet filler_y = new Array(Math.abs(this.no_of_extra_pts)).fill(last_old_y_pos);\n\n\t\t\told_x = old_x.concat(filler_x);\n\t\t\told_y = old_y.concat(filler_y);\n\n\t\t} else {\n\t\t\t// Just modify the new points to have extra points\n\t\t\t// with the same position at end\n\t\t\tlet filler_x = new Array(Math.abs(this.no_of_extra_pts)).fill(last_new_x_pos);\n\t\t\tlet filler_y = new Array(Math.abs(this.no_of_extra_pts)).fill(last_new_y_pos);\n\n\t\t\tnew_x = new_x.concat(filler_x);\n\t\t\tnew_y = new_y.concat(filler_y);\n\t\t}\n\n\t\treturn [old_x, old_y, new_x, new_y];\n\t}\n\n\tmake_anim_x_axis(height, text_start_at, axis_line_class) {\n\t\t// Animate X AXIS to account for more or less axis lines\n\n\t\tconst old_pos = this.x_old_axis_positions;\n\t\tconst new_pos = this.x_axis_positions;\n\n\t\tconst old_vals = this.old_x_values;\n\t\tconst new_vals = this.x;\n\n\t\tconst last_line_pos = old_pos[old_pos.length - 1];\n\n\t\tlet add_and_animate_line = (value, old_pos, new_pos) => {\n\t\t\tconst x_line = this.make_x_line(\n\t\t\t\theight,\n\t\t\t\ttext_start_at,\n\t\t\t\tvalue, // new value\n\t\t\t\t'x-value-text',\n\t\t\t\taxis_line_class,\n\t\t\t\told_pos // old position\n\t\t\t);\n\t\t\tthis.x_axis_group.appendChild(x_line);\n\n\t\t\tthis.elements_to_animate && this.elements_to_animate.push([\n\t\t\t\t{unit: x_line, array: [0], index: 0},\n\t\t\t\t{transform: `${ new_pos }, 0`},\n\t\t\t\t250,\n\t\t\t\t\"easein\",\n\t\t\t\t\"translate\",\n\t\t\t\t{transform: `${ old_pos }, 0`}\n\t\t\t]);\n\t\t};\n\n\t\tthis.x_axis_group.textContent = '';\n\n\t\tthis.make_new_axis_anim_lines(\n\t\t\told_pos,\n\t\t\tnew_pos,\n\t\t\told_vals,\n\t\t\tnew_vals,\n\t\t\tlast_line_pos,\n\t\t\tadd_and_animate_line\n\t\t);\n\t}\n\n\tmake_anim_y_axis() {\n\t\t// Animate Y AXIS to account for more or less axis lines\n\n\t\tconst old_pos = this.y_old_axis_values.map(value =>\n\t\t\tthis.zero_line - value * this.multiplier);\n\t\tconst new_pos = this.y_axis_values.map(value =>\n\t\t\tthis.zero_line - value * this.multiplier);\n\n\t\tconst old_vals = this.y_old_axis_values;\n\t\tconst new_vals = this.y_axis_values;\n\n\t\tconst last_line_pos = old_pos[old_pos.length - 1];\n\n\t\tthis.y_axis_group.textContent = '';\n\n\t\tthis.make_new_axis_anim_lines(\n\t\t\told_pos,\n\t\t\tnew_pos,\n\t\t\told_vals,\n\t\t\tnew_vals,\n\t\t\tlast_line_pos,\n\t\t\tthis.add_and_animate_y_line.bind(this),\n\t\t\tthis.y_axis_group\n\t\t);\n\t}\n\n\tmake_anim_y_specifics() {\n\t\tthis.specific_y_group.textContent = '';\n\t\tthis.specific_values.map((d) => {\n\t\t\tthis.add_and_animate_y_line(\n\t\t\t\td.title,\n\t\t\t\tthis.old_zero_line - d.value * this.old_multiplier,\n\t\t\t\tthis.zero_line - d.value * this.multiplier,\n\t\t\t\t0,\n\t\t\t\tthis.specific_y_group,\n\t\t\t\td.line_type,\n\t\t\t\ttrue\n\t\t\t);\n\t\t});\n\t}\n\n\tmake_new_axis_anim_lines(old_pos, new_pos, old_vals, new_vals, last_line_pos, add_and_animate_line, group) {\n\t\tlet superimposed_positions, superimposed_values;\n\t\tlet no_of_extras = new_vals.length - old_vals.length;\n\t\tif(no_of_extras > 0) {\n\t\t\t// More axis are needed\n\t\t\t// First make only the superimposed (same position) ones\n\t\t\t// Add in the extras at the end later\n\t\t\tsuperimposed_positions = new_pos.slice(0, old_pos.length);\n\t\t\tsuperimposed_values = new_vals.slice(0, old_vals.length);\n\t\t} else {\n\t\t\t// Axis have to be reduced\n\t\t\t// Fake it by moving all current extra axis to the last position\n\t\t\t// You'll need filler positions and values in the new arrays\n\t\t\tconst filler_vals = new Array(Math.abs(no_of_extras)).fill(\"\");\n\t\t\tsuperimposed_values = new_vals.concat(filler_vals);\n\n\t\t\tconst filler_pos = new Array(Math.abs(no_of_extras)).fill(last_line_pos);\n\t\t\tsuperimposed_positions = new_pos.concat(filler_pos);\n\t\t}\n\n\t\tsuperimposed_values.map((value, i) => {\n\t\t\tadd_and_animate_line(value, old_pos[i], superimposed_positions[i], i, group);\n\t\t});\n\n\t\tif(no_of_extras > 0) {\n\t\t\t// Add in extra axis in the end\n\t\t\t// and then animate to new positions\n\t\t\tconst extra_values = new_vals.slice(old_vals.length);\n\t\t\tconst extra_positions = new_pos.slice(old_pos.length);\n\n\t\t\textra_values.map((value, i) => {\n\t\t\t\tadd_and_animate_line(value, last_line_pos, extra_positions[i], i, group);\n\t\t\t});\n\t\t}\n\t}\n\n\tmake_x_line(height, text_start_at, point, label_class, axis_line_class, x_pos) {\n\t\tlet allowed_space = this.avg_unit_width * 1.5;\n\n\t\tif(this.get_strwidth(point) > allowed_space) {\n\t\t\tlet allowed_letters = allowed_space / 8;\n\t\t\tpoint = point.slice(0, allowed_letters-3) + \" ...\";\n\t\t}\n\n\t\tlet line = $.createSVG('line', {\n\t\t\tx1: 0,\n\t\t\tx2: 0,\n\t\t\ty1: 0,\n\t\t\ty2: height\n\t\t});\n\n\t\tlet text = $.createSVG('text', {\n\t\t\tclassName: label_class,\n\t\t\tx: 0,\n\t\t\ty: text_start_at,\n\t\t\tdy: '.71em',\n\t\t\tinnerHTML: point\n\t\t});\n\n\t\tlet x_level = $.createSVG('g', {\n\t\t\tclassName: `tick ${axis_line_class}`,\n\t\t\ttransform: `translate(${ x_pos }, 0)`\n\t\t});\n\n\t\tx_level.appendChild(line);\n\t\tx_level.appendChild(text);\n\n\t\treturn x_level;\n\t}\n\n\tmake_y_line(start_at, width, text_end_at, point, label_class, axis_line_class, y_pos, darker=false, line_type=\"\") {\n\t\tlet line = $.createSVG('line', {\n\t\t\tclassName: line_type === \"dashed\" ? \"dashed\": \"\",\n\t\t\tx1: start_at,\n\t\t\tx2: width,\n\t\t\ty1: 0,\n\t\t\ty2: 0\n\t\t});\n\n\t\tlet text = $.createSVG('text', {\n\t\t\tclassName: label_class,\n\t\t\tx: text_end_at,\n\t\t\ty: 0,\n\t\t\tdy: '.32em',\n\t\t\tinnerHTML: point+\"\"\n\t\t});\n\n\t\tlet y_level = $.createSVG('g', {\n\t\t\tclassName: `tick ${axis_line_class}`,\n\t\t\ttransform: `translate(0, ${y_pos})`\n\t\t});\n\n\t\tif(darker) {\n\t\t\tline.style.stroke = \"rgba(27, 31, 35, 0.6)\";\n\t\t}\n\n\t\ty_level.appendChild(line);\n\t\ty_level.appendChild(text);\n\n\t\treturn y_level;\n\t}\n\n\tadd_and_animate_y_line(value, old_pos, new_pos, i, group, type, specific=false) {\n\t\tlet [width, text_end_at, axis_line_class, start_at] = this.get_y_axis_line_props(specific);\n\t\tlet axis_label_class = !specific ? 'y-value-text' : 'specific-value';\n\t\tvalue = !specific ? value : (value+\"\").toUpperCase();\n\t\tconst y_line = this.make_y_line(\n\t\t\tstart_at,\n\t\t\twidth,\n\t\t\ttext_end_at,\n\t\t\tvalue,\n\t\t\taxis_label_class,\n\t\t\taxis_line_class,\n\t\t\told_pos, // old position\n\t\t\t(value === 0 && i !== 0), // Non-first Zero line\n\t\t\ttype\n\t\t);\n\n\t\tgroup.appendChild(y_line);\n\n\t\tthis.elements_to_animate && this.elements_to_animate.push([\n\t\t\t{unit: y_line, array: [0], index: 0},\n\t\t\t{transform: `0, ${ new_pos }`},\n\t\t\t250,\n\t\t\t\"easein\",\n\t\t\t\"translate\",\n\t\t\t{transform: `0, ${ old_pos }`}\n\t\t]);\n\t}\n\n\tget_y_axis_points(array) {\n\t\t//*** Where the magic happens ***\n\n\t\t// Calculates best-fit y intervals from given values\n\t\t// and returns the interval array\n\n\t\t// TODO: Fractions\n\n\t\tlet max_bound, min_bound, pos_no_of_parts, neg_no_of_parts, part_size; // eslint-disable-line no-unused-vars\n\n\t\t// Critical values\n\t\tlet max_val = parseInt(Math.max(...array));\n\t\tlet min_val = parseInt(Math.min(...array));\n\t\tif(min_val >= 0) {\n\t\t\tmin_val = 0;\n\t\t}\n\n\t\tlet get_params = (value1, value2) => {\n\t\t\tlet bound1, bound2, no_of_parts_1, no_of_parts_2, interval_size;\n\t\t\tif((value1+\"\").length <= 1) {\n\t\t\t\t[bound1, no_of_parts_1] = [10, 5];\n\t\t\t} else {\n\t\t\t\t[bound1, no_of_parts_1] = this.calc_upper_bound_and_no_of_parts(value1);\n\t\t\t}\n\n\t\t\tinterval_size = bound1 / no_of_parts_1;\n\t\t\tno_of_parts_2 = this.calc_no_of_parts(value2, interval_size);\n\t\t\tbound2 = no_of_parts_2 * interval_size;\n\n\t\t\treturn [bound1, bound2, no_of_parts_1, no_of_parts_2, interval_size];\n\t\t};\n\n\t\tconst abs_min_val = min_val * -1;\n\t\tif(abs_min_val <= max_val) {\n\t\t\t// Get the positive region intervals\n\t\t\t// then calc negative ones accordingly\n\t\t\t[max_bound, min_bound, pos_no_of_parts, neg_no_of_parts, part_size]\n\t\t\t\t= get_params(max_val, abs_min_val);\n\t\t\tif(abs_min_val === 0) {\n\t\t\t\tmin_bound = 0; neg_no_of_parts = 0;\n\t\t\t}\n\t\t} else {\n\t\t\t// Get the negative region here first\n\t\t\t[min_bound, max_bound, neg_no_of_parts, pos_no_of_parts, part_size]\n\t\t\t\t= get_params(abs_min_val, max_val);\n\t\t}\n\n\t\t// Make both region parts even\n\t\tif(pos_no_of_parts % 2 !== 0 && neg_no_of_parts > 0) pos_no_of_parts++;\n\t\tif(neg_no_of_parts % 2 !== 0) {\n\t\t\t// every increase in no_of_parts entails an increase in corresponding bound\n\t\t\t// except here, it happens implicitly after every calc_no_of_parts() call\n\t\t\tneg_no_of_parts++;\n\t\t\tmin_bound += part_size;\n\t\t}\n\n\t\tlet no_of_parts = pos_no_of_parts + neg_no_of_parts;\n\t\tif(no_of_parts > 5) {\n\t\t\tno_of_parts /= 2;\n\t\t\tpart_size *= 2;\n\t\t}\n\n\t\treturn this.get_intervals(\n\t\t\t(-1) * min_bound,\n\t\t\tpart_size,\n\t\t\tno_of_parts\n\t\t);\n\t}\n\n\tget_intervals(start, interval_size, count) {\n\t\tlet intervals = [];\n\t\tfor(var i = 0; i <= count; i++){\n\t\t\tintervals.push(start);\n\t\t\tstart += interval_size;\n\t\t}\n\t\treturn intervals;\n\t}\n\n\tcalc_upper_bound_and_no_of_parts(max_val) {\n\t\t// Given a positive value, calculates a nice-number upper bound\n\t\t// and a consequent optimal number of parts\n\n\t\tconst part_size = Math.pow(10, ((max_val+\"\").length - 1));\n\t\tconst no_of_parts = this.calc_no_of_parts(max_val, part_size);\n\n\t\t// Use it to get a nice even upper bound\n\t\tconst upper_bound = part_size * no_of_parts;\n\n\t\treturn [upper_bound, no_of_parts];\n\t}\n\n\tcalc_no_of_parts(value, divisor) {\n\t\t// value should be a positive number, divisor should be greater than 0\n\t\t// returns an even no of parts\n\t\tlet no_of_parts = Math.ceil(value / divisor);\n\t\tif(no_of_parts % 2 !== 0) no_of_parts++; // Make it an even number\n\n\t\treturn no_of_parts;\n\t}\n\n\tget_optimal_no_of_parts(no_of_parts) {\n\t\t// aka Divide by 2 if too large\n\t\treturn (no_of_parts < 5) ? no_of_parts : no_of_parts / 2;\n\t}\n\n\tset_avg_unit_width_and_x_offset() {\n\t\t// Set the ... you get it\n\t\tthis.avg_unit_width = this.width/(this.x.length - 1);\n\t\tthis.x_offset = 0;\n\t}\n\n\tget_all_y_values() {\n\t\tlet all_values = [];\n\n\t\t// Add in all the y values in the datasets\n\t\tthis.y.map(d => {\n\t\t\tall_values = all_values.concat(d.values);\n\t\t});\n\n\t\t// Add in all the specific values\n\t\treturn all_values.concat(this.specific_values.map(d => d.value));\n\t}\n\n\tcalc_y_dependencies() {\n\t\tthis.y_min_tops = new Array(this.x_axis_positions.length).fill(9999);\n\t\tthis.y.map(d => {\n\t\t\td.y_tops = d.values.map( val => float_2(this.zero_line - val * this.multiplier));\n\t\t\td.y_tops.map( (y_top, i) => {\n\t\t\t\tif(y_top < this.y_min_tops[i]) {\n\t\t\t\t\tthis.y_min_tops[i] = y_top;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tget_bar_height_and_y_attr(y_top) {\n\t\tlet height, y;\n\t\tif (y_top <= this.zero_line) {\n\t\t\theight = this.zero_line - y_top;\n\t\t\ty = y_top;\n\n\t\t\t// In case of invisible bars\n\t\t\tif(height === 0) {\n\t\t\t\theight = this.height * 0.01;\n\t\t\t\ty -= height;\n\t\t\t}\n\t\t} else {\n\t\t\theight = y_top - this.zero_line;\n\t\t\ty = this.zero_line;\n\n\t\t\t// In case of invisible bars\n\t\t\tif(height === 0) {\n\t\t\t\theight = this.height * 0.01;\n\t\t\t}\n\t\t}\n\n\t\treturn [height, y];\n\t}\n\n\tsetup_utils() {\n\t\tthis.draw = {\n\t\t\t'bar': (x, y_top, args, color, index, no_of_datasets) => {\n\t\t\t\tlet total_width = this.avg_unit_width - args.space_width;\n\t\t\t\tlet start_x = x - total_width/2;\n\n\t\t\t\tlet width = total_width / no_of_datasets;\n\t\t\t\tlet current_x = start_x + width * index;\n\n\t\t\t\tlet [height, y] = this.get_bar_height_and_y_attr(y_top);\n\n\t\t\t\treturn $.createSVG('rect', {\n\t\t\t\t\tclassName: `bar mini fill ${color}`,\n\t\t\t\t\tx: current_x,\n\t\t\t\t\ty: y,\n\t\t\t\t\twidth: width,\n\t\t\t\t\theight: height\n\t\t\t\t});\n\n\t\t\t},\n\t\t\t'dot': (x, y, args, color) => {\n\t\t\t\treturn $.createSVG('circle', {\n\t\t\t\t\tclassName: `fill ${color}`,\n\t\t\t\t\tcx: x,\n\t\t\t\t\tcy: y,\n\t\t\t\t\tr: args.radius\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\n\t\tthis.animate = {\n\t\t\t'bar': (bar_obj, x, y_top, index) => {\n\t\t\t\tlet start = x - this.avg_unit_width/4;\n\t\t\t\tlet width = (this.avg_unit_width/2)/this.y.length;\n\t\t\t\tlet [height, y] = this.get_bar_height_and_y_attr(y_top);\n\n\t\t\t\tx = start + (width * index);\n\n\t\t\t\treturn [bar_obj, {width: width, height: height, x: x, y: y}, 250, \"easein\"];\n\t\t\t\t// bar.animate({height: args.new_height, y: y_top}, 250, mina.easein);\n\t\t\t},\n\t\t\t'dot': (dot_obj, x, y_top) => {\n\t\t\t\treturn [dot_obj, {cx: x, cy: y_top}, 300, \"easein\"];\n\t\t\t\t// dot.animate({cy: y_top}, 250, mina.easein);\n\t\t\t}\n\t\t};\n\t}\n}\n","import AxisChart from './AxisChart';\n\nexport default class BarChart extends AxisChart {\n\tconstructor(args) {\n\t\tsuper(args);\n\n\t\tthis.type = 'bar';\n\t\tthis.x_axis_mode = args.x_axis_mode || 'tick';\n\t\tthis.y_axis_mode = args.y_axis_mode || 'span';\n\t\tthis.setup();\n\t}\n\n\tsetup_values() {\n\t\tsuper.setup_values();\n\t\tthis.x_offset = this.avg_unit_width;\n\t\tthis.unit_args = {\n\t\t\ttype: 'bar',\n\t\t\targs: {\n\t\t\t\tspace_width: this.avg_unit_width/2,\n\t\t\t}\n\t\t};\n\t}\n\n\tmake_overlay() {\n\t\t// Just make one out of the first element\n\t\tlet index = this.x.length - 1;\n\t\tlet unit = this.y[0].svg_units[index];\n\t\tthis.update_current_data_point(index);\n\n\t\tif(this.overlay) {\n\t\t\tthis.overlay.parentNode.removeChild(this.overlay);\n\t\t}\n\n\t\tthis.overlay = unit.cloneNode();\n\t\tthis.overlay.style.fill = '#000000';\n\t\tthis.overlay.style.opacity = '0.4';\n\t\tthis.draw_area.appendChild(this.overlay);\n\t}\n\n\tbind_overlay() {\n\t\t// on event, update overlay\n\t\tthis.parent.addEventListener('data-select', (e) => {\n\t\t\tthis.update_overlay(e.svg_unit);\n\t\t});\n\t}\n\n\tupdate_overlay(unit) {\n\t\tlet attributes = [];\n\t\tObject.keys(unit.attributes).map(index => {\n\t\t\tattributes.push(unit.attributes[index]);\n\t\t});\n\n\t\tattributes.filter(attr => attr.specified).map(attr => {\n\t\t\tthis.overlay.setAttribute(attr.name, attr.nodeValue);\n\t\t});\n\t}\n\n\ton_left_arrow() {\n\t\tthis.update_current_data_point(this.current_index - 1);\n\t}\n\n\ton_right_arrow() {\n\t\tthis.update_current_data_point(this.current_index + 1);\n\t}\n\n\tset_avg_unit_width_and_x_offset() {\n\t\tthis.avg_unit_width = this.width/(this.x.length + 1);\n\t\tthis.x_offset = this.avg_unit_width;\n\t}\n}\n","import AxisChart from './AxisChart';\nimport $ from '../helpers/dom';\n\nexport default class LineChart extends AxisChart {\n\tconstructor(args) {\n\t\tsuper(args);\n\t\tif(Object.getPrototypeOf(this) !== LineChart.prototype) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.type = 'line';\n\t\tthis.region_fill = args.region_fill;\n\t\tthis.x_axis_mode = args.x_axis_mode || 'span';\n\t\tthis.y_axis_mode = args.y_axis_mode || 'span';\n\n\t\tthis.setup();\n\t}\n\n\tsetup_graph_components() {\n\t\tthis.setup_path_groups();\n\t\tsuper.setup_graph_components();\n\t}\n\n\tsetup_path_groups() {\n\t\tthis.paths_groups = [];\n\t\tthis.y.map((d, i) => {\n\t\t\tthis.paths_groups[i] = $.createSVG('g', {\n\t\t\t\tclassName: 'path-group path-group-' + i,\n\t\t\t\tinside: this.draw_area\n\t\t\t});\n\t\t});\n\t}\n\n\tsetup_values() {\n\t\tsuper.setup_values();\n\t\tthis.unit_args = {\n\t\t\ttype: 'dot',\n\t\t\targs: { radius: 8 }\n\t\t};\n\t}\n\n\tmake_paths() {\n\t\tthis.y.map((d, i) => {\n\t\t\tthis.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]);\n\t\t});\n\t}\n\n\tmake_path(d, i, x_positions, y_positions, color) {\n\t\tlet points_list = y_positions.map((y, i) => (x_positions[i] + ',' + y));\n\t\tlet points_str = points_list.join(\"L\");\n\n\t\tthis.paths_groups[i].textContent = '';\n\n\t\td.path = $.createSVG('path', {\n\t\t\tinside: this.paths_groups[i],\n\t\t\tclassName: `stroke ${color}`,\n\t\t\td: \"M\"+points_str\n\t\t});\n\n\t\tif(this.region_fill) {\n\t\t\tlet gradient_id ='path-fill-gradient' + '-' + color;\n\n\t\t\tthis.gradient_def = $.createSVG('linearGradient', {\n\t\t\t\tinside: this.svg_defs,\n\t\t\t\tid: gradient_id,\n\t\t\t\tx1: 0,\n\t\t\t\tx2: 0,\n\t\t\t\ty1: 0,\n\t\t\t\ty2: 1\n\t\t\t});\n\n\t\t\tlet set_gradient_stop = (grad_elem, offset, color, opacity) => {\n\t\t\t\t$.createSVG('stop', {\n\t\t\t\t\t'className': 'stop-color ' + color,\n\t\t\t\t\t'inside': grad_elem,\n\t\t\t\t\t'offset': offset,\n\t\t\t\t\t'stop-opacity': opacity\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tset_gradient_stop(this.gradient_def, \"0%\", color, 0.4);\n\t\t\tset_gradient_stop(this.gradient_def, \"50%\", color, 0.2);\n\t\t\tset_gradient_stop(this.gradient_def, \"100%\", color, 0);\n\n\t\t\td.region_path = $.createSVG('path', {\n\t\t\t\tinside: this.paths_groups[i],\n\t\t\t\tclassName: `region-fill`,\n\t\t\t\td: \"M\" + `0,${this.zero_line}L` + points_str + `L${this.width},${this.zero_line}`,\n\t\t\t});\n\n\t\t\td.region_path.style.stroke = \"none\";\n\t\t\td.region_path.style.fill = `url(#${gradient_id})`;\n\t\t}\n\t}\n}\n","import BaseChart from './BaseChart';\nimport $ from '../helpers/dom';\n\nexport default class PercentageChart extends BaseChart {\n\tconstructor(args) {\n\t\tsuper(args);\n\t\tthis.type = 'percentage';\n\n\t\tthis.get_y_label = this.format_lambdas.y_label;\n\t\tthis.get_x_tooltip = this.format_lambdas.x_tooltip;\n\t\tthis.get_y_tooltip = this.format_lambdas.y_tooltip;\n\n\t\tthis.max_slices = 10;\n\t\tthis.max_legend_points = 6;\n\n\t\tthis.colors = args.colors;\n\n\t\tif(!this.colors || this.colors.length < this.data.labels.length) {\n\t\t\tthis.colors = ['light-blue', 'blue', 'violet', 'red', 'orange',\n\t\t\t\t'yellow', 'green', 'light-green', 'purple', 'magenta'];\n\t\t}\n\n\t\tthis.setup();\n\t}\n\n\tmake_chart_area() {\n\t\tthis.chart_wrapper.className += ' ' + 'graph-focus-margin';\n\t\tthis.chart_wrapper.style.marginTop = '45px';\n\n\t\tthis.stats_wrapper.className += ' ' + 'graph-focus-margin';\n\t\tthis.stats_wrapper.style.marginBottom = '30px';\n\t\tthis.stats_wrapper.style.paddingTop = '0px';\n\t}\n\n\tmake_draw_area() {\n\t\tthis.chart_div = $.create('div', {\n\t\t\tclassName: 'div',\n\t\t\tinside: this.chart_wrapper,\n\t\t\twidth: this.base_width,\n\t\t\theight: this.base_height\n\t\t});\n\n\t\tthis.chart = $.create('div', {\n\t\t\tclassName: 'progress-chart',\n\t\t\tinside: this.chart_div\n\t\t});\n\t}\n\n\tsetup_components() {\n\t\tthis.percentage_bar = $.create('div', {\n\t\t\tclassName: 'progress',\n\t\t\tinside: this.chart\n\t\t});\n\t}\n\n\tsetup_values() {\n\t\tthis.slice_totals = [];\n\t\tlet all_totals = this.data.labels.map((d, i) => {\n\t\t\tlet total = 0;\n\t\t\tthis.data.datasets.map(e => {\n\t\t\t\ttotal += e.values[i];\n\t\t\t});\n\t\t\treturn [total, d];\n\t\t}).filter(d => { return d[0] > 0; }); // keep only positive results\n\n\t\tlet totals = all_totals;\n\n\t\tif(all_totals.length > this.max_slices) {\n\t\t\tall_totals.sort((a, b) => { return b[0] - a[0]; });\n\n\t\t\ttotals = all_totals.slice(0, this.max_slices-1);\n\t\t\tlet others = all_totals.slice(this.max_slices-1);\n\n\t\t\tlet sum_of_others = 0;\n\t\t\tothers.map(d => {sum_of_others += d[0];});\n\n\t\t\ttotals.push([sum_of_others, 'Rest']);\n\n\t\t\tthis.colors[this.max_slices-1] = 'grey';\n\t\t}\n\n\t\tthis.labels = [];\n\t\ttotals.map(d => {\n\t\t\tthis.slice_totals.push(d[0]);\n\t\t\tthis.labels.push(d[1]);\n\t\t});\n\n\t\tthis.legend_totals = this.slice_totals.slice(0, this.max_legend_points);\n\t}\n\n\tsetup_utils() { }\n\n\tmake_graph_components() {\n\t\tthis.grand_total = this.slice_totals.reduce((a, b) => a + b, 0);\n\t\tthis.slices = [];\n\t\tthis.slice_totals.map((total, i) => {\n\t\t\tlet slice = $.create('div', {\n\t\t\t\tclassName: `progress-bar background ${this.colors[i]}`,\n\t\t\t\tstyle: `width: ${total*100/this.grand_total}%`,\n\t\t\t\tinside: this.percentage_bar\n\t\t\t});\n\t\t\tthis.slices.push(slice);\n\t\t});\n\t}\n\n\tbind_tooltip() {\n\t\tthis.slices.map((slice, i) => {\n\t\t\tslice.addEventListener('mouseenter', () => {\n\t\t\t\tlet g_off = $.offset(this.chart_wrapper), p_off = $.offset(slice);\n\n\t\t\t\tlet x = p_off.left - g_off.left + slice.offsetWidth/2;\n\t\t\t\tlet y = p_off.top - g_off.top - 6;\n\t\t\t\tlet title = (this.formatted_labels && this.formatted_labels.length>0\n\t\t\t\t\t? this.formatted_labels[i] : this.labels[i]) + ': ';\n\t\t\t\tlet percent = (this.slice_totals[i]*100/this.grand_total).toFixed(1);\n\n\t\t\t\tthis.tip.set_values(x, y, title, percent + \"%\");\n\t\t\t\tthis.tip.show_tip();\n\t\t\t});\n\t\t});\n\t}\n\n\tshow_summary() {\n\t\tlet x_values = this.formatted_labels && this.formatted_labels.length > 0\n\t\t\t? this.formatted_labels : this.labels;\n\t\tthis.legend_totals.map((d, i) => {\n\t\t\tif(d) {\n\t\t\t\tlet stats = $.create('div', {\n\t\t\t\t\tclassName: 'stats',\n\t\t\t\t\tinside: this.stats_wrapper\n\t\t\t\t});\n\t\t\t\tstats.innerHTML = `\n\t\t\t\t\t${x_values[i]}:\n\t\t\t\t\t${d}\n\t\t\t\t`;\n\t\t\t}\n\t\t});\n\t}\n}\n","import BaseChart from './BaseChart';\nimport $ from '../helpers/dom';\n\nexport default class Heatmap extends BaseChart {\n\tconstructor({\n\t\tstart = '',\n\t\tdomain = '',\n\t\tsubdomain = '',\n\t\tdata = {},\n\t\tdiscrete_domains = 0,\n\t\tcount_label = ''\n\t}) {\n\t\tsuper(arguments[0]);\n\n\t\tthis.type = 'heatmap';\n\n\t\tthis.domain = domain;\n\t\tthis.subdomain = subdomain;\n\t\tthis.data = data;\n\t\tthis.discrete_domains = discrete_domains;\n\t\tthis.count_label = count_label;\n\n\t\tlet today = new Date();\n\t\tthis.start = start || this.add_days(today, 365);\n\n\t\tthis.legend_colors = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];\n\n\t\tthis.translate_x = 0;\n\t\tthis.setup();\n\t}\n\n\tsetup_base_values() {\n\t\tthis.today = new Date();\n\n\t\tif(!this.start) {\n\t\t\tthis.start = new Date();\n\t\t\tthis.start.setFullYear( this.start.getFullYear() - 1 );\n\t\t}\n\t\tthis.first_week_start = new Date(this.start.toDateString());\n\t\tthis.last_week_start = new Date(this.today.toDateString());\n\t\tif(this.first_week_start.getDay() !== 7) {\n\t\t\tthis.add_days(this.first_week_start, (-1) * this.first_week_start.getDay());\n\t\t}\n\t\tif(this.last_week_start.getDay() !== 7) {\n\t\t\tthis.add_days(this.last_week_start, (-1) * this.last_week_start.getDay());\n\t\t}\n\t\tthis.no_of_cols = this.get_weeks_between(this.first_week_start + '', this.last_week_start + '') + 1;\n\t}\n\n\tset_width() {\n\t\tthis.base_width = (this.no_of_cols) * 12;\n\n\t\tif(this.discrete_domains) {\n\t\t\tthis.base_width += (12 * 12);\n\t\t}\n\t}\n\n\tsetup_components() {\n\t\tthis.domain_label_group = $.createSVG(\"g\", {\n\t\t\tclassName: \"domain-label-group chart-label\",\n\t\t\tinside: this.draw_area\n\t\t});\n\t\tthis.data_groups = $.createSVG(\"g\", {\n\t\t\tclassName: \"data-groups\",\n\t\t\tinside: this.draw_area,\n\t\t\ttransform: `translate(0, 20)`\n\t\t});\n\t}\n\n\tsetup_values() {\n\t\tthis.domain_label_group.textContent = '';\n\t\tthis.data_groups.textContent = '';\n\t\tthis.distribution = this.get_distribution(this.data, this.legend_colors);\n\t\tthis.month_names = [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n\t\t\t\"July\", \"August\", \"September\", \"October\", \"November\", \"December\"\n\t\t];\n\n\t\tthis.render_all_weeks_and_store_x_values(this.no_of_cols);\n\t}\n\n\trender_all_weeks_and_store_x_values(no_of_weeks) {\n\t\tlet current_week_sunday = new Date(this.first_week_start);\n\t\tthis.week_col = 0;\n\t\tthis.current_month = current_week_sunday.getMonth();\n\n\t\tthis.months = [this.current_month + ''];\n\t\tthis.month_weeks = {}, this.month_start_points = [];\n\t\tthis.month_weeks[this.current_month] = 0;\n\t\tthis.month_start_points.push(13);\n\n\t\tfor(var i = 0; i < no_of_weeks; i++) {\n\t\t\tlet data_group, month_change = 0;\n\t\t\tlet day = new Date(current_week_sunday);\n\n\t\t\t[data_group, month_change] = this.get_week_squares_group(day, this.week_col);\n\t\t\tthis.data_groups.appendChild(data_group);\n\t\t\tthis.week_col += 1 + parseInt(this.discrete_domains && month_change);\n\t\t\tthis.month_weeks[this.current_month]++;\n\t\t\tif(month_change) {\n\t\t\t\tthis.current_month = (this.current_month + 1) % 12;\n\t\t\t\tthis.months.push(this.current_month + '');\n\t\t\t\tthis.month_weeks[this.current_month] = 1;\n\t\t\t}\n\t\t\tthis.add_days(current_week_sunday, 7);\n\t\t}\n\t\tthis.render_month_labels();\n\t}\n\n\tget_week_squares_group(current_date, index) {\n\t\tconst no_of_weekdays = 7;\n\t\tconst square_side = 10;\n\t\tconst cell_padding = 2;\n\t\tconst step = 1;\n\n\t\tlet month_change = 0;\n\t\tlet week_col_change = 0;\n\n\t\tlet data_group = $.createSVG(\"g\", {\n\t\t\tclassName: \"data-group\",\n\t\t\tinside: this.data_groups\n\t\t});\n\n\t\tfor(var y = 0, i = 0; i < no_of_weekdays; i += step, y += (square_side + cell_padding)) {\n\t\t\tlet data_value = 0;\n\t\t\tlet color_index = 0;\n\n\t\t\tlet timestamp = Math.floor(current_date.getTime()/1000).toFixed(1);\n\n\t\t\tif(this.data[timestamp]) {\n\t\t\t\tdata_value = this.data[timestamp];\n\t\t\t\tcolor_index = this.get_max_checkpoint(data_value, this.distribution);\n\t\t\t}\n\n\t\t\tif(this.data[Math.round(timestamp)]) {\n\t\t\t\tdata_value = this.data[Math.round(timestamp)];\n\t\t\t\tcolor_index = this.get_max_checkpoint(data_value, this.distribution);\n\t\t\t}\n\n\t\t\tlet x = 13 + (index + week_col_change) * 12;\n\n\t\t\t$.createSVG(\"rect\", {\n\t\t\t\tclassName: 'day',\n\t\t\t\tinside: data_group,\n\t\t\t\tx: x,\n\t\t\t\ty: y,\n\t\t\t\twidth: square_side,\n\t\t\t\theight: square_side,\n\t\t\t\tfill: this.legend_colors[color_index],\n\t\t\t\t'data-date': this.get_dd_mm_yyyy(current_date),\n\t\t\t\t'data-value': data_value,\n\t\t\t\t'data-day': current_date.getDay()\n\t\t\t});\n\n\t\t\tlet next_date = new Date(current_date);\n\t\t\tthis.add_days(next_date, 1);\n\t\t\tif(next_date.getMonth() - current_date.getMonth()) {\n\t\t\t\tmonth_change = 1;\n\t\t\t\tif(this.discrete_domains) {\n\t\t\t\t\tweek_col_change = 1;\n\t\t\t\t}\n\n\t\t\t\tthis.month_start_points.push(13 + (index + week_col_change) * 12);\n\t\t\t}\n\t\t\tcurrent_date = next_date;\n\t\t}\n\n\t\treturn [data_group, month_change];\n\t}\n\n\trender_month_labels() {\n\t\t// this.first_month_label = 1;\n\t\t// if (this.first_week_start.getDate() > 8) {\n\t\t// \tthis.first_month_label = 0;\n\t\t// }\n\t\t// this.last_month_label = 1;\n\n\t\t// let first_month = this.months.shift();\n\t\t// let first_month_start = this.month_start_points.shift();\n\t\t// render first month if\n\n\t\t// let last_month = this.months.pop();\n\t\t// let last_month_start = this.month_start_points.pop();\n\t\t// render last month if\n\n\t\tthis.months.shift();\n\t\tthis.month_start_points.shift();\n\t\tthis.months.pop();\n\t\tthis.month_start_points.pop();\n\n\t\tthis.month_start_points.map((start, i) => {\n\t\t\tlet month_name = this.month_names[this.months[i]].substring(0, 3);\n\n\t\t\t$.createSVG('text', {\n\t\t\t\tclassName: 'y-value-text',\n\t\t\t\tinside: this.domain_label_group,\n\t\t\t\tx: start + 12,\n\t\t\t\ty: 10,\n\t\t\t\tdy: '.32em',\n\t\t\t\tinnerHTML: month_name\n\t\t\t});\n\n\t\t});\n\t}\n\n\tmake_graph_components() {\n\t\tArray.prototype.slice.call(\n\t\t\tthis.container.querySelectorAll('.graph-stats-container, .sub-title, .title')\n\t\t).map(d => {\n\t\t\td.style.display = 'None';\n\t\t});\n\t\tthis.chart_wrapper.style.marginTop = '0px';\n\t\tthis.chart_wrapper.style.paddingTop = '0px';\n\t}\n\n\tbind_tooltip() {\n\t\tArray.prototype.slice.call(\n\t\t\tdocument.querySelectorAll(\".data-group .day\")\n\t\t).map(el => {\n\t\t\tel.addEventListener('mouseenter', (e) => {\n\t\t\t\tlet count = e.target.getAttribute('data-value');\n\t\t\t\tlet date_parts = e.target.getAttribute('data-date').split('-');\n\n\t\t\t\tlet month = this.month_names[parseInt(date_parts[1])-1].substring(0, 3);\n\n\t\t\t\tlet g_off = this.chart_wrapper.getBoundingClientRect(), p_off = e.target.getBoundingClientRect();\n\n\t\t\t\tlet width = parseInt(e.target.getAttribute('width'));\n\t\t\t\tlet x = p_off.left - g_off.left + (width+2)/2;\n\t\t\t\tlet y = p_off.top - g_off.top - (width+2)/2;\n\t\t\t\tlet value = count + ' ' + this.count_label;\n\t\t\t\tlet name = ' on ' + month + ' ' + date_parts[0] + ', ' + date_parts[2];\n\n\t\t\t\tthis.tip.set_values(x, y, name, value, [], 1);\n\t\t\t\tthis.tip.show_tip();\n\t\t\t});\n\t\t});\n\t}\n\n\tupdate(data) {\n\t\tthis.data = data;\n\t\tthis.setup_values();\n\t\tthis.bind_tooltip();\n\t}\n\n\tget_distribution(data={}, mapper_array) {\n\t\tlet data_values = Object.keys(data).map(key => data[key]);\n\t\tlet data_max_value = Math.max(...data_values);\n\n\t\tlet distribution_step = 1 / (mapper_array.length - 1);\n\t\tlet distribution = [];\n\n\t\tmapper_array.map((color, i) => {\n\t\t\tlet checkpoint = data_max_value * (distribution_step * i);\n\t\t\tdistribution.push(checkpoint);\n\t\t});\n\n\t\treturn distribution;\n\t}\n\n\tget_max_checkpoint(value, distribution) {\n\t\treturn distribution.filter((d, i) => {\n\t\t\tif(i === 1) {\n\t\t\t\treturn distribution[0] < value;\n\t\t\t}\n\t\t\treturn d <= value;\n\t\t}).length - 1;\n\t}\n\n\t// TODO: date utils, move these out\n\n\t// https://stackoverflow.com/a/11252167/6495043\n\ttreat_as_utc(date_str) {\n\t\tlet result = new Date(date_str);\n\t\tresult.setMinutes(result.getMinutes() - result.getTimezoneOffset());\n\t\treturn result;\n\t}\n\n\tget_dd_mm_yyyy(date) {\n\t\tlet dd = date.getDate();\n\t\tlet mm = date.getMonth() + 1; // getMonth() is zero-based\n\t\treturn [\n\t\t\t(dd>9 ? '' : '0') + dd,\n\t\t\t(mm>9 ? '' : '0') + mm,\n\t\t\tdate.getFullYear()\n\t\t].join('-');\n\t}\n\n\tget_weeks_between(start_date_str, end_date_str) {\n\t\treturn Math.ceil(this.get_days_between(start_date_str, end_date_str) / 7);\n\t}\n\n\tget_days_between(start_date_str, end_date_str) {\n\t\tlet milliseconds_per_day = 24 * 60 * 60 * 1000;\n\t\treturn (this.treat_as_utc(end_date_str) - this.treat_as_utc(start_date_str)) / milliseconds_per_day;\n\t}\n\n\t// mutates\n\tadd_days(date, number_of_days) {\n\t\tdate.setDate(date.getDate() + number_of_days);\n\t}\n\n\tget_month_name() {}\n}\n","import BarChart from './charts/BarChart';\nimport LineChart from './charts/LineChart';\nimport PercentageChart from './charts/PercentageChart';\nimport Heatmap from './charts/Heatmap';\n\nexport default class Chart {\n\tconstructor(args) {\n\t\tif(args.type === 'line') {\n\t\t\treturn new LineChart(arguments[0]);\n\t\t} else if(args.type === 'bar') {\n\t\t\treturn new BarChart(arguments[0]);\n\t\t} else if(args.type === 'percentage') {\n\t\t\treturn new PercentageChart(arguments[0]);\n\t\t} else if(args.type === 'heatmap') {\n\t\t\treturn new Heatmap(arguments[0]);\n\t\t} else {\n\t\t\treturn new LineChart(arguments[0]);\n\t\t}\n\t}\n}"],"names":["$","expr","con","document","querySelector","float_2","d","parseFloat","toFixed","arrays_equal","arr1","arr2","length","are_equal","map","i","findNodeIndex","node","previousSibling","create","tag","o","element","createElement","val","appendChild","ref","parentNode","insertBefore","setAttribute","createSVG","createElementNS","runSVGAnimation","svg_container","elements","new_elements","anim_elements","obj","parent","unit","anim_element","new_element","animateSVG","push","replaceChild","array","index","object","key","anim_svg","cloneNode","props","dur","easing_type","type","undefined","old_values","easing","attributeName","animate_element","current_value","getAttribute","value","anim_attr","offset","rect","getBoundingClientRect","top","documentElement","scrollTop","body","left","scrollLeft","isElementInViewport","el","bottom","window","innerHeight","clientHeight","right","innerWidth","clientWidth","bind","event","callback","split","forEach","addEventListener","unbind","removeEventListener","fire","target","properties","evt","createEvent","initEvent","j","dispatchEvent","SvgTip","title_name","title_value","list_values","title_value_first","x","y","setup","make_tooltip","fill","calc_position","container","this","hide_tip","title","data_point_list","innerHTML","set","li","color","offsetHeight","offsetWidth","max_left","pointer","style","delta","refresh","opacity","BaseChart","height","subtitle","data","format_lambdas","summary","is_navigable","raw_chart_args","arguments","specific_values","current_index","chart_types","set_margins","includes","error","base_height","translate_x","translate_y","bind_window_events","_this","init","setup_base_values","set_width","setup_container","setup_components","setup_values","setup_utils","make_graph_components","show_custom_summary","show_summary","setup_navigation","special_values_width","_this2","get_strwidth","base_width","width","chart_wrapper","stats_wrapper","make_chart_area","make_draw_area","svg","svg_defs","draw_area","tip","bind_tooltip","stats","make_overlay","bind_overlay","e","_this4","keyCode","on_left_arrow","on_right_arrow","on_up_arrow","on_down_arrow","on_enter_key","data_point","data_key","slice","label","get_data_point","string","AxisChart","args","labels","datasets","get_y_label","y_label","get_y_tooltip","y_tooltip","get_x_tooltip","x_tooltip","colors","zero_line","values","isNaN","setup_x","setup_y","set_avg_unit_width_and_x_offset","x_axis_positions","x_old_axis_positions","x_offset","avg_unit_width","y_axis_values","y_old_axis_values","get_all_y_values","y_sums","concat","get_y_axis_points","y_pts","value_range","multiplier","old_multiplier","zero_index","indexOf","interval_height","old_zero_line","setup_marker_components","setup_aggregation_components","setup_graph_components","y_axis_group","className","inside","x_axis_group","specific_y_group","sum_group","average_group","svg_units_groups","_this3","make_y_axis","make_x_axis","draw_graph","make_y_specifics","animate","start_at","text_start_at","axis_line_class","x_axis_mode","make_anim_x_axis","textContent","point","make_x_line","make_anim_y_axis","make_anim_y_specifics","get_y_axis_line_props","text_end_at","_this5","make_y_line","y_axis_mode","draw_new_graph_and_animate","svg_units","make_path","_this6","y_tops","make_new_units","Array","_this7","update_values","make_new_units_for_dataset","x_values","y_values","dataset_index","no_of_datasets","group","unit_args","data_unit","_this9","draw","_this10","toUpperCase","line_type","_this11","relX","pageX","pageY","map_tooltip_x_position_and_show","x_val","y_min_tops","formatted","_this12","set_values","show_tip","updating","sum_units","_this13","old_specific_values","sum","average","indices_to_remove","auto","unshift","splice","new_y","new_x","elements_to_animate","old_x_values","old_y_axis_tops","old_y_values","no_of_extra_pts","_this16","calc_y_dependencies","animate_graphs","run_animation","y_point","x_point","data_set","removeChild","_this17","_this18","calc_old_and_new_postions","old_x","old_y","path","animate_path","animate_units","new_path_str","join","path_args","region_path","reg_start_pt","reg_end_pt","region_args","_this19","last_old_x_pos","last_old_y_pos","last_new_x_pos","last_new_y_pos","filler_x","Math","abs","filler_y","old_pos","new_pos","old_vals","new_vals","last_line_pos","make_new_axis_anim_lines","x_line","_this20","transform","_this21","add_and_animate_y_line","_this22","add_and_animate_line","superimposed_positions","superimposed_values","no_of_extras","filler_vals","filler_pos","extra_values","extra_positions","label_class","x_pos","allowed_space","allowed_letters","line","text","x_level","y_pos","darker","y_level","stroke","specific","axis_label_class","y_line","min_bound","pos_no_of_parts","neg_no_of_parts","part_size","max_val","parseInt","max","min_val","min","get_params","value1","value2","bound1","bound2","no_of_parts_1","no_of_parts_2","interval_size","_this23","calc_upper_bound_and_no_of_parts","calc_no_of_parts","abs_min_val","no_of_parts","get_intervals","start","count","intervals","pow","divisor","ceil","all_values","_this24","y_top","total_width","_this25","space_width","current_x","get_bar_height_and_y_attr","radius","bar_obj","dot_obj","cx","cy","BarChart","update_current_data_point","overlay","update_overlay","svg_unit","attributes","keys","filter","attr","specified","name","nodeValue","LineChart","Object","getPrototypeOf","prototype","region_fill","setup_path_groups","paths_groups","x_positions","y_positions","points_str","gradient_id","gradient_def","set_gradient_stop","grad_elem","PercentageChart","max_slices","max_legend_points","marginTop","marginBottom","paddingTop","chart_div","chart","percentage_bar","slice_totals","all_totals","total","totals","sort","a","b","sum_of_others","legend_totals","grand_total","reduce","slices","g_off","p_off","formatted_labels","percent","Heatmap","domain","subdomain","discrete_domains","count_label","today","Date","add_days","legend_colors","setFullYear","getFullYear","first_week_start","toDateString","last_week_start","getDay","no_of_cols","get_weeks_between","domain_label_group","data_groups","distribution","get_distribution","month_names","render_all_weeks_and_store_x_values","no_of_weeks","current_week_sunday","week_col","current_month","getMonth","months","month_weeks","month_start_points","data_group","month_change","day","get_week_squares_group","render_month_labels","current_date","week_col_change","square_side","data_value","color_index","timestamp","floor","getTime","get_max_checkpoint","round","get_dd_mm_yyyy","next_date","shift","pop","month_name","substring","call","querySelectorAll","display","date_parts","month","mapper_array","data_values","data_max_value","distribution_step","checkpoint","date_str","result","setMinutes","getMinutes","getTimezoneOffset","date","dd","getDate","mm","start_date_str","end_date_str","get_days_between","treat_as_utc","number_of_days","setDate"],"mappings":"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"} \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index e3f1fd5..3ac95e1 100644 --- a/docs/index.html +++ b/docs/index.html @@ -156,8 +156,6 @@ - - diff --git a/package-lock.json b/package-lock.json index 1fc2b1f..2ec3d62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -942,6 +942,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2260,6 +2266,15 @@ "resolve": "1.5.0" } }, + "rollup-plugin-uglify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-uglify/-/rollup-plugin-uglify-2.0.1.tgz", + "integrity": "sha1-Z7N60e/a+9g69MNrQMGJ7khmyWk=", + "dev": true, + "requires": { + "uglify-js": "3.1.5" + } + }, "rollup-pluginutils": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz", @@ -2519,6 +2534,24 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "uglify-js": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.1.5.tgz", + "integrity": "sha512-tSqlO7/GZHAVSw6mbtJt2kz0ZcUrKUH7Xg92o52aE+gL0r6cXiASZY4dpHqQ7RVGXmoQuPA2qAkG4TkP59f8XA==", + "dev": true, + "requires": { + "commander": "2.11.0", + "source-map": "0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index ade9457..a7367f1 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "rollup": "^0.50.0", "rollup-plugin-babel": "^3.0.2", "rollup-plugin-eslint": "^4.0.0", - "rollup-plugin-node-resolve": "^3.0.0" + "rollup-plugin-node-resolve": "^3.0.0", + "rollup-plugin-uglify": "^2.0.1" } } diff --git a/rollup.config.js b/rollup.config.js index 43d4620..1b6b9ba 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,21 +1,21 @@ // Rollup plugins -import resolve from 'rollup-plugin-node-resolve'; import babel from 'rollup-plugin-babel'; import eslint from 'rollup-plugin-eslint'; +import uglify from 'rollup-plugin-uglify'; export default { - input: 'src/charts.js', - output: { - file: 'dist/frappe-charts.min.js', - format: 'iife', - }, - name: 'Chart', - sourcemap: 'inline', - plugins: [ - resolve(), - eslint(), - babel({ - exclude: 'node_modules/**', - }), - ], + input: 'src/scripts/charts.js', + output: { + file: 'dist/frappe-charts.min.js', + format: 'iife', + }, + name: 'Chart', + sourcemap: 'true', + plugins: [ + eslint(), + babel({ + exclude: 'node_modules/**', + }), + uglify() + ], }; diff --git a/src/scripts/charts.js b/src/scripts/charts.js new file mode 100644 index 0000000..a8f3c49 --- /dev/null +++ b/src/scripts/charts.js @@ -0,0 +1,20 @@ +import BarChart from './charts/BarChart'; +import LineChart from './charts/LineChart'; +import PercentageChart from './charts/PercentageChart'; +import Heatmap from './charts/Heatmap'; + +export default class Chart { + constructor(args) { + if(args.type === 'line') { + return new LineChart(arguments[0]); + } else if(args.type === 'bar') { + return new BarChart(arguments[0]); + } else if(args.type === 'percentage') { + return new PercentageChart(arguments[0]); + } else if(args.type === 'heatmap') { + return new Heatmap(arguments[0]); + } else { + return new LineChart(arguments[0]); + } + } +} \ No newline at end of file diff --git a/src/charts.js b/src/scripts/charts/AxisChart.js similarity index 52% rename from src/charts.js rename to src/scripts/charts/AxisChart.js index 6e02969..8ccd3a7 100644 --- a/src/charts.js +++ b/src/scripts/charts/AxisChart.js @@ -1,272 +1,8 @@ -import $ from './dom'; -import { float_2, arrays_equal } from './utils'; +import $ from '../helpers/dom'; +import { float_2, arrays_equal } from '../helpers/utils'; +import BaseChart from './BaseChart'; -export default class Chart { - constructor({ - parent = "", - height = 240, - - title = '', subtitle = '', - - data = {}, - format_lambdas = {}, - - summary = [], - - is_navigable = 0, - - type = '' - }) { - if(Object.getPrototypeOf(this) === Chart.prototype) { - if(type === 'line') { - return new LineChart(arguments[0]); - } else if(type === 'bar') { - return new BarChart(arguments[0]); - } else if(type === 'percentage') { - return new PercentageChart(arguments[0]); - } else if(type === 'heatmap') { - return new HeatMap(arguments[0]); - } else { - return new LineChart(arguments[0]); - } - } - - this.raw_chart_args = arguments[0]; - - this.parent = document.querySelector(parent); - this.title = title; - this.subtitle = subtitle; - - this.data = data; - this.format_lambdas = format_lambdas; - - this.specific_values = data.specific_values || []; - this.summary = summary; - - this.is_navigable = is_navigable; - if(this.is_navigable) { - this.current_index = 0; - } - - this.chart_types = ['line', 'bar', 'percentage', 'heatmap']; - - this.set_margins(height); - } - - get_different_chart(type) { - if(!this.chart_types.includes(type)) { - console.error(`'${type}' is not a valid chart type.`); - } - if(type === this.type) return; - - // Only across compatible types - let compatible_types = { - bar: ['line', 'percentage'], - line: ['bar', 'percentage'], - percentage: ['bar', 'line'], - heatmap: [] - }; - - if(!compatible_types[this.type].includes(type)) { - console.error(`'${this.type}' chart cannot be converted to a '${type}' chart.`); - } - - // Okay, this is anticlimactic - // this function will need to actually be 'change_chart_type(type)' - // that will update only the required elements, but for now ... - return new Chart({ - parent: this.raw_chart_args.parent, - data: this.raw_chart_args.data, - type: type, - height: this.raw_chart_args.height - }); - } - - set_margins(height) { - this.base_height = height; - this.height = height - 40; - this.translate_x = 60; - this.translate_y = 10; - } - - setup() { - this.bind_window_events(); - this.refresh(true); - } - - bind_window_events() { - window.addEventListener('resize', () => this.refresh()); - window.addEventListener('orientationchange', () => this.refresh()); - } - - refresh(init=false) { - this.setup_base_values(); - this.set_width(); - - this.setup_container(); - this.setup_components(); - - this.setup_values(); - this.setup_utils(); - - this.make_graph_components(init); - this.make_tooltip(); - - if(this.summary.length > 0) { - this.show_custom_summary(); - } else { - this.show_summary(); - } - - if(this.is_navigable) { - this.setup_navigation(init); - } - } - - set_width() { - let special_values_width = 0; - this.specific_values.map(val => { - if(this.get_strwidth(val.title) > special_values_width) { - special_values_width = this.get_strwidth(val.title) - 40; - } - }); - this.base_width = this.parent.offsetWidth - special_values_width; - this.width = this.base_width - this.translate_x * 2; - } - - setup_base_values() {} - - setup_container() { - this.container = $.create('div', { - className: 'chart-container', - innerHTML: `
    ${this.title}
    -
    ${this.subtitle}
    -
    -
    ` - }); - - // Chart needs a dedicated parent element - this.parent.innerHTML = ''; - this.parent.appendChild(this.container); - - this.chart_wrapper = this.container.querySelector('.frappe-chart'); - this.stats_wrapper = this.container.querySelector('.graph-stats-container'); - - this.make_chart_area(); - this.make_draw_area(); - } - - make_chart_area() { - this.svg = $.createSVG('svg', { - className: 'chart', - inside: this.chart_wrapper, - width: this.base_width, - height: this.base_height - }); - - this.svg_defs = $.createSVG('defs', { - inside: this.svg, - }); - - return this.svg; - } - - make_draw_area() { - this.draw_area = $.createSVG("g", { - className: this.type + '-chart', - inside: this.svg, - transform: `translate(${this.translate_x}, ${this.translate_y})` - }); - } - - setup_components() { } - - make_tooltip() { - this.tip = new SvgTip({ - parent: this.chart_wrapper, - }); - this.bind_tooltip(); - } - - - show_summary() {} - show_custom_summary() { - this.summary.map(d => { - let stats = $.create('div', { - className: 'stats', - innerHTML: `${d.title}: ${d.value}` - }); - this.stats_wrapper.appendChild(stats); - }); - } - - setup_navigation(init=false) { - this.make_overlay(); - - if(init) { - this.bind_overlay(); - - document.addEventListener('keydown', (e) => { - if($.isElementInViewport(this.chart_wrapper)) { - e = e || window.event; - - if (e.keyCode == '37') { - this.on_left_arrow(); - } else if (e.keyCode == '39') { - this.on_right_arrow(); - } else if (e.keyCode == '38') { - this.on_up_arrow(); - } else if (e.keyCode == '40') { - this.on_down_arrow(); - } else if (e.keyCode == '13') { - this.on_enter_key(); - } - } - }); - } - } - - make_overlay() {} - bind_overlay() {} - - on_left_arrow() {} - on_right_arrow() {} - on_up_arrow() {} - on_down_arrow() {} - on_enter_key() {} - - get_data_point(index=this.current_index) { - // check for length - let data_point = { - index: index - }; - let y = this.y[0]; - ['svg_units', 'y_tops', 'values'].map(key => { - let data_key = key.slice(0, key.length-1); - data_point[data_key] = y[key][index]; - }); - data_point.label = this.x[index]; - return data_point; - } - - update_current_data_point(index) { - if(index < 0) index = 0; - if(index >= this.x.length) index = this.x.length - 1; - if(index === this.current_index) return; - this.current_index = index; - $.fire(this.parent, "data-select", this.get_data_point()); - } - - // Helpers - get_strwidth(string) { - return string.length * 8; - } - - // Objects - setup_utils() { } -} - -class AxisChart extends Chart { +export default class AxisChart extends BaseChart { constructor(args) { super(args); @@ -1262,713 +998,3 @@ class AxisChart extends Chart { }; } } - -class BarChart extends AxisChart { - constructor(args) { - super(args); - - this.type = 'bar'; - this.x_axis_mode = args.x_axis_mode || 'tick'; - this.y_axis_mode = args.y_axis_mode || 'span'; - this.setup(); - } - - setup_values() { - super.setup_values(); - this.x_offset = this.avg_unit_width; - this.unit_args = { - type: 'bar', - args: { - space_width: this.avg_unit_width/2, - } - }; - } - - make_overlay() { - // Just make one out of the first element - let index = this.x.length - 1; - let unit = this.y[0].svg_units[index]; - this.update_current_data_point(index); - - if(this.overlay) { - this.overlay.parentNode.removeChild(this.overlay); - } - - this.overlay = unit.cloneNode(); - this.overlay.style.fill = '#000000'; - this.overlay.style.opacity = '0.4'; - this.draw_area.appendChild(this.overlay); - } - - bind_overlay() { - // on event, update overlay - this.parent.addEventListener('data-select', (e) => { - this.update_overlay(e.svg_unit); - }); - } - - update_overlay(unit) { - let attributes = []; - Object.keys(unit.attributes).map(index => { - attributes.push(unit.attributes[index]); - }); - - attributes.filter(attr => attr.specified).map(attr => { - this.overlay.setAttribute(attr.name, attr.nodeValue); - }); - } - - on_left_arrow() { - this.update_current_data_point(this.current_index - 1); - } - - on_right_arrow() { - this.update_current_data_point(this.current_index + 1); - } - - set_avg_unit_width_and_x_offset() { - this.avg_unit_width = this.width/(this.x.length + 1); - this.x_offset = this.avg_unit_width; - } -} - -class LineChart extends AxisChart { - constructor(args) { - super(args); - if(Object.getPrototypeOf(this) !== LineChart.prototype) { - return; - } - - this.type = 'line'; - this.region_fill = args.region_fill; - this.x_axis_mode = args.x_axis_mode || 'span'; - this.y_axis_mode = args.y_axis_mode || 'span'; - - this.setup(); - } - - setup_graph_components() { - this.setup_path_groups(); - super.setup_graph_components(); - } - - setup_path_groups() { - this.paths_groups = []; - this.y.map((d, i) => { - this.paths_groups[i] = $.createSVG('g', { - className: 'path-group path-group-' + i, - inside: this.draw_area - }); - }); - } - - setup_values() { - super.setup_values(); - this.unit_args = { - type: 'dot', - args: { radius: 8 } - }; - } - - make_paths() { - this.y.map((d, i) => { - this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]); - }); - } - - make_path(d, i, x_positions, y_positions, color) { - let points_list = y_positions.map((y, i) => (x_positions[i] + ',' + y)); - let points_str = points_list.join("L"); - - this.paths_groups[i].textContent = ''; - - d.path = $.createSVG('path', { - inside: this.paths_groups[i], - className: `stroke ${color}`, - d: "M"+points_str - }); - - if(this.region_fill) { - let gradient_id ='path-fill-gradient' + '-' + color; - - this.gradient_def = $.createSVG('linearGradient', { - inside: this.svg_defs, - id: gradient_id, - x1: 0, - x2: 0, - y1: 0, - y2: 1 - }); - - let set_gradient_stop = (grad_elem, offset, color, opacity) => { - $.createSVG('stop', { - 'className': 'stop-color ' + color, - 'inside': grad_elem, - 'offset': offset, - 'stop-opacity': opacity - }); - }; - - set_gradient_stop(this.gradient_def, "0%", color, 0.4); - set_gradient_stop(this.gradient_def, "50%", color, 0.2); - set_gradient_stop(this.gradient_def, "100%", color, 0); - - d.region_path = $.createSVG('path', { - inside: this.paths_groups[i], - className: `region-fill`, - d: "M" + `0,${this.zero_line}L` + points_str + `L${this.width},${this.zero_line}`, - }); - - d.region_path.style.stroke = "none"; - d.region_path.style.fill = `url(#${gradient_id})`; - } - } -} - -class PercentageChart extends Chart { - constructor(args) { - super(args); - this.type = 'percentage'; - - this.get_y_label = this.format_lambdas.y_label; - this.get_x_tooltip = this.format_lambdas.x_tooltip; - this.get_y_tooltip = this.format_lambdas.y_tooltip; - - this.max_slices = 10; - this.max_legend_points = 6; - - this.colors = args.colors; - - if(!this.colors || this.colors.length < this.data.labels.length) { - this.colors = ['light-blue', 'blue', 'violet', 'red', 'orange', - 'yellow', 'green', 'light-green', 'purple', 'magenta']; - } - - this.setup(); - } - - make_chart_area() { - this.chart_wrapper.className += ' ' + 'graph-focus-margin'; - this.chart_wrapper.style.marginTop = '45px'; - - this.stats_wrapper.className += ' ' + 'graph-focus-margin'; - this.stats_wrapper.style.marginBottom = '30px'; - this.stats_wrapper.style.paddingTop = '0px'; - } - - make_draw_area() { - this.chart_div = $.create('div', { - className: 'div', - inside: this.chart_wrapper, - width: this.base_width, - height: this.base_height - }); - - this.chart = $.create('div', { - className: 'progress-chart', - inside: this.chart_div - }); - } - - setup_components() { - this.percentage_bar = $.create('div', { - className: 'progress', - inside: this.chart - }); - } - - setup_values() { - this.slice_totals = []; - let all_totals = this.data.labels.map((d, i) => { - let total = 0; - this.data.datasets.map(e => { - total += e.values[i]; - }); - return [total, d]; - }).filter(d => { return d[0] > 0; }); // keep only positive results - - let totals = all_totals; - - if(all_totals.length > this.max_slices) { - all_totals.sort((a, b) => { return b[0] - a[0]; }); - - totals = all_totals.slice(0, this.max_slices-1); - let others = all_totals.slice(this.max_slices-1); - - let sum_of_others = 0; - others.map(d => {sum_of_others += d[0];}); - - totals.push([sum_of_others, 'Rest']); - - this.colors[this.max_slices-1] = 'grey'; - } - - this.labels = []; - totals.map(d => { - this.slice_totals.push(d[0]); - this.labels.push(d[1]); - }); - - this.legend_totals = this.slice_totals.slice(0, this.max_legend_points); - } - - setup_utils() { } - - make_graph_components() { - this.grand_total = this.slice_totals.reduce((a, b) => a + b, 0); - this.slices = []; - this.slice_totals.map((total, i) => { - let slice = $.create('div', { - className: `progress-bar background ${this.colors[i]}`, - style: `width: ${total*100/this.grand_total}%`, - inside: this.percentage_bar - }); - this.slices.push(slice); - }); - } - - bind_tooltip() { - this.slices.map((slice, i) => { - slice.addEventListener('mouseenter', () => { - let g_off = $.offset(this.chart_wrapper), p_off = $.offset(slice); - - let x = p_off.left - g_off.left + slice.offsetWidth/2; - let y = p_off.top - g_off.top - 6; - let title = (this.formatted_labels && this.formatted_labels.length>0 - ? this.formatted_labels[i] : this.labels[i]) + ': '; - let percent = (this.slice_totals[i]*100/this.grand_total).toFixed(1); - - this.tip.set_values(x, y, title, percent + "%"); - this.tip.show_tip(); - }); - }); - } - - show_summary() { - let x_values = this.formatted_labels && this.formatted_labels.length > 0 - ? this.formatted_labels : this.labels; - this.legend_totals.map((d, i) => { - if(d) { - let stats = $.create('div', { - className: 'stats', - inside: this.stats_wrapper - }); - stats.innerHTML = ` - ${x_values[i]}: - ${d} - `; - } - }); - } -} - -class HeatMap extends Chart { - constructor({ - start = '', - domain = '', - subdomain = '', - data = {}, - discrete_domains = 0, - count_label = '' - }) { - super(arguments[0]); - - this.type = 'heatmap'; - - this.domain = domain; - this.subdomain = subdomain; - this.data = data; - this.discrete_domains = discrete_domains; - this.count_label = count_label; - - let today = new Date(); - this.start = start || this.add_days(today, 365); - - this.legend_colors = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127']; - - this.translate_x = 0; - this.setup(); - } - - setup_base_values() { - this.today = new Date(); - - if(!this.start) { - this.start = new Date(); - this.start.setFullYear( this.start.getFullYear() - 1 ); - } - this.first_week_start = new Date(this.start.toDateString()); - this.last_week_start = new Date(this.today.toDateString()); - if(this.first_week_start.getDay() !== 7) { - this.add_days(this.first_week_start, (-1) * this.first_week_start.getDay()); - } - if(this.last_week_start.getDay() !== 7) { - this.add_days(this.last_week_start, (-1) * this.last_week_start.getDay()); - } - this.no_of_cols = this.get_weeks_between(this.first_week_start + '', this.last_week_start + '') + 1; - } - - set_width() { - this.base_width = (this.no_of_cols) * 12; - - if(this.discrete_domains) { - this.base_width += (12 * 12); - } - } - - setup_components() { - this.domain_label_group = $.createSVG("g", { - className: "domain-label-group chart-label", - inside: this.draw_area - }); - this.data_groups = $.createSVG("g", { - className: "data-groups", - inside: this.draw_area, - transform: `translate(0, 20)` - }); - } - - setup_values() { - this.domain_label_group.textContent = ''; - this.data_groups.textContent = ''; - this.distribution = this.get_distribution(this.data, this.legend_colors); - this.month_names = ["January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December" - ]; - - this.render_all_weeks_and_store_x_values(this.no_of_cols); - } - - render_all_weeks_and_store_x_values(no_of_weeks) { - let current_week_sunday = new Date(this.first_week_start); - this.week_col = 0; - this.current_month = current_week_sunday.getMonth(); - - this.months = [this.current_month + '']; - this.month_weeks = {}, this.month_start_points = []; - this.month_weeks[this.current_month] = 0; - this.month_start_points.push(13); - - for(var i = 0; i < no_of_weeks; i++) { - let data_group, month_change = 0; - let day = new Date(current_week_sunday); - - [data_group, month_change] = this.get_week_squares_group(day, this.week_col); - this.data_groups.appendChild(data_group); - this.week_col += 1 + parseInt(this.discrete_domains && month_change); - this.month_weeks[this.current_month]++; - if(month_change) { - this.current_month = (this.current_month + 1) % 12; - this.months.push(this.current_month + ''); - this.month_weeks[this.current_month] = 1; - } - this.add_days(current_week_sunday, 7); - } - this.render_month_labels(); - } - - get_week_squares_group(current_date, index) { - const no_of_weekdays = 7; - const square_side = 10; - const cell_padding = 2; - const step = 1; - - let month_change = 0; - let week_col_change = 0; - - let data_group = $.createSVG("g", { - className: "data-group", - inside: this.data_groups - }); - - for(var y = 0, i = 0; i < no_of_weekdays; i += step, y += (square_side + cell_padding)) { - let data_value = 0; - let color_index = 0; - - let timestamp = Math.floor(current_date.getTime()/1000).toFixed(1); - - if(this.data[timestamp]) { - data_value = this.data[timestamp]; - color_index = this.get_max_checkpoint(data_value, this.distribution); - } - - if(this.data[Math.round(timestamp)]) { - data_value = this.data[Math.round(timestamp)]; - color_index = this.get_max_checkpoint(data_value, this.distribution); - } - - let x = 13 + (index + week_col_change) * 12; - - $.createSVG("rect", { - className: 'day', - inside: data_group, - x: x, - y: y, - width: square_side, - height: square_side, - fill: this.legend_colors[color_index], - 'data-date': this.get_dd_mm_yyyy(current_date), - 'data-value': data_value, - 'data-day': current_date.getDay() - }); - - let next_date = new Date(current_date); - this.add_days(next_date, 1); - if(next_date.getMonth() - current_date.getMonth()) { - month_change = 1; - if(this.discrete_domains) { - week_col_change = 1; - } - - this.month_start_points.push(13 + (index + week_col_change) * 12); - } - current_date = next_date; - } - - return [data_group, month_change]; - } - - render_month_labels() { - // this.first_month_label = 1; - // if (this.first_week_start.getDate() > 8) { - // this.first_month_label = 0; - // } - // this.last_month_label = 1; - - // let first_month = this.months.shift(); - // let first_month_start = this.month_start_points.shift(); - // render first month if - - // let last_month = this.months.pop(); - // let last_month_start = this.month_start_points.pop(); - // render last month if - - this.months.shift(); - this.month_start_points.shift(); - this.months.pop(); - this.month_start_points.pop(); - - this.month_start_points.map((start, i) => { - let month_name = this.month_names[this.months[i]].substring(0, 3); - - $.createSVG('text', { - className: 'y-value-text', - inside: this.domain_label_group, - x: start + 12, - y: 10, - dy: '.32em', - innerHTML: month_name - }); - - }); - } - - make_graph_components() { - Array.prototype.slice.call( - this.container.querySelectorAll('.graph-stats-container, .sub-title, .title') - ).map(d => { - d.style.display = 'None'; - }); - this.chart_wrapper.style.marginTop = '0px'; - this.chart_wrapper.style.paddingTop = '0px'; - } - - bind_tooltip() { - Array.prototype.slice.call( - document.querySelectorAll(".data-group .day") - ).map(el => { - el.addEventListener('mouseenter', (e) => { - let count = e.target.getAttribute('data-value'); - let date_parts = e.target.getAttribute('data-date').split('-'); - - let month = this.month_names[parseInt(date_parts[1])-1].substring(0, 3); - - let g_off = this.chart_wrapper.getBoundingClientRect(), p_off = e.target.getBoundingClientRect(); - - let width = parseInt(e.target.getAttribute('width')); - let x = p_off.left - g_off.left + (width+2)/2; - let y = p_off.top - g_off.top - (width+2)/2; - let value = count + ' ' + this.count_label; - let name = ' on ' + month + ' ' + date_parts[0] + ', ' + date_parts[2]; - - this.tip.set_values(x, y, name, value, [], 1); - this.tip.show_tip(); - }); - }); - } - - update(data) { - this.data = data; - this.setup_values(); - this.bind_tooltip(); - } - - get_distribution(data={}, mapper_array) { - let data_values = Object.keys(data).map(key => data[key]); - let data_max_value = Math.max(...data_values); - - let distribution_step = 1 / (mapper_array.length - 1); - let distribution = []; - - mapper_array.map((color, i) => { - let checkpoint = data_max_value * (distribution_step * i); - distribution.push(checkpoint); - }); - - return distribution; - } - - get_max_checkpoint(value, distribution) { - return distribution.filter((d, i) => { - if(i === 1) { - return distribution[0] < value; - } - return d <= value; - }).length - 1; - } - - // TODO: date utils, move these out - - // https://stackoverflow.com/a/11252167/6495043 - treat_as_utc(date_str) { - let result = new Date(date_str); - result.setMinutes(result.getMinutes() - result.getTimezoneOffset()); - return result; - } - - get_dd_mm_yyyy(date) { - let dd = date.getDate(); - let mm = date.getMonth() + 1; // getMonth() is zero-based - return [ - (dd>9 ? '' : '0') + dd, - (mm>9 ? '' : '0') + mm, - date.getFullYear() - ].join('-'); - } - - get_weeks_between(start_date_str, end_date_str) { - return Math.ceil(this.get_days_between(start_date_str, end_date_str) / 7); - } - - get_days_between(start_date_str, end_date_str) { - let milliseconds_per_day = 24 * 60 * 60 * 1000; - return (this.treat_as_utc(end_date_str) - this.treat_as_utc(start_date_str)) / milliseconds_per_day; - } - - // mutates - add_days(date, number_of_days) { - date.setDate(date.getDate() + number_of_days); - } - - get_month_name() {} -} - -class SvgTip { - constructor({ - parent = null - }) { - this.parent = parent; - this.title_name = ''; - this.title_value = ''; - this.list_values = []; - this.title_value_first = 0; - - this.x = 0; - this.y = 0; - - this.top = 0; - this.left = 0; - - this.setup(); - } - - setup() { - this.make_tooltip(); - } - - refresh() { - this.fill(); - this.calc_position(); - // this.show_tip(); - } - - make_tooltip() { - this.container = $.create('div', { - inside: this.parent, - className: 'graph-svg-tip comparison', - innerHTML: ` -
      -
      ` - }); - this.hide_tip(); - - this.title = this.container.querySelector('.title'); - this.data_point_list = this.container.querySelector('.data-point-list'); - - this.parent.addEventListener('mouseleave', () => { - this.hide_tip(); - }); - } - - fill() { - let title; - if(this.title_value_first) { - title = `${this.title_value}${this.title_name}`; - } else { - title = `${this.title_name}${this.title_value}`; - } - this.title.innerHTML = title; - this.data_point_list.innerHTML = ''; - - this.list_values.map((set) => { - let li = $.create('li', { - className: `border-top ${set.color || 'black'}`, - innerHTML: `${set.value ? set.value : '' } - ${set.title ? set.title : '' }` - }); - - this.data_point_list.appendChild(li); - }); - } - - calc_position() { - this.top = this.y - this.container.offsetHeight; - this.left = this.x - this.container.offsetWidth/2; - let max_left = this.parent.offsetWidth - this.container.offsetWidth; - - let pointer = this.container.querySelector('.svg-pointer'); - - if(this.left < 0) { - pointer.style.left = `calc(50% - ${-1 * this.left}px)`; - this.left = 0; - } else if(this.left > max_left) { - let delta = this.left - max_left; - pointer.style.left = `calc(50% + ${delta}px)`; - this.left = max_left; - } else { - pointer.style.left = `50%`; - } - } - - set_values(x, y, title_name = '', title_value = '', list_values = [], title_value_first = 0) { - this.title_name = title_name; - this.title_value = title_value; - this.list_values = list_values; - this.x = x; - this.y = y; - this.title_value_first = title_value_first; - this.refresh(); - } - - hide_tip() { - this.container.style.top = '0px'; - this.container.style.left = '0px'; - this.container.style.opacity = '0'; - } - - show_tip() { - this.container.style.top = this.top + 'px'; - this.container.style.left = this.left + 'px'; - this.container.style.opacity = '1'; - } -} diff --git a/src/scripts/charts/BarChart.js b/src/scripts/charts/BarChart.js new file mode 100644 index 0000000..8754d19 --- /dev/null +++ b/src/scripts/charts/BarChart.js @@ -0,0 +1,70 @@ +import AxisChart from './AxisChart'; + +export default class BarChart extends AxisChart { + constructor(args) { + super(args); + + this.type = 'bar'; + this.x_axis_mode = args.x_axis_mode || 'tick'; + this.y_axis_mode = args.y_axis_mode || 'span'; + this.setup(); + } + + setup_values() { + super.setup_values(); + this.x_offset = this.avg_unit_width; + this.unit_args = { + type: 'bar', + args: { + space_width: this.avg_unit_width/2, + } + }; + } + + make_overlay() { + // Just make one out of the first element + let index = this.x.length - 1; + let unit = this.y[0].svg_units[index]; + this.update_current_data_point(index); + + if(this.overlay) { + this.overlay.parentNode.removeChild(this.overlay); + } + + this.overlay = unit.cloneNode(); + this.overlay.style.fill = '#000000'; + this.overlay.style.opacity = '0.4'; + this.draw_area.appendChild(this.overlay); + } + + bind_overlay() { + // on event, update overlay + this.parent.addEventListener('data-select', (e) => { + this.update_overlay(e.svg_unit); + }); + } + + update_overlay(unit) { + let attributes = []; + Object.keys(unit.attributes).map(index => { + attributes.push(unit.attributes[index]); + }); + + attributes.filter(attr => attr.specified).map(attr => { + this.overlay.setAttribute(attr.name, attr.nodeValue); + }); + } + + on_left_arrow() { + this.update_current_data_point(this.current_index - 1); + } + + on_right_arrow() { + this.update_current_data_point(this.current_index + 1); + } + + set_avg_unit_width_and_x_offset() { + this.avg_unit_width = this.width/(this.x.length + 1); + this.x_offset = this.avg_unit_width; + } +} diff --git a/src/scripts/charts/BaseChart.js b/src/scripts/charts/BaseChart.js new file mode 100644 index 0000000..665b545 --- /dev/null +++ b/src/scripts/charts/BaseChart.js @@ -0,0 +1,253 @@ +import SvgTip from '../objects/SvgTip'; +import $ from '../helpers/dom'; + +export default class BaseChart { + constructor({ + parent = "", + height = 240, + + title = '', subtitle = '', + + data = {}, + format_lambdas = {}, + + summary = [], + + is_navigable = 0, + + type = '' // eslint-disable-line no-unused-vars + }) { + this.raw_chart_args = arguments[0]; + + this.parent = document.querySelector(parent); + this.title = title; + this.subtitle = subtitle; + + this.data = data; + this.format_lambdas = format_lambdas; + + this.specific_values = data.specific_values || []; + this.summary = summary; + + this.is_navigable = is_navigable; + if(this.is_navigable) { + this.current_index = 0; + } + + this.chart_types = ['line', 'bar', 'percentage', 'heatmap']; + + this.set_margins(height); + } + + get_different_chart(type) { + if(!this.chart_types.includes(type)) { + console.error(`'${type}' is not a valid chart type.`); + } + if(type === this.type) return; + + // Only across compatible types + let compatible_types = { + bar: ['line', 'percentage'], + line: ['bar', 'percentage'], + percentage: ['bar', 'line'], + heatmap: [] + }; + + if(!compatible_types[this.type].includes(type)) { + console.error(`'${this.type}' chart cannot be converted to a '${type}' chart.`); + } + + // Okay, this is anticlimactic + // this function will need to actually be 'change_chart_type(type)' + // that will update only the required elements, but for now ... + return new BaseChart({ + parent: this.raw_chart_args.parent, + data: this.raw_chart_args.data, + type: type, + height: this.raw_chart_args.height + }); + } + + set_margins(height) { + this.base_height = height; + this.height = height - 40; + this.translate_x = 60; + this.translate_y = 10; + } + + setup() { + this.bind_window_events(); + this.refresh(true); + } + + bind_window_events() { + window.addEventListener('resize', () => this.refresh()); + window.addEventListener('orientationchange', () => this.refresh()); + } + + refresh(init=false) { + this.setup_base_values(); + this.set_width(); + + this.setup_container(); + this.setup_components(); + + this.setup_values(); + this.setup_utils(); + + this.make_graph_components(init); + this.make_tooltip(); + + if(this.summary.length > 0) { + this.show_custom_summary(); + } else { + this.show_summary(); + } + + if(this.is_navigable) { + this.setup_navigation(init); + } + } + + set_width() { + let special_values_width = 0; + this.specific_values.map(val => { + if(this.get_strwidth(val.title) > special_values_width) { + special_values_width = this.get_strwidth(val.title) - 40; + } + }); + this.base_width = this.parent.offsetWidth - special_values_width; + this.width = this.base_width - this.translate_x * 2; + } + + setup_base_values() {} + + setup_container() { + this.container = $.create('div', { + className: 'chart-container', + innerHTML: `
      ${this.title}
      +
      ${this.subtitle}
      +
      +
      ` + }); + + // Chart needs a dedicated parent element + this.parent.innerHTML = ''; + this.parent.appendChild(this.container); + + this.chart_wrapper = this.container.querySelector('.frappe-chart'); + this.stats_wrapper = this.container.querySelector('.graph-stats-container'); + + this.make_chart_area(); + this.make_draw_area(); + } + + make_chart_area() { + this.svg = $.createSVG('svg', { + className: 'chart', + inside: this.chart_wrapper, + width: this.base_width, + height: this.base_height + }); + + this.svg_defs = $.createSVG('defs', { + inside: this.svg, + }); + + return this.svg; + } + + make_draw_area() { + this.draw_area = $.createSVG("g", { + className: this.type + '-chart', + inside: this.svg, + transform: `translate(${this.translate_x}, ${this.translate_y})` + }); + } + + setup_components() { } + + make_tooltip() { + this.tip = new SvgTip({ + parent: this.chart_wrapper, + }); + this.bind_tooltip(); + } + + + show_summary() {} + show_custom_summary() { + this.summary.map(d => { + let stats = $.create('div', { + className: 'stats', + innerHTML: `${d.title}: ${d.value}` + }); + this.stats_wrapper.appendChild(stats); + }); + } + + setup_navigation(init=false) { + this.make_overlay(); + + if(init) { + this.bind_overlay(); + + document.addEventListener('keydown', (e) => { + if($.isElementInViewport(this.chart_wrapper)) { + e = e || window.event; + + if (e.keyCode == '37') { + this.on_left_arrow(); + } else if (e.keyCode == '39') { + this.on_right_arrow(); + } else if (e.keyCode == '38') { + this.on_up_arrow(); + } else if (e.keyCode == '40') { + this.on_down_arrow(); + } else if (e.keyCode == '13') { + this.on_enter_key(); + } + } + }); + } + } + + make_overlay() {} + bind_overlay() {} + + on_left_arrow() {} + on_right_arrow() {} + on_up_arrow() {} + on_down_arrow() {} + on_enter_key() {} + + get_data_point(index=this.current_index) { + // check for length + let data_point = { + index: index + }; + let y = this.y[0]; + ['svg_units', 'y_tops', 'values'].map(key => { + let data_key = key.slice(0, key.length-1); + data_point[data_key] = y[key][index]; + }); + data_point.label = this.x[index]; + return data_point; + } + + update_current_data_point(index) { + if(index < 0) index = 0; + if(index >= this.x.length) index = this.x.length - 1; + if(index === this.current_index) return; + this.current_index = index; + $.fire(this.parent, "data-select", this.get_data_point()); + } + + // Helpers + get_strwidth(string) { + return string.length * 8; + } + + // Objects + setup_utils() { } +} diff --git a/src/scripts/charts/Heatmap.js b/src/scripts/charts/Heatmap.js new file mode 100644 index 0000000..e09747e --- /dev/null +++ b/src/scripts/charts/Heatmap.js @@ -0,0 +1,303 @@ +import BaseChart from './BaseChart'; +import $ from '../helpers/dom'; + +export default class Heatmap extends BaseChart { + constructor({ + start = '', + domain = '', + subdomain = '', + data = {}, + discrete_domains = 0, + count_label = '' + }) { + super(arguments[0]); + + this.type = 'heatmap'; + + this.domain = domain; + this.subdomain = subdomain; + this.data = data; + this.discrete_domains = discrete_domains; + this.count_label = count_label; + + let today = new Date(); + this.start = start || this.add_days(today, 365); + + this.legend_colors = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127']; + + this.translate_x = 0; + this.setup(); + } + + setup_base_values() { + this.today = new Date(); + + if(!this.start) { + this.start = new Date(); + this.start.setFullYear( this.start.getFullYear() - 1 ); + } + this.first_week_start = new Date(this.start.toDateString()); + this.last_week_start = new Date(this.today.toDateString()); + if(this.first_week_start.getDay() !== 7) { + this.add_days(this.first_week_start, (-1) * this.first_week_start.getDay()); + } + if(this.last_week_start.getDay() !== 7) { + this.add_days(this.last_week_start, (-1) * this.last_week_start.getDay()); + } + this.no_of_cols = this.get_weeks_between(this.first_week_start + '', this.last_week_start + '') + 1; + } + + set_width() { + this.base_width = (this.no_of_cols) * 12; + + if(this.discrete_domains) { + this.base_width += (12 * 12); + } + } + + setup_components() { + this.domain_label_group = $.createSVG("g", { + className: "domain-label-group chart-label", + inside: this.draw_area + }); + this.data_groups = $.createSVG("g", { + className: "data-groups", + inside: this.draw_area, + transform: `translate(0, 20)` + }); + } + + setup_values() { + this.domain_label_group.textContent = ''; + this.data_groups.textContent = ''; + this.distribution = this.get_distribution(this.data, this.legend_colors); + this.month_names = ["January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + ]; + + this.render_all_weeks_and_store_x_values(this.no_of_cols); + } + + render_all_weeks_and_store_x_values(no_of_weeks) { + let current_week_sunday = new Date(this.first_week_start); + this.week_col = 0; + this.current_month = current_week_sunday.getMonth(); + + this.months = [this.current_month + '']; + this.month_weeks = {}, this.month_start_points = []; + this.month_weeks[this.current_month] = 0; + this.month_start_points.push(13); + + for(var i = 0; i < no_of_weeks; i++) { + let data_group, month_change = 0; + let day = new Date(current_week_sunday); + + [data_group, month_change] = this.get_week_squares_group(day, this.week_col); + this.data_groups.appendChild(data_group); + this.week_col += 1 + parseInt(this.discrete_domains && month_change); + this.month_weeks[this.current_month]++; + if(month_change) { + this.current_month = (this.current_month + 1) % 12; + this.months.push(this.current_month + ''); + this.month_weeks[this.current_month] = 1; + } + this.add_days(current_week_sunday, 7); + } + this.render_month_labels(); + } + + get_week_squares_group(current_date, index) { + const no_of_weekdays = 7; + const square_side = 10; + const cell_padding = 2; + const step = 1; + + let month_change = 0; + let week_col_change = 0; + + let data_group = $.createSVG("g", { + className: "data-group", + inside: this.data_groups + }); + + for(var y = 0, i = 0; i < no_of_weekdays; i += step, y += (square_side + cell_padding)) { + let data_value = 0; + let color_index = 0; + + let timestamp = Math.floor(current_date.getTime()/1000).toFixed(1); + + if(this.data[timestamp]) { + data_value = this.data[timestamp]; + color_index = this.get_max_checkpoint(data_value, this.distribution); + } + + if(this.data[Math.round(timestamp)]) { + data_value = this.data[Math.round(timestamp)]; + color_index = this.get_max_checkpoint(data_value, this.distribution); + } + + let x = 13 + (index + week_col_change) * 12; + + $.createSVG("rect", { + className: 'day', + inside: data_group, + x: x, + y: y, + width: square_side, + height: square_side, + fill: this.legend_colors[color_index], + 'data-date': this.get_dd_mm_yyyy(current_date), + 'data-value': data_value, + 'data-day': current_date.getDay() + }); + + let next_date = new Date(current_date); + this.add_days(next_date, 1); + if(next_date.getMonth() - current_date.getMonth()) { + month_change = 1; + if(this.discrete_domains) { + week_col_change = 1; + } + + this.month_start_points.push(13 + (index + week_col_change) * 12); + } + current_date = next_date; + } + + return [data_group, month_change]; + } + + render_month_labels() { + // this.first_month_label = 1; + // if (this.first_week_start.getDate() > 8) { + // this.first_month_label = 0; + // } + // this.last_month_label = 1; + + // let first_month = this.months.shift(); + // let first_month_start = this.month_start_points.shift(); + // render first month if + + // let last_month = this.months.pop(); + // let last_month_start = this.month_start_points.pop(); + // render last month if + + this.months.shift(); + this.month_start_points.shift(); + this.months.pop(); + this.month_start_points.pop(); + + this.month_start_points.map((start, i) => { + let month_name = this.month_names[this.months[i]].substring(0, 3); + + $.createSVG('text', { + className: 'y-value-text', + inside: this.domain_label_group, + x: start + 12, + y: 10, + dy: '.32em', + innerHTML: month_name + }); + + }); + } + + make_graph_components() { + Array.prototype.slice.call( + this.container.querySelectorAll('.graph-stats-container, .sub-title, .title') + ).map(d => { + d.style.display = 'None'; + }); + this.chart_wrapper.style.marginTop = '0px'; + this.chart_wrapper.style.paddingTop = '0px'; + } + + bind_tooltip() { + Array.prototype.slice.call( + document.querySelectorAll(".data-group .day") + ).map(el => { + el.addEventListener('mouseenter', (e) => { + let count = e.target.getAttribute('data-value'); + let date_parts = e.target.getAttribute('data-date').split('-'); + + let month = this.month_names[parseInt(date_parts[1])-1].substring(0, 3); + + let g_off = this.chart_wrapper.getBoundingClientRect(), p_off = e.target.getBoundingClientRect(); + + let width = parseInt(e.target.getAttribute('width')); + let x = p_off.left - g_off.left + (width+2)/2; + let y = p_off.top - g_off.top - (width+2)/2; + let value = count + ' ' + this.count_label; + let name = ' on ' + month + ' ' + date_parts[0] + ', ' + date_parts[2]; + + this.tip.set_values(x, y, name, value, [], 1); + this.tip.show_tip(); + }); + }); + } + + update(data) { + this.data = data; + this.setup_values(); + this.bind_tooltip(); + } + + get_distribution(data={}, mapper_array) { + let data_values = Object.keys(data).map(key => data[key]); + let data_max_value = Math.max(...data_values); + + let distribution_step = 1 / (mapper_array.length - 1); + let distribution = []; + + mapper_array.map((color, i) => { + let checkpoint = data_max_value * (distribution_step * i); + distribution.push(checkpoint); + }); + + return distribution; + } + + get_max_checkpoint(value, distribution) { + return distribution.filter((d, i) => { + if(i === 1) { + return distribution[0] < value; + } + return d <= value; + }).length - 1; + } + + // TODO: date utils, move these out + + // https://stackoverflow.com/a/11252167/6495043 + treat_as_utc(date_str) { + let result = new Date(date_str); + result.setMinutes(result.getMinutes() - result.getTimezoneOffset()); + return result; + } + + get_dd_mm_yyyy(date) { + let dd = date.getDate(); + let mm = date.getMonth() + 1; // getMonth() is zero-based + return [ + (dd>9 ? '' : '0') + dd, + (mm>9 ? '' : '0') + mm, + date.getFullYear() + ].join('-'); + } + + get_weeks_between(start_date_str, end_date_str) { + return Math.ceil(this.get_days_between(start_date_str, end_date_str) / 7); + } + + get_days_between(start_date_str, end_date_str) { + let milliseconds_per_day = 24 * 60 * 60 * 1000; + return (this.treat_as_utc(end_date_str) - this.treat_as_utc(start_date_str)) / milliseconds_per_day; + } + + // mutates + add_days(date, number_of_days) { + date.setDate(date.getDate() + number_of_days); + } + + get_month_name() {} +} diff --git a/src/scripts/charts/LineChart.js b/src/scripts/charts/LineChart.js new file mode 100644 index 0000000..7c650ce --- /dev/null +++ b/src/scripts/charts/LineChart.js @@ -0,0 +1,95 @@ +import AxisChart from './AxisChart'; +import $ from '../helpers/dom'; + +export default class LineChart extends AxisChart { + constructor(args) { + super(args); + if(Object.getPrototypeOf(this) !== LineChart.prototype) { + return; + } + + this.type = 'line'; + this.region_fill = args.region_fill; + this.x_axis_mode = args.x_axis_mode || 'span'; + this.y_axis_mode = args.y_axis_mode || 'span'; + + this.setup(); + } + + setup_graph_components() { + this.setup_path_groups(); + super.setup_graph_components(); + } + + setup_path_groups() { + this.paths_groups = []; + this.y.map((d, i) => { + this.paths_groups[i] = $.createSVG('g', { + className: 'path-group path-group-' + i, + inside: this.draw_area + }); + }); + } + + setup_values() { + super.setup_values(); + this.unit_args = { + type: 'dot', + args: { radius: 8 } + }; + } + + make_paths() { + this.y.map((d, i) => { + this.make_path(d, i, this.x_axis_positions, d.y_tops, d.color || this.colors[i]); + }); + } + + make_path(d, i, x_positions, y_positions, color) { + let points_list = y_positions.map((y, i) => (x_positions[i] + ',' + y)); + let points_str = points_list.join("L"); + + this.paths_groups[i].textContent = ''; + + d.path = $.createSVG('path', { + inside: this.paths_groups[i], + className: `stroke ${color}`, + d: "M"+points_str + }); + + if(this.region_fill) { + let gradient_id ='path-fill-gradient' + '-' + color; + + this.gradient_def = $.createSVG('linearGradient', { + inside: this.svg_defs, + id: gradient_id, + x1: 0, + x2: 0, + y1: 0, + y2: 1 + }); + + let set_gradient_stop = (grad_elem, offset, color, opacity) => { + $.createSVG('stop', { + 'className': 'stop-color ' + color, + 'inside': grad_elem, + 'offset': offset, + 'stop-opacity': opacity + }); + }; + + set_gradient_stop(this.gradient_def, "0%", color, 0.4); + set_gradient_stop(this.gradient_def, "50%", color, 0.2); + set_gradient_stop(this.gradient_def, "100%", color, 0); + + d.region_path = $.createSVG('path', { + inside: this.paths_groups[i], + className: `region-fill`, + d: "M" + `0,${this.zero_line}L` + points_str + `L${this.width},${this.zero_line}`, + }); + + d.region_path.style.stroke = "none"; + d.region_path.style.fill = `url(#${gradient_id})`; + } + } +} diff --git a/src/scripts/charts/PercentageChart.js b/src/scripts/charts/PercentageChart.js new file mode 100644 index 0000000..3b5299a --- /dev/null +++ b/src/scripts/charts/PercentageChart.js @@ -0,0 +1,139 @@ +import BaseChart from './BaseChart'; +import $ from '../helpers/dom'; + +export default class PercentageChart extends BaseChart { + constructor(args) { + super(args); + this.type = 'percentage'; + + this.get_y_label = this.format_lambdas.y_label; + this.get_x_tooltip = this.format_lambdas.x_tooltip; + this.get_y_tooltip = this.format_lambdas.y_tooltip; + + this.max_slices = 10; + this.max_legend_points = 6; + + this.colors = args.colors; + + if(!this.colors || this.colors.length < this.data.labels.length) { + this.colors = ['light-blue', 'blue', 'violet', 'red', 'orange', + 'yellow', 'green', 'light-green', 'purple', 'magenta']; + } + + this.setup(); + } + + make_chart_area() { + this.chart_wrapper.className += ' ' + 'graph-focus-margin'; + this.chart_wrapper.style.marginTop = '45px'; + + this.stats_wrapper.className += ' ' + 'graph-focus-margin'; + this.stats_wrapper.style.marginBottom = '30px'; + this.stats_wrapper.style.paddingTop = '0px'; + } + + make_draw_area() { + this.chart_div = $.create('div', { + className: 'div', + inside: this.chart_wrapper, + width: this.base_width, + height: this.base_height + }); + + this.chart = $.create('div', { + className: 'progress-chart', + inside: this.chart_div + }); + } + + setup_components() { + this.percentage_bar = $.create('div', { + className: 'progress', + inside: this.chart + }); + } + + setup_values() { + this.slice_totals = []; + let all_totals = this.data.labels.map((d, i) => { + let total = 0; + this.data.datasets.map(e => { + total += e.values[i]; + }); + return [total, d]; + }).filter(d => { return d[0] > 0; }); // keep only positive results + + let totals = all_totals; + + if(all_totals.length > this.max_slices) { + all_totals.sort((a, b) => { return b[0] - a[0]; }); + + totals = all_totals.slice(0, this.max_slices-1); + let others = all_totals.slice(this.max_slices-1); + + let sum_of_others = 0; + others.map(d => {sum_of_others += d[0];}); + + totals.push([sum_of_others, 'Rest']); + + this.colors[this.max_slices-1] = 'grey'; + } + + this.labels = []; + totals.map(d => { + this.slice_totals.push(d[0]); + this.labels.push(d[1]); + }); + + this.legend_totals = this.slice_totals.slice(0, this.max_legend_points); + } + + setup_utils() { } + + make_graph_components() { + this.grand_total = this.slice_totals.reduce((a, b) => a + b, 0); + this.slices = []; + this.slice_totals.map((total, i) => { + let slice = $.create('div', { + className: `progress-bar background ${this.colors[i]}`, + style: `width: ${total*100/this.grand_total}%`, + inside: this.percentage_bar + }); + this.slices.push(slice); + }); + } + + bind_tooltip() { + this.slices.map((slice, i) => { + slice.addEventListener('mouseenter', () => { + let g_off = $.offset(this.chart_wrapper), p_off = $.offset(slice); + + let x = p_off.left - g_off.left + slice.offsetWidth/2; + let y = p_off.top - g_off.top - 6; + let title = (this.formatted_labels && this.formatted_labels.length>0 + ? this.formatted_labels[i] : this.labels[i]) + ': '; + let percent = (this.slice_totals[i]*100/this.grand_total).toFixed(1); + + this.tip.set_values(x, y, title, percent + "%"); + this.tip.show_tip(); + }); + }); + } + + show_summary() { + let x_values = this.formatted_labels && this.formatted_labels.length > 0 + ? this.formatted_labels : this.labels; + this.legend_totals.map((d, i) => { + if(d) { + let stats = $.create('div', { + className: 'stats', + inside: this.stats_wrapper + }); + stats.innerHTML = ` + ${x_values[i]}: + ${d} + `; + } + }); + } +} diff --git a/src/dom.js b/src/scripts/helpers/dom.js similarity index 100% rename from src/dom.js rename to src/scripts/helpers/dom.js diff --git a/src/utils.js b/src/scripts/helpers/utils.js similarity index 100% rename from src/utils.js rename to src/scripts/helpers/utils.js diff --git a/src/scripts/objects/SvgTip.js b/src/scripts/objects/SvgTip.js new file mode 100644 index 0000000..b24eab9 --- /dev/null +++ b/src/scripts/objects/SvgTip.js @@ -0,0 +1,111 @@ +import $ from '../helpers/dom'; + +export default class SvgTip { + constructor({ + parent = null + }) { + this.parent = parent; + this.title_name = ''; + this.title_value = ''; + this.list_values = []; + this.title_value_first = 0; + + this.x = 0; + this.y = 0; + + this.top = 0; + this.left = 0; + + this.setup(); + } + + setup() { + this.make_tooltip(); + } + + refresh() { + this.fill(); + this.calc_position(); + // this.show_tip(); + } + + make_tooltip() { + this.container = $.create('div', { + inside: this.parent, + className: 'graph-svg-tip comparison', + innerHTML: ` +
        +
        ` + }); + this.hide_tip(); + + this.title = this.container.querySelector('.title'); + this.data_point_list = this.container.querySelector('.data-point-list'); + + this.parent.addEventListener('mouseleave', () => { + this.hide_tip(); + }); + } + + fill() { + let title; + if(this.title_value_first) { + title = `${this.title_value}${this.title_name}`; + } else { + title = `${this.title_name}${this.title_value}`; + } + this.title.innerHTML = title; + this.data_point_list.innerHTML = ''; + + this.list_values.map((set) => { + let li = $.create('li', { + className: `border-top ${set.color || 'black'}`, + innerHTML: `${set.value ? set.value : '' } + ${set.title ? set.title : '' }` + }); + + this.data_point_list.appendChild(li); + }); + } + + calc_position() { + this.top = this.y - this.container.offsetHeight; + this.left = this.x - this.container.offsetWidth/2; + let max_left = this.parent.offsetWidth - this.container.offsetWidth; + + let pointer = this.container.querySelector('.svg-pointer'); + + if(this.left < 0) { + pointer.style.left = `calc(50% - ${-1 * this.left}px)`; + this.left = 0; + } else if(this.left > max_left) { + let delta = this.left - max_left; + pointer.style.left = `calc(50% + ${delta}px)`; + this.left = max_left; + } else { + pointer.style.left = `50%`; + } + } + + set_values(x, y, title_name = '', title_value = '', list_values = [], title_value_first = 0) { + this.title_name = title_name; + this.title_value = title_value; + this.list_values = list_values; + this.x = x; + this.y = y; + this.title_value_first = title_value_first; + this.refresh(); + } + + hide_tip() { + this.container.style.top = '0px'; + this.container.style.left = '0px'; + this.container.style.opacity = '0'; + } + + show_tip() { + this.container.style.top = this.top + 'px'; + this.container.style.left = this.left + 'px'; + this.container.style.opacity = '1'; + } +}