@vess-id/mdl 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +179 -0
  2. package/README.md +181 -0
  3. package/lib/buffer_utils.d.ts +6 -0
  4. package/lib/buffer_utils.js +36 -0
  5. package/lib/cbor/DataItem.d.ts +26 -0
  6. package/lib/cbor/DataItem.js +77 -0
  7. package/lib/cbor/index.d.ts +15 -0
  8. package/lib/cbor/index.js +73 -0
  9. package/lib/cose/coseKey.d.ts +14 -0
  10. package/lib/cose/coseKey.js +36 -0
  11. package/lib/index.d.ts +12 -0
  12. package/lib/index.js +28 -0
  13. package/lib/mdoc/IssuerSignedItem.d.ts +18 -0
  14. package/lib/mdoc/IssuerSignedItem.js +101 -0
  15. package/lib/mdoc/Verifier.d.ts +33 -0
  16. package/lib/mdoc/Verifier.js +405 -0
  17. package/lib/mdoc/checkCallback.d.ts +49 -0
  18. package/lib/mdoc/checkCallback.js +63 -0
  19. package/lib/mdoc/errors.d.ts +7 -0
  20. package/lib/mdoc/errors.js +21 -0
  21. package/lib/mdoc/model/DeviceResponse.d.ts +120 -0
  22. package/lib/mdoc/model/DeviceResponse.js +295 -0
  23. package/lib/mdoc/model/DeviceSignedDocument.d.ts +20 -0
  24. package/lib/mdoc/model/DeviceSignedDocument.js +50 -0
  25. package/lib/mdoc/model/Document.d.ts +75 -0
  26. package/lib/mdoc/model/Document.js +249 -0
  27. package/lib/mdoc/model/IssuerAuth.d.ts +17 -0
  28. package/lib/mdoc/model/IssuerAuth.js +72 -0
  29. package/lib/mdoc/model/IssuerSignedDocument.d.ts +29 -0
  30. package/lib/mdoc/model/IssuerSignedDocument.js +49 -0
  31. package/lib/mdoc/model/MDoc.d.ts +21 -0
  32. package/lib/mdoc/model/MDoc.js +34 -0
  33. package/lib/mdoc/model/PresentationDefinition.d.ts +21 -0
  34. package/lib/mdoc/model/PresentationDefinition.js +3 -0
  35. package/lib/mdoc/model/types.d.ts +110 -0
  36. package/lib/mdoc/model/types.js +3 -0
  37. package/lib/mdoc/parser.d.ts +8 -0
  38. package/lib/mdoc/parser.js +88 -0
  39. package/lib/mdoc/utils.d.ts +17 -0
  40. package/lib/mdoc/utils.js +145 -0
  41. package/package.json +82 -0
