UNPKG

passkit-generator

Version:

The easiest way to generate custom Apple Wallet passes in Node.js

766 lines 53.1 kB
"use strict"; var _a, _b, _c; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const node_buffer_1 = require("node:buffer"); const node_path_1 = tslib_1.__importDefault(require("node:path")); const FieldsArray_js_1 = tslib_1.__importDefault(require("./FieldsArray.js")); const Bundle_js_1 = tslib_1.__importStar(require("./Bundle.js")); const getModelFolderContents_js_1 = tslib_1.__importDefault(require("./getModelFolderContents.js")); const Schemas = tslib_1.__importStar(require("./schemas/index.js")); const Signature = tslib_1.__importStar(require("./Signature.js")); const Strings = tslib_1.__importStar(require("./StringsUtils.js")); const Utils = tslib_1.__importStar(require("./utils.js")); const Messages = tslib_1.__importStar(require("./messages.js")); const propsSymbol = Symbol("props"); const localizationSymbol = Symbol("pass.l10n"); const importMetadataSymbol = Symbol("import.pass.metadata"); const createManifestSymbol = Symbol("pass.manifest"); const closePassSymbol = Symbol("pass.close"); const passTypeSymbol = Symbol("pass.type"); const certificatesSymbol = Symbol("pass.certificates"); const RegExps = { PASS_JSON: /pass\.json/, MANIFEST_OR_SIGNATURE: /manifest|signature/, PERSONALIZATION: { JSON: /personalization\.json/, LOGO: /personalizationLogo@(?:.{2})/, }, PASS_STRINGS: /(?<lang>[a-zA-Z-]{2,}).lproj\/pass\.strings/, PASS_ICON: /icon(?:@\d{1}x)?/, }; class PKPass extends Bundle_js_1.default { /** * Either create a pass from another one * or a disk path. * * @param source * @returns */ static async from(source, props) { let certificates = undefined; let buffers = undefined; if (!source) { throw new TypeError(Messages.format(Messages.FROM.MISSING_SOURCE, source)); } if (source instanceof PKPass) { /** Cloning is happening here */ certificates = source[certificatesSymbol]; buffers = {}; const buffersEntries = Object.entries(source[Bundle_js_1.filesSymbol]); /** Cloning all the buffers to prevent unwanted edits */ for (let i = 0; i < buffersEntries.length; i++) { const [fileName, contentBuffer] = buffersEntries[i]; buffers[fileName] = node_buffer_1.Buffer.alloc(contentBuffer.length); contentBuffer.copy(buffers[fileName]); } /** * Moving props to pass.json instead of overrides * because many might get excluded when passing * through validation */ buffers["pass.json"] = node_buffer_1.Buffer.from(JSON.stringify(source[propsSymbol])); } else { Schemas.assertValidity(Schemas.Template, source, Messages.TEMPLATE.INVALID); buffers = await (0, getModelFolderContents_js_1.default)(source.model); certificates = source.certificates; } return new PKPass(buffers, certificates, props); } /** * Creates a Bundle made of PKPass to be distributed * as a `.pkpasses` zip file. Returns a Bundle instance * so it can be outputted both as stream or as a buffer. * * Using this will freeze all the instances passed as * parameter. * * Throws if not all the files are instance of PKPass. * * @param passes */ static pack(...passes) { const [bundle, freezeBundle] = Bundle_js_1.default.freezable("application/vnd.apple.pkpasses"); for (let i = 0; i < passes.length; i++) { const pass = passes[i]; if (!(pass instanceof PKPass)) { throw new Error(Messages.PACK.INVALID); } bundle.addBuffer(`packed-pass-${i + 1}.pkpass`, pass.getAsBuffer()); } freezeBundle(); return bundle; } // **************** // // *** INSTANCE *** // // **************** // constructor(buffers, certificates, props) { super("application/vnd.apple.pkpass"); this[_a] = {}; this[_b] = {}; this[_c] = undefined; if (buffers && typeof buffers === "object") { const buffersEntries = Object.entries(buffers); for (let i = buffersEntries.length, buffer; (buffer = buffersEntries[--i]);) { const [fileName, contentBuffer] = buffer; this.addBuffer(fileName, contentBuffer); } } else { console.warn(Messages.format(Messages.INIT.INVALID_BUFFERS, typeof buffers)); } if (props) { /** Overrides validation and pushing in props */ const overridesValidation = Schemas.validate(Schemas.OverridablePassProps, props); Object.assign(this[propsSymbol], overridesValidation); } if (certificates) { this.certificates = certificates; } } /** * Allows changing the certificates, if needed. * They are actually expected to be received in * the constructor, but they can get overridden * here for whatever purpose. * * When using this setter, all certificates are * expected to be received, or an exception will * be thrown. * * @param certs */ set certificates(certs) { Utils.assertUnfrozen(this); Schemas.assertValidity(Schemas.CertificatesSchema, certs, Messages.CERTIFICATES.INVALID); this[certificatesSymbol] = certs; } /** * Allows retrieving current languages */ get languages() { return Object.keys(this[localizationSymbol]); } /** * Allows getting an image of the props * that are composing your pass instance. */ get props() { return Utils.cloneRecursive(this[propsSymbol]); } /** * Allows accessing to iOS 18 new Event Ticket * property `preferredStyleSchemes`. * * @throws if current type is not "eventTicket". */ get preferredStyleSchemes() { if (this.type !== "eventTicket") { throw new TypeError(Messages.PREFERRED_STYLE_SCHEMES.UNEXPECTED_PASS_TYPE_GET); } return this[propsSymbol].preferredStyleSchemes; } /** * Allows setting a preferredStyleSchemes property * for a eventTicket. * * @throws if current type is not "eventTicket". * @param value */ set preferredStyleSchemes(value) { Utils.assertUnfrozen(this); if (this.type !== "eventTicket") { throw new TypeError(Messages.PREFERRED_STYLE_SCHEMES.UNEXPECTED_PASS_TYPE_SET); } Schemas.assertValidity(Schemas.PreferredStyleSchemes, value, Messages.PREFERRED_STYLE_SCHEMES.INVALID); this[propsSymbol].preferredStyleSchemes = value; } /** * Allows setting a transitType property * for a boardingPass. * * @throws if current type is not "boardingPass". * @param value */ set transitType(value) { Utils.assertUnfrozen(this); if (this.type !== "boardingPass") { throw new TypeError(Messages.TRANSIT_TYPE.UNEXPECTED_PASS_TYPE); } Schemas.assertValidity(Schemas.TransitType, value, Messages.TRANSIT_TYPE.INVALID); this[propsSymbol]["boardingPass"].transitType = value; } /** * Allows getting the current transitType * from pass props. * * @throws (automatically) if current type is not "boardingPass". */ get transitType() { return this[propsSymbol]["boardingPass"].transitType; } /** * Allows accessing to primaryFields object. * * @throws (automatically) if no valid pass.json * has been parsed yet or, anyway, if current * instance has not a valid type set yet. */ get primaryFields() { return this[propsSymbol][this.type].primaryFields; } /** * Allows accessing to secondaryFields object * * @throws (automatically) if no valid pass.json * has been parsed yet or, anyway, if current * instance has not a valid type set yet. */ get secondaryFields() { return this[propsSymbol][this.type].secondaryFields; } /** * Allows accessing to auxiliaryFields object * * For Typescript users: this signature allows * in any case to add the 'row' field, but on * runtime they are only allowed on "eventTicket" * passes. * * @throws (automatically) if no valid pass.json * has been parsed yet or, anyway, if current * instance has not a valid type set yet. */ get auxiliaryFields() { return this[propsSymbol][this.type].auxiliaryFields; } /** * Allows accessing to headerFields object * * @throws (automatically) if no valid pass.json * has been parsed yet or, anyway, if current * instance has not a valid type set yet. */ get headerFields() { return this[propsSymbol][this.type].headerFields; } /** * Allows accessing to backFields object * * @throws (automatically) if no valid pass.json * has been parsed yet or, anyway, if current * instance has not a valid type set yet. */ get backFields() { return this[propsSymbol][this.type].backFields; } /** * Allows accessing to new iOS 18 * event ticket additional fields * * @throws (automatically) if no valid pass.json * has been parsed yet or, anyway, if current * type is not "eventTicket". */ get additionalInfoFields() { return this[propsSymbol]["eventTicket"].additionalInfoFields; } /** * Allows setting a pass type. * * **Warning**: setting a type with this setter, * will reset all the fields (primaryFields, * secondaryFields, headerFields, auxiliaryFields, backFields), * both imported or manually set. */ set type(nextType) { Utils.assertUnfrozen(this); Schemas.assertValidity(Schemas.PassType, nextType, Messages.PASS_TYPE.INVALID); /** Shut up, typescript strict mode! */ const type = nextType; if (this.type) { /** * Removing reference to previous type and its content because * we might have some differences between types. It is way easier * to reset everything instead of making checks. */ this[propsSymbol][this.type] = undefined; this[propsSymbol].preferredStyleSchemes = undefined; } const sharedKeysPool = new Set(); this[passTypeSymbol] = type; this[propsSymbol][type] = { headerFields /******/: new FieldsArray_js_1.default(this, sharedKeysPool, Schemas.Field), primaryFields /*****/: new FieldsArray_js_1.default(this, sharedKeysPool, Schemas.Field), secondaryFields /***/: new FieldsArray_js_1.default(this, sharedKeysPool, Schemas.Field), auxiliaryFields /***/: new FieldsArray_js_1.default(this, sharedKeysPool, type === "eventTicket" ? Schemas.FieldWithRow : Schemas.Field), backFields /********/: new FieldsArray_js_1.default(this, sharedKeysPool, Schemas.Field), additionalInfoFields: new FieldsArray_js_1.default(this, sharedKeysPool, Schemas.Field), transitType: undefined, }; } get type() { var _d; return (_d = this[passTypeSymbol]) !== null && _d !== void 0 ? _d : undefined; } // **************************** // // *** ASSETS SETUP METHODS *** // // **************************** // /** * Allows adding a new asset inside the pass / bundle with * the following exceptions: * * - Empty buffers are ignored; * - `manifest.json` and `signature` files will be ignored; * - `pass.json` will be read validated and merged in the * current instance, if it wasn't added previously. * It's properties will overwrite the instance ones. * You might loose data; * - `pass.strings` files will be read, parsed and merged * with the current translations. Comments will be ignored; * - `personalization.json` will be read, validated and added. * They will be stripped out when exporting the pass if * it won't have NFC details or if any of the personalization * files is missing; * * @param pathName * @param buffer */ addBuffer(pathName, buffer) { if (!(buffer === null || buffer === void 0 ? void 0 : buffer.length)) { return; } if (RegExps.MANIFEST_OR_SIGNATURE.test(pathName)) { return; } if (RegExps.PASS_JSON.test(pathName)) { if (this[Bundle_js_1.filesSymbol]["pass.json"]) { /** * Ignoring any further addition. In a * future we might consider merging instead */ return; } try { this[importMetadataSymbol](validateJSONBuffer(buffer, Schemas.PassProps)); } catch (err) { console.warn(Messages.format(Messages.PASS_SOURCE.INVALID, err)); return; } /** * Adding an empty buffer just for reference * that we received a valid pass.json file. * It will be reconciliated in export phase. */ return super.addBuffer(pathName, node_buffer_1.Buffer.alloc(0)); } if (RegExps.PERSONALIZATION.JSON.test(pathName)) { /** * We are still allowing `personalizationLogo@XX.png` * to be added to the bundle, but we'll delete it * once the pass is getting closed, if needed. */ try { validateJSONBuffer(buffer, Schemas.Personalize); } catch (err) { console.warn(Messages.format(Messages.PERSONALIZE.INVALID, err)); return; } return super.addBuffer(pathName, buffer); } /** * Converting Windows path to Unix path * @example de.lproj\\icon.png => de.lproj/icon.png */ const normalizedPathName = pathName.replace(node_path_1.default.sep, "/"); /** * If a new pass.strings file is added, we want to * prevent it from being merged and, instead, save * its translations for later */ let match; if ((match = normalizedPathName.match(RegExps.PASS_STRINGS))) { const [, lang] = match; const parsedTranslations = Strings.parse(buffer).translations; if (!parsedTranslations.length) { return; } this.localize(lang, Object.fromEntries(parsedTranslations)); return; } return super.addBuffer(normalizedPathName, buffer); } /** * Given data from a pass.json, reads them to bring them * into the current pass instance. * * @param data */ [(_a = propsSymbol, _b = localizationSymbol, _c = passTypeSymbol, importMetadataSymbol)](data) { const possibleTypes = [ "boardingPass", "coupon", "eventTicket", "storeCard", "generic", ]; const type = possibleTypes.find((type) => Boolean(data[type])); const { boardingPass, coupon, storeCard, generic, eventTicket, ...otherPassData } = data; if (Object.keys(this[propsSymbol]).length) { console.warn(Messages.PASS_SOURCE.JOIN); } Object.assign(this[propsSymbol], otherPassData); if (!type) { if (!this[passTypeSymbol]) { console.warn(Messages.PASS_SOURCE.UNKNOWN_TYPE); } } else { this.type = type; const { headerFields = [], primaryFields = [], secondaryFields = [], auxiliaryFields = [], backFields = [], transitType, additionalInfoFields = [], } = data[type] || {}; this.headerFields.push(...headerFields); this.primaryFields.push(...primaryFields); this.secondaryFields.push(...secondaryFields); this.auxiliaryFields.push(...auxiliaryFields); this.backFields.push(...backFields); if (this.type === "boardingPass") { this.transitType = transitType; } if (this.type === "eventTicket") { this.additionalInfoFields.push(...additionalInfoFields); } } } /** * Creates the manifest starting from files * added to the bundle */ [createManifestSymbol]() { const manifest = Object.entries(this[Bundle_js_1.filesSymbol]).reduce((acc, [fileName, buffer]) => ({ ...acc, [fileName]: Signature.createHash(buffer), }), {}); return node_buffer_1.Buffer.from(JSON.stringify(manifest)); } /** * Applies the last validation checks against props, * applies the props to pass.json and creates l10n * files and folders and creates manifest and * signature files */ [closePassSymbol]() { if (!this.type) { throw new TypeError(Messages.CLOSE.MISSING_TYPE); } const fileNames = Object.keys(this[Bundle_js_1.filesSymbol]); const passJson = node_buffer_1.Buffer.from(JSON.stringify(this[propsSymbol])); super.addBuffer("pass.json", passJson); if (!fileNames.some((fileName) => RegExps.PASS_ICON.test(fileName))) { console.warn(Messages.CLOSE.MISSING_ICON); } // *********************************** // // *** LOCALIZATION FILES CREATION *** // // *********************************** // const localizationEntries = Object.entries(this[localizationSymbol]); for (let i = localizationEntries.length - 1; i >= 0; i--) { const [lang, translations] = localizationEntries[i]; const stringsFile = Strings.create(translations); if (stringsFile.length) { super.addBuffer(`${lang}.lproj/pass.strings`, stringsFile); } } // *********************** // // *** PERSONALIZATION *** // // *********************** // const meetsPersonalizationRequirements = Boolean(this[propsSymbol]["nfc"] && this[Bundle_js_1.filesSymbol]["personalization.json"] && fileNames.find((file) => RegExps.PERSONALIZATION.LOGO.test(file))); if (!meetsPersonalizationRequirements) { /** * Looking for every personalization file * and removing it */ for (let i = 0; i < fileNames.length; i++) { if (fileNames[i].includes("personalization")) { console.warn(Messages.format(Messages.CLOSE.PERSONALIZATION_REMOVED, fileNames[i])); delete this[Bundle_js_1.filesSymbol][fileNames[i]]; } } } // ******************************** // // *** BOARDING PASS VALIDATION *** // // ******************************** // if (this.type === "boardingPass" && !this.transitType) { throw new TypeError(Messages.CLOSE.MISSING_TRANSIT_TYPE); } // ****************************** // // *** SIGNATURE AND MANIFEST *** // // ****************************** // const manifestBuffer = this[createManifestSymbol](); super.addBuffer("manifest.json", manifestBuffer); const signatureBuffer = Signature.create(manifestBuffer, this[certificatesSymbol]); super.addBuffer("signature", signatureBuffer); } // ************************* // // *** EXPORTING METHODS *** // // ************************* // /** * Exports the pass as a zip buffer. When this method * is invoked, the bundle will get frozen and, thus, * no files will be allowed to be added any further. * * @returns */ getAsBuffer() { if (!this.isFrozen) { this[closePassSymbol](); } return super.getAsBuffer(); } /** * Exports the pass as a zip stream. When this method * is invoked, the bundle will get frozen and, thus, * no files will be allowed to be added any further. * * @returns */ getAsStream() { if (!this.isFrozen) { this[closePassSymbol](); } return super.getAsStream(); } /** * Exports the pass as a list of file paths and buffers. * When this method is invoked, the bundle will get * frozen and, thus, no files will be allowed to be * added any further. * * This allows developers to choose a different way * of serving, analyzing or zipping the file, outside the * default compression system. * * @returns a frozen object containing files paths as key * and Buffers as content. */ getAsRaw() { if (!this.isFrozen) { this[closePassSymbol](); } return super.getAsRaw(); } // ************************** // // *** DATA SETUP METHODS *** // // ************************** // /** * Allows to add a localization details to the * final bundle with some translations. * * If the language already exists, translations will be * merged with the existing ones. * * Setting `translations` to `null` fully deletes a language, * its translations and its files. * * @see https://developer.apple.com/documentation/walletpasses/creating_the_source_for_a_pass#3736718 * @param lang * @param translations */ localize(lang, translations) { var _d; var _e; Utils.assertUnfrozen(this); if (typeof lang !== "string") { throw new TypeError(Messages.format(Messages.LANGUAGES.INVALID_LANG, typeof lang)); } if (translations === null) { delete this[localizationSymbol][lang]; const allFilesKeys = Object.keys(this[Bundle_js_1.filesSymbol]); const langFolderIdentifier = `${lang}.lproj`; for (let i = allFilesKeys.length - 1; i >= 0; i--) { const filePath = allFilesKeys[i]; if (filePath.startsWith(langFolderIdentifier)) { delete this[Bundle_js_1.filesSymbol][filePath]; } } return; } if (!translations || !Object.keys(translations).length) { console.warn(Messages.format(Messages.LANGUAGES.NO_TRANSLATIONS, lang)); return; } (_d = (_e = this[localizationSymbol])[lang]) !== null && _d !== void 0 ? _d : (_e[lang] = {}); if (typeof translations === "object" && !Array.isArray(translations)) { Object.assign(this[localizationSymbol][lang], translations); } } /** * Allows to specify an expiration date for the pass. * * Pass `null` to remove the expiration date. * * @param date * @throws if pass is frozen due to previous export * @returns */ setExpirationDate(date) { Utils.assertUnfrozen(this); if (date === null) { delete this[propsSymbol]["expirationDate"]; return; } try { this[propsSymbol]["expirationDate"] = Utils.processDate(date); } catch (err) { throw new TypeError(Messages.format(Messages.DATE.INVALID, "expirationDate", date)); } } setBeacons(...beacons) { Utils.assertUnfrozen(this); if (beacons[0] === null) { delete this[propsSymbol]["beacons"]; return; } this[propsSymbol]["beacons"] = Schemas.filterValid(Schemas.Beacon, beacons); } setLocations(...locations) { Utils.assertUnfrozen(this); if (locations[0] === null) { delete this[propsSymbol]["locations"]; return; } this[propsSymbol]["locations"] = Schemas.filterValid(Schemas.Location, locations); } /** * Allows setting a series of relevancy intervals or * relevancy entries for the pass. * * @param {Schemas.RelevantDate[] | null} relevancyEntries * @returns {void} */ setRelevantDates(relevancyEntries) { Utils.assertUnfrozen(this); if (relevancyEntries === null) { this[propsSymbol]["relevantDates"] = undefined; return; } const processedDateEntries = relevancyEntries.reduce((acc, entry) => { try { Schemas.validate(Schemas.RelevantDate, entry); if (isRelevantEntry(entry)) { acc.push({ relevantDate: Utils.processDate(new Date(entry.relevantDate)), }); return acc; } acc.push({ startDate: Utils.processDate(new Date(entry.startDate)), endDate: Utils.processDate(new Date(entry.endDate)), }); } catch (err) { console.warn(new TypeError(Messages.RELEVANT_DATE.INVALID)); } return acc; }, []); this[propsSymbol]["relevantDates"] = processedDateEntries; } /** * Allows setting a relevant date in which the OS * should show this pass. * * Pass `null` to remove relevant date from this pass. * * @param {Date | null} date * @throws if pass is frozen due to previous export * * @warning `relevantDate` property has been deprecated in iOS 18 * in order to get replaced by `relevantDates` array of intervals * (`relevantDates[].startDate` + `relevantDates[].endDate`) * or single date (`relevantDates[].relevantDate`). */ setRelevantDate(date) { Utils.assertUnfrozen(this); if (date === null) { delete this[propsSymbol]["relevantDate"]; return; } try { this[propsSymbol]["relevantDate"] = Utils.processDate(date); } catch (err) { throw new TypeError(Messages.format(Messages.DATE.INVALID, "relevantDate", date)); } } setBarcodes(...barcodes) { Utils.assertUnfrozen(this); if (!barcodes.length) { return; } if (barcodes[0] === null) { delete this[propsSymbol]["barcodes"]; return; } let finalBarcodes; if (typeof barcodes[0] === "string") { /** * A string has been received instead of objects. We can * only auto-fill them all with the same data. */ const supportedFormats = [ "PKBarcodeFormatQR", "PKBarcodeFormatPDF417", "PKBarcodeFormatAztec", "PKBarcodeFormatCode128", ]; finalBarcodes = supportedFormats.map((format) => Schemas.validate(Schemas.Barcode, { format, message: barcodes[0], })); } else { finalBarcodes = Schemas.filterValid(Schemas.Barcode, barcodes); } this[propsSymbol]["barcodes"] = finalBarcodes; } /** * Allows to specify details to make this, an * NFC-capable pass. * * Pass `null` as parameter to remove it at all. * * @see https://developer.apple.com/documentation/walletpasses/pass/nfc * @param data * @throws if pass is frozen due to previous export * @returns */ setNFC(nfc) { var _d; Utils.assertUnfrozen(this); if (nfc === null) { delete this[propsSymbol]["nfc"]; return; } this[propsSymbol]["nfc"] = (_d = Schemas.validate(Schemas.NFC, nfc)) !== null && _d !== void 0 ? _d : undefined; } } exports.default = PKPass; function validateJSONBuffer(buffer, schema) { let contentAsJSON; try { contentAsJSON = JSON.parse(buffer.toString("utf8")); } catch (err) { throw new TypeError(Messages.JSON.INVALID); } return Schemas.validate(schema, contentAsJSON); } function isRelevantEntry(entry) { return Object.prototype.hasOwnProperty.call(entry, "relevantDate"); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUEtQYXNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL1BLUGFzcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQ0EsNkNBQXFDO0FBQ3JDLGtFQUE2QjtBQUM3Qiw4RUFBMkM7QUFDM0MsaUVBQWtEO0FBQ2xELG9HQUFpRTtBQUNqRSxvRUFBOEM7QUFDOUMsa0VBQTRDO0FBQzVDLG1FQUE2QztBQUM3QywwREFBb0M7QUFDcEMsZ0VBQTBDO0FBRTFDLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUNwQyxNQUFNLGtCQUFrQixHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUMvQyxNQUFNLG9CQUFvQixHQUFHLE1BQU0sQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO0FBQzVELE1BQU0sb0JBQW9CLEdBQUcsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0FBQ3JELE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztBQUM3QyxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7QUFDM0MsTUFBTSxrQkFBa0IsR0FBRyxNQUFNLENBQUMsbUJBQW1CLENBQUMsQ0FBQztBQUV2RCxNQUFNLE9BQU8sR0FBRztJQUNmLFNBQVMsRUFBRSxZQUFZO0lBQ3ZCLHFCQUFxQixFQUFFLG9CQUFvQjtJQUMzQyxlQUFlLEVBQUU7UUFDaEIsSUFBSSxFQUFFLHVCQUF1QjtRQUM3QixJQUFJLEVBQUUsOEJBQThCO0tBQzNCO0lBQ1YsWUFBWSxFQUFFLDZDQUE2QztJQUMzRCxTQUFTLEVBQUUsa0JBQWtCO0NBQ3BCLENBQUM7QUFFWCxNQUFxQixNQUFPLFNBQVEsbUJBQU07SUFVekM7Ozs7OztPQU1HO0lBRUksTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQ3ZCLE1BQVMsRUFDVCxLQUFvQztRQUVwQyxJQUFJLFlBQVksR0FBMkMsU0FBUyxDQUFDO1FBQ3JFLElBQUks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