@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
498 lines • 84.9 kB
JavaScript
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Component, ElementRef, EventEmitter, inject, Input, Output, ViewChild } from '@angular/core';
import { BehaviorSubject, forkJoin, lastValueFrom, of } from 'rxjs';
import { map, switchMap, tap } from 'rxjs/operators';
import { CustomMeasurementService } from './services/custom-measurements.service';
import { AlarmRealtimeService, CoreModule, DismissAlertStrategy, DynamicComponentAlert, DynamicComponentAlertAggregator, EventRealtimeService, gettext, MeasurementRealtimeService, WidgetTimeContextDateRangeService } from '@c8y/ngx-components';
import { EchartsOptionsService } from './services/echarts-options.service';
import { ChartRealtimeService } from './services/chart-realtime.service';
import { ChartTypesService } from './services/chart-types.service';
import { CommonModule } from '@angular/common';
import { NGX_ECHARTS_CONFIG, NgxEchartsModule } from 'ngx-echarts';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
import { PopoverModule } from 'ngx-bootstrap/popover';
import { YAxisService } from './services/y-axis.service';
import { ChartAlertsComponent } from './chart-alerts/chart-alerts.component';
import { aggregationType, AlarmStatus } from '@c8y/client';
import { ChartEventsService } from './services/chart-events.service';
import { ChartAlarmsService } from './services/chart-alarms.service';
import { AlarmSeverityToIconPipe, AlarmSeverityToLabelPipe, AlarmsModule } from '@c8y/ngx-components/alarms';
import { INTERVALS } from '@c8y/ngx-components/interval-picker';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "@c8y/ngx-components";
import * as i3 from "ngx-echarts";
export class ChartsComponent {
constructor() {
this.showLoadMore = false;
this.alarms = [];
this.events = [];
this.sliderZoomUsed = false;
this.configChangeOnZoomOut = new EventEmitter();
this.timeRangeChangeOnRealtime = new EventEmitter();
this.datapointOutOfSync = new EventEmitter();
this.updateAlarmsAndEvents = new EventEmitter();
this.isMarkedAreaEnabled = new EventEmitter();
this.configChangedSubject = new BehaviorSubject(null);
this.measurementService = inject(CustomMeasurementService);
this.echartsOptionsService = inject(EchartsOptionsService);
this.chartRealtimeService = inject(ChartRealtimeService);
this.chartEventsService = inject(ChartEventsService);
this.chartAlarmsService = inject(ChartAlarmsService);
this.widgetTimeContextDateRangeService = inject(WidgetTimeContextDateRangeService);
this.chartOption$ = this.configChangedSubject.pipe(switchMap(() => this.loadAlarmsAndEvents()), switchMap(() => this.fetchSeriesForDatapoints$()), switchMap((datapointsWithValues) => {
if (datapointsWithValues.length === 0) {
this.echartsInstance?.clear();
this.showLoadMore = false;
return of(this.getDefaultChartOptions());
}
return this.getChartOptions(datapointsWithValues);
}), tap(v => {
if (v['empty']) {
return;
}
this.chartRealtimeService.stopRealtime();
this.startRealtimeIfPossible();
if (this.echartsInstance) {
this.echartsInstance.setOption(v, true);
const options = this.echartsInstance.getOption();
const dataZoom = options['dataZoom'][0];
if (dataZoom.start !== 0) {
this.showLoadMore = false;
}
}
this.sliderZoomUsed = false;
}));
}
ngOnChanges() {
this.configChangedSubject.next();
}
ngOnInit() {
if (this.alerts) {
this.alerts.setAlertGroupDismissStrategy('warning', DismissAlertStrategy.TEMPORARY_OR_PERMANENT);
}
}
ngOnDestroy() {
this.chartRealtimeService.stopRealtime();
}
onChartInit(ec) {
this.echartsInstance = ec;
this.echartsOptionsService.echartsInstance = this.echartsInstance;
this.startRealtimeIfPossible();
const dataZoomHandler = (evt) => {
if (evt.batch?.[0]?.start === 0 || evt['start'] === 0) {
this.showLoadMore = true;
}
const options = this.echartsInstance.getOption();
const dataZoom = options['dataZoom'][0];
this.sliderZoomUsed = true;
this.configChangeOnZoomOut.emit({
dateFrom: new Date(dataZoom['startValue']),
dateTo: new Date(dataZoom['endValue']),
interval: 'custom'
});
this.echartsInstance.setOption(options);
this.chartRealtimeService.stopRealtime();
};
const debouncedDataZoomHandler = this.config.realtime
? dataZoomHandler
: this.debounce(dataZoomHandler, 1000);
this.echartsInstance.on('dataZoom', debouncedDataZoomHandler);
this.echartsInstance.on('click', this.onChartClick.bind(this));
let originalFormatter = null;
this.echartsInstance.on('mouseover', (params) => {
if (params?.componentType !== 'markLine' && params?.componentType !== 'markPoint') {
return;
}
const options = this.echartsInstance.getOption();
if (!options.tooltip || !Array.isArray(options.tooltip) || !options.tooltip[0]) {
return;
}
originalFormatter = originalFormatter ?? options['tooltip'][0].formatter;
const updatedOptions = { tooltip: options['tooltip'][0] };
if (!updatedOptions.tooltip) {
return;
}
updatedOptions.tooltip.formatter = (tooltipParams) => {
return this.echartsOptionsService.getTooltipFormatterForAlarmAndEvents(tooltipParams, params, this.events, this.alarms);
};
this.echartsInstance.setOption(updatedOptions);
});
this.echartsInstance.on('mouseout', () => {
const options = this.echartsInstance.getOption();
if (originalFormatter) {
options['tooltip'][0].formatter = originalFormatter;
this.echartsInstance.setOption(options);
}
});
}
onChartClick(params) {
const options = this.echartsInstance.getOption();
if (!this.isAlarmClick(params)) {
this.echartsInstance.setOption({
tooltip: { triggerOn: 'mousemove' },
series: [{ markArea: { data: [] }, markLine: { data: [] } }]
});
return;
}
const clickedAlarms = this.alarms.filter(alarm => alarm.type === params.data.itemType);
this.isMarkedAreaEnabled.emit(this.hasMarkArea(options));
const updatedOptions = !this.hasMarkArea(options)
? {
tooltip: { enterable: true, triggerOn: 'click' },
series: [
{
markArea: { label: { show: false }, data: this.getMarkedAreaData(clickedAlarms) },
markLine: {
showSymbol: true,
symbol: ['none', 'none'],
data: this.getMarkedLineData(clickedAlarms)
}
}
]
}
: // if markArea already exists, remove it and remove lastUpdated from markLine
{
tooltip: { triggerOn: 'mousemove' },
series: [{ markArea: { data: [] }, markLine: { data: [] } }]
};
this.echartsInstance.setOption(updatedOptions);
}
isAlarmClick(params) {
return this.alarms.some(alarm => alarm.type === params.data.itemType);
}
hasMarkArea(options) {
return options?.series?.[0]?.markArea?.data?.length > 0;
}
saveAsImage() {
this.echartsInstance.setOption({ legend: { show: true } });
const url = this.echartsInstance.getDataURL({
pixelRatio: 2,
backgroundColor: '#fff',
type: 'png'
});
const link = document.createElement('a');
link.href = url;
link.download = 'datapoints-graph-screenshot';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.echartsInstance.setOption({ legend: { show: false } });
}
loadMoreData() {
const currentTimeRangeInMs = this.echartsOptionsService.calculateExtendedIntervalInMs(this.config.interval || 'custom', {
dateTo: this.widgetTimeContextDateRangeService.initialTimeRange().dateTo,
dateFrom: this.widgetTimeContextDateRangeService.initialTimeRange().dateFrom
});
this.widgetTimeContextDateRangeService.updateInitialTimeRange({
dateFrom: new Date(new Date(this.widgetTimeContextDateRangeService.initialTimeRange().dateFrom).valueOf() -
currentTimeRangeInMs / 4).toISOString(),
dateTo: this.widgetTimeContextDateRangeService.initialTimeRange().dateTo,
interval: 'custom'
});
const options = this.echartsInstance.getOption();
const dataZoom = options['dataZoom'][0];
this.configChangeOnZoomOut.emit({
dateFrom: new Date(dataZoom['startValue']),
dateTo: new Date(dataZoom['endValue']),
interval: 'custom'
});
this.showLoadMore = false;
}
debounce(func, wait) {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => func(...args), wait);
};
}
getDefaultChartOptions() {
return {
title: {
text: gettext('No data available.'),
left: 'center',
top: 'center',
textStyle: { fontSize: 30 }
},
empty: true,
xAxis: { type: 'category', data: [] },
yAxis: { type: 'value' },
series: []
};
}
getMarkedAreaData(clickedAlarms) {
const timeRange = this.getTimeRange();
const clearedAlarmColor = 'rgba(221,255,221,1.00)';
const activeAlarmColor = 'rgba(255, 173, 177, 0.4)';
return clickedAlarms.map(clickedAlarm => {
return [
{
name: clickedAlarm.type,
xAxis: clickedAlarm.creationTime,
itemStyle: {
color: clickedAlarm.status === AlarmStatus.CLEARED ? clearedAlarmColor : activeAlarmColor
}
},
{
xAxis: clickedAlarm['lastUpdated'] === clickedAlarm.creationTime ||
clickedAlarm.status !== AlarmStatus.CLEARED
? timeRange.dateTo
: clickedAlarm['lastUpdated']
}
];
});
}
getMarkedLineData(clickedAlarms) {
return clickedAlarms.reduce((acc, alarm) => {
const isClickedAlarmCleared = alarm.status === AlarmStatus.CLEARED;
if (isClickedAlarmCleared) {
return acc.concat([
{
xAxis: alarm.creationTime,
itemType: alarm.type,
label: { show: false, formatter: () => alarm.type },
itemStyle: { color: alarm['color'] }
},
{
xAxis: alarm['lastUpdated'],
itemType: alarm.type,
label: { show: false, formatter: () => alarm.type },
itemStyle: { color: alarm['color'] }
}
]);
}
return acc.concat([
{
xAxis: alarm.creationTime,
itemType: alarm.type,
label: { show: false, formatter: () => alarm.type },
itemStyle: { color: alarm['color'] }
}
]);
}, []);
}
async loadAlarmsAndEvents(customTimeRange) {
const timeRange = this.getTimeRange();
const updatedTimeRange = {
lastUpdatedFrom: customTimeRange ? customTimeRange.dateFrom : timeRange.dateFrom,
createdTo: customTimeRange ? customTimeRange.dateTo : timeRange.dateTo
};
if (!this.config.alarmsEventsConfigs)
return;
const visibleAlarmsOrEvents = this.config.alarmsEventsConfigs?.filter(alarmOrEvent => !alarmOrEvent.__hidden && alarmOrEvent.__active);
const alarms = visibleAlarmsOrEvents?.filter(alarmOrEvent => alarmOrEvent.timelineType === 'ALARM');
const events = visibleAlarmsOrEvents?.filter(alarmOrEvent => alarmOrEvent.timelineType === 'EVENT');
const [listedEvents, listedAlarms] = await Promise.all([
this.chartEventsService.listEvents(updatedTimeRange, events),
this.chartAlarmsService.listAlarms(updatedTimeRange, alarms)
]);
this.events = listedEvents;
this.alarms = listedAlarms;
await this.addActiveAlarms(alarms);
this.updateAlarmsAndEvents.emit(this.config.alarmsEventsConfigs);
}
startRealtimeIfPossible() {
const activeDatapoints = this.config?.datapoints?.filter(dp => dp.__active);
if (activeDatapoints && this.config.realtime && this.echartsInstance) {
this.chartRealtimeService.startRealtime(this.echartsInstance, activeDatapoints, this.getTimeRange(), dp => this.datapointOutOfSync.emit(dp), timeRange => this.timeRangeChangeOnRealtime.emit(timeRange), this.config.alarmsEventsConfigs, {
displayMarkedLine: this.config.displayMarkedLine || false,
displayMarkedPoint: this.config.displayMarkedPoint || false
});
}
}
/*
This method should check and add active alarms from the begining of time to the alarm array
*/
async addActiveAlarms(alarms) {
const timeRange = this.getTimeRange();
const params = {
dateFrom: '1970-01-01T01:00:00+01:00',
dateTo: timeRange.dateTo,
status: AlarmStatus.ACTIVE
};
const activeAlarms = await this.chartAlarmsService.listAlarms(params, alarms);
this.config.activeAlarmTypesOutOfRange = [];
// iterate through the activeAlarms and check if the alarm is in the alarms array, if not update the config.activeAlarmTypesOutOfRange prop
activeAlarms.forEach(activeAlarm => {
const alarmType = activeAlarm.type;
const alarm = this.alarms.find(alarm => alarm.type === alarmType);
if (!alarm && this.config.activeAlarmTypesOutOfRange) {
this.config.activeAlarmTypesOutOfRange.push(alarmType);
}
});
}
async getChartOptions(datapointsWithValues) {
const timeRange = { ...this.getTimeRange(), interval: this.config.interval };
if (!this.widgetTimeContextDateRangeService.initialTimeRange()) {
this.widgetTimeContextDateRangeService.updateInitialTimeRange(timeRange);
const aggregatedDatapoints = await lastValueFrom(this.fetchSeriesForDatapoints$({
dateFrom: new Date(new Date(timeRange.dateFrom).valueOf() -
this.echartsOptionsService.calculateExtendedIntervalInMs(this.config.interval || 'custom', { dateFrom: timeRange.dateFrom, dateTo: timeRange.dateTo })).toISOString(),
dateTo: timeRange.dateTo
}));
return this.echartsOptionsService.getChartOptions(datapointsWithValues, timeRange, {
YAxis: this.config.yAxisSplitLines || false,
XAxis: this.config.xAxisSplitLines || false
}, this.events, this.alarms, {
displayMarkedLine: this.config.displayMarkedLine || false,
displayMarkedPoint: this.config.displayMarkedPoint || false,
mergeMatchingDatapoints: this.config.mergeMatchingDatapoints || false,
showLabelAndUnit: this.config.showLabelAndUnit || false,
showSlider: this.config.showSlider || false
}, undefined, aggregatedDatapoints);
}
else {
const aggregatedDatapoints = await lastValueFrom(this.fetchSeriesForDatapoints$({
dateFrom: new Date(new Date(this.widgetTimeContextDateRangeService.initialTimeRange().dateFrom).valueOf() -
this.echartsOptionsService.calculateExtendedIntervalInMs(this.config.interval || 'custom', {
dateFrom: this.widgetTimeContextDateRangeService.initialTimeRange().dateFrom,
dateTo: this.widgetTimeContextDateRangeService.initialTimeRange().dateTo
})).toISOString(),
dateTo: new Date(this.widgetTimeContextDateRangeService.initialTimeRange().dateTo).toISOString()
}));
return this.echartsOptionsService.getChartOptions(datapointsWithValues, this.widgetTimeContextDateRangeService.initialTimeRange(), {
YAxis: this.config.yAxisSplitLines || false,
XAxis: this.config.xAxisSplitLines || false
}, this.events, this.alarms, {
displayMarkedLine: this.config.displayMarkedLine || false,
displayMarkedPoint: this.config.displayMarkedPoint || false,
mergeMatchingDatapoints: this.config.mergeMatchingDatapoints || false,
showLabelAndUnit: this.config.showLabelAndUnit || false,
showSlider: this.config.showSlider || false
}, timeRange, aggregatedDatapoints, true);
}
}
fetchSeriesForDatapoints$(customTimeRange) {
const activeDatapoints = this.config?.datapoints?.filter(dp => dp.__active);
if (!activeDatapoints || activeDatapoints.length === 0) {
return of([]);
}
const datapointsWithValuesRequests = [];
const timeRange = this.getTimeRange(60_000);
for (const dp of activeDatapoints) {
const request = this.measurementService
.listSeries$({
...(customTimeRange ? customTimeRange : timeRange),
source: dp.__target?.id || '',
series: [`${dp.fragment}.${dp.series}`],
...(this.config.aggregation || customTimeRange
? {
aggregationType: customTimeRange ? aggregationType.HOURLY : this.config.aggregation
}
: {})
})
.pipe(map(res => {
const values = res.data.values;
if (res.data.truncated && this.config.dateFrom) {
values[new Date(this.config.dateFrom).toISOString()] = [{ min: null, max: null }];
}
else {
if (this.alerts) {
this.alerts.clear();
}
}
return { ...dp, values, truncated: res.data.truncated };
}));
datapointsWithValuesRequests.push(request);
}
return forkJoin(datapointsWithValuesRequests).pipe(tap((dpsWithValues) => {
if (dpsWithValues.some(dp => dp['truncated'])) {
this.addTruncatedDataAlert();
}
}));
}
addTruncatedDataAlert() {
if (this.alerts?.alertGroups.find(a => a.type === 'warning')?.value?.alerts?.length) {
return;
}
const alert = new DynamicComponentAlert({
type: 'warning',
text: gettext('Truncated data. Change aggregation or select shorter date range.')
});
this.alerts?.addAlerts(alert);
}
getTimeRange(additionalPadding) {
let timeRange;
if (this.config.widgetInstanceGlobalTimeContext ||
(this.config.interval === 'custom' && !this.config.realtime)) {
timeRange = {
dateFrom: new Date(this.config.dateFrom),
dateTo: new Date(this.config.dateTo)
};
}
else {
let timeRangeInMs = 0;
if (this.config.interval && this.config.interval !== 'custom') {
timeRangeInMs = INTERVALS.find(i => i.id === this.config.interval)?.timespanInMs || 0;
}
else if (this.config.realtime) {
timeRangeInMs =
new Date(this.config.dateTo).valueOf() -
new Date(this.config.dateFrom).valueOf();
}
const now = new Date();
timeRange = { dateFrom: new Date(now.valueOf() - timeRangeInMs), dateTo: now };
}
if (additionalPadding) {
timeRange.dateFrom = new Date(timeRange.dateFrom.valueOf() - additionalPadding);
timeRange.dateTo = new Date(timeRange.dateTo.valueOf() + additionalPadding);
}
return { dateFrom: timeRange.dateFrom.toISOString(), dateTo: timeRange.dateTo.toISOString() };
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChartsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ChartsComponent, isStandalone: true, selector: "c8y-charts", inputs: { config: "config", alerts: "alerts" }, outputs: { configChangeOnZoomOut: "configChangeOnZoomOut", timeRangeChangeOnRealtime: "timeRangeChangeOnRealtime", datapointOutOfSync: "datapointOutOfSync", updateAlarmsAndEvents: "updateAlarmsAndEvents", isMarkedAreaEnabled: "isMarkedAreaEnabled" }, providers: [
{ provide: NGX_ECHARTS_CONFIG, useFactory: () => ({ echarts: () => import('echarts') }) },
ChartRealtimeService,
MeasurementRealtimeService,
AlarmRealtimeService,
EventRealtimeService,
ChartTypesService,
EchartsOptionsService,
CustomMeasurementService,
YAxisService,
AlarmSeverityToIconPipe,
AlarmSeverityToLabelPipe
], viewQueries: [{ propertyName: "chart", first: true, predicate: ["chart"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"p-relative fit-h chart-container\"\n>\n <div\n class=\"fit-w fit-h\"\n #chart\n echarts\n [options]=\"chartOption$ | async\"\n (chartInit)=\"onChartInit($event)\"\n ></div>\n\n <c8y-chart-alerts [alerts]=\"alerts\"></c8y-chart-alerts>\n\n <div *ngIf=\"showLoadMore\" class=\"chart-load-more\">\n <button\n class=\"btn btn-primary btn-sm btn-block\"\n (click)=\"loadMoreData()\"\n >\n <i c8yIcon=\"restore\"></i>\n {{ 'Load more' | translate }}\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "ngmodule", type: NgxEchartsModule }, { kind: "directive", type: i3.NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: ChartAlertsComponent, selector: "c8y-chart-alerts", inputs: ["alerts"] }, { kind: "ngmodule", type: AlarmsModule }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ChartsComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-charts', providers: [
{ provide: NGX_ECHARTS_CONFIG, useFactory: () => ({ echarts: () => import('echarts') }) },
ChartRealtimeService,
MeasurementRealtimeService,
AlarmRealtimeService,
EventRealtimeService,
ChartTypesService,
EchartsOptionsService,
CustomMeasurementService,
YAxisService,
AlarmSeverityToIconPipe,
AlarmSeverityToLabelPipe
], standalone: true, imports: [
CommonModule,
CoreModule,
NgxEchartsModule,
TooltipModule,
PopoverModule,
ChartAlertsComponent,
AlarmsModule
], template: "<div\n class=\"p-relative fit-h chart-container\"\n>\n <div\n class=\"fit-w fit-h\"\n #chart\n echarts\n [options]=\"chartOption$ | async\"\n (chartInit)=\"onChartInit($event)\"\n ></div>\n\n <c8y-chart-alerts [alerts]=\"alerts\"></c8y-chart-alerts>\n\n <div *ngIf=\"showLoadMore\" class=\"chart-load-more\">\n <button\n class=\"btn btn-primary btn-sm btn-block\"\n (click)=\"loadMoreData()\"\n >\n <i c8yIcon=\"restore\"></i>\n {{ 'Load more' | translate }}\n </button>\n </div>\n</div>\n" }]
}], ctorParameters: () => [], propDecorators: { config: [{
type: Input
}], alerts: [{
type: Input
}], configChangeOnZoomOut: [{
type: Output
}], timeRangeChangeOnRealtime: [{
type: Output
}], datapointOutOfSync: [{
type: Output
}], updateAlarmsAndEvents: [{
type: Output
}], isMarkedAreaEnabled: [{
type: Output
}], chart: [{
type: ViewChild,
args: ['chart']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcnRzLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2VjaGFydC9jaGFydHMuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vZWNoYXJ0L2NoYXJ0cy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx1REFBdUQ7QUFDdkQsT0FBTyxFQUNMLFNBQVMsRUFDVCxVQUFVLEVBQ1YsWUFBWSxFQUNaLE1BQU0sRUFDTixLQUFLLEVBSUwsTUFBTSxFQUNOLFNBQVMsRUFDVixNQUFNLGVBQWUsQ0FBQztBQVd2QixPQUFPLEVBQUUsZUFBZSxFQUFFLFFBQVEsRUFBRSxhQUFhLEVBQWMsRUFBRSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ2hGLE9BQU8sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3JELE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLHdDQUF3QyxDQUFDO0FBQ2xGLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsVUFBVSxFQUNWLG9CQUFvQixFQUNwQixxQkFBcUIsRUFDckIsK0JBQStCLEVBQy9CLG9CQUFvQixFQUNwQixPQUFPLEVBQ1AsMEJBQTBCLEVBQzFCLGlDQUFpQyxFQUNsQyxNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQzNFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBTXpFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDbkUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3RELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN0RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDekQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDN0UsT0FBTyxFQUFFLGVBQWUsRUFBRSxXQUFXLEVBQWtCLE1BQU0sYUFBYSxDQUFDO0FBQzNFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3JFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBR3JFLE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsd0JBQXdCLEVBQ3hCLFlBQVksRUFDYixNQUFNLDRCQUE0QixDQUFDO0FBQ3BDLE9BQU8sRUFBWSxTQUFTLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQzs7Ozs7QUE2QjFFLE1BQU0sT0FBTyxlQUFlO0lBOEIxQjtRQTNCQSxpQkFBWSxHQUFHLEtBQUssQ0FBQztRQUNyQixXQUFNLEdBQWEsRUFBRSxDQUFDO1FBQ3RCLFdBQU0sR0FBYSxFQUFFLENBQUM7UUFDdEIsbUJBQWMsR0FBRyxLQUFLLENBQUM7UUFHYiwwQkFBcUIsR0FBRyxJQUFJLFlBQVksRUFJOUMsQ0FBQztRQUNLLDhCQUF5QixHQUFHLElBQUksWUFBWSxFQUVuRCxDQUFDO1FBQ00sdUJBQWtCLEdBQUcsSUFBSSxZQUFZLEVBQTZCLENBQUM7UUFDbkUsMEJBQXFCLEdBQUcsSUFBSSxZQUFZLEVBQTBCLENBQUM7UUFDbkUsd0JBQW1CLEdBQUcsSUFBSSxZQUFZLEVBQVcsQ0FBQztRQUVwRCx5QkFBb0IsR0FBRyxJQUFJLGVBQWUsQ0FBYyxJQUFJLENBQUMsQ0FBQztRQUVyRCx1QkFBa0IsR0FBRyxNQUFNLENBQUMsd0JBQXdCLENBQUMsQ0FBQztRQUN0RCwwQkFBcUIsR0FBRyxNQUFNLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUN0RCx5QkFBb0IsR0FBRyxNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUNwRCx1QkFBa0IsR0FBRyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUNoRCx1QkFBa0IsR0FBRyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUNoRCxzQ0FBaUMsR0FBRyxNQUFNLENBQUMsaUNBQWlDLENBQUMsQ0FBQztRQUc3RixJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQ2hELFNBQVMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQyxFQUMzQyxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLHlCQUF5QixFQUFFLENBQUMsRUFDakQsU0FBUyxDQUFDLENBQUMsb0JBQW9DLEVBQUUsRUFBRTtZQUNqRCxJQUFJLG9CQUFvQixDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDdEMsSUFBSSxDQUFDLGVBQWUsRUFBRSxLQUFLLEVBQUUsQ0FBQztnQkFDOUIsSUFBSSxDQUFDLFlBQVksR0FBRyxLQUFLLENBQUM7Z0JBQzFCLE9BQU8sRUFBRSxDQUFDLElBQUksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDLENBQUM7WUFDM0MsQ0FBQztZQUNELE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ3BELENBQUMsQ0FBQyxFQUNGLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRTtZQUNOLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7Z0JBQ2YsT0FBTztZQUNULENBQUM7WUFDRCxJQUFJLENBQUMsb0JBQW9CLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDekMsSUFBSSxDQUFDLHVCQUF1QixFQUFFLENBQUM7WUFFL0IsSUFBSSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7Z0JBQ3pCLElBQUksQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztnQkFDeEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDakQsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUN4QyxJQUFJLFFBQVEsQ0FBQyxLQUFLLEtBQUssQ0FBQyxFQUFFLENBQUM7b0JBQ3pCLElBQUksQ0FBQyxZQUFZLEdBQUcsS0FBSyxDQUFDO2dCQUM1QixDQUFDO1lBQ0gsQ0FBQztZQUNELElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDO1FBQzlCLENBQUMsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNuQyxDQUFDO0lBRUQsUUFBUTtRQUNOLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2hCLElBQUksQ0FBQyxNQUFNLENBQUMsNEJBQTRCLENBQ3RDLFNBQVMsRUFDVCxvQkFBb0IsQ0FBQyxzQkFBc0IsQ0FDNUMsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUMzQyxDQUFDO0lBRUQsV0FBVyxDQUFDLEVBQVc7UUFDckIsSUFBSSxDQUFDLGVBQWUsR0FBRyxFQUFFLENBQUM7UUFDMUIsSUFBSSxDQUFDLHFCQUFxQixDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDO1FBQ2xFLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1FBRS9CLE1BQU0sZUFBZSxHQUFHLENBQUMsR0FBa0IsRUFBRSxFQUFFO1lBQzdDLElBQUksR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssS0FBSyxDQUFDLElBQUksR0FBRyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUN0RCxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQztZQUMzQixDQUFDO1lBRUQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNqRCxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDeEMsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUM7WUFDM0IsSUFBSSxDQUFDLHFCQUFxQixDQUFDLElBQUksQ0FBQztnQkFDOUIsUUFBUSxFQUFFLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQztnQkFDMUMsTUFBTSxFQUFFLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDdEMsUUFBUSxFQUFFLFFBQVE7YUFDbkIsQ0FBQyxDQUFDO1lBQ0gsSUFBSSxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDeEMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLFlBQVksRUFBRSxDQUFDO1FBQzNDLENBQUMsQ0FBQztRQUVGLE1BQU0sd0JBQXdCLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRO1lBQ25ELENBQUMsQ0FBQyxlQUFlO1lBQ2pCLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWUsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUV6QyxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQyxVQUFVLEVBQUUsd0JBQXdCLENBQUMsQ0FBQztRQUM5RCxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUUvRCxJQUFJLGlCQUFpQixHQUlMLElBQUksQ0FBQztRQUVyQixJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxNQUFXLEVBQUUsRUFBRTtZQUNuRCxJQUFJLE1BQU0sRUFBRSxhQUFhLEtBQUssVUFBVSxJQUFJLE1BQU0sRUFBRSxhQUFhLEtBQUssV0FBVyxFQUFFLENBQUM7Z0JBQ2xGLE9BQU87WUFDVCxDQUFDO1lBRUQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxTQUFTLEVBQW1CLENBQUM7WUFDbEUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDL0UsT0FBTztZQUNULENBQUM7WUFDRCxpQkFBaUIsR0FBRyxpQkFBaUIsSUFBSSxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1lBRXpFLE1BQU0sY0FBYyxHQUEwQixFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUVqRixJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUM1QixPQUFPO1lBQ1QsQ0FBQztZQUNELGNBQWMsQ0FBQyxPQUFPLENBQUMsU0FBUyxHQUFHLENBQUMsYUFBaUMsRUFBRSxFQUFFO2dCQUN2RSxPQUFPLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxvQ0FBb0MsQ0FDcEUsYUFBYSxFQUNiLE1BQU0sRUFDTixJQUFJLENBQUMsTUFBTSxFQUNYLElBQUksQ0FBQyxNQUFNLENBQ1osQ0FBQztZQUNKLENBQUMsQ0FBQztZQUVGLElBQUksQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ2pELENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUMsVUFBVSxFQUFFLEdBQUcsRUFBRTtZQUN2QyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsRUFBMEIsQ0FBQztZQUN6RSxJQUFJLGlCQUFpQixFQUFFLENBQUM7Z0JBQ3RCLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUcsaUJBQWlCLENBQUM7Z0JBQ3BELElBQUksQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzFDLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxZQUFZLENBQUMsTUFBc0M7UUFDakQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNqRCxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQy9CLElBQUksQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDO2dCQUM3QixPQUFPLEVBQUUsRUFBRSxTQUFTLEVBQUUsV0FBVyxFQUFFO2dCQUNuQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLFFBQVEsRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsRUFBRSxRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQzthQUM3RCxDQUFDLENBQUM7WUFDSCxPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRXZGLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBQ3pELE1BQU0sY0FBYyxHQUFHLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUM7WUFDL0MsQ0FBQyxDQUFDO2dCQUNFLE9BQU8sRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRTtnQkFDaEQsTUFBTSxFQUFFO29CQUNOO3dCQUNFLFFBQVEsRUFBRSxFQUFFLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLGlCQUFpQixDQUFDLGFBQWEsQ0FBQyxFQUFFO3dCQUNqRixRQUFRLEVBQUU7NEJBQ1IsVUFBVSxFQUFFLElBQUk7NEJBQ2hCLE1BQU0sRUFBRSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUM7NEJBQ3hCLElBQUksRUFBRSxJQUFJLENBQUMsaUJBQWlCLENBQUMsYUFBYSxDQUFDO3lCQUM1QztxQkFDRjtpQkFDRjthQUNGO1lBQ0gsQ0FBQyxDQUFDLDZFQUE2RTtnQkFDN0U7b0JBQ0UsT0FBTyxFQUFFLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRTtvQkFDbkMsTUFBTSxFQUFFLENBQUMsRUFBRSxRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUM7aUJBQzdELENBQUM7UUFFTixJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQsWUFBWSxDQUFDLE1BQVc7UUFDdEIsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN4RSxDQUFDO0lBRUQsV0FBVyxDQUFDLE9BQVk7UUFDdEIsT0FBTyxPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQzFELENBQUM7SUFFRCxXQUFXO1FBQ1QsSUFBSSxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsRUFBRSxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQzNELE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsVUFBVSxDQUFDO1lBQzFDLFVBQVUsRUFBRSxDQUFDO1lBQ2IsZUFBZSxFQUFFLE1BQU07WUFDdkIsSUFBSSxFQUFFLEtBQUs7U0FDWixDQUFDLENBQUM7UUFDSCxNQUFNLElBQUksR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pDLElBQUksQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFDO1FBQ2hCLElBQUksQ0FBQyxRQUFRLEdBQUcsNkJBQTZCLENBQUM7UUFDOUMsUUFBUSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2IsUUFBUSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsRUFBRSxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzlELENBQUM7SUFFRCxZQUFZO1FBQ1YsTUFBTSxvQkFBb0IsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsNkJBQTZCLENBQ25GLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxJQUFJLFFBQVEsRUFDaEM7WUFDRSxNQUFNLEVBQUUsSUFBSSxDQUFDLGlDQUFpQyxDQUFDLGdCQUFnQixFQUFFLENBQUMsTUFBTTtZQUN4RSxRQUFRLEVBQUUsSUFBSSxDQUFDLGlDQUFpQyxDQUFDLGdCQUFnQixFQUFFLENBQUMsUUFBUTtTQUM3RSxDQUNGLENBQUM7UUFDRixJQUFJLENBQUMsaUNBQWlDLENBQUMsc0JBQXNCLENBQUM7WUFDNUQsUUFBUSxFQUFFLElBQUksSUFBSSxDQUNoQixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsaUNBQWlDLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxPQUFPLEVBQUU7Z0JBQ3BGLG9CQUFvQixHQUFHLENBQUMsQ0FDM0IsQ0FBQyxXQUFXLEVBQUU7WUFDZixNQUFNLEVBQUUsSUFBSSxDQUFDLGlDQUFpQyxDQUFDLGdCQUFnQixFQUFFLENBQUMsTUFBTTtZQUN4RSxRQUFRLEVBQUUsUUFBUTtTQUNuQixDQUFDLENBQUM7UUFDSCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ2pELE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN4QyxJQUFJLENBQUMscUJBQXFCLENBQUMsSUFBSSxDQUFDO1lBQzlCLFFBQVEsRUFBRSxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDMUMsTUFBTSxFQUFFLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUN0QyxRQUFRLEVBQUUsUUFBUTtTQUNuQixDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQztJQUM1QixDQUFDO0lBRUQsUUFBUSxDQUNOLElBQU8sRUFDUCxJQUFZO1FBRVosSUFBSSxPQUFzQyxDQUFDO1FBQzNDLE9BQU8sQ0FBQyxHQUFHLElBQW1CLEVBQUUsRUFBRTtZQUNoQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDdEIsT0FBTyxHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNsRCxDQUFDLENBQUM7SUFDSixDQUFDO0lBRU8sc0JBQXNCO1FBQzVCLE9BQU87WUFDTCxLQUFLLEVBQUU7Z0JBQ0wsSUFBSSxFQUFFLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQztnQkFDbkMsSUFBSSxFQUFFLFFBQVE7Z0JBQ2QsR0FBRyxFQUFFLFFBQVE7Z0JBQ2IsU0FBUyxFQUFFLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRTthQUM1QjtZQUNELEtBQUssRUFBRSxJQUFJO1lBQ1gsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFO1lBQ3JDLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUU7WUFDeEIsTUFBTSxFQUFFLEVBQUU7U0FDWCxDQUFDO0lBQ0osQ0FBQztJQUVPLGlCQUFpQixDQUFDLGFBQXVCO1FBQy9DLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUN0QyxNQUFNLGlCQUFpQixHQUFHLHdCQUF3QixDQUFDO1FBQ25ELE1BQU0sZ0JBQWdCLEdBQUcsMEJBQTBCLENBQUM7UUFFcEQsT0FBTyxhQUFhLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxFQUFFO1lBQ3RDLE9BQU87Z0JBQ0w7b0JBQ0UsSUFBSSxFQUFFLFlBQVksQ0FBQyxJQUFJO29CQUN2QixLQUFLLEVBQUUsWUFBWSxDQUFDLFlBQVk7b0JBQ2hDLFNBQVMsRUFBRTt3QkFDVCxLQUFLLEVBQ0gsWUFBWSxDQUFDLE1BQU0sS0FBSyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCO3FCQUNyRjtpQkFDRjtnQkFDRDtvQkFDRSxLQUFLLEVBQ0gsWUFBWSxDQUFDLGFBQWEsQ0FBQyxLQUFLLFlBQVksQ0FBQyxZQUFZO3dCQUN6RCxZQUFZLENBQUMsTUFBTSxLQUFLLFdBQVcsQ0FBQyxPQUFPO3dCQUN6QyxDQUFDLENBQUMsU0FBUyxDQUFDLE1BQU07d0JBQ2xCLENBQUMsQ0FBQyxZQUFZLENBQUMsYUFBYSxDQUFDO2lCQUNsQzthQUNGLENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTyxpQkFBaUIsQ0FBQyxhQUF1QjtRQUMvQyxPQUFPLGFBQWEsQ0FBQyxNQUFNLENBQWlCLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ3pELE1BQU0scUJBQXFCLEdBQUcsS0FBSyxDQUFDLE1BQU0sS0FBSyxXQUFXLENBQUMsT0FBTyxDQUFDO1lBQ25FLElBQUkscUJBQXFCLEVBQUUsQ0FBQztnQkFDMUIsT0FBTyxHQUFHLENBQUMsTUFBTSxDQUFDO29CQUNoQjt3QkFDRSxLQUFLLEVBQUUsS0FBSyxDQUFDLFlBQVk7d0JBQ3pCLFFBQVEsRUFBRSxLQUFLLENBQUMsSUFBSTt3QkFDcEIsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRTt3QkFDbkQsU0FBUyxFQUFFLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRTtxQkFDckM7b0JBQ0Q7d0JBQ0UsS0FBSyxFQUFFLEtBQUssQ0FBQyxhQUFhLENBQUM7d0JBQzNCLFFBQVEsRUFBRSxLQUFLLENBQUMsSUFBSTt3QkFDcEIsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRTt3QkFDbkQsU0FBUyxFQUFFLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRTtxQkFDckM7aUJBQ0YsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUNELE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQztnQkFDaEI7b0JBQ0UsS0FBSyxFQUFFLEtBQUssQ0FBQyxZQUFZO29CQUN6QixRQUFRLEVBQUUsS0FBSyxDQUFDLElBQUk7b0JBQ3BCLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUU7b0JBQ25ELFNBQVMsRUFBRSxFQUFFLEtBQUssRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUU7aUJBQ3JDO2FBQ0YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ1QsQ0FBQztJQUVPLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxlQUFxQjtRQUNyRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDdEMsTUFBTSxnQkFBZ0IsR0FBRztZQUN2QixlQUFlLEVBQUUsZUFBZSxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsUUFBUTtZQUNoRixTQUFTLEVBQUUsZUFBZSxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsTUFBTTtTQUN2RSxDQUFDO1FBQ0YsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsbUJBQW1CO1lBQUUsT0FBTztRQUM3QyxNQUFNLHFCQUFxQixHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsbUJBQW1CLEVBQUUsTUFBTSxDQUNuRSxZQUFZLENBQUMsRUFBRSxDQUFDLENBQUMsWUFBWSxDQUFDLFFBQVEsSUFBSSxZQUFZLENBQUMsUUFBUSxDQUNoRSxDQUFDO1FBQ0YsTUFBTSxNQUFNLEdBQUcscUJBQXFCLEVBQUUsTUFBTSxDQUMxQyxZQUFZLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxZQUFZLEtBQUssT0FBTyxDQUM1QixDQUFDO1FBQzVCLE1BQU0sTUFBTSxHQUFHLHFCQUFxQixFQUFFLE1BQU0sQ0FDMUMsWUFBWSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsWUFBWSxLQUFLLE9BQU8sQ0FDNUIsQ0FBQztRQUU1QixNQUFNLENBQUMsWUFBWSxFQUFFLFlBQVksQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUNyRCxJQUFJLENBQUMsa0JBQWtCLENBQUMsVUFBVSxDQUFDLGdCQUFnQixFQUFFLE1BQU0sQ0FBQztZQUM1RCxJQUFJLENBQUMsa0JBQWtCLENBQUMsVUFBVSxDQUFDLGdCQUFnQixFQUFFLE1BQU0sQ0FBQztTQUM3RCxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsTUFBTSxHQUFHLFlBQVksQ0FBQztRQUMzQixJQUFJLENBQUMsTUFBTSxHQUFHLFlBQVksQ0FBQztRQUMzQixNQUFNLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFbkMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDbkUsQ0FBQztJQUVPLHVCQUF1QjtRQUM3QixNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM1RSxJQUFJLGdCQUFnQixJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUNyRSxJQUFJLENBQUMsb0JBQW9CLENBQUMsYUFBYSxDQUNyQyxJQUFJLENBQUMsZUFBZSxFQUNwQixnQkFBZ0IsRUFDaEIsSUFBSSxDQUFDLFlBQVksRUFBRSxFQUNuQixFQUFFLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQ3RDLFNBQVMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLHlCQUF5QixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFDM0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsRUFDL0I7Z0JBQ0UsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsSUFBSSxLQUFLO2dCQUN6RCxrQkFBa0IsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixJQUFJLEtBQUs7YUFDNUQsQ0FDRixDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFRDs7TUFFRTtJQUNNLEtBQUssQ0FBQyxlQUFlLENBQUMsTUFBOEI7UUFDMUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3RDLE1BQU0sTUFBTSxHQUFHO1lBQ2IsUUFBUSxFQUFFLDJCQUEyQjtZQUNyQyxNQUFNLEVBQUUsU0FBUyxDQUFDLE1BQU07WUFDeEIsTUFBTSxFQUFFLFdBQVcsQ0FBQyxNQUFNO1NBQzNCLENBQUM7UUFFRixNQUFNLFlBQVksR0FBRyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQzlFLElBQUksQ0FBQyxNQUFNLENBQUMsMEJBQTBCLEdBQUcsRUFBRSxDQUFDO1FBQzVDLDJJQUEySTtRQUMzSSxZQUFZLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxFQUFFO1lBQ2pDLE1BQU0sU0FBUyxHQUFHLFdBQVcsQ0FBQyxJQUFJLENBQUM7WUFDbkMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLFNBQVMsQ0FBQyxDQUFDO1lBQ2xFLElBQUksQ0FBQyxLQUFLLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQywwQkFBMEIsRUFBRSxDQUFDO2dCQUNyRCxJQUFJLENBQUMsTUFBTSxDQUFDLDBCQUEwQixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUN6RCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sS0FBSyxDQUFDLGVBQWUsQ0FBQyxvQkFBb0M7UUFDaEUsTUFBTSxTQUFTLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxZQUFZLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUM3RSxJQUFJLENBQUMsSUFBSSxDQUFDLGlDQUFpQyxDQUFDLGdCQUFnQixFQUFFLEVBQUUsQ0FBQztZQUMvRCxJQUFJLENBQUMsaUNBQWlDLENBQUMsc0JBQXNCLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDekUsTUFBTSxvQkFBb0IsR0FBRyxNQUFNLGFBQWEsQ0FDOUMsSUFBSSxDQUFDLHlCQUF5QixDQUFDO2dCQUM3QixRQUFRLEVBQUUsSUFBSSxJQUFJLENBQ2hCLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxPQUFPLEVBQUU7b0JBQ3BDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyw2QkFBNkIsQ0FDdEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLElBQUksUUFBUSxFQUNoQyxFQUFFLFFBQVEsRUFBRSxTQUFTLENBQUMsUUFBUSxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsTUFBTSxFQUFFLENBQzNELENBQ0osQ0FBQyxXQUFXLEVBQUU7Z0JBQ2YsTUFBTSxFQUFFLFNBQVMsQ0FBQyxNQUFNO2FBQ3pCLENBQUMsQ0FDSCxDQUFDO1lBQ0YsT0FBTyxJQUFJLENBQUMscUJBQXFCLENBQUMsZUFBZSxDQUMvQyxvQkFBb0IsRUFDcEIsU0FBUyxFQUNUO2dCQUNFLEtBQUssRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsSUFBSSxLQUFLO2dCQUMzQyxLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLElBQUksS0FBSzthQUM1QyxFQUNELElBQUksQ0FBQyxNQUFNLEVBQ1gsSUFBSSxDQUFDLE1BQU0sRUFDWDtnQkFDRSxpQkFBaUIsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLGlCQUFpQixJQUFJLEtBQUs7Z0JBQ3pELGtCQUFrQixFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsa0JBQWtCLElBQUksS0FBSztnQkFDM0QsdUJBQXVCLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyx1QkFBdUIsSUFBSSxLQUFLO2dCQUNyRSxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLGdCQUFnQixJQUFJLEtBQUs7Z0JBQ3ZELFVBQVUsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsSUFBSSxLQUFLO2FBQzVDLEVBQ0QsU0FBUyxFQUNULG9CQUFvQixDQUNyQixDQUFDO1FBQ0osQ0FBQzthQUFNLENBQUM7WUFDTixNQUFNLG9CQUFvQixHQUFHLE1BQU0sYUFBYSxDQUM5QyxJQUFJLENBQUMseUJBQXlCLENBQUM7Z0JBQzdCLFFBQVEsRUFBRSxJQUFJLElBQUksQ0FDaEIsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLGlDQUFpQyxDQUFDLGdCQUFnQixFQUFFLENBQUMsUUFBUSxDQUFDLENBQUMsT0FBTyxFQUFFO29CQUNwRixJQUFJLENBQUMscUJBQXFCLENBQUMsNkJBQTZCLENBQ3RELElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxJQUFJLFFBQVEsRUFDaEM7d0JBQ0UsUUFBUSxFQUFFLElBQUksQ0FBQyxpQ0FBaUMsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLFFBQVE7d0JBQzVFLE1BQU0sRUFBRSxJQUFJLENBQUMsaUNBQWlDLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxNQUFNO3FCQUN6RSxDQUNGLENBQ0osQ0FBQyxXQUFXLEVBQUU7Z0JBQ2YsTUFBTSxFQUFFLElBQUksSUFBSSxDQUNkLElBQUksQ0FBQyxpQ0FBaUMsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLE1BQU0sQ0FDakUsQ0FBQyxXQUFXLEVBQUU7YUFDaEIsQ0FBQyxDQUNILENBQUM7WUFDRixPQUFPLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxlQUFlLENBQy9DLG9CQUFvQixFQUNwQixJQUFJLENBQUMsaUNBQWlDLENBQUMsZ0JBQWdCLEVBQUUsRUFDekQ7Z0JBQ0UsS0FBSyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxJQUFJLEtBQUs7Z0JBQzNDLEtBQUssRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsSUFBSSxLQUFLO2FBQzVDLEVBQ0QsSUFBSSxDQUFDLE1BQU0sRUFDWCxJQUFJLENBQUMsTUFBTSxFQUNYO2dCQUNFLGlCQUFpQixFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsaUJBQWlCLElBQUksS0FBSztnQkFDekQsa0JBQWtCLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsSUFBSSxLQUFLO2dCQUMzRCx1QkFBdUIsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLHVCQUF1QixJQUFJLEtBQUs7Z0JBQ3JFLGdCQUFnQixFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLElBQUksS0FBSztnQkFDdkQsVUFBVSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxJQUFJLEtBQUs7YUFDNUMsRUFDRCxTQUFTLEVBQ1Qsb0JBQW9CLEVBQ3BCLElBQUksQ0FDTCxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFTyx5QkFBeUIsQ0FBQyxlQUFxQjtRQUNyRCxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM1RSxJQUFJLENBQUMsZ0JBQWdCLElBQUksZ0JBQWdCLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3ZELE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ2hCLENBQUM7UUFDRCxNQUFNLDRCQUE0QixHQUErQixFQUFFLENBQUM7UUFDcEUsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUM1QyxLQUFLLE1BQU0sRUFBRSxJQUFJLGdCQUFnQixFQUFFLENBQUM7WUFDbEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLGtCQUFrQjtpQkFDcEMsV0FBVyxDQUFDO2dCQUNYLEdBQUcsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO2dCQUNsRCxNQUFNLEVBQUUsRUFBRSxDQUFDLFFBQVEsRUFBRSxFQUFFLElBQUksRUFBRTtnQkFDN0IsTUFBTSxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDdkMsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxJQUFJLGVBQWU7b0JBQzVDLENBQUMsQ0FBQzt3QkFDRSxlQUFlLEVBQUUsZUFBZSxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVc7cUJBQ3BGO29CQUNILENBQUMsQ0FBQyxFQUFFLENBQUM7YUFDUixDQUFDO2lCQUNELElBQUksQ0FDSCxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUU7Z0JBQ1IsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7Z0JBQy9CLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztvQkFDL0MsTUFBTSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDcEYsQ0FBQztxQkFBTSxDQUFDO29CQUNOLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO3dCQUNoQixJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUN0QixDQUFDO2dCQUNILENBQUM7Z0JBQ0QsT0FBTyxFQUFFLEdBQUcsRUFBRSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUMxRCxDQUFDLENBQUMsQ0FDSCxDQUFDO1lBRUosNEJBQTRCLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzdDLENBQUM7UUFDRCxPQUFPLFFBQVEsQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDLElBQUksQ0FDaEQsR0FBRyxDQUFDLENBQUMsYUFBNkIsRUFBRSxFQUFFO1lBQ3BDLElBQUksYUFBYSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQzlDLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1lBQy9CLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FDSCxDQUFDO0lBQ0osQ0FBQztJQUVPLHFCQUFxQjtRQUMzQixJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssU0FBUyxDQU