UNPKG

@ajsf/core

Version:

Angular JSON Schema Form builder core

656 lines 103 kB
import { Injectable } from '@angular/core'; import { Subject } from 'rxjs'; import cloneDeep from 'lodash/cloneDeep'; import Ajv from 'ajv'; import jsonDraft6 from 'ajv/lib/refs/json-schema-draft-06.json'; import { buildFormGroup, buildFormGroupTemplate, formatFormData, getControl, fixTitle, forEach, hasOwn, toTitleCase, buildLayout, getLayoutNode, buildSchemaFromData, buildSchemaFromLayout, removeRecursiveReferences, hasValue, isArray, isDefined, isEmpty, isObject, JsonPointer } from './shared'; import { deValidationMessages, enValidationMessages, esValidationMessages, frValidationMessages, itValidationMessages, ptValidationMessages, zhValidationMessages } from './locale'; import * as i0 from "@angular/core"; export class JsonSchemaFormService { constructor() { this.JsonFormCompatibility = false; this.ReactJsonSchemaFormCompatibility = false; this.AngularSchemaFormCompatibility = false; this.tpldata = {}; this.ajvOptions = { allErrors: true, jsonPointers: true, unknownFormats: 'ignore' }; this.ajv = new Ajv(this.ajvOptions); // AJV: Another JSON Schema Validator this.validateFormData = null; // Compiled AJV function to validate active form's schema this.formValues = {}; // Internal form data (may not have correct types) this.data = {}; // Output form data (formValues, formatted with correct data types) this.schema = {}; // Internal JSON Schema this.layout = []; // Internal form layout this.formGroupTemplate = {}; // Template used to create formGroup this.formGroup = null; // Angular formGroup, which powers the reactive form this.framework = null; // Active framework component this.validData = null; // Valid form data (or null) (=== isValid ? data : null) this.isValid = null; // Is current form data valid? this.ajvErrors = null; // Ajv errors for current data this.validationErrors = null; // Any validation errors for current data this.dataErrors = new Map(); // this.formValueSubscription = null; // Subscription to formGroup.valueChanges observable (for un- and re-subscribing) this.dataChanges = new Subject(); // Form data observable this.isValidChanges = new Subject(); // isValid observable this.validationErrorChanges = new Subject(); // validationErrors observable this.arrayMap = new Map(); // Maps arrays in data object and number of tuple values this.dataMap = new Map(); // Maps paths in form data to schema and formGroup paths this.dataRecursiveRefMap = new Map(); // Maps recursive reference points in form data this.schemaRecursiveRefMap = new Map(); // Maps recursive reference points in schema this.schemaRefLibrary = {}; // Library of schemas for resolving schema $refs this.layoutRefLibrary = { '': null }; // Library of layout nodes for adding to form this.templateRefLibrary = {}; // Library of formGroup templates for adding to form this.hasRootReference = false; // Does the form include a recursive reference to itself? this.language = 'en-US'; // Does the form include a recursive reference to itself? // Default global form options this.defaultFormOptions = { autocomplete: true, addSubmit: 'auto', // for addSubmit: true = always, false = never, // 'auto' = only if layout is undefined (form is built from schema alone) debug: false, disableInvalidSubmit: true, formDisabled: false, formReadonly: false, fieldsRequired: false, framework: 'no-framework', loadExternalAssets: false, pristine: { errors: true, success: true }, supressPropertyTitles: false, setSchemaDefaults: 'auto', // true = always set (unless overridden by layout default or formValues) // false = never set // 'auto' = set in addable components, and everywhere if formValues not set setLayoutDefaults: 'auto', // true = always set (unless overridden by formValues) // false = never set // 'auto' = set in addable components, and everywhere if formValues not set validateOnRender: 'auto', // true = validate all fields immediately // false = only validate fields after they are touched by user // 'auto' = validate fields with values immediately, empty fields after they are touched widgets: {}, defautWidgetOptions: { // Default options for form control widgets listItems: 1, addable: true, orderable: true, removable: true, enableErrorState: true, // disableErrorState: false, // Don't apply 'has-error' class when field fails validation? enableSuccessState: true, // disableSuccessState: false, // Don't apply 'has-success' class when field validates? feedback: false, feedbackOnRender: false, notitle: false, disabled: false, readonly: false, returnEmptyFields: true, validationMessages: {} // set by setLanguage() } }; this.setLanguage(this.language); this.ajv.addMetaSchema(jsonDraft6); } setLanguage(language = 'en-US') { this.language = language; const languageValidationMessages = { de: deValidationMessages, en: enValidationMessages, es: esValidationMessages, fr: frValidationMessages, it: itValidationMessages, pt: ptValidationMessages, zh: zhValidationMessages, }; const languageCode = language.slice(0, 2); const validationMessages = languageValidationMessages[languageCode]; this.defaultFormOptions.defautWidgetOptions.validationMessages = cloneDeep(validationMessages); } getData() { return this.data; } getSchema() { return this.schema; } getLayout() { return this.layout; } resetAllValues() { this.JsonFormCompatibility = false; this.ReactJsonSchemaFormCompatibility = false; this.AngularSchemaFormCompatibility = false; this.tpldata = {}; this.validateFormData = null; this.formValues = {}; this.schema = {}; this.layout = []; this.formGroupTemplate = {}; this.formGroup = null; this.framework = null; this.data = {}; this.validData = null; this.isValid = null; this.validationErrors = null; this.arrayMap = new Map(); this.dataMap = new Map(); this.dataRecursiveRefMap = new Map(); this.schemaRecursiveRefMap = new Map(); this.layoutRefLibrary = {}; this.schemaRefLibrary = {}; this.templateRefLibrary = {}; this.formOptions = cloneDeep(this.defaultFormOptions); } /** * 'buildRemoteError' function * * Example errors: * { * last_name: [ { * message: 'Last name must by start with capital letter.', * code: 'capital_letter' * } ], * email: [ { * message: 'Email must be from example.com domain.', * code: 'special_domain' * }, { * message: 'Email must contain an @ symbol.', * code: 'at_symbol' * } ] * } * //{ErrorMessages} errors */ buildRemoteError(errors) { forEach(errors, (value, key) => { if (key in this.formGroup.controls) { for (const error of value) { const err = {}; err[error['code']] = error['message']; this.formGroup.get(key).setErrors(err, { emitEvent: true }); } } }); } validateData(newValue, updateSubscriptions = true) { // Format raw form data to correct data types this.data = formatFormData(newValue, this.dataMap, this.dataRecursiveRefMap, this.arrayMap, this.formOptions.returnEmptyFields); this.isValid = this.validateFormData(this.data); this.validData = this.isValid ? this.data : null; const compileErrors = errors => { const compiledErrors = {}; (errors || []).forEach(error => { if (!compiledErrors[error.dataPath]) { compiledErrors[error.dataPath] = []; } compiledErrors[error.dataPath].push(error.message); }); return compiledErrors; }; this.ajvErrors = this.validateFormData.errors; this.validationErrors = compileErrors(this.validateFormData.errors); if (updateSubscriptions) { this.dataChanges.next(this.data); this.isValidChanges.next(this.isValid); this.validationErrorChanges.next(this.ajvErrors); } } buildFormGroupTemplate(formValues = null, setValues = true) { this.formGroupTemplate = buildFormGroupTemplate(this, formValues, setValues); } buildFormGroup() { this.formGroup = buildFormGroup(this.formGroupTemplate); if (this.formGroup) { this.compileAjvSchema(); this.validateData(this.formGroup.value); // Set up observables to emit data and validation info when form data changes if (this.formValueSubscription) { this.formValueSubscription.unsubscribe(); } this.formValueSubscription = this.formGroup.valueChanges.subscribe(formValue => this.validateData(formValue)); } } buildLayout(widgetLibrary) { this.layout = buildLayout(this, widgetLibrary); } setOptions(newOptions) { if (isObject(newOptions)) { const addOptions = cloneDeep(newOptions); // Backward compatibility for 'defaultOptions' (renamed 'defautWidgetOptions') if (isObject(addOptions.defaultOptions)) { Object.assign(this.formOptions.defautWidgetOptions, addOptions.defaultOptions); delete addOptions.defaultOptions; } if (isObject(addOptions.defautWidgetOptions)) { Object.assign(this.formOptions.defautWidgetOptions, addOptions.defautWidgetOptions); delete addOptions.defautWidgetOptions; } Object.assign(this.formOptions, addOptions); // convert disableErrorState / disableSuccessState to enable... const globalDefaults = this.formOptions.defautWidgetOptions; ['ErrorState', 'SuccessState'] .filter(suffix => hasOwn(globalDefaults, 'disable' + suffix)) .forEach(suffix => { globalDefaults['enable' + suffix] = !globalDefaults['disable' + suffix]; delete globalDefaults['disable' + suffix]; }); } } compileAjvSchema() { if (!this.validateFormData) { // if 'ui:order' exists in properties, move it to root before compiling with ajv if (Array.isArray(this.schema.properties['ui:order'])) { this.schema['ui:order'] = this.schema.properties['ui:order']; delete this.schema.properties['ui:order']; } this.ajv.removeSchema(this.schema); this.validateFormData = this.ajv.compile(this.schema); } } buildSchemaFromData(data, requireAllFields = false) { if (data) { return buildSchemaFromData(data, requireAllFields); } this.schema = buildSchemaFromData(this.formValues, requireAllFields); } buildSchemaFromLayout(layout) { if (layout) { return buildSchemaFromLayout(layout); } this.schema = buildSchemaFromLayout(this.layout); } setTpldata(newTpldata = {}) { this.tpldata = newTpldata; } parseText(text = '', value = {}, values = {}, key = null) { if (!text || !/{{.+?}}/.test(text)) { return text; } return text.replace(/{{(.+?)}}/g, (...a) => this.parseExpression(a[1], value, values, key, this.tpldata)); } parseExpression(expression = '', value = {}, values = {}, key = null, tpldata = null) { if (typeof expression !== 'string') { return ''; } const index = typeof key === 'number' ? key + 1 + '' : key || ''; expression = expression.trim(); if ((expression[0] === "'" || expression[0] === '"') && expression[0] === expression[expression.length - 1] && expression.slice(1, expression.length - 1).indexOf(expression[0]) === -1) { return expression.slice(1, expression.length - 1); } if (expression === 'idx' || expression === '$index') { return index; } if (expression === 'value' && !hasOwn(values, 'value')) { return value; } if (['"', "'", ' ', '||', '&&', '+'].every(delim => expression.indexOf(delim) === -1)) { const pointer = JsonPointer.parseObjectPath(expression); return pointer[0] === 'value' && JsonPointer.has(value, pointer.slice(1)) ? JsonPointer.get(value, pointer.slice(1)) : pointer[0] === 'values' && JsonPointer.has(values, pointer.slice(1)) ? JsonPointer.get(values, pointer.slice(1)) : pointer[0] === 'tpldata' && JsonPointer.has(tpldata, pointer.slice(1)) ? JsonPointer.get(tpldata, pointer.slice(1)) : JsonPointer.has(values, pointer) ? JsonPointer.get(values, pointer) : ''; } if (expression.indexOf('[idx]') > -1) { expression = expression.replace(/\[idx\]/g, index); } if (expression.indexOf('[$index]') > -1) { expression = expression.replace(/\[$index\]/g, index); } // TODO: Improve expression evaluation by parsing quoted strings first // let expressionArray = expression.match(/([^"']+|"[^"]+"|'[^']+')/g); if (expression.indexOf('||') > -1) { return expression .split('||') .reduce((all, term) => all || this.parseExpression(term, value, values, key, tpldata), ''); } if (expression.indexOf('&&') > -1) { return expression .split('&&') .reduce((all, term) => all && this.parseExpression(term, value, values, key, tpldata), ' ') .trim(); } if (expression.indexOf('+') > -1) { return expression .split('+') .map(term => this.parseExpression(term, value, values, key, tpldata)) .join(''); } return ''; } setArrayItemTitle(parentCtx = {}, childNode = null, index = null) { const parentNode = parentCtx.layoutNode; const parentValues = this.getFormControlValue(parentCtx); const isArrayItem = (parentNode.type || '').slice(-5) === 'array' && isArray(parentValues); const text = JsonPointer.getFirst(isArrayItem && childNode.type !== '$ref' ? [ [childNode, '/options/legend'], [childNode, '/options/title'], [parentNode, '/options/title'], [parentNode, '/options/legend'] ] : [ [childNode, '/options/title'], [childNode, '/options/legend'], [parentNode, '/options/title'], [parentNode, '/options/legend'] ]); if (!text) { return text; } const childValue = isArray(parentValues) && index < parentValues.length ? parentValues[index] : parentValues; return this.parseText(text, childValue, parentValues, index); } setItemTitle(ctx) { return !ctx.options.title && /^(\d+|-)$/.test(ctx.layoutNode.name) ? null : this.parseText(ctx.options.title || toTitleCase(ctx.layoutNode.name), this.getFormControlValue(this), (this.getFormControlGroup(this) || {}).value, ctx.dataIndex[ctx.dataIndex.length - 1]); } evaluateCondition(layoutNode, dataIndex) { const arrayIndex = dataIndex && dataIndex[dataIndex.length - 1]; let result = true; if (hasValue((layoutNode.options || {}).condition)) { if (typeof layoutNode.options.condition === 'string') { let pointer = layoutNode.options.condition; if (hasValue(arrayIndex)) { pointer = pointer.replace('[arrayIndex]', `[${arrayIndex}]`); } pointer = JsonPointer.parseObjectPath(pointer); result = !!JsonPointer.get(this.data, pointer); if (!result && pointer[0] === 'model') { result = !!JsonPointer.get({ model: this.data }, pointer); } } else if (typeof layoutNode.options.condition === 'function') { result = layoutNode.options.condition(this.data); } else if (typeof layoutNode.options.condition.functionBody === 'string') { try { const dynFn = new Function('model', 'arrayIndices', layoutNode.options.condition.functionBody); result = dynFn(this.data, dataIndex); } catch (e) { result = true; console.error('condition functionBody errored out on evaluation: ' + layoutNode.options.condition.functionBody); } } } return result; } initializeControl(ctx, bind = true) { if (!isObject(ctx)) { return false; } if (isEmpty(ctx.options)) { ctx.options = !isEmpty((ctx.layoutNode || {}).options) ? ctx.layoutNode.options : cloneDeep(this.formOptions); } ctx.formControl = this.getFormControl(ctx); ctx.boundControl = bind && !!ctx.formControl; if (ctx.formControl) { ctx.controlName = this.getFormControlName(ctx); ctx.controlValue = ctx.formControl.value; ctx.controlDisabled = ctx.formControl.disabled; ctx.options.errorMessage = ctx.formControl.status === 'VALID' ? null : this.formatErrors(ctx.formControl.errors, ctx.options.validationMessages); ctx.options.showErrors = this.formOptions.validateOnRender === true || (this.formOptions.validateOnRender === 'auto' && hasValue(ctx.controlValue)); ctx.formControl.statusChanges.subscribe(status => (ctx.options.errorMessage = status === 'VALID' ? null : this.formatErrors(ctx.formControl.errors, ctx.options.validationMessages))); ctx.formControl.valueChanges.subscribe(value => { if (!!value) { ctx.controlValue = value; } }); } else { ctx.controlName = ctx.layoutNode.name; ctx.controlValue = ctx.layoutNode.value || null; const dataPointer = this.getDataPointer(ctx); if (bind && dataPointer) { console.error(`warning: control "${dataPointer}" is not bound to the Angular FormGroup.`); } } return ctx.boundControl; } formatErrors(errors, validationMessages = {}) { if (isEmpty(errors)) { return null; } if (!isObject(validationMessages)) { validationMessages = {}; } const addSpaces = string => string[0].toUpperCase() + (string.slice(1) || '') .replace(/([a-z])([A-Z])/g, '$1 $2') .replace(/_/g, ' '); const formatError = error => typeof error === 'object' ? Object.keys(error) .map(key => error[key] === true ? addSpaces(key) : error[key] === false ? 'Not ' + addSpaces(key) : addSpaces(key) + ': ' + formatError(error[key])) .join(', ') : addSpaces(error.toString()); const messages = []; return (Object.keys(errors) // Hide 'required' error, unless it is the only one .filter(errorKey => errorKey !== 'required' || Object.keys(errors).length === 1) .map(errorKey => // If validationMessages is a string, return it typeof validationMessages === 'string' ? validationMessages : // If custom error message is a function, return function result typeof validationMessages[errorKey] === 'function' ? validationMessages[errorKey](errors[errorKey]) : // If custom error message is a string, replace placeholders and return typeof validationMessages[errorKey] === 'string' ? // Does error message have any {{property}} placeholders? !/{{.+?}}/.test(validationMessages[errorKey]) ? validationMessages[errorKey] : // Replace {{property}} placeholders with values Object.keys(errors[errorKey]).reduce((errorMessage, errorProperty) => errorMessage.replace(new RegExp('{{' + errorProperty + '}}', 'g'), errors[errorKey][errorProperty]), validationMessages[errorKey]) : // If no custom error message, return formatted error data instead addSpaces(errorKey) + ' Error: ' + formatError(errors[errorKey])) .join('<br>')); } updateValue(ctx, value) { // Set value of current control ctx.controlValue = value; if (ctx.boundControl) { ctx.formControl.setValue(value); ctx.formControl.markAsDirty(); } ctx.layoutNode.value = value; // Set values of any related controls in copyValueTo array if (isArray(ctx.options.copyValueTo)) { for (const item of ctx.options.copyValueTo) { const targetControl = getControl(this.formGroup, item); if (isObject(targetControl) && typeof targetControl.setValue === 'function') { targetControl.setValue(value); targetControl.markAsDirty(); } } } } updateArrayCheckboxList(ctx, checkboxList) { const formArray = this.getFormControl(ctx); // Remove all existing items while (formArray.value.length) { formArray.removeAt(0); } // Re-add an item for each checked box const refPointer = removeRecursiveReferences(ctx.layoutNode.dataPointer + '/-', this.dataRecursiveRefMap, this.arrayMap); for (const checkboxItem of checkboxList) { if (checkboxItem.checked) { const newFormControl = buildFormGroup(this.templateRefLibrary[refPointer]); newFormControl.setValue(checkboxItem.value); formArray.push(newFormControl); } } formArray.markAsDirty(); } getFormControl(ctx) { if (!ctx.layoutNode || !isDefined(ctx.layoutNode.dataPointer) || ctx.layoutNode.type === '$ref') { return null; } return getControl(this.formGroup, this.getDataPointer(ctx)); } getFormControlValue(ctx) { if (!ctx.layoutNode || !isDefined(ctx.layoutNode.dataPointer) || ctx.layoutNode.type === '$ref') { return null; } const control = getControl(this.formGroup, this.getDataPointer(ctx)); return control ? control.value : null; } getFormControlGroup(ctx) { if (!ctx.layoutNode || !isDefined(ctx.layoutNode.dataPointer)) { return null; } return getControl(this.formGroup, this.getDataPointer(ctx), true); } getFormControlName(ctx) { if (!ctx.layoutNode || !isDefined(ctx.layoutNode.dataPointer) || !hasValue(ctx.dataIndex)) { return null; } return JsonPointer.toKey(this.getDataPointer(ctx)); } getLayoutArray(ctx) { return JsonPointer.get(this.layout, this.getLayoutPointer(ctx), 0, -1); } getParentNode(ctx) { return JsonPointer.get(this.layout, this.getLayoutPointer(ctx), 0, -2); } getDataPointer(ctx) { if (!ctx.layoutNode || !isDefined(ctx.layoutNode.dataPointer) || !hasValue(ctx.dataIndex)) { return null; } return JsonPointer.toIndexedPointer(ctx.layoutNode.dataPointer, ctx.dataIndex, this.arrayMap); } getLayoutPointer(ctx) { if (!hasValue(ctx.layoutIndex)) { return null; } return '/' + ctx.layoutIndex.join('/items/'); } isControlBound(ctx) { if (!ctx.layoutNode || !isDefined(ctx.layoutNode.dataPointer) || !hasValue(ctx.dataIndex)) { return false; } const controlGroup = this.getFormControlGroup(ctx); const name = this.getFormControlName(ctx); return controlGroup ? hasOwn(controlGroup.controls, name) : false; } addItem(ctx, name) { if (!ctx.layoutNode || !isDefined(ctx.layoutNode.$ref) || !hasValue(ctx.dataIndex) || !hasValue(ctx.layoutIndex)) { return false; } // Create a new Angular form control from a template in templateRefLibrary const newFormGroup = buildFormGroup(this.templateRefLibrary[ctx.layoutNode.$ref]); // Add the new form control to the parent formArray or formGroup if (ctx.layoutNode.arrayItem) { // Add new array item to formArray this.getFormControlGroup(ctx).push(newFormGroup); } else { // Add new $ref item to formGroup this.getFormControlGroup(ctx).addControl(name || this.getFormControlName(ctx), newFormGroup); } // Copy a new layoutNode from layoutRefLibrary const newLayoutNode = getLayoutNode(ctx.layoutNode, this); newLayoutNode.arrayItem = ctx.layoutNode.arrayItem; if (ctx.layoutNode.arrayItemType) { newLayoutNode.arrayItemType = ctx.layoutNode.arrayItemType; } else { delete newLayoutNode.arrayItemType; } if (name) { newLayoutNode.name = name; newLayoutNode.dataPointer += '/' + JsonPointer.escape(name); newLayoutNode.options.title = fixTitle(name); } // Add the new layoutNode to the form layout JsonPointer.insert(this.layout, this.getLayoutPointer(ctx), newLayoutNode); return true; } moveArrayItem(ctx, oldIndex, newIndex) { if (!ctx.layoutNode || !isDefined(ctx.layoutNode.dataPointer) || !hasValue(ctx.dataIndex) || !hasValue(ctx.layoutIndex) || !isDefined(oldIndex) || !isDefined(newIndex) || oldIndex === newIndex) { return false; } // Move item in the formArray const formArray = this.getFormControlGroup(ctx); const arrayItem = formArray.at(oldIndex); formArray.removeAt(oldIndex); formArray.insert(newIndex, arrayItem); formArray.updateValueAndValidity(); // Move layout item const layoutArray = this.getLayoutArray(ctx); layoutArray.splice(newIndex, 0, layoutArray.splice(oldIndex, 1)[0]); return true; } removeItem(ctx) { if (!ctx.layoutNode || !isDefined(ctx.layoutNode.dataPointer) || !hasValue(ctx.dataIndex) || !hasValue(ctx.layoutIndex)) { return false; } // Remove the Angular form control from the parent formArray or formGroup if (ctx.layoutNode.arrayItem) { // Remove array item from formArray this.getFormControlGroup(ctx).removeAt(ctx.dataIndex[ctx.dataIndex.length - 1]); } else { // Remove $ref item from formGroup this.getFormControlGroup(ctx).removeControl(this.getFormControlName(ctx)); } // Remove layoutNode from layout JsonPointer.remove(this.layout, this.getLayoutPointer(ctx)); return true; } } JsonSchemaFormService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: JsonSchemaFormService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); JsonSchemaFormService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: JsonSchemaFormService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: JsonSchemaFormService, decorators: [{ type: Injectable }], ctorParameters: function () { return []; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianNvbi1zY2hlbWEtZm9ybS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYWpzZi1jb3JlL3NyYy9saWIvanNvbi1zY2hlbWEtZm9ybS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFM0MsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQixPQUFPLFNBQVMsTUFBTSxrQkFBa0IsQ0FBQztBQUN6QyxPQUFPLEdBQUcsTUFBTSxLQUFLLENBQUM7QUFDdEIsT0FBTyxVQUFVLE1BQU0sd0NBQXdDLENBQUM7QUFDaEUsT0FBTyxFQUNMLGNBQWMsRUFDZCxzQkFBc0IsRUFDdEIsY0FBYyxFQUNkLFVBQVUsRUFDVixRQUFRLEVBQ1IsT0FBTyxFQUNQLE1BQU0sRUFDTixXQUFXLEVBQ1gsV0FBVyxFQUNYLGFBQWEsRUFDYixtQkFBbUIsRUFDbkIscUJBQXFCLEVBQ3JCLHlCQUF5QixFQUN6QixRQUFRLEVBQ1IsT0FBTyxFQUNQLFNBQVMsRUFDVCxPQUFPLEVBQ1AsUUFBUSxFQUNSLFdBQVcsRUFDWixNQUFNLFVBQVUsQ0FBQztBQUNsQixPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLG9CQUFvQixFQUNwQixvQkFBb0IsRUFDcEIsb0JBQW9CLEVBQ3BCLG9CQUFvQixFQUNwQixvQkFBb0IsRUFDcEIsb0JBQW9CLEVBQ3JCLE1BQU0sVUFBVSxDQUFDOztBQWtCbEIsTUFBTSxPQUFPLHFCQUFxQjtJQTRGaEM7UUEzRkEsMEJBQXFCLEdBQUcsS0FBSyxDQUFDO1FBQzlCLHFDQUFnQyxHQUFHLEtBQUssQ0FBQztRQUN6QyxtQ0FBOEIsR0FBRyxLQUFLLENBQUM7UUFDdkMsWUFBTyxHQUFRLEVBQUUsQ0FBQztRQUVsQixlQUFVLEdBQVE7WUFDaEIsU0FBUyxFQUFFLElBQUk7WUFDZixZQUFZLEVBQUUs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