UNPKG

@typegoose/typegoose

Version:

Define Mongoose models using TypeScript classes

675 lines 51.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.allVirtualoptions = void 0; exports.isPrimitive = isPrimitive; exports.isAnRefType = isAnRefType; exports.isObject = isObject; exports.isNumber = isNumber; exports.isString = isString; exports.getCachedSchema = getCachedSchema; exports.getClass = getClass; exports.isWithStringValidate = isWithStringValidate; exports.isWithStringTransform = isWithStringTransform; exports.isWithNumberValidate = isWithNumberValidate; exports.isWithEnumValidate = isWithEnumValidate; exports.isWithVirtualPOP = isWithVirtualPOP; exports.includesAllVirtualPOP = includesAllVirtualPOP; exports.assignMetadata = assignMetadata; exports.mergeMetadata = mergeMetadata; exports.mergeSchemaOptions = mergeSchemaOptions; exports.getRightTarget = getRightTarget; exports.getName = getName; exports.isNotDefined = isNotDefined; exports.mapArrayOptions = mapArrayOptions; exports.mapOptions = mapOptions; exports.isTypeMeantToBeArray = isTypeMeantToBeArray; exports.warnMixed = warnMixed; exports.isNullOrUndefined = isNullOrUndefined; exports.getMergedModelOptions = getMergedModelOptions; exports.createArrayFromDimensions = createArrayFromDimensions; exports.assertion = assertion; exports.assertionIsClass = assertionIsClass; exports.getType = getType; exports.isConstructor = isConstructor; exports.warnNotCorrectTypeOptions = warnNotCorrectTypeOptions; exports.warnNotMatchingExisting = warnNotMatchingExisting; exports.toStringNoFail = toStringNoFail; exports.mapModelOptionsToNaming = mapModelOptionsToNaming; exports.isGlobalCachingEnabled = isGlobalCachingEnabled; exports.isCachingEnabled = isCachingEnabled; const tslib_1 = require("tslib"); const lodash_1 = tslib_1.__importDefault(require("lodash")); const mongoose_1 = tslib_1.__importDefault(require("mongoose")); const logSettings_1 = require("../logSettings"); const constants_1 = require("./constants"); const data_1 = require("./data"); const errors_1 = require("./errors"); /** * Returns true, if the type is included in mongoose.Schema.Types * @param Type The Type to test * @returns true, if it includes it */ function isPrimitive(Type) { if (typeof Type?.name === 'string') { // try to match "Type.name" with all the Property Names of "mongoose.Schema.Types" // (like "String" with "mongoose.Schema.Types.String") return (Object.getOwnPropertyNames(mongoose_1.default.Schema.Types).includes(Type.name) || // try to match "Type.name" with all "mongoose.Schema.Types.*.name" // (like "SchemaString" with "mongoose.Schema.Types.String.name") Object.values(mongoose_1.default.Schema.Types).findIndex((v) => v.name === Type.name) >= 0); } return false; } /** * Returns true, if the type is included in mongoose.Schema.Types except the aliases * @param Type The Type to test * @returns true, if it includes it */ function isAnRefType(Type) { if (typeof Type?.name === 'string') { // Note: this is not done "once" because types can be added as custom types const tmp = Object.getOwnPropertyNames(mongoose_1.default.Schema.Types).filter((x) => { switch (x) { case 'Oid': case 'Bool': case 'Object': case 'Boolean': return false; default: return true; } }); // try to match "Type.name" with all the Property Names of "mongoose.Schema.Types" except the ones with aliases // (like "String" with "mongoose.Schema.Types.String") return (tmp.includes(Type.name) || // try to match "Type.name" with all "mongoose.Schema.Types.*.name" // (like "SchemaString" with "mongoose.Schema.Types.String.name") Object.values(mongoose_1.default.Schema.Types).findIndex((v) => v.name === Type.name) >= 0); } return false; } /** * Returns true, if it is an Object * Looks down the prototype chain, unless "once" is set to "true" * @param Type The Type to test * @param once Set to not loop down the prototype chain, default "false" * @returns true, if it is an Object */ function isObject(Type, once = false) { if (typeof Type?.name === 'string') { let prototype = Type.prototype; // schemaName is "Mixed", whereas name for ".Types.Mixed" is since mongoose 8.0 "SchemaMixed" // so use "schemaName" if it exists and use ".name" as a fallback let name = Type?.schemaName ?? Type.name; while (name) { if (name === 'Object' || name === 'Mixed') { return true; } if (once) { break; } prototype = Object.getPrototypeOf(prototype); name = prototype?.constructor.name; } } return false; } /** * Returns true, if it is an Number * @param Type The Type to test * @returns true, if it is an Number */ function isNumber(Type) { const name = Type?.name ?? ''; return name === 'Number' || name === mongoose_1.default.Schema.Types.Number.name; } /** * Returns true, if it is an String * @param Type The Type to test * @returns true, if it is an String */ function isString(Type) { const name = Type?.name ?? ''; return name === 'String' || name === mongoose_1.default.Schema.Types.String.name; } /** * Get or init the Cached Schema * @param target The Target to get / init the cached schema * @returns The Schema to use */ function getCachedSchema(target) { let schemaReflectTarget = Reflect.getMetadata(constants_1.DecoratorKeys.CachedSchema, target); if (isNullOrUndefined(schemaReflectTarget)) { Reflect.defineMetadata(constants_1.DecoratorKeys.CachedSchema, {}, target); schemaReflectTarget = Reflect.getMetadata(constants_1.DecoratorKeys.CachedSchema, target); } else if (isNullOrUndefined(Reflect.getOwnMetadata(constants_1.DecoratorKeys.CachedSchema, target))) { // set own metadata and clone object, because otherwise on inheritance it would just modify the base class's object, not its own object schemaReflectTarget = { ...schemaReflectTarget }; Reflect.defineMetadata(constants_1.DecoratorKeys.CachedSchema, schemaReflectTarget, target); } return schemaReflectTarget; } /** * Get the Class for a number of inputs * @param input The Input to fetch the class from */ function getClass(input) { assertion(isGlobalCachingEnabled(), () => new errors_1.CacheDisabledError('getClass')); if (typeof input === 'string') { return data_1.constructors.get(input); } if (typeof input?.typegooseName === 'string') { return data_1.constructors.get(input.typegooseName); } if (typeof input?.typegooseName === 'function') { return data_1.constructors.get(input.typegooseName()); } if (typeof input?.constructor?.modelName === 'string') { return data_1.constructors.get(input.constructor.modelName); } throw new errors_1.ResolveTypegooseNameError(input); } /** * Returns all options found in "options" that are String-validate related * @param options The raw Options that may contain the wanted options */ function isWithStringValidate(options) { return lodash_1.default.intersection(Object.keys(options), ['match', 'minlength', 'maxlength']); } /** * Returns all options found in "options" that are String-transform related * @param options The raw Options */ function isWithStringTransform(options) { return lodash_1.default.intersection(Object.keys(options), ['lowercase', 'uppercase', 'trim']); } /** * Returns all options found in "options" that are Number-Validate related * @param options The raw Options */ function isWithNumberValidate(options) { return lodash_1.default.intersection(Object.keys(options), ['min', 'max']); } /** * Returns all options found in "options" that are Enum Related * @param options The raw Options */ function isWithEnumValidate(options) { return lodash_1.default.intersection(Object.keys(options), ['enum']); } const virtualOptions = ['localField', 'foreignField']; /** * Check if the "options" contain any Virtual-Populate related options (excluding "ref" by it self) * @param options The raw Options */ function isWithVirtualPOP(options) { return Object.keys(options).some((v) => virtualOptions.includes(v)); } exports.allVirtualoptions = virtualOptions.slice(0); // copy "virtualOptions" array exports.allVirtualoptions.push('ref'); /** * Check if all Required options for Virtual-Populate are included in "options" * @param options The raw Options */ function includesAllVirtualPOP(options) { return exports.allVirtualoptions.every((v) => Object.keys(options).includes(v)); } /** * Merge "value" with existing Metadata and save it to the class * Difference with "mergeMetadata" is that this one DOES save it to the class * Overwrites any existing Metadata that is new in "value" * @param key Metadata key to read from and assign the new value to * @param value Options to merge with * @param cl The Class to read and assign the new metadata to * @internal */ function assignMetadata(key, value, cl) { if (isNullOrUndefined(value)) { return value; } const newValue = mergeMetadata(key, value, cl); Reflect.defineMetadata(key, newValue, cl); return newValue; } /** * Merge "value" with existing Metadata * Difference with "assignMetadata" is that this one DOES NOT save it to the class * Overwrites any existing Metadata that is new in "value" * @param key Metadata key to read existing metadata from * @param value Option to merge with * @param cl The Class to read the metadata from * @param getOwn Use "getOwnMetadata" isntead of "getMetadata" * @returns Returns the merged output, where "value" overwrites existing Metadata values * @internal */ function mergeMetadata(key, value, cl, getOwn = false) { assertion(typeof key === 'string' && key.length > 0, () => new errors_1.StringLengthExpectedError(1, key, getName(cl), 'key')); assertionIsClass(cl); let classMetadata = (getOwn ? Reflect.getOwnMetadata(key, cl) : Reflect.getMetadata(key, cl)) ?? {}; // dont inherit some options if the current class does not have its own metadata // this is somewhat hacky if (key === constants_1.DecoratorKeys.ModelOptions && !Reflect.hasOwnMetadata(key, cl) && 'options' in classMetadata) { // this has to be done, because otherwise it will be deleted on the original classMetadata = { ...classMetadata }; classMetadata.options = { ...classMetadata.options }; // dont inherit "disableLowerIndexes" because that would otherwise be inherited and so disable all indexes if inherited, not just from where it was set delete classMetadata?.options?.disableLowerIndexes; } return mergeObjects(classMetadata, value); } /** * Merge 2 different objects into a new object, with {@link customMerger} (deep merge). * @param src1 Properties overlapping with `src2` will be overwritten by `src2` * @param src2 Properties overlapping with `src1` will be overwritten */ function mergeObjects(src1, src2) { // Please don't remove the other values from the function, even when unused - it is made to be clear what is what return lodash_1.default.mergeWith({}, src1, src2, (_objValue, srcValue, ckey) => customMerger(ckey, srcValue)); } /** * Used for lodash customizers (cloneWith, cloneDeepWith, mergeWith) * @param key the key of the current object * @param val the value of the object that should get returned for "existingMongoose" & "existingConnection" */ function customMerger(key, val) { if (typeof key !== 'string') { return undefined; } if (/^(existingMongoose|existingConnection)$/.test(key)) { return val; } return undefined; } /** * Merge only schemaOptions from ModelOptions of the class * @param value The value to use * @param cl The Class to get the values from */ function mergeSchemaOptions(value, cl) { return mergeMetadata(constants_1.DecoratorKeys.ModelOptions, { schemaOptions: value }, cl).schemaOptions; } /** * Tries to return the right target * if target.constructor.name is "Function", return "target", otherwise "target.constructor" * @param target The target to determine */ function getRightTarget(target) { return target.constructor?.name === 'Function' ? target : target.constructor; } /** * Get the Class's final name * (combines all available options to generate a name) * @param cl The Class to get the name for * @param overwriteNaming Overwrite naming options used for generating the name */ function getName(cl, overwriteNaming) { // this case (cl being undefined / null) can happen when type casting (or type being "any") happened and wanting to throw a Error (and there using "getName" to help) // check if input variable is undefined, if it is throw a error (cannot be combined with the error below because of "getRightTarget") assertion(!isNullOrUndefined(cl), () => new errors_1.NoValidClassError(cl)); const ctor = getRightTarget(cl); assertion(isConstructor(ctor), () => new errors_1.NoValidClassError(ctor)); const options = Reflect.getMetadata(constants_1.DecoratorKeys.ModelOptions, ctor) ?? {}; const baseName = ctor.name; const customName = overwriteNaming?.customName ?? options.options?.customName; if (typeof customName === 'function') { const name = customName(options); assertion(typeof name === 'string' && name.length > 0, () => new errors_1.StringLengthExpectedError(1, name, baseName, 'options.customName(function)')); return name; } const automaticName = overwriteNaming?.automaticName ?? options.options?.automaticName; if (automaticName) { const suffix = customName ?? overwriteNaming?.schemaCollection ?? options.schemaOptions?.collection; return !isNullOrUndefined(suffix) ? `${baseName}_${suffix}` : baseName; } if (isNullOrUndefined(customName)) { return baseName; } assertion(typeof customName === 'string' && customName.length > 0, () => new errors_1.StringLengthExpectedError(1, customName, baseName, 'options.customName')); return customName; } /** * Check if "Type" is a class and if it is already in "schemas" * @param Type The Type to check */ function isNotDefined(Type) { return (typeof Type === 'function' && !isPrimitive(Type) && Type !== Object && isNullOrUndefined(Reflect.getMetadata(constants_1.DecoratorKeys.CachedSchema, Type))); } /** * Map Options to "inner" & "outer" * -> inner: means inner of "type: [{here})" * -> outer: means outer of "type: [{}], here" * * Specific to Arrays * @param rawOptions The raw options * @param Type The Type of the array * @param target The Target class * @param pkey Key of the Property * @param loggerType Type to use for logging * @param extraInner Extra Options to Mad explicitly to "inner" */ function mapArrayOptions(rawOptions, Type, target, pkey, loggerType, extraInner) { logSettings_1.logger.debug('mapArrayOptions called'); loggerType = loggerType ?? Type; if (!(Type instanceof mongoose_1.default.Schema)) { loggerType = Type; } const dim = rawOptions.dim; // needed, otherwise it will be included (and not removed) in the returnObject delete rawOptions.dim; const mapped = mapOptions(rawOptions, Type, target, pkey, loggerType); /** The Object that gets returned */ const returnObject = { ...mapped.outer, type: [ { type: Type, ...mapped.inner, ...extraInner, }, ], }; rawOptions.dim = dim; // re-add for "createArrayFromDimensions" returnObject.type = createArrayFromDimensions(rawOptions, returnObject.type, getName(target), pkey); if (loggerType) { logSettings_1.logger.debug('(Array) Final mapped Options for Type "%s"', getName(loggerType), returnObject); } return returnObject; } /** * Map Options to "inner" & "outer" * @param rawOptions The raw options * @param Type The Type of the array * @param target The Target class * @param pkey Key of the Property * @param loggerType Type to use for logging */ function mapOptions(rawOptions, Type, target, pkey, loggerType) { logSettings_1.logger.debug('mapOptions called'); loggerType = loggerType ?? Type; /** The Object that gets returned */ const ret = { inner: {}, outer: {}, }; // if Type is not a Schema, try to convert js type to mongoose type (Object => Mixed) if (!(Type instanceof mongoose_1.default.Schema)) { // set the loggerType to the js type loggerType = Type; const loggerTypeName = getName(loggerType); if (loggerTypeName in mongoose_1.default.Schema.Types) { logSettings_1.logger.info('Converting "%s" to mongoose Type', loggerTypeName); Type = mongoose_1.default.Schema.Types[loggerTypeName]; if (Type === mongoose_1.default.Schema.Types.Mixed) { warnMixed(target, pkey); } } } if (isNullOrUndefined(loggerType)) { logSettings_1.logger.info('mapOptions loggerType is undefined!'); } /** The OptionsConstructor to use */ let OptionsCTOR = Type?.prototype?.OptionsConstructor; if (Type instanceof mongoose_1.default.Schema) { OptionsCTOR = mongoose_1.default.Schema.Types.Subdocument.prototype.OptionsConstructor; } assertion(!isNullOrUndefined(OptionsCTOR), () => new errors_1.InvalidOptionsConstructorError(getName(target), pkey, loggerType)); const options = Object.assign({}, rawOptions); // for sanity if (OptionsCTOR.prototype instanceof mongoose_1.default.SchemaTypeOptions) { for (const [key, value] of Object.entries(options)) { if (Object.getOwnPropertyNames(OptionsCTOR.prototype).includes(key)) { ret.inner[key] = value; } else { ret.outer[key] = value; } } } else { if (loggerType) { logSettings_1.logger.info('The Type "%s" has a property "OptionsConstructor" but it does not extend "SchemaTypeOptions"', getName(loggerType)); } ret.outer = options; } if (typeof options?.innerOptions === 'object') { delete ret.outer.innerOptions; for (const [key, value] of Object.entries(options.innerOptions)) { ret.inner[key] = value; } } if (typeof options?.outerOptions === 'object') { delete ret.outer.outerOptions; for (const [key, value] of Object.entries(options.outerOptions)) { ret.outer[key] = value; } } if (loggerType) { logSettings_1.logger.debug('Final mapped Options for Type "%s"', getName(loggerType), ret); } return ret; } /** * Check if the current Type is meant to be a Array * @param rawOptions The raw options */ function isTypeMeantToBeArray(rawOptions) { // check if the "dim" option exists, if yes the type is meant to be a array in the end return !isNullOrUndefined(rawOptions) && !isNullOrUndefined(rawOptions.dim) && typeof rawOptions.dim === 'number' && rawOptions.dim > 0; } /** * Warn, Error or Allow if an mixed type is set * -> this function exists for de-duplication * @param target Target Class * @param key Property key */ function warnMixed(target, key) { const name = getName(target); const modelOptions = Reflect.getMetadata(constants_1.DecoratorKeys.ModelOptions, getRightTarget(target)) ?? {}; const rawOptions = Reflect.getMetadata(constants_1.DecoratorKeys.PropCache, target); const setSeverity = rawOptions?.get(key)?.options?.allowMixed ?? modelOptions.options?.allowMixed ?? constants_1.Severity.WARN; logSettings_1.logger.debug(`setSeverity for "${name}.${key}" is "${setSeverity}"`); switch (setSeverity) { default: case constants_1.Severity.WARN: logSettings_1.logger.warn('Setting "Mixed" for property "%s.%s"\nLook here for how to disable this message: https://typegoose.github.io/typegoose/docs/api/decorators/model-options/#allowmixed', name, key); break; case constants_1.Severity.ALLOW: break; case constants_1.Severity.ERROR: throw new TypeError(`Setting "Mixed" is not allowed! (${name}, ${key}) [E017]`); } return; // always return, if "allowMixed" is not "ERROR" } /** * Check if "val" is "null" to "undefined" * This Function exists because since node 4.0.0 the internal util.is* functions got deprecated * @param val Any value to test if null or undefined */ function isNullOrUndefined(val) { return val === null || val === undefined; } /** * Consistently get the "ModelOptions", merged with. * * Property (deep) priority list: * input "rawOptions" > decorator `ModelOptions` > globalOptions * @param rawOptions Options to merge(-overwrite) all previous options * @param cl The Class to get / set the ModelOptions on * @param getOwn use "getOwnMetadata" instead of "getMetadata" * @returns A ModelOptions object */ function getMergedModelOptions(rawOptions, cl, getOwn = false) { let opt = typeof rawOptions === 'object' ? rawOptions : {}; // dont skip merging if "getOwn" is "true" if (!(opt?.[constants_1.AlreadyMerged] && !getOwn)) { opt = mergeMetadata(constants_1.DecoratorKeys.ModelOptions, opt, cl, getOwn); logSettings_1.logger.info('Applying global Schema Options to "%s"', getName(cl)); opt = mergeObjects(lodash_1.default.omit(data_1.globalOptions, 'globalOptions'), opt); opt[constants_1.AlreadyMerged] = true; } return opt; } /** * Loop over "dimensions" and create an array from that * @param rawOptions baseProp's rawOptions * @param extra What is actually in the deepest array * @param name name of the target for better error logging * @param key key of target-key for better error logging */ function createArrayFromDimensions(rawOptions, extra, name, key) { // dimensions start at 1 (not 0) const dim = typeof rawOptions.dim === 'number' ? rawOptions.dim : 1; if (dim < 1) { throw new RangeError(`"dim" needs to be higher than 0 (${name}.${key}) [E018]`); } delete rawOptions.dim; // delete this property to not actually put it as an option logSettings_1.logger.info('createArrayFromDimensions called with %d dimensions', dim); let retArray = Array.isArray(extra) ? extra : [extra]; // index starts at 1 because "retArray" is already once wrapped in an array for (let index = 1; index < dim; index++) { retArray = [retArray]; } return retArray; } /** * Assert a condition, if "false" throw error * Note: it is not named "assert" to differentiate between node and jest types * * Note: "error" can be a function to not execute the constructor when not needed * @param cond The Condition to check * @param error A Custom Error to throw or a function that returns a Error */ function assertion(cond, error) { if (!cond) { throw typeof error === 'function' ? error() : (error ?? new errors_1.AssertionFallbackError()); } } /** * Assert if "val" is an function (constructor for classes) * @param val Value to test */ function assertionIsClass(val) { assertion(isConstructor(val), () => new errors_1.NoValidClassError(val)); } /** * Get Type, if input is an arrow-function, execute it and return the result * @param typeOrFunc Function or Type * @param returnLastFoundArray Return the last found array (used for something like PropOptions.discriminators) */ function getType(typeOrFunc, returnLastFoundArray = false) { const returnObject = { type: typeOrFunc, dim: 0, }; if (typeof returnObject.type === 'function' && !isConstructor(returnObject.type)) { returnObject.type = returnObject.type(); } function getDepth() { if (returnObject.dim > 100) { // this is arbitrary, but why would anyone have more than 10 nested arrays anyway? throw new Error('getDepth recursed too much (dim > 100)'); } if (Array.isArray(returnObject.type)) { returnObject.dim++; if (returnLastFoundArray && !Array.isArray(returnObject.type[0])) { return; } returnObject.type = returnObject.type[0]; getDepth(); } } getDepth(); logSettings_1.logger.debug('Final getType: dim: %s, type:', returnObject.dim, returnObject.type); return returnObject; } /** * Is the provided input an class with an constructor? * @param obj The Value to test */ function isConstructor(obj) { return (typeof obj === 'function' && !isNullOrUndefined(obj.prototype?.constructor?.name) // TODO: maybe change to the following implementation, because it would be more correct, but would involve some refactoring // if the js environment is spec-compliant, then the following should always work // /^class\s/.test(Function.prototype.toString.call(obj)) ); } // /** // * Execute util.deprecate or when "process" does not exist use "console.log" // * (if "process" does not exist, the codes are not cached, and are always logged again) // * This Function is here to try to make typegoose compatible with the browser (see https://github.com/typegoose/typegoose/issues/33) // */ // export function deprecate<T extends Function>(fn: T, message: string, code: string): T { // if (!isNullOrUndefined(process)) { // // eslint-disable-next-line @typescript-eslint/no-var-requires // return require('util').deprecate(fn, message, code); // } // console.log(`[${code}] DeprecationWarning: ${message}`); // return fn; // } /** * Logs an warning if "included > 0" that the options of not the current type are included * @param name Name of the Class * @param key Name of the Currently Processed key * @param type Name of the Expected Type * @param extra Extra string to be included * @param included Included Options to be listed */ function warnNotCorrectTypeOptions(name, key, type, extra, included) { // this "if" is in this function to de-duplicate code if (included.length > 0) { logSettings_1.logger.warn(`Type of "${name}.${key}" is not ${type}, but includes the following ${extra} options [W001]:\n` + ` [${included.join(', ')}]`); } } /** * Logs a warning for Discriminator setting a different "existing*" property than the base * @param fromName Name of the Base Model * @param clName Name of the Discriminator's class * @param property The property defined that does not match */ function warnNotMatchingExisting(fromName, clName, property) { logSettings_1.logger.warn(`Property "${property}" was defined on "${clName}", but is different from discriminator base "${fromName}", which is not supported! [W002]`); } /** * Try to convert input "value" to a String, without it failing * @param value The Value to convert to String * @returns A String, either "value.toString" or a placeholder */ function toStringNoFail(value) { try { return String(value); // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (_) { return '(Error: Converting value to String failed)'; } } /** * Map options from {@link IModelOptions} to {@link INamingOptions} * @param options The options to map * @returns Always a object, contains mapped options from {@link IModelOptions} */ function mapModelOptionsToNaming(options) { const mappedNaming = { ...options?.options }; // this copies more than necessary, but works because most of the options are from there if (!isNullOrUndefined(options?.schemaOptions?.collection)) { mappedNaming.schemaCollection = options?.schemaOptions?.collection; } return mappedNaming; } /** * Helper function to check if caching is enabled globally * @returns "true" if caching is enabled or "false" if disabled */ function isGlobalCachingEnabled() { return !(data_1.globalOptions.globalOptions?.disableGlobalCaching === true); } /** * Helper function to check if caching is enabled globally AND by options * @param opt The caching option (from IModelOptions) * @returns "true" if caching is enabled or "false" if disabled */ function isCachingEnabled(opt) { return isGlobalCachingEnabled() && !(opt === true); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW50ZXJuYWwvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBbUNBLGtDQWFDO0FBT0Qsa0NBMEJDO0FBU0QsNEJBb0JDO0FBT0QsNEJBSUM7QUFPRCw0QkFJQztBQU9ELDBDQWFDO0FBTUQsNEJBcUJDO0FBTUQsb0RBRUM7QUFNRCxzREFFQztBQU1ELG9EQUVDO0FBTUQsZ0RBRUM7QUFRRCw0Q0FFQztBQVNELHNEQUVDO0FBV0Qsd0NBU0M7QUFhRCxzQ0FrQkM7QUFpQ0QsZ0RBRUM7QUFPRCx3Q0FFQztBQVFELDBCQXdDQztBQU1ELG9DQU9DO0FBZUQsMENBeUNDO0FBVUQsZ0NBaUZDO0FBTUQsb0RBR0M7QUFRRCw4QkEwQkM7QUFPRCw4Q0FFQztBQVlELHNEQWtCQztBQVNELDhEQWtCQztBQVVELDhCQUlDO0FBTUQsNENBRUM7QUFPRCwwQkFnQ0M7QUFNRCxzQ0FPQztBQTBCRCw4REFPQztBQVFELDBEQUlDO0FBT0Qsd0NBT0M7QUFPRCwwREFRQztBQU1ELHdEQUVDO0FBT0QsNENBRUM7O0FBenlCRCw0REFBNEI7QUFDNUIsZ0VBQWdDO0FBQ2hDLGdEQUF3QztBQWlCeEMsMkNBQXFFO0FBQ3JFLGlDQUFxRDtBQUNyRCxxQ0FPa0I7QUFFbEI7Ozs7R0FJRztBQUNILFNBQWdCLFdBQVcsQ0FBQyxJQUFTO0lBQ25DLElBQUksT0FBTyxJQUFJLEVBQUUsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ25DLGtGQUFrRjtRQUNsRixzREFBc0Q7UUFDdEQsT0FBTyxDQUNMLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxrQkFBUSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztZQUNyRSxtRUFBbUU7WUFDbkUsaUVBQWlFO1lBQ2pFLE1BQU0sQ0FBQyxNQUFNLENBQUMsa0JBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQ2pGLENBQUM7SUFDSixDQUFDO0lBRUQsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLFdBQVcsQ0FBQyxJQUFTO0lBQ25DLElBQUksT0FBTyxJQUFJLEVBQUUsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ25DLDJFQUEyRTtRQUMzRSxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsbUJBQW1CLENBQUMsa0JBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7WUFDekUsUUFBUSxDQUFDLEVBQUUsQ0FBQztnQkFDVixLQUFLLEtBQUssQ0FBQztnQkFDWCxLQUFLLE1BQU0sQ0FBQztnQkFDWixLQUFLLFFBQVEsQ0FBQztnQkFDZCxLQUFLLFNBQVM7b0JBQ1osT0FBTyxLQUFLLENBQUM7Z0JBQ2Y7b0JBQ0UsT0FBTyxJQUFJLENBQUM7WUFDaEIsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsK0dBQStHO1FBQy9HLHNEQUFzRDtRQUN0RCxPQUFPLENBQ0wsR0FBRyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1lBQ3ZCLG1FQUFtRTtZQUNuRSxpRUFBaUU7WUFDakUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxrQkFBUSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FDakYsQ0FBQztJQUNKLENBQUM7SUFFRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxTQUFnQixRQUFRLENBQUMsSUFBUyxFQUFFLE9BQWdCLEtBQUs7SUFDdkQsSUFBSSxPQUFPLElBQUksRUFBRSxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDbkMsSUFBSSxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQztRQUMvQiw2RkFBNkY7UUFDN0YsaUVBQWlFO1FBQ2pFLElBQUksSUFBSSxHQUFHLElBQUksRUFBRSxVQUFVLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQztRQUN6QyxPQUFPLElBQUksRUFBRSxDQUFDO1lBQ1osSUFBSSxJQUFJLEtBQUssUUFBUSxJQUFJLElBQUksS0FBSyxPQUFPLEVBQUUsQ0FBQztnQkFDMUMsT0FBTyxJQUFJLENBQUM7WUFDZCxDQUFDO1lBQ0QsSUFBSSxJQUFJLEVBQUUsQ0FBQztnQkFDVCxNQUFNO1lBQ1IsQ0FBQztZQUVELFNBQVMsR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQzdDLElBQUksR0FBRyxTQUFTLEVBQUUsV0FBVyxDQUFDLElBQUksQ0FBQztRQUNyQyxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFnQixRQUFRLENBQUMsSUFBUztJQUNoQyxNQUFNLElBQUksR0FBRyxJQUFJLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQztJQUU5QixPQUFPLElBQUksS0FBSyxRQUFRLElBQUksSUFBSSxLQUFLLGtCQUFRLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDO0FBQ3pFLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBZ0IsUUFBUSxDQUFDLElBQVM7SUFDaEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxFQUFFLElBQUksSUFBSSxFQUFFLENBQUM7SUFFOUIsT0FBTyxJQUFJLEtBQUssUUFBUSxJQUFJLElBQUksS0FBSyxrQkFBUSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztBQUN6RSxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLGVBQWUsQ0FBQyxNQUFnQztJQUM5RCxJQUFJLG1CQUFtQixHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMseUJBQWEsQ0FBQyxZQUFZLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFFbEYsSUFBSSxpQkFBaUIsQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUM7UUFDM0MsT0FBTyxDQUFDLGNBQWMsQ0FBQyx5QkFBYSxDQUFDLFlBQVksRUFBRSxFQUFFLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDL0QsbUJBQW1CLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQyx5QkFBYSxDQUFDLFlBQVksRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNoRixDQUFDO1NBQU0sSUFBSSxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLHlCQUFhLENBQUMsWUFBWSxFQUFFLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN6Rix1SUFBdUk7UUFDdkksbUJBQW1CLEdBQUcsRUFBRSxHQUFHLG1CQUFtQixFQUFFLENBQUM7UUFDakQsT0FBTyxDQUFDLGNBQWMsQ0FBQyx5QkFBYSxDQUFDLFlBQVksRUFBRSxtQkFBbUIsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNsRixDQUFDO0lBRUQsT0FBTyxtQkFBbUIsQ0FBQztBQUM3QixDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsU0FBZ0IsUUFBUSxDQUN0QixLQUFrRztJQUVsRyxTQUFTLENBQUMsc0JBQXNCLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLDJCQUFrQixDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFFOUUsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUM5QixPQUFPLG1CQUFZLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFDRCxJQUFJLE9BQU8sS0FBSyxFQUFFLGFBQWEsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUM3QyxPQUFPLG1CQUFZLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUMvQyxDQUFDO0lBRUQsSUFBSSxPQUFPLEtBQUssRUFBRSxhQUFhLEtBQUssVUFBVSxFQUFFLENBQUM7UUFDL0MsT0FBTyxtQkFBWSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQsSUFBSSxPQUFPLEtBQUssRUFBRSxXQUFXLEVBQUUsU0FBUyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ3RELE9BQU8sbUJBQVksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN2RCxDQUFDO0lBRUQsTUFBTSxJQUFJLGtDQUF5QixDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQzdDLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFnQixvQkFBb0IsQ0FBQyxPQUE2QjtJQUNoRSxPQUFPLGdCQUFNLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsV0FBVyxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUM7QUFDeEYsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLHFCQUFxQixDQUFDLE9BQTZCO0lBQ2pFLE9BQU8sZ0JBQU0sQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLFdBQVcsRUFBRSxXQUFXLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztBQUN2RixDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsU0FBZ0Isb0JBQW9CLENBQUMsT0FBNkI7SUFDaEUsT0FBTyxnQkFBTSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDbkUsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLGtCQUFrQixDQUFDLE9BQW9EO0lBQ3JGLE9BQU8sZ0JBQU0sQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7QUFDN0QsQ0FBQztBQUVELE1BQU0sY0FBYyxHQUFHLENBQUMsWUFBWSxFQUFFLGNBQWMsQ0FBQyxDQUFDO0FBRXREOzs7R0FHRztBQUNILFNBQWdCLGdCQUFnQixDQUFDLE9BQWdDO0lBQy9ELE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUN0RSxDQUFDO0FBRVksUUFBQSxpQkFBaUIsR0FBRyxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsOEJBQThCO0FBQ3hGLHlCQUFpQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUU5Qjs7O0dBR0c7QUFDSCxTQUFnQixxQkFBcUIsQ0FBQyxPQUFnQztJQUNwRSxPQUFPLHlCQUFpQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUMxRSxDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxTQUFnQixjQUFjLENBQUMsR0FBa0IsRUFBRSxLQUFjLEVBQUUsRUFBNEI7SUFDN0YsSUFBSSxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQzdCLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVELE1BQU0sUUFBUSxHQUFHLGFBQWEsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQy9DLE9BQU8sQ0FBQyxjQUFjLENBQUMsR0FBRyxFQUFFLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUUxQyxPQUFPLFFBQVEsQ0FBQztBQUNsQixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7R0FVRztBQUNILFNBQWdCLGFBQWEsQ0FBVSxHQUFrQixFQUFFLEtBQWMsRUFBRSxFQUE0QixFQUFFLFNBQWtCLEtBQUs7SUFDOUgsU0FBUyxDQUFDLE9BQU8sR0FBRyxLQUFLLFFBQVEsSUFBSSxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLGtDQUF5QixDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDdEgsZ0JBQWdCLENBQUMsRUFBRSxDQUFDLENBQUM7SUFFckIsSUFBSSxhQUFhLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUVwRyxnRkFBZ0Y7SUFDaEYseUJBQXlCO0lBQ3pCLElBQUksR0FBRyxLQUFLLHlCQUFhLENBQUMsWUFBWSxJQUFJLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLElBQUksU0FBUyxJQUFJLGFBQWEsRUFBRSxDQUFDO1FBQ3pHLDRFQUE0RTtRQUM1RSxhQUFhLEdBQUcsRUFBRSxHQUFHLGFBQWEsRUFBRSxDQUFDO1FBQ3JDLGFBQWEsQ0FBQyxPQUFPLEdBQUcsRUFBRSxHQUFHLGFBQWEsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUVyRCx1SkFBdUo7UUFDdkosT0FBTyxhQUFhLEVBQUUsT0FBTyxFQUFFLG1CQUFtQixDQUFDO0lBQ3JELENBQUM7SUFFRCxPQUFPLFlBQVksQ0FBQyxhQUFhLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFDNUMsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFTLFlBQVksQ0FBVSxJQUFPLEVBQUUsSUFBTztJQUM3QyxpSEFBaUg7SUFDakgsT0FBTyxnQkFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLFNBQVMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUM7QUFDdkcsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxHQUFvQixFQUFFLEdBQVk7SUFDdEQsSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUM1QixPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBQ0QsSUFBSSx5Q0FBeUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN4RCxPQUFPLEdBQUcsQ0FBQztJQUNiLENBQUM7SUFFRCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLGtCQUFrQixDQUFxQyxLQUF5QyxFQUFFLEVBQUs7SUFDckgsT0FBTyxhQUFhLENBQWdCLHlCQUFhLENBQUMsWUFBWSxFQUFFLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLGFBQWEsQ0FBQztBQUM5RyxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLGNBQWMsQ0FBQyxNQUFXO0lBQ3hDLE9BQU8sTUFBTSxDQUFDLFdBQVcsRUFBRSxJQUFJLEtBQUssVUFBVSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUM7QUFDL0UsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBZ0IsT0FBTyxDQUFxQyxFQUFLLEVBQUUsZUFBZ0M7SUFDakcscUtBQXFLO0lBQ3JLLHFJQUFxSTtJQUNySSxTQUFTLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLDBCQUFpQixDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDbkUsTUFBTSxJQUFJLEdBQVEsY0FBYyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3JDLFNBQVMsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSwwQkFBaUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBRWxFLE1BQU0sT0FBTyxHQUFrQixPQUFPLENBQUMsV0FBVyxDQUFDLHlCQUFhLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUMzRixNQUFNLFFBQVEsR0FBVyxJQUFJLENBQUMsSUFBSSxDQUFDO0lBQ25DLE1BQU0sVUFBVSxHQUFHLGVBQWUsRUFBRSxVQUFVLElBQUksT0FBTyxDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUM7SUFFOUUsSUFBSSxPQUFPLFVBQVUsS0FBSyxVQUFVLEVBQUUsQ0FBQztRQUNyQyxNQUFNLElBQUksR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFakMsU0FBUyxDQUNQLE9BQU8sSUFBSSxLQUFLLFFBQVEsSUFBSSxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsRUFDM0MsR0FBRyxFQUFFLENBQUMsSUFBSSxrQ0FBeUIsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSw4QkFBOEIsQ0FBQyxDQUN2RixDQUFDO1FBRUYsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsTUFBTSxhQUFhLEdBQUcsZUFBZSxFQUFFLGFBQWEsSUFBSSxPQUFPLENBQUMsT0FBTyxFQUFFLGFBQWEsQ0FBQztJQUV2RixJQUFJLGFBQWEsRUFBRSxDQUFDO1FBQ2xCLE1BQU0sTUFBTSxHQUFHLFVBQVUsSUFBSSxlQUFlLEVBQUUsZ0JBQWdCLElBQUksT0FBTyxDQUFDLGFBQWEsRUFBRSxVQUFVLENBQUM7UUFFcEcsT0FBTyxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLFFBQVEsSUFBSSxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDO0lBQ3pFLENBQUM7SUFFRCxJQUFJLGlCQUFpQixDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7UUFDbEMsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUVELFNBQVMsQ0FDUCxPQUFPLFVBQVUsS0FBSyxRQUFRLElBQUksVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQ3ZELEdBQUcsRUFBRSxDQUFDLElBQUksa0NBQXlCLENBQUMsQ0FBQyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsb0JBQW9CLENBQUMsQ0FDbkYsQ0FBQztJQUVGLE9BQU8sVUFBVSxDQUFDO0FBQ3BCLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFnQixZQUFZLENBQUMsSUFBUztJQUNwQyxPQUFPLENBQ0wsT0FBTyxJQUFJLEtBQUssVUFBVTtRQUMxQixDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUM7UUFDbEIsSUFBSSxLQUFLLE1BQU07UUFDZixpQkFBaUIsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLHlCQUFhLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQ3pFLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsU0FBZ0IsZUFBZSxDQUM3QixVQUFlLEVBQ2YsSUFBZ0QsRUFDaEQsTUFBVyxFQUNYLElBQVksRUFDWixVQUFxQyxFQUNyQyxVQUF5QjtJQUV6QixvQkFBTSxDQUFDLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO0lBQ3ZDLFVBQVUsR0FBRyxVQUFVLElBQUssSUFBaUMsQ0FBQztJQUU5RCxJQUFJLENBQUMsQ0FBQyxJQUFJLFlBQVksa0JBQVEsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQ3ZDLFVBQVUsR0FBRyxJQUFJLENBQUM7SUFDcEIsQ0FBQztJQUVELE1BQU0sR0FBRyxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyw4RUFBOEU7SUFDMUcsT0FBTyxVQUFVLENBQUMsR0FBRyxDQUFDO0lBRXRCLE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxVQUFVLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFFdEUsb0NBQW9DO0lBQ3BDLE1BQU0sWUFBWSxHQUFpQjtRQUNqQyxHQUFHLE1BQU0sQ0FBQyxLQUFLO1FBQ2YsSUFBSSxFQUFFO1lBQ0o7Z0JBQ0UsSUFBSSxFQUFFLElBQUk7Z0JBQ1YsR0FBRyxNQUFNLENBQUMsS0FBSztnQkFDZixHQUFHLFVBQVU7YUFDZDtTQUNGO0tBQ0YsQ0FBQztJQUVGLFVBQVUsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLENBQUMseUNBQXlDO0lBRS9ELFlBQVksQ0FBQyxJQUFJLEdBQUcseUJBQXlCLENBQUMsVUFBVSxFQUFFLFlBQVksQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBRXBHLElBQUksVUFBVSxFQUFFLENBQUM7UUFDZixvQkFBTSxDQUFDLEtBQUssQ0FBQyw0Q0FBNEMsRUFBRSxPQUFPLENBQUMsVUFBVSxDQUFDLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFDaEcsQ0FBQztJQUVELE9BQU8sWUFBWSxDQUFDO0FBQ3RCLENBQUM7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsU0FBZ0IsVUFBVSxDQUN4QixVQUFlLEVBQ2YsSUFBK0QsRUFDL0QsTUFBVyxFQUNYLElBQVksRUFDWixVQUFxQztJQUVyQyxvQkFBTSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0lBQ2xDLFVBQVUsR0FBRyxVQUFVLElBQUssSUFBaUMsQ0FBQztJQUU5RCxvQ0FBb0M7SUFDcEMsTUFBTSxHQUFHLEdBQTRCO1FBQ25DLEtBQUssRUFBRSxFQUFFO1FBQ1QsS0FBSyxFQUFFLEVBQUU7S0FDVixDQUFDO0lBRUYscUZBQXFGO0lBQ3JGLElBQUksQ0FBQyxDQUFDLElBQUksWUFBWSxrQkFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFDdkMsb0NBQW9DO1FBQ3BDLFVBQVUsR0FBRyxJQUFJLENBQUM7UUFDbEIsTUFBTSxjQUFjLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBRTNDLElBQUksY0FBYyxJQUFJLGtCQUFRLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQzVDLG9CQUFNLENBQUMsSUFBSSxDQUFDLGtDQUFrQyxFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBQ2hFLElBQUksR0FBRyxrQkFBUSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLENBQUM7WUFFN0MsSUFBSSxJQUFJLEtBQUssa0JBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUN6QyxTQUFTLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQzFCLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELElBQUksaUJBQWlCLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUNsQyxvQkFBTSxDQUFDLElBQUksQ0FBQyxxQ0FBcUMsQ0FBQyxDQUFDO0lBQ3JELENBQUM7SUFFRCxvQ0FBb0M7SUFDcEMsSUFBSSxXQUFXLEdBQWdELElBQUksRUFBRSxTQUFTLEVBQUUsa0JBQWtCLENBQUM7SUFFbkcsSUFBSSxJQUFJLFlBQVksa0JBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNwQyxXQUFXLEdBQUcsa0JBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsa0JBQWtCLENBQUM7SUFDL0UsQ0FBQztJQUVELFNBQVMsQ0FBQyxDQUFDLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksdUNBQThCLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBRXhILE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsYUFBYTtJQUU1RCxJQUFJLFdBQVcsQ0FBQyxTQUFTLFlBQVksa0JBQVEsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ2hFLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDbkQsSUFBSSxNQUFNLENBQUMsbUJBQW1CLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNwRSxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQztZQUN6QixDQUFDO2lCQUFNLENBQUM7Z0JBQ04sR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUM7WUFDekIsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO1NBQU0sQ0FBQztRQUNOLElBQUksVUFBVSxFQUFFLENBQUM7WUFDZixvQkFBTSxDQUFDLElBQUksQ0FBQyw4RkFBOEYsRUFBRSxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztRQUNuSSxDQUFDO1FBRUQsR0FBRyxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUM7SUFDdEIsQ0FBQztJQUVELElBQUksT0FBTyxPQUFPLEVBQUUsWUFBWSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzlDLE9BQU8sR0FBRyxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUM7UUFDOUIsS0FBSyxNQUFNLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7WUFDaEUsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUM7UUFDekIsQ0FBQztJQUNILENBQUM7SUFDRCxJQUFJLE9BQU8sT0FBTyxFQUFFLFlBQVksS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUM5QyxPQUFPLEdBQUcsQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDO1FBQzlCLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDO1lBQ2hFLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEdBQUcsS0FBSyxDQUFDO1FBQ3pCLENBQUM7SUFDSCxDQUFDO0lBRUQsSUFBSSxVQUFVLEVBQUUsQ0FBQztRQUNmLG9CQUFNLENBQUMsS0FBSyxDQUFDLG9DQUFvQyxFQUFFLE9BQU8sQ0FBQyxVQUFVLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUMvRSxDQUFDO0lBRUQsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsU0FBZ0Isb0JBQW9CLENBQUMsVUFBZTtJQUNsRCxzRkFBc0Y7SUFDdEYsT0FBTyxDQUFDLGlCQUFpQixDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxJQUFJLE9BQU8sVUFBVSxDQUFDLEdBQUcsS0FBSyxRQUFRLElBQUksVUFBVSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUM7QUFDMUksQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBZ0IsU0FBUyxDQUFDLE1BQVcsRUFBRSxHQUFXO0lBQ2hELE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUM3QixNQUFNLFlBQVksR0FBa0IsT0FBTyxDQUFDLFdBQVcsQ0FBQyx5QkFBYSxDQUFDLFlBQVksRUFBRSxjQUFjLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDbEgsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQyx5QkFBYSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQTZDLENBQUM7SUFFcEgsTUFBTSxXQUFXLEdBQWEsVUFBVSxFQUFFLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxPQUFPLEVBQUUsVUFBVSxJQUFJLFlBQVksQ0FBQyxPQUFPLEVBQUUsVUFBVSxJQUFJLG9CQUFRLENBQUMsSUFBSSxDQUFDO0lBRTdILG9CQUFNLENBQUMsS0FBSyxDQUFDLG9CQUFvQixJQUFJLElBQUksR0FBRyxTQUFTLFdBQVcsR0FBRyxDQUFDLENBQUM7SUFFckUsUUFBUSxXQUFXLEVBQUUsQ0FBQztRQUNwQixRQUFRO1FBQ1IsS0FBSyxvQkFBUSxDQUFDLElBQUk7WUFDaEIsb0JBQU0sQ0FBQyxJQUFJLENBQ1Qsc0tBQXNLLEVBQ3RLLElBQUksRUFDSixHQUFHLENBQ0osQ0FBQztZQUVGLE1BQU07UUFDUixLQUFLLG9CQUFRLENBQUMsS0FBSztZQUNqQixNQUFNO1FBQ1IsS0FBSyxvQkFBUSxDQUFDLEtBQUs7WUFDakIsTUFBTSxJQUFJLFNBQVMsQ0FBQyxvQ0FBb0MsSUFBSSxLQUFLLEdBQUcsVUFBVSxDQUFDLENBQUM7SUFDcEYsQ0FBQztJQUVELE9BQU8sQ0FBQyxnREFBZ0Q7QUFDMUQsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFnQixpQkFBaUIsQ0FBQyxHQUFZO0lBQzVDLE9BQU8sR0FBRyxLQUFLLElBQUksSUFBSSxHQUFHLEtBQUssU0FBUyxDQUFDO0FBQzNDLENBQUM7QUFFRDs7Ozs7Ozs7O0dBU0c7QUFDSCxTQUFnQixxQkFBcUIsQ0FDbkMsVUFBcUMsRUFDckMsRUFBNEIsRUFDNUIsU0FBa0IsS0FBSztJQUV2QixJQUFJLEdBQUcsR0FBRyxPQUFPLFVBQVUsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBRTNELDBDQUEwQztJQUMxQyxJQUFJLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyx5QkFBYSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQ3ZDLEdBQUcsR0FBRyxhQUFhLENBQUMseUJBQWEsQ0FBQyxZQUFZLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUVqRSxvQkFBTSxDQUFDLElBQUksQ0FBQyx3Q0FBd0MsRUFBRSxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNuRSxHQUFHLEdBQUcsWUFBWSxDQUFDLGdCQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFhLEVBQUUsZUFBZSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFFckUsR0FBRyxDQUFDLHlCQUFhLENBQUMsR0FBRyxJQUFJLENBQUM7SUFDNUIsQ0FBQztJQUVELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILFNBQWdCLHlCQUF5QixDQUFDLFVBQWUsRUFBRSxLQUFVLEVBQUUsSUFBWSxFQUFFLEdBQVc7SUFDOUYsZ0NBQWdDO0lBQ2hDLE1BQU0sR0FBRyxHQUFHLE9BQU8sVUFBVSxDQUFDLEdBQUcsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUVwRSxJQUFJLEdBQUcsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUNaLE1BQU0sSUFBSSxVQUFVLENBQUMsb0NBQW9DLElBQUksSUFBSSxHQUFHLFVBQVUsQ0FBQyxDQUFDO0lBQ2xGLENBQUM7SUFFRCxPQUFPLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQywyREFBMkQ7SUFDbEYsb0JBQU0sQ0FBQyxJQUFJLENBQUMscURBQXFELEVBQUUsR0FBRyxDQUFDLENBQUM7SUFFeEUsSUFBSSxRQUFRLEdBQVUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzdELDJFQUEyRTtJQUMzRSxLQUFLLElBQUksS0FBSyxHQUFHLENBQUMsRUFBRSxLQUFLLEdBQUcsR0FBRyxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUM7UUFDekMsUUFBUSxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDeEIsQ0FBQztJQUVELE9BQU8sUUFBaUIsQ0FBQztBQUMzQixDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILFNBQWdCLFNBQVMsQ0FBQyxJQUFTLEVBQUUsS0FBbUM7SUFDdEUsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1YsTUFBTSxPQUFPLEtBQUssS0FBSyxVQUFVLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssSUFBSSxJQUFJLCtCQUFzQixFQUFFLENBQUMsQ0FBQztJQUN4RixDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLGdCQUFnQixDQUFDLEdBQVE7SUFDdkMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLDBCQUFpQixDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7QUFDbEUsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFnQixPQUFPLENBQUMsVUFBc0IsRUFBRSx1QkFBZ0MsS0FBSztJQUNuRixNQUFNLFlBQVksR0FBa0I7UUFDbEMsSUFBSSxFQUFFLFVBQVU7UUFDaEIsR0FBRyxFQUFFLENBQUM7S0FDUCxDQUFDO0lBRUYsSUFBSSxPQUFPLFlBQVksQ0FBQyxJQUFJLEtBQUssVUFBVSxJQUFJLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ2pGLFlBQVksQ0FBQyxJQUFJLEdBQUksWUFBWSxDQUFDLElBQWEsRUFBRSxDQUFDO0lBQ3BELENBQUM7SUFFRCxTQUFTLFFBQVE7UUFDZixJQUFJLFlBQVksQ0FBQyxHQUFHLEdBQUcsR0FBRyxFQUFFLENBQUM7WUFDM0Isa0ZBQWtGO1lBQ2xGLE1BQU0sSUFBSSxLQUFLLENBQUMsd0NBQXdDLENBQUMsQ0FBQztRQUM1RCxDQUFDO1FBQ0QsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3JDLFlBQVksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUVuQixJQUFJLG9CQUFvQixJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDakUsT0FBTztZQUNULENBQUM7WUFFRCxZQUFZLENBQUMsSUFBSSxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDekMsUUFBUSxFQUFFLENBQUM7UUFDYixDQUFDO0lBQ0gsQ0FBQztJQUVELFFBQVEsRUFBRSxDQUFDO0lBRVgsb0JBQU0sQ0FBQyxLQUFLLENBQUMsK0JBQStCLEVBQUUsWUFBWSxDQUFDLEdBQUcsRUFBRSxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFbkYsT0FBTyxZQUFZLENBQUM7QUFDdEIsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLGFBQWEsQ0FBQyxHQUFRO0lBQ3BDLE9BQU8sQ0FDTCxPQUFPLEdBQUcsS0FBSyxVQUFVLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLFdBQVcsRUFBRSxJQUFJLENBQUM7SUFDakYsMkhBQTJIO0lBQzNILGlGQUFpRjtJQUNqRix5REFBeUQ7S0FDMUQsQ0FBQztBQUNKLENBQUM7QUFFRCxNQUFNO0FBQ04sK0VBQStFO0FBQy9FLDBGQUEwRjtBQUMxRix1SUFBdUk7QUFDdkksTUFBTTtBQUNOLDJGQUEyRjtBQUMzRix1Q0FBdUM7QUFDdkMscUVBQXFFO0FBQ3JFLDJEQUEyRDtBQUMzRCxNQUFNO0FBRU4sNkRBQTZEO0FBRTdELGVBQWU7QUFDZixJQUFJO0FBRUo7Ozs7Ozs7R0FPRztBQUNILFNBQWdCLHlCQUF5QixDQUFDLElBQVksRUFBRSxHQUFXLEVBQUUsSUFBWSxFQUFFLEtBQWEsRUFBRSxRQUFrQjtJQUNsSCxxREFBcUQ7SUFDckQsSUFBSSxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ3hCLG9CQUFNLENBQUMsSUFBSSxDQUNULFlBQVksSUFBSSxJQUFJLEdBQUcsWUFBWSxJQUFJLGdDQUFnQyxLQUFLLG9CQUFvQixHQUFHLE1BQU0sU