package/lib/index.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ export { Verifier } from './mdoc/Verifier';
2
+ export { parse } from './mdoc/parser';
3
+ export { DataItem } from './cbor/DataItem';
4
+ export { DiagnosticInformation as DianosticInformation } from './mdoc/model/types';
5
+ export { MDoc } from './mdoc/model/MDoc';
6
+ export { Document } from './mdoc/model/Document';
7
+ export { IssuerSignedDocument } from './mdoc/model/IssuerSignedDocument';
8
+ export { DeviceSignedDocument } from './mdoc/model/DeviceSignedDocument';
9
+ export { DeviceResponse } from './mdoc/model/DeviceResponse';
10
+ export { MDLError, MDLParseError } from './mdoc/errors';
11
+ export { VerificationAssessmentId } from './mdoc/checkCallback';
12
+ export { getCborEncodeDecodeOptions, setCborEncodeDecodeOptions } from './cbor';
package/lib/index.js ADDED
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setCborEncodeDecodeOptions = exports.getCborEncodeDecodeOptions = exports.VerificationAssessmentId = exports.MDLParseError = exports.MDLError = exports.DeviceResponse = exports.DeviceSignedDocument = exports.IssuerSignedDocument = exports.Document = exports.MDoc = exports.DataItem = exports.parse = exports.Verifier = void 0;
4
+ var Verifier_1 = require("./mdoc/Verifier");
5
+ Object.defineProperty(exports, "Verifier", { enumerable: true, get: function () { return Verifier_1.Verifier; } });
6
+ var parser_1 = require("./mdoc/parser");
7
+ Object.defineProperty(exports, "parse", { enumerable: true, get: function () { return parser_1.parse; } });
8
+ var DataItem_1 = require("./cbor/DataItem");
9
+ Object.defineProperty(exports, "DataItem", { enumerable: true, get: function () { return DataItem_1.DataItem; } });
10
+ var MDoc_1 = require("./mdoc/model/MDoc");
11
+ Object.defineProperty(exports, "MDoc", { enumerable: true, get: function () { return MDoc_1.MDoc; } });
12
+ var Document_1 = require("./mdoc/model/Document");
13
+ Object.defineProperty(exports, "Document", { enumerable: true, get: function () { return Document_1.Document; } });
14
+ var IssuerSignedDocument_1 = require("./mdoc/model/IssuerSignedDocument");
15
+ Object.defineProperty(exports, "IssuerSignedDocument", { enumerable: true, get: function () { return IssuerSignedDocument_1.IssuerSignedDocument; } });
16
+ var DeviceSignedDocument_1 = require("./mdoc/model/DeviceSignedDocument");
17
+ Object.defineProperty(exports, "DeviceSignedDocument", { enumerable: true, get: function () { return DeviceSignedDocument_1.DeviceSignedDocument; } });
18
+ var DeviceResponse_1 = require("./mdoc/model/DeviceResponse");
19
+ Object.defineProperty(exports, "DeviceResponse", { enumerable: true, get: function () { return DeviceResponse_1.DeviceResponse; } });
20
+ var errors_1 = require("./mdoc/errors");
21
+ Object.defineProperty(exports, "MDLError", { enumerable: true, get: function () { return errors_1.MDLError; } });
22
+ Object.defineProperty(exports, "MDLParseError", { enumerable: true, get: function () { return errors_1.MDLParseError; } });
23
+ var checkCallback_1 = require("./mdoc/checkCallback");
24
+ Object.defineProperty(exports, "VerificationAssessmentId", { enumerable: true, get: function () { return checkCallback_1.VerificationAssessmentId; } });
25
+ var cbor_1 = require("./cbor");
26
+ Object.defineProperty(exports, "getCborEncodeDecodeOptions", { enumerable: true, get: function () { return cbor_1.getCborEncodeDecodeOptions; } });
27
+ Object.defineProperty(exports, "setCborEncodeDecodeOptions", { enumerable: true, get: function () { return cbor_1.setCborEncodeDecodeOptions; } });
28
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNENBQTJDO0FBQWxDLG9HQUFBLFFBQVEsT0FBQTtBQUNqQix3Q0FBc0M7QUFBN0IsK0ZBQUEsS0FBSyxPQUFBO0FBQ2QsNENBQTJDO0FBQWxDLG9HQUFBLFFBQVEsT0FBQTtBQUVqQiwwQ0FBeUM7QUFBaEMsNEZBQUEsSUFBSSxPQUFBO0FBQ2Isa0RBQWlEO0FBQXhDLG9HQUFBLFFBQVEsT0FBQTtBQUNqQiwwRUFBeUU7QUFBaEUsNEhBQUEsb0JBQW9CLE9BQUE7QUFDN0IsMEVBQXlFO0FBQWhFLDRIQUFBLG9CQUFvQixPQUFBO0FBQzdCLDhEQUE2RDtBQUFwRCxnSEFBQSxjQUFjLE9BQUE7QUFDdkIsd0NBQXdEO0FBQS9DLGtHQUFBLFFBQVEsT0FBQTtBQUFFLHVHQUFBLGFBQWEsT0FBQTtBQUNoQyxzREFBZ0U7QUFBdkQseUhBQUEsd0JBQXdCLE9BQUE7QUFDakMsK0JBQWdGO0FBQXZFLGtIQUFBLDBCQUEwQixPQUFBO0FBQUUsa0hBQUEsMEJBQTBCLE9BQUEifQ==
@@ -0,0 +1,18 @@
1
+ import { DataItem } from '../cbor/DataItem';
2
+ import IssuerAuth from './model/IssuerAuth';
3
+ export type IssuerSignedDataItem = DataItem<Map<keyof IssuerSignedItem, unknown>>;
4
+ export declare class IssuerSignedItem {
5
+ #private;
6
+ constructor(dataItem: IssuerSignedDataItem);
7
+ encode(): Uint8Array<ArrayBufferLike>;
8
+ get dataItem(): IssuerSignedDataItem;
9
+ private get decodedData();
10
+ get digestID(): number;
11
+ get random(): Uint8Array;
12
+ get elementIdentifier(): string;
13
+ get elementValue(): any;
14
+ calculateDigest(alg: Parameters<SubtleCrypto['digest']>[0]): Promise<ArrayBuffer>;
15
+ isValid(nameSpace: string, { decodedPayload: { valueDigests, digestAlgorithm }, }: IssuerAuth): Promise<boolean>;
16
+ matchCertificate(nameSpace: string, { countryName, stateOrProvince }: IssuerAuth): boolean | undefined;
17
+ static create(digestID: number, elementIdentifier: string, elementValue: any): IssuerSignedItem;
18
+ }
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _IssuerSignedItem_dataItem, _IssuerSignedItem_isValid;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.IssuerSignedItem = void 0;
16
+ const uncrypto_1 = require("uncrypto");
17
+ const cbor_1 = require("../cbor");
18
+ const DataItem_1 = require("../cbor/DataItem");
19
+ const buffer_utils_1 = require("../buffer_utils");
20
+ const utils_1 = require("./utils");
21
+ const MDL_NAMESPACE = 'org.iso.18013.5.1';
22
+ const supportedDigestAlgorithms = ['SHA-256', 'SHA-384', 'SHA-512'];
23
+ class IssuerSignedItem {
24
+ constructor(dataItem) {
25
+ _IssuerSignedItem_dataItem.set(this, void 0);
26
+ _IssuerSignedItem_isValid.set(this, void 0);
27
+ __classPrivateFieldSet(this, _IssuerSignedItem_dataItem, dataItem, "f");
28
+ }
29
+ encode() {
30
+ return __classPrivateFieldGet(this, _IssuerSignedItem_dataItem, "f").buffer;
31
+ }
32
+ get dataItem() {
33
+ return __classPrivateFieldGet(this, _IssuerSignedItem_dataItem, "f");
34
+ }
35
+ get decodedData() {
36
+ if (!__classPrivateFieldGet(this, _IssuerSignedItem_dataItem, "f").data.has('digestID')) {
37
+ throw new Error('Invalid data item');
38
+ }
39
+ return __classPrivateFieldGet(this, _IssuerSignedItem_dataItem, "f").data;
40
+ }
41
+ get digestID() {
42
+ return this.decodedData.get('digestID');
43
+ }
44
+ get random() {
45
+ return this.decodedData.get('random');
46
+ }
47
+ get elementIdentifier() {
48
+ return this.decodedData.get('elementIdentifier');
49
+ }
50
+ get elementValue() {
51
+ return this.decodedData.get('elementValue');
52
+ }
53
+ async calculateDigest(alg) {
54
+ const bytes = (0, cbor_1.cborEncode)(__classPrivateFieldGet(this, _IssuerSignedItem_dataItem, "f"));
55
+ const result = await uncrypto_1.subtle.digest(alg, bytes);
56
+ return result;
57
+ }
58
+ async isValid(nameSpace, { decodedPayload: { valueDigests, digestAlgorithm }, }) {
59
+ if (typeof __classPrivateFieldGet(this, _IssuerSignedItem_isValid, "f") !== 'undefined') {
60
+ return __classPrivateFieldGet(this, _IssuerSignedItem_isValid, "f");
61
+ }
62
+ if (!supportedDigestAlgorithms.includes(digestAlgorithm)) {
63
+ __classPrivateFieldSet(this, _IssuerSignedItem_isValid, false, "f");
64
+ return false;
65
+ }
66
+ const digest = await this.calculateDigest(digestAlgorithm);
67
+ const digests = valueDigests.get(nameSpace);
68
+ if (typeof digests === 'undefined') {
69
+ return false;
70
+ }
71
+ const expectedDigest = digests.get(this.digestID);
72
+ __classPrivateFieldSet(this, _IssuerSignedItem_isValid, expectedDigest &&
73
+ (0, buffer_utils_1.areEqual)(new Uint8Array(digest), expectedDigest), "f");
74
+ return __classPrivateFieldGet(this, _IssuerSignedItem_isValid, "f");
75
+ }
76
+ matchCertificate(nameSpace, { countryName, stateOrProvince }) {
77
+ if (nameSpace !== MDL_NAMESPACE) {
78
+ return undefined;
79
+ }
80
+ if (this.elementIdentifier === 'issuing_country') {
81
+ return countryName === this.elementValue;
82
+ }
83
+ if (this.elementIdentifier === 'issuing_jurisdiction' && stateOrProvince) {
84
+ return stateOrProvince === this.elementValue;
85
+ }
86
+ return undefined;
87
+ }
88
+ static create(digestID, elementIdentifier, elementValue) {
89
+ const random = (0, utils_1.getRandomBytes)(32);
90
+ const dataItem = DataItem_1.DataItem.fromData(new Map([
91
+ ['digestID', digestID],
92
+ ['elementIdentifier', elementIdentifier],
93
+ ['elementValue', elementValue],
94
+ ['random', random],
95
+ ]));
96
+ return new IssuerSignedItem(dataItem);
97
+ }
98
+ }
99
+ exports.IssuerSignedItem = IssuerSignedItem;
100
+ _IssuerSignedItem_dataItem = new WeakMap(), _IssuerSignedItem_isValid = new WeakMap();
101
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSXNzdWVyU2lnbmVkSXRlbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9tZG9jL0lzc3VlclNpZ25lZEl0ZW0udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsdUNBQWtDO0FBQ2xDLGtDQUFxQztBQUNyQywrQ0FBNEM7QUFFNUMsa0RBQTJDO0FBQzNDLG1DQUF5QztBQUV6QyxNQUFNLGFBQWEsR0FBRyxtQkFBbUIsQ0FBQztBQUUxQyxNQUFNLHlCQUF5QixHQUFHLENBQUMsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQztBQUtwRSxNQUFhLGdCQUFnQjtJQUkzQixZQUNFLFFBQThCO1FBSnZCLDZDQUFnQztRQUN6Qyw0Q0FBOEI7UUFLNUIsdUJBQUEsSUFBSSw4QkFBYSxRQUFRLE1BQUEsQ0FBQztJQUM1QixDQUFDO0lBRU0sTUFBTTtRQUNYLE9BQU8sdUJBQUEsSUFBSSxrQ0FBVSxDQUFDLE1BQU0sQ0FBQztJQUMvQixDQUFDO0lBRUQsSUFBVyxRQUFRO1FBQ2pCLE9BQU8sdUJBQUEsSUFBSSxrQ0FBVSxDQUFDO0lBQ3hCLENBQUM7SUFFRCxJQUFZLFdBQVc7UUFDckIsSUFBSSxDQUFDLHVCQUFBLElBQUksa0NBQVUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDekMsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBQ3ZDLENBQUM7UUFDRCxPQUFPLHVCQUFBLElBQUksa0NBQVUsQ0FBQyxJQUFJLENBQUM7SUFDN0IsQ0FBQztJQUVELElBQVcsUUFBUTtRQUNqQixPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBVyxDQUFDO0lBQ3BELENBQUM7SUFFRCxJQUFXLE1BQU07UUFDZixPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBZSxDQUFDO0lBQ3RELENBQUM7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
@@ -0,0 +1,33 @@
1
+ import { Buffer } from 'buffer';
2
+ import { MDoc } from './model/MDoc';
3
+ import { DiagnosticInformation } from './model/types';
4
+ import { UserDefinedVerificationCallback } from './checkCallback';
5
+ export declare class Verifier {
6
+ readonly issuersRootCertificates: string[];
7
+ /**
8
+ *
9
+ * @param issuersRootCertificates The IACA root certificates list of the supported issuers.
10
+ */
11
+ constructor(issuersRootCertificates: string[]);
12
+ private verifyIssuerSignature;
13
+ private verifyDeviceSignature;
14
+ private verifyData;
15
+ /**
16
+ * Parse and validate a DeviceResponse as specified in ISO/IEC 18013-5 (Device Retrieval section).
17
+ *
18
+ * @param encodedDeviceResponse
19
+ * @param options.encodedSessionTranscript The CBOR encoded SessionTranscript.
20
+ * @param options.ephemeralReaderKey The private part of the ephemeral key used in the session where the DeviceResponse was obtained. This is only required if the DeviceResponse is using the MAC method for device authentication.
21
+ */
22
+ verify(encodedDeviceResponse: Uint8Array, options?: {
23
+ encodedSessionTranscript?: Uint8Array;
24
+ ephemeralReaderKey?: Uint8Array;
25
+ disableCertificateChainValidation?: boolean;
26
+ onCheck?: UserDefinedVerificationCallback;
27
+ }): Promise<MDoc>;
28
+ getDiagnosticInformation(encodedDeviceResponse: Buffer, options: {
29
+ encodedSessionTranscript?: Buffer;
30
+ ephemeralReaderKey?: Buffer;
31
+ disableCertificateChainValidation?: boolean;
32
+ }): Promise<DiagnosticInformation>;
33
+ }
@@ -0,0 +1,405 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Verifier = void 0;
7
+ const compare_versions_1 = require("compare-versions");
8
+ const x509_1 = require("@peculiar/x509");
9
+ const jose_1 = require("jose");
10
+ const buffer_1 = require("buffer");
11
+ const cose_kit_1 = require("cose-kit");
12
+ const uncrypto_1 = __importDefault(require("uncrypto"));
13
+ const utils_1 = require("./utils");
14
+ const checkCallback_1 = require("./checkCallback");
15
+ const parser_1 = require("./parser");
16
+ const DeviceSignedDocument_1 = require("./model/DeviceSignedDocument");
17
+ const MDL_NAMESPACE = 'org.iso.18013.5.1';
18
+ const DIGEST_ALGS = {
19
+ 'SHA-256': 'sha256',
20
+ 'SHA-384': 'sha384',
21
+ 'SHA-512': 'sha512',
22
+ };
23
+ class Verifier {
24
+ /**
25
+ *
26
+ * @param issuersRootCertificates The IACA root certificates list of the supported issuers.
27
+ */
28
+ constructor(issuersRootCertificates) {
29
+ this.issuersRootCertificates = issuersRootCertificates;
30
+ }
31
+ async verifyIssuerSignature(issuerAuth, disableCertificateChainValidation, onCheckG) {
32
+ const onCheck = (0, checkCallback_1.onCatCheck)(onCheckG, 'ISSUER_AUTH');
33
+ const { certificate, countryName } = issuerAuth;
34
+ const verificationKey = certificate ? (await (0, jose_1.importX509)(certificate.toString(), issuerAuth.algName)) : undefined;
35
+ if (!disableCertificateChainValidation) {
36
+ try {
37
+ await issuerAuth.verifyX509Chain(this.issuersRootCertificates);
38
+ onCheck({
39
+ status: 'PASSED',
40
+ check: 'Issuer certificate must be valid',
41
+ id: checkCallback_1.VerificationAssessmentId.ISSUER_AUTH.IssuerCertificateValidity,
42
+ });
43
+ }
44
+ catch (err) {
45
+ onCheck({
46
+ status: 'FAILED',
47
+ check: 'Issuer certificate must be valid',
48
+ id: checkCallback_1.VerificationAssessmentId.ISSUER_AUTH.IssuerCertificateValidity,
49
+ reason: err.message,
50
+ });
51
+ }
52
+ }
53
+ const verificationResult = verificationKey && await issuerAuth.verify(verificationKey);
54
+ onCheck({
55
+ status: verificationResult ? 'PASSED' : 'FAILED',
56
+ check: 'Issuer signature must be valid',
57
+ id: checkCallback_1.VerificationAssessmentId.ISSUER_AUTH.IssuerSignatureValidity,
58
+ });
59
+ // Validity
60
+ const { validityInfo } = issuerAuth.decodedPayload;
61
+ const now = new Date();
62
+ onCheck({
63
+ status: certificate && validityInfo && (validityInfo.signed < certificate.notBefore || validityInfo.signed > certificate.notAfter) ? 'FAILED' : 'PASSED',
64
+ check: 'The MSO signed date must be within the validity period of the certificate',
65
+ id: checkCallback_1.VerificationAssessmentId.ISSUER_AUTH.MsoSignedDateWithinCertificateValidity,
66
+ reason: `The MSO signed date (${validityInfo.signed.toUTCString()}) must be within the validity period of the certificate (${certificate.notBefore.toUTCString()} to ${certificate.notAfter.toUTCString()})`,
67
+ });
68
+ onCheck({
69
+ status: validityInfo && (now < validityInfo.validFrom || now > validityInfo.validUntil) ? 'FAILED' : 'PASSED',
70
+ check: 'The MSO must be valid at the time of verification',
71
+ id: checkCallback_1.VerificationAssessmentId.ISSUER_AUTH.MsoValidityAtVerificationTime,
72
+ reason: `The MSO must be valid at the time of verification (${now.toUTCString()})`,
73
+ });
74
+ onCheck({
75
+ status: countryName ? 'PASSED' : 'FAILED',
76
+ check: 'Country name (C) must be present in the issuer certificate\'s subject distinguished name',
77
+ id: checkCallback_1.VerificationAssessmentId.ISSUER_AUTH.IssuerSubjectCountryNamePresence,
78
+ });
79
+ }
80
+ async verifyDeviceSignature(document, options) {
81
+ const onCheck = (0, checkCallback_1.onCatCheck)(options.onCheck, 'DEVICE_AUTH');
82
+ if (!(document instanceof DeviceSignedDocument_1.DeviceSignedDocument)) {
83
+ onCheck({
84
+ status: 'FAILED',
85
+ check: 'The document is not signed by the device.',
86
+ id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DocumentDeviceSignaturePresence,
87
+ });
88
+ return;
89
+ }
90
+ const { deviceAuth, nameSpaces } = document.deviceSigned;
91
+ const { docType } = document;
92
+ const { deviceKeyInfo } = document.issuerSigned.issuerAuth.decodedPayload;
93
+ const { deviceKey: deviceKeyCoseKey } = deviceKeyInfo || {};
94
+ // Prevent cloning of the mdoc and mitigate man in the middle attacks
95
+ if (!deviceAuth.deviceMac && !deviceAuth.deviceSignature) {
96
+ onCheck({
97
+ status: 'FAILED',
98
+ check: 'Device Auth must contain a deviceSignature or deviceMac element',
99
+ id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceAuthSignatureOrMacPresence,
100
+ });
101
+ return;
102
+ }
103
+ if (!options.sessionTranscriptBytes) {
104
+ onCheck({
105
+ status: 'FAILED',
106
+ check: 'Session Transcript Bytes missing from options, aborting device signature check',
107
+ id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.SessionTranscriptProvided,
108
+ });
109
+ return;
110
+ }
111
+ const deviceAuthenticationBytes = (0, utils_1.calculateDeviceAutenticationBytes)(options.sessionTranscriptBytes, docType, nameSpaces);
112
+ if (!deviceKeyCoseKey) {
113
+ onCheck({
114
+ status: 'FAILED',
115
+ check: 'Issuer signature must contain the device key.',
116
+ id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceKeyAvailableInIssuerAuth,
117
+ reason: 'Unable to verify deviceAuth signature: missing device key in issuerAuth',
118
+ });
119
+ return;
120
+ }
121
+ if (deviceAuth.deviceSignature) {
122
+ const deviceKey = await (0, cose_kit_1.importCOSEKey)(deviceKeyCoseKey);
123
+ // ECDSA/EdDSA authentication
124
+ try {
125
+ const ds = deviceAuth.deviceSignature;
126
+ const verificationResult = await new cose_kit_1.Sign1(ds.protectedHeaders, ds.unprotectedHeaders, deviceAuthenticationBytes, ds.signature).verify(deviceKey);
127
+ onCheck({
128
+ status: verificationResult ? 'PASSED' : 'FAILED',
129
+ check: 'Device signature must be valid',
130
+ id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceSignatureValidity,
131
+ });
132
+ }
133
+ catch (err) {
134
+ onCheck({
135
+ status: 'FAILED',
136
+ check: 'Device signature must be valid',
137
+ id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceSignatureValidity,
138
+ reason: `Unable to verify deviceAuth signature (ECDSA/EdDSA): ${err.message}`,
139
+ });
140
+ }
141
+ return;
142
+ }
143
+ // MAC authentication
144
+ onCheck({
145
+ status: deviceAuth.deviceMac ? 'PASSED' : 'FAILED',
146
+ check: 'Device MAC must be present when using MAC authentication',
147
+ id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceMacPresence,
148
+ });
149
+ if (!deviceAuth.deviceMac) {
150
+ return;
151
+ }
152
+ onCheck({
153
+ status: deviceAuth.deviceMac.hasSupportedAlg() ? 'PASSED' : 'FAILED',
154
+ check: 'Device MAC must use alg 5 (HMAC 256/256)',
155
+ id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceMacAlgorithmCorrectness,
156
+ });
157
+ if (!deviceAuth.deviceMac.hasSupportedAlg()) {
158
+ return;
159
+ }
160
+ onCheck({
161
+ status: options.ephemeralPrivateKey ? 'PASSED' : 'FAILED',
162
+ check: 'Ephemeral private key must be present when using MAC authentication',
163
+ id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.EphemeralKeyPresence,
164
+ });
165
+ if (!options.ephemeralPrivateKey) {
166
+ return;
167
+ }
168
+ try {
169
+ const ephemeralMacKey = await (0, utils_1.calculateEphemeralMacKey)(options.ephemeralPrivateKey, deviceKeyCoseKey, options.sessionTranscriptBytes);
170
+ const isValid = await deviceAuth.deviceMac.verify(ephemeralMacKey, undefined, deviceAuthenticationBytes);
171
+ onCheck({
172
+ status: isValid ? 'PASSED' : 'FAILED',
173
+ check: 'Device MAC must be valid',
174
+ id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceMacValidity,
175
+ });
176
+ }
177
+ catch (err) {
178
+ onCheck({
179
+ status: 'FAILED',
180
+ check: 'Device MAC must be valid',
181
+ id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceMacValidity,
182
+ reason: `Unable to verify deviceAuth MAC: ${err.message}`,
183
+ });
184
+ }
185
+ }
186
+ async verifyData(mdoc, onCheckG) {
187
+ // Confirm that the mdoc data has not changed since issuance
188
+ const { issuerAuth } = mdoc.issuerSigned;
189
+ const { valueDigests, digestAlgorithm } = issuerAuth.decodedPayload;
190
+ const onCheck = (0, checkCallback_1.onCatCheck)(onCheckG, 'DATA_INTEGRITY');
191
+ onCheck({
192
+ status: digestAlgorithm && DIGEST_ALGS[digestAlgorithm] ? 'PASSED' : 'FAILED',
193
+ check: 'Issuer Auth must include a supported digestAlgorithm element',
194
+ id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.IssuerAuthDigestAlgorithmSupported,
195
+ });
196
+ const nameSpaces = mdoc.issuerSigned.nameSpaces || {};
197
+ await Promise.all(Object.keys(nameSpaces).map(async (ns) => {
198
+ onCheck({
199
+ status: valueDigests.has(ns) ? 'PASSED' : 'FAILED',
200
+ check: `Issuer Auth must include digests for namespace: ${ns}`,
201
+ id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.IssuerAuthNamespaceDigestPresence,
202
+ });
203
+ const verifications = await Promise.all(nameSpaces[ns].map(async (ev) => {
204
+ const isValid = await ev.isValid(ns, issuerAuth);
205
+ return { ev, ns, isValid };
206
+ }));
207
+ verifications.filter((v) => v.isValid).forEach((v) => {
208
+ onCheck({
209
+ status: 'PASSED',
210
+ check: `The calculated digest for ${ns}/${v.ev.elementIdentifier} attribute must match the digest in the issuerAuth element`,
211
+ id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.AttributeDigestMatch,
212
+ });
213
+ });
214
+ verifications.filter((v) => !v.isValid).forEach((v) => {
215
+ onCheck({
216
+ status: 'FAILED',
217
+ check: `The calculated digest for ${ns}/${v.ev.elementIdentifier} attribute must match the digest in the issuerAuth element`,
218
+ id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.AttributeDigestMatch,
219
+ });
220
+ });
221
+ if (ns === MDL_NAMESPACE) {
222
+ const issuer = issuerAuth.certificate.issuerName;
223
+ if (!issuer) {
224
+ onCheck({
225
+ status: 'FAILED',
226
+ check: "The 'issuing_country' if present must match the 'countryName' in the subject field within the DS certificate",
227
+ id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.IssuingCountryMatchesCertificate,
228
+ reason: "The 'issuing_country' and 'issuing_jurisdiction' cannot be verified because the DS certificate was not provided",
229
+ });
230
+ }
231
+ else {
232
+ const invalidCountry = verifications.filter((v) => v.ns === ns && v.ev.elementIdentifier === 'issuing_country')
233
+ .find((v) => !v.isValid || !v.ev.matchCertificate(ns, issuerAuth));
234
+ onCheck({
235
+ status: invalidCountry ? 'FAILED' : 'PASSED',
236
+ check: "The 'issuing_country' if present must match the 'countryName' in the subject field within the DS certificate",
237
+ id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.IssuingCountryMatchesCertificate,
238
+ reason: invalidCountry ?
239
+ `The 'issuing_country' (${invalidCountry.ev.elementValue}) must match the 'countryName' (${issuerAuth.countryName}) in the subject field within the issuer certificate` :
240
+ undefined,
241
+ });
242
+ const invalidJurisdiction = verifications.filter((v) => v.ns === ns && v.ev.elementIdentifier === 'issuing_jurisdiction')
243
+ .find((v) => !v.isValid || (issuerAuth.stateOrProvince && !v.ev.matchCertificate(ns, issuerAuth)));
244
+ onCheck({
245
+ status: invalidJurisdiction ? 'FAILED' : 'PASSED',
246
+ check: "The 'issuing_jurisdiction' if present must match the 'stateOrProvinceName' in the subject field within the DS certificate",
247
+ id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.IssuingJurisdictionMatchesCertificate,
248
+ reason: invalidJurisdiction ?
249
+ `The 'issuing_jurisdiction' (${invalidJurisdiction.ev.elementValue}) must match the 'stateOrProvinceName' (${issuerAuth.stateOrProvince}) in the subject field within the issuer certificate` :
250
+ undefined,
251
+ });
252
+ }
253
+ }
254
+ }));
255
+ }
256
+ /**
257
+ * Parse and validate a DeviceResponse as specified in ISO/IEC 18013-5 (Device Retrieval section).
258
+ *
259
+ * @param encodedDeviceResponse
260
+ * @param options.encodedSessionTranscript The CBOR encoded SessionTranscript.
261
+ * @param options.ephemeralReaderKey The private part of the ephemeral key used in the session where the DeviceResponse was obtained. This is only required if the DeviceResponse is using the MAC method for device authentication.
262
+ */
263
+ async verify(encodedDeviceResponse, options = {}) {
264
+ const onCheck = (0, checkCallback_1.buildCallback)(options.onCheck);
265
+ const dr = (0, parser_1.parse)(encodedDeviceResponse);
266
+ onCheck({
267
+ status: dr.version ? 'PASSED' : 'FAILED',
268
+ check: 'Device Response must include "version" element.',
269
+ id: checkCallback_1.VerificationAssessmentId.DOCUMENT_FORMAT.DeviceResponseVersionPresence,
270
+ category: 'DOCUMENT_FORMAT',
271
+ });
272
+ onCheck({
273
+ status: (0, compare_versions_1.compareVersions)(dr.version, '1.0') >= 0 ? 'PASSED' : 'FAILED',
274
+ check: 'Device Response version must be 1.0 or greater',
275
+ id: checkCallback_1.VerificationAssessmentId.DOCUMENT_FORMAT.DeviceResponseVersionSupported,
276
+ category: 'DOCUMENT_FORMAT',
277
+ });
278
+ onCheck({
279
+ status: dr.documents && dr.documents.length > 0 ? 'PASSED' : 'FAILED',
280
+ check: 'Device Response must include at least one document.',
281
+ id: checkCallback_1.VerificationAssessmentId.DOCUMENT_FORMAT.DeviceResponseDocumentPresence,
282
+ category: 'DOCUMENT_FORMAT',
283
+ });
284
+ for (const document of dr.documents) {
285
+ const { issuerAuth } = document.issuerSigned;
286
+ await this.verifyIssuerSignature(issuerAuth, options.disableCertificateChainValidation, onCheck);
287
+ await this.verifyDeviceSignature(document, {
288
+ ephemeralPrivateKey: options.ephemeralReaderKey,
289
+ sessionTranscriptBytes: options.encodedSessionTranscript,
290
+ onCheck,
291
+ });
292
+ await this.verifyData(document, onCheck);
293
+ }
294
+ return dr;
295
+ }
296
+ async getDiagnosticInformation(encodedDeviceResponse, options) {
297
+ const dr = [];
298
+ const decoded = await this.verify(
299
+ // @ts-ignore
300
+ encodedDeviceResponse, {
301
+ ...options,
302
+ onCheck: (check) => dr.push(check),
303
+ });
304
+ const document = decoded.documents[0];
305
+ const { issuerAuth } = document.issuerSigned;
306
+ const issuerCert = issuerAuth.x5chain &&
307
+ issuerAuth.x5chain.length > 0 &&
308
+ new x509_1.X509Certificate(issuerAuth.x5chain[0]);
309
+ const attributes = (await Promise.all(Object.keys(document.issuerSigned.nameSpaces).map(async (ns) => {
310
+ const items = document.issuerSigned.nameSpaces[ns];
311
+ return Promise.all(items.map(async (item) => {
312
+ const isValid = await item.isValid(ns, issuerAuth);
313
+ return {
314
+ ns,
315
+ id: item.elementIdentifier,
316
+ value: item.elementValue,
317
+ isValid,
318
+ matchCertificate: item.matchCertificate(ns, issuerAuth),
319
+ };
320
+ }));
321
+ }))).flat();
322
+ const deviceAttributes = document instanceof DeviceSignedDocument_1.DeviceSignedDocument ?
323
+ Object.entries(document.deviceSigned.nameSpaces).map(([ns, items]) => {
324
+ return Object.entries(items).map(([id, value]) => {
325
+ return {
326
+ ns,
327
+ id,
328
+ value,
329
+ };
330
+ });
331
+ }).flat() : undefined;
332
+ let deviceKey;
333
+ if (document?.issuerSigned.issuerAuth) {
334
+ const { deviceKeyInfo } = document.issuerSigned.issuerAuth.decodedPayload;
335
+ if (deviceKeyInfo?.deviceKey) {
336
+ deviceKey = (0, cose_kit_1.COSEKeyToJWK)(deviceKeyInfo.deviceKey);
337
+ }
338
+ }
339
+ const disclosedAttributes = attributes.filter((attr) => attr.isValid).length;
340
+ const totalAttributes = Array.from(document
341
+ .issuerSigned
342
+ .issuerAuth
343
+ .decodedPayload
344
+ .valueDigests
345
+ .entries()).reduce((prev, [, digests]) => prev + digests.size, 0);
346
+ return {
347
+ general: {
348
+ version: decoded.version,
349
+ type: 'DeviceResponse',
350
+ status: decoded.status,
351
+ documents: decoded.documents.length,
352
+ },
353
+ validityInfo: document.issuerSigned.issuerAuth.decodedPayload.validityInfo,
354
+ issuerCertificate: issuerCert ? {
355
+ subjectName: issuerCert.subjectName.toString(),
356
+ pem: issuerCert.toString(),
357
+ notBefore: issuerCert.notBefore,
358
+ notAfter: issuerCert.notAfter,
359
+ serialNumber: issuerCert.serialNumber,
360
+ thumbprint: buffer_1.Buffer.from(await issuerCert.getThumbprint(uncrypto_1.default)).toString('hex'),
361
+ } : undefined,
362
+ issuerSignature: {
363
+ alg: document.issuerSigned.issuerAuth.algName,
364
+ isValid: dr
365
+ .filter((check) => check.category === 'ISSUER_AUTH')
366
+ .every((check) => check.status === 'PASSED'),
367
+ reasons: dr
368
+ .filter((check) => check.category === 'ISSUER_AUTH' && check.status === 'FAILED')
369
+ .map((check) => check.reason ?? check.check),
370
+ digests: Object.fromEntries(Array.from(document
371
+ .issuerSigned
372
+ .issuerAuth
373
+ .decodedPayload
374
+ .valueDigests
375
+ .entries()).map(([ns, digests]) => [ns, digests.size])),
376
+ },
377
+ deviceKey: {
378
+ jwk: deviceKey,
379
+ },
380
+ deviceSignature: document instanceof DeviceSignedDocument_1.DeviceSignedDocument ? {
381
+ alg: document.deviceSigned.deviceAuth.deviceSignature?.algName ??
382
+ document.deviceSigned.deviceAuth.deviceMac?.algName,
383
+ isValid: dr
384
+ .filter((check) => check.category === 'DEVICE_AUTH')
385
+ .every((check) => check.status === 'PASSED'),
386
+ reasons: dr
387
+ .filter((check) => check.category === 'DEVICE_AUTH' && check.status === 'FAILED')
388
+ .map((check) => check.reason ?? check.check),
389
+ } : undefined,
390
+ dataIntegrity: {
391
+ disclosedAttributes: `${disclosedAttributes} of ${totalAttributes}`,
392
+ isValid: dr
393
+ .filter((check) => check.category === 'DATA_INTEGRITY')
394
+ .every((check) => check.status === 'PASSED'),
395
+ reasons: dr
396
+ .filter((check) => check.category === 'DATA_INTEGRITY' && check.status === 'FAILED')
397
+ .map((check) => check.reason ?? check.check),
398
+ },
399
+ attributes,
400
+ deviceAttributes,
401
+ };
402
+ }
403
+ }
404
+ exports.Verifier = Verifier;
405
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVmVyaWZpZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbWRvYy9WZXJpZmllci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSx1REFBbUQ7QUFDbkQseUNBQWlEO0FBQ2pELCtCQUFnRDtBQUNoRCxtQ0FBZ0M7QUFDaEMsdUNBQThEO0FBQzlELHdEQUE4QjtBQUc5QixtQ0FHaUI7QUFLakIsbURBQStJO0FBRS9JLHFDQUFpQztBQUdqQyx1RUFBb0U7QUFFcEUsTUFBTSxhQUFhLEdBQUcsbUJBQW1CLENBQUM7QUFFMUMsTUFBTSxXQUFXLEdBQUc7SUFDbEIsU0FBUyxFQUFFLFFBQVE7SUFDbkIsU0FBUyxFQUFFLFFBQVE7SUFDbkIsU0FBUyxFQUFFLFFBQVE7Q0FDUyxDQUFDO0FBRS9CLE1BQWEsUUFBUTtJQUNuQjs7O09BR0c7SUFDSCxZQUE0Qix1QkFBaUM7UUFBakMsNEJBQXVCLEdBQXZCLHVCQUF1QixDQUFVO0lBQUksQ0FBQztJQUUxRCxLQUFLLENBQUMscUJBQXFCLENBQ2pDLFVBQXNCLEVBQ3RCLGlDQUEwQyxFQUMxQyxRQUF5QztRQUV6QyxNQUFNLE9BQU8sR0FBRyxJQUFBLDBCQUFVLEVBQUMsUUFBUSxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBQ3BELE1BQU0sRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFFLEdBQUcsVUFBVSxDQUFDO1FBQ2hELE1BQU0sZUFBZSxHQUF3QixXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxJQUFBLGlCQUFVLEVBQzFFLFdBQVcsQ0FBQyxRQUFRLEVBQUUsRUFDdEIsVUFBVSxDQUFDLE9BQU8sQ0FDbkIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFFZixJQUFJLENBQUMsaUNBQWlDLEVBQUUsQ0FBQztZQUN2QyxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxVQUFVLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO2dCQUMvRCxPQUFPLENBQUM7b0JBQ04sTUFBTSxFQUFFLFFBQVE7b0JBQ2hCLEtBQUssRUFBRSxrQ0FBa0M7b0JBQ3pDLEVBQUUsRUFBRSx3Q0FBd0IsQ0FBQyxXQUFXLENBQUMseUJBQXlCO2lCQUNuRSxDQUFDLENBQUM7WUFDTCxDQUFDO1lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztnQkFDYixPQUFPLENBQUM7b0JBQ04sTUFBTSxFQUFFLFFBQVE7b0JBQ2hCLEtBQUssRUFBRSxrQ0FBa0M7b0JBQ3pDLEVBQUUsRUFBRSx3Q0FBd0IsQ0FBQyxXQUFXLENBQUMseUJBQXlCO29CQUNsRSxNQUFNLEVBQUUsR0FBRyxDQUFDLE9BQU87aUJBQ3BCLENBQUMsQ0FBQztZQUNMLENBQUM7UUFDSCxDQUFDO1FBRUQsTUFBTSxrQkFBa0IsR0FBRyxlQUFlLElBQUksTUFBTSxVQUFVLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ3ZGLE9BQU8sQ0FBQztZQUNOLE1BQU0sRUFBRSxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRO1lBQ2hELEtBQUssRUFBRSxnQ0FBZ0M7WUFDdkMsRUFBRSxFQUFFLHdDQUF3QixDQUFDLFdBQVcsQ0FBQyx1QkFBdUI7U0FDakUsQ0FBQyxDQUFDO1FBRUgsV0FBVztRQUNYLE1BQU0sRUFBRSxZQUFZLEVBQUUsR0FBRyxVQUFVLENBQUMsY0FBYyxDQUFDO1FBQ25ELE1BQU0sR0FBRyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7UUFFdkIsT0FBTyxDQUFDO1lBQ04sTUFBTSxFQUFFLFdBQVcsSUFBSSxZQUFZLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxHQUFHLFdBQVcsQ0FBQyxTQUFTLElBQUksWUFBWSxDQUFDLE1BQU0sR0FBRyxXQUFXLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUTtZQUN4SixLQUFLLEVBQUUsMkVBQTJFO1lBQ2xGLEVBQUUsRUFBRSx3Q0FBd0IsQ0FBQyxXQUFXLENBQUMsc0NBQXNDO1lBQy9FLE1BQU0sRUFBRSx3QkFBd0IsWUFBWSxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsNERBQTRELFdBQVcsQ0FBQyxTQUFTLENBQUMsV0FBVyxFQUFFLE9BQU8sV0FBVyxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsR0FBRztTQUM3TSxDQUFDLENBQUM7UUFFSCxPQUFPLENBQUM7WUFDTixNQUFNLEVBQUUsWUFBWSxJQUFJLENBQUMsR0FBRyxHQUFHLFlBQVksQ0FBQyxTQUFTLElBQUksR0FBRyxHQUFHLFlBQVksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRO1lBQzdHLEtBQUssRUFBRSxtREFBbUQ7WUFDMUQsRUFBRSxFQUFFLHdDQUF3QixDQUFDLFdBQVcsQ0FBQyw2QkFBNkI7WUFDdEUsTUFBTSxFQUFFLHNEQUFzRCxHQUFHLENBQUMsV0FBVyxFQUFFLEdBQUc7U0FDbkYsQ0FBQyxDQUFDO1FBRUgsT0FBTyxDQUFDO1lBQ04sTUFBTSxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRO1lBQ3pDLEtBQUssRUFBRSwwRkFBMEY7WUFDakcsRUFBRSxFQUFFLHdDQUF3QixDQUFDLFdBQVcsQ0FBQyxnQ0FBZ0M7U0FDMUUsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVPLEtBQUssQ0FBQyxxQkFBcUIsQ0FDakMsUUFBcUQsRUFDckQsT0FJQztRQUVELE1BQU0sT0FBTyxHQUFHLElBQUEsMEJBQVUsRUFBQyxPQUFPLENBQUMsT0FBTyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBRTNELElBQUksQ0FBQyxDQUFDLFFBQVEsWUFBWSwyQ0FBb0IsQ0FBQyxFQUFFLENBQUM7WUFDaEQsT0FBTyxDQUFDO2dCQUNOLE1BQU0sRUFBRSxRQUFRO2dCQUNoQixLQUFLLEVBQUUsMkNBQTJDO2dCQUNsRCxFQUFFLEVBQUUsd0NBQXdCLENBQUMsV0FBVyxDQUFDLCtCQUErQjthQUN6RSxDQUFDLENBQUM7WUFDSCxPQUFPO1FBQ1QsQ0FBQztRQUNELE1BQU0sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLEdBQUcsUUFBUSxDQUFDLFlBQVksQ0FBQztRQUN6RCxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsUUFBUSxDQUFDO1FBQzdCLE1BQU0sRUFBRSxhQUFhLEVBQUUsR0FBRyxRQUFRLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxjQUFjLENBQUM7UUFDMUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLGFBQWEsSUFBSSxFQUFFLENBQUM7UUFFNUQscUVBQXFFO1FBQ3JFLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxJQUFJLENBQUMsVUFBVSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQ3pELE9BQU8sQ0FBQztnQkFDTixNQUFNLEVBQUUsUUFBUTtnQkFDaEIsS0FBSyxFQUFFLGlFQUFpRTtnQkFDeEUsRUFBRSxFQUFFLHdDQUF3QixDQUFDLFdBQVcsQ0FBQyxnQ0FBZ0M7YUFDMUUsQ0FBQyxDQUFDO1lBQ0gsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLHNCQUFzQixFQUFFLENBQUM7WUFDcEMsT0FBTyxDQUFDO2dCQUNOLE1BQU0sRUFBRSxRQUFRO2dCQUNoQixLQUFLLEVBQUUsZ0ZBQWdGO2dCQUN2RixFQUFFLEVBQUUsd0NBQXdCLENBQUMsV0FBVyxDQUFDLHlCQUF5QjthQUNuRSxDQUFDLENBQUM7WUFDSCxPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0seUJBQXlCLEdBQUcsSUFBQSx5Q0FBaUMsRUFDakUsT0FBTyxDQUFDLHNCQUFzQixFQUM5QixPQUFPLEVBQ1AsVUFBVSxDQUNYLENBQUM7UUFFRixJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUN0QixPQUFPLENBQUM7Z0JBQ04sTUFBTSxFQUFFLFFBQVE7Z0JBQ2hCLEtBQUssRUFBRSwrQ0FBK0M7Z0JBQ3RELEVBQUUsRUFBRSx3Q0FBd0IsQ0FBQyxXQUFXLENBQUMsOEJBQThCO2dCQUN2RSxNQUFNLEVBQUUseUVBQXlFO2FBQ2xGLENBQUMsQ0FBQztZQUNILE9BQU87UUFDVCxDQUFDO1FBRUQsSUFBSSxVQUFVLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDL0IsTUFBTSxTQUFTLEdBQUcsTUFBTSxJQUFBLHdCQUFhLEVBQUMsZ0JBQWdCLENBQUMsQ0FBQztZQUV4RCw2QkFBNkI7WUFDN0IsSUFBSSxDQUFDO2dCQUNILE1BQU0sRUFBRSxHQUFHLFVBQVUsQ0FBQyxlQUFlLENBQUM7Z0JBRXRDLE1BQU0sa0JBQWtCLEdBQUcsTUFBTSxJQUFJLGdCQUFLLENBQ3hDLEVBQUUsQ0FBQyxnQkFBZ0IsRUFDbkIsRUFBRSxDQUFDLGtCQUFrQixFQUNyQix5QkFBeUIsRUFDekIsRUFBRSxDQUFDLFNBQVMsQ0FDYixDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFFcEIsT0FBTyxDQUFDO29CQUNOLE1BQU0sRUFBRSxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRO29CQUNoRCxLQUFLLEVBQUUsZ0NBQWdDO29CQUN2QyxFQUFFLEVBQUUsd0NBQXdCLENBQUMsV0FBVyxDQUFDLHVCQUF1QjtpQkFDakUsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7Z0JBQ2IsT0FBTyxDQUFDO29CQUNOLE1BQU0sRUFBRSxRQUFRO29CQUNoQixLQUFLLEVBQUUsZ0NBQWdDO29CQUN2QyxFQUFFLEVBQUUsd0NBQXdCLENBQUMsV0FBVyxDQUFDLHVCQUF1QjtvQkFDaEUsTUFBTSxFQUFFLHdEQUF3RCxHQUFHLENBQUMsT0FBTyxFQUFFO2lCQUM5RSxDQUFDLENBQUM7WUFDTCxDQUFDO1lBQ0QsT0FBTztRQUNULENBQUM7UUFFRCxxQkFBcUI7UUFDckIsT0FBTyxDQUFDO1lBQ04sTUFBTSxFQUFFLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUTtZQUNsRCxLQUFLLEVBQUUsMERBQTBEO1lBQ2pFLEVBQUUsRUFBRSx3Q0FBd0IsQ0FBQyxXQUFXLENBQUMsaUJBQWlCO1NBQzNELENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUFFLENBQUM7WUFBQyxPQUFPO1FBQUMsQ0FBQztRQUV0QyxPQUFPLENBQUM7WUFDTixNQUFNLEVBQUUsVUFBVSxDQUFDLFNBQVMsQ0FBQyxlQUFlLEVBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRO1lBQ3BFLEtBQUssRUFBRSwwQ0FBMEM7WUFDakQsRUFBRSxFQUFFLHdDQUF3QixDQUFDLFdBQVcsQ0FBQyw2QkFBNkI7U0FDdkUsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsZUFBZSxFQUFFLEVBQUUsQ0FBQztZQUFDLE9BQU87UUFBQyxDQUFDO1FBRXhELE9BQU8sQ0FBQztZQUNOLE1BQU0sRUFBRSxPQUFPLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUTtZQUN6RCxLQUFLLEVBQUUscUVBQXFFO1lBQzVFLEVBQUUsRUFBRSx3Q0FBd0IsQ0FBQyxXQUFXLENBQUMsb0JBQW9CO1NBQzlELENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxPQUFPLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUFDLE9BQU87UUFBQyxDQUFDO1FBRTdDLElBQUksQ0FBQztZQUNILE1BQU0sZUFBZSxHQUFHLE1BQU0sSUFBQSxnQ0FBd0IsRUFDcEQsT0FBTyxDQUFDLG1CQUFtQixFQUMzQixnQkFBZ0IsRUFDaEIsT0FBTyxDQUFDLHNCQUFzQixDQUMvQixDQUFDO1lBRUYsTUFBTSxPQUFPLEdBQUcsTUFBTSxVQUFVLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FDL0MsZUFBZSxFQUNmLFNBQVMsRUFDVCx5QkFBeUIsQ0FDMUIsQ0FBQztZQUVGLE9BQU8sQ0FBQztnQkFDTixNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVE7Z0JBQ3JDLEtBQUssRUFBRSwwQkFBMEI7Z0JBQ2pDLEVBQUUsRUFBRSx3Q0FBd0IsQ0FBQyxXQUFXLENBQUMsaUJBQWlCO2FBQzNELENBQUMsQ0FBQztRQUNMLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2IsT0FBTyxDQUFDO2dCQUNOLE1BQU0sRUFBRSxRQUFRO2dCQUNoQixLQUFLLEVBQUUsMEJBQTBCO2dCQUNqQyxFQUFFLEVBQUUsd0NBQXdCLENBQUMsV0FBVyxDQUFDLGlCQUFpQjtnQkFDMUQsTUFBTSxFQUFFLG9DQUFvQyxHQUFHLENBQUMsT0FBTyxFQUFFO2FBQzFELENBQUMsQ0FBQztRQUNMLENBQUM7SUFDSCxDQUFDO0lBRU8sS0FBSyxDQUFDLFVBQVUsQ0FDdEIsSUFBMEIsRUFDMUIsUUFBeUM7UUFFekMsNERBQTREO1FBQzVELE1BQU0sRUFBRSxVQUFVLEVBQUUsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDO1FBQ3pDLE1BQU0sRUFBRSxZQUFZLEVBQUUsZUFBZSxFQUFFLEdBQUcsVUFBVSxDQUFDLGNBQWMsQ0FBQztRQUNwRSxNQUFNLE9BQU8sR0FBRyxJQUFBLDBCQUFVLEVBQUMsUUFBUSxFQUFFLGdCQUFnQixDQUFDLENBQUM7UUFFdkQsT0FBTyxDQUFDO1lBQ04sTUFBTSxFQUFFLGVBQWUsSUFBSSxXQUFXLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUTtZQUM3RSxLQUFLLEVBQUUsOERBQThEO1lBQ3JFLEVBQUUsRUFBRSx3Q0FBd0IsQ0FBQyxjQUFjLENBQUMsa0NBQWtDO1NBQy9FLENBQUMsQ0FBQztRQUVILE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQztRQUV0RCxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFO1lBQ3pELE9BQU8sQ0FBQztnQkFDTixNQUFNLEVBQUUsWUFBWSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRO2dCQUNsRCxLQUFLLEVBQUUsbURBQW1ELEVBQUUsRUFBRTtnQkFDOUQsRUFBRSxFQUFFLHdDQUF3QixDQUFDLGNBQWMsQ0FBQyxpQ0FBaUM7YUFDOUUsQ0FBQyxDQUFDO1lBRUgsTUFBTSxhQUFhLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFO2dCQUN0RSxNQUFNLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxDQUFDO2dCQUNqRCxPQUFPLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxPQUFPLEVBQUUsQ0FBQztZQUM3QixDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRUosYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO2dCQUNuRCxPQUFPLENBQUM7b0JBQ04sTUFBTSxFQUFFLFFBQVE7b0JBQ2hCLEtBQUssRUFBRSw2QkFBNkIsRUFBRSxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsaUJBQWlCLDREQUE0RDtvQkFDNUgsRUFBRSxFQUFFLHdDQUF3QixDQUFDLGNBQWMsQ0FBQyxvQkFBb0I7aUJBQ2pFLENBQUMsQ0FBQztZQUNMLENBQUMsQ0FBQyxDQUFDO1lBRUgsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7Z0JBQ3BELE9BQU8sQ0FBQztvQkFDTixNQUFNLEVBQUUsUUFBUTtvQkFDaEIsS0FBSyxFQUFFLDZCQUE2QixFQUFFLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxpQkFBaUIsNERBQTREO29CQUM1SCxFQUFFLEVBQUUsd0NBQXdCLENBQUMsY0FBYyxDQUFDLG9CQUFvQjtpQkFDakUsQ0FBQyxDQUFDO1lBQ0wsQ0FBQyxDQUFDLENBQUM7WUFFSCxJQUFJLEVBQUUsS0FBSyxhQUFhLEVBQUUsQ0FBQztnQkFDekIsTUFBTSxNQUFNLEdBQUcsVUFBVSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUM7Z0JBQ2pELElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztvQkFDWixPQUFPLENBQUM7d0JBQ04sTUFBTSxFQUFFLFFBQVE7d0JBQ2hCLEtBQUssRUFBRSw4R0FBOEc7d0JBQ3JILEVBQUUsRUFBRSx3Q0FBd0IsQ0FBQyxjQUFjLENBQUMsZ0NBQWdDO3dCQUM1RSxNQUFNLEVBQUUsaUhBQWlIO3FCQUMxSCxDQUFDLENBQUM7Z0JBQ0wsQ0FBQztxQkFBTSxDQUFDO29CQUNOLE1BQU0sY0FBYyxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsaUJBQWlCLEtBQUssaUJBQWlCLENBQUM7eUJBQzVHLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQztvQkFFckUsT0FBTyxDQUFDO3dCQUNOLE1BQU0sRUFBRSxjQUFjLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUTt3QkFDNUMsS0FBSyxFQUFFLDhHQUE4Rzt3QkFDckgsRUFBRSxFQUFFLHdDQUF3QixDQUFDLGNBQWMsQ0FBQyxnQ0FBZ0M7d0JBQzVFLE1BQU0sRUFBRSxjQUFjLENBQUMsQ0FBQzs0QkFDdEIsMEJBQTBCLGNBQWMsQ0FBQyxFQUFFLENBQUMsWUFBWSxtQ0FBbUMsVUFBVSxDQUFDLFdBQVcsc0RBQXNELENBQUMsQ0FBQzs0QkFDekssU0FBUztxQkFDWixDQUFDLENBQUM7b0JBRUgsTUFBTSxtQkFBbUIsR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDLGlCQUFpQixLQUFLLHNCQUFzQixDQUFDO3lCQUN0SCxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxlQUFlLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7b0JBRXJHLE9BQU8sQ0FBQzt3QkFDTixNQUFNLEVBQUUsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUTt3QkFDakQsS0FBSyxFQUFFLDJIQUEySDt3QkFDbEksRUFBRSxFQUFFLHdDQUF3QixDQUFDLGNBQWMsQ0FBQyxxQ0FBcUM7d0JBQ2pGLE1BQU0sRUFBRSxtQkFBbUIsQ0FBQyxDQUFDOzRCQUMzQiwrQkFBK0IsbUJBQW1CLENBQUMsRUFBRSxDQUFDLFlBQVksMkNBQTJDLFVBQVUsQ0FBQyxlQUFlLHNEQUFzRCxDQUFDLENBQUM7NEJBQy9MLFNBQVM7cUJBQ1osQ0FBQyxDQUFDO2dCQUNMLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNOLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxLQUFLLENBQUMsTUFBTSxDQUNWLHFCQUFpQyxFQUNqQyxVQUtJLEVBQUU7UUFFTixNQUFNLE9BQU8sR0FBRyxJQUFBLDZCQUFhLEVBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRS9DLE1BQU0sRUFBRSxHQUFHLElBQUEsY0FBSyxFQUFDLHFCQUFxQixDQUFDLENBQUM7UUFFeEMsT0FBTyxDQUFDO1lBQ04sTUFBTSxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUTtZQUN4QyxLQUFLLEVBQUUsaURBQWlEO1lBQ3hELEVBQUUsRUFBRSx3Q0FBd0IsQ0FBQyxlQUFlLENBQUMsNkJBQTZCO1lBQzFFLFFBQVEsRUFBRSxpQkFBaUI7U0FDNUIsQ0FBQyxDQUFDO1FBRUgsT0FBTyxDQUFDO1lBQ04sTUFBTSxFQUFFLElBQUEsa0NBQWUsRUFBQyxFQUFFLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRO1lBQ3JFLEtBQUssRUFBRSxnREFBZ0Q7WUFDdkQsRUFBRSxFQUFFLHdDQUF3QixDQUFDLGVBQWUsQ0FBQyw4QkFBOEI7WUFDM0UsUUFBUSxFQUFFLGlCQUFpQjtTQUM1QixDQUFDLENBQUM7UUFFSCxPQUFPLENBQUM7WUFDTixNQUFNLEVBQUUsRUFBRSxDQUFDLFNBQVMsSUFBSSxFQUFFLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUTtZQUNyRSxLQUFLLEVBQUUscURBQXFEO1lBQzVELEVBQUUsRUFBRSx3Q0FBd0IsQ0FBQyxlQUFlLENBQUMsOEJBQThCO1lBQzNFLFFBQVEsRUFBRSxpQkFBaUI7U0FDNUIsQ0FBQyxDQUFDO1FBRUgsS0FBSyxNQUFNLFFBQVEsSUFBSSxFQUFFLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDcEMsTUFBTSxFQUFFLFVBQVUsRUFBRSxHQUFHLFFBQVEsQ0FBQyxZQUFZLENBQUM7WUFDN0MsTUFBTSxJQUFJLENBQUMscUJBQXFCLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxpQ0FBaUMsRUFBRSxPQUFPLENBQUMsQ0FBQztZQUVqRyxNQUFNLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxRQUFRLEVBQUU7Z0JBQ3pDLG1CQUFtQixFQUFFLE9BQU8sQ0FBQyxrQkFBa0I7Z0JBQy9DLHNCQUFzQixFQUFFLE9BQU8sQ0FBQyx3QkFBd0I7Z0JBQ3hELE9BQU87YUFDUixDQUFDLENBQUM7WUFFSCxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzNDLENBQUM7UUFFRCxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFRCxLQUFLLENBQUMsd0JBQXdCLENBQzVCLHFCQUE2QixFQUM3QixPQUlDO1FBRUQsTUFBTSxFQUFFLEdBQTZCLEVBQUUsQ0FBQztRQUN4QyxNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxNQUFNO1FBQy9CLGFBQWE7UUFDYixxQkFBcUIsRUFDckI7WUFDRSxHQUFHLE9BQU87WUFDVixPQUFPLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDO1NBQ25DLENBQ0YsQ0FBQztRQUVGLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdEMsTUFBTSxFQUFFLFVBQVUsRUFBRSxHQUFHLFFBQVEsQ0FBQyxZQUFZLENBQUM7UUFDN0MsTUFBTSxVQUFVLEdBQUcsVUFBVSxDQUFDLE9BQU87WUFDbkMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQztZQUM3QixJQUFJLHNCQUFlLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRTdDLE1BQU0sVUFBVSxHQUFHLENBQUMsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFO1lBQ25HLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ25ELE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRTtnQkFDMUMsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsQ0FBQztnQkFDbkQsT0FBTztvQkFDTCxFQUFFO29CQUNGLEVBQUUsRUFBRSxJQUFJLENBQUMsaUJBQWlCO29CQUMxQixLQUFLLEVBQUUsSUFBSSxDQUFDLFlBQVk7b0JBQ3hCLE9BQU87b0JBQ1AsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUM7aUJBQ3hELENBQUM7WUFDSixDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ04sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO1FBRVosTUFBTSxnQkFBZ0IsR0FBRyxRQUFRLFlBQVksMkNBQW9CLENBQUMsQ0FBQztZQUNqRSxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLEVBQUUsRUFBRTtnQkFDbkUsT0FBTyxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxFQUFFLEVBQUU7b0JBQy9DLE9BQU87d0JBQ0wsRUFBRTt3QkFDRixFQUFFO3dCQUNGLEtBQUs7cUJBQ04sQ0FBQztnQkFDSixDQUFDLENBQUMsQ0FBQztZQUNMLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFFeEIsSUFBSSxTQUFjLENBQUM7UUFFbkIsSUFBSSxRQUFRLEVBQUUsWUFBWSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ3RDLE1BQU0sRUFBRSxhQUFhLEVBQUUsR0FBRyxRQUFRLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxjQUFjLENBQUM7WUFDMUUsSUFBSSxhQUFhLEVBQUUsU0FBUyxFQUFFLENBQUM7Z0JBQzdCLFNBQVMsR0FBRyxJQUFBLHVCQUFZLEVBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQ3BELENBQUM7UUFDSCxDQUFDO1FBQ0QsTUFBTSxtQkFBbUIsR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxDQUFDO1FBQzdFLE1BQU0sZUFBZSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQ2hDLFFBQVE7YUFDTCxZQUFZO2FBQ1osVUFBVTthQUNWLGNBQWM7YUFDZCxZQUFZO2FBQ1osT0FBTyxFQUFFLENBQ2IsQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLEdBQUcsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztRQUV4RCxPQUFPO1lBQ0wsT0FBTyxFQUFFO2dCQUNQLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTztnQkFDeEIsSUFBSSxFQUFFLGdCQUFnQjtnQkFDdEIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO2dCQUN0QixTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNO2FBQ3BDO1lBQ0QsWUFBWSxFQUFFLFFBQVEsQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLGNBQWMsQ0FBQyxZQUFZO1lBQzFFLGlCQUFpQixFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUM7Z0JBQzlCLFdBQVcsRUFBRSxVQUFVLENBQUMsV0FBVyxDQUFDLFFBQVEsRUFBRTtnQkFDOUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxRQUFRLEVBQUU7Z0JBQzFCLFNBQVMsRUFBRSxVQUFVLENBQUMsU0FBUztnQkFDL0IsUUFBUSxFQUFFLFVBQVUsQ0FBQyxRQUFRO2dCQUM3QixZQUFZLEVBQUUsVUFBVSxDQUFDLFlBQVk7Z0JBQ3JDLFVBQVUsRUFBRSxlQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sVUFBVSxDQUFDLGFBQWEsQ0FBQyxrQkFBTSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDO2FBQ2hGLENBQUMsQ0FBQyxDQUFDLFNBQVM7WUFDYixlQUFlLEVBQUU7Z0JBQ2YsR0FBRyxFQUFFLFFBQVEsQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLE9BQU87Z0JBQzdDLE9BQU8sRUFBRSxFQUFFO3FCQUNSLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLFFBQVEsS0FBSyxhQUFhLENBQUM7cUJBQ25ELEtBQUssQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE1BQU0sS0FBSyxRQUFRLENBQUM7Z0JBQzlDLE9BQU8sRUFBRSxFQUFFO3FCQUNSLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLFFBQVEsS0FBSyxhQUFhLElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxRQUFRLENBQUM7cUJBQ2hGLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE1BQU0sSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDO2dCQUM5QyxPQUFPLEVBQUUsTUFBTSxDQUFDLFdBQVcsQ0FDekIsS0FBSyxDQUFDLElBQUksQ0FDUixRQUFRO3FCQUNMLFlBQVk7cUJBQ1osVUFBVTtxQkFDVixjQUFjO3FCQUNkLFlBQVk7cUJBQ1osT0FBTyxFQUFFLENBQ2IsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQzdDO2FBQ0Y7WUFDRCxTQUFTLEVBQUU7Z0JBQ1QsR0FBRyxFQUFFLFNBQVM7YUFDZjtZQUNELGVBQWUsRUFBRSxRQUFRLFlBQVksMkNBQW9CLENBQUMsQ0FBQyxDQUFDO2dCQUMxRCxHQUFHLEVBQUUsUUFBUSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsZUFBZSxFQUFFLE9BQU87b0JBQzVELFFBQVEsQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxPQUFPO2dCQUNyRCxPQUFPLEVBQUUsRUFBRTtxQkFDUixNQUFNLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxRQUFRLEtBQUssYUFBYSxDQUFDO3FCQUNuRCxLQUFLLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxNQUFNLEtBQUssUUFBUSxDQUFDO2dCQUM5QyxPQUFPLEVBQUUsRUFBRTtxQkFDUixNQUFNLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxRQUFRLEtBQUssYUFBYSxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssUUFBUSxDQUFDO3FCQUNoRixHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxNQUFNLElBQUksS0FBSyxDQUFDLEtBQUssQ0FBQzthQUMvQyxDQUFDLENBQUMsQ0FBQyxTQUFTO1lBQ2IsYUFBYSxFQUFFO2dCQUNiLG1CQUFtQixFQUFFLEdBQUcsbUJBQW1CLE9BQU8sZUFBZSxFQUFFO2dCQUNuRSxPQUFPLEVBQUUsRUFBRTtxQkFDUixNQUFNLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxRQUFRLEtBQUssZ0JBQWdCLENBQUM7cUJBQ3RELEtBQUssQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE1BQU0sS0FBSyxRQUFRLENBQUM7Z0JBQzlDLE9BQU8sRUFBRSxFQUFFO3FCQUNSLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLFFBQVEsS0FBSyxnQkFBZ0IsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLFFBQVEsQ0FBQztxQkFDbkYsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQyxLQUFLLENBQUM7YUFDL0M7WUFDRCxVQUFVO1lBQ1YsZ0JBQWdCO1NBQ2pCLENBQUM7SUFDSixDQUFDO0NBQ0Y7QUEzZEQsNEJBMmRDIn0=