kwikid-forms
Version:
KwikID's JSON Configuration based Forms Renderer and Builder
780 lines • 113 kB
JavaScript
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 {
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;
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"
},
saveButton: {
hidden: false,
label: "Save"
}
},
isUnsavedDataAlertEnabled: false
};
if (checkObjectKeyExists(formConfig, "properties")) {
formConfig.properties = getObjectDeepCopy(mergeObjects(formViewProperties, formConfig.properties));
}
else {
formConfig.properties = formViewProperties;
}
const language = getLanguage();
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, getLanguage());
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLWNvbnZlcnRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2t3aWtpZC1mb3Jtcy9zcmMvbGliL3JlbmRlcmVyL2NvbmZpZy1jb252ZXJ0ZXIvY29uZmlnLWNvbnZlcnRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUNMLG9CQUFvQixFQUNwQixxQkFBcUIsRUFDckIsaUJBQWlCLEVBQ2pCLFlBQVksRUFDWixlQUFlLEVBQ2YsUUFBUSxFQUNSLFNBQVMsRUFDVCxZQUFZLEVBQ1osa0JBQWtCLEVBQ2xCLG9CQUFvQixFQUNyQixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFDTCxVQUFVLEVBRVgsTUFBTSxzREFBc0QsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNoRSxPQUFPLEVBQ0wsYUFBYSxFQUNiLFdBQVcsRUFDWCxVQUFVLEVBQ1YsVUFBVSxFQUNWLHFCQUFxQixFQUNyQixtQkFBbUIsRUFDbkIsaUJBQWlCLEVBQ2pCLGdCQUFnQixFQUNoQix1QkFBdUIsRUFDdkIsY0FBYyxFQUNmLE1BQU0sMkJBQTJCLENBQUM7QUFFbkMsTUFBTSxPQUFPLFNBQVM7SUFFcEIsNkJBQTZCLENBQUMsVUFBZSxFQUFFLElBQVM7UUFDdEQsSUFBSSxvQkFBb0IsQ0FBQyxJQUFJLEVBQUUsaUJBQWlCLENBQUMsRUFBRTtZQUNqRCxVQUFVLEdBQUcsb0JBQW9CLENBQy9CLFVBQVUsRUFDVixpQkFBaUIsRUFDakIsSUFBSSxDQUFDLGVBQWUsQ0FDckIsQ0FBQztTQUNIO1FBRUQsT0FBTyxVQUFVLENBQUM7SUFDcEIsQ0FBQztJQUdELDhCQUE4QixDQUFDLFVBQWUsRUFBRSxVQUFlO1FBQzdELElBQUksZUFBZSxDQUFDLFVBQVUsQ0FBQyxFQUFFO1lBQy9CLElBQUksb0JBQW9CLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FB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