UNPKG

kwikid-forms

Version:

KwikID's JSON Configuration based Forms Renderer and Builder

793 lines 115 kB
import { __decorate } from "tslib"; import { checkObjectKeyExists, checkObjectPathExists, getObjectDeepCopy, isEmptyValue, isNotEmptyValue, isObject, logMethod, mergeObjects, setMissingKeyValue, setValueToObjectPath } from "kwikid-toolkit"; import { EFieldType } from "../form-view/definitions/form-view.fields.definition"; import { FIELD_PROPERTIES } from "./config-converter.constants"; import { getFormFields, getLanguage, getMaxDate, getMinDate, setFieldAsFormElement, setFieldKeyDisabled, setFieldKeyHidden, setFieldKeyValue, setMissingFieldKeyValue, updateLanguage } from "./config-converter.helper"; export class Converter { constructor(context = {}) { this.context = context; } resolveLanguage() { var _a; return getLanguage((_a = this.context.reduxData) !== null && _a !== void 0 ? _a : {}, this.context.userConfig); } updateFormConfigMiscellaneous(formConfig, args) { if (checkObjectKeyExists(args, "formsListLength")) { formConfig = setValueToObjectPath(formConfig, "formsListLength", args.formsListLength); } return formConfig; } updateFormConfigFromUserConfig(formConfig, userConfig) { if (isNotEmptyValue(userConfig)) { if (checkObjectKeyExists(userConfig, "theme")) { if (checkObjectKeyExists(userConfig.theme, "clientLogo")) { setValueToObjectPath(formConfig, "properties.header.logo.src", userConfig.theme.clientLogo); } } } return formConfig; } updateFormConfigProperties(formConfig) { var _a, _b; formConfig = formConfig && typeof formConfig === "object" ? getObjectDeepCopy(formConfig) : formConfig; const formViewProperties = { header: { logo: { src: "", alt: "Logo", hidden: false, styles: "" }, backButton: { mode: "TABBED", bypassConfirmation: false, hidden: true }, title: { hidden: false, label: (_b = (_a = formConfig === null || formConfig === void 0 ? void 0 : formConfig.title) !== null && _a !== void 0 ? _a : formConfig === null || formConfig === void 0 ? void 0 : formConfig.props.title) !== null && _b !== void 0 ? _b : "Form", styles: "" }, steps: { hidden: false, styles: "" } }, main: { styles: "" }, footer: { viewFormsButton: { bypassConfirmation: false, hidden: false, label: "View Forms", styles: "width: 100%" }, saveButton: { hidden: false, label: "Save", styles: "width: 100%" } }, isUnsavedDataAlertEnabled: false }; if (checkObjectKeyExists(formConfig, "properties")) { formConfig.properties = getObjectDeepCopy(mergeObjects(formViewProperties, formConfig.properties)); } else { formConfig.properties = formViewProperties; } const language = this.resolveLanguage(); if (checkObjectPathExists(formConfig, "properties.header.title.label")) { formConfig.properties.header.title.label = updateLanguage(formConfig.properties.header.title.label, language); } if (checkObjectPathExists(formConfig, "properties.footer.viewFormsButton.label")) { formConfig.properties.footer.viewFormsButton.label = updateLanguage(formConfig.properties.footer.viewFormsButton.label, language); } if (checkObjectPathExists(formConfig, "properties.footer.saveButton.label")) { formConfig.properties.footer.saveButton.label = updateLanguage(formConfig.properties.footer.saveButton.label, language); } return formConfig; } convertFormConfig(formConfig) { const formatOnFieldType = (field) => { const updateFormFieldProperties = (field) => { if (checkObjectKeyExists(FIELD_PROPERTIES, field.type)) { field.properties = mergeObjects(getObjectDeepCopy(FIELD_PROPERTIES[field.type]), field.properties); } return field; }; const formatFieldTypeHtml = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, false); return field; }; const formatFieldTypeTitle = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, false); return field; }; const formatFieldTypeButton = (field) => { field = setMissingFieldKeyValue(field, "hidden", false); field = setFieldAsFormElement(field, false); field = updateFormFieldProperties(field); return field; }; const formatFieldTypeText = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypePassword = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypeEmail = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypeStarRating = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypeCurrency = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypeTextarea = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); return field; }; const formatFieldTypeCheckbox = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); return field; }; const formatFieldTypeNumber = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); if (checkObjectKeyExists(field, "key")) { if (field.key === "aadhaar_number") { field = setFieldKeyValue(field, "type", "aadhaar_number"); } if (field.key === "contact_number") { field = setFieldKeyValue(field, "type", "phone"); } if (field.type === "phone" || field.type === "number") { field = updateFormFieldProperties(field); } } return field; }; const formatFieldTypeImage = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypeDate = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field.properties = getObjectDeepCopy(mergeObjects(getObjectDeepCopy(FIELD_PROPERTIES[field.type]), { max: getMaxDate(field), min: getMinDate(field) }, field.properties)); return field; }; const formatFieldTypeTime = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypePhone = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypeRadio = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); field.options = field.options.map((x) => { if (typeof x === "string" || typeof x === "number") { return { label: x, disabled: false, description: "" }; } if (checkObjectKeyExists(x, "label") && checkObjectKeyExists(x, "disabled") && checkObjectKeyExists(x, "description")) { return x; } if (!checkObjectKeyExists(x, "disabled")) { x = Object.assign(Object.assign({}, x), { disabled: false }); } if (!checkObjectKeyExists(x, "description")) { x = Object.assign(Object.assign({}, x), { description: false }); } return x; }); return field; }; const formatFieldTypeSlider = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypeSelect = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypeApi = (field) => { field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); if (!checkObjectKeyExists(field, "showLoader")) { field = setFieldKeyValue(field, "showLoader", false); } if (!checkObjectKeyExists(field, "api")) { const fieldApiDefaults = { url: "", request: {}, response: {}, status: { value: "default", labels: { default: "Call API", loading: "Call API", retry: "Retry API", success: "API Success", failed: "API Failed" } } }; field.api = getObjectDeepCopy(mergeObjects(fieldApiDefaults, fieldApiDefaults)); } if (!checkObjectKeyExists(field.api, "request") && !checkObjectKeyExists(field.api, "entrypoint")) { const apiEntrypoint = { triggers: ["ON_API_CALL"], rules: [], actions: [ { id: "1", key: "API_CALL", condition: "true", props: { fieldKey: field.key, apiKey: field.api.endpoints[0].apiKey } } ] }; field.entrypoint = getObjectDeepCopy(mergeObjects(apiEntrypoint, field.api)); } return field; }; const formatFieldTypeLiveLocation = (field) => { field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); if (!checkObjectKeyExists(field, "showLoader")) { field = setFieldKeyValue(field, "showLoader", false); } if (!checkObjectKeyExists(field, "api")) { const fieldApiDefaults = { url: "", request: {}, response: {}, status: { value: "default", labels: { default: "Get Live Location", loading: "Getting Live Location", retry: "Get Live Location", success: "Live Location", failed: "Live Location" } } }; field.api = getObjectDeepCopy(mergeObjects(fieldApiDefaults, fieldApiDefaults)); } return field; }; const formatFieldTypeDataHolder = (field) => { field = setFieldKeyHidden(field); field = setFieldKeyDisabled(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypeOtp = (field) => { var _a, _b; field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field.properties = getObjectDeepCopy(mergeObjects(getObjectDeepCopy(FIELD_PROPERTIES[field.type]), { mask: new Array((_b = (_a = field === null || field === void 0 ? void 0 : field.properties) === null || _a === void 0 ? void 0 : _a.otpLength) !== null && _b !== void 0 ? _b : 4) .fill("#") .join(" ") }, field.properties)); return field; }; const formatFieldTypeAadhaarNumber = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypeFile = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; const formatFieldTypeCapture = (field) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); field.properties = getObjectDeepCopy(Object.assign(Object.assign({}, field.properties), { features: Object.assign(Object.assign({}, field.properties.features), { watermark: { isEnabled: (_d = (_c = (_b = (_a = field === null || field === void 0 ? void 0 : field.properties) === null || _a === void 0 ? void 0 : _a.cameraConfig) === null || _b === void 0 ? void 0 : _b.others) === null || _c === void 0 ? void 0 : _c.isWatermark) !== null && _d !== void 0 ? _d : field.properties.features.watermark.isWatermark, isWatermarkFromServer: (_h = (_g = (_f = (_e = field === null || field === void 0 ? void 0 : field.properties) === null || _e === void 0 ? void 0 : _e.cameraConfig) === null || _f === void 0 ? void 0 : _f.others) === null || _g === void 0 ? void 0 : _g.isWatermarkFromServer) !== null && _h !== void 0 ? _h : field.properties.features.watermark.isWatermarkFromServer, sources: (_k = (_j = field === null || field === void 0 ? void 0 : field.properties) === null || _j === void 0 ? void 0 : _j.watermarkDataSources) !== null && _k !== void 0 ? _k : field.properties.features.watermark.sources } }) })); delete field.properties.watermarkDataSources; /** * Current commented because in kwikid-camera new config structure is not handled * Will uncomment once handled here and modify the structure a little bit here as well. */ // delete field.properties.cameraConfig.others.isWatermark; // delete field.properties.cameraConfig.others.isWatermarkForImageUpload; return field; }; const formatFieldTypeRecord = (field) => { field = setFieldKeyHidden(field); field = setFieldAsFormElement(field, true); field = updateFormFieldProperties(field); return field; }; switch (field.type) { case EFieldType.HTML: field = formatFieldTypeHtml(field); break; case EFieldType.TITLE: field = formatFieldTypeTitle(field); break; case EFieldType.BUTTON: field = formatFieldTypeButton(field); break; case EFieldType.TEXT: field = formatFieldTypeText(field); break; case EFieldType.PASSWORD: field = formatFieldTypePassword(field); break; case EFieldType.EMAIL: field = formatFieldTypeEmail(field); break; case EFieldType.TEXTAREA: field = formatFieldTypeTextarea(field); break; case EFieldType.CHECKBOX: field = formatFieldTypeCheckbox(field); break; case EFieldType.NUMBER: field = formatFieldTypeNumber(field); break; case EFieldType.PREVIEW_IMAGE: field = setFieldKeyValue(field, "type", "image"); field = formatFieldTypeImage(field); break; case EFieldType.IMAGE: field = formatFieldTypeImage(field); break; case EFieldType.DATE: field = formatFieldTypeDate(field); break; case EFieldType.TIME: field = formatFieldTypeTime(field); break; case EFieldType.PHONE: field = formatFieldTypePhone(field); break; case EFieldType.RADIO: field = formatFieldTypeRadio(field); break; case EFieldType.SLIDER: field = formatFieldTypeSlider(field); break; case "search-text": field = setFieldKeyValue(field, "type", "select"); field = formatFieldTypeSelect(field); break; case EFieldType.DROPDOWN_WITH_SEARCH: field = setFieldKeyValue(field, "type", "select"); field = formatFieldTypeSelect(field); break; case EFieldType.SELECT: field = formatFieldTypeSelect(field); break; case EFieldType.API_CALL: field = setFieldKeyValue(field, "type", "api"); field = formatFieldTypeApi(field); break; case EFieldType.LIVE_LOCATION: field = formatFieldTypeLiveLocation(field); break; case EFieldType.DATA_HOLDER: field = formatFieldTypeDataHolder(field); break; case EFieldType.API: field = formatFieldTypeApi(field); break; case EFieldType.OTP: field = formatFieldTypeOtp(field); break; case EFieldType.AADHAAR_NUMBER: field = formatFieldTypeAadhaarNumber(field); break; case EFieldType.FILE: field = formatFieldTypeFile(field); break; case EFieldType.CAPTURE: field = formatFieldTypeCapture(field); break; case EFieldType.RECORD: field = formatFieldTypeRecord(field); break; case EFieldType.STAR_RATING: field = formatFieldTypeStarRating(field); break; case EFieldType.CURRENCY: field = formatFieldTypeCurrency(field); break; default: break; } return field; }; const updateFieldValidators = (field) => { var _a, _b, _c, _d, _e; if (field.isFormElement) { const validators = checkObjectKeyExists(field, "validators") ? field.validators : {}; field = setMissingFieldKeyValue(field, "validators", {}); field = setFieldKeyValue(field, "validators", Object.assign(Object.assign({}, field.validators), { min: checkObjectKeyExists(validators, "min") ? isNotEmptyValue(validators.min) ? Number(validators.min) : null : checkObjectKeyExists(field, "min") ? Number(field.min) : null, max: checkObjectKeyExists(validators, "max") ? isNotEmptyValue(validators.max) ? Number(validators.max) : null : checkObjectKeyExists(field, "max") ? Number(field.max) : null, required: checkObjectKeyExists(validators, "required") ? Boolean(validators.required) : checkObjectKeyExists(field, "required") ? Boolean(field.required) : false, minLength: checkObjectKeyExists(validators, "minLength") ? isNotEmptyValue(validators.minLength) ? Number(validators.minLength) : null : checkObjectKeyExists(field, "minLength") ? Number(field.minLength) : null, maxLength: checkObjectKeyExists(validators, "maxLength") ? isNotEmptyValue(validators.maxLength) ? Number(validators.maxLength) : null : checkObjectKeyExists(field, "length") ? Number(field.length) : checkObjectKeyExists(field, "maxLength") ? Number(field.maxLength) : null, pattern: checkObjectKeyExists(validators, "pattern") ? isNotEmptyValue(validators.pattern) ? validators.pattern : undefined : checkObjectKeyExists(field, "pattern") ? { key: "CUSTOM", pattern: String(field.pattern) } : checkObjectKeyExists(field, "regex") ? { key: "CUSTOM", pattern: String(field.regex) } : undefined })); delete field.min; delete field.max; delete field.required; delete field.minLength; delete field.length; delete field.maxLength; delete field.pattern; delete field.regex; switch (field.type) { case EFieldType.TEXT: delete field.validators.min; delete field.validators.max; break; case EFieldType.DATA_HOLDER: delete field.validators.min; delete field.validators.max; break; case EFieldType.CHECKBOX: delete field.validators.min; delete field.validators.max; break; case EFieldType.PREVIEW_IMAGE: delete field.validators.min; delete field.validators.max; delete field.validators.minLength; delete field.validators.maxLength; break; case EFieldType.FILE: delete field.validators.min; delete field.validators.max; delete field.validators.minLength; delete field.validators.maxLength; delete field.validators.pattern; break; case EFieldType.CAPTURE: delete field.validators.min; delete field.validators.max; delete field.validators.minLength; delete field.validators.maxLength; delete field.validators.pattern; break; case EFieldType.RECORD: delete field.validators.min; delete field.validators.max; delete field.validators.minLength; delete field.validators.maxLength; delete field.validators.pattern; break; default: break; } if (isEmptyValue((_a = field.validators) === null || _a === void 0 ? void 0 : _a.min)) { delete field.validators.min; } if (isEmptyValue((_b = field.validators) === null || _b === void 0 ? void 0 : _b.max)) { delete field.validators.min; } if (isEmptyValue((_c = field.validators) === null || _c === void 0 ? void 0 : _c.minLength)) { delete field.validators.minLength; } if (isEmptyValue((_d = field.validators) === null || _d === void 0 ? void 0 : _d.maxLength)) { delete field.validators.maxLength; } if (isEmptyValue((_e = field.validators) === null || _e === void 0 ? void 0 : _e.pattern)) { delete field.validators.pattern; } field.focus = false; field.invalid = false; } return field; }; const updateFieldDefaultValue = (field) => { if (field.isFormElement) { if (checkObjectKeyExists(field, "defaultValue")) { return field; } if (checkObjectPathExists(field, "default.value.sources")) { return field; } if (checkObjectPathExists(field, "default.value.rules") && checkObjectPathExists(field, "default.value.actions")) { return field; } if (checkObjectPathExists(field, "default.value.value") && isNotEmptyValue(field.default.value.value)) { return field; } if (!checkObjectPathExists(field, "default.value.sources")) { const defaultValue = { value: "", triggers: ["ON_INIT"], rules: [], actions: [ { id: "1", key: "SET_FIELD_DEFAULT_VALUE", condition: "true", props: { value: { source: { key: "OBJECT", props: { object: { key: "FORM_DATA", path: `$.${field.key}` } } } } } } ] }; field = setValueToObjectPath(field, "default.value", defaultValue); return field; } delete field.defaultVal; delete field.defaultValue; } return field; }; const updateFieldDisability = (field) => { field = setMissingKeyValue(field, "disabled", false); return field; }; const updateFieldMessages = (field) => { if (field.isFormElement) { field = setMissingFieldKeyValue(field, "messages", []); } return field; }; const updateFieldResetButton = (field) => { if (field.isFormElement) { if (checkObjectKeyExists(field, "action") && field.action === "reset" && checkObjectKeyExists(field, "fields")) { field = setFieldKeyValue(field, "reset", { fields: field.fields }); } } return field; }; const setFormFields = (formConfig, fields) => { if (checkObjectKeyExists(formConfig, "multiForm")) { formConfig.multiForm.fields = fields; } else { formConfig.fields = fields; } return formConfig; }; const setFormFieldGroups = (formConfig, groups) => { formConfig.fieldGroups = groups; return formConfig; }; const updateFieldGroupKey = (field) => { if (checkObjectKeyExists(field, "groupKey") && !Array.isArray(field.groupKey)) { field.groupKey = [field.groupKey]; } return field; }; const updateFormFieldGroups = (fieldGroups, field) => { if (checkObjectKeyExists(field, "groupKey")) { for (const groupKey of field.groupKey) { if (checkObjectKeyExists(fieldGroups, groupKey)) { fieldGroups[groupKey].push(field.key); } else { fieldGroups[groupKey] = [field.key]; } } } return fieldGroups; }; const updateFieldLanguage = (field, language) => { if (checkObjectKeyExists(field, "label")) { field.label = updateLanguage(field.label, language); } if (checkObjectPathExists(field, "properties.placeholder")) { field.properties.placeholder = updateLanguage(field.properties.placeholder, language); } if (checkObjectPathExists(field, "properties.label")) { field.properties.label = updateLanguage(field.properties.label, language); } const updateApiStatus = (fieldApiStatus) => { for (const status in fieldApiStatus) { if (isNotEmptyValue(status)) { fieldApiStatus[status] = updateLanguage(fieldApiStatus[status], language); } } return fieldApiStatus; }; switch (field.type) { case EFieldType.HTML: field.html = updateLanguage(field.html, language); break; case EFieldType.CAPTURE: field.properties.cameraConfig.header.title = updateLanguage(field.properties.cameraConfig.header.title, language); break; case EFieldType.RECORD: field.properties.cameraConfig.header.title = updateLanguage(field.properties.cameraConfig.header.title, language); break; case EFieldType.SELECT: field.options = field.options.map((option) => { if (isObject(option)) { if (checkObjectKeyExists(option, "title")) { option.title = updateLanguage(option.title, language); } else { option = updateLanguage(option, language); } } return option; }); break; case EFieldType.DROPDOWN_WITH_SEARCH: field.options = field.options.map((option) => { if (isObject(option)) { if (checkObjectKeyExists(option, "title")) { option.title = updateLanguage(option.title, language); } else { option = updateLanguage(option, language); } } return option; }); break; case EFieldType.RADIO: field.options = field.options.map((option) => { if (isObject(option)) { if (checkObjectKeyExists(option, "label")) { option.label = updateLanguage(option.label, language); } else { option = updateLanguage(option, language); } } return option; }); break; case EFieldType.API_CALL: field.api.status.labels = updateApiStatus(field.api.status.labels); break; case EFieldType.LIVE_LOCATION: field.api.status.labels = updateApiStatus(field.api.status.labels); break; default: break; } return field; }; const fields = getFormFields(formConfig); let fieldGroups = {}; for (let field of fields) { field = updateFieldLanguage(field, this.resolveLanguage()); field = formatOnFieldType(field); field = updateFieldDisability(field); field = updateFieldGroupKey(field); fieldGroups = updateFormFieldGroups(fieldGroups, field); field = updateFieldDefaultValue(field); field = updateFieldValidators(field); field = updateFieldResetButton(field); field = updateFieldMessages(field); } formConfig = setFormFieldGroups(formConfig, fieldGroups); formConfig = setFormFields(formConfig, fields); return formConfig; } } __decorate([ logMethod ], Converter.prototype, "updateFormConfigMiscellaneous", null); __decorate([ logMethod ], Converter.prototype, "updateFormConfigFromUserConfig", null); __decorate([ logMethod ], Converter.prototype, "updateFormConfigProperties", null); __decorate([ logMethod ], Converter.prototype, "convertFormConfig", null); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLWNvbnZlcnRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2t3aWtpZC1mb3Jtcy9zcmMvbGliL3JlbmRlcmVyL2NvbmZpZy1jb252ZXJ0ZXIvY29uZmlnLWNvbnZlcnRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUNMLG9CQUFvQixFQUNwQixxQkFBcUIsRUFDckIsaUJBQWlCLEVBQ2pCLFlBQVksRUFDWixlQUFlLEVBQ2YsUUFBUSxFQUNSLFNBQVMsRUFDVCxZQUFZLEVBQ1osa0JBQWtCLEVBQ2xCLG9CQUFvQixFQUNyQixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFDTCxVQUFVLEVBRVgsTUFBTSxzREFBc0QsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNoRSxPQUFPLEVBQ0wsYUFBYSxFQUNiLFdBQVcsRUFDWCxVQUFVLEVBQ1YsVUFBVSxFQUNWLHFCQUFxQixFQUNyQixtQkFBbUIsRUFDbkIsaUJBQWlCLEVBQ2pCLGdCQUFnQixFQUNoQix1QkFBdUIsRUFDdkIsY0FBYyxFQUNmLE1BQU0sMkJBQTJCLENBQUM7QUFPbkMsTUFBTSxPQUFPLFNBQVM7SUFDcEIsWUFBNkIsVUFBNEIsRUFBRTtRQUE5QixZQUFPLEdBQVAsT0FBTyxDQUF1QjtJQUFHLENBQUM7SUFFdkQsZUFBZTs7UUFDckIsT0FBTyxXQUFXLENBQUMsTUFBQSxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsbUNBQUksRUFBRSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDNUUsQ0FBQztJQUdELDZCQUE2QixDQUFDLFVBQWUsRUFBRSxJQUFTO1FBQ3RELElBQUksb0JBQW9CLENBQUMsSUFBSSxFQUFFLGlCQUFpQixDQUFDLEVBQUU7WUFDakQsVUFBVSxHQUFHLG9CQUFvQixDQUMvQixVQUFVLEVBQ1Ys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