ethio-calendar-converter-angular
Version:
Ethiopian Calendar Converter for Angular applications
494 lines (468 loc) • 48.6 kB
JavaScript
import { Component, Output, EventEmitter } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import * as i0 from "@angular/core";
import * as i1 from "./ethiopian-calendar.service";
import * as i2 from "@angular/common";
import * as i3 from "@angular/forms";
export class EthiopianCalendarComponent {
calendarService;
ethiopianDate = { year: 2015, month: 4, day: 25 };
gregorianDate = { year: 2022, month: 3, day: 25 };
lastConversion = '';
showEthiopianPicker = false;
ethiopianMonths = [
{ value: 1, label: 'Meskerem' },
{ value: 2, label: 'Tikimt' },
{ value: 3, label: 'Hidar' },
{ value: 4, label: 'Tahsas' },
{ value: 5, label: 'Tir' },
{ value: 6, label: 'Yekatit' },
{ value: 7, label: 'Megabit' },
{ value: 8, label: 'Miyazia' },
{ value: 9, label: 'Ginbot' },
{ value: 10, label: 'Sene' },
{ value: 11, label: 'Hamle' },
{ value: 12, label: 'Nehase' },
{ value: 13, label: 'Pagume' }
];
get ethiopianYears() {
const currentYear = new Date().getFullYear();
const years = [];
for (let i = currentYear - 100; i <= currentYear + 100; i++) {
years.push(i - 8); // Convert to approximate Ethiopian year
}
return years;
}
ethiopianDateChange = new EventEmitter();
gregorianDateChange = new EventEmitter();
constructor(calendarService) {
this.calendarService = calendarService;
}
toggleEthiopianPicker() {
this.showEthiopianPicker = !this.showEthiopianPicker;
}
getEthiopianDays() {
const maxDays = this.ethiopianDate.month === 13 ?
(this.calendarService['isEthiopianLeapYear'](this.ethiopianDate.year) ? 6 : 5) :
30;
return Array.from({ length: maxDays }, (_, i) => i + 1);
}
applyEthiopianDate() {
this.convertToGregorian();
this.toggleEthiopianPicker();
}
formatEthiopianDateForDisplay(date) {
const monthName = this.ethiopianMonths.find(m => m.value === date.month)?.label || '';
return `${monthName} ${date.day}, ${date.year}`;
}
convertToGregorian() {
try {
this.gregorianDate = this.calendarService.toGregorian(this.ethiopianDate);
this.gregorianDateChange.emit(this.gregorianDate);
this.lastConversion = `Ethiopian ${this.formatDate(this.ethiopianDate)} → Gregorian ${this.formatDate(this.gregorianDate)}`;
}
catch (error) {
this.lastConversion = 'Invalid Ethiopian date';
}
}
convertToEthiopian() {
try {
this.ethiopianDate = this.calendarService.toEthiopian(this.gregorianDate);
this.ethiopianDateChange.emit(this.ethiopianDate);
this.lastConversion = `Gregorian ${this.formatDate(this.gregorianDate)} → Ethiopian ${this.formatDate(this.ethiopianDate)}`;
}
catch (error) {
this.lastConversion = 'Invalid Gregorian date';
}
}
onGregorianDateSelected(event) {
const date = new Date(event.target.value);
this.gregorianDate = {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate()
};
this.convertToEthiopian();
}
formatDate(date) {
return `${date.year}-${String(date.month).padStart(2, '0')}-${String(date.day).padStart(2, '0')}`;
}
formatDateForInput(date) {
return `${date.year}-${String(date.month).padStart(2, '0')}-${String(date.day).padStart(2, '0')}`;
}
formatGregorianDate(date) {
return new Date(date.year, date.month - 1, date.day)
.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
}
weekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
previousMonth() {
if (this.ethiopianDate.month > 1) {
this.ethiopianDate.month--;
}
else {
this.ethiopianDate.month = 13;
this.ethiopianDate.year--;
}
this.updateEthiopianDate();
}
nextMonth() {
if (this.ethiopianDate.month < 13) {
this.ethiopianDate.month++;
}
else {
this.ethiopianDate.month = 1;
this.ethiopianDate.year++;
}
this.updateEthiopianDate();
}
getDaysArray() {
const daysInMonth = this.ethiopianDate.month === 13 ?
(this.calendarService['isEthiopianLeapYear'](this.ethiopianDate.year) ? 6 : 5) :
30;
// Create array with padding for alignment
const days = [];
const firstDayOffset = this.getFirstDayOffset();
// Add padding
for (let i = 0; i < firstDayOffset; i++) {
days.push(0);
}
// Add days
for (let i = 1; i <= daysInMonth; i++) {
days.push(i);
}
return days;
}
getFirstDayOffset() {
// This is a simplified version - you might want to implement proper Ethiopian calendar day-of-week calculation
return (this.ethiopianDate.month * 2) % 7;
}
getDayClasses(day) {
const baseClasses = 'h-8 w-8 rounded-full flex items-center justify-center text-sm';
const isSelected = day === this.ethiopianDate.day;
if (isSelected) {
return `${baseClasses} bg-blue-600 text-white`;
}
return `${baseClasses} hover:bg-gray-100 text-gray-700`;
}
selectDay(day) {
this.ethiopianDate.day = day;
this.updateEthiopianDate();
this.toggleEthiopianPicker();
}
selectToday() {
const today = this.calendarService.toEthiopian({
year: new Date().getFullYear(),
month: new Date().getMonth() + 1,
day: new Date().getDate()
});
this.ethiopianDate = today;
this.updateEthiopianDate();
this.toggleEthiopianPicker();
}
updateEthiopianDate() {
this.ethiopianDateChange.emit(this.ethiopianDate);
this.convertToGregorian();
}
formatEthiopianDateForInput(date) {
const monthName = this.ethiopianMonths.find(m => m.value === date.month)?.label || '';
return `${monthName} ${date.day}, ${date.year}`;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EthiopianCalendarComponent, deps: [{ token: i1.EthiopianCalendarService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: EthiopianCalendarComponent, isStandalone: true, selector: "ethiopian-calendar", outputs: { ethiopianDateChange: "ethiopianDateChange", gregorianDateChange: "gregorianDateChange" }, ngImport: i0, template: `
<div class="bg-white rounded-lg shadow-lg p-6 max-w-md mx-auto">
<!-- Ethiopian Calendar Input -->
<div class="mb-8">
<h3 class="text-lg font-medium text-gray-900 mb-4">Ethiopian Calendar</h3>
<div class="relative">
<input
type="text"
[value]="formatEthiopianDateForInput(ethiopianDate)"
(click)="toggleEthiopianPicker()"
readonly
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all cursor-pointer"
/>
<label class="absolute -top-2 left-2 bg-white px-1 text-xs text-gray-600">Select Date</label>
<!-- Calendar Icon -->
<button
(click)="toggleEthiopianPicker()"
class="absolute right-2 top-2 text-gray-400 hover:text-gray-600 focus:outline-none"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
</button>
<!-- Ethiopian Calendar Picker -->
<div *ngIf="showEthiopianPicker"
class="absolute left-0 mt-1 p-4 bg-white rounded-lg shadow-lg border border-gray-200 z-50 w-[320px]">
<!-- Month and Year Navigation -->
<div class="flex justify-between items-center mb-4">
<button
(click)="previousMonth()"
class="p-1 hover:bg-gray-100 rounded-full"
>
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg>
</button>
<div class="flex items-center space-x-2">
<select
[(ngModel)]="ethiopianDate.month"
(change)="updateEthiopianDate()"
class="text-sm border-none bg-transparent font-semibold focus:outline-none focus:ring-0"
>
<option *ngFor="let month of ethiopianMonths" [value]="month.value">
{{month.label}}
</option>
</select>
<select
[(ngModel)]="ethiopianDate.year"
(change)="updateEthiopianDate()"
class="text-sm border-none bg-transparent font-semibold focus:outline-none focus:ring-0"
>
<option *ngFor="let year of ethiopianYears" [value]="year">{{year}}</option>
</select>
</div>
<button
(click)="nextMonth()"
class="p-1 hover:bg-gray-100 rounded-full"
>
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
<!-- Calendar Grid -->
<div class="grid grid-cols-7 gap-1">
<!-- Week days -->
<div *ngFor="let day of weekDays"
class="text-center text-xs font-medium text-gray-500 py-1">
{{day}}
</div>
<!-- Days -->
<ng-container *ngFor="let day of getDaysArray()">
<button *ngIf="day !== 0"
(click)="selectDay(day)"
[class]="getDayClasses(day)"
>
{{day}}
</button>
<div *ngIf="day === 0" class="h-8"></div>
</ng-container>
</div>
<!-- Today Button -->
<div class="mt-4 flex justify-between items-center border-t pt-4">
<button
(click)="selectToday()"
class="text-sm text-blue-600 hover:text-blue-800 font-medium"
>
Today
</button>
<button
(click)="toggleEthiopianPicker()"
class="text-sm text-gray-600 hover:text-gray-800 font-medium"
>
Close
</button>
</div>
</div>
</div>
<div *ngIf="ethiopianDate" class="mt-2 text-sm text-gray-600">
Selected: {{formatEthiopianDateForDisplay(ethiopianDate)}}
</div>
<button
(click)="convertToGregorian()"
class="mt-4 w-full bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors"
>
Convert to Gregorian
</button>
</div>
<!-- Gregorian Calendar Input -->
<div class="mb-8">
<h3 class="text-lg font-medium text-gray-900 mb-4">Gregorian Calendar</h3>
<div class="relative">
<input
type="date"
[value]="formatDateForInput(gregorianDate)"
(change)="onGregorianDateSelected($event)"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
/>
<label class="absolute -top-2 left-2 bg-white px-1 text-xs text-gray-600">Select Date</label>
</div>
<div *ngIf="gregorianDate" class="mt-2 text-sm text-gray-600">
Selected: {{formatGregorianDate(gregorianDate)}}
</div>
<button
(click)="convertToEthiopian()"
class="mt-4 w-full bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors"
>
Convert to Ethiopian
</button>
</div>
<!-- Conversion Result -->
<div *ngIf="lastConversion"
class="p-4 bg-gray-50 rounded-lg border border-gray-200">
<p class="text-sm font-medium text-gray-900">Last Conversion:</p>
<p class="text-sm text-gray-600 mt-1">{{lastConversion}}</p>
</div>
</div>
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EthiopianCalendarComponent, decorators: [{
type: Component,
args: [{
selector: 'ethiopian-calendar',
standalone: true,
imports: [
CommonModule,
FormsModule
],
template: `
<div class="bg-white rounded-lg shadow-lg p-6 max-w-md mx-auto">
<!-- Ethiopian Calendar Input -->
<div class="mb-8">
<h3 class="text-lg font-medium text-gray-900 mb-4">Ethiopian Calendar</h3>
<div class="relative">
<input
type="text"
[value]="formatEthiopianDateForInput(ethiopianDate)"
(click)="toggleEthiopianPicker()"
readonly
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all cursor-pointer"
/>
<label class="absolute -top-2 left-2 bg-white px-1 text-xs text-gray-600">Select Date</label>
<!-- Calendar Icon -->
<button
(click)="toggleEthiopianPicker()"
class="absolute right-2 top-2 text-gray-400 hover:text-gray-600 focus:outline-none"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
</button>
<!-- Ethiopian Calendar Picker -->
<div *ngIf="showEthiopianPicker"
class="absolute left-0 mt-1 p-4 bg-white rounded-lg shadow-lg border border-gray-200 z-50 w-[320px]">
<!-- Month and Year Navigation -->
<div class="flex justify-between items-center mb-4">
<button
(click)="previousMonth()"
class="p-1 hover:bg-gray-100 rounded-full"
>
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg>
</button>
<div class="flex items-center space-x-2">
<select
[(ngModel)]="ethiopianDate.month"
(change)="updateEthiopianDate()"
class="text-sm border-none bg-transparent font-semibold focus:outline-none focus:ring-0"
>
<option *ngFor="let month of ethiopianMonths" [value]="month.value">
{{month.label}}
</option>
</select>
<select
[(ngModel)]="ethiopianDate.year"
(change)="updateEthiopianDate()"
class="text-sm border-none bg-transparent font-semibold focus:outline-none focus:ring-0"
>
<option *ngFor="let year of ethiopianYears" [value]="year">{{year}}</option>
</select>
</div>
<button
(click)="nextMonth()"
class="p-1 hover:bg-gray-100 rounded-full"
>
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
<!-- Calendar Grid -->
<div class="grid grid-cols-7 gap-1">
<!-- Week days -->
<div *ngFor="let day of weekDays"
class="text-center text-xs font-medium text-gray-500 py-1">
{{day}}
</div>
<!-- Days -->
<ng-container *ngFor="let day of getDaysArray()">
<button *ngIf="day !== 0"
(click)="selectDay(day)"
[class]="getDayClasses(day)"
>
{{day}}
</button>
<div *ngIf="day === 0" class="h-8"></div>
</ng-container>
</div>
<!-- Today Button -->
<div class="mt-4 flex justify-between items-center border-t pt-4">
<button
(click)="selectToday()"
class="text-sm text-blue-600 hover:text-blue-800 font-medium"
>
Today
</button>
<button
(click)="toggleEthiopianPicker()"
class="text-sm text-gray-600 hover:text-gray-800 font-medium"
>
Close
</button>
</div>
</div>
</div>
<div *ngIf="ethiopianDate" class="mt-2 text-sm text-gray-600">
Selected: {{formatEthiopianDateForDisplay(ethiopianDate)}}
</div>
<button
(click)="convertToGregorian()"
class="mt-4 w-full bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors"
>
Convert to Gregorian
</button>
</div>
<!-- Gregorian Calendar Input -->
<div class="mb-8">
<h3 class="text-lg font-medium text-gray-900 mb-4">Gregorian Calendar</h3>
<div class="relative">
<input
type="date"
[value]="formatDateForInput(gregorianDate)"
(change)="onGregorianDateSelected($event)"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
/>
<label class="absolute -top-2 left-2 bg-white px-1 text-xs text-gray-600">Select Date</label>
</div>
<div *ngIf="gregorianDate" class="mt-2 text-sm text-gray-600">
Selected: {{formatGregorianDate(gregorianDate)}}
</div>
<button
(click)="convertToEthiopian()"
class="mt-4 w-full bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors"
>
Convert to Ethiopian
</button>
</div>
<!-- Conversion Result -->
<div *ngIf="lastConversion"
class="p-4 bg-gray-50 rounded-lg border border-gray-200">
<p class="text-sm font-medium text-gray-900">Last Conversion:</p>
<p class="text-sm text-gray-600 mt-1">{{lastConversion}}</p>
</div>
</div>
`
}]
}], ctorParameters: () => [{ type: i1.EthiopianCalendarService }], propDecorators: { ethiopianDateChange: [{
type: Output
}], gregorianDateChange: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXRoaW9waWFuLWNhbGVuZGFyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvZXRoaW9waWFuLWNhbGVuZGFyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDaEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7Ozs7QUFtSy9DLE1BQU0sT0FBTywwQkFBMEI7SUFrQ2pCO0lBakNwQixhQUFhLEdBQWtCLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUNqRSxhQUFhLEdBQWtCLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUNqRSxjQUFjLEdBQVcsRUFBRSxDQUFDO0lBQzVCLG1CQUFtQixHQUFZLEtBQUssQ0FBQztJQUVyQyxlQUFlLEdBQUc7UUFDaEIsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUU7UUFDL0IsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUU7UUFDN0IsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUU7UUFDNUIsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUU7UUFDN0IsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUU7UUFDMUIsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUU7UUFDOUIsRUFBRSxL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SSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxLQUFLLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxLQUFLLElBQUksRUFBRSxDQUFDO1FBQ3RGLE9BQU8sR0FBRyxTQUFTLElBQUksSUFBSSxDQUFDLEdBQUcsS0FBSyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDbEQsQ0FBQzt3R0E3TFUsMEJBQTBCOzRGQUExQiwwQkFBMEIsbUxBeEozQjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0pULDJEQXpKQyxZQUFZLCtQQUNaLFdBQVc7OzRGQTBKRiwwQkFBMEI7a0JBL0p0QyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSxvQkFBb0I7b0JBQzlCLFVBQVUsRUFBRSxJQUFJO29CQUNoQixPQUFPLEVBQUU7d0JBQ1AsWUFBWTt3QkFDWixXQUFXO3FCQUNaO29CQUNELFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0pUO2lCQUNGOzZGQWdDVyxtQkFBbUI7c0JBQTVCLE1BQU07Z0JBQ0csbUJBQW1CO3NCQUE1QixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBPdXRwdXQsIEV2ZW50RW1pdHRlciB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgRXRoaW9waWFuQ2FsZW5kYXJTZXJ2aWNlIH0gZnJvbSAnLi9ldGhpb3BpYW4tY2FsZW5kYXIuc2VydmljZSc7XG5pbXBvcnQgeyBFdGhpb3BpYW5EYXRlLCBHcmVnb3JpYW5EYXRlIH0gZnJvbSAnLi9tb2RlbHMvY2FsZW5kYXIubW9kZWwnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdldGhpb3BpYW4tY2FsZW5kYXInLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgQ29tbW9uTW9kdWxlLFxuICAgIEZvcm1zTW9kdWxlXG4gIF0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdiBjbGFzcz1cImJnLXdoaXRlIHJvdW5kZWQtbGcgc2hhZG93LWxnIHAtNiBtYXgtdy1tZCBteC1hdXRvXCI+XG4gICAgICA8IS0tIEV0aGlvcGlhbiBDYWxlbmRhciBJbnB1dCAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJtYi04XCI+XG4gICAgICAgIDxoMyBjbGFzcz1cInRleHQtbGcgZm9udC1tZWRpdW0gdGV4dC1ncmF5LTkwMCBtYi00XCI+RXRoaW9waWFuIENhbGVuZGFyPC9oMz5cbiAgICAgICAgPGRpdiBjbGFzcz1cInJlbGF0aXZlXCI+XG4gICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICBbdmFsdWVdPVwiZm9ybWF0RXRoaW9waWFuRGF0ZUZvcklucHV0KGV0aGlvcGlhbkRhdGUpXCJcbiAgICAgICAgICAgIChjbGljayk9XCJ0b2dnbGVFdGhpb3BpYW5QaWNrZXIoKVwiXG4gICAgICAgICAgICByZWFkb25seVxuICAgICAgICAgICAgY2xhc3M9XCJ3LWZ1bGwgcHgtMyBweS0yIGJvcmRlciBib3JkZXItZ3JheS0zMDAgcm91bmRlZC1tZCBmb2N1czpvdXRsaW5lLW5vbmUgZm9jdXM6cmluZy0yIGZvY3VzOnJpbmctYmx1ZS01MDAgZm9jdXM6Ym9yZGVyLXRyYW5zcGFyZW50IHRyYW5zaXRpb24tYWxsIGN1cnNvci1wb2ludGVyXCJcbiAgICAgICAgICAvPlxuICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImFic29sdXRlIC10b3AtMiBsZWZ0LTIgYmctd2hpdGUgcHgtMSB0ZXh0LXhzIHRleHQtZ3JheS02MDBcIj5TZWxlY3QgRGF0ZTwvbGFiZWw+XG4gICAgICAgICAgXG4gICAgICAgICAgPCEtLSBDYWxlbmRhciBJY29uIC0tPlxuICAgICAgICAgIDxidXR0b24gXG4gICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlRXRoaW9waWFuUGlja2VyKClcIlxuICAgICAgICAgICAgY2xhc3M9XCJhYnNvbHV0ZSByaWdodC0yIHRvcC0yIHRleHQtZ3JheS00MDAgaG92ZXI6dGV4dC1ncmF5LTYwMCBmb2N1czpvdXRsaW5lLW5vbmVcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIGNsYXNzPVwiaC01IHctNVwiIGZpbGw9XCJub25lXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiPlxuICAgICAgICAgICAgICA8cGF0aCBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiBzdHJva2Utd2lkdGg9XCIyXCIgZD1cIk04IDdWM204IDRWM20tOSA4aDEwTTUgMjFoMTRhMiAyIDAgMDAyLTJWN2EyIDIgMCAwMC0yLTJINWEyIDIgMCAwMC0yIDJ2MTJhMiAyIDAgMDAyIDJ6XCIgLz5cbiAgICAgICAgICAgIDwvc3ZnPlxuICAgICAgICAgIDwvYnV0dG9uPlxuXG4gICAgICAgICAgPCEtLSBFdGhpb3BpYW4gQ2FsZW5kYXIgUGlja2VyIC0tPlxuICAgICAgICAgIDxkaXYgKm5nSWY9XCJzaG93RXRoaW9waWFuUGlja2VyXCIgXG4gICAgICAgICAgICAgICBjbGFzcz1cImFic29sdXRlIGxlZnQtMCBtdC0xIHAtNCBiZy13aGl0ZSByb3VuZGVkLWxnIHNoYWRvdy1sZyBib3JkZXIgYm9yZGVyLWdyYXktMjAwIHotNTAgdy1bMzIwcHhdXCI+XG4gICAgICAgICAgICA8IS0tIE1vbnRoIGFuZCBZZWFyIE5hdmlnYXRpb24gLS0+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmxleCBqdXN0aWZ5LWJldHdlZW4gaXRlbXMtY2VudGVyIG1iLTRcIj5cbiAgICAgICAgICAgICAgPGJ1dHRvbiBcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwicHJldmlvdXNNb250aCgpXCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cInAtMSBob3ZlcjpiZy1ncmF5LTEwMCByb3VuZGVkLWZ1bGxcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPHN2ZyBjbGFzcz1cImgtNSB3LTVcIiBmaWxsPVwibm9uZVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIj5cbiAgICAgICAgICAgICAgICAgIDxwYXRoIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiIHN0cm9rZS13aWR0aD1cIjJcIiBkPVwiTTE1IDE5bC03LTcgNy03XCIgLz5cbiAgICAgICAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgIFxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIgc3BhY2UteC0yXCI+XG4gICAgICAgICAgICAgICAgPHNlbGVjdCBcbiAgICAgICAgICAgICAgICAgIFsobmdNb2RlbCldPVwiZXRoaW9waWFuRGF0ZS5tb250aFwiXG4gICAgICAgICAgICAgICAgICAoY2hhbmdlKT1cInVwZGF0ZUV0aGlvcGlhbkRhdGUoKVwiXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cInRleHQtc20gYm9yZGVyLW5vbmUgYmctdHJhbnNwYXJlbnQgZm9udC1zZW1pYm9sZCBmb2N1czpvdXRsaW5lLW5vbmUgZm9jdXM6cmluZy0wXCJcbiAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICA8b3B0aW9uICpuZ0Zvcj1cImxldCBtb250aCBvZiBldGhpb3BpYW5Nb250aHNcIiBbdmFsdWVdPVwibW9udGgudmFsdWVcIj5cbiAgICAgICAgICAgICAgICAgICAge3ttb250aC5sYWJlbH19XG4gICAgICAgICAgICAgICAgICA8L29wdGlvbj5cbiAgICAgICAgICAgICAgICA8L3NlbGVjdD5cbiAgICAgICAgICAgICAgICA8c2VsZWN0IFxuICAgICAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJldGhpb3BpYW5EYXRlLnllYXJcIlxuICAgICAgICAgICAgICAgICAgKGNoYW5nZSk9XCJ1cGRhdGVFdGhpb3BpYW5EYXRlKClcIlxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LXNtIGJvcmRlci1ub25lIGJnLXRyYW5zcGFyZW50IGZvbnQtc2VtaWJvbGQgZm9jdXM6b3V0bGluZS1ub25lIGZvY3VzOnJpbmctMFwiXG4gICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgPG9wdGlvbiAqbmdGb3I9XCJsZXQgeWVhciBvZiBldGhpb3BpYW5ZZWFyc1wiIFt2YWx1ZV09XCJ5ZWFyXCI+e3t5ZWFyfX08L29wdGlvbj5cbiAgICAgICAgICAgICAgICA8L3NlbGVjdD5cbiAgICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgICAgPGJ1dHRvbiBcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwibmV4dE1vbnRoKClcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwicC0xIGhvdmVyOmJnLWdyYXktMTAwIHJvdW5kZWQtZnVsbFwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8c3ZnIGNsYXNzPVwiaC01IHctNVwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiPlxuICAgICAgICAgICAgICAgICAgPHBhdGggc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIGQ9XCJNOSA1bDcgNy03IDdcIiAvPlxuICAgICAgICAgICAgICAgIDwvc3ZnPlxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8IS0tIENhbGVuZGFyIEdyaWQgLS0+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZ3JpZCBncmlkLWNvbHMtNyBnYXAtMVwiPlxuICAgICAgICAgICAgICA8IS0tIFdlZWsgZGF5cyAtLT5cbiAgICAgICAgICAgICAgPGRpdiAqbmdGb3I9XCJsZXQgZGF5IG9mIHdlZWtEYXlzXCIgXG4gICAgICAgICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LWNlbnRlciB0ZXh0LXhzIGZvbnQtbWVkaXVtIHRleHQtZ3JheS01MDAgcHktMVwiPlxuICAgICAgICAgICAgICAgIHt7ZGF5fX1cbiAgICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgICAgPCEtLSBEYXlzIC0tPlxuICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBkYXkgb2YgZ2V0RGF5c0FycmF5KClcIj5cbiAgICAgICAgICAgICAgICA8YnV0dG9uICpuZ0lmPVwiZGF5ICE9PSAwXCJcbiAgICAgICAgICAgICAgICAgIChjbGljayk9XCJzZWxlY3REYXkoZGF5KVwiXG4gICAgICAgICAgICAgICAgICBbY2xhc3NdPVwiZ2V0RGF5Q2xhc3NlcyhkYXkpXCJcbiAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICB7e2RheX19XG4gICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgICAgPGRpdiAqbmdJZj1cImRheSA9PT0gMFwiIGNsYXNzPVwiaC04XCI+PC9kaXY+XG4gICAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIDwhLS0gVG9kYXkgQnV0dG9uIC0tPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm10LTQgZmxleCBqdXN0aWZ5LWJldHdlZW4gaXRlbXMtY2VudGVyIGJvcmRlci10IHB0LTRcIj5cbiAgICAgICAgICAgICAgPGJ1dHRvbiBcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwic2VsZWN0VG9kYXkoKVwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LXNtIHRleHQtYmx1ZS02MDAgaG92ZXI6dGV4dC1ibHVlLTgwMCBmb250LW1lZGl1bVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICBUb2RheVxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgPGJ1dHRvbiBcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlRXRoaW9waWFuUGlja2VyKClcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwidGV4dC1zbSB0ZXh0LWdyYXktNjAwIGhvdmVyOnRleHQtZ3JheS04MDAgZm9udC1tZWRpdW1cIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgQ2xvc2VcbiAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgPGRpdiAqbmdJZj1cImV0aGlvcGlhbkRhdGVcIiBjbGFzcz1cIm10LTIgdGV4dC1zbSB0ZXh0LWdyYXktNjAwXCI+XG4gICAgICAgICAgU2VsZWN0ZWQ6IHt7Zm9ybWF0RXRoaW9waWFuRGF0ZUZvckRpc3BsYXkoZXRoaW9waWFuRGF0ZSl9fVxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgKGNsaWNrKT1cImNvbnZlcnRUb0dyZWdvcmlhbigpXCJcbiAgICAgICAgICBjbGFzcz1cIm10LTQgdy1mdWxsIGJnLWJsdWUtNjAwIHRleHQtd2hpdGUgcHgtNCBweS0yIHJvdW5kZWQtbWQgaG92ZXI6YmctYmx1ZS03MDAgZm9jdXM6b3V0bGluZS1ub25lIGZvY3VzOnJpbmctMiBmb2N1czpyaW5nLWJsdWUtNTAwIGZvY3VzOnJpbmctb2Zmc2V0LTIgdHJhbnNpdGlvbi1jb2xvcnNcIlxuICAgICAgICA+XG4gICAgICAgICAgQ29udmVydCB0byBHcmVnb3JpYW5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSBHcmVnb3JpYW4gQ2FsZW5kYXIgSW5wdXQgLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwibWItOFwiPlxuICAgICAgICA8aDMgY2xhc3M9XCJ0ZXh0LWxnIGZvbnQtbWVkaXVtIHRleHQtZ3JheS05MDAgbWItNFwiPkdyZWdvcmlhbiBDYWxlbmRhcjwvaDM+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJyZWxhdGl2ZVwiPlxuICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgdHlwZT1cImRhdGVcIlxuICAgICAgICAgICAgW3ZhbHVlXT1cImZvcm1hdERhdGVGb3JJbnB1dChncmVnb3JpYW5EYXRlKVwiXG4gICAgICAgICAgICAoY2hhbmdlKT1cIm9uR3JlZ29yaWFuRGF0ZVNlbGVjdGVkKCRldmVudClcIlxuICAgICAgICAgICAgY2xhc3M9XCJ3LWZ1bGwgcHgtMyBweS0yIGJvcmRlciBib3JkZXItZ3JheS0zMDAgcm91bmRlZC1tZCBmb2N1czpvdXRsaW5lLW5vbmUgZm9jdXM6cmluZy0yIGZvY3VzOnJpbmctYmx1ZS01MDAgZm9jdXM6Ym9yZGVyLXRyYW5zcGFyZW50IHRyYW5zaXRpb24tYWxsXCJcbiAgICAgICAgICAvPlxuICAgICAgICAgIDxsYWJlbCBjbGFzcz1cImFic29sdXRlIC10b3AtMiBsZWZ0LTIgYmctd2hpdGUgcHgtMSB0ZXh0LXhzIHRleHQtZ3JheS02MDBcIj5TZWxlY3QgRGF0ZTwvbGFiZWw+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgKm5nSWY9XCJncmVnb3JpYW5EYXRlXCIgY2xhc3M9XCJtdC0yIHRleHQtc20gdGV4dC1ncmF5LTYwMFwiPlxuICAgICAgICAgIFNlbGVjdGVkOiB7e2Zvcm1hdEdyZWdvcmlhbkRhdGUoZ3JlZ29yaWFuRGF0ZSl9fVxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgKGNsaWNrKT1cImNvbnZlcnRUb0V0aGlvcGlhbigpXCJcbiAgICAgICAgICBjbGFzcz1cIm10LTQgdy1mdWxsIGJnLWJsdWUtNjAwIHRleHQtd2hpdGUgcHgtNCBweS0yIHJvdW5kZWQtbWQgaG92ZXI6YmctYmx1ZS03MDAgZm9jdXM6b3V0bGluZS1ub25lIGZvY3VzOnJpbmctMiBmb2N1czpyaW5nLWJsdWUtNTAwIGZvY3VzOnJpbmctb2Zmc2V0LTIgdHJhbnNpdGlvbi1jb2xvcnNcIlxuICAgICAgICA+XG4gICAgICAgICAgQ29udmVydCB0byBFdGhpb3BpYW5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSBDb252ZXJzaW9uIFJlc3VsdCAtLT5cbiAgICAgIDxkaXYgKm5nSWY9XCJsYXN0Q29udmVyc2lvblwiIFxuICAgICAgICAgICBjbGFzcz1cInAtNCBiZy1ncmF5LTUwIHJvdW5kZWQtbGcgYm9yZGVyIGJvcmRlci1ncmF5LTIwMFwiPlxuICAgICAgICA8cCBjbGFzcz1cInRleHQtc20gZm9udC1tZWRpdW0gdGV4dC1ncmF5LTkwMFwiPkxhc3QgQ29udmVyc2lvbjo8L3A+XG4gICAgICAgIDxwIGNsYXNzPVwidGV4dC1zbSB0ZXh0LWdyYXktNjAwIG10LTFcIj57e2xhc3RDb252ZXJzaW9ufX08L3A+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgYFxufSlcbmV4cG9ydCBjbGFzcyBFdGhpb3BpYW5DYWxlbmRhckNvbXBvbmVudCB7XG4gIGV0aGlvcGlhbkRhdGU6IEV0aGlvcGlhbkRhdGUgPSB7IHllYXI6IDIwMTUsIG1vbnRoOiA0LCBkYXk6IDI1IH07XG4gIGdyZWdvcmlhbkRhdGU6IEdyZWdvcmlhbkRhdGUgPSB7IHllYXI6IDIwMjIsIG1vbnRoOiAzLCBkYXk6IDI1IH07XG4gIGxhc3RDb252ZXJzaW9uOiBzdHJpbmcgPSAnJztcbiAgc2hvd0V0aGlvcGlhblBpY2tlcjogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIGV0aGlvcGlhbk1vbnRocyA9IFtcbiAgICB7IHZhbHVlOiAxLCBsYWJlbDogJ01lc2tlcmVtJyB9LFxuICAgIHsgdmFsdWU6IDIsIGxhYmVsOiAnVGlraW10JyB9LFxuICAgIHsgdmFsdWU6IDMsIGxhYmVsOiAnSGlkYXInIH0sXG4gICAgeyB2YWx1ZTogNCwgbGFiZWw6ICdUYWhzYXMnIH0sXG4gICAgeyB2YWx1ZTogNSwgbGFiZWw6ICdUaXInIH0sXG4gICAgeyB2YWx1ZTogNiwgbGFiZWw6ICdZZWthdGl0JyB9LFxuICAgIHsgdmFsdWU6IDcsIGxhYmVsOiAnTWVnYWJpdCcgfSxcbiAgICB7IHZhbHVlOiA4LCBsYWJlbDogJ01peWF6aWEnIH0sXG4gICAgeyB2YWx1ZTogOSwgbGFiZWw6ICdHaW5ib3QnIH0sXG4gICAgeyB2YWx1ZTogMTAsIGxhYmVsOiAnU2VuZScgfSxcbiAgICB7IHZhbHVlOiAxMSwgbGFiZWw6ICdIYW1sZScgfSxcbiAgICB7IHZhbHVlOiAxMiwgbGFiZWw6ICdOZWhhc2UnIH0sXG4gICAgeyB2YWx1ZTogMTMsIGxhYmVsOiAnUGFndW1lJyB9XG4gIF07XG5cbiAgZ2V0IGV0aGlvcGlhblllYXJzKCk6IG51bWJlcltdIHtcbiAgICBjb25zdCBjdXJyZW50WWVhciA9IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKTtcbiAgICBjb25zdCB5ZWFyczogbnVtYmVyW10gPSBbXTtcbiAgICBmb3IgKGxldCBpID0gY3VycmVudFllYXIgLSAxMDA7IGkgPD0gY3VycmVudFllYXIgKyAxMDA7IGkrKykge1xuICAgICAgeWVhcnMucHVzaChpIC0gOCk7IC8vIENvbnZlcnQgdG8gYXBwcm94aW1hdGUgRXRoaW9waWFuIHllYXJcbiAgICB9XG4gICAgcmV0dXJuIHllYXJzO1xuICB9XG5cbiAgQE91dHB1dCgpIGV0aGlvcGlhbkRhdGVDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPEV0aGlvcGlhbkRhdGU+KCk7XG4gIEBPdXRwdXQoKSBncmVnb3JpYW5EYXRlQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxHcmVnb3JpYW5EYXRlPigpO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY2FsZW5kYXJTZXJ2aWNlOiBFdGhpb3BpYW5DYWxlbmRhclNlcnZpY2UpIHt9XG5cbiAgdG9nZ2xlRXRoaW9waWFuUGlja2VyKCkge1xuICAgIHRoaXMuc2hvd0V0aGlvcGlhblBpY2tlciA9ICF0aGlzLnNob3dFdGhpb3BpYW5QaWNrZXI7XG4gIH1cblxuICBnZXRFdGhpb3BpYW5EYXlzKCk6IG51bWJlcltdIHtcbiAgICBjb25zdCBtYXhEYXlzID0gdGhpcy5ldGhpb3BpYW5EYXRlLm1vbnRoID09PSAxMyA/IFxuICAgICAgKHRoaXMuY2FsZW5kYXJTZXJ2aWNlWydpc0V0aGlvcGlhbkxlYXBZZWFyJ10odGhpcy5ldGhpb3BpYW5EYXRlLnllYXIpID8gNiA6IDUpIDogXG4gICAgICAzMDtcbiAgICByZXR1cm4gQXJyYXkuZnJvbSh7bGVuZ3RoOiBtYXhEYXlzfSwgKF8sIGkpID0+IGkgKyAxKTtcbiAgfVxuXG4gIGFwcGx5RXRoaW9waWFuRGF0ZSgpIHtcbiAgICB0aGlzLmNvbnZlcnRUb0dyZWdvcmlhbigpO1xuICAgIHRoaXMudG9nZ2xlRXRoaW9waWFuUGlja2VyKCk7XG4gIH1cblxuICBmb3JtYXRFdGhpb3BpYW5EYXRlRm9yRGlzcGxheShkYXRlOiBFdGhpb3BpYW5EYXRlKTogc3RyaW5nIHtcbiAgICBjb25zdCBtb250aE5hbWUgPSB0aGlzLmV0aGlvcGlhbk1vbnRocy5maW5kKG0gPT4gbS52YWx1ZSA9PT0gZGF0ZS5tb250aCk/LmxhYmVsIHx8ICcnO1xuICAgIHJldHVybiBgJHttb250aE5hbWV9ICR7ZGF0ZS5kYXl9LCAke2RhdGUueWVhcn1gO1xuICB9XG5cbiAgY29udmVydFRvR3JlZ29yaWFuKCkge1xuICAgIHRyeSB7XG4gICAgICB0aGlzLmdyZWdvcmlhbkRhdGUgPSB0aGlzLmNhbGVuZGFyU2VydmljZS50b0dyZWdvcmlhbih0aGlzLmV0aGlvcGlhbkRhdGUpO1xuICAgICAgdGhpcy5ncmVnb3JpYW5EYXRlQ2hhbmdlLmVtaXQodGhpcy5ncmVnb3JpYW5EYXRlKTtcbiAgICAgIHRoaXMubGFzdENvbnZlcnNpb24gPSBgRXRoaW9waWFuICR7dGhpcy5mb3JtYXREYXRlKHRoaXMuZXRoaW9waWFuRGF0ZSl9IOKGkiBHcmVnb3JpYW4gJHt0aGlzLmZvcm1hdERhdGUodGhpcy5ncmVnb3JpYW5EYXRlKX1gO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLmxhc3RDb252ZXJzaW9uID0gJ0ludmFsaWQgRXRoaW9waWFuIGRhdGUnO1xuICAgIH1cbiAgfVxuXG4gIGNvbnZlcnRUb0V0aGlvcGlhbigpIHtcbiAgICB0cnkge1xuICAgICAgdGhpcy5ldGhpb3BpYW5EYXRlID0gdGhpcy5jYWxlbmRhclNlcnZpY2UudG9FdGhpb3BpYW4odGhpcy5ncmVnb3JpYW5EYXRlKTtcbiAgICAgIHRoaXMuZXRoaW9waWFuRGF0ZUNoYW5nZS5lbWl0KHRoaXMuZXRoaW9waWFuRGF0ZSk7XG4gICAgICB0aGlzLmxhc3RDb252ZXJzaW9uID0gYEdyZWdvcmlhbiAke3RoaXMuZm9ybWF0RGF0ZSh0aGlzLmdyZWdvcmlhbkRhdGUpfSDihpIgRXRoaW9waWFuICR7dGhpcy5mb3JtYXREYXRlKHRoaXMuZXRoaW9waWFuRGF0ZSl9YDtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5sYXN0Q29udmVyc2lvbiA9ICdJbnZhbGlkIEdyZWdvcmlhbiBkYXRlJztcbiAgICB9XG4gIH1cblxuICBvbkdyZWdvcmlhbkRhdGVTZWxlY3RlZChldmVudDogYW55KSB7XG4gICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKGV2ZW50LnRhcmdldC52YWx1ZSk7XG4gICAgdGhpcy5ncmVnb3JpYW5EYXRlID0ge1xuICAgICAgeWVhcjogZGF0ZS5nZXRGdWxsWWVhcigpLFxuICAgICAgbW9udGg6IGRhdGUuZ2V0TW9udGgoKSArIDEsXG4gICAgICBkYXk6IGRhdGUuZ2V0RGF0ZSgpXG4gICAgfTtcbiAgICB0aGlzLmNvbnZlcnRUb0V0aGlvcGlhbigpO1xuICB9XG5cbiAgZm9ybWF0RGF0ZShkYXRlOiBFdGhpb3BpYW5EYXRlIHwgR3JlZ29yaWFuRGF0ZSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGAke2RhdGUueWVhcn0tJHtTdHJpbmcoZGF0ZS5tb250aCkucGFkU3RhcnQoMiwgJzAnKX0tJHtTdHJpbmcoZGF0ZS5kYXkpLnBhZFN0YXJ0KDIsICcwJyl9YDtcbiAgfVxuXG4gIGZvcm1hdERhdGVGb3JJbnB1dChkYXRlOiBHcmVnb3JpYW5EYXRlKTogc3RyaW5nIHtcbiAgICByZXR1cm4gYCR7ZGF0ZS55ZWFyfS0ke1N0cmluZyhkYXRlLm1vbnRoKS5wYWRTdGFydCgyLCAnMCcpfS0ke1N0cmluZyhkYXRlLmRheSkucGFkU3RhcnQoMiwgJzAnKX1gO1xuICB9XG5cbiAgZm9ybWF0R3JlZ29yaWFuRGF0ZShkYXRlOiBHcmVnb3JpYW5EYXRlKTogc3RyaW5nIHtcbiAgICByZXR1cm4gbmV3IERhdGUoZGF0ZS55ZWFyLCBkYXRlLm1vbnRoIC0gMSwgZGF0ZS5kYXkpXG4gICAgICAudG9Mb2NhbGVEYXRlU3RyaW5nKCdlbi1VUycsIHtcbiAgICAgICAgeWVhcjogJ251bWVyaWMnLFxuICAgICAgICBtb250aDogJ2xvbmcnLFxuICAgICAgICBkYXk6ICdudW1lcmljJ1xuICAgICAgfSk7XG4gIH1cblxuICB3ZWVrRGF5cyA9IFsnU3VuJywgJ01vbicsICdUdWUnLCAnV2VkJywgJ1RodScsICdGcmknLCAnU2F0J107XG5cbiAgcHJldmlvdXNNb250aCgpIHtcbiAgICBpZiAodGhpcy5ldGhpb3BpYW5EYXRlLm1vbnRoID4gMSkge1xuICAgICAgdGhpcy5ldGhpb3BpYW5EYXRlLm1vbnRoLS07XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZXRoaW9waWFuRGF0ZS5tb250aCA9IDEzO1xuICAgICAgdGhpcy5ldGhpb3BpYW5EYXRlLnllYXItLTtcbiAgICB9XG4gICAgdGhpcy51cGRhdGVFdGhpb3BpYW5EYXRlKCk7XG4gIH1cblxuICBuZXh0TW9udGgoKSB7XG4gICAgaWYgKHRoaXMuZXRoaW9waWFuRGF0ZS5tb250aCA8IDEzKSB7XG4gICAgICB0aGlzLmV0aGlvcGlhbkRhdGUubW9udGgrKztcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5ldGhpb3BpYW5EYXRlLm1vbnRoID0gMTtcbiAgICAgIHRoaXMuZXRoaW9waWFuRGF0ZS55ZWFyKys7XG4gICAgfVxuICAgIHRoaXMudXBkYXRlRXRoaW9waWFuRGF0ZSgpO1xuICB9XG5cbiAgZ2V0RGF5c0FycmF5KCk6IG51bWJlcltdIHtcbiAgICBjb25zdCBkYXlzSW5Nb250aCA9IHRoaXMuZXRoaW9waWFuRGF0ZS5tb250aCA9PT0gMTMgPyBcbiAgICAgICh0aGlzLmNhbGVuZGFyU2VydmljZVsnaXNFdGhpb3BpYW5MZWFwWWVhciddKHRoaXMuZXRoaW9waWFuRGF0ZS55ZWFyKSA/IDYgOiA1KSA6IFxuICAgICAgMzA7XG4gICAgXG4gICAgLy8gQ3JlYXRlIGFycmF5IHdpdGggcGFkZGluZyBmb3IgYWxpZ25tZW50XG4gICAgY29uc3QgZGF5czogbnVtYmVyW10gPSBbXTtcbiAgICBjb25zdCBmaXJzdERheU9mZnNldCA9IHRoaXMuZ2V0Rmlyc3REYXlPZmZzZXQoKTtcbiAgICBcbiAgICAvLyBBZGQgcGFkZGluZ1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZmlyc3REYXlPZmZzZXQ7IGkrKykge1xuICAgICAgZGF5cy5wdXNoKDApO1xuICAgIH1cbiAgICBcbiAgICAvLyBBZGQgZGF5c1xuICAgIGZvciAobGV0IGkgPSAxOyBpIDw9IGRheXNJbk1vbnRoOyBpKyspIHtcbiAgICAgIGRheXMucHVzaChpKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGRheXM7XG4gIH1cblxuICBnZXRGaXJzdERheU9mZnNldCgpOiBudW1iZXIge1xuICAgIC8vIFRoaXMgaXMgYSBzaW1wbGlmaWVkIHZlcnNpb24gLSB5b3UgbWlnaHQgd2FudCB0byBpbXBsZW1lbnQgcHJvcGVyIEV0aGlvcGlhbiBjYWxlbmRhciBkYXktb2Ytd2VlayBjYWxjdWxhdGlvblxuICAgIHJldHVybiAodGhpcy5ldGhpb3BpYW5EYXRlLm1vbnRoICogMikgJSA3O1xuICB9XG5cbiAgZ2V0RGF5Q2xhc3NlcyhkYXk6IG51bWJlcik6IHN0cmluZyB7XG4gICAgY29uc3QgYmFzZUNsYXNzZXMgPSAnaC04IHctOCByb3VuZGVkLWZ1bGwgZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXIgdGV4dC1zbSc7XG4gICAgY29uc3QgaXNTZWxlY3RlZCA9IGRheSA9PT0gdGhpcy5ldGhpb3BpYW5EYXRlLmRheTtcbiAgICBcbiAgICBpZiAoaXNTZWxlY3RlZCkge1xuICAgICAgcmV0dXJuIGAke2Jhc2VDbGFzc2VzfSBiZy1ibHVlLTYwMCB0ZXh0LXdoaXRlYDtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGAke2Jhc2VDbGFzc2VzfSBob3ZlcjpiZy1ncmF5LTEwMCB0ZXh0LWdyYXktNzAwYDtcbiAgfVxuXG4gIHNlbGVjdERheShkYXk6IG51bWJlcikge1xuICAgIHRoaXMuZXRoaW9waWFuRGF0ZS5kYXkgPSBkYXk7XG4gICAgdGhpcy51cGRhdGVFdGhpb3BpYW5EYXRlKCk7XG4gICAgdGhpcy50b2dnbGVFdGhpb3BpYW5QaWNrZXIoKTtcbiAgfVxuXG4gIHNlbGVjdFRvZGF5KCkge1xuICAgIGNvbnN0IHRvZGF5ID0gdGhpcy5jYWxlbmRhclNlcnZpY2UudG9FdGhpb3BpYW4oe1xuICAgICAgeWVhcjogbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpLFxuICAgICAgbW9udGg6IG5ldyBEYXRlKCkuZ2V0TW9udGgoKSArIDEsXG4gICAgICBkYXk6IG5ldyBEYXRlKCkuZ2V0RGF0ZSgpXG4gICAgfSk7XG4gICAgdGhpcy5ldGhpb3BpYW5EYXRlID0gdG9kYXk7XG4gICAgdGhpcy51cGRhdGVFdGhpb3BpYW5EYXRlKCk7XG4gICAgdGhpcy50b2dnbGVFdGhpb3BpYW5QaWNrZXIoKTtcbiAgfVxuXG4gIHVwZGF0ZUV0aGlvcGlhbkRhdGUoKSB7XG4gICAgdGhpcy5ldGhpb3BpYW5EYXRlQ2hhbmdlLmVtaXQodGhpcy5ldGhpb3BpYW5EYXRlKTtcbiAgICB0aGlzLmNvbnZlcnRUb0dyZWdvcmlhbigpO1xuICB9XG5cbiAgZm9ybWF0RXRoaW9waWFuRGF0ZUZvcklucHV0KGRhdGU6IEV0aGlvcGlhbkRhdGUpOiBzdHJpbmcge1xuICAgIGNvbnN0IG1vbnRoTmFtZSA9IHRoaXMuZXRoaW9waWFuTW9udGhzLmZpbmQobSA9PiBtLnZhbHVlID09PSBkYXRlLm1vbnRoKT8ubGFiZWwgfHwgJyc7XG4gICAgcmV0dXJuIGAke21vbnRoTmFtZX0gJHtkYXRlLmRheX0sICR7ZGF0ZS55ZWFyfWA7XG4gIH1cbn0gIl19