UNPKG

@ux-aspects/ux-aspects

Version:

Open source user interface framework for building modern, responsive, mobile big data applications

757 lines 115 kB
import { END, HOME, LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes'; import { NgModule } from '@angular/core'; import * as i0 from "@angular/core"; const timelineDefaultOptions = { timeline: { backgroundColor: '#f1f2f3', selectionColor: 'rgba(198, 23, 157, 0.15)', // eslint-disable-next-line @typescript-eslint/no-empty-function onChange: function onChange() { }, keyboard: { step: 2_592_000_000, // 30 days }, handles: { backgroundColor: '#000', foregroundColor: '#dcdedf', focusIndicatorColor: 'rgba(0, 115, 231, 0.5)', }, range: { lower: null, upper: null, minimum: 0, maximum: Infinity, }, state: { lowerHandleFocus: false, upperHandleFocus: false, rangeHandleFocus: false, }, }, }; export class TimelineChartPlugin { constructor() { this.id = 'timeline-chart-plugin'; } /** We only want to register the plugin once per application */ static { this._isRegistered = false; } /** Register this plugin */ static register() { /** * We have to register this plugin globally because * ng2-charts doesn't support plugins on an invidual * basis. We must check in all lifecycle hooks that * it is an timeline chart before performing any actions. * * We also need to have it inside the class otherwise it * will be included in every application by default. * Having it here allows it to be tree-shaken. */ if (!this._isRegistered) { // if pluginService exists then we are in v2 if (window.Chart?.pluginService) { window.Chart.pluginService.register(new TimelineChartPlugin()); } else { import('chart.js').then(({ Chart }) => { Chart.register(new TimelineChartPlugin()); }); } this._isRegistered = true; } } isVersion3() { return window.Chart?.pluginService ? false : true; } /** * When chart is initialised store the chart instance and context * for use outside lifecycle hooks. * * We should also supply default options for any options that have * not been specified by the consuming application. * * We also need to add some event listeners for events that Chart.js * does not inform us of. */ beforeInit(chart) { // provide the default options for any missing properties if (this.getEnabled(chart)) { // chart.config.options.timeline = { ...timelineDefaultOptions.timeline, ...this.getOptions(chart) }; chart.config.options.timeline = this.getOptionsWithDefaults(this.getOptions(chart)); // get the range const { lower, upper } = this.getRange(chart); // ensure we have an initial range set if (lower === null || upper === null) { throw new Error('Timeline Chart - Ensure that both an upper and lower range are initially provided.'); } // setup the function chart.config.options.timeline.state.onMouseDown = () => this.onMouseDown(chart); chart.config.options.timeline.state.onMouseUp = () => this.onMouseUp(chart); // add mouse down and mouseup event listeners chart.canvas.addEventListener('mousedown', chart.config.options.timeline.state.onMouseDown); document.addEventListener('mouseup', chart.config.options.timeline.state.onMouseUp); } } /** * We want to setup some additional functionality * after the chart has initialized. */ afterInit(chart) { if (this.getEnabled(chart)) { // add accessibility attributes and elements to the chart this.setupAccessibility(chart); // intially call the onChange function this.triggerOnChange(chart); } } /** * The timeline chart should have a subtle background * color behind the main chart area (excluding the axis area). * Suprisingly Chart.js does not support this out of the box * so we need to add this functionality but it should be behind * all chart elements. */ beforeDraw(chart) { if (this.getEnabled(chart)) { this.drawBackgroundColor(chart); } } /** * Once the Chart elements have been drawn we want to draw the drag * handles and the overlay showing the selected region */ afterDraw(chart) { if (this.getEnabled(chart)) { this.drawSelection(chart); this.drawHandles(chart); } } /** * We want to update the cursor whenever the mouse is over * one of the drag handles. We have do calculate this manually * as there are no DOM element to add CSS to. */ afterEvent(chart, parentEvent) { const event = this.isVersion3() ? parentEvent.event : parentEvent; if (parentEvent.replay === true) { return; } // skip this if timeline is not enabled if (!this.getEnabled(chart)) { return; } switch (event.type) { case 'mousemove': this.setCursor(chart, event); this.setRangeOnDrag(chart, event); this.handleMouseMove(chart, event); // store the latest mouse position this.setState(chart, { mouseX: event.x }); break; case 'mouseout': this.resetCursor(chart); this.hideTooltip(chart); break; } } /** * Unbind from the event listeners we manually set up */ destroy(chart) { if (this.getEnabled(chart)) { document.removeEventListener('mouseup', chart.config.options.timeline.state.onMouseUp, true); } } /** Get the timeline options from the chart instance */ getOptions(chart) { return chart.config.options.timeline; } /** Determine if this chart is using the timeline */ getEnabled(chart) { return !!this.getOptions(chart); } /** Get the timeline range from the chart instance */ getRange(chart) { return this.getOptions(chart).range; } /** Get the chart area but include any padding */ getChartArea(chart) { const { top, right, bottom, left } = chart.chartArea; const padding = chart.config.options.layout && chart.config.options.layout.padding ? chart.config.options.layout.padding : 0; if (typeof padding === 'number') { return { top: top - padding, right: right - padding, left: left - padding, bottom: bottom - padding, }; } else if (typeof padding === 'object') { return { top: top - padding.top, right: right - padding.right, left: left - padding.left, bottom: bottom - padding.bottom, }; } return chart.chartArea; } /** Get stored state inside the chart options */ getState(chart) { return this.getOptions(chart).state; } /** Store state inside the chart options */ setState(chart, state) { // store the latest state chart.config.options.timeline.state = { ...chart.config.options.timeline.state, ...state }; // trigger a chart re-render chart.update(); } /** Call the callback with the latest range */ triggerOnChange(chart) { // get the current date range const { lower, upper } = this.getRange(chart); // get the callback function const { onChange } = this.getOptions(chart); // call the callback with the lower and upper values requestAnimationFrame(() => onChange(lower, upper)); // get the handle elements const { lowerHandleElement, upperHandleElement } = this.getState(chart); // update the aria properties lowerHandleElement.setAttribute('aria-valuemin', new Date(this.getHandleMinimum(chart, TimelineHandle.Lower)).toDateString()); lowerHandleElement.setAttribute('aria-valuenow', lower.toDateString()); lowerHandleElement.setAttribute('aria-valuemax', new Date(this.getHandleMaximum(chart, TimelineHandle.Lower)).toDateString()); upperHandleElement.setAttribute('aria-valuemin', new Date(this.getHandleMinimum(chart, TimelineHandle.Upper)).toDateString()); upperHandleElement.setAttribute('aria-valuenow', upper.toDateString()); upperHandleElement.setAttribute('aria-valuemax', new Date(this.getHandleMaximum(chart, TimelineHandle.Upper)).toDateString()); } /** To make the chart accessible add some internal elements that can be focused */ setupAccessibility(chart) { // create the invisible elements const lowerHandle = document.createElement('div'); const upperHandle = document.createElement('div'); const rangeHandle = document.createElement('div'); // make the items focusable lowerHandle.setAttribute('tabindex', '0'); upperHandle.setAttribute('tabindex', '0'); rangeHandle.setAttribute('tabindex', '0'); // insert the elements chart.canvas.appendChild(lowerHandle); chart.canvas.appendChild(upperHandle); chart.canvas.appendChild(rangeHandle); // add the event handlers lowerHandle.addEventListener('focus', () => this.setState(chart, { lowerHandleFocus: true })); lowerHandle.addEventListener('blur', () => this.setState(chart, { lowerHandleFocus: false })); lowerHandle.addEventListener('keydown', (event) => this.onKeydown(chart, event, TimelineHandle.Lower)); upperHandle.addEventListener('focus', () => this.setState(chart, { upperHandleFocus: true })); upperHandle.addEventListener('blur', () => this.setState(chart, { upperHandleFocus: false })); upperHandle.addEventListener('keydown', (event) => this.onKeydown(chart, event, TimelineHandle.Upper)); rangeHandle.addEventListener('focus', () => this.setState(chart, { rangeHandleFocus: true })); rangeHandle.addEventListener('blur', () => this.setState(chart, { rangeHandleFocus: false })); rangeHandle.addEventListener('keydown', (event) => this.onRangeKeydown(chart, event)); // store the items in the state object this.setState(chart, { lowerHandleElement: lowerHandle, upperHandleElement: upperHandle, rangeHandleElement: rangeHandle, }); } /** Handle keyboard accessibility events */ onKeydown(chart, event, handle) { // get the current value for the given handle const value = this.getHandleValue(chart, handle).getTime(); const step = this.getOptions(chart).keyboard.step; const [minimum, maximum] = this.getChartRange(chart); switch (event.keyCode) { case LEFT_ARROW: this.setHandleValue(chart, handle, new Date(value - step)); event.preventDefault(); break; case HOME: this.setHandleValue(chart, handle, new Date(minimum)); event.preventDefault(); break; case RIGHT_ARROW: this.setHandleValue(chart, handle, new Date(value + step)); event.preventDefault(); break; case END: this.setHandleValue(chart, handle, new Date(maximum)); event.preventDefault(); break; } } /** * Handle range changes made with the keyboard as these are exempt from * many of the validation checks that are required when dragging only one * handle at a time. */ onRangeKeydown(chart, event) { // get the current handle values let lowerValue = this.getHandleValue(chart, TimelineHandle.Lower).getTime(); let upperValue = this.getHandleValue(chart, TimelineHandle.Upper).getTime(); const step = this.getOptions(chart).keyboard.step; const difference = upperValue - lowerValue; // get the chart boundaries const [minimum, maximum] = this.getChartRange(chart); switch (event.keyCode) { case LEFT_ARROW: lowerValue = Math.max(lowerValue - step, minimum); upperValue = lowerValue + difference; event.preventDefault(); break; case RIGHT_ARROW: upperValue = Math.min(upperValue + step, maximum); lowerValue = upperValue - difference; event.preventDefault(); break; case HOME: lowerValue = minimum; upperValue = lowerValue + difference; event.preventDefault(); break; case END: upperValue = maximum; lowerValue = upperValue - difference; event.preventDefault(); break; } // store the new values chart.config.options.timeline.range[TimelineHandle.Lower] = new Date(lowerValue); chart.config.options.timeline.range[TimelineHandle.Upper] = new Date(upperValue); // update the chart chart.update(); // emit the latest range this.triggerOnChange(chart); } /** * When the mouse is first pressed within a chart we should see if we are * currently over a drag handle to start the dragging */ onMouseDown(chart) { // ensure we only proceed when we have a chart context if (!chart.ctx) { return; } // get the position from the chart area const { top } = this.getChartArea(chart); // get the properties from the state const { mouseX } = this.getState(chart); // check if the event started within a drag handle const handle = this.isWithinHandle(chart, { x: mouseX, y: top }); // if it did then we are now dragging the handle and should store it this.setState(chart, { handle: handle !== null ? handle : null }); } /** When the mouse is released we are no longer dragging */ onMouseUp(chart) { if (chart.canvas) { this.setState(chart, { handle: null }); } } handleMouseMove(chart, event) { const mousePosition = this.isWithinHandle(chart, event); const timelineOptions = (this.isVersion3() ? chart.config.options : chart.options); // eslint-disable-next-line no-prototype-builtins const hasTooltipOnRange = timelineOptions.timeline.range.hasOwnProperty('tooltip'); // eslint-disable-next-line no-prototype-builtins const hasTooltipOnHandles = timelineOptions.timeline.handles.hasOwnProperty('tooltip'); let timelineTooltipText; let handleTooltipText; if (hasTooltipOnRange) { timelineTooltipText = timelineOptions.timeline.range.tooltip.label(); } if (hasTooltipOnHandles) { handleTooltipText = timelineOptions.timeline.handles.tooltip.label(); } if (mousePosition === TimelineHandle.Range && hasTooltipOnRange) { this.externalTooltipHandler(chart, TimelineHandle.Range, timelineTooltipText); } else if (mousePosition === TimelineHandle.Lower && hasTooltipOnHandles) { this.externalTooltipHandler(chart, TimelineHandle.Lower, handleTooltipText.rangeLower); } else if (mousePosition === TimelineHandle.Upper && hasTooltipOnHandles) { this.externalTooltipHandler(chart, TimelineHandle.Upper, handleTooltipText.rangeUpper); } else { this.hideTooltip(chart); } } hideTooltip(chart) { const tooltipEl = this.getOrCreateTooltip(chart); tooltipEl.style.opacity = '0'; } getOrCreateTooltip(chart) { let tooltipEl = chart.canvas.parentNode.querySelector('.timeline-tooltip'); if (!tooltipEl) { tooltipEl = document.createElement('div'); tooltipEl.classList.add('timeline-tooltip'); tooltipEl.classList.add('tooltip'); const caret = document.createElement('div'); caret.classList.add('tooltip-caret'); const span = document.createElement('span'); tooltipEl.appendChild(span); tooltipEl.appendChild(caret); chart.canvas.parentNode.appendChild(tooltipEl); } return tooltipEl; } externalTooltipHandler(chart, position, tooltipText) { // Tooltip Element const tooltipEl = this.getOrCreateTooltip(chart); const span = tooltipEl.querySelector('span'); span.innerText = tooltipText; const { x, y } = this.tooltipPositioner(chart, position); tooltipEl.style.left = x + 'px'; tooltipEl.style.top = y + 'px'; tooltipEl.style.opacity = '1'; } tooltipPositioner(chart, position) { const lower = this.getHandleArea(chart, TimelineHandle.Lower).left; const upper = this.getHandleArea(chart, TimelineHandle.Upper).left; const tooltipEl = this.getOrCreateTooltip(chart); const width = tooltipEl.getBoundingClientRect().width; const caret = tooltipEl.querySelector('.tooltip-caret'); if (position === TimelineHandle.Range) { caret.style.top = null; caret.style.right = null; caret.style.left = '50%'; caret.style.transform = 'rotate(0deg)'; const middle = (lower + upper) / 2; return { x: middle + 2, y: -14, }; } else if (position === TimelineHandle.Lower) { caret.style.top = '40%'; caret.style.right = 'auto'; caret.style.left = '-2px'; caret.style.transform = 'rotate(90deg)'; return { x: lower + (width / 2 + 20), y: 10, }; } else if (position === TimelineHandle.Upper) { caret.style.top = '40%'; caret.style.right = '-7px'; caret.style.left = 'auto'; caret.style.transform = 'rotate(-90deg)'; return { x: upper - (width / 2 + 20), y: 10, }; } } /** Update the range when dragged */ setRangeOnDrag(chart, event) { const { handle, mouseX } = this.getState(chart); // if we are not dragging then do nothing if (!handle) { return; } // get the chart area const { left, right } = this.getChartArea(chart); // get the current range const { lower, upper } = this.getRange(chart); // get the difference in x position since the last mouse position const delta = event.x - mouseX; // get the width of the chart area const width = right - left; // get the time range on the x-axis const [minimum, maximum] = this.getChartRange(chart); // determine how much of the time range was spanned in the move const percentageDiff = (delta / width) * 100; // calculate the time difference in the movement const valueDiff = ((maximum - minimum) / 100) * percentageDiff; if (handle === TimelineHandle.Lower) { this.setHandleValue(chart, TimelineHandle.Lower, new Date(lower.getTime() + valueDiff)); } if (handle === TimelineHandle.Upper) { this.setHandleValue(chart, TimelineHandle.Upper, new Date(upper.getTime() + valueDiff)); } if (handle === TimelineHandle.Range) { // get the current range const range = upper.getTime() - lower.getTime(); // update the values if (valueDiff < 0) { this.setHandleValue(chart, TimelineHandle.Upper, new Date(upper.getTime() + valueDiff)); this.setHandleValue(chart, TimelineHandle.Lower, new Date(lower.getTime() + valueDiff)); } else { this.setHandleValue(chart, TimelineHandle.Lower, new Date(lower.getTime() + valueDiff)); this.setHandleValue(chart, TimelineHandle.Upper, new Date(upper.getTime() + valueDiff)); } // calculate the new range const currentRange = chart.config.options.timeline.range.upper.getTime() - chart.config.options.timeline.range.lower.getTime(); // ensure the range is still the same if (currentRange !== range) { if (valueDiff < 0) { this.setHandleValue(chart, TimelineHandle.Upper, new Date(chart.config.options.timeline.range.upper.getTime() + (range - currentRange))); } else { this.setHandleValue(chart, TimelineHandle.Lower, new Date(chart.config.options.timeline.range.lower.getTime() + (currentRange - range))); } } } } /** * Draw the background color in the region that sits behind all the chart content */ drawBackgroundColor(chart) { // get the region that the chart is drawn on (excluding axis) const { top, right, bottom, left } = this.getChartArea(chart); // fill the background color chart.ctx.save(); chart.ctx.fillStyle = this.getOptions(chart).backgroundColor; chart.ctx.fillRect(left, top, right - left, bottom - top); chart.ctx.restore(); } /** Draw the overlay that indicates the selected region */ drawSelection(chart) { // get the region that the chart is drawn on (excluding axis) const { top, bottom } = this.getChartArea(chart); // get the fill color const selectionColor = this.getOptions(chart).selectionColor; // get the focus indicator color const { focusIndicatorColor } = this.getOptions(chart).handles; // get the lower and upper handle render regions const lower = this.getHandleArea(chart, TimelineHandle.Lower); const upper = this.getHandleArea(chart, TimelineHandle.Upper); // draw selection region chart.ctx.save(); chart.ctx.fillStyle = selectionColor; chart.ctx.fillRect(lower.left, 0, upper.right - lower.left, bottom - top); // check if we are focused on the range handle if (this.isHandleFocused(chart, TimelineHandle.Range)) { chart.ctx.strokeStyle = focusIndicatorColor; const handleWidth = 4; const lineWidth = 2; chart.ctx.lineWidth = lineWidth; chart.ctx.strokeRect(lower.left + handleWidth + lineWidth, lineWidth / 2, upper.right - lower.left - (handleWidth + lineWidth) * 2, bottom - top - lineWidth); } chart.ctx.restore(); } /** Darw the drag handles */ drawHandles(chart) { // get the region that the chart is drawn on (excluding axis) const { top, bottom } = this.getChartArea(chart); // get the handle colors const { backgroundColor, foregroundColor, focusIndicatorColor } = this.getOptions(chart).handles; // draw each handle [TimelineHandle.Lower, TimelineHandle.Upper].forEach(handle => { // get the area of the handle const area = this.getHandleArea(chart, handle); const handleWidth = 5; const chartHeight = bottom - top; chart.ctx.save(); // if the handle is focused draw an outline if (this.isHandleFocused(chart, handle)) { chart.ctx.fillStyle = focusIndicatorColor; chart.ctx.fillRect(area.left - 2, 0, handleWidth + 4, chartHeight); } // draw the handle chart.ctx.fillStyle = backgroundColor; chart.ctx.fillRect(area.left, 0, handleWidth, chartHeight); // draw the 3 drag handles within the drag handle chart.ctx.fillStyle = foregroundColor; // calculate size and position const width = 3; const height = 3; const x = area.left + (handleWidth - width) / 2; const midpoint = area.top + chartHeight / 2; const topY = midpoint - height * 2.5; const middleY = midpoint - height / 2; const bottomY = midpoint + height * 1.5; chart.ctx.fillRect(x, topY, width, height); chart.ctx.fillRect(x, middleY, width, height); chart.ctx.fillRect(x, bottomY, width, height); chart.ctx.restore(); }); } /** * Update the CSS cursor on the canvas element if we are hovering over a drag handle */ setCursor(chart, event) { // get the handle if we are hovering over one const handle = this.getState(chart).handle || this.isWithinHandle(chart, event); if (handle === TimelineHandle.Lower || handle === TimelineHandle.Upper) { chart.canvas.style.cursor = 'ew-resize'; } else if (handle === TimelineHandle.Range) { chart.canvas.style.cursor = 'move'; } else { this.resetCursor(chart); } } // restore the cursor to the default resetCursor(chart) { if (chart.canvas.style.cursor !== '') { chart.canvas.style.cursor = ''; } } isHandleFocused(chart, handle) { if (handle === TimelineHandle.Lower) { return this.getState(chart).lowerHandleFocus; } if (handle === TimelineHandle.Upper) { return this.getState(chart).upperHandleFocus; } if (handle === TimelineHandle.Range) { return this.getState(chart).rangeHandleFocus; } return false; } /** Determine if a position is within one of the drag handles */ isWithinHandle(chart, event) { // get the lower and upper handle render regions const lower = this.getHandleArea(chart, TimelineHandle.Lower); const upper = this.getHandleArea(chart, TimelineHandle.Upper); // get the position co-ordinates const { x, y } = event; if (x >= lower.left && x <= lower.right && y >= lower.top && y <= lower.bottom) { return TimelineHandle.Lower; } if (x >= upper.left && x <= upper.right && y >= upper.top && y <= upper.bottom) { return TimelineHandle.Upper; } if (x > lower.right && x < upper.left && y >= lower.top && y <= lower.bottom) { return TimelineHandle.Range; } return null; } /** Get the area a specific handle covers within the chart */ getHandleArea(chart, handle) { // get the region that the chart is drawn on (excluding axis) const { left, top, right, bottom } = this.getChartArea(chart); // perform some calculations on the chart area const width = right - left; // get the minimum and maximum ticks on the chart const [minimum, maximum] = this.getChartRange(chart); // get the lower and upper range values const { lower, upper } = this.getOptions(chart).range; if (handle === TimelineHandle.Lower) { const percentage = ((lower.getTime() - minimum) / (maximum - minimum)) * 100; const position = left + (width / 100) * percentage; return { top, left: position, right: position + 5, bottom }; } if (handle === TimelineHandle.Upper) { const percentage = ((upper.getTime() - minimum) / (maximum - minimum)) * 100; const position = left + (width / 100) * percentage; return { top, left: position - 5, right: position, bottom }; } } /** * Get the minimum and maximum values on the x-axis */ getChartRange(chart) { let minimum; let maximum; if (this.isVersion3()) { // get the current data const data = chart.scales; // get the range on the x-axis minimum = data.x.min; maximum = data.x.max; } else { // get the current data const { data } = chart.getDatasetMeta(0); // get the range on the x-axis minimum = data[0]._xScale.min; maximum = data[0]._xScale.max; } return [minimum, maximum]; } /** Get the value for a given handle */ getHandleValue(chart, handle) { const { lower, upper } = this.getOptions(chart).range; return handle === TimelineHandle.Lower ? lower : upper; } setHandleValue(chart, handle, value) { // perform lower handle validation if (handle === TimelineHandle.Lower) { value = new Date(Math.min(Math.max(this.getHandleMinimum(chart, handle), value.getTime()), this.getHandleMaximum(chart, handle))); } // perform upper handle validation if (handle === TimelineHandle.Upper) { value = new Date(Math.max(Math.min(this.getHandleMaximum(chart, handle), value.getTime()), this.getHandleMinimum(chart, handle))); } // store the new value chart.config.options.timeline.range[handle] = value; // update the chart chart.update(); // emit the latest range this.triggerOnChange(chart); } getHandleMinimum(chart, handle) { // get the minimum distance const minDistance = this.getOptions(chart).range.minimum || 0; const maxDistance = this.getOptions(chart).range.maximum || Infinity; // get the chart boundaries const [minimum] = this.getChartRange(chart); // get the current date range const { lower, upper } = this.getRange(chart); if (handle === TimelineHandle.Lower) { return Math.max(upper.getTime() - maxDistance, minimum); } if (handle === TimelineHandle.Upper) { return lower.getTime() + minDistance; } } getHandleMaximum(chart, handle) { // get the minimum distance const minDistance = this.getOptions(chart).range.minimum || 0; const maxDistance = this.getOptions(chart).range.maximum || Infinity; // get the chart boundaries const [, maximum] = this.getChartRange(chart); // get the current date range const { lower, upper } = this.getRange(chart); if (handle === TimelineHandle.Lower) { return upper.getTime() - minDistance; } if (handle === TimelineHandle.Upper) { return Math.min(lower.getTime() + maxDistance, maximum); } } getOptionsWithDefaults(options) { const merge = (target, source) => { for (const key of Object.keys(source)) { if (source[key] instanceof Object && !(source[key] instanceof Date) && typeof source[key] !== 'function') { Object.assign(source[key], merge(target[key], source[key])); } } return Object.assign(target || {}, source); }; return merge({ ...timelineDefaultOptions.timeline }, options); } } /** * Directly exporting a file that is not an Angular component, module, etc.. * can cause build issues. We can use a module that instantiates the plugin * instead of directly exporting the Chart.js plugin. */ export class TimelineChartModule { constructor() { TimelineChartPlugin.register(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TimelineChartModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.12", ngImport: i0, type: TimelineChartModule }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TimelineChartModule }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: TimelineChartModule, decorators: [{ type: NgModule, args: [{}] }], ctorParameters: () => [] }); export var TimelineHandle; (function (TimelineHandle) { TimelineHandle["Lower"] = "lower"; TimelineHandle["Upper"] = "upper"; TimelineHandle["Range"] = "range"; })(TimelineHandle || (TimelineHandle = {})); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZWxpbmUtY2hhcnQubW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL3BsdWdpbnMvY2hhcnRqcy90aW1lbGluZS90aW1lbGluZS1jaGFydC5tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzNFLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7O0FBR3pDLE1BQU0sc0JBQXNCLEdBQXFEO0lBQy9FLFFBQVEsRUFBRTtRQUNSLGVBQWUsRUFBRSxTQUFTO1FBQzFCLGNBQWMsRUFBRSwwQkFBMEI7UUFDMUMsZ0VBQWdFO1FBQ2hFLFFBQVEsRUFBRSxTQUFTLFFBQVEsS0FBSSxDQUFDO1FBQ2hDLFFBQVEsRUFBRTtZQUNSLElBQUksRUFBRSxhQUFhLEVBQUUsVUFBVTtTQUNoQztRQUNELE9BQU8sRUFBRTtZQUNQLGVBQWUsRUFBRSxNQUFNO1lBQ3ZCLGVBQWUsRUFBRSxTQUFTO1lBQzFCLG1CQUFtQixFQUFFLHdCQUF3QjtTQUM5QztRQUNELEtBQUssRUFBRTtZQUNMLEtBQUssRUFBRSxJQUFJO1lBQ1gsS0FBSyxFQUFFLElBQUk7WUFDWCxPQUFPLEVBQUUsQ0FBQztZQUNWLE9BQU8sRUFBRSxRQUFRO1NBQ2xCO1FBQ0QsS0FBSyxFQUFFO1lBQ0wsZ0JBQWdCLEVBQUUsS0FBSztZQUN2QixnQkFBZ0IsRUFBRSxLQUFLO1lBQ3ZCLGdCQUFnQixFQUFFLEtBQUs7U0FDeEI7S0FDRjtDQUNGLENBQUM7QUFFRixNQUFNLE9BQU8sbUJBQW1CO0lBQWhDO1FBQ0UsT0FBRSxHQUFXLHVCQUF1QixDQUFDO0lBMDRCdkMsQ0FBQztJQXg0QkMsK0RBQStEO2FBQ2hELGtCQUFhLEdBQVksS0FBSyxBQUFqQixDQUFrQjtJQUU5QywyQkFBMkI7SUFDM0IsTUFBTSxDQUFDLFFBQVE7UUFDYjs7Ozs7Ozs7O1dBU0c7UUFDSCxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQ3hCLDRDQUE0QztZQUM1QyxJQUFLLE1BQWMsQ0FBQyxLQUFLLEVBQUUsYUFBYSxFQUFFLENBQUM7Z0JBQ3hDLE1BQWMsQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxJQUFJLG1CQUFtQixFQUFFLENBQUMsQ0FBQztZQUMxRSxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRTtvQkFDbkMsS0FBYSxDQUFDLFFBQVEsQ0FBQyxJQUFJLG1CQUFtQixFQUFFLENBQUMsQ0FBQztnQkFDckQsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDO1lBRUQsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUM7UUFDNUIsQ0FBQztJQUNILENBQUM7SUFFRCxVQUFVO1FBQ1IsT0FBUSxNQUFjLENBQUMsS0FBSyxFQUFFLGFBQWEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDN0QsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNILFVBQVUsQ0FBQyxLQUFvQjtRQUM3Qix5REFBeUQ7UUFDekQsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDM0IscUdBQXFHO1lBQ3JHLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBRXBGLGdCQUFnQjtZQUNoQixNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7WUFFOUMsc0NBQXNDO1lBQ3RDLElBQUksS0FBSyxLQUFLLElBQUksSUFBSSxLQUFLLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQ3JDLE1BQU0sSUFBSSxLQUFLLENBQ2Isb0ZBQW9GLENBQ3JGLENBQUM7WUFDSixDQUFDO1lBRUQscUJBQXFCO1lBQ3JCLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsV0FBVyxHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDaEYsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxTQUFTLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUU1RSw2Q0FBNkM7WUFDN0MsS0FBSyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxXQUFXLEVBQUUsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUM1RixRQUFRLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDdEYsQ0FBQztJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSCxTQUFTLENBQUMsS0FBb0I7UUFDNUIsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDM0IseURBQXlEO1lBQ3pELElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUUvQixzQ0FBc0M7WUFDdEMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM5QixDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILFVBQVUsQ0FBQyxLQUFvQjtRQUM3QixJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUMzQixJQUFJLENBQUMsbUJBQW1CLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbEMsQ0FBQztJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSCxTQUFTLENBQUMsS0FBb0I7UUFDNUIsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDM0IsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUMxQixJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzFCLENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILFVBQVUsQ0FBQyxLQUFvQixFQUFFLFdBQWdCO1FBQy9DLE1BQU0sS0FBSyxHQUFlLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDO1FBRTlFLElBQUksV0FBVyxDQUFDLE1BQU0sS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUNoQyxPQUFPO1FBQ1QsQ0FBQztRQUVELHVDQUF1QztRQUN2QyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzVCLE9BQU87UUFDVCxDQUFDO1FBRUQsUUFBUSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDbkIsS0FBSyxXQUFXO2dCQUNkLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLEtBQW1CLENBQUMsQ0FBQztnQkFDM0MsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsS0FBbUIsQ0FBQyxDQUFDO2dCQUNoRCxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssRUFBRSxLQUFtQixDQUFDLENBQUM7Z0JBRWpELGtDQUFrQztnQkFDbEMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQzFDLE1BQU07WUFFUixLQUFLLFVBQVU7Z0JBQ2IsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDeEIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDeEIsTUFBTTtRQUNWLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxPQUFPLENBQUMsS0FBb0I7UUFDMUIsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDM0IsUUFBUSxDQUFDLG1CQUFtQixDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUMvRixDQUFDO0lBQ0gsQ0FBQztJQUVELHVEQUF1RDtJQUMvQyxVQUFVLENBQUMsS0FBb0I7UUFDckMsT0FBTyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUM7SUFDdkMsQ0FBQztJQUVELG9EQUFvRDtJQUM1QyxVQUFVLENBQUMsS0FBb0I7UUFDckMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBRUQscURBQXFEO0lBQzdDLFFBQVEsQ0FBQyxLQUFvQjtRQUNuQyxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQ3RDLENBQUM7SUFFRCxpREFBaUQ7SUFDekMsWUFBWSxDQUFDLEtBQW9CO1FBQ3ZDLE1BQU0sRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDO1FBQ3JELE1BQU0sT0FBTyxHQUNYLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsT0FBTztZQUNoRSxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLE9BQU87WUFDckMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUVSLElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDaEMsT0FBTztnQkFDTCxHQUFHLEVBQUUsR0FBRyxHQUFHLE9BQU87Z0JBQ2xCLEtBQUssRUFBRSxLQUFLLEdBQUcsT0FBTztnQkFDdEIsSUFBSSxFQUFFLElBQUksR0FBRyxPQUFPO2dCQUNwQixNQUFNLEVBQUUsTUFBTSxHQUFHLE9BQU87YUFDekIsQ0FBQztRQUNKLENBQUM7YUFBTSxJQUFJLE9BQU8sT0FBTyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ3ZDLE9BQU87Z0JBQ0wsR0FBRyxFQUFFLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRztnQkFDdEIsS0FBSyxFQUFFLEtBQUssR0FBRyxPQUFPLENBQUMsS0FBSztnQkFDNUIsSUFBSSxFQUFFLElBQUksR0FBRyxPQUFPLENBQUMsSUFBSTtnQkFDekIsTUFBTSxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTTthQUNoQyxDQUFDO1FBQ0osQ0FBQztRQUVELE9BQU8sS0FBSyxDQUFDLFNBQVMsQ0FBQztJQUN6QixDQUFDO0lBRUQsZ0RBQWdEO0lBQ3hDLFFBQVEsQ0FBQyxLQUFvQjtRQUNuQyxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQ3RDLENBQUM7SUFFRCwyQ0FBMkM7SUFDbkMsUUFBUSxDQUFDLEtBQW9CLEVBQUUsS0FBeUI7UUFDOUQseUJBQXlCO1FBQ3pCLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLEdBQUcsRUFBRSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsR0FBRyxLQUFLLEVBQUUsQ0FBQztRQUUzRiw0QkFBNEI7UUFDNUIsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQ2pCLENBQUM7SUFFRCw4Q0FBOEM7SUFDdEMsZUFBZSxDQUFDLEtBQW9CO1FBQzFDLDZCQUE2QjtRQUM3QixNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFOUMsNEJBQTRCO1FBQzVCLE1BQU0sRUFBRSxRQUFRLEVBQUUsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRTVDLG9EQUFvRDtRQUNwRCxxQkFBcUIsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFFcEQsMEJBQTBCO1FBQzFCLE1BQU0sRUFBRSxrQkFBa0IsRUFBRSxrQkFBa0IsRUFBRSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFeEUsNkJBQTZCO1FBQzdCLGtCQUFrQixDQUFDLFlBQVksQ0FDN0IsZUFBZSxFQUNmLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsWUFBWSxFQUFFLENBQzVFLENBQUM7UUFDRixrQkFBa0IsQ0FBQyxZQUFZLENBQUMsZUFBZSxFQUFFLEtBQUssQ0FBQyxZQUFZLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZFLGtCQUFrQixDQUFDLFlBQVksQ0FDN0IsZUFBZSxFQUNmLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsWUFBWSxFQUFFLENBQzVFLENBQUM7UUFDRixrQkFBa0IsQ0FBQyxZQUFZLENBQzdCLGVBQWUsRUFDZixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFlBQVksRUFBRSxDQUM1RSxDQUFDO1FBQ0Ysa0JBQWtCLENBQUMsWUFBWSxDQUFDLGVBQWUsRUFBRSxLQUFLLENBQUMsWUFBWSxFQUFFLENBQUMsQ0FBQztRQUN2RSxrQkFBa0IsQ0FBQyxZQUFZLENBQzdCLGVBQWUsRUFDZixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFlBQVksRUFBRSxDQUM1RSxDQUFDO0lBQ0osQ0FBQztJQUVELGtGQUFrRjtJQUMxRSxrQkFBa0IsQ0FBQyxLQUFvQjtRQUM3QyxnQ0FBZ0M7UUFDaEMsTUFBTSxXQUFXLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNsRCxNQUFNLFdBQVcsR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2xELE1BQU0sV0FBVyxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFbEQsMkJBQTJCO1FBQzNCLFdBQVcsQ0FBQyxZQUFZLENBQUMsVUFBVSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzFDLFdBQVcsQ0FBQyxZQUFZLENBQUMsVUFBVSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzFDLFdBQVcsQ0FBQyxZQUFZLENBQUMsVUFBVSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBRTFDLHNCQUFzQjtRQUN0QixLQUFLLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUN0QyxLQUFLLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUN0QyxLQUFLLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUV0Qyx5QkFBeUI7UUFDekIsV0FBVyxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxFQUFFLGdCQUFnQixFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztRQUM5RixXQUFXLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLEVBQUUsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzlGLFdBQVcsQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxLQUFvQixFQUFFLEVBQUUsQ0FDL0QsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FDbkQsQ0FBQztRQUVGLFdBQVcsQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxnQkFBZ0IsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDOUYsV0FBVyxDQUFDLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxFQUFFLGdCQUFnQixFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQztRQUM5RixXQUFXLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLENBQUMsS0FBb0IsRUFBRSxFQUFFLENBQy9ELElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxjQUFjLENBQUMsS0FBSyxDQUFDLENBQ25ELENBQUM7UUFFRixXQUFXLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLEVBQUUsZ0JBQWdCLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzlGLFdBQVcsQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxnQkFBZ0IsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDOUYsV0FBVyxDQUFDLGdCQUFnQixDQUFDLFNBQVMsRUFBRSxDQUFDLEtBQW9CLEVBQUUsRUFBRSxDQUMvRCxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FDbEMsQ0FBQztRQUVGLHNDQUFzQztRQUN0QyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRTtZQUNuQixrQkFBa0IsRUFBRSxXQUFXO1lBQy9CLGtCQUFrQixFQUFFLFdBQVc7WUFDL0Isa0JBQWtCLEVBQUUsV0FBVztTQUNoQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsMkNBQTJDO0lBQ25DLFNBQVMsQ0FBQyxLQUFvQixFQUFFLEtBQW9CLEVBQUUsTUFBc0I7UUFDbEYsNkNBQTZDO1FBQzdDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQzNELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQztRQUNsRCxNQUFNLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFckQsUUFBUSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDdEIsS0FBSyxVQUFVO2dCQUNiLElBQUksQ0FBQyxjQUFjLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxJQUFJLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQztnQkFDM0QsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUN2QixNQUFNO1lBRVIsS0FBSyxJQUFJO2dCQUNQLElBQUksQ0FBQyxjQUFjLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUN0RCxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3ZCLE1BQU07WUFFUixLQUFLLFdBQVc7Z0JBQ2QsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLElBQUksSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUMzRCxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3ZCLE1BQU07WUFFUixLQUFLLEdBQUc7Z0JBQ04sSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7Z0JBQ3RELEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDdkIsTUFBTTtRQUNWLENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLGNBQWMsQ0FBQyxLQUFvQixFQUFFLEtBQW9CO1FBQy9ELGdDQUFnQztRQUNoQyxJQUFJLFVBQVUsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssRUFBRSxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDNUUsSUFBSSxVQUFVLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQzVFLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQztRQUNsRCxNQUFNLFVBQVUsR0FBRyxVQUFVLEdBQUcsVUFBVSxDQUFDO1FBRTNDLDJCQUEyQjtRQUMzQixNQUFNLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFckQsUUFBUSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDdEIsS0FBSyxVQUFVO2dCQUNiLFVBQVUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFVBQVUsR0FBRyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7Z0JBQ2xELFVBQVUsR0FBRyxVQUFVLEdBQUcsVUFBVSxDQUFDO2dCQUNyQyxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3ZCLE1BQU07WUFFUixLQUFLLFdBQVc7Z0JBQ2QsVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxHQUFHLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztnQkFDbEQsVUFBVSxHQUFHLFVBQVUsR0FBRyxVQUFVLENBQUM7Z0JBQ3JDLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDdkIsTUFBTTtZQUVSLEtBQUssSUFBSTtnQkFDUCxVQUFVLEdBQUcsT0FBTyxDQUFDO2dCQUNyQixVQUFVLEdBQUcsVUFBVSxHQUFHLFVBQVUsQ0FBQztnQkFDckMsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUN2QixNQUFNO1lBRVIsS0FBSyxHQUFHO2dCQUNOLFVBQVUsR0FBRyxPQUFPLENBQUM7Z0JBQ3JCLFVBQVUsR0FBRyxVQUFVLEdBQUcsVUFBVSxDQUFDO2dCQUNyQyxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3ZCLE1BQU07UUFDVixDQUFDO1FBRUQsdUJBQXVCO1FBQ3ZCLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2pGLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBRWpGLG1CQUFtQjtRQUNuQixLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7UUFFZix3QkFBd0I7UUFDeEIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM5QixDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssV0FBVyxDQUFDLEtBQW9CO1FBQ3RDLHNEQUFzRDtRQUN0RCxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ2YsT0FBTztRQUNULENBQUM7UUFFRCx1Q0FBdUM7UUFDdkMsTUFBTSxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFekMsb0NBQW9DO1FBQ3BDLE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRXhDLGtEQUFrRDtRQUNsRCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFFakUsb0VBQW9FO1FBQ3BFLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLEVBQUUsTUFBTSxFQUFFLE1BQU0sS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNwRSxDQUFDO0lBRUQsMkRBQTJEO0lBQ25ELFNBQVMsQ0FBQyxLQUFvQjtRQUNwQyxJQUFJLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNqQixJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQ3pDLENBQUM7SUFDSCxDQUFDO0lBRU8sZUFBZSxDQUFDLEtBQW9CLEVBQUUsS0FBVTtRQUN0RCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztRQUV4RCxNQUFNLGVBQWUsR0FBRyxDQUN0QixJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUNqQyxDQUFDO1FBQzFCLGlEQUFpRDtRQUNqRCxNQUFNLGlCQUFpQixHQUFZLGVBQWUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUM1RixpREFBaUQ7UUFDakQsTUFBTSxtQkFBbUIsR0FBWSxlQUFlLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDaEcsSUFBSSxtQkFBMkIsQ0FBQztRQUNoQyxJQUFJLGlCQUE2RCxDQUFDO1FBRWxFLElBQUksaUJBQWlCLEVBQUUsQ0FBQztZQUN0QixtQkFBbUIsR0FBRyxlQUFlLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDdkUsQ0FBQztRQUVELElBQUksbUJBQW1CLEVBQUUsQ0FBQztZQUN4QixpQkFBaUIsR0FBRyxlQUFlLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDdkUsQ0FBQztRQUVELElBQUksYUFBYSxLQUFLLGNBQWMsQ0FBQyxLQUFLLElBQUksaUJBQWlCLEVBQUUsQ0FBQztZQUNoRSxJQUFJLENBQUMsc0JBQXNCLENBQUMsS0FBSyxFQUFFLGNBQWMsQ0FBQyxLQUFLLEVBQUUsbUJBQW1CLENBQUMsQ0FBQztRQUNoRixDQUFDO2FBQU0sSUFBSSxhQUFhLEtBQUssY0FBYyxDQUFDLEtBQUssSUFBSSxtQkFBbUIsRUFBRSxDQUFDO1lBQ3pFLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxLQUFLLEVBQUUsY0FBYyxDQUFDLEtBQUssRUFBRSxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN6RixDQUFDO2FBQU0sSUFBSSxhQUFhLEtBQUssY0FBYyxDQUFDLEtBQUssSUFBSSxtQkFBbUIsRUFBRSxDQUFDO1lBQ3pFLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxLQUFLLEVBQUUsY0FBYyxDQUFDLEtBQUssRUFBRSxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN6RixDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDMUIsQ0FBQztJQUNILENBQUM7SUFFTyxXQUFXLENBQUMsS0FBb0I7UUFDdEMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2pELFNBQVMsQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQztJQUNoQyxDQUFDO0lBRU8sa0JBQWtCLENBQUMsS0FBb0I7UUFDN0MsSUFBSSxTQUFTLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLG1CQUFtQixDQUFnQixDQUFDO1FBRTFGLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNmLFNBQVMsR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLEtBQU