From 43e380e5c10a68be0f381a0dbdad71e13e55ada3 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 29 Mar 2026 19:04:24 +0700 Subject: [PATCH] 690329:1904 Fixing revision number Kimi K2.5 #01 --- ...119442391-1908b04cd11e739233ee8977de00dc57 | Bin 71038 -> 71015 bytes ...rvicespec_3ec95775e6a66568410dc80a476cb50b | 561 +++++++++++ ...espec_3ec95775e6a66568410dc80a476cb50b.map | 1 + ...ceservice_502139c633196704eef09d9c7ce64dc0 | 893 ++++++++++++++++++ ...rvice_502139c633196704eef09d9c7ce64dc0.map | 1 + ...ceservice_5585ce2f5626b5a93fd64e63909b087f | 893 ++++++++++++++++++ ...rvice_5585ce2f5626b5a93fd64e63909b087f.map | 1 + ...rvicespec_6e17e53289c744ad0b09ce4420c50e0e | 561 +++++++++++ ...espec_6e17e53289c744ad0b09ce4420c50e0e.map | 1 + ...ceservice_d8463801745469340085197633f7ae6b | 893 ++++++++++++++++++ ...rvice_d8463801745469340085197633f7ae6b.map | 1 + ...cac696b99-da39a3ee5e6b4b0d3255bfef95601890 | 2 +- .../correspondence.service.spec.ts | 292 ++++++ .../correspondence/correspondence.service.ts | 15 +- .../01-03-modules/01-03-02-correspondence.md | 8 +- 15 files changed, 4120 insertions(+), 3 deletions(-) create mode 100644 backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/3e/correspondenceservicespec_3ec95775e6a66568410dc80a476cb50b create mode 100644 backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/3e/correspondenceservicespec_3ec95775e6a66568410dc80a476cb50b.map create mode 100644 backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/50/correspondenceservice_502139c633196704eef09d9c7ce64dc0 create mode 100644 backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/50/correspondenceservice_502139c633196704eef09d9c7ce64dc0.map create mode 100644 backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/55/correspondenceservice_5585ce2f5626b5a93fd64e63909b087f create mode 100644 backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/55/correspondenceservice_5585ce2f5626b5a93fd64e63909b087f.map create mode 100644 backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/6e/correspondenceservicespec_6e17e53289c744ad0b09ce4420c50e0e create mode 100644 backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/6e/correspondenceservicespec_6e17e53289c744ad0b09ce4420c50e0e.map create mode 100644 backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/d8/correspondenceservice_d8463801745469340085197633f7ae6b create mode 100644 backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/d8/correspondenceservice_d8463801745469340085197633f7ae6b.map diff --git a/backend/src/.jest-cache/haste-map-60cab15b743c6776f41d29bcac696b99-0ca4a1d6e3dfec1d63b61b0119442391-1908b04cd11e739233ee8977de00dc57 b/backend/src/.jest-cache/haste-map-60cab15b743c6776f41d29bcac696b99-0ca4a1d6e3dfec1d63b61b0119442391-1908b04cd11e739233ee8977de00dc57 index 75295316a61870ba7f7c5a17c05338d7bb34d5be..cf5c0f131d48e7bb3b5139715fea3cfed677fe2a 100644 GIT binary patch delta 1219 zcmYjPeNfa@6y^SQUHC1FyRf_Ng0R3QnvRIAH8i5Irj;-#LPeG%N`jwIB4}udj^oE< zBa%mYDT6YhA|f-$O%`D#pfpJ(&~Ypk(G;*E4YV|Iv|Z7e-XCx7x%ZuW-aYR*3Tj<6T`6+I+jP%r_n7Iz0~P z6J6MgpBOq+IO?|$VHP9z4c|zvU^7+*RUtEY6O6&LVGB8d3d>TyACgAs54OWI>=@6n z9+vn_d6I;VPMKT6+LZxQR926f9tE*+`R7-^Hq*nsa=x|4O4jR0+&_W;7!yDUiB=-! z(;+CCtik1?p==!cl7iE1wS@R+Gg4j+fK&G64Utv_a_ij*El+!SK%!UB-e7V=wAww9 zY4;jFs8)4U`trG&efveX+D;X&%Vw^$Kay1AM|h~LehH5w{X`7;Y zR**!Ypjjqvey7rtY-mpnLBU*a_dxh;UL%FOGh8s&Ni_OtxO9GZxUwKFE}!4d|3}F? z3VRgFMmJo$Yk|aZm@e_PqA!Ry@7vSAJ2oA^9tG;0v0dhn_US}Zkab}MN1UJHI&|)90lvC|)xD_T?~>#(lLhmDsLWc>b{KbPLh zQMi4s=*@$v_j4ZoXSjs+JITnsZ9wv!MLg=SO+@1m+BXbG`{QYXD>C8xzDtPgH?jHd z-61IacNzK~Y^{D+Lm2re1ycu%s2P~U8y_W0n)$A;;QF7j2gk-ruscK9=gD3Ytr7(Y z2a(fly{J@@Z{bP0=*X6+MIml^Q6=K%$zqxp?GsK<@)yl23RagqYt=T=(Wjy~5|dPv zDdwojPn5}YQe05eVo~Akf|+Vcc1-rB2tv#aSzOZ4ZDAWqCj881QKX?H$4wuKCZY19 z4)+!$YV;H>Zun7+$o8cmN3oWcNW!Y66md^a%S4xfHb~Y<$SO69#|D?eRs+2+78%L( E9~s^CRR910 delta 1249 zcmYLIX-t$?6!m^HGJeBM`DTM*b4J91wICA}H#E4lkS%GTCo}_VnE{PMMrj85wwV%TG|?&R;;OFK?UMcBh}6ro4#M~o_o)|FZY~xy-NM4 zO6`u*vMTr+LY&semAXADoHm)T)0l|_vk5;KzQZL`CaxO)#Cwr%AXxDsW7GJ3Zk*g~;z*rKu8{xXtm*{B}98Idum*k(J$9{WmS z^VmZY7RS`FG5(?&mkYJ#fe6!u^B>MlSEskR(u2~a^ieTqQ82-dz3WZrk2j-uW-#_l zh(zy(Xp|(J#6E|HU5PVPXdNei-Vu!3^JGY6VQih(Cvm0Y1aVt(j0%IPRZen^LAVkT2E`H0-dRy9bZyZfXOflWIhP36 zrY9p~j5c&cN9|K$^B?q-_=TS+TRCIKu!J>{8ZjY=WY{m7*!IF?9rt8KOS~|%NJV3C zB`b_A*)wbHYVO;eCQ$;G3p+ROYFDY9 z9e0X&+n2c#T!}KLe7%kMrE-hJZF{$>cv-~|iQW(jhp$4x;dl)@s}>Tw53VJYSC2*h zbRBvp>Ul?HOaR!xt>ZE!wjG+G#(=w%5;5qGz&iH^av;@WhWE$;Z0wcM#0o}oI9A`+ z1}7E#p6h+Gv2J*M@&4QznvR=Ct;pdlxNgbVc+`c}S7n}3Tjrrqb7wkER z?h_3NYhRB0?H}QT_KkSIqY!P$R#et4!5a-x__*GOzJ@(m-%tQmeIajc^h)e(9Zz_@ z^<>t_b4cC)pOG23>nYY z%ILb-?|+_*@xENtUCQI_zNHfKZiI7b?>d#=9Wu)LKS58HjI}p(DCv{&Tz@_#`vo-z zB2Kv(BH`HWJWRd43cuV^P&43P(7-zc_0SNu`(&iJw5T0)^1UH#5H>$pi)(*x=DQD$ z6Gjg&#iGbwuFAA4pA?Vr*z>4@JvknTH?kB>^=> zh|h?ArMO+G6u#>iHF{P^bVel%GPwfEiX9r7XzZCY_#p7TK6}fs^h3;4b{yL%;#X4$2ah)ud z>d55j($j1bcMKFRN=>wYW?^}S)nhb}OM<;BTr5$@g!%%5NDHBTVxB_BpL~t{3Pq4Y kb7^* { + let service; + let numberingService; + let correspondenceRepo; + let revisionRepo; + let testingModule; + let _dataSource; + const createMockRepository = () => ({ + find: jest.fn(), + findOne: jest.fn(), + create: jest.fn(), + save: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + softDelete: jest.fn(), + createQueryBuilder: jest.fn(() => ({ + leftJoinAndSelect: jest.fn().mockReturnThis(), + where: jest.fn().mockReturnThis(), + andWhere: jest.fn().mockReturnThis(), + orderBy: jest.fn().mockReturnThis(), + skip: jest.fn().mockReturnThis(), + take: jest.fn().mockReturnThis(), + getOne: jest.fn().mockResolvedValue(null), + getMany: jest.fn().mockResolvedValue([]), + getManyAndCount: jest.fn().mockResolvedValue([[], 0]), + })), + }); + const mockDataSource = { + createQueryRunner: jest.fn(() => ({ + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn(), + save: jest.fn(), + findOne: jest.fn(), + }, + })), + getRepository: jest.fn(() => createMockRepository()), + manager: { + findOne: jest.fn(), + }, + }; + beforeEach(async () => { + testingModule = await testing_1.Test.createTestingModule({ + providers: [ + correspondence_service_1.CorrespondenceService, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_entity_1.Correspondence), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_revision_entity_1.CorrespondenceRevision), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_status_entity_1.CorrespondenceStatus), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_reference_entity_1.CorrespondenceReference), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_tag_entity_1.CorrespondenceTag), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(organization_entity_1.Organization), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_recipient_entity_1.CorrespondenceRecipient), + useValue: createMockRepository(), + }, + { + provide: document_numbering_service_1.DocumentNumberingService, + useValue: { + generateNextNumber: jest.fn(), + updateNumberForDraft: jest.fn(), + previewNextNumber: jest.fn(), + }, + }, + { + provide: json_schema_service_1.JsonSchemaService, + useValue: { validate: jest.fn() }, + }, + { + provide: workflow_engine_service_1.WorkflowEngineService, + useValue: { createInstance: jest.fn() }, + }, + { + provide: user_service_1.UserService, + useValue: { + findOne: jest.fn(), + getUserPermissions: jest.fn().mockResolvedValue([]), + }, + }, + { + provide: typeorm_2.DataSource, + useValue: mockDataSource, + }, + { + provide: search_service_1.SearchService, + useValue: { indexDocument: jest.fn() }, + }, + { + provide: file_storage_service_1.FileStorageService, + useValue: { commit: jest.fn().mockResolvedValue([]) }, + }, + { + provide: uuid_resolver_service_1.UuidResolverService, + useValue: { + resolveProjectId: jest.fn().mockResolvedValue(1), + resolveOrganizationId: jest.fn().mockResolvedValue(1), + }, + }, + { + provide: notification_service_1.NotificationService, + useValue: { send: jest.fn().mockResolvedValue(undefined) }, + }, + ], + }).compile(); + service = testingModule.get(correspondence_service_1.CorrespondenceService); + numberingService = testingModule.get(document_numbering_service_1.DocumentNumberingService); + correspondenceRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_entity_1.Correspondence)); + revisionRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_revision_entity_1.CorrespondenceRevision)); + _dataSource = testingModule.get(typeorm_2.DataSource); + }); + it('should be defined', () => { + expect(service).toBeDefined(); + }); + describe('update', () => { + it('should NOT regenerate number if critical fields unchanged', async () => { + const mockUser = { id: 1, primaryOrganizationId: 10 }; + const mockRevision = { + id: 100, + correspondenceId: 1, + isCurrent: true, + statusId: 5, + }; + jest + .spyOn(revisionRepo, 'findOne') + .mockResolvedValue(mockRevision); + const mockCorr = { + id: 1, + projectId: 1, + correspondenceTypeId: 2, + disciplineId: 3, + originatorId: 10, + correspondenceNumber: 'OLD-NUM', + recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }], + }; + jest + .spyOn(correspondenceRepo, 'findOne') + .mockResolvedValue(mockCorr); + const updateDto = { + projectId: 1, + disciplineId: 3, + }; + await service.update(1, updateDto, mockUser); + expect(numberingService.updateNumberForDraft).not.toHaveBeenCalled(); + }); + it('should regenerate number if Project ID changes', async () => { + const mockUser = { id: 1, primaryOrganizationId: 10 }; + const mockRevision = { + id: 100, + correspondenceId: 1, + isCurrent: true, + statusId: 5, + }; + jest + .spyOn(revisionRepo, 'findOne') + .mockResolvedValue(mockRevision); + const mockCorr = { + id: 1, + projectId: 1, + correspondenceTypeId: 2, + disciplineId: 3, + originatorId: 10, + correspondenceNumber: 'OLD-NUM', + recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }], + }; + jest + .spyOn(correspondenceRepo, 'findOne') + .mockResolvedValue(mockCorr); + const updateDto = { + projectId: 2, + }; + const uuidResolver = testingModule.get(uuid_resolver_service_1.UuidResolverService); + uuidResolver.resolveProjectId.mockResolvedValue(2); + await service.update(1, updateDto, mockUser); + expect(numberingService.updateNumberForDraft).toHaveBeenCalled(); + }); + it('should regenerate number if Document Type changes', async () => { + const mockUser = { id: 1, primaryOrganizationId: 10 }; + const mockRevision = { + id: 100, + correspondenceId: 1, + isCurrent: true, + statusId: 5, + }; + jest + .spyOn(revisionRepo, 'findOne') + .mockResolvedValue(mockRevision); + const mockCorr = { + id: 1, + projectId: 1, + correspondenceTypeId: 2, + disciplineId: 3, + originatorId: 10, + correspondenceNumber: 'OLD-NUM', + recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }], + }; + jest + .spyOn(correspondenceRepo, 'findOne') + .mockResolvedValue(mockCorr); + const updateDto = { + typeId: 999, + }; + const typeRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType)); + typeRepo.findOne.mockResolvedValue({ + id: 999, + typeCode: 'NEW-TYPE', + }); + await service.update(1, updateDto, mockUser); + expect(numberingService.updateNumberForDraft).toHaveBeenCalled(); + }); + it('should regenerate number if Recipient Organization changes', async () => { + const mockUser = { id: 1, primaryOrganizationId: 10 }; + const mockRevision = { + id: 100, + correspondenceId: 1, + isCurrent: true, + statusId: 5, + }; + jest + .spyOn(revisionRepo, 'findOne') + .mockResolvedValue(mockRevision); + const mockCorr = { + id: 1, + projectId: 1, + correspondenceTypeId: 2, + disciplineId: 3, + originatorId: 10, + correspondenceNumber: 'OLD-NUM', + recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }], + }; + jest + .spyOn(correspondenceRepo, 'findOne') + .mockResolvedValue(mockCorr); + // Access DataSource manager for mocking + mockDataSource.manager.findOne.mockResolvedValue({ + id: 88, + organizationCode: 'NEW-ORG', + }); + const updateDto = { + recipients: [{ type: 'TO', organizationId: 88 }], + }; + await service.update(1, updateDto, mockUser); + expect(numberingService.updateNumberForDraft).toHaveBeenCalled(); + }); + }); + describe('create', () => { + it('should allow system.manage_all user without primaryOrganizationId when originatorId is provided', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: null, + }; + const createDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + originatorId: 'originator-uuid', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + const userService = testingModule.get(user_service_1.UserService); + const typeRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType)); + const statusRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_status_entity_1.CorrespondenceStatus)); + const uuidResolver = testingModule.get(uuid_resolver_service_1.UuidResolverService); + userService.findOne.mockResolvedValue({ + user_id: 1, + primaryOrganizationId: null, + }); + userService.getUserPermissions.mockResolvedValue([ + 'system.manage_all', + ]); + uuidResolver.resolveProjectId.mockResolvedValue(100); + uuidResolver.resolveOrganizationId.mockImplementation((value) => { + if (value === 'originator-uuid') + return 10; + if (value === 'recipient-uuid') + return 20; + return 0; + }); + typeRepo.findOne.mockResolvedValue({ + id: 1, + typeCode: 'LTR', + }); + statusRepo.findOne.mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + numberingService.generateNextNumber.mockResolvedValue({ + number: 'DOC-001', + }); + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn((_entity, payload) => payload), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + mockDataSource.createQueryRunner.mockReturnValue(queryRunner); + await service.create(createDto, mockUser); + expect(queryRunner.manager.create).toHaveBeenCalledWith(correspondence_entity_1.Correspondence, expect.objectContaining({ originatorId: 10 })); + }); + it('should set revisionLabel to "A" for RFA type', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: 10, + }; + const createDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + const typeRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType)); + const statusRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_status_entity_1.CorrespondenceStatus)); + const uuidResolver = testingModule.get(uuid_resolver_service_1.UuidResolverService); + uuidResolver.resolveProjectId.mockResolvedValue(100); + uuidResolver.resolveOrganizationId.mockResolvedValue(20); + typeRepo.findOne.mockResolvedValue({ + id: 1, + typeCode: 'RFA', + }); + statusRepo.findOne.mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + numberingService.generateNextNumber.mockResolvedValue({ + number: 'DOC-001', + }); + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn((_entity, payload) => payload), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + mockDataSource.createQueryRunner.mockReturnValue(queryRunner); + await service.create(createDto, mockUser); + expect(queryRunner.manager.create).toHaveBeenCalledWith(correspondence_revision_entity_1.CorrespondenceRevision, expect.objectContaining({ revisionLabel: 'A' })); + }); + it('should set revisionLabel to "A" for RFI type', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: 10, + }; + const createDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + const typeRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType)); + const statusRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_status_entity_1.CorrespondenceStatus)); + const uuidResolver = testingModule.get(uuid_resolver_service_1.UuidResolverService); + uuidResolver.resolveProjectId.mockResolvedValue(100); + uuidResolver.resolveOrganizationId.mockResolvedValue(20); + typeRepo.findOne.mockResolvedValue({ + id: 1, + typeCode: 'RFI', + }); + statusRepo.findOne.mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + numberingService.generateNextNumber.mockResolvedValue({ + number: 'DOC-001', + }); + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn((_entity, payload) => payload), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + mockDataSource.createQueryRunner.mockReturnValue(queryRunner); + await service.create(createDto, mockUser); + expect(queryRunner.manager.create).toHaveBeenCalledWith(correspondence_revision_entity_1.CorrespondenceRevision, expect.objectContaining({ revisionLabel: 'A' })); + }); + it('should set revisionLabel to null for LETTER type', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: 10, + }; + const createDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + const typeRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType)); + const statusRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_status_entity_1.CorrespondenceStatus)); + const uuidResolver = testingModule.get(uuid_resolver_service_1.UuidResolverService); + uuidResolver.resolveProjectId.mockResolvedValue(100); + uuidResolver.resolveOrganizationId.mockResolvedValue(20); + typeRepo.findOne.mockResolvedValue({ + id: 1, + typeCode: 'LETTER', + }); + statusRepo.findOne.mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + numberingService.generateNextNumber.mockResolvedValue({ + number: 'DOC-001', + }); + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn((_entity, payload) => payload), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + mockDataSource.createQueryRunner.mockReturnValue(queryRunner); + await service.create(createDto, mockUser); + expect(queryRunner.manager.create).toHaveBeenCalledWith(correspondence_revision_entity_1.CorrespondenceRevision, expect.objectContaining({ revisionLabel: null })); + }); + it('should set revisionLabel to null for MEMO type', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: 10, + }; + const createDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + const typeRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType)); + const statusRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_status_entity_1.CorrespondenceStatus)); + const uuidResolver = testingModule.get(uuid_resolver_service_1.UuidResolverService); + uuidResolver.resolveProjectId.mockResolvedValue(100); + uuidResolver.resolveOrganizationId.mockResolvedValue(20); + typeRepo.findOne.mockResolvedValue({ + id: 1, + typeCode: 'MEMO', + }); + statusRepo.findOne.mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + numberingService.generateNextNumber.mockResolvedValue({ + number: 'DOC-001', + }); + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn((_entity, payload) => payload), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + mockDataSource.createQueryRunner.mockReturnValue(queryRunner); + await service.create(createDto, mockUser); + expect(queryRunner.manager.create).toHaveBeenCalledWith(correspondence_revision_entity_1.CorrespondenceRevision, expect.objectContaining({ revisionLabel: null })); + }); + }); +}); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoiRTpcXG5wLWRtc1xcbGNicDNcXGJhY2tlbmRcXHNyY1xcbW9kdWxlc1xcY29ycmVzcG9uZGVuY2VcXGNvcnJlc3BvbmRlbmNlLnNlcnZpY2Uuc3BlYy50cyIsIm1hcHBpbmdzIjoiOztBQUFBLDZDQUFzRDtBQUN0RCw2Q0FBcUQ7QUFDckQscUNBQWlEO0FBQ2pELHFFQUFpRTtBQUNqRSw0RUFBa0U7QUFDbEUsOEZBQW1GO0FBQ25GLHNGQUEyRTtBQUMzRSwwRkFBK0U7QUFDL0UsZ0dBQXFGO0FBQ3JGLG9GQUF5RTtBQUN6RSxzRkFBNEU7QUFDNUUsZ0dBQXFGO0FBQ3JGLDBHQUFxRztBQUNyRyw0RUFBdUU7QUFDdkUsd0ZBQW1GO0FBQ25GLHVEQUFtRDtBQUNuRCw2REFBeUQ7QUFDekQseUZBQW9GO0FBQ3BGLHVGQUFrRjtBQUNsRiwrRUFBMkU7QUFLM0UsUUFBUSxDQUFDLHVCQUF1QixFQUFFLEdBQUcsRUFBRTtJQUNyQyxJQUFJLE9BQThCLENBQUM7SUFDbkMsSUFBSSxnQkFBMEMsQ0FBQztJQUMvQyxJQUFJLGtCQUE4QyxDQUFDO0lBQ25ELElBQUksWUFBZ0QsQ0FBQztJQUNyRCxJQUFJLGFBQTRCLENBQUM7SUFDakMsSUFBSSxXQUF1QixDQUFDO0lBRTVCLE1BQU0sb0JBQW9CLEdBQUcsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUNsQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtRQUNmLE9BQU8sRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO1FBQ2xCLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO1FBQ2pCLElBQUksRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO1FBQ2YsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7UUFDakIsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7UUFDakIsVUFBVSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7UUFDckIsa0JBQWtCLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1lBQ2pDLGlCQUFpQixFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLEVBQUU7WUFDN0MsS0FBSyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLEVBQUU7WUFDakMsUUFBUSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLEVBQUU7WUFDcEMsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLEVBQUU7WUFDbkMsSUFBSSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLEVBQUU7WUFDaEMsSUFBSSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLEVBQUU7WUFDaEMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUM7WUFDekMsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLENBQUM7WUFDeEMsZUFBZSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztTQUN0RCxDQUFDLENBQUM7S0FDSixDQUFDLENBQUM7SUFFSCxNQUFNLGNBQWMsR0FBRztRQUNyQixpQkFBaUIsRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7WUFDaEMsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7WUFDbEIsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtZQUMzQixpQkFBaUIsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO1lBQzVCLG1CQUFtQixFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7WUFDOUIsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7WUFDbEIsT0FBTyxFQUFFO2dCQUNQLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO2dCQUNqQixJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDZixPQUFPLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTthQUNuQjtTQUNGLENBQUMsQ0FBQztRQUNILGFBQWEsRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLG9CQUFvQixFQUFFLENBQUM7UUFDcEQsT0FBTyxFQUFFO1lBQ1AsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7U0FDbkI7S0FDRixDQUFDO0lBRUYsVUFBVSxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQ3BCLGFBQWEsR0FBRyxNQUFNLGNBQUksQ0FBQyxtQkFBbUIsQ0FBQztZQUM3QyxTQUFTLEVBQUU7Z0JBQ1QsOENBQXFCO2dCQUNyQjtvQkFDRSxPQUFPLEVBQUUsSUFBQSw0QkFBa0IsRUFBQyxzQ0FBYyxDQUFDO29CQUMzQyxRQUFRLEVBQUUsb0JBQW9CLEVBQUU7aUJBQ2pDO2dCQUNEO29CQUNFLE9BQU8sRUFBRSxJQUFBLDRCQUFrQixFQUFDLHVEQUFzQixDQUFDO29CQUNuRCxRQUFRLEVBQUUsb0JBQW9CLEVBQUU7aUJBQ2pDO2dCQUNEO29CQUNFLE9BQU8sRUFBRSxJQUFBLDRCQUFrQixFQUFDLCtDQUFrQixDQUFDO29CQUMvQyxRQUFRLEVBQUUsb0JBQW9CLEVBQUU7aUJBQ2pDO2dCQUNEO29CQUNFLE9BQU8sRUFBRSxJQUFBLDRCQUFrQixFQUFDLG1EQUFvQixDQUFDO29CQUNqRCxRQUFRLEVBQUUsb0JBQW9CLEVBQUU7aUJBQ2pDO2dCQUNEO29CQUNFLE9BQU8sRUFBRSxJQUFBLDRCQUFrQixFQUFDLHlEQUF1QixDQUFDO29CQUNwRCxRQUFRLEVBQUUsb0JBQW9CLEVBQUU7aUJBQ2pDO2dCQUNEO29CQUNFLE9BQU8sRUFBRSxJQUFBLDRCQUFrQixFQUFDLDZDQUFpQixDQUFDO29CQUM5QyxRQUFRLEVBQUUsb0JBQW9CLEVBQUU7aUJBQ2pDO2dCQUNEO29CQUNFLE9BQU8sRUFBRSxJQUFBLDRCQUFrQixFQUFDLGtDQUFZLENBQUM7b0JBQ3pDLFFBQVEsRUFBRSxvQkFBb0IsRUFBRTtpQkFDakM7Z0JBQ0Q7b0JBQ0UsT0FBTyxFQUFFLElBQUEsNEJBQWtCLEVBQUMseURBQXVCLENBQUM7b0JBQ3BELFFBQVEsRUFBRSxvQkFBb0IsRUFBRTtpQkFDakM7Z0JBQ0Q7b0JBQ0UsT0FBTyxFQUFFLHFEQUF3QjtvQkFDakMsUUFBUSxFQUFFO3dCQUNSLGtCQUFrQixFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7d0JBQzdCLG9CQUFvQixFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7d0JBQy9CLGlCQUFpQixFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7cUJBQzdCO2lCQUNGO2dCQUNEO29CQUNFLE9BQU8sRUFBRSx1Q0FBaUI7b0JBQzFCLFFBQVEsRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUU7aUJBQ2xDO2dCQUNEO29CQUNFLE9BQU8sRUFBRSwrQ0FBcUI7b0JBQzlCLFFBQVEsRUFBRSxFQUFFLGNBQWMsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUU7aUJBQ3hDO2dCQUNEO29CQUNFLE9BQU8sRUFBRSwwQkFBVztvQkFDcEIsUUFBUSxFQUFFO3dCQUNSLE9BQU8sRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO3dCQUNsQixrQkFBa0IsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDO3FCQUNwRDtpQkFDRjtnQkFDRDtvQkFDRSxPQUFPLEVBQUUsb0JBQVU7b0JBQ25CLFFBQVEsRUFBRSxjQUFjO2lCQUN6QjtnQkFDRDtvQkFDRSxPQUFPLEVBQUUsOEJBQWE7b0JBQ3RCLFFBQVEsRUFBRSxFQUFFLGFBQWEsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUU7aUJBQ3ZDO2dCQUNEO29CQUNFLE9BQU8sRUFBRSx5Q0FBa0I7b0JBQzNCLFFBQVEsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDLEVBQUU7aUJBQ3REO2dCQUNEO29CQUNFLE9BQU8sRUFBRSwyQ0FBbUI7b0JBQzVCLFFBQVEsRUFBRTt3QkFDUixnQkFBZ0IsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxDQUFDO3dCQUNoRCxxQkFBcUIsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxDQUFDO3FCQUN0RDtpQkFDRjtnQkFDRDtvQkFDRSxPQUFPLEVBQUUsMENBQW1CO29CQUM1QixRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxFQUFFO2lCQUMzRDthQUNGO1NBQ0YsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBRWIsT0FBTyxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQXdCLDhDQUFxQixDQUFDLENBQUM7UUFDMUUsZ0JBQWdCLEdBQUcsYUFBYSxDQUFDLEdBQUcsQ0FDbEMscURBQXdCLENBQ3pCLENBQUM7UUFDRixrQkFBa0IsR0FBRyxhQUFhLENBQUMsR0FBRyxDQUNwQyxJQUFBLDRCQUFrQixFQUFDLHNDQUFjLENBQUMsQ0FDbkMsQ0FBQztRQUNGLFlBQVksR0FBRyxhQUFhLENBQUMsR0FBRyxDQUM5QixJQUFBLDRCQUFrQixFQUFDLHVEQUFzQixDQUFDLENBQzNDLENBQUM7UUFDRixXQUFXLEdBQUcsYUFBYSxDQUFDLEdBQUcsQ0FBYSxvQkFBVSxDQUFDLENBQUM7SUFDMUQsQ0FBQyxDQUFDLENBQUM7SUFFSCxFQUFFLENBQUMsbUJBQW1CLEVBQUUsR0FBRyxFQUFFO1FBQzNCLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNoQyxDQUFDLENBQUMsQ0FBQztJQUVILFFBQVEsQ0FBQyxRQUFRLEVBQUUsR0FBRyxFQUFFO1FBQ3RCLEVBQUUsQ0FBQywyREFBMkQsRUFBRSxLQUFLLElBQUksRUFBRTtZQUN6RSxNQUFNLFFBQVEsR0FBRyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUscUJBQXFCLEVBQUUsRUFBRSxFQUFxQixDQUFDO1lBQ3pFLE1BQU0sWUFBWSxHQUFHO2dCQUNuQixFQUFFLEVBQUUsR0FBRztnQkFDUCxnQkFBZ0IsRUFBRSxDQUFDO2dCQUNuQixTQUFTLEVBQUUsSUFBSTtnQkFDZixRQUFRLEVBQUUsQ0FBQzthQUNaLENBQUM7WUFFRixJQUFJO2lCQUNELEtBQUssQ0FBQyxZQUFZLEVBQUUsU0FBUyxDQUFDO2lCQUM5QixpQkFBaUIsQ0FBQyxZQUFpRCxDQUFDLENBQUM7WUFFeEUsTUFBTSxRQUFRLEdBQUc7Z0JBQ2YsRUFBRSxFQUFFLENBQUM7Z0JBQ0wsU0FBUyxFQUFFLENBQUM7Z0JBQ1osb0JBQW9CLEVBQUUsQ0FBQztnQkFDdkIsWUFBWSxFQUFFLENBQUM7Z0JBQ2YsWUFBWSxFQUFFLEVBQUU7Z0JBQ2hCLG9CQUFvQixFQUFFLFNBQVM7Z0JBQy9CLFVBQVUsRUFBRSxDQUFDLEVBQUUsYUFBYSxFQUFFLElBQUksRUFBRSx1QkFBdUIsRUFBRSxFQUFFLEVBQUUsQ0FBQzthQUNuRSxDQUFDO1lBQ0YsSUFBSTtpQkFDRCxLQUFLLENBQUMsa0JBQWtCLEVBQUUsU0FBUyxDQUFDO2lCQUNwQyxpQkFBaUIsQ0FBQyxRQUFxQyxDQUFDLENBQUM7WUFFNUQsTUFBTSxTQUFTLEdBQTRCO2dCQUN6QyxTQUFTLEVBQUUsQ0FBQztnQkFDWixZQUFZLEVBQUUsQ0FBQzthQUNoQixDQUFDO1lBRUYsTUFBTSxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxTQUFTLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFFN0MsTUFBTSxDQUNKLGdCQUFnQixDQUFDLG9CQUFpQyxDQUNuRCxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQzNCLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLGdEQUFnRCxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQzlELE1BQU0sUUFBUSxHQUFHLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxxQkFBcUIsRUFBRSxFQUFFLEVBQXFCLENBQUM7WUFDekUsTUFBTSxZQUFZLEdBQUc7Z0JBQ25CLEVBQUUsRUFBRSxHQUFHO2dCQUNQLGdCQUFnQixFQUFFLENBQUM7Z0JBQ25CLFNBQVMsRUFBRSxJQUFJO2dCQUNmLFFBQVEsRUFBRSxDQUFDO2FBQ1osQ0FBQztZQUNGLElBQUk7aUJBQ0QsS0FBSyxDQUFDLFlBQVksRUFBRSxTQUFTLENBQUM7aUJBQzlCLGlCQUFpQixDQUFDLFlBQWlELENBQUMsQ0FBQztZQUV4RSxNQUFNLFFBQVEsR0FBRztnQkFDZixFQUFFLEVBQUUsQ0FBQztnQkFDTCxTQUFTLEVBQUUsQ0FBQztnQkFDWixvQkFBb0IsRUFBRSxDQUFDO2dCQUN2QixZQUFZLEVBQUUsQ0FBQztnQkFDZixZQUFZLEVBQUUsRUFBRTtnQkFDaEIsb0JBQW9CLEVBQUUsU0FBUztnQkFDL0IsVUFBVSxFQUFFLENBQUMsRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFFLHVCQUF1QixFQUFFLEVBQUUsRUFBRSxDQUFDO2FBQ25FLENBQUM7WUFDRixJQUFJO2lCQUNELEtBQUssQ0FBQyxrQkFBa0IsRUFBRSxTQUFTLENBQUM7aUJBQ3BDLGlCQUFpQixDQUFDLFFBQXFDLENBQUMsQ0FBQztZQUU1RCxNQUFNLFNBQVMsR0FBNEI7Z0JBQ3pDLFNBQVMsRUFBRSxDQUFDO2FBQ2IsQ0FBQztZQUVGLE1BQU0sWUFBWSxHQUNoQixhQUFhLENBQUMsR0FBRyxDQUFzQiwyQ0FBbUIsQ0FBQyxDQUFDO1lBQzdELFlBQVksQ0FBQyxnQkFBOEIsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUVsRSxNQUFNLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQztZQUU3QyxNQUFNLENBQ0osZ0JBQWdCLENBQUMsb0JBQWlDLENBQ25ELENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUN2QixDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyxtREFBbUQsRUFBRSxLQUFLLElBQUksRUFBRTtZQUNqRSxNQUFNLFFBQVEsR0FBRyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUscUJBQXFCLEVBQUUsRUFBRSxFQUFxQixDQUFDO1lBQ3pFLE1BQU0sWUFBWSxHQUFHO2dCQUNuQixFQUFFLEVBQUUsR0FBRztnQkFDUCxnQkFBZ0IsRUFBRSxDQUFDO2dCQUNuQixTQUFTLEVBQUUsSUFBSTtnQkFDZixRQUFRLEVBQUUsQ0FBQzthQUNaLENBQUM7WUFDRixJQUFJO2lCQUNELEtBQUssQ0FBQyxZQUFZLEVBQUUsU0FBUyxDQUFDO2lCQUM5QixpQkFBaUIsQ0FBQyxZQUFpRCxDQUFDLENBQUM7WUFFeEUsTUFBTSxRQUFRLEdBQUc7Z0JBQ2YsRUFBRSxFQUFFLENBQUM7Z0JBQ0wsU0FBUyxFQUFFLENBQUM7Z0JBQ1osb0JBQW9CLEVBQUUsQ0FBQztnQkFDdkIsWUFBWSxFQUFFLENBQUM7Z0JBQ2YsWUFBWSxFQUFFLEVBQUU7Z0JBQ2hCLG9CQUFvQixFQUFFLFNBQVM7Z0JBQy9CLFVBQVUsRUFBRSxDQUFDLEVBQUUsYUFBYSxFQUFFLElBQUksRUFBRSx1QkFBdUIsRUFBRSxFQUFFLEVBQUUsQ0FBQzthQUNuRSxDQUFDO1lBQ0YsSUFBSTtpQkFDRCxLQUFLLENBQUMsa0JBQWtCLEVBQUUsU0FBUyxDQUFDO2lCQUNwQyxpQkFBaUIsQ0FBQyxRQUFxQyxDQUFDLENBQUM7WUFFNUQsTUFBTSxTQUFTLEdBQTRCO2dCQUN6QyxNQUFNLEVBQUUsR0FBRzthQUNaLENBQUM7WUFFRixNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUMsR0FBRyxDQUNoQyxJQUFBLDRCQUFrQixFQUFDLCtDQUFrQixDQUFDLENBQ3ZDLENBQUM7WUFDRCxRQUFRLENBQUMsT0FBcUIsQ0FBQyxpQkFBaUIsQ0FBQztnQkFDaEQsRUFBRSxFQUFFLEdBQUc7Z0JBQ1AsUUFBUSxFQUFFLFVBQVU7YUFDckIsQ0FBQyxDQUFDO1lBRUgsTUFBTSxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxTQUFTLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFFN0MsTUFBTSxDQUNKLGdCQUFnQixDQUFDLG9CQUFpQyxDQUNuRCxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDdkIsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsNERBQTRELEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDMUUsTUFBTSxRQUFRLEdBQUcsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLHFCQUFxQixFQUFFLEVBQUUsRUFBcUIsQ0FBQztZQUN6RSxNQUFNLFlBQVksR0FBRztnQkFDbkIsRUFBRSxFQUFFLEdBQUc7Z0JBQ1AsZ0JBQWdCLEVBQUUsQ0FBQztnQkFDbkIsU0FBUyxFQUFFLElBQUk7Z0JBQ2YsUUFBUSxFQUFFLENBQUM7YUFDWixDQUFDO1lBQ0YsSUFBSTtpQkFDRCxLQUFLLENBQUMsWUFBWSxFQUFFLFNBQVMsQ0FBQztpQkFDOUIsaUJBQWlCLENBQUMsWUFBaUQsQ0FBQyxDQUFDO1lBRXhFLE1BQU0sUUFBUSxHQUFHO2dCQUNmLEVBQUUsRUFBRSxDQUFDO2dCQUNMLFNBQVMsRUFBRSxDQUFDO2dCQUNaLG9CQUFvQixFQUFFLENBQUM7Z0JBQ3ZCLFlBQVksRUFBRSxDQUFDO2dCQUNmLFlBQVksRUFBRSxFQUFFO2dCQUNoQixvQkFBb0IsRUFBRSxTQUFTO2dCQUMvQixVQUFVLEVBQUUsQ0FBQyxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsdUJBQXVCLEVBQUUsRUFBRSxFQUFFLENBQUM7YUFDbkUsQ0FBQztZQUNGLElBQUk7aUJBQ0QsS0FBSyxDQUFDLGtCQUFrQixFQUFFLFNBQVMsQ0FBQztpQkFDcEMsaUJBQWlCLENBQUMsUUFBcUMsQ0FBQyxDQUFDO1lBRTVELHdDQUF3QztZQUN4QyxjQUFjLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztnQkFDL0MsRUFBRSxFQUFFLEVBQUU7Z0JBQ04sZ0JBQWdCLEVBQUUsU0FBUzthQUNELENBQUMsQ0FBQztZQUU5QixNQUFNLFNBQVMsR0FBNEI7Z0JBQ3pDLFVBQVUsRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxjQUFjLEVBQUUsRUFBRSxFQUFFLENBQUM7YUFDakQsQ0FBQztZQUVGLE1BQU0sT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBRTdDLE1BQU0sQ0FDSixnQkFBZ0IsQ0FBQyxvQkFBaUMsQ0FDbkQsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3ZCLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFFSCxRQUFRLENBQUMsUUFBUSxFQUFFLEdBQUcsRUFBRTtRQUN0QixFQUFFLENBQUMsaUdBQWlHLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDL0csTUFBTSxRQUFRLEdBQUc7Z0JBQ2YsT0FBTyxFQUFFLENBQUM7Z0JBQ1YscUJBQXFCLEVBQUUsSUFBSTthQUNULENBQUM7WUFFckIsTUFBTSxTQUFTLEdBQTRCO2dCQUN6QyxTQUFTLEVBQUUsY0FBYztnQkFDekIsTUFBTSxFQUFFLENBQUM7Z0JBQ1QsT0FBTyxFQUFFLGNBQWM7Z0JBQ3ZCLFlBQVksRUFBRSxpQkFBaUI7Z0JBQy9CLFVBQVUsRUFBRSxDQUFDLEVBQUUsY0FBYyxFQUFFLGdCQUFnQixFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQzthQUMvRCxDQUFDO1lBRUYsTUFBTSxXQUFXLEdBQUcsYUFBYSxDQUFDLEdBQUcsQ0FBYywwQkFBVyxDQUFDLENBQUM7WUFDaEUsTUFBTSxRQUFRLEdBQUcsYUFBYSxDQUFDLEdBQUcsQ0FDaEMsSUFBQSw0QkFBa0IsRUFBQywrQ0FBa0IsQ0FBQyxDQUN2QyxDQUFDO1lBQ0YsTUFBTSxVQUFVLEdBQUcsYUFBYSxDQUFDLEdBQUcsQ0FDbEMsSUFBQSw0QkFBa0IsRUFBQyxtREFBb0IsQ0FBQyxDQUN6QyxDQUFDO1lBQ0YsTUFBTSxZQUFZLEdBQ2hCLGFBQWEsQ0FBQyxHQUFHLENBQXNCLDJDQUFtQixDQUFDLENBQUM7WUFFN0QsV0FBVyxDQUFDLE9BQXFCLENBQUMsaUJBQWlCLENBQUM7Z0JBQ25ELE9BQU8sRUFBRSxDQUFDO2dCQUNWLHFCQUFxQixFQUFFLElBQUk7YUFDNUIsQ0FBQyxDQUFDO1lBQ0YsV0FBVyxDQUFDLGtCQUFnQyxDQUFDLGlCQUFpQixDQUFDO2dCQUM5RCxtQkFBbUI7YUFDcEIsQ0FBQyxDQUFDO1lBRUYsWUFBWSxDQUFDLGdCQUE4QixDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ25FLFlBQVksQ0FBQyxxQkFBbUMsQ0FBQyxrQkFBa0IsQ0FDbEUsQ0FBQyxLQUFzQixFQUFFLEVBQUU7Z0JBQ3pCLElBQUksS0FBSyxLQUFLLGlCQUFpQjtvQkFBRSxPQUFPLEVBQUUsQ0FBQztnQkFDM0MsSUFBSSxLQUFLLEtBQUssZ0JBQWdCO29CQUFFLE9BQU8sRUFBRSxDQUFDO2dCQUMxQyxPQUFPLENBQUMsQ0FBQztZQUNYLENBQUMsQ0FDRixDQUFDO1lBRUQsUUFBUSxDQUFDLE9BQXFCLENBQUMsaUJBQWlCLENBQUM7Z0JBQ2hELEVBQUUsRUFBRSxDQUFDO2dCQUNMLFFBQVEsRUFBRSxLQUFLO2FBQ2hCLENBQUMsQ0FBQztZQUNGLFVBQVUsQ0FBQyxPQUFxQixDQUFDLGlCQUFpQixDQUFDO2dCQUNsRCxFQUFFLEVBQUUsQ0FBQztnQkFDTCxVQUFVLEVBQUUsT0FBTzthQUNwQixDQUFDLENBQUM7WUFFRixnQkFBZ0IsQ0FBQyxrQkFBZ0MsQ0FBQyxpQkFBaUIsQ0FBQztnQkFDbkUsTUFBTSxFQUFFLFNBQVM7YUFDbEIsQ0FBQyxDQUFDO1lBRUgsY0FBYyxDQUFDLE9BQU8sQ0FBQyxPQUFPO2lCQUMzQixxQkFBcUIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLENBQUM7aUJBQzFELHFCQUFxQixDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxnQkFBZ0IsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBRTlELE1BQU0sV0FBVyxHQUFHO2dCQUNsQixPQUFPLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDbEIsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDM0IsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDNUIsbUJBQW1CLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDOUIsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7Z0JBQ2xCLE9BQU8sRUFBRTtvQkFDUCxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FDYixDQUFDLE9BQWdCLEVBQUUsT0FBZ0MsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUNoRTtvQkFDRCxJQUFJLEVBQUUsSUFBSTt5QkFDUCxFQUFFLEVBQUU7eUJBQ0oscUJBQXFCLENBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsQ0FBQzt5QkFDekQscUJBQXFCLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUM7eUJBQ25DLHFCQUFxQixDQUFDLEVBQUUsQ0FBQztvQkFDNUIsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7aUJBQ25CO2FBQ0YsQ0FBQztZQUVELGNBQWMsQ0FBQyxpQkFBK0IsQ0FBQyxlQUFlLENBQzdELFdBQVcsQ0FDWixDQUFDO1lBRUYsTUFBTSxPQUFPLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQztZQUUxQyxNQUFNLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxvQkFBb0IsQ0FDckQsc0NBQWMsRUFDZCxNQUFNLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxZQUFZLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FDOUMsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLDhDQUE4QyxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQzVELE1BQU0sUUFBUSxHQUFHO2dCQUNmLE9BQU8sRUFBRSxDQUFDO2dCQUNWLHFCQUFxQixFQUFFLEVBQUU7YUFDUCxDQUFDO1lBRXJCLE1BQU0sU0FBUyxHQUE0QjtnQkFDekMsU0FBUyxFQUFFLGNBQWM7Z0JBQ3pCLE1BQU0sRUFBRSxDQUFDO2dCQUNULE9BQU8sRUFBRSxjQUFjO2dCQUN2QixVQUFVLEVBQUUsQ0FBQyxFQUFFLGNBQWMsRUFBRSxnQkFBZ0IsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUM7YUFDL0QsQ0FBQztZQUVGLE1BQU0sUUFBUSxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQ2hDLElBQUEsNEJBQWtCLEVBQUMsK0NBQWtCLENBQUMsQ0FDdkMsQ0FBQztZQUNGLE1BQU0sVUFBVSxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQ2xDLElBQUEsNEJBQWtCLEVBQUMsbURBQW9CLENBQUMsQ0FDekMsQ0FBQztZQUNGLE1BQU0sWUFBWSxHQUNoQixhQUFhLENBQUMsR0FBRyxDQUFzQiwyQ0FBbUIsQ0FBQyxDQUFDO1lBRTdELFlBQVksQ0FBQyxnQkFBOEIsQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNuRSxZQUFZLENBQUMscUJBQW1DLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDLENBQUM7WUFFdkUsUUFBUSxDQUFDLE9BQXFCLENBQUMsaUJBQWlCLENBQUM7Z0JBQ2hELEVBQUUsRUFBRSxDQUFDO2dCQUNMLFFBQVEsRUFBRSxLQUFLO2FBQ2hCLENBQUMsQ0FBQztZQUNGLFVBQVUsQ0FBQyxPQUFxQixDQUFDLGlCQUFpQixDQUFDO2dCQUNsRCxFQUFFLEVBQUUsQ0FBQztnQkFDTCxVQUFVLEVBQUUsT0FBTzthQUNwQixDQUFDLENBQUM7WUFFRixnQkFBZ0IsQ0FBQyxrQkFBZ0MsQ0FBQyxpQkFBaUIsQ0FBQztnQkFDbkUsTUFBTSxFQUFFLFNBQVM7YUFDbEIsQ0FBQyxDQUFDO1lBRUgsY0FBYyxDQUFDLE9BQU8sQ0FBQyxPQUFPO2lCQUMzQixxQkFBcUIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLENBQUM7aUJBQzFELHFCQUFxQixDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxnQkFBZ0IsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBRTlELE1BQU0sV0FBVyxHQUFHO2dCQUNsQixPQUFPLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDbEIsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDM0IsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDNUIsbUJBQW1CLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDOUIsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7Z0JBQ2xCLE9BQU8sRUFBRTtvQkFDUCxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FDYixDQUFDLE9BQWdCLEVBQUUsT0FBZ0MsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUNoRTtvQkFDRCxJQUFJLEVBQUUsSUFBSTt5QkFDUCxFQUFFLEVBQUU7eUJBQ0oscUJBQXFCLENBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsQ0FBQzt5QkFDekQscUJBQXFCLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUM7eUJBQ25DLHFCQUFxQixDQUFDLEVBQUUsQ0FBQztvQkFDNUIsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7aUJBQ25CO2FBQ0YsQ0FBQztZQUVELGNBQWMsQ0FBQyxpQkFBK0IsQ0FBQyxlQUFlLENBQzdELFdBQVcsQ0FDWixDQUFDO1lBRUYsTUFBTSxPQUFPLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQztZQUUxQyxNQUFNLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxvQkFBb0IsQ0FDckQsdURBQXNCLEVBQ3RCLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLGFBQWEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUNoRCxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsOENBQThDLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDNUQsTUFBTSxRQUFRLEdBQUc7Z0JBQ2YsT0FBTyxFQUFFLENBQUM7Z0JBQ1YscUJBQXFCLEVBQUUsRUFBRTthQUNQLENBQUM7WUFFckIsTUFBTSxTQUFTLEdBQTRCO2dCQUN6QyxTQUFTLEVBQUUsY0FBYztnQkFDekIsTUFBTSxFQUFFLENBQUM7Z0JBQ1QsT0FBTyxFQUFFLGNBQWM7Z0JBQ3ZCLFVBQVUsRUFBRSxDQUFDLEVBQUUsY0FBYyxFQUFFLGdCQUFnQixFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQzthQUMvRCxDQUFDO1lBRUYsTUFBTSxRQUFRLEdBQUcsYUFBYSxDQUFDLEdBQUcsQ0FDaEMsSUFBQSw0QkFBa0IsRUFBQywrQ0FBa0IsQ0FBQyxDQUN2QyxDQUFDO1lBQ0YsTUFBTSxVQUFVLEdBQUcsYUFBYSxDQUFDLEdBQUcsQ0FDbEMsSUFBQSw0QkFBa0IsRUFBQyxtREFBb0IsQ0FBQyxDQUN6QyxDQUFDO1lBQ0YsTUFBTSxZQUFZLEdBQ2hCLGFBQWEsQ0FBQyxHQUFHLENBQXNCLDJDQUFtQixDQUFDLENBQUM7WUFFN0QsWUFBWSxDQUFDLGdCQUE4QixDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ25FLFlBQVksQ0FBQyxxQkFBbUMsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUV2RSxRQUFRLENBQUMsT0FBcUIsQ0FBQyxpQkFBaUIsQ0FBQztnQkFDaEQsRUFBRSxFQUFFLENBQUM7Z0JBQ0wsUUFBUSxFQUFFLEtBQUs7YUFDaEIsQ0FBQyxDQUFDO1lBQ0YsVUFBVSxDQUFDLE9BQXFCLENBQUMsaUJBQWlCLENBQUM7Z0JBQ2xELEVBQUUsRUFBRSxDQUFDO2dCQUNMLFVBQVUsRUFBRSxPQUFPO2FBQ3BCLENBQUMsQ0FBQztZQUVGLGdCQUFnQixDQUFDLGtCQUFnQyxDQUFDLGlCQUFpQixDQUFDO2dCQUNuRSxNQUFNLEVBQUUsU0FBUzthQUNsQixDQUFDLENBQUM7WUFFSCxjQUFjLENBQUMsT0FBTyxDQUFDLE9BQU87aUJBQzNCLHFCQUFxQixDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxnQkFBZ0IsRUFBRSxLQUFLLEVBQUUsQ0FBQztpQkFDMUQscUJBQXFCLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLGdCQUFnQixFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFFOUQsTUFBTSxXQUFXLEdBQUc7Z0JBQ2xCLE9BQU8sRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO2dCQUNsQixnQkFBZ0IsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO2dCQUMzQixpQkFBaUIsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO2dCQUM1QixtQkFBbUIsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO2dCQUM5QixPQUFPLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDbEIsT0FBTyxFQUFFO29CQUNQLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUNiLENBQUMsT0FBZ0IsRUFBRSxPQUFnQyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQ2hFO29CQUNELElBQUksRUFBRSxJQUFJO3lCQUNQLEVBQUUsRUFBRTt5QkFDSixxQkFBcUIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxDQUFDO3lCQUN6RCxxQkFBcUIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsQ0FBQzt5QkFDbkMscUJBQXFCLENBQUMsRUFBRSxDQUFDO29CQUM1QixPQUFPLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtpQkFDbkI7YUFDRixDQUFDO1lBRUQsY0FBYyxDQUFDLGlCQUErQixDQUFDLGVBQWUsQ0FDN0QsV0FBVyxDQUNaLENBQUM7WUFFRixNQUFNLE9BQU8sQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBRTFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLG9CQUFvQixDQUNyRCx1REFBc0IsRUFDdEIsTUFBTSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsYUFBYSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQ2hELENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyxrREFBa0QsRUFBRSxLQUFLLElBQUksRUFBRTtZQUNoRSxNQUFNLFFBQVEsR0FBRztnQkFDZixPQUFPLEVBQUUsQ0FBQztnQkFDVixxQkFBcUIsRUFBRSxFQUFFO2FBQ1AsQ0FBQztZQUVyQixNQUFNLFNBQVMsR0FBNEI7Z0JBQ3pDLFNBQVMsRUFBRSxjQUFjO2dCQUN6QixNQUFNLEVBQUUsQ0FBQztnQkFDVCxPQUFPLEVBQUUsY0FBYztnQkFDdkIsVUFBVSxFQUFFLENBQUMsRUFBRSxjQUFjLEVBQUUsZ0JBQWdCLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDO2FBQy9ELENBQUM7WUFFRixNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUMsR0FBRyxDQUNoQyxJQUFBLDRCQUFrQixFQUFDLCtDQUFrQixDQUFDLENBQ3ZDLENBQUM7WUFDRixNQUFNLFVBQVUsR0FBRyxhQUFhLENBQUMsR0FBRyxDQUNsQyxJQUFBLDRCQUFrQixFQUFDLG1EQUFvQixDQUFDLENBQ3pDLENBQUM7WUFDRixNQUFNLFlBQVksR0FDaEIsYUFBYSxDQUFDLEdBQUcsQ0FBc0IsMkNBQW1CLENBQUMsQ0FBQztZQUU3RCxZQUFZLENBQUMsZ0JBQThCLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDbkUsWUFBWSxDQUFDLHFCQUFtQyxDQUFDLGlCQUFpQixDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBRXZFLFFBQVEsQ0FBQyxPQUFxQixDQUFDLGlCQUFpQixDQUFDO2dCQUNoRCxFQUFFLEVBQUUsQ0FBQztnQkFDTCxRQUFRLEVBQUUsUUFBUTthQUNuQixDQUFDLENBQUM7WUFDRixVQUFVLENBQUMsT0FBcUIsQ0FBQyxpQkFBaUIsQ0FBQztnQkFDbEQsRUFBRSxFQUFFLENBQUM7Z0JBQ0wsVUFBVSxFQUFFLE9BQU87YUFDcEIsQ0FBQyxDQUFDO1lBRUYsZ0JBQWdCLENBQUMsa0JBQWdDLENBQUMsaUJBQWlCLENBQUM7Z0JBQ25FLE1BQU0sRUFBRSxTQUFTO2FBQ2xCLENBQUMsQ0FBQztZQUVILGNBQWMsQ0FBQyxPQUFPLENBQUMsT0FBTztpQkFDM0IscUJBQXFCLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLGdCQUFnQixFQUFFLEtBQUssRUFBRSxDQUFDO2lCQUMxRCxxQkFBcUIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUU5RCxNQUFNLFdBQVcsR0FBRztnQkFDbEIsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7Z0JBQ2xCLGdCQUFnQixFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7Z0JBQzNCLGlCQUFpQixFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7Z0JBQzVCLG1CQUFtQixFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7Z0JBQzlCLE9BQU8sRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO2dCQUNsQixPQUFPLEVBQUU7b0JBQ1AsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQ2IsQ0FBQyxPQUFnQixFQUFFLE9BQWdDLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FDaEU7b0JBQ0QsSUFBSSxFQUFFLElBQUk7eUJBQ1AsRUFBRSxFQUFFO3lCQUNKLHFCQUFxQixDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLENBQUM7eUJBQ3pELHFCQUFxQixDQUFDLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxDQUFDO3lCQUNuQyxxQkFBcUIsQ0FBQyxFQUFFLENBQUM7b0JBQzVCLE9BQU8sRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO2lCQUNuQjthQUNGLENBQUM7WUFFRCxjQUFjLENBQUMsaUJBQStCLENBQUMsZUFBZSxDQUM3RCxXQUFXLENBQ1osQ0FBQztZQUVGLE1BQU0sT0FBTyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFFMUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsb0JBQW9CLENBQ3JELHVEQUFzQixFQUN0QixNQUFNLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FDakQsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLGdEQUFnRCxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQzlELE1BQU0sUUFBUSxHQUFHO2dCQUNmLE9BQU8sRUFBRSxDQUFDO2dCQUNWLHFCQUFxQixFQUFFLEVBQUU7YUFDUCxDQUFDO1lBRXJCLE1BQU0sU0FBUyxHQUE0QjtnQkFDekMsU0FBUyxFQUFFLGNBQWM7Z0JBQ3pCLE1BQU0sRUFBRSxDQUFDO2dCQUNULE9BQU8sRUFBRSxjQUFjO2dCQUN2QixVQUFVLEVBQUUsQ0FBQyxFQUFFLGNBQWMsRUFBRSxnQkFBZ0IsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUM7YUFDL0QsQ0FBQztZQUVGLE1BQU0sUUFBUSxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQ2hDLElBQUEsNEJBQWtCLEVBQUMsK0NBQWtCLENBQUMsQ0FDdkMsQ0FBQztZQUNGLE1BQU0sVUFBVSxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQ2xDLElBQUEsNEJBQWtCLEVBQUMsbURBQW9CLENBQUMsQ0FDekMsQ0FBQztZQUNGLE1BQU0sWUFBWSxHQUNoQixhQUFhLENBQUMsR0FBRyxDQUFzQiwyQ0FBbUIsQ0FBQyxDQUFDO1lBRTdELFlBQVksQ0FBQyxnQkFBOEIsQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNuRSxZQUFZLENBQUMscUJBQW1DLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDLENBQUM7WUFFdkUsUUFBUSxDQUFDLE9BQXFCLENBQUMsaUJBQWlCLENBQUM7Z0JBQ2hELEVBQUUsRUFBRSxDQUFDO2dCQUNMLFFBQVEsRUFBRSxNQUFNO2FBQ2pCLENBQUMsQ0FBQztZQUNGLFVBQVUsQ0FBQyxPQUFxQixDQUFDLGlCQUFpQixDQUFDO2dCQUNsRCxFQUFFLEVBQUUsQ0FBQztnQkFDTCxVQUFVLEVBQUUsT0FBTzthQUNwQixDQUFDLENBQUM7WUFFRixnQkFBZ0IsQ0FBQyxrQkFBZ0MsQ0FBQyxpQkFBaUIsQ0FBQztnQkFDbkUsTUFBTSxFQUFFLFNBQVM7YUFDbEIsQ0FBQyxDQUFDO1lBRUgsY0FBYyxDQUFDLE9BQU8sQ0FBQyxPQUFPO2lCQUMzQixxQkFBcUIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLENBQUM7aUJBQzFELHFCQUFxQixDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxnQkFBZ0IsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBRTlELE1BQU0sV0FBVyxHQUFHO2dCQUNsQixPQUFPLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDbEIsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDM0IsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDNUIsbUJBQW1CLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDOUIsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7Z0JBQ2xCLE9BQU8sRUFBRTtvQkFDUCxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FDYixDQUFDLE9BQWdCLEVBQUUsT0FBZ0MsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUNoRTtvQkFDRCxJQUFJLEVBQUUsSUFBSTt5QkFDUCxFQUFFLEVBQUU7eUJBQ0oscUJBQXFCLENBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsQ0FBQzt5QkFDekQscUJBQXFCLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUM7eUJBQ25DLHFCQUFxQixDQUFDLEVBQUUsQ0FBQztvQkFDNUIsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7aUJBQ25CO2FBQ0YsQ0FBQztZQUVELGNBQWMsQ0FBQyxpQkFBK0IsQ0FBQyxlQUFlLENBQzdELFdBQVcsQ0FDWixDQUFDO1lBRUYsTUFBTSxPQUFPLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQztZQUUxQyxNQUFNLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxvQkFBb0IsQ0FDckQsdURBQXNCLEVBQ3RCLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUNqRCxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIkU6XFxucC1kbXNcXGxjYnAzXFxiYWNrZW5kXFxzcmNcXG1vZHVsZXNcXGNvcnJlc3BvbmRlbmNlXFxjb3JyZXNwb25kZW5jZS5zZXJ2aWNlLnNwZWMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgVGVzdCwgVGVzdGluZ01vZHVsZSB9IGZyb20gJ0BuZXN0anMvdGVzdGluZyc7XHJcbmltcG9ydCB7IGdldFJlcG9zaXRvcnlUb2tlbiB9IGZyb20gJ0BuZXN0anMvdHlwZW9ybSc7XHJcbmltcG9ydCB7IERhdGFTb3VyY2UsIFJlcG9zaXRvcnkgfSBmcm9tICd0eXBlb3JtJztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VTZXJ2aWNlIH0gZnJvbSAnLi9jb3JyZXNwb25kZW5jZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2UgfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlUmV2aXNpb24gfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLXJldmlzaW9uLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlVHlwZSB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2UtdHlwZS5lbnRpdHknO1xyXG5pbXBvcnQgeyBDb3JyZXNwb25kZW5jZVN0YXR1cyB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2Utc3RhdHVzLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlUmVmZXJlbmNlIH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS1yZWZlcmVuY2UuZW50aXR5JztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VUYWcgfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLXRhZy5lbnRpdHknO1xyXG5pbXBvcnQgeyBPcmdhbml6YXRpb24gfSBmcm9tICcuLi9vcmdhbml6YXRpb24vZW50aXRpZXMvb3JnYW5pemF0aW9uLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlUmVjaXBpZW50IH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS1yZWNpcGllbnQuZW50aXR5JztcclxuaW1wb3J0IHsgRG9jdW1lbnROdW1iZXJpbmdTZXJ2aWNlIH0gZnJvbSAnLi4vZG9jdW1lbnQtbnVtYmVyaW5nL3NlcnZpY2VzL2RvY3VtZW50LW51bWJlcmluZy5zZXJ2aWNlJztcclxuaW1wb3J0IHsgSnNvblNjaGVtYVNlcnZpY2UgfSBmcm9tICcuLi9qc29uLXNjaGVtYS9qc29uLXNjaGVtYS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgV29ya2Zsb3dFbmdpbmVTZXJ2aWNlIH0gZnJvbSAnLi4vd29ya2Zsb3ctZW5naW5lL3dvcmtmbG93LWVuZ2luZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgVXNlclNlcnZpY2UgfSBmcm9tICcuLi91c2VyL3VzZXIuc2VydmljZSc7XHJcbmltcG9ydCB7IFNlYXJjaFNlcnZpY2UgfSBmcm9tICcuLi9zZWFyY2gvc2VhcmNoLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBGaWxlU3RvcmFnZVNlcnZpY2UgfSBmcm9tICcuLi8uLi9jb21tb24vZmlsZS1zdG9yYWdlL2ZpbGUtc3RvcmFnZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgVXVpZFJlc29sdmVyU2VydmljZSB9IGZyb20gJy4uLy4uL2NvbW1vbi9zZXJ2aWNlcy91dWlkLXJlc29sdmVyLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBOb3RpZmljYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi4vbm90aWZpY2F0aW9uL25vdGlmaWNhdGlvbi5zZXJ2aWNlJztcclxuaW1wb3J0IHsgVXBkYXRlQ29ycmVzcG9uZGVuY2VEdG8gfSBmcm9tICcuL2R0by91cGRhdGUtY29ycmVzcG9uZGVuY2UuZHRvJztcclxuaW1wb3J0IHsgQ3JlYXRlQ29ycmVzcG9uZGVuY2VEdG8gfSBmcm9tICcuL2R0by9jcmVhdGUtY29ycmVzcG9uZGVuY2UuZHRvJztcclxuaW1wb3J0IHsgVXNlciB9IGZyb20gJy4uL3VzZXIvZW50aXRpZXMvdXNlci5lbnRpdHknO1xyXG5cclxuZGVzY3JpYmUoJ0NvcnJlc3BvbmRlbmNlU2VydmljZScsICgpID0+IHtcclxuICBsZXQgc2VydmljZTogQ29ycmVzcG9uZGVuY2VTZXJ2aWNlO1xyXG4gIGxldCBudW1iZXJpbmdTZXJ2aWNlOiBEb2N1bWVudE51bWJlcmluZ1NlcnZpY2U7XHJcbiAgbGV0IGNvcnJlc3BvbmRlbmNlUmVwbzogUmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZT47XHJcbiAgbGV0IHJldmlzaW9uUmVwbzogUmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVJldmlzaW9uPjtcclxuICBsZXQgdGVzdGluZ01vZHVsZTogVGVzdGluZ01vZHVsZTtcclxuICBsZXQgX2RhdGFTb3VyY2U6IERhdGFTb3VyY2U7XHJcblxyXG4gIGNvbnN0IGNyZWF0ZU1vY2tSZXBvc2l0b3J5ID0gKCkgPT4gKHtcclxuICAgIGZpbmQ6IGplc3QuZm4oKSxcclxuICAgIGZpbmRPbmU6IGplc3QuZm4oKSxcclxuICAgIGNyZWF0ZTogamVzdC5mbigpLFxyXG4gICAgc2F2ZTogamVzdC5mbigpLFxyXG4gICAgdXBkYXRlOiBqZXN0LmZuKCksXHJcbiAgICBkZWxldGU6IGplc3QuZm4oKSxcclxuICAgIHNvZnREZWxldGU6IGplc3QuZm4oKSxcclxuICAgIGNyZWF0ZVF1ZXJ5QnVpbGRlcjogamVzdC5mbigoKSA9PiAoe1xyXG4gICAgICBsZWZ0Sm9pbkFuZFNlbGVjdDogamVzdC5mbigpLm1vY2tSZXR1cm5UaGlzKCksXHJcbiAgICAgIHdoZXJlOiBqZXN0LmZuKCkubW9ja1JldHVyblRoaXMoKSxcclxuICAgICAgYW5kV2hlcmU6IGplc3QuZm4oKS5tb2NrUmV0dXJuVGhpcygpLFxyXG4gICAgICBvcmRlckJ5OiBqZXN0LmZuKCkubW9ja1JldHVyblRoaXMoKSxcclxuICAgICAgc2tpcDogamVzdC5mbigpLm1vY2tSZXR1cm5UaGlzKCksXHJcbiAgICAgIHRha2U6IGplc3QuZm4oKS5tb2NrUmV0dXJuVGhpcygpLFxyXG4gICAgICBnZXRPbmU6IGplc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZShudWxsKSxcclxuICAgICAgZ2V0TWFueTogamVzdC5mbigpLm1vY2tSZXNvbHZlZFZhbHVlKFtdKSxcclxuICAgICAgZ2V0TWFueUFuZENvdW50OiBqZXN0LmZuKCkubW9ja1Jlc29sdmVkVmFsdWUoW1tdLCAwXSksXHJcbiAgICB9KSksXHJcbiAgfSk7XHJcblxyXG4gIGNvbnN0IG1vY2tEYXRhU291cmNlID0ge1xyXG4gICAgY3JlYXRlUXVlcnlSdW5uZXI6IGplc3QuZm4oKCkgPT4gKHtcclxuICAgICAgY29ubmVjdDogamVzdC5mbigpLFxyXG4gICAgICBzdGFydFRyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgIGNvbW1pdFRyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgIHJvbGxiYWNrVHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgcmVsZWFzZTogamVzdC5mbigpLFxyXG4gICAgICBtYW5hZ2VyOiB7XHJcbiAgICAgICAgY3JlYXRlOiBqZXN0LmZuKCksXHJcbiAgICAgICAgc2F2ZTogamVzdC5mbigpLFxyXG4gICAgICAgIGZpbmRPbmU6IGplc3QuZm4oKSxcclxuICAgICAgfSxcclxuICAgIH0pKSxcclxuICAgIGdldFJlcG9zaXRvcnk6IGplc3QuZm4oKCkgPT4gY3JlYXRlTW9ja1JlcG9zaXRvcnkoKSksXHJcbiAgICBtYW5hZ2VyOiB7XHJcbiAgICAgIGZpbmRPbmU6IGplc3QuZm4oKSxcclxuICAgIH0sXHJcbiAgfTtcclxuXHJcbiAgYmVmb3JlRWFjaChhc3luYyAoKSA9PiB7XHJcbiAgICB0ZXN0aW5nTW9kdWxlID0gYXdhaXQgVGVzdC5jcmVhdGVUZXN0aW5nTW9kdWxlKHtcclxuICAgICAgcHJvdmlkZXJzOiBbXHJcbiAgICAgICAgQ29ycmVzcG9uZGVuY2VTZXJ2aWNlLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZSksXHJcbiAgICAgICAgICB1c2VWYWx1ZTogY3JlYXRlTW9ja1JlcG9zaXRvcnkoKSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVJldmlzaW9uKSxcclxuICAgICAgICAgIHVzZVZhbHVlOiBjcmVhdGVNb2NrUmVwb3NpdG9yeSgpLFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcHJvdmlkZTogZ2V0UmVwb3NpdG9yeVRva2VuKENvcnJlc3BvbmRlbmNlVHlwZSksXHJcbiAgICAgICAgICB1c2VWYWx1ZTogY3JlYXRlTW9ja1JlcG9zaXRvcnkoKSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVN0YXR1cyksXHJcbiAgICAgICAgICB1c2VWYWx1ZTogY3JlYXRlTW9ja1JlcG9zaXRvcnkoKSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVJlZmVyZW5jZSksXHJcbiAgICAgICAgICB1c2VWYWx1ZTogY3JlYXRlTW9ja1JlcG9zaXRvcnkoKSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVRhZyksXHJcbiAgICAgICAgICB1c2VWYWx1ZTogY3JlYXRlTW9ja1JlcG9zaXRvcnkoKSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IGdldFJlcG9zaXRvcnlUb2tlbihPcmdhbml6YXRpb24pLFxyXG4gICAgICAgICAgdXNlVmFsdWU6IGNyZWF0ZU1vY2tSZXBvc2l0b3J5KCksXHJcbiAgICAgICAgfSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwcm92aWRlOiBnZXRSZXBvc2l0b3J5VG9rZW4oQ29ycmVzcG9uZGVuY2VSZWNpcGllbnQpLFxyXG4gICAgICAgICAgdXNlVmFsdWU6IGNyZWF0ZU1vY2tSZXBvc2l0b3J5KCksXHJcbiAgICAgICAgfSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwcm92aWRlOiBEb2N1bWVudE51bWJlcmluZ1NlcnZpY2UsXHJcbiAgICAgICAgICB1c2VWYWx1ZToge1xyXG4gICAgICAgICAgICBnZW5lcmF0ZU5leHROdW1iZXI6IGplc3QuZm4oKSxcclxuICAgICAgICAgICAgdXBkYXRlTnVtYmVyRm9yRHJhZnQ6IGplc3QuZm4oKSxcclxuICAgICAgICAgICAgcHJldmlld05leHROdW1iZXI6IGplc3QuZm4oKSxcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgfSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwcm92aWRlOiBKc29uU2NoZW1hU2VydmljZSxcclxuICAgICAgICAgIHVzZVZhbHVlOiB7IHZhbGlkYXRlOiBqZXN0LmZuKCkgfSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IFdvcmtmbG93RW5naW5lU2VydmljZSxcclxuICAgICAgICAgIHVzZVZhbHVlOiB7IGNyZWF0ZUluc3RhbmNlOiBqZXN0LmZuKCkgfSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IFVzZXJTZXJ2aWNlLFxyXG4gICAgICAgICAgdXNlVmFsdWU6IHtcclxuICAgICAgICAgICAgZmluZE9uZTogamVzdC5mbigpLFxyXG4gICAgICAgICAgICBnZXRVc2VyUGVybWlzc2lvbnM6IGplc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZShbXSksXHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcHJvdmlkZTogRGF0YVNvdXJjZSxcclxuICAgICAgICAgIHVzZVZhbHVlOiBtb2NrRGF0YVNvdXJjZSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IFNlYXJjaFNlcnZpY2UsXHJcbiAgICAgICAgICB1c2VWYWx1ZTogeyBpbmRleERvY3VtZW50OiBqZXN0LmZuKCkgfSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IEZpbGVTdG9yYWdlU2VydmljZSxcclxuICAgICAgICAgIHVzZVZhbHVlOiB7IGNvbW1pdDogamVzdC5mbigpLm1vY2tSZXNvbHZlZFZhbHVlKFtdKSB9LFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcHJvdmlkZTogVXVpZFJlc29sdmVyU2VydmljZSxcclxuICAgICAgICAgIHVzZVZhbHVlOiB7XHJcbiAgICAgICAgICAgIHJlc29sdmVQcm9qZWN0SWQ6IGplc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZSgxKSxcclxuICAgICAgICAgICAgcmVzb2x2ZU9yZ2FuaXphdGlvbklkOiBqZXN0LmZuKCkubW9ja1Jlc29sdmVkVmFsdWUoMSksXHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcHJvdmlkZTogTm90aWZpY2F0aW9uU2VydmljZSxcclxuICAgICAgICAgIHVzZVZhbHVlOiB7IHNlbmQ6IGplc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZSh1bmRlZmluZWQpIH0sXHJcbiAgICAgICAgfSxcclxuICAgICAgXSxcclxuICAgIH0pLmNvbXBpbGUoKTtcclxuXHJcbiAgICBzZXJ2aWNlID0gdGVzdGluZ01vZHVsZS5nZXQ8Q29ycmVzcG9uZGVuY2VTZXJ2aWNlPihDb3JyZXNwb25kZW5jZVNlcnZpY2UpO1xyXG4gICAgbnVtYmVyaW5nU2VydmljZSA9IHRlc3RpbmdNb2R1bGUuZ2V0PERvY3VtZW50TnVtYmVyaW5nU2VydmljZT4oXHJcbiAgICAgIERvY3VtZW50TnVtYmVyaW5nU2VydmljZVxyXG4gICAgKTtcclxuICAgIGNvcnJlc3BvbmRlbmNlUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2U+PihcclxuICAgICAgZ2V0UmVwb3NpdG9yeVRva2VuKENvcnJlc3BvbmRlbmNlKVxyXG4gICAgKTtcclxuICAgIHJldmlzaW9uUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VSZXZpc2lvbj4+KFxyXG4gICAgICBnZXRSZXBvc2l0b3J5VG9rZW4oQ29ycmVzcG9uZGVuY2VSZXZpc2lvbilcclxuICAgICk7XHJcbiAgICBfZGF0YVNvdXJjZSA9IHRlc3RpbmdNb2R1bGUuZ2V0PERhdGFTb3VyY2U+KERhdGFTb3VyY2UpO1xyXG4gIH0pO1xyXG5cclxuICBpdCgnc2hvdWxkIGJlIGRlZmluZWQnLCAoKSA9PiB7XHJcbiAgICBleHBlY3Qoc2VydmljZSkudG9CZURlZmluZWQoKTtcclxuICB9KTtcclxuXHJcbiAgZGVzY3JpYmUoJ3VwZGF0ZScsICgpID0+IHtcclxuICAgIGl0KCdzaG91bGQgTk9UIHJlZ2VuZXJhdGUgbnVtYmVyIGlmIGNyaXRpY2FsIGZpZWxkcyB1bmNoYW5nZWQnLCBhc3luYyAoKSA9PiB7XHJcbiAgICAgIGNvbnN0IG1vY2tVc2VyID0geyBpZDogMSwgcHJpbWFyeU9yZ2FuaXphdGlvbklkOiAxMCB9IGFzIHVua25vd24gYXMgVXNlcjtcclxuICAgICAgY29uc3QgbW9ja1JldmlzaW9uID0ge1xyXG4gICAgICAgIGlkOiAxMDAsXHJcbiAgICAgICAgY29ycmVzcG9uZGVuY2VJZDogMSxcclxuICAgICAgICBpc0N1cnJlbnQ6IHRydWUsXHJcbiAgICAgICAgc3RhdHVzSWQ6IDUsXHJcbiAgICAgIH07XHJcblxyXG4gICAgICBqZXN0XHJcbiAgICAgICAgLnNweU9uKHJldmlzaW9uUmVwbywgJ2ZpbmRPbmUnKVxyXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZShtb2NrUmV2aXNpb24gYXMgdW5rbm93biBhcyBDb3JyZXNwb25kZW5jZVJldmlzaW9uKTtcclxuXHJcbiAgICAgIGNvbnN0IG1vY2tDb3JyID0ge1xyXG4gICAgICAgIGlkOiAxLFxyXG4gICAgICAgIHByb2plY3RJZDogMSxcclxuICAgICAgICBjb3JyZXNwb25kZW5jZVR5cGVJZDogMixcclxuICAgICAgICBkaXNjaXBsaW5lSWQ6IDMsXHJcbiAgICAgICAgb3JpZ2luYXRvcklkOiAxMCxcclxuICAgICAgICBjb3JyZXNwb25kZW5jZU51bWJlcjogJ09MRC1OVU0nLFxyXG4gICAgICAgIHJlY2lwaWVudHM6IFt7IHJlY2lwaWVudFR5cGU6ICdUTycsIHJlY2lwaWVudE9yZ2FuaXphdGlvbklkOiA5OSB9XSxcclxuICAgICAgfTtcclxuICAgICAgamVzdFxyXG4gICAgICAgIC5zcHlPbihjb3JyZXNwb25kZW5jZVJlcG8sICdmaW5kT25lJylcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWUobW9ja0NvcnIgYXMgdW5rbm93biBhcyBDb3JyZXNwb25kZW5jZSk7XHJcblxyXG4gICAgICBjb25zdCB1cGRhdGVEdG86IFVwZGF0ZUNvcnJlc3BvbmRlbmNlRHRvID0ge1xyXG4gICAgICAgIHByb2plY3RJZDogMSxcclxuICAgICAgICBkaXNjaXBsaW5lSWQ6IDMsXHJcbiAgICAgIH07XHJcblxyXG4gICAgICBhd2FpdCBzZXJ2aWNlLnVwZGF0ZSgxLCB1cGRhdGVEdG8sIG1vY2tVc2VyKTtcclxuXHJcbiAgICAgIGV4cGVjdChcclxuICAgICAgICBudW1iZXJpbmdTZXJ2aWNlLnVwZGF0ZU51bWJlckZvckRyYWZ0IGFzIGplc3QuTW9ja1xyXG4gICAgICApLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBpdCgnc2hvdWxkIHJlZ2VuZXJhdGUgbnVtYmVyIGlmIFByb2plY3QgSUQgY2hhbmdlcycsIGFzeW5jICgpID0+IHtcclxuICAgICAgY29uc3QgbW9ja1VzZXIgPSB7IGlkOiAxLCBwcmltYXJ5T3JnYW5pemF0aW9uSWQ6IDEwIH0gYXMgdW5rbm93biBhcyBVc2VyO1xyXG4gICAgICBjb25zdCBtb2NrUmV2aXNpb24gPSB7XHJcbiAgICAgICAgaWQ6IDEwMCxcclxuICAgICAgICBjb3JyZXNwb25kZW5jZUlkOiAxLFxyXG4gICAgICAgIGlzQ3VycmVudDogdHJ1ZSxcclxuICAgICAgICBzdGF0dXNJZDogNSxcclxuICAgICAgfTtcclxuICAgICAgamVzdFxyXG4gICAgICAgIC5zcHlPbihyZXZpc2lvblJlcG8sICdmaW5kT25lJylcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWUobW9ja1JldmlzaW9uIGFzIHVua25vd24gYXMgQ29ycmVzcG9uZGVuY2VSZXZpc2lvbik7XHJcblxyXG4gICAgICBjb25zdCBtb2NrQ29yciA9IHtcclxuICAgICAgICBpZDogMSxcclxuICAgICAgICBwcm9qZWN0SWQ6IDEsXHJcbiAgICAgICAgY29ycmVzcG9uZGVuY2VUeXBlSWQ6IDIsXHJcbiAgICAgICAgZGlzY2lwbGluZUlkOiAzLFxyXG4gICAgICAgIG9yaWdpbmF0b3JJZDogMTAsXHJcbiAgICAgICAgY29ycmVzcG9uZGVuY2VOdW1iZXI6ICdPTEQtTlVNJyxcclxuICAgICAgICByZWNpcGllbnRzOiBbeyByZWNpcGllbnRUeXBlOiAnVE8nLCByZWNpcGllbnRPcmdhbml6YXRpb25JZDogOTkgfV0sXHJcbiAgICAgIH07XHJcbiAgICAgIGplc3RcclxuICAgICAgICAuc3B5T24oY29ycmVzcG9uZGVuY2VSZXBvLCAnZmluZE9uZScpXHJcbiAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlKG1vY2tDb3JyIGFzIHVua25vd24gYXMgQ29ycmVzcG9uZGVuY2UpO1xyXG5cclxuICAgICAgY29uc3QgdXBkYXRlRHRvOiBVcGRhdGVDb3JyZXNwb25kZW5jZUR0byA9IHtcclxuICAgICAgICBwcm9qZWN0SWQ6IDIsXHJcbiAgICAgIH07XHJcblxyXG4gICAgICBjb25zdCB1dWlkUmVzb2x2ZXIgPVxyXG4gICAgICAgIHRlc3RpbmdNb2R1bGUuZ2V0PFV1aWRSZXNvbHZlclNlcnZpY2U+KFV1aWRSZXNvbHZlclNlcnZpY2UpO1xyXG4gICAgICAodXVpZFJlc29sdmVyLnJlc29sdmVQcm9qZWN0SWQgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSgyKTtcclxuXHJcbiAgICAgIGF3YWl0IHNlcnZpY2UudXBkYXRlKDEsIHVwZGF0ZUR0bywgbW9ja1VzZXIpO1xyXG5cclxuICAgICAgZXhwZWN0KFxyXG4gICAgICAgIG51bWJlcmluZ1NlcnZpY2UudXBkYXRlTnVtYmVyRm9yRHJhZnQgYXMgamVzdC5Nb2NrXHJcbiAgICAgICkudG9IYXZlQmVlbkNhbGxlZCgpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgaXQoJ3Nob3VsZCByZWdlbmVyYXRlIG51bWJlciBpZiBEb2N1bWVudCBUeXBlIGNoYW5nZXMnLCBhc3luYyAoKSA9PiB7XHJcbiAgICAgIGNvbnN0IG1vY2tVc2VyID0geyBpZDogMSwgcHJpbWFyeU9yZ2FuaXphdGlvbklkOiAxMCB9IGFzIHVua25vd24gYXMgVXNlcjtcclxuICAgICAgY29uc3QgbW9ja1JldmlzaW9uID0ge1xyXG4gICAgICAgIGlkOiAxMDAsXHJcbiAgICAgICAgY29ycmVzcG9uZGVuY2VJZDogMSxcclxuICAgICAgICBpc0N1cnJlbnQ6IHRydWUsXHJcbiAgICAgICAgc3RhdHVzSWQ6IDUsXHJcbiAgICAgIH07XHJcbiAgICAgIGplc3RcclxuICAgICAgICAuc3B5T24ocmV2aXNpb25SZXBvLCAnZmluZE9uZScpXHJcbiAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlKG1vY2tSZXZpc2lvbiBhcyB1bmtub3duIGFzIENvcnJlc3BvbmRlbmNlUmV2aXNpb24pO1xyXG5cclxuICAgICAgY29uc3QgbW9ja0NvcnIgPSB7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgcHJvamVjdElkOiAxLFxyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlVHlwZUlkOiAyLFxyXG4gICAgICAgIGRpc2NpcGxpbmVJZDogMyxcclxuICAgICAgICBvcmlnaW5hdG9ySWQ6IDEwLFxyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlTnVtYmVyOiAnT0xELU5VTScsXHJcbiAgICAgICAgcmVjaXBpZW50czogW3sgcmVjaXBpZW50VHlwZTogJ1RPJywgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQ6IDk5IH1dLFxyXG4gICAgICB9O1xyXG4gICAgICBqZXN0XHJcbiAgICAgICAgLnNweU9uKGNvcnJlc3BvbmRlbmNlUmVwbywgJ2ZpbmRPbmUnKVxyXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZShtb2NrQ29yciBhcyB1bmtub3duIGFzIENvcnJlc3BvbmRlbmNlKTtcclxuXHJcbiAgICAgIGNvbnN0IHVwZGF0ZUR0bzogVXBkYXRlQ29ycmVzcG9uZGVuY2VEdG8gPSB7XHJcbiAgICAgICAgdHlwZUlkOiA5OTksXHJcbiAgICAgIH07XHJcblxyXG4gICAgICBjb25zdCB0eXBlUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VUeXBlPj4oXHJcbiAgICAgICAgZ2V0UmVwb3NpdG9yeVRva2VuKENvcnJlc3BvbmRlbmNlVHlwZSlcclxuICAgICAgKTtcclxuICAgICAgKHR5cGVSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDk5OSxcclxuICAgICAgICB0eXBlQ29kZTogJ05FVy1UWVBFJyxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBhd2FpdCBzZXJ2aWNlLnVwZGF0ZSgxLCB1cGRhdGVEdG8sIG1vY2tVc2VyKTtcclxuXHJcbiAgICAgIGV4cGVjdChcclxuICAgICAgICBudW1iZXJpbmdTZXJ2aWNlLnVwZGF0ZU51bWJlckZvckRyYWZ0IGFzIGplc3QuTW9ja1xyXG4gICAgICApLnRvSGF2ZUJlZW5DYWxsZWQoKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGl0KCdzaG91bGQgcmVnZW5lcmF0ZSBudW1iZXIgaWYgUmVjaXBpZW50IE9yZ2FuaXphdGlvbiBjaGFuZ2VzJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgICBjb25zdCBtb2NrVXNlciA9IHsgaWQ6IDEsIHByaW1hcnlPcmdhbml6YXRpb25JZDogMTAgfSBhcyB1bmtub3duIGFzIFVzZXI7XHJcbiAgICAgIGNvbnN0IG1vY2tSZXZpc2lvbiA9IHtcclxuICAgICAgICBpZDogMTAwLFxyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IDEsXHJcbiAgICAgICAgaXNDdXJyZW50OiB0cnVlLFxyXG4gICAgICAgIHN0YXR1c0lkOiA1LFxyXG4gICAgICB9O1xyXG4gICAgICBqZXN0XHJcbiAgICAgICAgLnNweU9uKHJldmlzaW9uUmVwbywgJ2ZpbmRPbmUnKVxyXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZShtb2NrUmV2aXNpb24gYXMgdW5rbm93biBhcyBDb3JyZXNwb25kZW5jZVJldmlzaW9uKTtcclxuXHJcbiAgICAgIGNvbnN0IG1vY2tDb3JyID0ge1xyXG4gICAgICAgIGlkOiAxLFxyXG4gICAgICAgIHByb2plY3RJZDogMSxcclxuICAgICAgICBjb3JyZXNwb25kZW5jZVR5cGVJZDogMixcclxuICAgICAgICBkaXNjaXBsaW5lSWQ6IDMsXHJcbiAgICAgICAgb3JpZ2luYXRvcklkOiAxMCxcclxuICAgICAgICBjb3JyZXNwb25kZW5jZU51bWJlcjogJ09MRC1OVU0nLFxyXG4gICAgICAgIHJlY2lwaWVudHM6IFt7IHJlY2lwaWVudFR5cGU6ICdUTycsIHJlY2lwaWVudE9yZ2FuaXphdGlvbklkOiA5OSB9XSxcclxuICAgICAgfTtcclxuICAgICAgamVzdFxyXG4gICAgICAgIC5zcHlPbihjb3JyZXNwb25kZW5jZVJlcG8sICdmaW5kT25lJylcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWUobW9ja0NvcnIgYXMgdW5rbm93biBhcyBDb3JyZXNwb25kZW5jZSk7XHJcblxyXG4gICAgICAvLyBBY2Nlc3MgRGF0YVNvdXJjZSBtYW5hZ2VyIGZvciBtb2NraW5nXHJcbiAgICAgIG1vY2tEYXRhU291cmNlLm1hbmFnZXIuZmluZE9uZS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDg4LFxyXG4gICAgICAgIG9yZ2FuaXphdGlvbkNvZGU6ICdORVctT1JHJyxcclxuICAgICAgfSBhcyB1bmtub3duIGFzIE9yZ2FuaXphdGlvbik7XHJcblxyXG4gICAgICBjb25zdCB1cGRhdGVEdG86IFVwZGF0ZUNvcnJlc3BvbmRlbmNlRHRvID0ge1xyXG4gICAgICAgIHJlY2lwaWVudHM6IFt7IHR5cGU6ICdUTycsIG9yZ2FuaXphdGlvbklkOiA4OCB9XSxcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGF3YWl0IHNlcnZpY2UudXBkYXRlKDEsIHVwZGF0ZUR0bywgbW9ja1VzZXIpO1xyXG5cclxuICAgICAgZXhwZWN0KFxyXG4gICAgICAgIG51bWJlcmluZ1NlcnZpY2UudXBkYXRlTnVtYmVyRm9yRHJhZnQgYXMgamVzdC5Nb2NrXHJcbiAgICAgICkudG9IYXZlQmVlbkNhbGxlZCgpO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcblxyXG4gIGRlc2NyaWJlKCdjcmVhdGUnLCAoKSA9PiB7XHJcbiAgICBpdCgnc2hvdWxkIGFsbG93IHN5c3RlbS5tYW5hZ2VfYWxsIHVzZXIgd2l0aG91dCBwcmltYXJ5T3JnYW5pemF0aW9uSWQgd2hlbiBvcmlnaW5hdG9ySWQgaXMgcHJvdmlkZWQnLCBhc3luYyAoKSA9PiB7XHJcbiAgICAgIGNvbnN0IG1vY2tVc2VyID0ge1xyXG4gICAgICAgIHVzZXJfaWQ6IDEsXHJcbiAgICAgICAgcHJpbWFyeU9yZ2FuaXphdGlvbklkOiBudWxsLFxyXG4gICAgICB9IGFzIHVua25vd24gYXMgVXNlcjtcclxuXHJcbiAgICAgIGNvbnN0IGNyZWF0ZUR0bzogQ3JlYXRlQ29ycmVzcG9uZGVuY2VEdG8gPSB7XHJcbiAgICAgICAgcHJvamVjdElkOiAncHJvamVjdC11dWlkJyxcclxuICAgICAgICB0eXBlSWQ6IDEsXHJcbiAgICAgICAgc3ViamVjdDogJ1Rlc3QgU3ViamVjdCcsXHJcbiAgICAgICAgb3JpZ2luYXRvcklkOiAnb3JpZ2luYXRvci11dWlkJyxcclxuICAgICAgICByZWNpcGllbnRzOiBbeyBvcmdhbml6YXRpb25JZDogJ3JlY2lwaWVudC11dWlkJywgdHlwZTogJ1RPJyB9XSxcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGNvbnN0IHVzZXJTZXJ2aWNlID0gdGVzdGluZ01vZHVsZS5nZXQ8VXNlclNlcnZpY2U+KFVzZXJTZXJ2aWNlKTtcclxuICAgICAgY29uc3QgdHlwZVJlcG8gPSB0ZXN0aW5nTW9kdWxlLmdldDxSZXBvc2l0b3J5PENvcnJlc3BvbmRlbmNlVHlwZT4+KFxyXG4gICAgICAgIGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVR5cGUpXHJcbiAgICAgICk7XHJcbiAgICAgIGNvbnN0IHN0YXR1c1JlcG8gPSB0ZXN0aW5nTW9kdWxlLmdldDxSZXBvc2l0b3J5PENvcnJlc3BvbmRlbmNlU3RhdHVzPj4oXHJcbiAgICAgICAgZ2V0UmVwb3NpdG9yeVRva2VuKENvcnJlc3BvbmRlbmNlU3RhdHVzKVxyXG4gICAgICApO1xyXG4gICAgICBjb25zdCB1dWlkUmVzb2x2ZXIgPVxyXG4gICAgICAgIHRlc3RpbmdNb2R1bGUuZ2V0PFV1aWRSZXNvbHZlclNlcnZpY2U+KFV1aWRSZXNvbHZlclNlcnZpY2UpO1xyXG5cclxuICAgICAgKHVzZXJTZXJ2aWNlLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgdXNlcl9pZDogMSxcclxuICAgICAgICBwcmltYXJ5T3JnYW5pemF0aW9uSWQ6IG51bGwsXHJcbiAgICAgIH0pO1xyXG4gICAgICAodXNlclNlcnZpY2UuZ2V0VXNlclBlcm1pc3Npb25zIGFzIGplc3QuTW9jaykubW9ja1Jlc29sdmVkVmFsdWUoW1xyXG4gICAgICAgICdzeXN0ZW0ubWFuYWdlX2FsbCcsXHJcbiAgICAgIF0pO1xyXG5cclxuICAgICAgKHV1aWRSZXNvbHZlci5yZXNvbHZlUHJvamVjdElkIGFzIGplc3QuTW9jaykubW9ja1Jlc29sdmVkVmFsdWUoMTAwKTtcclxuICAgICAgKHV1aWRSZXNvbHZlci5yZXNvbHZlT3JnYW5pemF0aW9uSWQgYXMgamVzdC5Nb2NrKS5tb2NrSW1wbGVtZW50YXRpb24oXHJcbiAgICAgICAgKHZhbHVlOiBudW1iZXIgfCBzdHJpbmcpID0+IHtcclxuICAgICAgICAgIGlmICh2YWx1ZSA9PT0gJ29yaWdpbmF0b3ItdXVpZCcpIHJldHVybiAxMDtcclxuICAgICAgICAgIGlmICh2YWx1ZSA9PT0gJ3JlY2lwaWVudC11dWlkJykgcmV0dXJuIDIwO1xyXG4gICAgICAgICAgcmV0dXJuIDA7XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgICAgKHR5cGVSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgdHlwZUNvZGU6ICdMVFInLFxyXG4gICAgICB9KTtcclxuICAgICAgKHN0YXR1c1JlcG8uZmluZE9uZSBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKHtcclxuICAgICAgICBpZDogMSxcclxuICAgICAgICBzdGF0dXNDb2RlOiAnRFJBRlQnLFxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIChudW1iZXJpbmdTZXJ2aWNlLmdlbmVyYXRlTmV4dE51bWJlciBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKHtcclxuICAgICAgICBudW1iZXI6ICdET0MtMDAxJyxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBtb2NrRGF0YVNvdXJjZS5tYW5hZ2VyLmZpbmRPbmVcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDEwLCBvcmdhbml6YXRpb25Db2RlOiAnT1JHJyB9KVxyXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogMjAsIG9yZ2FuaXphdGlvbkNvZGU6ICdSRUMnIH0pO1xyXG5cclxuICAgICAgY29uc3QgcXVlcnlSdW5uZXIgPSB7XHJcbiAgICAgICAgY29ubmVjdDogamVzdC5mbigpLFxyXG4gICAgICAgIHN0YXJ0VHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICBjb21taXRUcmFuc2FjdGlvbjogamVzdC5mbigpLFxyXG4gICAgICAgIHJvbGxiYWNrVHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICByZWxlYXNlOiBqZXN0LmZuKCksXHJcbiAgICAgICAgbWFuYWdlcjoge1xyXG4gICAgICAgICAgY3JlYXRlOiBqZXN0LmZuKFxyXG4gICAgICAgICAgICAoX2VudGl0eTogdW5rbm93biwgcGF5bG9hZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pID0+IHBheWxvYWRcclxuICAgICAgICAgICksXHJcbiAgICAgICAgICBzYXZlOiBqZXN0XHJcbiAgICAgICAgICAgIC5mbigpXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogOTk5LCBwdWJsaWNJZDogJ2NvcnItdXVpZCcgfSlcclxuICAgICAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7IGlkOiAxMDAwIH0pXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoW10pLFxyXG4gICAgICAgICAgZmluZE9uZTogamVzdC5mbigpLFxyXG4gICAgICAgIH0sXHJcbiAgICAgIH07XHJcblxyXG4gICAgICAobW9ja0RhdGFTb3VyY2UuY3JlYXRlUXVlcnlSdW5uZXIgYXMgamVzdC5Nb2NrKS5tb2NrUmV0dXJuVmFsdWUoXHJcbiAgICAgICAgcXVlcnlSdW5uZXJcclxuICAgICAgKTtcclxuXHJcbiAgICAgIGF3YWl0IHNlcnZpY2UuY3JlYXRlKGNyZWF0ZUR0bywgbW9ja1VzZXIpO1xyXG5cclxuICAgICAgZXhwZWN0KHF1ZXJ5UnVubmVyLm1hbmFnZXIuY3JlYXRlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcclxuICAgICAgICBDb3JyZXNwb25kZW5jZSxcclxuICAgICAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7IG9yaWdpbmF0b3JJZDogMTAgfSlcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGl0KCdzaG91bGQgc2V0IHJldmlzaW9uTGFiZWwgdG8gXCJBXCIgZm9yIFJGQSB0eXBlJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgICBjb25zdCBtb2NrVXNlciA9IHtcclxuICAgICAgICB1c2VyX2lkOiAxLFxyXG4gICAgICAgIHByaW1hcnlPcmdhbml6YXRpb25JZDogMTAsXHJcbiAgICAgIH0gYXMgdW5rbm93biBhcyBVc2VyO1xyXG5cclxuICAgICAgY29uc3QgY3JlYXRlRHRvOiBDcmVhdGVDb3JyZXNwb25kZW5jZUR0byA9IHtcclxuICAgICAgICBwcm9qZWN0SWQ6ICdwcm9qZWN0LXV1aWQnLFxyXG4gICAgICAgIHR5cGVJZDogMSxcclxuICAgICAgICBzdWJqZWN0OiAnVGVzdCBTdWJqZWN0JyxcclxuICAgICAgICByZWNpcGllbnRzOiBbeyBvcmdhbml6YXRpb25JZDogJ3JlY2lwaWVudC11dWlkJywgdHlwZTogJ1RPJyB9XSxcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGNvbnN0IHR5cGVSZXBvID0gdGVzdGluZ01vZHVsZS5nZXQ8UmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVR5cGU+PihcclxuICAgICAgICBnZXRSZXBvc2l0b3J5VG9rZW4oQ29ycmVzcG9uZGVuY2VUeXBlKVxyXG4gICAgICApO1xyXG4gICAgICBjb25zdCBzdGF0dXNSZXBvID0gdGVzdGluZ01vZHVsZS5nZXQ8UmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVN0YXR1cz4+KFxyXG4gICAgICAgIGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVN0YXR1cylcclxuICAgICAgKTtcclxuICAgICAgY29uc3QgdXVpZFJlc29sdmVyID1cclxuICAgICAgICB0ZXN0aW5nTW9kdWxlLmdldDxVdWlkUmVzb2x2ZXJTZXJ2aWNlPihVdWlkUmVzb2x2ZXJTZXJ2aWNlKTtcclxuXHJcbiAgICAgICh1dWlkUmVzb2x2ZXIucmVzb2x2ZVByb2plY3RJZCBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKDEwMCk7XHJcbiAgICAgICh1dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkIGFzIGplc3QuTW9jaykubW9ja1Jlc29sdmVkVmFsdWUoMjApO1xyXG5cclxuICAgICAgKHR5cGVSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgdHlwZUNvZGU6ICdSRkEnLFxyXG4gICAgICB9KTtcclxuICAgICAgKHN0YXR1c1JlcG8uZmluZE9uZSBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKHtcclxuICAgICAgICBpZDogMSxcclxuICAgICAgICBzdGF0dXNDb2RlOiAnRFJBRlQnLFxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIChudW1iZXJpbmdTZXJ2aWNlLmdlbmVyYXRlTmV4dE51bWJlciBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKHtcclxuICAgICAgICBudW1iZXI6ICdET0MtMDAxJyxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBtb2NrRGF0YVNvdXJjZS5tYW5hZ2VyLmZpbmRPbmVcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDEwLCBvcmdhbml6YXRpb25Db2RlOiAnT1JHJyB9KVxyXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogMjAsIG9yZ2FuaXphdGlvbkNvZGU6ICdSRUMnIH0pO1xyXG5cclxuICAgICAgY29uc3QgcXVlcnlSdW5uZXIgPSB7XHJcbiAgICAgICAgY29ubmVjdDogamVzdC5mbigpLFxyXG4gICAgICAgIHN0YXJ0VHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICBjb21taXRUcmFuc2FjdGlvbjogamVzdC5mbigpLFxyXG4gICAgICAgIHJvbGxiYWNrVHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICByZWxlYXNlOiBqZXN0LmZuKCksXHJcbiAgICAgICAgbWFuYWdlcjoge1xyXG4gICAgICAgICAgY3JlYXRlOiBqZXN0LmZuKFxyXG4gICAgICAgICAgICAoX2VudGl0eTogdW5rbm93biwgcGF5bG9hZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pID0+IHBheWxvYWRcclxuICAgICAgICAgICksXHJcbiAgICAgICAgICBzYXZlOiBqZXN0XHJcbiAgICAgICAgICAgIC5mbigpXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogOTk5LCBwdWJsaWNJZDogJ2NvcnItdXVpZCcgfSlcclxuICAgICAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7IGlkOiAxMDAwIH0pXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoW10pLFxyXG4gICAgICAgICAgZmluZE9uZTogamVzdC5mbigpLFxyXG4gICAgICAgIH0sXHJcbiAgICAgIH07XHJcblxyXG4gICAgICAobW9ja0RhdGFTb3VyY2UuY3JlYXRlUXVlcnlSdW5uZXIgYXMgamVzdC5Nb2NrKS5tb2NrUmV0dXJuVmFsdWUoXHJcbiAgICAgICAgcXVlcnlSdW5uZXJcclxuICAgICAgKTtcclxuXHJcbiAgICAgIGF3YWl0IHNlcnZpY2UuY3JlYXRlKGNyZWF0ZUR0bywgbW9ja1VzZXIpO1xyXG5cclxuICAgICAgZXhwZWN0KHF1ZXJ5UnVubmVyLm1hbmFnZXIuY3JlYXRlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcclxuICAgICAgICBDb3JyZXNwb25kZW5jZVJldmlzaW9uLFxyXG4gICAgICAgIGV4cGVjdC5vYmplY3RDb250YWluaW5nKHsgcmV2aXNpb25MYWJlbDogJ0EnIH0pXHJcbiAgICAgICk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBpdCgnc2hvdWxkIHNldCByZXZpc2lvbkxhYmVsIHRvIFwiQVwiIGZvciBSRkkgdHlwZScsIGFzeW5jICgpID0+IHtcclxuICAgICAgY29uc3QgbW9ja1VzZXIgPSB7XHJcbiAgICAgICAgdXNlcl9pZDogMSxcclxuICAgICAgICBwcmltYXJ5T3JnYW5pemF0aW9uSWQ6IDEwLFxyXG4gICAgICB9IGFzIHVua25vd24gYXMgVXNlcjtcclxuXHJcbiAgICAgIGNvbnN0IGNyZWF0ZUR0bzogQ3JlYXRlQ29ycmVzcG9uZGVuY2VEdG8gPSB7XHJcbiAgICAgICAgcHJvamVjdElkOiAncHJvamVjdC11dWlkJyxcclxuICAgICAgICB0eXBlSWQ6IDEsXHJcbiAgICAgICAgc3ViamVjdDogJ1Rlc3QgU3ViamVjdCcsXHJcbiAgICAgICAgcmVjaXBpZW50czogW3sgb3JnYW5pemF0aW9uSWQ6ICdyZWNpcGllbnQtdXVpZCcsIHR5cGU6ICdUTycgfV0sXHJcbiAgICAgIH07XHJcblxyXG4gICAgICBjb25zdCB0eXBlUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VUeXBlPj4oXHJcbiAgICAgICAgZ2V0UmVwb3NpdG9yeVRva2VuKENvcnJlc3BvbmRlbmNlVHlwZSlcclxuICAgICAgKTtcclxuICAgICAgY29uc3Qgc3RhdHVzUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VTdGF0dXM+PihcclxuICAgICAgICBnZXRSZXBvc2l0b3J5VG9rZW4oQ29ycmVzcG9uZGVuY2VTdGF0dXMpXHJcbiAgICAgICk7XHJcbiAgICAgIGNvbnN0IHV1aWRSZXNvbHZlciA9XHJcbiAgICAgICAgdGVzdGluZ01vZHVsZS5nZXQ8VXVpZFJlc29sdmVyU2VydmljZT4oVXVpZFJlc29sdmVyU2VydmljZSk7XHJcblxyXG4gICAgICAodXVpZFJlc29sdmVyLnJlc29sdmVQcm9qZWN0SWQgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSgxMDApO1xyXG4gICAgICAodXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZCBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKDIwKTtcclxuXHJcbiAgICAgICh0eXBlUmVwby5maW5kT25lIGFzIGplc3QuTW9jaykubW9ja1Jlc29sdmVkVmFsdWUoe1xyXG4gICAgICAgIGlkOiAxLFxyXG4gICAgICAgIHR5cGVDb2RlOiAnUkZJJyxcclxuICAgICAgfSk7XHJcbiAgICAgIChzdGF0dXNSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgc3RhdHVzQ29kZTogJ0RSQUZUJyxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAobnVtYmVyaW5nU2VydmljZS5nZW5lcmF0ZU5leHROdW1iZXIgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgbnVtYmVyOiAnRE9DLTAwMScsXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgbW9ja0RhdGFTb3VyY2UubWFuYWdlci5maW5kT25lXHJcbiAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7IGlkOiAxMCwgb3JnYW5pemF0aW9uQ29kZTogJ09SRycgfSlcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDIwLCBvcmdhbml6YXRpb25Db2RlOiAnUkVDJyB9KTtcclxuXHJcbiAgICAgIGNvbnN0IHF1ZXJ5UnVubmVyID0ge1xyXG4gICAgICAgIGNvbm5lY3Q6IGplc3QuZm4oKSxcclxuICAgICAgICBzdGFydFRyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgICAgY29tbWl0VHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICByb2xsYmFja1RyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgICAgcmVsZWFzZTogamVzdC5mbigpLFxyXG4gICAgICAgIG1hbmFnZXI6IHtcclxuICAgICAgICAgIGNyZWF0ZTogamVzdC5mbihcclxuICAgICAgICAgICAgKF9lbnRpdHk6IHVua25vd24sIHBheWxvYWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiBwYXlsb2FkXHJcbiAgICAgICAgICApLFxyXG4gICAgICAgICAgc2F2ZTogamVzdFxyXG4gICAgICAgICAgICAuZm4oKVxyXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDk5OSwgcHVibGljSWQ6ICdjb3JyLXV1aWQnIH0pXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogMTAwMCB9KVxyXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKFtdKSxcclxuICAgICAgICAgIGZpbmRPbmU6IGplc3QuZm4oKSxcclxuICAgICAgICB9LFxyXG4gICAgICB9O1xyXG5cclxuICAgICAgKG1vY2tEYXRhU291cmNlLmNyZWF0ZVF1ZXJ5UnVubmVyIGFzIGplc3QuTW9jaykubW9ja1JldHVyblZhbHVlKFxyXG4gICAgICAgIHF1ZXJ5UnVubmVyXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBhd2FpdCBzZXJ2aWNlLmNyZWF0ZShjcmVhdGVEdG8sIG1vY2tVc2VyKTtcclxuXHJcbiAgICAgIGV4cGVjdChxdWVyeVJ1bm5lci5tYW5hZ2VyLmNyZWF0ZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoXHJcbiAgICAgICAgQ29ycmVzcG9uZGVuY2VSZXZpc2lvbixcclxuICAgICAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7IHJldmlzaW9uTGFiZWw6ICdBJyB9KVxyXG4gICAgICApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgaXQoJ3Nob3VsZCBzZXQgcmV2aXNpb25MYWJlbCB0byBudWxsIGZvciBMRVRURVIgdHlwZScsIGFzeW5jICgpID0+IHtcclxuICAgICAgY29uc3QgbW9ja1VzZXIgPSB7XHJcbiAgICAgICAgdXNlcl9pZDogMSxcclxuICAgICAgICBwcmltYXJ5T3JnYW5pemF0aW9uSWQ6IDEwLFxyXG4gICAgICB9IGFzIHVua25vd24gYXMgVXNlcjtcclxuXHJcbiAgICAgIGNvbnN0IGNyZWF0ZUR0bzogQ3JlYXRlQ29ycmVzcG9uZGVuY2VEdG8gPSB7XHJcbiAgICAgICAgcHJvamVjdElkOiAncHJvamVjdC11dWlkJyxcclxuICAgICAgICB0eXBlSWQ6IDEsXHJcbiAgICAgICAgc3ViamVjdDogJ1Rlc3QgU3ViamVjdCcsXHJcbiAgICAgICAgcmVjaXBpZW50czogW3sgb3JnYW5pemF0aW9uSWQ6ICdyZWNpcGllbnQtdXVpZCcsIHR5cGU6ICdUTycgfV0sXHJcbiAgICAgIH07XHJcblxyXG4gICAgICBjb25zdCB0eXBlUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VUeXBlPj4oXHJcbiAgICAgICAgZ2V0UmVwb3NpdG9yeVRva2VuKENvcnJlc3BvbmRlbmNlVHlwZSlcclxuICAgICAgKTtcclxuICAgICAgY29uc3Qgc3RhdHVzUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VTdGF0dXM+PihcclxuICAgICAgICBnZXRSZXBvc2l0b3J5VG9rZW4oQ29ycmVzcG9uZGVuY2VTdGF0dXMpXHJcbiAgICAgICk7XHJcbiAgICAgIGNvbnN0IHV1aWRSZXNvbHZlciA9XHJcbiAgICAgICAgdGVzdGluZ01vZHVsZS5nZXQ8VXVpZFJlc29sdmVyU2VydmljZT4oVXVpZFJlc29sdmVyU2VydmljZSk7XHJcblxyXG4gICAgICAodXVpZFJlc29sdmVyLnJlc29sdmVQcm9qZWN0SWQgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSgxMDApO1xyXG4gICAgICAodXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZCBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKDIwKTtcclxuXHJcbiAgICAgICh0eXBlUmVwby5maW5kT25lIGFzIGplc3QuTW9jaykubW9ja1Jlc29sdmVkVmFsdWUoe1xyXG4gICAgICAgIGlkOiAxLFxyXG4gICAgICAgIHR5cGVDb2RlOiAnTEVUVEVSJyxcclxuICAgICAgfSk7XHJcbiAgICAgIChzdGF0dXNSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgc3RhdHVzQ29kZTogJ0RSQUZUJyxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAobnVtYmVyaW5nU2VydmljZS5nZW5lcmF0ZU5leHROdW1iZXIgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgbnVtYmVyOiAnRE9DLTAwMScsXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgbW9ja0RhdGFTb3VyY2UubWFuYWdlci5maW5kT25lXHJcbiAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7IGlkOiAxMCwgb3JnYW5pemF0aW9uQ29kZTogJ09SRycgfSlcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDIwLCBvcmdhbml6YXRpb25Db2RlOiAnUkVDJyB9KTtcclxuXHJcbiAgICAgIGNvbnN0IHF1ZXJ5UnVubmVyID0ge1xyXG4gICAgICAgIGNvbm5lY3Q6IGplc3QuZm4oKSxcclxuICAgICAgICBzdGFydFRyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgICAgY29tbWl0VHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICByb2xsYmFja1RyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgICAgcmVsZWFzZTogamVzdC5mbigpLFxyXG4gICAgICAgIG1hbmFnZXI6IHtcclxuICAgICAgICAgIGNyZWF0ZTogamVzdC5mbihcclxuICAgICAgICAgICAgKF9lbnRpdHk6IHVua25vd24sIHBheWxvYWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiBwYXlsb2FkXHJcbiAgICAgICAgICApLFxyXG4gICAgICAgICAgc2F2ZTogamVzdFxyXG4gICAgICAgICAgICAuZm4oKVxyXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDk5OSwgcHVibGljSWQ6ICdjb3JyLXV1aWQnIH0pXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogMTAwMCB9KVxyXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKFtdKSxcclxuICAgICAgICAgIGZpbmRPbmU6IGplc3QuZm4oKSxcclxuICAgICAgICB9LFxyXG4gICAgICB9O1xyXG5cclxuICAgICAgKG1vY2tEYXRhU291cmNlLmNyZWF0ZVF1ZXJ5UnVubmVyIGFzIGplc3QuTW9jaykubW9ja1JldHVyblZhbHVlKFxyXG4gICAgICAgIHF1ZXJ5UnVubmVyXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBhd2FpdCBzZXJ2aWNlLmNyZWF0ZShjcmVhdGVEdG8sIG1vY2tVc2VyKTtcclxuXHJcbiAgICAgIGV4cGVjdChxdWVyeVJ1bm5lci5tYW5hZ2VyLmNyZWF0ZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoXHJcbiAgICAgICAgQ29ycmVzcG9uZGVuY2VSZXZpc2lvbixcclxuICAgICAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7IHJldmlzaW9uTGFiZWw6IG51bGwgfSlcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGl0KCdzaG91bGQgc2V0IHJldmlzaW9uTGFiZWwgdG8gbnVsbCBmb3IgTUVNTyB0eXBlJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgICBjb25zdCBtb2NrVXNlciA9IHtcclxuICAgICAgICB1c2VyX2lkOiAxLFxyXG4gICAgICAgIHByaW1hcnlPcmdhbml6YXRpb25JZDogMTAsXHJcbiAgICAgIH0gYXMgdW5rbm93biBhcyBVc2VyO1xyXG5cclxuICAgICAgY29uc3QgY3JlYXRlRHRvOiBDcmVhdGVDb3JyZXNwb25kZW5jZUR0byA9IHtcclxuICAgICAgICBwcm9qZWN0SWQ6ICdwcm9qZWN0LXV1aWQnLFxyXG4gICAgICAgIHR5cGVJZDogMSxcclxuICAgICAgICBzdWJqZWN0OiAnVGVzdCBTdWJqZWN0JyxcclxuICAgICAgICByZWNpcGllbnRzOiBbeyBvcmdhbml6YXRpb25JZDogJ3JlY2lwaWVudC11dWlkJywgdHlwZTogJ1RPJyB9XSxcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGNvbnN0IHR5cGVSZXBvID0gdGVzdGluZ01vZHVsZS5nZXQ8UmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVR5cGU+PihcclxuICAgICAgICBnZXRSZXBvc2l0b3J5VG9rZW4oQ29ycmVzcG9uZGVuY2VUeXBlKVxyXG4gICAgICApO1xyXG4gICAgICBjb25zdCBzdGF0dXNSZXBvID0gdGVzdGluZ01vZHVsZS5nZXQ8UmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVN0YXR1cz4+KFxyXG4gICAgICAgIGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVN0YXR1cylcclxuICAgICAgKTtcclxuICAgICAgY29uc3QgdXVpZFJlc29sdmVyID1cclxuICAgICAgICB0ZXN0aW5nTW9kdWxlLmdldDxVdWlkUmVzb2x2ZXJTZXJ2aWNlPihVdWlkUmVzb2x2ZXJTZXJ2aWNlKTtcclxuXHJcbiAgICAgICh1dWlkUmVzb2x2ZXIucmVzb2x2ZVByb2plY3RJZCBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKDEwMCk7XHJcbiAgICAgICh1dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkIGFzIGplc3QuTW9jaykubW9ja1Jlc29sdmVkVmFsdWUoMjApO1xyXG5cclxuICAgICAgKHR5cGVSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgdHlwZUNvZGU6ICdNRU1PJyxcclxuICAgICAgfSk7XHJcbiAgICAgIChzdGF0dXNSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgc3RhdHVzQ29kZTogJ0RSQUZUJyxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAobnVtYmVyaW5nU2VydmljZS5nZW5lcmF0ZU5leHROdW1iZXIgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgbnVtYmVyOiAnRE9DLTAwMScsXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgbW9ja0RhdGFTb3VyY2UubWFuYWdlci5maW5kT25lXHJcbiAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7IGlkOiAxMCwgb3JnYW5pemF0aW9uQ29kZTogJ09SRycgfSlcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDIwLCBvcmdhbml6YXRpb25Db2RlOiAnUkVDJyB9KTtcclxuXHJcbiAgICAgIGNvbnN0IHF1ZXJ5UnVubmVyID0ge1xyXG4gICAgICAgIGNvbm5lY3Q6IGplc3QuZm4oKSxcclxuICAgICAgICBzdGFydFRyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgICAgY29tbWl0VHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICByb2xsYmFja1RyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgICAgcmVsZWFzZTogamVzdC5mbigpLFxyXG4gICAgICAgIG1hbmFnZXI6IHtcclxuICAgICAgICAgIGNyZWF0ZTogamVzdC5mbihcclxuICAgICAgICAgICAgKF9lbnRpdHk6IHVua25vd24sIHBheWxvYWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiBwYXlsb2FkXHJcbiAgICAgICAgICApLFxyXG4gICAgICAgICAgc2F2ZTogamVzdFxyXG4gICAgICAgICAgICAuZm4oKVxyXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDk5OSwgcHVibGljSWQ6ICdjb3JyLXV1aWQnIH0pXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogMTAwMCB9KVxyXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKFtdKSxcclxuICAgICAgICAgIGZpbmRPbmU6IGplc3QuZm4oKSxcclxuICAgICAgICB9LFxyXG4gICAgICB9O1xyXG5cclxuICAgICAgKG1vY2tEYXRhU291cmNlLmNyZWF0ZVF1ZXJ5UnVubmVyIGFzIGplc3QuTW9jaykubW9ja1JldHVyblZhbHVlKFxyXG4gICAgICAgIHF1ZXJ5UnVubmVyXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBhd2FpdCBzZXJ2aWNlLmNyZWF0ZShjcmVhdGVEdG8sIG1vY2tVc2VyKTtcclxuXHJcbiAgICAgIGV4cGVjdChxdWVyeVJ1bm5lci5tYW5hZ2VyLmNyZWF0ZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoXHJcbiAgICAgICAgQ29ycmVzcG9uZGVuY2VSZXZpc2lvbixcclxuICAgICAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7IHJldmlzaW9uTGFiZWw6IG51bGwgfSlcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59KTtcclxuIl0sInZlcnNpb24iOjN9 \ No newline at end of file diff --git a/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/3e/correspondenceservicespec_3ec95775e6a66568410dc80a476cb50b.map b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/3e/correspondenceservicespec_3ec95775e6a66568410dc80a476cb50b.map new file mode 100644 index 0000000..53056ca --- /dev/null +++ b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/3e/correspondenceservicespec_3ec95775e6a66568410dc80a476cb50b.map @@ -0,0 +1 @@ +{"file":"E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.spec.ts","mappings":"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","names":[],"sources":["E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.spec.ts"],"sourcesContent":["import { Test, TestingModule } from '@nestjs/testing';\r\nimport { getRepositoryToken } from '@nestjs/typeorm';\r\nimport { DataSource, Repository } from 'typeorm';\r\nimport { CorrespondenceService } from './correspondence.service';\r\nimport { Correspondence } from './entities/correspondence.entity';\r\nimport { CorrespondenceRevision } from './entities/correspondence-revision.entity';\r\nimport { CorrespondenceType } from './entities/correspondence-type.entity';\r\nimport { CorrespondenceStatus } from './entities/correspondence-status.entity';\r\nimport { CorrespondenceReference } from './entities/correspondence-reference.entity';\r\nimport { CorrespondenceTag } from './entities/correspondence-tag.entity';\r\nimport { Organization } from '../organization/entities/organization.entity';\r\nimport { CorrespondenceRecipient } from './entities/correspondence-recipient.entity';\r\nimport { DocumentNumberingService } from '../document-numbering/services/document-numbering.service';\r\nimport { JsonSchemaService } from '../json-schema/json-schema.service';\r\nimport { WorkflowEngineService } from '../workflow-engine/workflow-engine.service';\r\nimport { UserService } from '../user/user.service';\r\nimport { SearchService } from '../search/search.service';\r\nimport { FileStorageService } from '../../common/file-storage/file-storage.service';\r\nimport { UuidResolverService } from '../../common/services/uuid-resolver.service';\r\nimport { NotificationService } from '../notification/notification.service';\r\nimport { UpdateCorrespondenceDto } from './dto/update-correspondence.dto';\r\nimport { CreateCorrespondenceDto } from './dto/create-correspondence.dto';\r\nimport { User } from '../user/entities/user.entity';\r\n\r\ndescribe('CorrespondenceService', () => {\r\n let service: CorrespondenceService;\r\n let numberingService: DocumentNumberingService;\r\n let correspondenceRepo: Repository;\r\n let revisionRepo: Repository;\r\n let testingModule: TestingModule;\r\n let _dataSource: DataSource;\r\n\r\n const createMockRepository = () => ({\r\n find: jest.fn(),\r\n findOne: jest.fn(),\r\n create: jest.fn(),\r\n save: jest.fn(),\r\n update: jest.fn(),\r\n delete: jest.fn(),\r\n softDelete: jest.fn(),\r\n createQueryBuilder: jest.fn(() => ({\r\n leftJoinAndSelect: jest.fn().mockReturnThis(),\r\n where: jest.fn().mockReturnThis(),\r\n andWhere: jest.fn().mockReturnThis(),\r\n orderBy: jest.fn().mockReturnThis(),\r\n skip: jest.fn().mockReturnThis(),\r\n take: jest.fn().mockReturnThis(),\r\n getOne: jest.fn().mockResolvedValue(null),\r\n getMany: jest.fn().mockResolvedValue([]),\r\n getManyAndCount: jest.fn().mockResolvedValue([[], 0]),\r\n })),\r\n });\r\n\r\n const mockDataSource = {\r\n createQueryRunner: jest.fn(() => ({\r\n connect: jest.fn(),\r\n startTransaction: jest.fn(),\r\n commitTransaction: jest.fn(),\r\n rollbackTransaction: jest.fn(),\r\n release: jest.fn(),\r\n manager: {\r\n create: jest.fn(),\r\n save: jest.fn(),\r\n findOne: jest.fn(),\r\n },\r\n })),\r\n getRepository: jest.fn(() => createMockRepository()),\r\n manager: {\r\n findOne: jest.fn(),\r\n },\r\n };\r\n\r\n beforeEach(async () => {\r\n testingModule = await Test.createTestingModule({\r\n providers: [\r\n CorrespondenceService,\r\n {\r\n provide: getRepositoryToken(Correspondence),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(CorrespondenceRevision),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(CorrespondenceType),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(CorrespondenceStatus),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(CorrespondenceReference),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(CorrespondenceTag),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(Organization),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(CorrespondenceRecipient),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: DocumentNumberingService,\r\n useValue: {\r\n generateNextNumber: jest.fn(),\r\n updateNumberForDraft: jest.fn(),\r\n previewNextNumber: jest.fn(),\r\n },\r\n },\r\n {\r\n provide: JsonSchemaService,\r\n useValue: { validate: jest.fn() },\r\n },\r\n {\r\n provide: WorkflowEngineService,\r\n useValue: { createInstance: jest.fn() },\r\n },\r\n {\r\n provide: UserService,\r\n useValue: {\r\n findOne: jest.fn(),\r\n getUserPermissions: jest.fn().mockResolvedValue([]),\r\n },\r\n },\r\n {\r\n provide: DataSource,\r\n useValue: mockDataSource,\r\n },\r\n {\r\n provide: SearchService,\r\n useValue: { indexDocument: jest.fn() },\r\n },\r\n {\r\n provide: FileStorageService,\r\n useValue: { commit: jest.fn().mockResolvedValue([]) },\r\n },\r\n {\r\n provide: UuidResolverService,\r\n useValue: {\r\n resolveProjectId: jest.fn().mockResolvedValue(1),\r\n resolveOrganizationId: jest.fn().mockResolvedValue(1),\r\n },\r\n },\r\n {\r\n provide: NotificationService,\r\n useValue: { send: jest.fn().mockResolvedValue(undefined) },\r\n },\r\n ],\r\n }).compile();\r\n\r\n service = testingModule.get(CorrespondenceService);\r\n numberingService = testingModule.get(\r\n DocumentNumberingService\r\n );\r\n correspondenceRepo = testingModule.get>(\r\n getRepositoryToken(Correspondence)\r\n );\r\n revisionRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceRevision)\r\n );\r\n _dataSource = testingModule.get(DataSource);\r\n });\r\n\r\n it('should be defined', () => {\r\n expect(service).toBeDefined();\r\n });\r\n\r\n describe('update', () => {\r\n it('should NOT regenerate number if critical fields unchanged', async () => {\r\n const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;\r\n const mockRevision = {\r\n id: 100,\r\n correspondenceId: 1,\r\n isCurrent: true,\r\n statusId: 5,\r\n };\r\n\r\n jest\r\n .spyOn(revisionRepo, 'findOne')\r\n .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);\r\n\r\n const mockCorr = {\r\n id: 1,\r\n projectId: 1,\r\n correspondenceTypeId: 2,\r\n disciplineId: 3,\r\n originatorId: 10,\r\n correspondenceNumber: 'OLD-NUM',\r\n recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],\r\n };\r\n jest\r\n .spyOn(correspondenceRepo, 'findOne')\r\n .mockResolvedValue(mockCorr as unknown as Correspondence);\r\n\r\n const updateDto: UpdateCorrespondenceDto = {\r\n projectId: 1,\r\n disciplineId: 3,\r\n };\r\n\r\n await service.update(1, updateDto, mockUser);\r\n\r\n expect(\r\n numberingService.updateNumberForDraft as jest.Mock\r\n ).not.toHaveBeenCalled();\r\n });\r\n\r\n it('should regenerate number if Project ID changes', async () => {\r\n const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;\r\n const mockRevision = {\r\n id: 100,\r\n correspondenceId: 1,\r\n isCurrent: true,\r\n statusId: 5,\r\n };\r\n jest\r\n .spyOn(revisionRepo, 'findOne')\r\n .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);\r\n\r\n const mockCorr = {\r\n id: 1,\r\n projectId: 1,\r\n correspondenceTypeId: 2,\r\n disciplineId: 3,\r\n originatorId: 10,\r\n correspondenceNumber: 'OLD-NUM',\r\n recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],\r\n };\r\n jest\r\n .spyOn(correspondenceRepo, 'findOne')\r\n .mockResolvedValue(mockCorr as unknown as Correspondence);\r\n\r\n const updateDto: UpdateCorrespondenceDto = {\r\n projectId: 2,\r\n };\r\n\r\n const uuidResolver =\r\n testingModule.get(UuidResolverService);\r\n (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(2);\r\n\r\n await service.update(1, updateDto, mockUser);\r\n\r\n expect(\r\n numberingService.updateNumberForDraft as jest.Mock\r\n ).toHaveBeenCalled();\r\n });\r\n\r\n it('should regenerate number if Document Type changes', async () => {\r\n const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;\r\n const mockRevision = {\r\n id: 100,\r\n correspondenceId: 1,\r\n isCurrent: true,\r\n statusId: 5,\r\n };\r\n jest\r\n .spyOn(revisionRepo, 'findOne')\r\n .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);\r\n\r\n const mockCorr = {\r\n id: 1,\r\n projectId: 1,\r\n correspondenceTypeId: 2,\r\n disciplineId: 3,\r\n originatorId: 10,\r\n correspondenceNumber: 'OLD-NUM',\r\n recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],\r\n };\r\n jest\r\n .spyOn(correspondenceRepo, 'findOne')\r\n .mockResolvedValue(mockCorr as unknown as Correspondence);\r\n\r\n const updateDto: UpdateCorrespondenceDto = {\r\n typeId: 999,\r\n };\r\n\r\n const typeRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceType)\r\n );\r\n (typeRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 999,\r\n typeCode: 'NEW-TYPE',\r\n });\r\n\r\n await service.update(1, updateDto, mockUser);\r\n\r\n expect(\r\n numberingService.updateNumberForDraft as jest.Mock\r\n ).toHaveBeenCalled();\r\n });\r\n\r\n it('should regenerate number if Recipient Organization changes', async () => {\r\n const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;\r\n const mockRevision = {\r\n id: 100,\r\n correspondenceId: 1,\r\n isCurrent: true,\r\n statusId: 5,\r\n };\r\n jest\r\n .spyOn(revisionRepo, 'findOne')\r\n .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);\r\n\r\n const mockCorr = {\r\n id: 1,\r\n projectId: 1,\r\n correspondenceTypeId: 2,\r\n disciplineId: 3,\r\n originatorId: 10,\r\n correspondenceNumber: 'OLD-NUM',\r\n recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],\r\n };\r\n jest\r\n .spyOn(correspondenceRepo, 'findOne')\r\n .mockResolvedValue(mockCorr as unknown as Correspondence);\r\n\r\n // Access DataSource manager for mocking\r\n mockDataSource.manager.findOne.mockResolvedValue({\r\n id: 88,\r\n organizationCode: 'NEW-ORG',\r\n } as unknown as Organization);\r\n\r\n const updateDto: UpdateCorrespondenceDto = {\r\n recipients: [{ type: 'TO', organizationId: 88 }],\r\n };\r\n\r\n await service.update(1, updateDto, mockUser);\r\n\r\n expect(\r\n numberingService.updateNumberForDraft as jest.Mock\r\n ).toHaveBeenCalled();\r\n });\r\n });\r\n\r\n describe('create', () => {\r\n it('should allow system.manage_all user without primaryOrganizationId when originatorId is provided', async () => {\r\n const mockUser = {\r\n user_id: 1,\r\n primaryOrganizationId: null,\r\n } as unknown as User;\r\n\r\n const createDto: CreateCorrespondenceDto = {\r\n projectId: 'project-uuid',\r\n typeId: 1,\r\n subject: 'Test Subject',\r\n originatorId: 'originator-uuid',\r\n recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],\r\n };\r\n\r\n const userService = testingModule.get(UserService);\r\n const typeRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceType)\r\n );\r\n const statusRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceStatus)\r\n );\r\n const uuidResolver =\r\n testingModule.get(UuidResolverService);\r\n\r\n (userService.findOne as jest.Mock).mockResolvedValue({\r\n user_id: 1,\r\n primaryOrganizationId: null,\r\n });\r\n (userService.getUserPermissions as jest.Mock).mockResolvedValue([\r\n 'system.manage_all',\r\n ]);\r\n\r\n (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);\r\n (uuidResolver.resolveOrganizationId as jest.Mock).mockImplementation(\r\n (value: number | string) => {\r\n if (value === 'originator-uuid') return 10;\r\n if (value === 'recipient-uuid') return 20;\r\n return 0;\r\n }\r\n );\r\n\r\n (typeRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n typeCode: 'LTR',\r\n });\r\n (statusRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n statusCode: 'DRAFT',\r\n });\r\n\r\n (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({\r\n number: 'DOC-001',\r\n });\r\n\r\n mockDataSource.manager.findOne\r\n .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })\r\n .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });\r\n\r\n const queryRunner = {\r\n connect: jest.fn(),\r\n startTransaction: jest.fn(),\r\n commitTransaction: jest.fn(),\r\n rollbackTransaction: jest.fn(),\r\n release: jest.fn(),\r\n manager: {\r\n create: jest.fn(\r\n (_entity: unknown, payload: Record) => payload\r\n ),\r\n save: jest\r\n .fn()\r\n .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })\r\n .mockResolvedValueOnce({ id: 1000 })\r\n .mockResolvedValueOnce([]),\r\n findOne: jest.fn(),\r\n },\r\n };\r\n\r\n (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(\r\n queryRunner\r\n );\r\n\r\n await service.create(createDto, mockUser);\r\n\r\n expect(queryRunner.manager.create).toHaveBeenCalledWith(\r\n Correspondence,\r\n expect.objectContaining({ originatorId: 10 })\r\n );\r\n });\r\n\r\n it('should set revisionLabel to \"A\" for RFA type', async () => {\r\n const mockUser = {\r\n user_id: 1,\r\n primaryOrganizationId: 10,\r\n } as unknown as User;\r\n\r\n const createDto: CreateCorrespondenceDto = {\r\n projectId: 'project-uuid',\r\n typeId: 1,\r\n subject: 'Test Subject',\r\n recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],\r\n };\r\n\r\n const typeRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceType)\r\n );\r\n const statusRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceStatus)\r\n );\r\n const uuidResolver =\r\n testingModule.get(UuidResolverService);\r\n\r\n (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);\r\n (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20);\r\n\r\n (typeRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n typeCode: 'RFA',\r\n });\r\n (statusRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n statusCode: 'DRAFT',\r\n });\r\n\r\n (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({\r\n number: 'DOC-001',\r\n });\r\n\r\n mockDataSource.manager.findOne\r\n .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })\r\n .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });\r\n\r\n const queryRunner = {\r\n connect: jest.fn(),\r\n startTransaction: jest.fn(),\r\n commitTransaction: jest.fn(),\r\n rollbackTransaction: jest.fn(),\r\n release: jest.fn(),\r\n manager: {\r\n create: jest.fn(\r\n (_entity: unknown, payload: Record) => payload\r\n ),\r\n save: jest\r\n .fn()\r\n .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })\r\n .mockResolvedValueOnce({ id: 1000 })\r\n .mockResolvedValueOnce([]),\r\n findOne: jest.fn(),\r\n },\r\n };\r\n\r\n (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(\r\n queryRunner\r\n );\r\n\r\n await service.create(createDto, mockUser);\r\n\r\n expect(queryRunner.manager.create).toHaveBeenCalledWith(\r\n CorrespondenceRevision,\r\n expect.objectContaining({ revisionLabel: 'A' })\r\n );\r\n });\r\n\r\n it('should set revisionLabel to \"A\" for RFI type', async () => {\r\n const mockUser = {\r\n user_id: 1,\r\n primaryOrganizationId: 10,\r\n } as unknown as User;\r\n\r\n const createDto: CreateCorrespondenceDto = {\r\n projectId: 'project-uuid',\r\n typeId: 1,\r\n subject: 'Test Subject',\r\n recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],\r\n };\r\n\r\n const typeRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceType)\r\n );\r\n const statusRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceStatus)\r\n );\r\n const uuidResolver =\r\n testingModule.get(UuidResolverService);\r\n\r\n (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);\r\n (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20);\r\n\r\n (typeRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n typeCode: 'RFI',\r\n });\r\n (statusRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n statusCode: 'DRAFT',\r\n });\r\n\r\n (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({\r\n number: 'DOC-001',\r\n });\r\n\r\n mockDataSource.manager.findOne\r\n .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })\r\n .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });\r\n\r\n const queryRunner = {\r\n connect: jest.fn(),\r\n startTransaction: jest.fn(),\r\n commitTransaction: jest.fn(),\r\n rollbackTransaction: jest.fn(),\r\n release: jest.fn(),\r\n manager: {\r\n create: jest.fn(\r\n (_entity: unknown, payload: Record) => payload\r\n ),\r\n save: jest\r\n .fn()\r\n .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })\r\n .mockResolvedValueOnce({ id: 1000 })\r\n .mockResolvedValueOnce([]),\r\n findOne: jest.fn(),\r\n },\r\n };\r\n\r\n (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(\r\n queryRunner\r\n );\r\n\r\n await service.create(createDto, mockUser);\r\n\r\n expect(queryRunner.manager.create).toHaveBeenCalledWith(\r\n CorrespondenceRevision,\r\n expect.objectContaining({ revisionLabel: 'A' })\r\n );\r\n });\r\n\r\n it('should set revisionLabel to null for LETTER type', async () => {\r\n const mockUser = {\r\n user_id: 1,\r\n primaryOrganizationId: 10,\r\n } as unknown as User;\r\n\r\n const createDto: CreateCorrespondenceDto = {\r\n projectId: 'project-uuid',\r\n typeId: 1,\r\n subject: 'Test Subject',\r\n recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],\r\n };\r\n\r\n const typeRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceType)\r\n );\r\n const statusRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceStatus)\r\n );\r\n const uuidResolver =\r\n testingModule.get(UuidResolverService);\r\n\r\n (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);\r\n (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20);\r\n\r\n (typeRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n typeCode: 'LETTER',\r\n });\r\n (statusRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n statusCode: 'DRAFT',\r\n });\r\n\r\n (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({\r\n number: 'DOC-001',\r\n });\r\n\r\n mockDataSource.manager.findOne\r\n .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })\r\n .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });\r\n\r\n const queryRunner = {\r\n connect: jest.fn(),\r\n startTransaction: jest.fn(),\r\n commitTransaction: jest.fn(),\r\n rollbackTransaction: jest.fn(),\r\n release: jest.fn(),\r\n manager: {\r\n create: jest.fn(\r\n (_entity: unknown, payload: Record) => payload\r\n ),\r\n save: jest\r\n .fn()\r\n .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })\r\n .mockResolvedValueOnce({ id: 1000 })\r\n .mockResolvedValueOnce([]),\r\n findOne: jest.fn(),\r\n },\r\n };\r\n\r\n (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(\r\n queryRunner\r\n );\r\n\r\n await service.create(createDto, mockUser);\r\n\r\n expect(queryRunner.manager.create).toHaveBeenCalledWith(\r\n CorrespondenceRevision,\r\n expect.objectContaining({ revisionLabel: null })\r\n );\r\n });\r\n\r\n it('should set revisionLabel to null for MEMO type', async () => {\r\n const mockUser = {\r\n user_id: 1,\r\n primaryOrganizationId: 10,\r\n } as unknown as User;\r\n\r\n const createDto: CreateCorrespondenceDto = {\r\n projectId: 'project-uuid',\r\n typeId: 1,\r\n subject: 'Test Subject',\r\n recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],\r\n };\r\n\r\n const typeRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceType)\r\n );\r\n const statusRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceStatus)\r\n );\r\n const uuidResolver =\r\n testingModule.get(UuidResolverService);\r\n\r\n (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);\r\n (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20);\r\n\r\n (typeRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n typeCode: 'MEMO',\r\n });\r\n (statusRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n statusCode: 'DRAFT',\r\n });\r\n\r\n (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({\r\n number: 'DOC-001',\r\n });\r\n\r\n mockDataSource.manager.findOne\r\n .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })\r\n .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });\r\n\r\n const queryRunner = {\r\n connect: jest.fn(),\r\n startTransaction: jest.fn(),\r\n commitTransaction: jest.fn(),\r\n rollbackTransaction: jest.fn(),\r\n release: jest.fn(),\r\n manager: {\r\n create: jest.fn(\r\n (_entity: unknown, payload: Record) => payload\r\n ),\r\n save: jest\r\n .fn()\r\n .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })\r\n .mockResolvedValueOnce({ id: 1000 })\r\n .mockResolvedValueOnce([]),\r\n findOne: jest.fn(),\r\n },\r\n };\r\n\r\n (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(\r\n queryRunner\r\n );\r\n\r\n await service.create(createDto, mockUser);\r\n\r\n expect(queryRunner.manager.create).toHaveBeenCalledWith(\r\n CorrespondenceRevision,\r\n expect.objectContaining({ revisionLabel: null })\r\n );\r\n });\r\n });\r\n});\r\n"],"version":3} \ No newline at end of file diff --git a/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/50/correspondenceservice_502139c633196704eef09d9c7ce64dc0 b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/50/correspondenceservice_502139c633196704eef09d9c7ce64dc0 new file mode 100644 index 0000000..2d2ada4 --- /dev/null +++ b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/50/correspondenceservice_502139c633196704eef09d9c7ce64dc0 @@ -0,0 +1,893 @@ +f6b8b3a06a5f56cde244a136c6d4bc18 +"use strict"; +// File: src/modules/correspondence/correspondence.service.ts +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +var __param = (this && this.__param) || function (paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +}; +var CorrespondenceService_1; +var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CorrespondenceService = void 0; +const common_1 = require("@nestjs/common"); +const typeorm_1 = require("@nestjs/typeorm"); +const typeorm_2 = require("typeorm"); +// Entities +const correspondence_entity_1 = require("./entities/correspondence.entity"); +const correspondence_revision_entity_1 = require("./entities/correspondence-revision.entity"); +const correspondence_type_entity_1 = require("./entities/correspondence-type.entity"); +const correspondence_status_entity_1 = require("./entities/correspondence-status.entity"); +const correspondence_reference_entity_1 = require("./entities/correspondence-reference.entity"); +const correspondence_recipient_entity_1 = require("./entities/correspondence-recipient.entity"); +const correspondence_tag_entity_1 = require("./entities/correspondence-tag.entity"); +const tag_entity_1 = require("../master/entities/tag.entity"); +const organization_entity_1 = require("../organization/entities/organization.entity"); +// Services +const document_numbering_service_1 = require("../document-numbering/services/document-numbering.service"); +const json_schema_service_1 = require("../json-schema/json-schema.service"); +const workflow_engine_service_1 = require("../workflow-engine/workflow-engine.service"); +const user_service_1 = require("../user/user.service"); +const search_service_1 = require("../search/search.service"); +const file_storage_service_1 = require("../../common/file-storage/file-storage.service"); +const uuid_resolver_service_1 = require("../../common/services/uuid-resolver.service"); +const notification_service_1 = require("../notification/notification.service"); +let CorrespondenceService = CorrespondenceService_1 = class CorrespondenceService { + async hasSystemManageAllPermission(userId) { + const permissions = await this.userService.getUserPermissions(userId); + return permissions.includes('system.manage_all'); + } + /** + * Business Rule: Revision Label Strategy + * - RFA, RFI: Use alphabet starting with 'A' (A, B, C...) + * - Other types (LETTER, MEMO, etc.): Use numeric (null for first, then 1, 2, 3...) + */ + getInitialRevisionLabel(typeCode) { + const alphabetTypes = ['RFA', 'RFI']; + if (alphabetTypes.includes(typeCode.toUpperCase())) { + return 'A'; // Alphabet for RFA, RFI + } + return null; // Numeric (null for revision 0) + } + constructor(correspondenceRepo, revisionRepo, typeRepo, statusRepo, referenceRepo, tagRepo, numberingService, jsonSchemaService, workflowEngine, userService, dataSource, searchService, fileStorageService, uuidResolver, notificationService) { + this.correspondenceRepo = correspondenceRepo; + this.revisionRepo = revisionRepo; + this.typeRepo = typeRepo; + this.statusRepo = statusRepo; + this.referenceRepo = referenceRepo; + this.tagRepo = tagRepo; + this.numberingService = numberingService; + this.jsonSchemaService = jsonSchemaService; + this.workflowEngine = workflowEngine; + this.userService = userService; + this.dataSource = dataSource; + this.searchService = searchService; + this.fileStorageService = fileStorageService; + this.uuidResolver = uuidResolver; + this.notificationService = notificationService; + this.logger = new common_1.Logger(CorrespondenceService_1.name); + } + /** + * Business Rule Validation: EC-CORR-003 - Correspondence to Self + * Prevent external correspondence to same organization + */ + async validateCorrespondenceRecipients(createDto, user) { + // Get user's organization + let userOrgId = user.primaryOrganizationId; + if (!userOrgId) { + const fullUser = await this.userService.findOne(user.user_id); + if (fullUser) { + userOrgId = fullUser.primaryOrganizationId; + } + } + if (!userOrgId) { + if (createDto.originatorId) { + const canManageAll = await this.hasSystemManageAllPermission(user.user_id); + if (canManageAll) { + userOrgId = await this.uuidResolver.resolveOrganizationId(createDto.originatorId); + } + } + if (!userOrgId) { + throw new common_1.BadRequestException('User must belong to an organization to create documents'); + } + } + // For impersonation, use the specified originator + const originatorOrgId = createDto.originatorId + ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId) + : userOrgId; + // Check if it's internal communication + if (createDto.isInternal) { + // Internal communications should use Circulation instead + throw new common_1.BadRequestException('Internal communications should use Circulation Sheet instead of Correspondence'); + } + // Validate recipients + if (!createDto.recipients || createDto.recipients.length === 0) { + throw new common_1.BadRequestException('At least one recipient (TO or CC) is required'); + } + const toRecipients = createDto.recipients.filter((r) => r.type === 'TO'); + const ccRecipients = createDto.recipients.filter((r) => r.type === 'CC'); + if (toRecipients.length === 0 && ccRecipients.length === 0) { + throw new common_1.BadRequestException('At least one TO or CC recipient is required'); + } + // Check for same organization correspondence + for (const recipient of createDto.recipients) { + const recipientOrgId = await this.uuidResolver.resolveOrganizationId(recipient.organizationId); + if (recipientOrgId === originatorOrgId) { + throw new common_1.BadRequestException('Cannot send correspondence to your own organization. Use Circulation Sheet for internal communication.'); + } + } + } + async create(createDto, user) { + // Business Rule Validation: EC-CORR-003 - Correspondence to Self + await this.validateCorrespondenceRecipients(createDto, user); + // ADR-019: Resolve UUID references to internal INT IDs + const resolvedProjectId = await this.uuidResolver.resolveProjectId(createDto.projectId); + const resolvedOriginatorId = createDto.originatorId + ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId) + : undefined; + const resolvedRecipients = createDto.recipients + ? await Promise.all(createDto.recipients.map(async (r) => ({ + organizationId: await this.uuidResolver.resolveOrganizationId(r.organizationId), + type: r.type, + }))) + : undefined; + const type = await this.typeRepo.findOne({ + where: { id: createDto.typeId }, + }); + if (!type) + throw new common_1.NotFoundException('Document Type not found'); + const statusDraft = await this.statusRepo.findOne({ + where: { statusCode: 'DRAFT' }, + }); + if (!statusDraft) { + throw new common_1.InternalServerErrorException('Status DRAFT not found in Master Data'); + } + let userOrgId = user.primaryOrganizationId; + if (!userOrgId) { + const fullUser = await this.userService.findOne(user.user_id); + if (fullUser) { + userOrgId = fullUser.primaryOrganizationId; + } + } + // Impersonation Logic + if (resolvedOriginatorId && resolvedOriginatorId !== userOrgId) { + const canManageAll = await this.hasSystemManageAllPermission(user.user_id); + if (!canManageAll) { + throw new common_1.ForbiddenException('You do not have permission to create documents on behalf of other organizations.'); + } + userOrgId = resolvedOriginatorId; + } + if (!userOrgId) { + throw new common_1.BadRequestException('User must belong to an organization to create documents'); + } + if (createDto.details) { + try { + await this.jsonSchemaService.validate(type.typeCode, createDto.details); + } + catch (error) { + this.logger.warn(`Schema validation warning for ${type.typeCode}: ${error.message}`); + } + } + const queryRunner = this.dataSource.createQueryRunner(); + await queryRunner.connect(); + await queryRunner.startTransaction(); + try { + // [Fix #6] Fetch real ORG Code from Organization entity + const originatorOrg = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { id: userOrgId }, + }); + const orgCode = originatorOrg?.organizationCode ?? 'UNK'; + // [v1.5.1] Extract recipient organization from recipients array (Primary TO) + const toRecipient = resolvedRecipients?.find((r) => r.type === 'TO'); + const recipientOrganizationId = toRecipient?.organizationId; + let recipientCode = ''; + if (recipientOrganizationId) { + const recOrg = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { id: recipientOrganizationId }, + }); + if (recOrg) + recipientCode = recOrg.organizationCode; + } + const docNumber = await this.numberingService.generateNextNumber({ + projectId: resolvedProjectId, + originatorOrganizationId: userOrgId, + typeId: createDto.typeId, + disciplineId: createDto.disciplineId, + subTypeId: createDto.subTypeId, + recipientOrganizationId, // [v1.5.1] Pass recipient for document number format + year: new Date().getFullYear(), + customTokens: { + TYPE_CODE: type.typeCode, + ORG_CODE: orgCode, + RECIPIENT_CODE: recipientCode, + REC_CODE: recipientCode, + }, + }); + const correspondence = queryRunner.manager.create(correspondence_entity_1.Correspondence, { + correspondenceNumber: docNumber.number, + correspondenceTypeId: createDto.typeId, + disciplineId: createDto.disciplineId, + projectId: resolvedProjectId, + originatorId: userOrgId, + isInternal: createDto.isInternal || false, + createdBy: user.user_id, + }); + const savedCorr = await queryRunner.manager.save(correspondence); + const revision = queryRunner.manager.create(correspondence_revision_entity_1.CorrespondenceRevision, { + correspondenceId: savedCorr.id, + revisionNumber: 0, + revisionLabel: 'A', + isCurrent: true, + statusId: statusDraft.id, + subject: createDto.subject, + body: createDto.body, + remarks: createDto.remarks, + dueDate: createDto.dueDate ? new Date(createDto.dueDate) : undefined, + documentDate: createDto.documentDate + ? new Date(createDto.documentDate) + : undefined, + issuedDate: createDto.issuedDate + ? new Date(createDto.issuedDate) + : undefined, + receivedDate: createDto.receivedDate + ? new Date(createDto.receivedDate) + : undefined, + description: createDto.description, + details: createDto.details, + createdBy: user.user_id, + schemaVersion: 1, + }); + await queryRunner.manager.save(revision); + // Save Recipients (using resolved INT IDs) + if (resolvedRecipients && resolvedRecipients.length > 0) { + const recipients = resolvedRecipients.map((r) => queryRunner.manager.create(correspondence_recipient_entity_1.CorrespondenceRecipient, { + correspondenceId: savedCorr.id, + recipientOrganizationId: r.organizationId, + recipientType: r.type, + })); + await queryRunner.manager.save(recipients); + } + // Commit attachments from Temp → Permanent (Two-Phase Storage) + if (createDto.attachmentTempIds?.length) { + const issueDate = createDto.issuedDate + ? new Date(createDto.issuedDate) + : createDto.documentDate + ? new Date(createDto.documentDate) + : undefined; + await this.fileStorageService.commit(createDto.attachmentTempIds, { + issueDate, + documentType: 'Correspondence', + }); + } + await queryRunner.commitTransaction(); + // Start Workflow Instance (non-blocking) + try { + const workflowCode = `CORRESPONDENCE_${type.typeCode}`; + await this.workflowEngine.createInstance(workflowCode, 'correspondence', savedCorr.id.toString(), { + projectId: resolvedProjectId, + originatorId: userOrgId, + disciplineId: createDto.disciplineId, + initiatorId: user.user_id, + }); + } + catch (error) { + this.logger.warn(`Workflow not started for ${docNumber.number} (Code: CORRESPONDENCE_${type.typeCode}): ${error.message}`); + } + // Fire-and-forget search indexing (non-blocking, void intentional) + void this.searchService.indexDocument({ + id: savedCorr.id, + publicId: savedCorr.publicId, + type: 'correspondence', + docNumber: docNumber.number, + title: createDto.subject, + description: createDto.description, + status: 'DRAFT', + projectId: resolvedProjectId, + createdAt: new Date(), + }); + return { + ...savedCorr, + currentRevision: revision, + }; + } + catch (err) { + await queryRunner.rollbackTransaction(); + this.logger.error(`Failed to create correspondence: ${err.message}`); + throw err; + } + finally { + await queryRunner.release(); + } + } + async findAll(searchDto = {}) { + const { search, typeId, projectId, statusId, status, page = 1, limit = 10, } = searchDto; + const skip = (page - 1) * limit; + // Change: Query from Revision Repo + const query = this.revisionRepo + .createQueryBuilder('rev') + .leftJoinAndSelect('rev.correspondence', 'corr') + .leftJoinAndSelect('corr.type', 'type') + .leftJoinAndSelect('corr.project', 'project') + .leftJoinAndSelect('corr.originator', 'org') + .leftJoinAndSelect('rev.status', 'status'); + // Filter by Revision Status + const revStatus = searchDto.revisionStatus || 'CURRENT'; + if (revStatus === 'CURRENT') { + query.where('rev.isCurrent = :isCurrent', { isCurrent: true }); + } + else if (revStatus === 'OLD') { + query.where('rev.isCurrent = :isCurrent', { isCurrent: false }); + } + // If 'ALL', no filter needed on isCurrent + if (projectId) { + query.andWhere('corr.projectId = :projectId', { projectId }); + } + if (typeId) { + query.andWhere('corr.correspondenceTypeId = :typeId', { typeId }); + } + if (statusId) { + query.andWhere('rev.statusId = :statusId', { statusId }); + } + if (status) { + query.andWhere('status.statusCode = :status', { status }); + } + if (search) { + query.andWhere('(corr.correspondenceNumber LIKE :search OR rev.subject LIKE :search)', { search: `%${search}%` }); + } + // Default Sort: Latest Created + query.orderBy('rev.createdAt', 'DESC').skip(skip).take(limit); + const [items, total] = await query.getManyAndCount(); + return { + data: items, + meta: { + total, + page, + limit, + totalPages: Math.ceil(total / limit), + }, + }; + } + async findOne(id) { + const correspondence = await this.correspondenceRepo.findOne({ + where: { id }, + relations: [ + 'revisions', + 'revisions.status', + 'type', + 'project', + 'originator', + 'recipients', + 'recipients.recipientOrganization', // [v1.5.1] Fixed relation name + ], + }); + if (!correspondence) { + throw new common_1.NotFoundException(`Correspondence with ID ${id} not found`); + } + return correspondence; + } + async findOneByUuid(publicId) { + const correspondence = await this.correspondenceRepo.findOne({ + where: { publicId }, + relations: [ + 'revisions', + 'revisions.status', + 'type', + 'project', + 'originator', + 'recipients', + 'recipients.recipientOrganization', + ], + }); + if (!correspondence) { + throw new common_1.NotFoundException(`Correspondence with UUID ${publicId} not found`); + } + return correspondence; + } + async addReference(id, dto) { + const source = await this.correspondenceRepo.findOne({ where: { id } }); + // ADR-019: Resolve target publicId → internal INT id + const target = await this.correspondenceRepo.findOne({ + where: { publicId: dto.targetUuid }, + }); + if (!source || !target) { + throw new common_1.NotFoundException('Source or Target correspondence not found'); + } + if (source.id === target.id) { + throw new common_1.BadRequestException('Cannot reference self'); + } + const exists = await this.referenceRepo.findOne({ + where: { + sourceId: id, + targetId: target.id, + }, + }); + if (exists) { + return exists; + } + const ref = this.referenceRepo.create({ + sourceId: id, + targetId: target.id, + }); + return this.referenceRepo.save(ref); + } + async removeReference(id, targetId) { + const result = await this.referenceRepo.delete({ + sourceId: id, + targetId: targetId, + }); + if (result.affected === 0) { + throw new common_1.NotFoundException('Reference not found'); + } + } + async getTags(id) { + const rows = await this.tagRepo.find({ + where: { correspondenceId: id }, + relations: ['tag'], + }); + return rows.map((r) => r.tag).filter(Boolean); + } + async addTag(id, tagId) { + const correspondence = await this.correspondenceRepo.findOne({ + where: { id }, + }); + if (!correspondence) { + throw new common_1.NotFoundException(`Correspondence ${id} not found`); + } + const tag = await this.dataSource.manager.findOne(tag_entity_1.Tag, { + where: { id: tagId }, + }); + if (!tag) { + throw new common_1.NotFoundException(`Tag ${tagId} not found`); + } + const exists = await this.tagRepo.findOne({ + where: { correspondenceId: id, tagId }, + }); + if (exists) + return exists; + const row = this.tagRepo.create({ correspondenceId: id, tagId }); + return this.tagRepo.save(row); + } + async removeTag(id, tagId) { + const result = await this.tagRepo.delete({ correspondenceId: id, tagId }); + if (result.affected === 0) { + throw new common_1.NotFoundException('Tag assignment not found'); + } + } + async getReferences(id) { + const outgoing = await this.referenceRepo.find({ + where: { sourceId: id }, + relations: ['target', 'target.type'], + }); + const incoming = await this.referenceRepo.find({ + where: { targetId: id }, + relations: ['source', 'source.type'], + }); + return { outgoing, incoming }; + } + async update(id, updateDto, user) { + // 1. Find Current Revision + const revision = await this.revisionRepo.findOne({ + where: { + correspondenceId: id, + isCurrent: true, + }, + relations: ['correspondence'], + }); + if (!revision) { + throw new common_1.NotFoundException(`Current revision for correspondence ${id} not found`); + } + // 2. Check Permission + if (revision.statusId) { + const status = await this.statusRepo.findOne({ + where: { id: revision.statusId }, + }); + if (status && status.statusCode !== 'DRAFT') { + throw new common_1.BadRequestException('Only DRAFT documents can be updated'); + } + } + // ADR-019: Resolve UUID references in update DTO + const updResolvedProjectId = updateDto.projectId + ? await this.uuidResolver.resolveProjectId(updateDto.projectId) + : undefined; + const updResolvedOriginatorId = updateDto.originatorId + ? await this.uuidResolver.resolveOrganizationId(updateDto.originatorId) + : undefined; + const updResolvedRecipients = updateDto.recipients + ? await Promise.all(updateDto.recipients.map(async (r) => ({ + organizationId: await this.uuidResolver.resolveOrganizationId(r.organizationId), + type: r.type, + }))) + : undefined; + // 3. Update Correspondence Entity if needed + const correspondenceUpdate = {}; + if (updateDto.disciplineId) + correspondenceUpdate.disciplineId = updateDto.disciplineId; + if (updResolvedProjectId) + correspondenceUpdate.projectId = updResolvedProjectId; + if (updResolvedOriginatorId) + correspondenceUpdate.originatorId = updResolvedOriginatorId; + if (Object.keys(correspondenceUpdate).length > 0) { + await this.correspondenceRepo.update(id, correspondenceUpdate); + } + // 4. Update Revision Entity + const revisionUpdate = {}; + if (updateDto.subject) + revisionUpdate.subject = updateDto.subject; + if (updateDto.body) + revisionUpdate.body = updateDto.body; + if (updateDto.remarks) + revisionUpdate.remarks = updateDto.remarks; + // Format Date correctly if string + if (updateDto.dueDate) + revisionUpdate.dueDate = new Date(updateDto.dueDate); + if (updateDto.documentDate) + revisionUpdate.documentDate = new Date(updateDto.documentDate); + if (updateDto.issuedDate) + revisionUpdate.issuedDate = new Date(updateDto.issuedDate); + if (updateDto.receivedDate) + revisionUpdate.receivedDate = new Date(updateDto.receivedDate); + if (updateDto.description) + revisionUpdate.description = updateDto.description; + if (updateDto.details) + revisionUpdate.details = updateDto.details; + if (Object.keys(revisionUpdate).length > 0) { + await this.revisionRepo.update(revision.id, revisionUpdate); + } + // 4.5 Commit new attachments from Temp → Permanent (Two-Phase Storage) + if (updateDto.attachmentTempIds?.length) { + const issueDate = updateDto.issuedDate + ? new Date(updateDto.issuedDate) + : updateDto.documentDate + ? new Date(updateDto.documentDate) + : revision.issuedDate || revision.documentDate || undefined; + await this.fileStorageService.commit(updateDto.attachmentTempIds, { + issueDate: issueDate ? new Date(issueDate) : undefined, + documentType: 'Correspondence', + }); + } + // 5. Update Recipients if provided + if (updResolvedRecipients) { + const recipientRepo = this.dataSource.getRepository(correspondence_recipient_entity_1.CorrespondenceRecipient); + await recipientRepo.delete({ correspondenceId: id }); + const newRecipients = updResolvedRecipients.map((r) => recipientRepo.create({ + correspondenceId: id, + recipientOrganizationId: r.organizationId, + recipientType: r.type, + })); + await recipientRepo.save(newRecipients); + } + // 6. Regenerate Document Number if structural fields changed (Recipient, Discipline, Type, Project) + // AND it is a DRAFT. + // Fetch fresh data for context and comparison + const currentCorr = await this.correspondenceRepo.findOne({ + where: { id }, + relations: ['type', 'recipients', 'recipients.recipientOrganization'], + }); + if (currentCorr) { + const currentToRecipient = currentCorr.recipients?.find((r) => r.recipientType === 'TO'); + const currentRecipientId = currentToRecipient?.recipientOrganizationId; + // Check for ACTUAL value changes + const isProjectChanged = updResolvedProjectId !== undefined && + updResolvedProjectId !== currentCorr.projectId; + const isOriginatorChanged = updResolvedOriginatorId !== undefined && + updResolvedOriginatorId !== currentCorr.originatorId; + const isDisciplineChanged = updateDto.disciplineId !== undefined && + updateDto.disciplineId !== currentCorr.disciplineId; + const isTypeChanged = updateDto.typeId !== undefined && + updateDto.typeId !== currentCorr.correspondenceTypeId; + let isRecipientChanged = false; + let newRecipientId; + if (updResolvedRecipients) { + const newToRecipient = updResolvedRecipients.find((r) => r.type === 'TO'); + newRecipientId = newToRecipient?.organizationId; + if (newRecipientId !== currentRecipientId) { + isRecipientChanged = true; + } + } + if (isProjectChanged || + isDisciplineChanged || + isTypeChanged || + isRecipientChanged || + isOriginatorChanged) { + const targetRecipientId = isRecipientChanged + ? newRecipientId + : currentRecipientId; + // Resolve Recipient Code for the NEW context + let recipientCode = ''; + if (targetRecipientId) { + const recOrg = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { id: targetRecipientId }, + }); + if (recOrg) + recipientCode = recOrg.organizationCode; + } + // [Fix #6] Fetch real ORG Code from originator organization + const originatorOrgForUpdate = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { + id: updResolvedOriginatorId ?? currentCorr.originatorId ?? 0, + }, + }); + const orgCode = originatorOrgForUpdate?.organizationCode ?? 'UNK'; + // Prepare Contexts + const oldCtx = { + projectId: currentCorr.projectId, + originatorOrganizationId: currentCorr.originatorId ?? 0, + typeId: currentCorr.correspondenceTypeId, + disciplineId: currentCorr.disciplineId, + recipientOrganizationId: currentRecipientId, + year: new Date().getFullYear(), + }; + const newCtx = { + projectId: updResolvedProjectId ?? currentCorr.projectId, + originatorOrganizationId: updResolvedOriginatorId ?? currentCorr.originatorId ?? 0, + typeId: updateDto.typeId ?? currentCorr.correspondenceTypeId, + disciplineId: updateDto.disciplineId ?? currentCorr.disciplineId, + recipientOrganizationId: targetRecipientId, + year: new Date().getFullYear(), + userId: user.user_id, // Pass User ID for Audit + customTokens: { + TYPE_CODE: currentCorr.type?.typeCode || '', + ORG_CODE: orgCode, + RECIPIENT_CODE: recipientCode, + REC_CODE: recipientCode, + }, + }; + // If Type Changed, need NEW Type Code + if (isTypeChanged) { + const newType = await this.typeRepo.findOne({ + where: { id: newCtx.typeId }, + }); + if (newType) + newCtx.customTokens.TYPE_CODE = newType.typeCode; + } + const newDocNumber = await this.numberingService.updateNumberForDraft(currentCorr.correspondenceNumber, oldCtx, newCtx); + await this.correspondenceRepo.update(id, { + correspondenceNumber: newDocNumber, + }); + } + } + const updated = await this.findOne(id); + // Re-index updated document in Elasticsearch (fire-and-forget) + void this.searchService.indexDocument({ + id: updated.id, + publicId: updated.publicId, + type: 'correspondence', + docNumber: updated.correspondenceNumber, + title: updateDto.subject ?? updated.revisions?.[0]?.subject, + description: updateDto.description ?? updated.revisions?.[0]?.description, + status: 'DRAFT', + projectId: updated.projectId, + createdAt: updated.createdAt, + }); + return updated; + } + async previewDocumentNumber(createDto, user) { + // ADR-019: Resolve UUID references + const previewProjectId = await this.uuidResolver.resolveProjectId(createDto.projectId); + const previewOriginatorId = createDto.originatorId + ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId) + : undefined; + const previewRecipients = createDto.recipients + ? await Promise.all(createDto.recipients.map(async (r) => ({ + organizationId: await this.uuidResolver.resolveOrganizationId(r.organizationId), + type: r.type, + }))) + : undefined; + const type = await this.typeRepo.findOne({ + where: { id: createDto.typeId }, + }); + if (!type) + throw new common_1.NotFoundException('Document Type not found'); + let userOrgId = user.primaryOrganizationId; + if (!userOrgId) { + const fullUser = await this.userService.findOne(user.user_id); + if (fullUser) + userOrgId = fullUser.primaryOrganizationId; + } + if (previewOriginatorId && previewOriginatorId !== userOrgId) { + // Allow impersonation for preview + userOrgId = previewOriginatorId; + } + // Extract recipient from recipients array + const toRecipient = previewRecipients?.find((r) => r.type === 'TO'); + const recipientOrganizationId = toRecipient?.organizationId; + let recipientCode = ''; + if (recipientOrganizationId) { + const recOrg = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { id: recipientOrganizationId }, + }); + if (recOrg) + recipientCode = recOrg.organizationCode; + } + return this.numberingService.previewNumber({ + projectId: previewProjectId, + originatorOrganizationId: userOrgId, + typeId: createDto.typeId, + disciplineId: createDto.disciplineId, + subTypeId: createDto.subTypeId, + recipientOrganizationId, + year: new Date().getFullYear(), + customTokens: { + TYPE_CODE: type.typeCode, + RECIPIENT_CODE: recipientCode, + REC_CODE: recipientCode, + }, + }); + } + /** + * Business Rule Implementation: EC-CORR-001 - Cancel Correspondence with Downstream Circulation + * Cancel correspondence and handle related circulations + */ + async cancel(publicId, reason, user) { + const correspondence = await this.findOneByUuid(publicId); + // Check if user has permission to cancel (Org Admin or Superadmin only) + const permissions = await this.userService.getUserPermissions(user.user_id); + const canCancel = permissions.includes('correspondence.cancel') || + permissions.includes('system.manage_all'); + if (!canCancel) { + throw new common_1.ForbiddenException('Only administrators can cancel correspondences'); + } + // Check if there are any active circulations + const circulationRepo = this.dataSource.getRepository('Circulation'); + const activeCirculations = await circulationRepo.find({ + where: { + correspondenceId: correspondence.id, + status: 'OPEN', + }, + }); + const warningMessage = activeCirculations.length > 0 + ? `There are ${activeCirculations.length} active circulation(s) for this correspondence. Canceling will force close all related circulations.` + : ''; + // Get the current revision to update status + const currentRevision = await this.revisionRepo.findOne({ + where: { + correspondenceId: correspondence.id, + isCurrent: true, + }, + }); + if (!currentRevision) { + throw new common_1.NotFoundException('Current revision not found'); + } + // Get cancelled status + const cancelledStatus = await this.statusRepo.findOne({ + where: { statusCode: 'CANCELLED' }, + }); + if (!cancelledStatus) { + throw new common_1.InternalServerErrorException('CANCELLED status not found'); + } + const queryRunner = this.dataSource.createQueryRunner(); + await queryRunner.connect(); + await queryRunner.startTransaction(); + try { + // Update correspondence revision status to CANCELLED + await queryRunner.manager.update(correspondence_revision_entity_1.CorrespondenceRevision, currentRevision.id, { + statusId: cancelledStatus.id, + remarks: `Cancelled: ${reason}`, + }); + // Force close all active circulations + if (activeCirculations.length > 0) { + await queryRunner.manager.update('Circulation', { + correspondenceId: correspondence.id, + status: 'OPEN', + }, { + status: 'FORCE_CLOSED', + closedAt: new Date(), + closedBy: user.user_id, + closeReason: `Correspondence cancelled: ${reason}`, + }); + } + await queryRunner.commitTransaction(); + // Re-index cancelled status in Elasticsearch (fire-and-forget) + void this.searchService.indexDocument({ + id: correspondence.id, + publicId: correspondence.publicId, + type: 'correspondence', + docNumber: correspondence.correspondenceNumber, + title: currentRevision.subject, + status: 'CANCELLED', + projectId: correspondence.projectId, + createdAt: correspondence.createdAt, + }); + // Notify originator's doc-control user about cancellation (fire-and-forget) + if (correspondence.originatorId) { + void this.userService + .findDocControlIdByOrg(correspondence.originatorId) + .then((targetUserId) => { + if (targetUserId) { + void this.notificationService.send({ + userId: targetUserId, + title: 'Correspondence Cancelled', + message: `${correspondence.correspondenceNumber} — ${currentRevision.subject} has been cancelled. Reason: ${reason}`, + type: 'EMAIL', + entityType: 'correspondence', + entityId: correspondence.id, + link: `/correspondences/${correspondence.publicId}`, + }); + } + }) + .catch((err) => this.logger.warn(`Cancel notification failed: ${err.message}`)); + } + return { + success: true, + message: warningMessage || 'Correspondence cancelled successfully', + activeCirculationsCount: activeCirculations.length, + }; + } + catch (error) { + await queryRunner.rollbackTransaction(); + this.logger.error(`Failed to cancel correspondence: ${error.message}`); + throw error; + } + finally { + await queryRunner.release(); + } + } + async bulkCancel(publicIds, reason, user) { + const succeeded = []; + const failed = []; + for (const publicId of publicIds) { + try { + await this.cancel(publicId, reason, user); + succeeded.push(publicId); + } + catch { + failed.push(publicId); + } + } + return { succeeded, failed }; + } + async exportCsv(searchDto) { + const { data } = await this.findAll(searchDto); + const header = [ + 'Document No.', + 'Rev', + 'Subject', + 'Type', + 'Status', + 'Project', + 'From', + 'Due Date', + 'Created At', + ]; + const rows = data.map((rev) => { + const corr = rev.correspondence ?? rev; + return [ + this.escapeCsv(corr.correspondenceNumber ?? ''), + this.escapeCsv(rev.revisionLabel ?? String(rev.revisionNumber ?? 0)), + this.escapeCsv(rev.subject ?? ''), + this.escapeCsv(corr.type?.typeCode ?? ''), + this.escapeCsv(rev.status?.statusCode ?? ''), + this.escapeCsv(corr.project?.projectCode ?? ''), + this.escapeCsv(corr.originator?.organizationCode ?? ''), + rev.dueDate ? new Date(rev.dueDate).toISOString().split('T')[0] : '', + new Date(rev.createdAt).toISOString().split('T')[0], + ].join(','); + }); + return [header.join(','), ...rows].join('\n'); + } + escapeCsv(value) { + if (value.includes(',') || value.includes('"') || value.includes('\n')) { + return `"${value.replace(/"/g, '""')}"`; + } + return value; + } +}; +exports.CorrespondenceService = CorrespondenceService; +exports.CorrespondenceService = CorrespondenceService = CorrespondenceService_1 = __decorate([ + (0, common_1.Injectable)(), + __param(0, (0, typeorm_1.InjectRepository)(correspondence_entity_1.Correspondence)), + __param(1, (0, typeorm_1.InjectRepository)(correspondence_revision_entity_1.CorrespondenceRevision)), + __param(2, (0, typeorm_1.InjectRepository)(correspondence_type_entity_1.CorrespondenceType)), + __param(3, (0, typeorm_1.InjectRepository)(correspondence_status_entity_1.CorrespondenceStatus)), + __param(4, (0, typeorm_1.InjectRepository)(correspondence_reference_entity_1.CorrespondenceReference)), + __param(5, (0, typeorm_1.InjectRepository)(correspondence_tag_entity_1.CorrespondenceTag)), + __metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _a : Object, typeof (_b = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _b : Object, typeof (_c = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _c : Object, typeof (_d = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _d : Object, typeof (_e = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _e : Object, typeof (_f = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _f : Object, typeof (_g = typeof document_numbering_service_1.DocumentNumberingService !== "undefined" && document_numbering_service_1.DocumentNumberingService) === "function" ? _g : Object, typeof (_h = typeof json_schema_service_1.JsonSchemaService !== "undefined" && json_schema_service_1.JsonSchemaService) === "function" ? _h : Object, typeof (_j = typeof workflow_engine_service_1.WorkflowEngineService !== "undefined" && workflow_engine_service_1.WorkflowEngineService) === "function" ? _j : Object, typeof (_k = typeof user_service_1.UserService !== "undefined" && user_service_1.UserService) === "function" ? _k : Object, typeof (_l = typeof typeorm_2.DataSource !== "undefined" && typeorm_2.DataSource) === "function" ? _l : Object, typeof (_m = typeof search_service_1.SearchService !== "undefined" && search_service_1.SearchService) === "function" ? _m : Object, typeof (_o = typeof file_storage_service_1.FileStorageService !== "undefined" && file_storage_service_1.FileStorageService) === "function" ? _o : Object, typeof (_p = typeof uuid_resolver_service_1.UuidResolverService !== "undefined" && uuid_resolver_service_1.UuidResolverService) === "function" ? _p : Object, typeof (_q = typeof notification_service_1.NotificationService !== "undefined" && notification_service_1.NotificationService) === "function" ? _q : Object]) +], CorrespondenceService); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoiRTpcXG5wLWRtc1xcbGNicDNcXGJhY2tlbmRcXHNyY1xcbW9kdWxlc1xcY29ycmVzcG9uZGVuY2VcXGNvcnJlc3BvbmRlbmNlLnNlcnZpY2UudHMiLCJtYXBwaW5ncyI6IjtBQUFBLDZEQUE2RDs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFN0QsMkNBT3dCO0FBQ3hCLDZDQUFtRDtBQUNuRCxxQ0FBaUQ7QUFFakQsV0FBVztBQUNYLDRFQUFrRTtBQUNsRSw4RkFBbUY7QUFDbkYsc0ZBQTJFO0FBQzNFLDBGQUErRTtBQUMvRSxnR0FBcUY7QUFDckYsZ0dBQXFGO0FBQ3JGLG9GQUF5RTtBQUN6RSw4REFBb0Q7QUFFcEQsc0ZBQTRFO0FBUTVFLFdBQVc7QUFDWCwwR0FBcUc7QUFDckcsNEVBQXVFO0FBQ3ZFLHdGQUFtRjtBQUNuRix1REFBbUQ7QUFDbkQsNkRBQXlEO0FBQ3pELHlGQUFvRjtBQUNwRix1RkFBa0Y7QUFDbEYsK0VBQTJFO0FBVXBFLElBQU0scUJBQXFCLDZCQUEzQixNQUFNLHFCQUFxQjtJQUd4QixLQUFLLENBQUMsNEJBQTRCLENBQUMsTUFBYztRQUN2RCxNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDdEUsT0FBTyxXQUFXLENBQUMsUUFBUSxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDbkQsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyx1QkFBdUIsQ0FBQyxRQUFnQjtRQUM5QyxNQUFNLGFBQWEsR0FBRyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNyQyxJQUFJLGFBQWEsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxDQUFDLEVBQUUsQ0FBQztZQUNuRCxPQUFPLEdBQUcsQ0FBQyxDQUFDLHdCQUF3QjtRQUN0QyxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsQ0FBQyxnQ0FBZ0M7SUFDL0MsQ0FBQztJQUVELFlBRUUsa0JBQXNELEVBRXRELFlBQXdELEVBRXhELFFBQWdELEVB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dURBQXNCLENBQUMsQ0FBQTtJQUV4QyxXQUFBLElBQUEsMEJBQWdCLEVBQUMsK0NBQWtCLENBQUMsQ0FBQTtJQUVwQyxXQUFBLElBQUEsMEJBQWdCLEVBQUMsbURBQW9CLENBQUMsQ0FBQTtJQUV0QyxXQUFBLElBQUEsMEJBQWdCLEVBQUMseURBQXVCLENBQUMsQ0FBQTtJQUV6QyxXQUFBLElBQUEsMEJBQWdCLEVBQUMsNkNBQWlCLENBQUMsQ0FBQTt5REFUUixvQkFBVSxvQkFBVixvQkFBVSxvREFFaEIsb0JBQVUsb0JBQVYsb0JBQVUsb0RBRWQsb0JBQVUsb0JBQVYsb0JBQVUsb0RBRVIsb0JBQVUsb0JBQVYsb0JBQVUsb0RBRVAsb0JBQVUsb0JBQVYsb0JBQVUsb0RBRWhCLG9CQUFVLG9CQUFWLG9CQUFVLG9EQUNELHFEQUF3QixvQkFBeEIscURBQXdCLG9EQUN2Qix1Q0FBaUIsb0JBQWpCLHVDQUFpQixvREFDcEIsK0NBQXFCLG9CQUFyQiwrQ0FBcUIsb0RBQ3hCLDBCQUFXLG9CQUFYLDBCQUFXLG9EQUNaLG9CQUFVLG9CQUFWLG9CQUFVLG9EQUNQLDhCQUFhLG9CQUFiLDhCQUFhLG9EQUNSLHlDQUFrQixvQkFBbEIseUNBQWtCLG9EQUN4QiwyQ0FBbUIsb0JBQW5CLDJDQUFtQixvREFDWiwwQ0FBbUIsb0JBQW5CLDBDQUFtQjtHQTFDdkMscUJBQXFCLENBa2pDakMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiRTpcXG5wLWRtc1xcbGNicDNcXGJhY2tlbmRcXHNyY1xcbW9kdWxlc1xcY29ycmVzcG9uZGVuY2VcXGNvcnJlc3BvbmRlbmNlLnNlcnZpY2UudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gRmlsZTogc3JjL21vZHVsZXMvY29ycmVzcG9uZGVuY2UvY29ycmVzcG9uZGVuY2Uuc2VydmljZS50c1xyXG5cclxuaW1wb3J0IHtcclxuICBJbmplY3RhYmxlLFxyXG4gIE5vdEZvdW5kRXhjZXB0aW9uLFxyXG4gIEJhZFJlcXVlc3RFeGNlcHRpb24sXHJcbiAgSW50ZXJuYWxTZXJ2ZXJFcnJvckV4Y2VwdGlvbixcclxuICBGb3JiaWRkZW5FeGNlcHRpb24sXHJcbiAgTG9nZ2VyLFxyXG59IGZyb20gJ0BuZXN0anMvY29tbW9uJztcclxuaW1wb3J0IHsgSW5qZWN0UmVwb3NpdG9yeSB9IGZyb20gJ0BuZXN0anMvdHlwZW9ybSc7XHJcbmltcG9ydCB7IFJlcG9zaXRvcnksIERhdGFTb3VyY2UgfSBmcm9tICd0eXBlb3JtJztcclxuXHJcbi8vIEVudGl0aWVzXHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlIH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS5lbnRpdHknO1xyXG5pbXBvcnQgeyBDb3JyZXNwb25kZW5jZVJldmlzaW9uIH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS1yZXZpc2lvbi5lbnRpdHknO1xyXG5pbXBvcnQgeyBDb3JyZXNwb25kZW5jZVR5cGUgfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLXR5cGUuZW50aXR5JztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VTdGF0dXMgfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLXN0YXR1cy5lbnRpdHknO1xyXG5pbXBvcnQgeyBDb3JyZXNwb25kZW5jZVJlZmVyZW5jZSB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2UtcmVmZXJlbmNlLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlUmVjaXBpZW50IH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS1yZWNpcGllbnQuZW50aXR5JztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VUYWcgfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLXRhZy5lbnRpdHknO1xyXG5pbXBvcnQgeyBUYWcgfSBmcm9tICcuLi9tYXN0ZXIvZW50aXRpZXMvdGFnLmVudGl0eSc7XHJcbmltcG9ydCB7IFVzZXIgfSBmcm9tICcuLi91c2VyL2VudGl0aWVzL3VzZXIuZW50aXR5JztcclxuaW1wb3J0IHsgT3JnYW5pemF0aW9uIH0gZnJvbSAnLi4vb3JnYW5pemF0aW9uL2VudGl0aWVzL29yZ2FuaXphdGlvbi5lbnRpdHknO1xyXG5cclxuLy8gRFRPc1xyXG5pbXBvcnQgeyBDcmVhdGVDb3JyZXNwb25kZW5jZUR0byB9IGZyb20gJy4vZHRvL2NyZWF0ZS1jb3JyZXNwb25kZW5jZS5kdG8nO1xyXG5pbXBvcnQgeyBVcGRhdGVDb3JyZXNwb25kZW5jZUR0byB9IGZyb20gJy4vZHRvL3VwZGF0ZS1jb3JyZXNwb25kZW5jZS5kdG8nO1xyXG5pbXBvcnQgeyBBZGRSZWZlcmVuY2VEdG8gfSBmcm9tICcuL2R0by9hZGQtcmVmZXJlbmNlLmR0byc7XHJcbmltcG9ydCB7IFNlYXJjaENvcnJlc3BvbmRlbmNlRHRvIH0gZnJvbSAnLi9kdG8vc2VhcmNoLWNvcnJlc3BvbmRlbmNlLmR0byc7XHJcblxyXG4vLyBTZXJ2aWNlc1xyXG5pbXBvcnQgeyBEb2N1bWVudE51bWJlcmluZ1NlcnZpY2UgfSBmcm9tICcuLi9kb2N1bWVudC1udW1iZXJpbmcvc2VydmljZXMvZG9jdW1lbnQtbnVtYmVyaW5nLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBKc29uU2NoZW1hU2VydmljZSB9IGZyb20gJy4uL2pzb24tc2NoZW1hL2pzb24tc2NoZW1hLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBXb3JrZmxvd0VuZ2luZVNlcnZpY2UgfSBmcm9tICcuLi93b3JrZmxvdy1lbmdpbmUvd29ya2Zsb3ctZW5naW5lLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBVc2VyU2VydmljZSB9IGZyb20gJy4uL3VzZXIvdXNlci5zZXJ2aWNlJztcclxuaW1wb3J0IHsgU2VhcmNoU2VydmljZSB9IGZyb20gJy4uL3NlYXJjaC9zZWFyY2guc2VydmljZSc7XHJcbmltcG9ydCB7IEZpbGVTdG9yYWdlU2VydmljZSB9IGZyb20gJy4uLy4uL2NvbW1vbi9maWxlLXN0b3JhZ2UvZmlsZS1zdG9yYWdlLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBVdWlkUmVzb2x2ZXJTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vY29tbW9uL3NlcnZpY2VzL3V1aWQtcmVzb2x2ZXIuc2VydmljZSc7XHJcbmltcG9ydCB7IE5vdGlmaWNhdGlvblNlcnZpY2UgfSBmcm9tICcuLi9ub3RpZmljYXRpb24vbm90aWZpY2F0aW9uLnNlcnZpY2UnO1xyXG5cclxuLyoqXHJcbiAqIENvcnJlc3BvbmRlbmNlU2VydmljZSAtIERvY3VtZW50IG1hbmFnZW1lbnQgKENSVUQpXHJcbiAqL1xyXG5pbnRlcmZhY2UgUmVzb2x2ZWRSZWNpcGllbnQge1xyXG4gIG9yZ2FuaXphdGlvbklkOiBudW1iZXI7XHJcbiAgdHlwZTogJ1RPJyB8ICdDQyc7XHJcbn1cclxuQEluamVjdGFibGUoKVxyXG5leHBvcnQgY2xhc3MgQ29ycmVzcG9uZGVuY2VTZXJ2aWNlIHtcclxuICBwcml2YXRlIHJlYWRvbmx5IGxvZ2dlciA9IG5ldyBMb2dnZXIoQ29ycmVzcG9uZGVuY2VTZXJ2aWNlLm5hbWUpO1xyXG5cclxuICBwcml2YXRlIGFzeW5jIGhhc1N5c3RlbU1hbmFnZUFsbFBlcm1pc3Npb24odXNlcklkOiBudW1iZXIpOiBQcm9taXNlPGJvb2xlYW4+IHtcclxuICAgIGNvbnN0IHBlcm1pc3Npb25zID0gYXdhaXQgdGhpcy51c2VyU2VydmljZS5nZXRVc2VyUGVybWlzc2lvbnModXNlcklkKTtcclxuICAgIHJldHVybiBwZXJtaXNzaW9ucy5pbmNsdWRlcygnc3lzdGVtLm1hbmFnZV9hbGwnKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEJ1c2luZXNzIFJ1bGU6IFJldmlzaW9uIExhYmVsIFN0cmF0ZWd5XHJcbiAgICogLSBSRkEsIFJGSTogVXNlIGFscGhhYmV0IHN0YXJ0aW5nIHdpdGggJ0EnIChBLCBCLCBDLi4uKVxyXG4gICAqIC0gT3RoZXIgdHlwZXMgKExFVFRFUiwgTUVNTywgZXRjLik6IFVzZSBudW1lcmljIChudWxsIGZvciBmaXJzdCwgdGhlbiAxLCAyLCAzLi4uKVxyXG4gICAqL1xyXG4gIHByaXZhdGUgZ2V0SW5pdGlhbFJldmlzaW9uTGFiZWwodHlwZUNvZGU6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xyXG4gICAgY29uc3QgYWxwaGFiZXRUeXBlcyA9IFsnUkZBJywgJ1JGSSddO1xyXG4gICAgaWYgKGFscGhhYmV0VHlwZXMuaW5jbHVkZXModHlwZUNvZGUudG9VcHBlckNhc2UoKSkpIHtcclxuICAgICAgcmV0dXJuICdBJzsgLy8gQWxwaGFiZXQgZm9yIFJGQSwgUkZJXHJcbiAgICB9XHJcbiAgICByZXR1cm4gbnVsbDsgLy8gTnVtZXJpYyAobnVsbCBmb3IgcmV2aXNpb24gMClcclxuICB9XHJcblxyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2UpXHJcbiAgICBwcml2YXRlIGNvcnJlc3BvbmRlbmNlUmVwbzogUmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZT4sXHJcbiAgICBASW5qZWN0UmVwb3NpdG9yeShDb3JyZXNwb25kZW5jZVJldmlzaW9uKVxyXG4gICAgcHJpdmF0ZSByZXZpc2lvblJlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VSZXZpc2lvbj4sXHJcbiAgICBASW5qZWN0UmVwb3NpdG9yeShDb3JyZXNwb25kZW5jZVR5cGUpXHJcbiAgICBwcml2YXRlIHR5cGVSZXBvOiBSZXBvc2l0b3J5PENvcnJlc3BvbmRlbmNlVHlwZT4sXHJcbiAgICBASW5qZWN0UmVwb3NpdG9yeShDb3JyZXNwb25kZW5jZVN0YXR1cylcclxuICAgIHByaXZhdGUgc3RhdHVzUmVwbzogUmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVN0YXR1cz4sXHJcbiAgICBASW5qZWN0UmVwb3NpdG9yeShDb3JyZXNwb25kZW5jZVJlZmVyZW5jZSlcclxuICAgIHByaXZhdGUgcmVmZXJlbmNlUmVwbzogUmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVJlZmVyZW5jZT4sXHJcbiAgICBASW5qZWN0UmVwb3NpdG9yeShDb3JyZXNwb25kZW5jZVRhZylcclxuICAgIHByaXZhdGUgdGFnUmVwbzogUmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVRhZz4sXHJcbiAgICBwcml2YXRlIG51bWJlcmluZ1NlcnZpY2U6IERvY3VtZW50TnVtYmVyaW5nU2VydmljZSxcclxuICAgIHByaXZhdGUganNvblNjaGVtYVNlcnZpY2U6IEpzb25TY2hlbWFTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSB3b3JrZmxvd0VuZ2luZTogV29ya2Zsb3dFbmdpbmVTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSB1c2VyU2VydmljZTogVXNlclNlcnZpY2UsXHJcbiAgICBwcml2YXRlIGRhdGFTb3VyY2U6IERhdGFTb3VyY2UsXHJcbiAgICBwcml2YXRlIHNlYXJjaFNlcnZpY2U6IFNlYXJjaFNlcnZpY2UsXHJcbiAgICBwcml2YXRlIGZpbGVTdG9yYWdlU2VydmljZTogRmlsZVN0b3JhZ2VTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSB1dWlkUmVzb2x2ZXI6IFV1aWRSZXNvbHZlclNlcnZpY2UsXHJcbiAgICBwcml2YXRlIG5vdGlmaWNhdGlvblNlcnZpY2U6IE5vdGlmaWNhdGlvblNlcnZpY2VcclxuICApIHt9XHJcblxyXG4gIC8qKlxyXG4gICAqIEJ1c2luZXNzIFJ1bGUgVmFsaWRhdGlvbjogRUMtQ09SUi0wMDMgLSBDb3JyZXNwb25kZW5jZSB0byBTZWxmXHJcbiAgICogUHJldmVudCBleHRlcm5hbCBjb3JyZXNwb25kZW5jZSB0byBzYW1lIG9yZ2FuaXphdGlvblxyXG4gICAqL1xyXG4gIHByaXZhdGUgYXN5bmMgdmFsaWRhdGVDb3JyZXNwb25kZW5jZVJlY2lwaWVudHMoXHJcbiAgICBjcmVhdGVEdG86IENyZWF0ZUNvcnJlc3BvbmRlbmNlRHRvLFxyXG4gICAgdXNlcjogVXNlclxyXG4gICk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgLy8gR2V0IHVzZXIncyBvcmdhbml6YXRpb25cclxuICAgIGxldCB1c2VyT3JnSWQgPSB1c2VyLnByaW1hcnlPcmdhbml6YXRpb25JZDtcclxuICAgIGlmICghdXNlck9yZ0lkKSB7XHJcbiAgICAgIGNvbnN0IGZ1bGxVc2VyID0gYXdhaXQgdGhpcy51c2VyU2VydmljZS5maW5kT25lKHVzZXIudXNlcl9pZCk7XHJcbiAgICAgIGlmIChmdWxsVXNlcikge1xyXG4gICAgICAgIHVzZXJPcmdJZCA9IGZ1bGxVc2VyLnByaW1hcnlPcmdhbml6YXRpb25JZDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmICghdXNlck9yZ0lkKSB7XHJcbiAgICAgIGlmIChjcmVhdGVEdG8ub3JpZ2luYXRvcklkKSB7XHJcbiAgICAgICAgY29uc3QgY2FuTWFuYWdlQWxsID0gYXdhaXQgdGhpcy5oYXNTeXN0ZW1NYW5hZ2VBbGxQZXJtaXNzaW9uKFxyXG4gICAgICAgICAgdXNlci51c2VyX2lkXHJcbiAgICAgICAgKTtcclxuICAgICAgICBpZiAoY2FuTWFuYWdlQWxsKSB7XHJcbiAgICAgICAgICB1c2VyT3JnSWQgPSBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlT3JnYW5pemF0aW9uSWQoXHJcbiAgICAgICAgICAgIGNyZWF0ZUR0by5vcmlnaW5hdG9ySWRcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICAgIHRocm93IG5ldyBCYWRSZXF1ZXN0RXhjZXB0aW9uKFxyXG4gICAgICAgICAgJ1VzZXIgbXVzdCBiZWxvbmcgdG8gYW4gb3JnYW5pemF0aW9uIHRvIGNyZWF0ZSBkb2N1bWVudHMnXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEZvciBpbXBlcnNvbmF0aW9uLCB1c2UgdGhlIHNwZWNpZmllZCBvcmlnaW5hdG9yXHJcbiAgICBjb25zdCBvcmlnaW5hdG9yT3JnSWQgPSBjcmVhdGVEdG8ub3JpZ2luYXRvcklkXHJcbiAgICAgID8gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKGNyZWF0ZUR0by5vcmlnaW5hdG9ySWQpXHJcbiAgICAgIDogdXNlck9yZ0lkO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIGl0J3MgaW50ZXJuYWwgY29tbXVuaWNhdGlvblxyXG4gICAgaWYgKGNyZWF0ZUR0by5pc0ludGVybmFsKSB7XHJcbiAgICAgIC8vIEludGVybmFsIGNvbW11bmljYXRpb25zIHNob3VsZCB1c2UgQ2lyY3VsYXRpb24gaW5zdGVhZFxyXG4gICAgICB0aHJvdyBuZXcgQmFkUmVxdWVzdEV4Y2VwdGlvbihcclxuICAgICAgICAnSW50ZXJuYWwgY29tbXVuaWNhdGlvbnMgc2hvdWxkIHVzZSBDaXJjdWxhdGlvbiBTaGVldCBpbnN0ZWFkIG9mIENvcnJlc3BvbmRlbmNlJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFZhbGlkYXRlIHJlY2lwaWVudHNcclxuICAgIGlmICghY3JlYXRlRHRvLnJlY2lwaWVudHMgfHwgY3JlYXRlRHRvLnJlY2lwaWVudHMubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgIHRocm93IG5ldyBCYWRSZXF1ZXN0RXhjZXB0aW9uKFxyXG4gICAgICAgICdBdCBsZWFzdCBvbmUgcmVjaXBpZW50IChUTyBvciBDQykgaXMgcmVxdWlyZWQnXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgdG9SZWNpcGllbnRzID0gY3JlYXRlRHRvLnJlY2lwaWVudHMuZmlsdGVyKChyKSA9PiByLnR5cGUgPT09ICdUTycpO1xyXG4gICAgY29uc3QgY2NSZWNpcGllbnRzID0gY3JlYXRlRHRvLnJlY2lwaWVudHMuZmlsdGVyKChyKSA9PiByLnR5cGUgPT09ICdDQycpO1xyXG5cclxuICAgIGlmICh0b1JlY2lwaWVudHMubGVuZ3RoID09PSAwICYmIGNjUmVjaXBpZW50cy5sZW5ndGggPT09IDApIHtcclxuICAgICAgdGhyb3cgbmV3IEJhZFJlcXVlc3RFeGNlcHRpb24oXHJcbiAgICAgICAgJ0F0IGxlYXN0IG9uZSBUTyBvciBDQyByZWNpcGllbnQgaXMgcmVxdWlyZWQnXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgZm9yIHNhbWUgb3JnYW5pemF0aW9uIGNvcnJlc3BvbmRlbmNlXHJcbiAgICBmb3IgKGNvbnN0IHJlY2lwaWVudCBvZiBjcmVhdGVEdG8ucmVjaXBpZW50cykge1xyXG4gICAgICBjb25zdCByZWNpcGllbnRPcmdJZCA9IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZChcclxuICAgICAgICByZWNpcGllbnQub3JnYW5pemF0aW9uSWRcclxuICAgICAgKTtcclxuXHJcbiAgICAgIGlmIChyZWNpcGllbnRPcmdJZCA9PT0gb3JpZ2luYXRvck9yZ0lkKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEJhZFJlcXVlc3RFeGNlcHRpb24oXHJcbiAgICAgICAgICAnQ2Fubm90IHNlbmQgY29ycmVzcG9uZGVuY2UgdG8geW91ciBvd24gb3JnYW5pemF0aW9uLiBVc2UgQ2lyY3VsYXRpb24gU2hlZXQgZm9yIGludGVybmFsIGNvbW11bmljYXRpb24uJ1xyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFzeW5jIGNyZWF0ZShjcmVhdGVEdG86IENyZWF0ZUNvcnJlc3BvbmRlbmNlRHRvLCB1c2VyOiBVc2VyKSB7XHJcbiAgICAvLyBCdXNpbmVzcyBSdWxlIFZhbGlkYXRpb246IEVDLUNPUlItMDAzIC0gQ29ycmVzcG9uZGVuY2UgdG8gU2VsZlxyXG4gICAgYXdhaXQgdGhpcy52YWxpZGF0ZUNvcnJlc3BvbmRlbmNlUmVjaXBpZW50cyhjcmVhdGVEdG8sIHVzZXIpO1xyXG4gICAgLy8gQURSLTAxOTogUmVzb2x2ZSBVVUlEIHJlZmVyZW5jZXMgdG8gaW50ZXJuYWwgSU5UIElEc1xyXG4gICAgY29uc3QgcmVzb2x2ZWRQcm9qZWN0SWQgPSBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlUHJvamVjdElkKFxyXG4gICAgICBjcmVhdGVEdG8ucHJvamVjdElkXHJcbiAgICApO1xyXG4gICAgY29uc3QgcmVzb2x2ZWRPcmlnaW5hdG9ySWQgPSBjcmVhdGVEdG8ub3JpZ2luYXRvcklkXHJcbiAgICAgID8gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKGNyZWF0ZUR0by5vcmlnaW5hdG9ySWQpXHJcbiAgICAgIDogdW5kZWZpbmVkO1xyXG4gICAgY29uc3QgcmVzb2x2ZWRSZWNpcGllbnRzID0gY3JlYXRlRHRvLnJlY2lwaWVudHNcclxuICAgICAgPyBhd2FpdCBQcm9taXNlLmFsbChcclxuICAgICAgICAgIGNyZWF0ZUR0by5yZWNpcGllbnRzLm1hcChcclxuICAgICAgICAgICAgYXN5bmMgKHIpOiBQcm9taXNlPFJlc29sdmVkUmVjaXBpZW50PiA9PiAoe1xyXG4gICAgICAgICAgICAgIG9yZ2FuaXphdGlvbklkOiBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlT3JnYW5pemF0aW9uSWQoXHJcbiAgICAgICAgICAgICAgICByLm9yZ2FuaXphdGlvbklkXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgICB0eXBlOiByLnR5cGUsXHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgKVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuICAgIGNvbnN0IHR5cGUgPSBhd2FpdCB0aGlzLnR5cGVSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZTogeyBpZDogY3JlYXRlRHRvLnR5cGVJZCB9LFxyXG4gICAgfSk7XHJcbiAgICBpZiAoIXR5cGUpIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbignRG9jdW1lbnQgVHlwZSBub3QgZm91bmQnKTtcclxuXHJcbiAgICBjb25zdCBzdGF0dXNEcmFmdCA9IGF3YWl0IHRoaXMuc3RhdHVzUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgc3RhdHVzQ29kZTogJ0RSQUZUJyB9LFxyXG4gICAgfSk7XHJcbiAgICBpZiAoIXN0YXR1c0RyYWZ0KSB7XHJcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbFNlcnZlckVycm9yRXhjZXB0aW9uKFxyXG4gICAgICAgICdTdGF0dXMgRFJBRlQgbm90IGZvdW5kIGluIE1hc3RlciBEYXRhJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCB1c2VyT3JnSWQgPSB1c2VyLnByaW1hcnlPcmdhbml6YXRpb25JZDtcclxuXHJcbiAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICBjb25zdCBmdWxsVXNlciA9IGF3YWl0IHRoaXMudXNlclNlcnZpY2UuZmluZE9uZSh1c2VyLnVzZXJfaWQpO1xyXG4gICAgICBpZiAoZnVsbFVzZXIpIHtcclxuICAgICAgICB1c2VyT3JnSWQgPSBmdWxsVXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBJbXBlcnNvbmF0aW9uIExvZ2ljXHJcbiAgICBpZiAocmVzb2x2ZWRPcmlnaW5hdG9ySWQgJiYgcmVzb2x2ZWRPcmlnaW5hdG9ySWQgIT09IHVzZXJPcmdJZCkge1xyXG4gICAgICBjb25zdCBjYW5NYW5hZ2VBbGwgPSBhd2FpdCB0aGlzLmhhc1N5c3RlbU1hbmFnZUFsbFBlcm1pc3Npb24oXHJcbiAgICAgICAgdXNlci51c2VyX2lkXHJcbiAgICAgICk7XHJcbiAgICAgIGlmICghY2FuTWFuYWdlQWxsKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEZvcmJpZGRlbkV4Y2VwdGlvbihcclxuICAgICAgICAgICdZb3UgZG8gbm90IGhhdmUgcGVybWlzc2lvbiB0byBjcmVhdGUgZG9jdW1lbnRzIG9uIGJlaGFsZiBvZiBvdGhlciBvcmdhbml6YXRpb25zLidcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICAgIHVzZXJPcmdJZCA9IHJlc29sdmVkT3JpZ2luYXRvcklkO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghdXNlck9yZ0lkKSB7XHJcbiAgICAgIHRocm93IG5ldyBCYWRSZXF1ZXN0RXhjZXB0aW9uKFxyXG4gICAgICAgICdVc2VyIG11c3QgYmVsb25nIHRvIGFuIG9yZ2FuaXphdGlvbiB0byBjcmVhdGUgZG9jdW1lbnRzJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChjcmVhdGVEdG8uZGV0YWlscykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGF3YWl0IHRoaXMuanNvblNjaGVtYVNlcnZpY2UudmFsaWRhdGUodHlwZS50eXBlQ29kZSwgY3JlYXRlRHRvLmRldGFpbHMpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xyXG4gICAgICAgIHRoaXMubG9nZ2VyLndhcm4oXHJcbiAgICAgICAgICBgU2NoZW1hIHZhbGlkYXRpb24gd2FybmluZyBmb3IgJHt0eXBlLnR5cGVDb2RlfTogJHsoZXJyb3IgYXMgRXJyb3IpLm1lc3NhZ2V9YFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBxdWVyeVJ1bm5lciA9IHRoaXMuZGF0YVNvdXJjZS5jcmVhdGVRdWVyeVJ1bm5lcigpO1xyXG4gICAgYXdhaXQgcXVlcnlSdW5uZXIuY29ubmVjdCgpO1xyXG4gICAgYXdhaXQgcXVlcnlSdW5uZXIuc3RhcnRUcmFuc2FjdGlvbigpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFtGaXggIzZdIEZldGNoIHJlYWwgT1JHIENvZGUgZnJvbSBPcmdhbml6YXRpb24gZW50aXR5XHJcbiAgICAgIGNvbnN0IG9yaWdpbmF0b3JPcmcgPSBhd2FpdCB0aGlzLmRhdGFTb3VyY2UubWFuYWdlci5maW5kT25lKFxyXG4gICAgICAgIE9yZ2FuaXphdGlvbixcclxuICAgICAgICB7XHJcbiAgICAgICAgICB3aGVyZTogeyBpZDogdXNlck9yZ0lkIH0sXHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG4gICAgICBjb25zdCBvcmdDb2RlID0gb3JpZ2luYXRvck9yZz8ub3JnYW5pemF0aW9uQ29kZSA/PyAnVU5LJztcclxuXHJcbiAgICAgIC8vIFt2MS41LjFdIEV4dHJhY3QgcmVjaXBpZW50IG9yZ2FuaXphdGlvbiBmcm9tIHJlY2lwaWVudHMgYXJyYXkgKFByaW1hcnkgVE8pXHJcbiAgICAgIGNvbnN0IHRvUmVjaXBpZW50ID0gcmVzb2x2ZWRSZWNpcGllbnRzPy5maW5kKChyKSA9PiByLnR5cGUgPT09ICdUTycpO1xyXG4gICAgICBjb25zdCByZWNpcGllbnRPcmdhbml6YXRpb25JZCA9IHRvUmVjaXBpZW50Py5vcmdhbml6YXRpb25JZDtcclxuXHJcbiAgICAgIGxldCByZWNpcGllbnRDb2RlID0gJyc7XHJcbiAgICAgIGlmIChyZWNpcGllbnRPcmdhbml6YXRpb25JZCkge1xyXG4gICAgICAgIGNvbnN0IHJlY09yZyA9IGF3YWl0IHRoaXMuZGF0YVNvdXJjZS5tYW5hZ2VyLmZpbmRPbmUoT3JnYW5pemF0aW9uLCB7XHJcbiAgICAgICAgICB3aGVyZTogeyBpZDogcmVjaXBpZW50T3JnYW5pemF0aW9uSWQgfSxcclxuICAgICAgICB9KTtcclxuICAgICAgICBpZiAocmVjT3JnKSByZWNpcGllbnRDb2RlID0gcmVjT3JnLm9yZ2FuaXphdGlvbkNvZGU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGNvbnN0IGRvY051bWJlciA9IGF3YWl0IHRoaXMubnVtYmVyaW5nU2VydmljZS5nZW5lcmF0ZU5leHROdW1iZXIoe1xyXG4gICAgICAgIHByb2plY3RJZDogcmVzb2x2ZWRQcm9qZWN0SWQsXHJcbiAgICAgICAgb3JpZ2luYXRvck9yZ2FuaXphdGlvbklkOiB1c2VyT3JnSWQsXHJcbiAgICAgICAgdHlwZUlkOiBjcmVhdGVEdG8udHlwZUlkLFxyXG4gICAgICAgIGRpc2NpcGxpbmVJZDogY3JlYXRlRHRvLmRpc2NpcGxpbmVJZCxcclxuICAgICAgICBzdWJUeXBlSWQ6IGNyZWF0ZUR0by5zdWJUeXBlSWQsXHJcbiAgICAgICAgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQsIC8vIFt2MS41LjFdIFBhc3MgcmVjaXBpZW50IGZvciBkb2N1bWVudCBudW1iZXIgZm9ybWF0XHJcbiAgICAgICAgeWVhcjogbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpLFxyXG4gICAgICAgIGN1c3RvbVRva2Vuczoge1xyXG4gICAgICAgICAgVFlQRV9DT0RFOiB0eXBlLnR5cGVDb2RlLFxyXG4gICAgICAgICAgT1JHX0NPREU6IG9yZ0NvZGUsXHJcbiAgICAgICAgICBSRUNJUElFTlRfQ09ERTogcmVjaXBpZW50Q29kZSxcclxuICAgICAgICAgIFJFQ19DT0RFOiByZWNpcGllbnRDb2RlLFxyXG4gICAgICAgIH0sXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgY29uc3QgY29ycmVzcG9uZGVuY2UgPSBxdWVyeVJ1bm5lci5tYW5hZ2VyLmNyZWF0ZShDb3JyZXNwb25kZW5jZSwge1xyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlTnVtYmVyOiBkb2NOdW1iZXIubnVtYmVyLFxyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlVHlwZUlkOiBjcmVhdGVEdG8udHlwZUlkLFxyXG4gICAgICAgIGRpc2NpcGxpbmVJZDogY3JlYXRlRHRvLmRpc2NpcGxpbmVJZCxcclxuICAgICAgICBwcm9qZWN0SWQ6IHJlc29sdmVkUHJvamVjdElkLFxyXG4gICAgICAgIG9yaWdpbmF0b3JJZDogdXNlck9yZ0lkLFxyXG4gICAgICAgIGlzSW50ZXJuYWw6IGNyZWF0ZUR0by5pc0ludGVybmFsIHx8IGZhbHNlLFxyXG4gICAgICAgIGNyZWF0ZWRCeTogdXNlci51c2VyX2lkLFxyXG4gICAgICB9KTtcclxuICAgICAgY29uc3Qgc2F2ZWRDb3JyID0gYXdhaXQgcXVlcnlSdW5uZXIubWFuYWdlci5zYXZlKGNvcnJlc3BvbmRlbmNlKTtcclxuXHJcbiAgICAgIGNvbnN0IHJldmlzaW9uID0gcXVlcnlSdW5uZXIubWFuYWdlci5jcmVhdGUoQ29ycmVzcG9uZGVuY2VSZXZpc2lvbiwge1xyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IHNhdmVkQ29yci5pZCxcclxuICAgICAgICByZXZpc2lvbk51bWJlcjogMCxcclxuICAgICAgICByZXZpc2lvbkxhYmVsOiAnQScsXHJcbiAgICAgICAgaXNDdXJyZW50OiB0cnVlLFxyXG4gICAgICAgIHN0YXR1c0lkOiBzdGF0dXNEcmFmdC5pZCxcclxuICAgICAgICBzdWJqZWN0OiBjcmVhdGVEdG8uc3ViamVjdCxcclxuICAgICAgICBib2R5OiBjcmVhdGVEdG8uYm9keSxcclxuICAgICAgICByZW1hcmtzOiBjcmVhdGVEdG8ucmVtYXJrcyxcclxuICAgICAgICBkdWVEYXRlOiBjcmVhdGVEdG8uZHVlRGF0ZSA/IG5ldyBEYXRlKGNyZWF0ZUR0by5kdWVEYXRlKSA6IHVuZGVmaW5lZCxcclxuICAgICAgICBkb2N1bWVudERhdGU6IGNyZWF0ZUR0by5kb2N1bWVudERhdGVcclxuICAgICAgICAgID8gbmV3IERhdGUoY3JlYXRlRHRvLmRvY3VtZW50RGF0ZSlcclxuICAgICAgICAgIDogdW5kZWZpbmVkLFxyXG4gICAgICAgIGlzc3VlZERhdGU6IGNyZWF0ZUR0by5pc3N1ZWREYXRlXHJcbiAgICAgICAgICA/IG5ldyBEYXRlKGNyZWF0ZUR0by5pc3N1ZWREYXRlKVxyXG4gICAgICAgICAgOiB1bmRlZmluZWQsXHJcbiAgICAgICAgcmVjZWl2ZWREYXRlOiBjcmVhdGVEdG8ucmVjZWl2ZWREYXRlXHJcbiAgICAgICAgICA/IG5ldyBEYXRlKGNyZWF0ZUR0by5yZWNlaXZlZERhdGUpXHJcbiAgICAgICAgICA6IHVuZGVmaW5lZCxcclxuICAgICAgICBkZXNjcmlwdGlvbjogY3JlYXRlRHRvLmRlc2NyaXB0aW9uLFxyXG4gICAgICAgIGRldGFpbHM6IGNyZWF0ZUR0by5kZXRhaWxzLFxyXG4gICAgICAgIGNyZWF0ZWRCeTogdXNlci51c2VyX2lkLFxyXG4gICAgICAgIHNjaGVtYVZlcnNpb246IDEsXHJcbiAgICAgIH0pO1xyXG4gICAgICBhd2FpdCBxdWVyeVJ1bm5lci5tYW5hZ2VyLnNhdmUocmV2aXNpb24pO1xyXG5cclxuICAgICAgLy8gU2F2ZSBSZWNpcGllbnRzICh1c2luZyByZXNvbHZlZCBJTlQgSURzKVxyXG4gICAgICBpZiAocmVzb2x2ZWRSZWNpcGllbnRzICYmIHJlc29sdmVkUmVjaXBpZW50cy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgY29uc3QgcmVjaXBpZW50cyA9IHJlc29sdmVkUmVjaXBpZW50cy5tYXAoKHIpID0+XHJcbiAgICAgICAgICBxdWVyeVJ1bm5lci5tYW5hZ2VyLmNyZWF0ZShDb3JyZXNwb25kZW5jZVJlY2lwaWVudCwge1xyXG4gICAgICAgICAgICBjb3JyZXNwb25kZW5jZUlkOiBzYXZlZENvcnIuaWQsXHJcbiAgICAgICAgICAgIHJlY2lwaWVudE9yZ2FuaXphdGlvbklkOiByLm9yZ2FuaXphdGlvbklkLFxyXG4gICAgICAgICAgICByZWNpcGllbnRUeXBlOiByLnR5cGUsXHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYXdhaXQgcXVlcnlSdW5uZXIubWFuYWdlci5zYXZlKHJlY2lwaWVudHMpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDb21taXQgYXR0YWNobWVudHMgZnJvbSBUZW1wIOKGkiBQZXJtYW5lbnQgKFR3by1QaGFzZSBTdG9yYWdlKVxyXG4gICAgICBpZiAoY3JlYXRlRHRvLmF0dGFjaG1lbnRUZW1wSWRzPy5sZW5ndGgpIHtcclxuICAgICAgICBjb25zdCBpc3N1ZURhdGUgPSBjcmVhdGVEdG8uaXNzdWVkRGF0ZVxyXG4gICAgICAgICAgPyBuZXcgRGF0ZShjcmVhdGVEdG8uaXNzdWVkRGF0ZSlcclxuICAgICAgICAgIDogY3JlYXRlRHRvLmRvY3VtZW50RGF0ZVxyXG4gICAgICAgICAgICA/IG5ldyBEYXRlKGNyZWF0ZUR0by5kb2N1bWVudERhdGUpXHJcbiAgICAgICAgICAgIDogdW5kZWZpbmVkO1xyXG5cclxuICAgICAgICBhd2FpdCB0aGlzLmZpbGVTdG9yYWdlU2VydmljZS5jb21taXQoY3JlYXRlRHRvLmF0dGFjaG1lbnRUZW1wSWRzLCB7XHJcbiAgICAgICAgICBpc3N1ZURhdGUsXHJcbiAgICAgICAgICBkb2N1bWVudFR5cGU6ICdDb3JyZXNwb25kZW5jZScsXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLmNvbW1pdFRyYW5zYWN0aW9uKCk7XHJcblxyXG4gICAgICAvLyBTdGFydCBXb3JrZmxvdyBJbnN0YW5jZSAobm9uLWJsb2NraW5nKVxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHdvcmtmbG93Q29kZSA9IGBDT1JSRVNQT05ERU5DRV8ke3R5cGUudHlwZUNvZGV9YDtcclxuICAgICAgICBhd2FpdCB0aGlzLndvcmtmbG93RW5naW5lLmNyZWF0ZUluc3RhbmNlKFxyXG4gICAgICAgICAgd29ya2Zsb3dDb2RlLFxyXG4gICAgICAgICAgJ2NvcnJlc3BvbmRlbmNlJyxcclxuICAgICAgICAgIHNhdmVkQ29yci5pZC50b1N0cmluZygpLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICBwcm9qZWN0SWQ6IHJlc29sdmVkUHJvamVjdElkLFxyXG4gICAgICAgICAgICBvcmlnaW5hdG9ySWQ6IHVzZXJPcmdJZCxcclxuICAgICAgICAgICAgZGlzY2lwbGluZUlkOiBjcmVhdGVEdG8uZGlzY2lwbGluZUlkLFxyXG4gICAgICAgICAgICBpbml0aWF0b3JJZDogdXNlci51c2VyX2lkLFxyXG4gICAgICAgICAgfSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPlxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XHJcbiAgICAgICAgdGhpcy5sb2dnZXIud2FybihcclxuICAgICAgICAgIGBXb3JrZmxvdyBub3Qgc3RhcnRlZCBmb3IgJHtkb2NOdW1iZXIubnVtYmVyfSAoQ29kZTogQ09SUkVTUE9OREVOQ0VfJHt0eXBlLnR5cGVDb2RlfSk6ICR7KGVycm9yIGFzIEVycm9yKS5tZXNzYWdlfWBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBGaXJlLWFuZC1mb3JnZXQgc2VhcmNoIGluZGV4aW5nIChub24tYmxvY2tpbmcsIHZvaWQgaW50ZW50aW9uYWwpXHJcbiAgICAgIHZvaWQgdGhpcy5zZWFyY2hTZXJ2aWNlLmluZGV4RG9jdW1lbnQoe1xyXG4gICAgICAgIGlkOiBzYXZlZENvcnIuaWQsXHJcbiAgICAgICAgcHVibGljSWQ6IHNhdmVkQ29yci5wdWJsaWNJZCxcclxuICAgICAgICB0eXBlOiAnY29ycmVzcG9uZGVuY2UnLFxyXG4gICAgICAgIGRvY051bWJlcjogZG9jTnVtYmVyLm51bWJlcixcclxuICAgICAgICB0aXRsZTogY3JlYXRlRHRvLnN1YmplY3QsXHJcbiAgICAgICAgZGVzY3JpcHRpb246IGNyZWF0ZUR0by5kZXNjcmlwdGlvbixcclxuICAgICAgICBzdGF0dXM6ICdEUkFGVCcsXHJcbiAgICAgICAgcHJvamVjdElkOiByZXNvbHZlZFByb2plY3RJZCxcclxuICAgICAgICBjcmVhdGVkQXQ6IG5ldyBEYXRlKCksXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICAuLi5zYXZlZENvcnIsXHJcbiAgICAgICAgY3VycmVudFJldmlzaW9uOiByZXZpc2lvbixcclxuICAgICAgfTtcclxuICAgIH0gY2F0Y2ggKGVycikge1xyXG4gICAgICBhd2FpdCBxdWVyeVJ1bm5lci5yb2xsYmFja1RyYW5zYWN0aW9uKCk7XHJcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKFxyXG4gICAgICAgIGBGYWlsZWQgdG8gY3JlYXRlIGNvcnJlc3BvbmRlbmNlOiAkeyhlcnIgYXMgRXJyb3IpLm1lc3NhZ2V9YFxyXG4gICAgICApO1xyXG4gICAgICB0aHJvdyBlcnI7XHJcbiAgICB9IGZpbmFsbHkge1xyXG4gICAgICBhd2FpdCBxdWVyeVJ1bm5lci5yZWxlYXNlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBhc3luYyBmaW5kQWxsKHNlYXJjaER0bzogU2VhcmNoQ29ycmVzcG9uZGVuY2VEdG8gPSB7fSkge1xyXG4gICAgY29uc3Qge1xyXG4gICAgICBzZWFyY2gsXHJcbiAgICAgIHR5cGVJZCxcclxuICAgICAgcHJvamVjdElkLFxyXG4gICAgICBzdGF0dXNJZCxcclxuICAgICAgc3RhdHVzLFxyXG4gICAgICBwYWdlID0gMSxcclxuICAgICAgbGltaXQgPSAxMCxcclxuICAgIH0gPSBzZWFyY2hEdG87XHJcbiAgICBjb25zdCBza2lwID0gKHBhZ2UgLSAxKSAqIGxpbWl0O1xyXG5cclxuICAgIC8vIENoYW5nZTogUXVlcnkgZnJvbSBSZXZpc2lvbiBSZXBvXHJcbiAgICBjb25zdCBxdWVyeSA9IHRoaXMucmV2aXNpb25SZXBvXHJcbiAgICAgIC5jcmVhdGVRdWVyeUJ1aWxkZXIoJ3JldicpXHJcbiAgICAgIC5sZWZ0Sm9pbkFuZFNlbGVjdCgncmV2LmNvcnJlc3BvbmRlbmNlJywgJ2NvcnInKVxyXG4gICAgICAubGVmdEpvaW5BbmRTZWxlY3QoJ2NvcnIudHlwZScsICd0eXBlJylcclxuICAgICAgLmxlZnRKb2luQW5kU2VsZWN0KCdjb3JyLnByb2plY3QnLCAncHJvamVjdCcpXHJcbiAgICAgIC5sZWZ0Sm9pbkFuZFNlbGVjdCgnY29yci5vcmlnaW5hdG9yJywgJ29yZycpXHJcbiAgICAgIC5sZWZ0Sm9pbkFuZFNlbGVjdCgncmV2LnN0YXR1cycsICdzdGF0dXMnKTtcclxuXHJcbiAgICAvLyBGaWx0ZXIgYnkgUmV2aXNpb24gU3RhdHVzXHJcbiAgICBjb25zdCByZXZTdGF0dXMgPSBzZWFyY2hEdG8ucmV2aXNpb25TdGF0dXMgfHwgJ0NVUlJFTlQnO1xyXG5cclxuICAgIGlmIChyZXZTdGF0dXMgPT09ICdDVVJSRU5UJykge1xyXG4gICAgICBxdWVyeS53aGVyZSgncmV2LmlzQ3VycmVudCA9IDppc0N1cnJlbnQnLCB7IGlzQ3VycmVudDogdHJ1ZSB9KTtcclxuICAgIH0gZWxzZSBpZiAocmV2U3RhdHVzID09PSAnT0xEJykge1xyXG4gICAgICBxdWVyeS53aGVyZSgncmV2LmlzQ3VycmVudCA9IDppc0N1cnJlbnQnLCB7IGlzQ3VycmVudDogZmFsc2UgfSk7XHJcbiAgICB9XHJcbiAgICAvLyBJZiAnQUxMJywgbm8gZmlsdGVyIG5lZWRlZCBvbiBpc0N1cnJlbnRcclxuXHJcbiAgICBpZiAocHJvamVjdElkKSB7XHJcbiAgICAgIHF1ZXJ5LmFuZFdoZXJlKCdjb3JyLnByb2plY3RJZCA9IDpwcm9qZWN0SWQnLCB7IHByb2plY3RJZCB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodHlwZUlkKSB7XHJcbiAgICAgIHF1ZXJ5LmFuZFdoZXJlKCdjb3JyLmNvcnJlc3BvbmRlbmNlVHlwZUlkID0gOnR5cGVJZCcsIHsgdHlwZUlkIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChzdGF0dXNJZCkge1xyXG4gICAgICBxdWVyeS5hbmRXaGVyZSgncmV2LnN0YXR1c0lkID0gOnN0YXR1c0lkJywgeyBzdGF0dXNJZCB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoc3RhdHVzKSB7XHJcbiAgICAgIHF1ZXJ5LmFuZFdoZXJlKCdzdGF0dXMuc3RhdHVzQ29kZSA9IDpzdGF0dXMnLCB7IHN0YXR1cyB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoc2VhcmNoKSB7XHJcbiAgICAgIHF1ZXJ5LmFuZFdoZXJlKFxyXG4gICAgICAgICcoY29yci5jb3JyZXNwb25kZW5jZU51bWJlciBMSUtFIDpzZWFyY2ggT1IgcmV2LnN1YmplY3QgTElLRSA6c2VhcmNoKScsXHJcbiAgICAgICAgeyBzZWFyY2g6IGAlJHtzZWFyY2h9JWAgfVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlZmF1bHQgU29ydDogTGF0ZXN0IENyZWF0ZWRcclxuICAgIHF1ZXJ5Lm9yZGVyQnkoJ3Jldi5jcmVhdGVkQXQnLCAnREVTQycpLnNraXAoc2tpcCkudGFrZShsaW1pdCk7XHJcblxyXG4gICAgY29uc3QgW2l0ZW1zLCB0b3RhbF0gPSBhd2FpdCBxdWVyeS5nZXRNYW55QW5kQ291bnQoKTtcclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBkYXRhOiBpdGVtcyxcclxuICAgICAgbWV0YToge1xyXG4gICAgICAgIHRvdGFsLFxyXG4gICAgICAgIHBhZ2UsXHJcbiAgICAgICAgbGltaXQsXHJcbiAgICAgICAgdG90YWxQYWdlczogTWF0aC5jZWlsKHRvdGFsIC8gbGltaXQpLFxyXG4gICAgICB9LFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIGFzeW5jIGZpbmRPbmUoaWQ6IG51bWJlcikge1xyXG4gICAgY29uc3QgY29ycmVzcG9uZGVuY2UgPSBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgaWQgfSxcclxuICAgICAgcmVsYXRpb25zOiBbXHJcbiAgICAgICAgJ3JldmlzaW9ucycsXHJcbiAgICAgICAgJ3JldmlzaW9ucy5zdGF0dXMnLFxyXG4gICAgICAgICd0eXBlJyxcclxuICAgICAgICAncHJvamVjdCcsXHJcbiAgICAgICAgJ29yaWdpbmF0b3InLFxyXG4gICAgICAgICdyZWNpcGllbnRzJyxcclxuICAgICAgICAncmVjaXBpZW50cy5yZWNpcGllbnRPcmdhbml6YXRpb24nLCAvLyBbdjEuNS4xXSBGaXhlZCByZWxhdGlvbiBuYW1lXHJcbiAgICAgIF0sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoIWNvcnJlc3BvbmRlbmNlKSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbihgQ29ycmVzcG9uZGVuY2Ugd2l0aCBJRCAke2lkfSBub3QgZm91bmRgKTtcclxuICAgIH1cclxuICAgIHJldHVybiBjb3JyZXNwb25kZW5jZTtcclxuICB9XHJcblxyXG4gIGFzeW5jIGZpbmRPbmVCeVV1aWQocHVibGljSWQ6IHN0cmluZykge1xyXG4gICAgY29uc3QgY29ycmVzcG9uZGVuY2UgPSBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgcHVibGljSWQgfSxcclxuICAgICAgcmVsYXRpb25zOiBbXHJcbiAgICAgICAgJ3JldmlzaW9ucycsXHJcbiAgICAgICAgJ3JldmlzaW9ucy5zdGF0dXMnLFxyXG4gICAgICAgICd0eXBlJyxcclxuICAgICAgICAncHJvamVjdCcsXHJcbiAgICAgICAgJ29yaWdpbmF0b3InLFxyXG4gICAgICAgICdyZWNpcGllbnRzJyxcclxuICAgICAgICAncmVjaXBpZW50cy5yZWNpcGllbnRPcmdhbml6YXRpb24nLFxyXG4gICAgICBdLFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKCFjb3JyZXNwb25kZW5jZSkge1xyXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oXHJcbiAgICAgICAgYENvcnJlc3BvbmRlbmNlIHdpdGggVVVJRCAke3B1YmxpY0lkfSBub3QgZm91bmRgXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gY29ycmVzcG9uZGVuY2U7XHJcbiAgfVxyXG5cclxuICBhc3luYyBhZGRSZWZlcmVuY2UoaWQ6IG51bWJlciwgZHRvOiBBZGRSZWZlcmVuY2VEdG8pIHtcclxuICAgIGNvbnN0IHNvdXJjZSA9IGF3YWl0IHRoaXMuY29ycmVzcG9uZGVuY2VSZXBvLmZpbmRPbmUoeyB3aGVyZTogeyBpZCB9IH0pO1xyXG4gICAgLy8gQURSLTAxOTogUmVzb2x2ZSB0YXJnZXQgcHVibGljSWQg4oaSIGludGVybmFsIElOVCBpZFxyXG4gICAgY29uc3QgdGFyZ2V0ID0gYXdhaXQgdGhpcy5jb3JyZXNwb25kZW5jZVJlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IHB1YmxpY0lkOiBkdG8udGFyZ2V0VXVpZCB9LFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKCFzb3VyY2UgfHwgIXRhcmdldCkge1xyXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oJ1NvdXJjZSBvciBUYXJnZXQgY29ycmVzcG9uZGVuY2Ugbm90IGZvdW5kJyk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHNvdXJjZS5pZCA9PT0gdGFyZ2V0LmlkKSB7XHJcbiAgICAgIHRocm93IG5ldyBCYWRSZXF1ZXN0RXhjZXB0aW9uKCdDYW5ub3QgcmVmZXJlbmNlIHNlbGYnKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBleGlzdHMgPSBhd2FpdCB0aGlzLnJlZmVyZW5jZVJlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7XHJcbiAgICAgICAgc291cmNlSWQ6IGlkLFxyXG4gICAgICAgIHRhcmdldElkOiB0YXJnZXQuaWQsXHJcbiAgICAgIH0sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoZXhpc3RzKSB7XHJcbiAgICAgIHJldHVybiBleGlzdHM7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgcmVmID0gdGhpcy5yZWZlcmVuY2VSZXBvLmNyZWF0ZSh7XHJcbiAgICAgIHNvdXJjZUlkOiBpZCxcclxuICAgICAgdGFyZ2V0SWQ6IHRhcmdldC5pZCxcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB0aGlzLnJlZmVyZW5jZVJlcG8uc2F2ZShyZWYpO1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgcmVtb3ZlUmVmZXJlbmNlKGlkOiBudW1iZXIsIHRhcmdldElkOiBudW1iZXIpIHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMucmVmZXJlbmNlUmVwby5kZWxldGUoe1xyXG4gICAgICBzb3VyY2VJZDogaWQsXHJcbiAgICAgIHRhcmdldElkOiB0YXJnZXRJZCxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmIChyZXN1bHQuYWZmZWN0ZWQgPT09IDApIHtcclxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXhjZXB0aW9uKCdSZWZlcmVuY2Ugbm90IGZvdW5kJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBhc3luYyBnZXRUYWdzKGlkOiBudW1iZXIpIHtcclxuICAgIGNvbnN0IHJvd3MgPSBhd2FpdCB0aGlzLnRhZ1JlcG8uZmluZCh7XHJcbiAgICAgIHdoZXJlOiB7IGNvcnJlc3BvbmRlbmNlSWQ6IGlkIH0sXHJcbiAgICAgIHJlbGF0aW9uczogWyd0YWcnXSxcclxuICAgIH0pO1xyXG4gICAgcmV0dXJuIHJvd3MubWFwKChyKSA9PiByLnRhZykuZmlsdGVyKEJvb2xlYW4pO1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgYWRkVGFnKGlkOiBudW1iZXIsIHRhZ0lkOiBudW1iZXIpIHtcclxuICAgIGNvbnN0IGNvcnJlc3BvbmRlbmNlID0gYXdhaXQgdGhpcy5jb3JyZXNwb25kZW5jZVJlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IGlkIH0sXHJcbiAgICB9KTtcclxuICAgIGlmICghY29ycmVzcG9uZGVuY2UpIHtcclxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXhjZXB0aW9uKGBDb3JyZXNwb25kZW5jZSAke2lkfSBub3QgZm91bmRgKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB0YWcgPSBhd2FpdCB0aGlzLmRhdGFTb3VyY2UubWFuYWdlci5maW5kT25lKFRhZywge1xyXG4gICAgICB3aGVyZTogeyBpZDogdGFnSWQgfSxcclxuICAgIH0pO1xyXG4gICAgaWYgKCF0YWcpIHtcclxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXhjZXB0aW9uKGBUYWcgJHt0YWdJZH0gbm90IGZvdW5kYCk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgZXhpc3RzID0gYXdhaXQgdGhpcy50YWdSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZTogeyBjb3JyZXNwb25kZW5jZUlkOiBpZCwgdGFnSWQgfSxcclxuICAgIH0pO1xyXG4gICAgaWYgKGV4aXN0cykgcmV0dXJuIGV4aXN0cztcclxuXHJcbiAgICBjb25zdCByb3cgPSB0aGlzLnRhZ1JlcG8uY3JlYXRlKHsgY29ycmVzcG9uZGVuY2VJZDogaWQsIHRhZ0lkIH0pO1xyXG4gICAgcmV0dXJuIHRoaXMudGFnUmVwby5zYXZlKHJvdyk7XHJcbiAgfVxyXG5cclxuICBhc3luYyByZW1vdmVUYWcoaWQ6IG51bWJlciwgdGFnSWQ6IG51bWJlcikge1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy50YWdSZXBvLmRlbGV0ZSh7IGNvcnJlc3BvbmRlbmNlSWQ6IGlkLCB0YWdJZCB9KTtcclxuICAgIGlmIChyZXN1bHQuYWZmZWN0ZWQgPT09IDApIHtcclxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXhjZXB0aW9uKCdUYWcgYXNzaWdubWVudCBub3QgZm91bmQnKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFzeW5jIGdldFJlZmVyZW5jZXMoaWQ6IG51bWJlcikge1xyXG4gICAgY29uc3Qgb3V0Z29pbmcgPSBhd2FpdCB0aGlzLnJlZmVyZW5jZVJlcG8uZmluZCh7XHJcbiAgICAgIHdoZXJlOiB7IHNvdXJjZUlkOiBpZCB9LFxyXG4gICAgICByZWxhdGlvbnM6IFsndGFyZ2V0JywgJ3RhcmdldC50eXBlJ10sXHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbmNvbWluZyA9IGF3YWl0IHRoaXMucmVmZXJlbmNlUmVwby5maW5kKHtcclxuICAgICAgd2hlcmU6IHsgdGFyZ2V0SWQ6IGlkIH0sXHJcbiAgICAgIHJlbGF0aW9uczogWydzb3VyY2UnLCAnc291cmNlLnR5cGUnXSxcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB7IG91dGdvaW5nLCBpbmNvbWluZyB9O1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgdXBkYXRlKGlkOiBudW1iZXIsIHVwZGF0ZUR0bzogVXBkYXRlQ29ycmVzcG9uZGVuY2VEdG8sIHVzZXI6IFVzZXIpIHtcclxuICAgIC8vIDEuIEZpbmQgQ3VycmVudCBSZXZpc2lvblxyXG4gICAgY29uc3QgcmV2aXNpb24gPSBhd2FpdCB0aGlzLnJldmlzaW9uUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHtcclxuICAgICAgICBjb3JyZXNwb25kZW5jZUlkOiBpZCxcclxuICAgICAgICBpc0N1cnJlbnQ6IHRydWUsXHJcbiAgICAgIH0sXHJcbiAgICAgIHJlbGF0aW9uczogWydjb3JyZXNwb25kZW5jZSddLFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKCFyZXZpc2lvbikge1xyXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oXHJcbiAgICAgICAgYEN1cnJlbnQgcmV2aXNpb24gZm9yIGNvcnJlc3BvbmRlbmNlICR7aWR9IG5vdCBmb3VuZGBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyAyLiBDaGVjayBQZXJtaXNzaW9uXHJcbiAgICBpZiAocmV2aXNpb24uc3RhdHVzSWQpIHtcclxuICAgICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgdGhpcy5zdGF0dXNSZXBvLmZpbmRPbmUoe1xyXG4gICAgICAgIHdoZXJlOiB7IGlkOiByZXZpc2lvbi5zdGF0dXNJZCB9LFxyXG4gICAgICB9KTtcclxuICAgICAgaWYgKHN0YXR1cyAmJiBzdGF0dXMuc3RhdHVzQ29kZSAhPT0gJ0RSQUZUJykge1xyXG4gICAgICAgIHRocm93IG5ldyBCYWRSZXF1ZXN0RXhjZXB0aW9uKCdPbmx5IERSQUZUIGRvY3VtZW50cyBjYW4gYmUgdXBkYXRlZCcpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQURSLTAxOTogUmVzb2x2ZSBVVUlEIHJlZmVyZW5jZXMgaW4gdXBkYXRlIERUT1xyXG4gICAgY29uc3QgdXBkUmVzb2x2ZWRQcm9qZWN0SWQgPSB1cGRhdGVEdG8ucHJvamVjdElkXHJcbiAgICAgID8gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZVByb2plY3RJZCh1cGRhdGVEdG8ucHJvamVjdElkKVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuICAgIGNvbnN0IHVwZFJlc29sdmVkT3JpZ2luYXRvcklkID0gdXBkYXRlRHRvLm9yaWdpbmF0b3JJZFxyXG4gICAgICA/IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZCh1cGRhdGVEdG8ub3JpZ2luYXRvcklkKVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuICAgIGNvbnN0IHVwZFJlc29sdmVkUmVjaXBpZW50cyA9IHVwZGF0ZUR0by5yZWNpcGllbnRzXHJcbiAgICAgID8gYXdhaXQgUHJvbWlzZS5hbGwoXHJcbiAgICAgICAgICB1cGRhdGVEdG8ucmVjaXBpZW50cy5tYXAoXHJcbiAgICAgICAgICAgIGFzeW5jIChyKTogUHJvbWlzZTxSZXNvbHZlZFJlY2lwaWVudD4gPT4gKHtcclxuICAgICAgICAgICAgICBvcmdhbml6YXRpb25JZDogYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKFxyXG4gICAgICAgICAgICAgICAgci5vcmdhbml6YXRpb25JZFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgICAgdHlwZTogci50eXBlLFxyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgIClcclxuICAgICAgOiB1bmRlZmluZWQ7XHJcblxyXG4gICAgLy8gMy4gVXBkYXRlIENvcnJlc3BvbmRlbmNlIEVudGl0eSBpZiBuZWVkZWRcclxuICAgIGNvbnN0IGNvcnJlc3BvbmRlbmNlVXBkYXRlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xyXG4gICAgaWYgKHVwZGF0ZUR0by5kaXNjaXBsaW5lSWQpXHJcbiAgICAgIGNvcnJlc3BvbmRlbmNlVXBkYXRlLmRpc2NpcGxpbmVJZCA9IHVwZGF0ZUR0by5kaXNjaXBsaW5lSWQ7XHJcbiAgICBpZiAodXBkUmVzb2x2ZWRQcm9qZWN0SWQpXHJcbiAgICAgIGNvcnJlc3BvbmRlbmNlVXBkYXRlLnByb2plY3RJZCA9IHVwZFJlc29sdmVkUHJvamVjdElkO1xyXG4gICAgaWYgKHVwZFJlc29sdmVkT3JpZ2luYXRvcklkKVxyXG4gICAgICBjb3JyZXNwb25kZW5jZVVwZGF0ZS5vcmlnaW5hdG9ySWQgPSB1cGRSZXNvbHZlZE9yaWdpbmF0b3JJZDtcclxuXHJcbiAgICBpZiAoT2JqZWN0LmtleXMoY29ycmVzcG9uZGVuY2VVcGRhdGUpLmxlbmd0aCA+IDApIHtcclxuICAgICAgYXdhaXQgdGhpcy5jb3JyZXNwb25kZW5jZVJlcG8udXBkYXRlKGlkLCBjb3JyZXNwb25kZW5jZVVwZGF0ZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gNC4gVXBkYXRlIFJldmlzaW9uIEVudGl0eVxyXG4gICAgY29uc3QgcmV2aXNpb25VcGRhdGU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XHJcbiAgICBpZiAodXBkYXRlRHRvLnN1YmplY3QpIHJldmlzaW9uVXBkYXRlLnN1YmplY3QgPSB1cGRhdGVEdG8uc3ViamVjdDtcclxuICAgIGlmICh1cGRhdGVEdG8uYm9keSkgcmV2aXNpb25VcGRhdGUuYm9keSA9IHVwZGF0ZUR0by5ib2R5O1xyXG4gICAgaWYgKHVwZGF0ZUR0by5yZW1hcmtzKSByZXZpc2lvblVwZGF0ZS5yZW1hcmtzID0gdXBkYXRlRHRvLnJlbWFya3M7XHJcbiAgICAvLyBGb3JtYXQgRGF0ZSBjb3JyZWN0bHkgaWYgc3RyaW5nXHJcbiAgICBpZiAodXBkYXRlRHRvLmR1ZURhdGUpIHJldmlzaW9uVXBkYXRlLmR1ZURhdGUgPSBuZXcgRGF0ZSh1cGRhdGVEdG8uZHVlRGF0ZSk7XHJcbiAgICBpZiAodXBkYXRlRHRvLmRvY3VtZW50RGF0ZSlcclxuICAgICAgcmV2aXNpb25VcGRhdGUuZG9jdW1lbnREYXRlID0gbmV3IERhdGUodXBkYXRlRHRvLmRvY3VtZW50RGF0ZSk7XHJcbiAgICBpZiAodXBkYXRlRHRvLmlzc3VlZERhdGUpXHJcbiAgICAgIHJldmlzaW9uVXBkYXRlLmlzc3VlZERhdGUgPSBuZXcgRGF0ZSh1cGRhdGVEdG8uaXNzdWVkRGF0ZSk7XHJcbiAgICBpZiAodXBkYXRlRHRvLnJlY2VpdmVkRGF0ZSlcclxuICAgICAgcmV2aXNpb25VcGRhdGUucmVjZWl2ZWREYXRlID0gbmV3IERhdGUodXBkYXRlRHRvLnJlY2VpdmVkRGF0ZSk7XHJcbiAgICBpZiAodXBkYXRlRHRvLmRlc2NyaXB0aW9uKVxyXG4gICAgICByZXZpc2lvblVwZGF0ZS5kZXNjcmlwdGlvbiA9IHVwZGF0ZUR0by5kZXNjcmlwdGlvbjtcclxuICAgIGlmICh1cGRhdGVEdG8uZGV0YWlscykgcmV2aXNpb25VcGRhdGUuZGV0YWlscyA9IHVwZGF0ZUR0by5kZXRhaWxzO1xyXG5cclxuICAgIGlmIChPYmplY3Qua2V5cyhyZXZpc2lvblVwZGF0ZSkubGVuZ3RoID4gMCkge1xyXG4gICAgICBhd2FpdCB0aGlzLnJldmlzaW9uUmVwby51cGRhdGUocmV2aXNpb24uaWQsIHJldmlzaW9uVXBkYXRlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyA0LjUgQ29tbWl0IG5ldyBhdHRhY2htZW50cyBmcm9tIFRlbXAg4oaSIFBlcm1hbmVudCAoVHdvLVBoYXNlIFN0b3JhZ2UpXHJcbiAgICBpZiAodXBkYXRlRHRvLmF0dGFjaG1lbnRUZW1wSWRzPy5sZW5ndGgpIHtcclxuICAgICAgY29uc3QgaXNzdWVEYXRlID0gdXBkYXRlRHRvLmlzc3VlZERhdGVcclxuICAgICAgICA/IG5ldyBEYXRlKHVwZGF0ZUR0by5pc3N1ZWREYXRlKVxyXG4gICAgICAgIDogdXBkYXRlRHRvLmRvY3VtZW50RGF0ZVxyXG4gICAgICAgICAgPyBuZXcgRGF0ZSh1cGRhdGVEdG8uZG9jdW1lbnREYXRlKVxyXG4gICAgICAgICAgOiByZXZpc2lvbi5pc3N1ZWREYXRlIHx8IHJldmlzaW9uLmRvY3VtZW50RGF0ZSB8fCB1bmRlZmluZWQ7XHJcblxyXG4gICAgICBhd2FpdCB0aGlzLmZpbGVTdG9yYWdlU2VydmljZS5jb21taXQodXBkYXRlRHRvLmF0dGFjaG1lbnRUZW1wSWRzLCB7XHJcbiAgICAgICAgaXNzdWVEYXRlOiBpc3N1ZURhdGUgPyBuZXcgRGF0ZShpc3N1ZURhdGUpIDogdW5kZWZpbmVkLFxyXG4gICAgICAgIGRvY3VtZW50VHlwZTogJ0NvcnJlc3BvbmRlbmNlJyxcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gNS4gVXBkYXRlIFJlY2lwaWVudHMgaWYgcHJvdmlkZWRcclxuICAgIGlmICh1cGRSZXNvbHZlZFJlY2lwaWVudHMpIHtcclxuICAgICAgY29uc3QgcmVjaXBpZW50UmVwbyA9IHRoaXMuZGF0YVNvdXJjZS5nZXRSZXBvc2l0b3J5KFxyXG4gICAgICAgIENvcnJlc3BvbmRlbmNlUmVjaXBpZW50XHJcbiAgICAgICk7XHJcbiAgICAgIGF3YWl0IHJlY2lwaWVudFJlcG8uZGVsZXRlKHsgY29ycmVzcG9uZGVuY2VJZDogaWQgfSk7XHJcblxyXG4gICAgICBjb25zdCBuZXdSZWNpcGllbnRzID0gdXBkUmVzb2x2ZWRSZWNpcGllbnRzLm1hcCgocikgPT5cclxuICAgICAgICByZWNpcGllbnRSZXBvLmNyZWF0ZSh7XHJcbiAgICAgICAgICBjb3JyZXNwb25kZW5jZUlkOiBpZCxcclxuICAgICAgICAgIHJlY2lwaWVudE9yZ2FuaXphdGlvbklkOiByLm9yZ2FuaXphdGlvbklkLFxyXG4gICAgICAgICAgcmVjaXBpZW50VHlwZTogci50eXBlLFxyXG4gICAgICAgIH0pXHJcbiAgICAgICk7XHJcbiAgICAgIGF3YWl0IHJlY2lwaWVudFJlcG8uc2F2ZShuZXdSZWNpcGllbnRzKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyA2LiBSZWdlbmVyYXRlIERvY3VtZW50IE51bWJlciBpZiBzdHJ1Y3R1cmFsIGZpZWxkcyBjaGFuZ2VkIChSZWNpcGllbnQsIERpc2NpcGxpbmUsIFR5cGUsIFByb2plY3QpXHJcbiAgICAvLyBBTkQgaXQgaXMgYSBEUkFGVC5cclxuXHJcbiAgICAvLyBGZXRjaCBmcmVzaCBkYXRhIGZvciBjb250ZXh0IGFuZCBjb21wYXJpc29uXHJcbiAgICBjb25zdCBjdXJyZW50Q29yciA9IGF3YWl0IHRoaXMuY29ycmVzcG9uZGVuY2VSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZTogeyBpZCB9LFxyXG4gICAgICByZWxhdGlvbnM6IFsndHlwZScsICdyZWNpcGllbnRzJywgJ3JlY2lwaWVudHMucmVjaXBpZW50T3JnYW5pemF0aW9uJ10sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoY3VycmVudENvcnIpIHtcclxuICAgICAgY29uc3QgY3VycmVudFRvUmVjaXBpZW50ID0gY3VycmVudENvcnIucmVjaXBpZW50cz8uZmluZChcclxuICAgICAgICAocikgPT4gci5yZWNpcGllbnRUeXBlID09PSAnVE8nXHJcbiAgICAgICk7XHJcbiAgICAgIGNvbnN0IGN1cnJlbnRSZWNpcGllbnRJZCA9IGN1cnJlbnRUb1JlY2lwaWVudD8ucmVjaXBpZW50T3JnYW5pemF0aW9uSWQ7XHJcblxyXG4gICAgICAvLyBDaGVjayBmb3IgQUNUVUFMIHZhbHVlIGNoYW5nZXNcclxuICAgICAgY29uc3QgaXNQcm9qZWN0Q2hhbmdlZCA9XHJcbiAgICAgICAgdXBkUmVzb2x2ZWRQcm9qZWN0SWQgIT09IHVuZGVmaW5lZCAmJlxyXG4gICAgICAgIHVwZFJlc29sdmVkUHJvamVjdElkICE9PSBjdXJyZW50Q29yci5wcm9qZWN0SWQ7XHJcbiAgICAgIGNvbnN0IGlzT3JpZ2luYXRvckNoYW5nZWQgPVxyXG4gICAgICAgIHVwZFJlc29sdmVkT3JpZ2luYXRvcklkICE9PSB1bmRlZmluZWQgJiZcclxuICAgICAgICB1cGRSZXNvbHZlZE9yaWdpbmF0b3JJZCAhPT0gY3VycmVudENvcnIub3JpZ2luYXRvcklkO1xyXG4gICAgICBjb25zdCBpc0Rpc2NpcGxpbmVDaGFuZ2VkID1cclxuICAgICAgICB1cGRhdGVEdG8uZGlzY2lwbGluZUlkICE9PSB1bmRlZmluZWQgJiZcclxuICAgICAgICB1cGRhdGVEdG8uZGlzY2lwbGluZUlkICE9PSBjdXJyZW50Q29yci5kaXNjaXBsaW5lSWQ7XHJcbiAgICAgIGNvbnN0IGlzVHlwZUNoYW5nZWQgPVxyXG4gICAgICAgIHVwZGF0ZUR0by50eXBlSWQgIT09IHVuZGVmaW5lZCAmJlxyXG4gICAgICAgIHVwZGF0ZUR0by50eXBlSWQgIT09IGN1cnJlbnRDb3JyLmNvcnJlc3BvbmRlbmNlVHlwZUlkO1xyXG5cclxuICAgICAgbGV0IGlzUmVjaXBpZW50Q2hhbmdlZCA9IGZhbHNlO1xyXG4gICAgICBsZXQgbmV3UmVjaXBpZW50SWQ6IG51bWJlciB8IHVuZGVmaW5lZDtcclxuXHJcbiAgICAgIGlmICh1cGRSZXNvbHZlZFJlY2lwaWVudHMpIHtcclxuICAgICAgICBjb25zdCBuZXdUb1JlY2lwaWVudCA9IHVwZFJlc29sdmVkUmVjaXBpZW50cy5maW5kKFxyXG4gICAgICAgICAgKHIpID0+IHIudHlwZSA9PT0gJ1RPJ1xyXG4gICAgICAgICk7XHJcbiAgICAgICAgbmV3UmVjaXBpZW50SWQgPSBuZXdUb1JlY2lwaWVudD8ub3JnYW5pemF0aW9uSWQ7XHJcblxyXG4gICAgICAgIGlmIChuZXdSZWNpcGllbnRJZCAhPT0gY3VycmVudFJlY2lwaWVudElkKSB7XHJcbiAgICAgICAgICBpc1JlY2lwaWVudENoYW5nZWQgPSB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIGlzUHJvamVjdENoYW5nZWQgfHxcclxuICAgICAgICBpc0Rpc2NpcGxpbmVDaGFuZ2VkIHx8XHJcbiAgICAgICAgaXNUeXBlQ2hhbmdlZCB8fFxyXG4gICAgICAgIGlzUmVjaXBpZW50Q2hhbmdlZCB8fFxyXG4gICAgICAgIGlzT3JpZ2luYXRvckNoYW5nZWRcclxuICAgICAgKSB7XHJcbiAgICAgICAgY29uc3QgdGFyZ2V0UmVjaXBpZW50SWQgPSBpc1JlY2lwaWVudENoYW5nZWRcclxuICAgICAgICAgID8gbmV3UmVjaXBpZW50SWRcclxuICAgICAgICAgIDogY3VycmVudFJlY2lwaWVudElkO1xyXG5cclxuICAgICAgICAvLyBSZXNvbHZlIFJlY2lwaWVudCBDb2RlIGZvciB0aGUgTkVXIGNvbnRleHRcclxuICAgICAgICBsZXQgcmVjaXBpZW50Q29kZSA9ICcnO1xyXG4gICAgICAgIGlmICh0YXJnZXRSZWNpcGllbnRJZCkge1xyXG4gICAgICAgICAgY29uc3QgcmVjT3JnID0gYXdhaXQgdGhpcy5kYXRhU291cmNlLm1hbmFnZXIuZmluZE9uZShPcmdhbml6YXRpb24sIHtcclxuICAgICAgICAgICAgd2hlcmU6IHsgaWQ6IHRhcmdldFJlY2lwaWVudElkIH0sXHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICAgIGlmIChyZWNPcmcpIHJlY2lwaWVudENvZGUgPSByZWNPcmcub3JnYW5pemF0aW9uQ29kZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFtGaXggIzZdIEZldGNoIHJlYWwgT1JHIENvZGUgZnJvbSBvcmlnaW5hdG9yIG9yZ2FuaXphdGlvblxyXG4gICAgICAgIGNvbnN0IG9yaWdpbmF0b3JPcmdGb3JVcGRhdGUgPSBhd2FpdCB0aGlzLmRhdGFTb3VyY2UubWFuYWdlci5maW5kT25lKFxyXG4gICAgICAgICAgT3JnYW5pemF0aW9uLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICB3aGVyZToge1xyXG4gICAgICAgICAgICAgIGlkOiB1cGRSZXNvbHZlZE9yaWdpbmF0b3JJZCA/PyBjdXJyZW50Q29yci5vcmlnaW5hdG9ySWQgPz8gMCxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICAgIGNvbnN0IG9yZ0NvZGUgPSBvcmlnaW5hdG9yT3JnRm9yVXBkYXRlPy5vcmdhbml6YXRpb25Db2RlID8/ICdVTksnO1xyXG5cclxuICAgICAgICAvLyBQcmVwYXJlIENvbnRleHRzXHJcbiAgICAgICAgY29uc3Qgb2xkQ3R4ID0ge1xyXG4gICAgICAgICAgcHJvamVjdElkOiBjdXJyZW50Q29yci5wcm9qZWN0SWQsXHJcbiAgICAgICAgICBvcmlnaW5hdG9yT3JnYW5pemF0aW9uSWQ6IGN1cnJlbnRDb3JyLm9yaWdpbmF0b3JJZCA/PyAwLFxyXG4gICAgICAgICAgdHlwZUlkOiBjdXJyZW50Q29yci5jb3JyZXNwb25kZW5jZVR5cGVJZCxcclxuICAgICAgICAgIGRpc2NpcGxpbmVJZDogY3VycmVudENvcnIuZGlzY2lwbGluZUlkLFxyXG4gICAgICAgICAgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQ6IGN1cnJlbnRSZWNpcGllbnRJZCxcclxuICAgICAgICAgIHllYXI6IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKSxcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICBjb25zdCBuZXdDdHggPSB7XHJcbiAgICAgICAgICBwcm9qZWN0SWQ6IHVwZFJlc29sdmVkUHJvamVjdElkID8/IGN1cnJlbnRDb3JyLnByb2plY3RJZCxcclxuICAgICAgICAgIG9yaWdpbmF0b3JPcmdhbml6YXRpb25JZDpcclxuICAgICAgICAgICAgdXBkUmVzb2x2ZWRPcmlnaW5hdG9ySWQgPz8gY3VycmVudENvcnIub3JpZ2luYXRvcklkID8/IDAsXHJcbiAgICAgICAgICB0eXBlSWQ6IHVwZGF0ZUR0by50eXBlSWQgPz8gY3VycmVudENvcnIuY29ycmVzcG9uZGVuY2VUeXBlSWQsXHJcbiAgICAgICAgICBkaXNjaXBsaW5lSWQ6IHVwZGF0ZUR0by5kaXNjaXBsaW5lSWQgPz8gY3VycmVudENvcnIuZGlzY2lwbGluZUlkLFxyXG4gICAgICAgICAgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQ6IHRhcmdldFJlY2lwaWVudElkLFxyXG4gICAgICAgICAgeWVhcjogbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpLFxyXG4gICAgICAgICAgdXNlcklkOiB1c2VyLnVzZXJfaWQsIC8vIFBhc3MgVXNlciBJRCBmb3IgQXVkaXRcclxuICAgICAgICAgIGN1c3RvbVRva2Vuczoge1xyXG4gICAgICAgICAgICBUWVBFX0NPREU6IGN1cnJlbnRDb3JyLnR5cGU/LnR5cGVDb2RlIHx8ICcnLFxyXG4gICAgICAgICAgICBPUkdfQ09ERTogb3JnQ29kZSxcclxuICAgICAgICAgICAgUkVDSVBJRU5UX0NPREU6IHJlY2lwaWVudENvZGUsXHJcbiAgICAgICAgICAgIFJFQ19DT0RFOiByZWNpcGllbnRDb2RlLFxyXG4gICAgICAgICAgfSxcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICAvLyBJZiBUeXBlIENoYW5nZWQsIG5lZWQgTkVXIFR5cGUgQ29kZVxyXG4gICAgICAgIGlmIChpc1R5cGVDaGFuZ2VkKSB7XHJcbiAgICAgICAgICBjb25zdCBuZXdUeXBlID0gYXdhaXQgdGhpcy50eXBlUmVwby5maW5kT25lKHtcclxuICAgICAgICAgICAgd2hlcmU6IHsgaWQ6IG5ld0N0eC50eXBlSWQgfSxcclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgaWYgKG5ld1R5cGUpIG5ld0N0eC5jdXN0b21Ub2tlbnMuVFlQRV9DT0RFID0gbmV3VHlwZS50eXBlQ29kZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNvbnN0IG5ld0RvY051bWJlciA9IGF3YWl0IHRoaXMubnVtYmVyaW5nU2VydmljZS51cGRhdGVOdW1iZXJGb3JEcmFmdChcclxuICAgICAgICAgIGN1cnJlbnRDb3JyLmNvcnJlc3BvbmRlbmNlTnVtYmVyLFxyXG4gICAgICAgICAgb2xkQ3R4LFxyXG4gICAgICAgICAgbmV3Q3R4XHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgYXdhaXQgdGhpcy5jb3JyZXNwb25kZW5jZVJlcG8udXBkYXRlKGlkLCB7XHJcbiAgICAgICAgICBjb3JyZXNwb25kZW5jZU51bWJlcjogbmV3RG9jTnVtYmVyLFxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgdXBkYXRlZCA9IGF3YWl0IHRoaXMuZmluZE9uZShpZCk7XHJcblxyXG4gICAgLy8gUmUtaW5kZXggdXBkYXRlZCBkb2N1bWVudCBpbiBFbGFzdGljc2VhcmNoIChmaXJlLWFuZC1mb3JnZXQpXHJcbiAgICB2b2lkIHRoaXMuc2VhcmNoU2VydmljZS5pbmRleERvY3VtZW50KHtcclxuICAgICAgaWQ6IHVwZGF0ZWQuaWQsXHJcbiAgICAgIHB1YmxpY0lkOiB1cGRhdGVkLnB1YmxpY0lkLFxyXG4gICAgICB0eXBlOiAnY29ycmVzcG9uZGVuY2UnLFxyXG4gICAgICBkb2NOdW1iZXI6IHVwZGF0ZWQuY29ycmVzcG9uZGVuY2VOdW1iZXIsXHJcbiAgICAgIHRpdGxlOiB1cGRhdGVEdG8uc3ViamVjdCA/PyB1cGRhdGVkLnJldmlzaW9ucz8uWzBdPy5zdWJqZWN0LFxyXG4gICAgICBkZXNjcmlwdGlvbjogdXBkYXRlRHRvLmRlc2NyaXB0aW9uID8/IHVwZGF0ZWQucmV2aXNpb25zPy5bMF0/LmRlc2NyaXB0aW9uLFxyXG4gICAgICBzdGF0dXM6ICdEUkFGVCcsXHJcbiAgICAgIHByb2plY3RJZDogdXBkYXRlZC5wcm9qZWN0SWQsXHJcbiAgICAgIGNyZWF0ZWRBdDogdXBkYXRlZC5jcmVhdGVkQXQsXHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4gdXBkYXRlZDtcclxuICB9XHJcblxyXG4gIGFzeW5jIHByZXZpZXdEb2N1bWVudE51bWJlcihjcmVhdGVEdG86IENyZWF0ZUNvcnJlc3BvbmRlbmNlRHRvLCB1c2VyOiBVc2VyKSB7XHJcbiAgICAvLyBBRFItMDE5OiBSZXNvbHZlIFVVSUQgcmVmZXJlbmNlc1xyXG4gICAgY29uc3QgcHJldmlld1Byb2plY3RJZCA9IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVQcm9qZWN0SWQoXHJcbiAgICAgIGNyZWF0ZUR0by5wcm9qZWN0SWRcclxuICAgICk7XHJcbiAgICBjb25zdCBwcmV2aWV3T3JpZ2luYXRvcklkID0gY3JlYXRlRHRvLm9yaWdpbmF0b3JJZFxyXG4gICAgICA/IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZChjcmVhdGVEdG8ub3JpZ2luYXRvcklkKVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuICAgIGNvbnN0IHByZXZpZXdSZWNpcGllbnRzID0gY3JlYXRlRHRvLnJlY2lwaWVudHNcclxuICAgICAgPyBhd2FpdCBQcm9taXNlLmFsbChcclxuICAgICAgICAgIGNyZWF0ZUR0by5yZWNpcGllbnRzLm1hcChcclxuICAgICAgICAgICAgYXN5bmMgKHIpOiBQcm9taXNlPFJlc29sdmVkUmVjaXBpZW50PiA9PiAoe1xyXG4gICAgICAgICAgICAgIG9yZ2FuaXphdGlvbklkOiBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlT3JnYW5pemF0aW9uSWQoXHJcbiAgICAgICAgICAgICAgICByLm9yZ2FuaXphdGlvbklkXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgICB0eXBlOiByLnR5cGUsXHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgKVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuXHJcbiAgICBjb25zdCB0eXBlID0gYXdhaXQgdGhpcy50eXBlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgaWQ6IGNyZWF0ZUR0by50eXBlSWQgfSxcclxuICAgIH0pO1xyXG4gICAgaWYgKCF0eXBlKSB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oJ0RvY3VtZW50IFR5cGUgbm90IGZvdW5kJyk7XHJcblxyXG4gICAgbGV0IHVzZXJPcmdJZCA9IHVzZXIucHJpbWFyeU9yZ2FuaXphdGlvbklkO1xyXG4gICAgaWYgKCF1c2VyT3JnSWQpIHtcclxuICAgICAgY29uc3QgZnVsbFVzZXIgPSBhd2FpdCB0aGlzLnVzZXJTZXJ2aWNlLmZpbmRPbmUodXNlci51c2VyX2lkKTtcclxuICAgICAgaWYgKGZ1bGxVc2VyKSB1c2VyT3JnSWQgPSBmdWxsVXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHByZXZpZXdPcmlnaW5hdG9ySWQgJiYgcHJldmlld09yaWdpbmF0b3JJZCAhPT0gdXNlck9yZ0lkKSB7XHJcbiAgICAgIC8vIEFsbG93IGltcGVyc29uYXRpb24gZm9yIHByZXZpZXdcclxuICAgICAgdXNlck9yZ0lkID0gcHJldmlld09yaWdpbmF0b3JJZDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBFeHRyYWN0IHJlY2lwaWVudCBmcm9tIHJlY2lwaWVudHMgYXJyYXlcclxuICAgIGNvbnN0IHRvUmVjaXBpZW50ID0gcHJldmlld1JlY2lwaWVudHM/LmZpbmQoKHIpID0+IHIudHlwZSA9PT0gJ1RPJyk7XHJcbiAgICBjb25zdCByZWNpcGllbnRPcmdhbml6YXRpb25JZCA9IHRvUmVjaXBpZW50Py5vcmdhbml6YXRpb25JZDtcclxuXHJcbiAgICBsZXQgcmVjaXBpZW50Q29kZSA9ICcnO1xyXG4gICAgaWYgKHJlY2lwaWVudE9yZ2FuaXphdGlvbklkKSB7XHJcbiAgICAgIGNvbnN0IHJlY09yZyA9IGF3YWl0IHRoaXMuZGF0YVNvdXJjZS5tYW5hZ2VyLmZpbmRPbmUoT3JnYW5pemF0aW9uLCB7XHJcbiAgICAgICAgd2hlcmU6IHsgaWQ6IHJlY2lwaWVudE9yZ2FuaXphdGlvbklkIH0sXHJcbiAgICAgIH0pO1xyXG4gICAgICBpZiAocmVjT3JnKSByZWNpcGllbnRDb2RlID0gcmVjT3JnLm9yZ2FuaXphdGlvbkNvZGU7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXMubnVtYmVyaW5nU2VydmljZS5wcmV2aWV3TnVtYmVyKHtcclxuICAgICAgcHJvamVjdElkOiBwcmV2aWV3UHJvamVjdElkLFxyXG4gICAgICBvcmlnaW5hdG9yT3JnYW5pemF0aW9uSWQ6IHVzZXJPcmdJZCEsXHJcbiAgICAgIHR5cGVJZDogY3JlYXRlRHRvLnR5cGVJZCxcclxuICAgICAgZGlzY2lwbGluZUlkOiBjcmVhdGVEdG8uZGlzY2lwbGluZUlkLFxyXG4gICAgICBzdWJUeXBlSWQ6IGNyZWF0ZUR0by5zdWJUeXBlSWQsXHJcbiAgICAgIHJlY2lwaWVudE9yZ2FuaXphdGlvbklkLFxyXG4gICAgICB5ZWFyOiBuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCksXHJcbiAgICAgIGN1c3RvbVRva2Vuczoge1xyXG4gICAgICAgIFRZUEVfQ09ERTogdHlwZS50eXBlQ29kZSxcclxuICAgICAgICBSRUNJUElFTlRfQ09ERTogcmVjaXBpZW50Q29kZSxcclxuICAgICAgICBSRUNfQ09ERTogcmVjaXBpZW50Q29kZSxcclxuICAgICAgfSxcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQnVzaW5lc3MgUnVsZSBJbXBsZW1lbnRhdGlvbjogRUMtQ09SUi0wMDEgLSBDYW5jZWwgQ29ycmVzcG9uZGVuY2Ugd2l0aCBEb3duc3RyZWFtIENpcmN1bGF0aW9uXHJcbiAgICogQ2FuY2VsIGNvcnJlc3BvbmRlbmNlIGFuZCBoYW5kbGUgcmVsYXRlZCBjaXJjdWxhdGlvbnNcclxuICAgKi9cclxuICBhc3luYyBjYW5jZWwocHVibGljSWQ6IHN0cmluZywgcmVhc29uOiBzdHJpbmcsIHVzZXI6IFVzZXIpIHtcclxuICAgIGNvbnN0IGNvcnJlc3BvbmRlbmNlID0gYXdhaXQgdGhpcy5maW5kT25lQnlVdWlkKHB1YmxpY0lkKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB1c2VyIGhhcyBwZXJtaXNzaW9uIHRvIGNhbmNlbCAoT3JnIEFkbWluIG9yIFN1cGVyYWRtaW4gb25seSlcclxuICAgIGNvbnN0IHBlcm1pc3Npb25zID0gYXdhaXQgdGhpcy51c2VyU2VydmljZS5nZXRVc2VyUGVybWlzc2lvbnModXNlci51c2VyX2lkKTtcclxuICAgIGNvbnN0IGNhbkNhbmNlbCA9XHJcbiAgICAgIHBlcm1pc3Npb25zLmluY2x1ZGVzKCdjb3JyZXNwb25kZW5jZS5jYW5jZWwnKSB8fFxyXG4gICAgICBwZXJtaXNzaW9ucy5pbmNsdWRlcygnc3lzdGVtLm1hbmFnZV9hbGwnKTtcclxuXHJcbiAgICBpZiAoIWNhbkNhbmNlbCkge1xyXG4gICAgICB0aHJvdyBuZXcgRm9yYmlkZGVuRXhjZXB0aW9uKFxyXG4gICAgICAgICdPbmx5IGFkbWluaXN0cmF0b3JzIGNhbiBjYW5jZWwgY29ycmVzcG9uZGVuY2VzJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGFyZSBhbnkgYWN0aXZlIGNpcmN1bGF0aW9uc1xyXG4gICAgY29uc3QgY2lyY3VsYXRpb25SZXBvID0gdGhpcy5kYXRhU291cmNlLmdldFJlcG9zaXRvcnkoJ0NpcmN1bGF0aW9uJyk7XHJcbiAgICBjb25zdCBhY3RpdmVDaXJjdWxhdGlvbnMgPSBhd2FpdCBjaXJjdWxhdGlvblJlcG8uZmluZCh7XHJcbiAgICAgIHdoZXJlOiB7XHJcbiAgICAgICAgY29ycmVzcG9uZGVuY2VJZDogY29ycmVzcG9uZGVuY2UuaWQsXHJcbiAgICAgICAgc3RhdHVzOiAnT1BFTicsXHJcbiAgICAgIH0sXHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCB3YXJuaW5nTWVzc2FnZSA9XHJcbiAgICAgIGFjdGl2ZUNpcmN1bGF0aW9ucy5sZW5ndGggPiAwXHJcbiAgICAgICAgPyBgVGhlcmUgYXJlICR7YWN0aXZlQ2lyY3VsYXRpb25zLmxlbmd0aH0gYWN0aXZlIGNpcmN1bGF0aW9uKHMpIGZvciB0aGlzIGNvcnJlc3BvbmRlbmNlLiBDYW5jZWxpbmcgd2lsbCBmb3JjZSBjbG9zZSBhbGwgcmVsYXRlZCBjaXJjdWxhdGlvbnMuYFxyXG4gICAgICAgIDogJyc7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjdXJyZW50IHJldmlzaW9uIHRvIHVwZGF0ZSBzdGF0dXNcclxuICAgIGNvbnN0IGN1cnJlbnRSZXZpc2lvbiA9IGF3YWl0IHRoaXMucmV2aXNpb25SZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZToge1xyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IGNvcnJlc3BvbmRlbmNlLmlkLFxyXG4gICAgICAgIGlzQ3VycmVudDogdHJ1ZSxcclxuICAgICAgfSxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmICghY3VycmVudFJldmlzaW9uKSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbignQ3VycmVudCByZXZpc2lvbiBub3QgZm91bmQnKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgY2FuY2VsbGVkIHN0YXR1c1xyXG4gICAgY29uc3QgY2FuY2VsbGVkU3RhdHVzID0gYXdhaXQgdGhpcy5zdGF0dXNSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZTogeyBzdGF0dXNDb2RlOiAnQ0FOQ0VMTEVEJyB9LFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKCFjYW5jZWxsZWRTdGF0dXMpIHtcclxuICAgICAgdGhyb3cgbmV3IEludGVybmFsU2VydmVyRXJyb3JFeGNlcHRpb24oJ0NBTkNFTExFRCBzdGF0dXMgbm90IGZvdW5kJyk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgcXVlcnlSdW5uZXIgPSB0aGlzLmRhdGFTb3VyY2UuY3JlYXRlUXVlcnlSdW5uZXIoKTtcclxuICAgIGF3YWl0IHF1ZXJ5UnVubmVyLmNvbm5lY3QoKTtcclxuICAgIGF3YWl0IHF1ZXJ5UnVubmVyLnN0YXJ0VHJhbnNhY3Rpb24oKTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBVcGRhdGUgY29ycmVzcG9uZGVuY2UgcmV2aXNpb24gc3RhdHVzIHRvIENBTkNFTExFRFxyXG4gICAgICBhd2FpdCBxdWVyeVJ1bm5lci5tYW5hZ2VyLnVwZGF0ZShcclxuICAgICAgICBDb3JyZXNwb25kZW5jZVJldmlzaW9uLFxyXG4gICAgICAgIGN1cnJlbnRSZXZpc2lvbi5pZCxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBzdGF0dXNJZDogY2FuY2VsbGVkU3RhdHVzLmlkLFxyXG4gICAgICAgICAgcmVtYXJrczogYENhbmNlbGxlZDogJHtyZWFzb259YCxcclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBGb3JjZSBjbG9zZSBhbGwgYWN0aXZlIGNpcmN1bGF0aW9uc1xyXG4gICAgICBpZiAoYWN0aXZlQ2lyY3VsYXRpb25zLmxlbmd0aCA+IDApIHtcclxuICAgICAgICBhd2FpdCBxdWVyeVJ1bm5lci5tYW5hZ2VyLnVwZGF0ZShcclxuICAgICAgICAgICdDaXJjdWxhdGlvbicsXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IGNvcnJlc3BvbmRlbmNlLmlkLFxyXG4gICAgICAgICAgICBzdGF0dXM6ICdPUEVOJyxcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIHN0YXR1czogJ0ZPUkNFX0NMT1NFRCcsXHJcbiAgICAgICAgICAgIGNsb3NlZEF0OiBuZXcgRGF0ZSgpLFxyXG4gICAgICAgICAgICBjbG9zZWRCeTogdXNlci51c2VyX2lkLFxyXG4gICAgICAgICAgICBjbG9zZVJlYXNvbjogYENvcnJlc3BvbmRlbmNlIGNhbmNlbGxlZDogJHtyZWFzb259YCxcclxuICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBhd2FpdCBxdWVyeVJ1bm5lci5jb21taXRUcmFuc2FjdGlvbigpO1xyXG5cclxuICAgICAgLy8gUmUtaW5kZXggY2FuY2VsbGVkIHN0YXR1cyBpbiBFbGFzdGljc2VhcmNoIChmaXJlLWFuZC1mb3JnZXQpXHJcbiAgICAgIHZvaWQgdGhpcy5zZWFyY2hTZXJ2aWNlLmluZGV4RG9jdW1lbnQoe1xyXG4gICAgICAgIGlkOiBjb3JyZXNwb25kZW5jZS5pZCxcclxuICAgICAgICBwdWJsaWNJZDogY29ycmVzcG9uZGVuY2UucHVibGljSWQsXHJcbiAgICAgICAgdHlwZTogJ2NvcnJlc3BvbmRlbmNlJyxcclxuICAgICAgICBkb2NOdW1iZXI6IGNvcnJlc3BvbmRlbmNlLmNvcnJlc3BvbmRlbmNlTnVtYmVyLFxyXG4gICAgICAgIHRpdGxlOiBjdXJyZW50UmV2aXNpb24uc3ViamVjdCxcclxuICAgICAgICBzdGF0dXM6ICdDQU5DRUxMRUQnLFxyXG4gICAgICAgIHByb2plY3RJZDogY29ycmVzcG9uZGVuY2UucHJvamVjdElkLFxyXG4gICAgICAgIGNyZWF0ZWRBdDogY29ycmVzcG9uZGVuY2UuY3JlYXRlZEF0LFxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIE5vdGlmeSBvcmlnaW5hdG9yJ3MgZG9jLWNvbnRyb2wgdXNlciBhYm91dCBjYW5jZWxsYXRpb24gKGZpcmUtYW5kLWZvcmdldClcclxuICAgICAgaWYgKGNvcnJlc3BvbmRlbmNlLm9yaWdpbmF0b3JJZCkge1xyXG4gICAgICAgIHZvaWQgdGhpcy51c2VyU2VydmljZVxyXG4gICAgICAgICAgLmZpbmREb2NDb250cm9sSWRCeU9yZyhjb3JyZXNwb25kZW5jZS5vcmlnaW5hdG9ySWQpXHJcbiAgICAgICAgICAudGhlbigodGFyZ2V0VXNlcklkKSA9PiB7XHJcbiAgICAgICAgICAgIGlmICh0YXJnZXRVc2VySWQpIHtcclxuICAgICAgICAgICAgICB2b2lkIHRoaXMubm90aWZpY2F0aW9uU2VydmljZS5zZW5kKHtcclxuICAgICAgICAgICAgICAgIHVzZXJJZDogdGFyZ2V0VXNlcklkLFxyXG4gICAgICAgICAgICAgICAgdGl0bGU6ICdDb3JyZXNwb25kZW5jZSBDYW5jZWxsZWQnLFxyXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYCR7Y29ycmVzcG9uZGVuY2UuY29ycmVzcG9uZGVuY2VOdW1iZXJ9IOKAlCAke2N1cnJlbnRSZXZpc2lvbi5zdWJqZWN0fSBoYXMgYmVlbiBjYW5jZWxsZWQuIFJlYXNvbjogJHtyZWFzb259YCxcclxuICAgICAgICAgICAgICAgIHR5cGU6ICdFTUFJTCcsXHJcbiAgICAgICAgICAgICAgICBlbnRpdHlUeXBlOiAnY29ycmVzcG9uZGVuY2UnLFxyXG4gICAgICAgICAgICAgICAgZW50aXR5SWQ6IGNvcnJlc3BvbmRlbmNlLmlkLFxyXG4gICAgICAgICAgICAgICAgbGluazogYC9jb3JyZXNwb25kZW5jZXMvJHtjb3JyZXNwb25kZW5jZS5wdWJsaWNJZH1gLFxyXG4gICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9KVxyXG4gICAgICAgICAgLmNhdGNoKChlcnI6IEVycm9yKSA9PlxyXG4gICAgICAgICAgICB0aGlzLmxvZ2dlci53YXJuKGBDYW5jZWwgbm90aWZpY2F0aW9uIGZhaWxlZDogJHtlcnIubWVzc2FnZX1gKVxyXG4gICAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBzdWNjZXNzOiB0cnVlLFxyXG4gICAgICAgIG1lc3NhZ2U6IHdhcm5pbmdNZXNzYWdlIHx8ICdDb3JyZXNwb25kZW5jZSBjYW5jZWxsZWQgc3VjY2Vzc2Z1bGx5JyxcclxuICAgICAgICBhY3RpdmVDaXJjdWxhdGlvbnNDb3VudDogYWN0aXZlQ2lyY3VsYXRpb25zLmxlbmd0aCxcclxuICAgICAgfTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLnJvbGxiYWNrVHJhbnNhY3Rpb24oKTtcclxuICAgICAgdGhpcy5sb2dnZXIuZXJyb3IoXHJcbiAgICAgICAgYEZhaWxlZCB0byBjYW5jZWwgY29ycmVzcG9uZGVuY2U6ICR7KGVycm9yIGFzIEVycm9yKS5tZXNzYWdlfWBcclxuICAgICAgKTtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9IGZpbmFsbHkge1xyXG4gICAgICBhd2FpdCBxdWVyeVJ1bm5lci5yZWxlYXNlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBhc3luYyBidWxrQ2FuY2VsKFxyXG4gICAgcHVibGljSWRzOiBzdHJpbmdbXSxcclxuICAgIHJlYXNvbjogc3RyaW5nLFxyXG4gICAgdXNlcjogVXNlclxyXG4gICk6IFByb21pc2U8eyBzdWNjZWVkZWQ6IHN0cmluZ1tdOyBmYWlsZWQ6IHN0cmluZ1tdIH0+IHtcclxuICAgIGNvbnN0IHN1Y2NlZWRlZDogc3RyaW5nW10gPSBbXTtcclxuICAgIGNvbnN0IGZhaWxlZDogc3RyaW5nW10gPSBbXTtcclxuXHJcbiAgICBmb3IgKGNvbnN0IHB1YmxpY0lkIG9mIHB1YmxpY0lkcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGF3YWl0IHRoaXMuY2FuY2VsKHB1YmxpY0lkLCByZWFzb24sIHVzZXIpO1xyXG4gICAgICAgIHN1Y2NlZWRlZC5wdXNoKHB1YmxpY0lkKTtcclxuICAgICAgfSBjYXRjaCB7XHJcbiAgICAgICAgZmFpbGVkLnB1c2gocHVibGljSWQpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHsgc3VjY2VlZGVkLCBmYWlsZWQgfTtcclxuICB9XHJcblxyXG4gIGFzeW5jIGV4cG9ydENzdihzZWFyY2hEdG86IFNlYXJjaENvcnJlc3BvbmRlbmNlRHRvKTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgIGNvbnN0IHsgZGF0YSB9ID0gYXdhaXQgdGhpcy5maW5kQWxsKHNlYXJjaER0byk7XHJcblxyXG4gICAgY29uc3QgaGVhZGVyID0gW1xyXG4gICAgICAnRG9jdW1lbnQgTm8uJyxcclxuICAgICAgJ1JldicsXHJcbiAgICAgICdTdWJqZWN0JyxcclxuICAgICAgJ1R5cGUnLFxyXG4gICAgICAnU3RhdHVzJyxcclxuICAgICAgJ1Byb2plY3QnLFxyXG4gICAgICAnRnJvbScsXHJcbiAgICAgICdEdWUgRGF0ZScsXHJcbiAgICAgICdDcmVhdGVkIEF0JyxcclxuICAgIF07XHJcbiAgICBjb25zdCByb3dzID0gZGF0YS5tYXAoKHJldikgPT4ge1xyXG4gICAgICBjb25zdCBjb3JyID0gcmV2LmNvcnJlc3BvbmRlbmNlID8/IChyZXYgYXMgdW5rbm93biBhcyBDb3JyZXNwb25kZW5jZSk7XHJcbiAgICAgIHJldHVybiBbXHJcbiAgICAgICAgdGhpcy5lc2NhcGVDc3YoY29yci5jb3JyZXNwb25kZW5jZU51bWJlciA/PyAnJyksXHJcbiAgICAgICAgdGhpcy5lc2NhcGVDc3YocmV2LnJldmlzaW9uTGFiZWwgPz8gU3RyaW5nKHJldi5yZXZpc2lvbk51bWJlciA/PyAwKSksXHJcbiAgICAgICAgdGhpcy5lc2NhcGVDc3YocmV2LnN1YmplY3QgPz8gJycpLFxyXG4gICAgICAgIHRoaXMuZXNjYXBlQ3N2KGNvcnIudHlwZT8udHlwZUNvZGUgPz8gJycpLFxyXG4gICAgICAgIHRoaXMuZXNjYXBlQ3N2KHJldi5zdGF0dXM/LnN0YXR1c0NvZGUgPz8gJycpLFxyXG4gICAgICAgIHRoaXMuZXNjYXBlQ3N2KGNvcnIucHJvamVjdD8ucHJvamVjdENvZGUgPz8gJycpLFxyXG4gICAgICAgIHRoaXMuZXNjYXBlQ3N2KGNvcnIub3JpZ2luYXRvcj8ub3JnYW5pemF0aW9uQ29kZSA/PyAnJyksXHJcbiAgICAgICAgcmV2LmR1ZURhdGUgPyBuZXcgRGF0ZShyZXYuZHVlRGF0ZSkudG9JU09TdHJpbmcoKS5zcGxpdCgnVCcpWzBdIDogJycsXHJcbiAgICAgICAgbmV3IERhdGUocmV2LmNyZWF0ZWRBdCkudG9JU09TdHJpbmcoKS5zcGxpdCgnVCcpWzBdLFxyXG4gICAgICBdLmpvaW4oJywnKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiBbaGVhZGVyLmpvaW4oJywnKSwgLi4ucm93c10uam9pbignXFxuJyk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGVzY2FwZUNzdih2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIGlmICh2YWx1ZS5pbmNsdWRlcygnLCcpIHx8IHZhbHVlLmluY2x1ZGVzKCdcIicpIHx8IHZhbHVlLmluY2x1ZGVzKCdcXG4nKSkge1xyXG4gICAgICByZXR1cm4gYFwiJHt2YWx1ZS5yZXBsYWNlKC9cIi9nLCAnXCJcIicpfVwiYDtcclxuICAgIH1cclxuICAgIHJldHVybiB2YWx1ZTtcclxuICB9XHJcbn1cclxuIl0sInZlcnNpb24iOjN9 \ No newline at end of file diff --git a/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/50/correspondenceservice_502139c633196704eef09d9c7ce64dc0.map b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/50/correspondenceservice_502139c633196704eef09d9c7ce64dc0.map new file mode 100644 index 0000000..84cf18f --- /dev/null +++ b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/50/correspondenceservice_502139c633196704eef09d9c7ce64dc0.map @@ -0,0 +1 @@ +{"file":"E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.ts","mappings":"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","names":[],"sources":["E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.ts"],"sourcesContent":["// File: src/modules/correspondence/correspondence.service.ts\r\n\r\nimport {\r\n Injectable,\r\n NotFoundException,\r\n BadRequestException,\r\n InternalServerErrorException,\r\n ForbiddenException,\r\n Logger,\r\n} from '@nestjs/common';\r\nimport { InjectRepository } from '@nestjs/typeorm';\r\nimport { Repository, DataSource } from 'typeorm';\r\n\r\n// Entities\r\nimport { Correspondence } from './entities/correspondence.entity';\r\nimport { CorrespondenceRevision } from './entities/correspondence-revision.entity';\r\nimport { CorrespondenceType } from './entities/correspondence-type.entity';\r\nimport { CorrespondenceStatus } from './entities/correspondence-status.entity';\r\nimport { CorrespondenceReference } from './entities/correspondence-reference.entity';\r\nimport { CorrespondenceRecipient } from './entities/correspondence-recipient.entity';\r\nimport { CorrespondenceTag } from './entities/correspondence-tag.entity';\r\nimport { Tag } from '../master/entities/tag.entity';\r\nimport { User } from '../user/entities/user.entity';\r\nimport { Organization } from '../organization/entities/organization.entity';\r\n\r\n// DTOs\r\nimport { CreateCorrespondenceDto } from './dto/create-correspondence.dto';\r\nimport { UpdateCorrespondenceDto } from './dto/update-correspondence.dto';\r\nimport { AddReferenceDto } from './dto/add-reference.dto';\r\nimport { SearchCorrespondenceDto } from './dto/search-correspondence.dto';\r\n\r\n// Services\r\nimport { DocumentNumberingService } from '../document-numbering/services/document-numbering.service';\r\nimport { JsonSchemaService } from '../json-schema/json-schema.service';\r\nimport { WorkflowEngineService } from '../workflow-engine/workflow-engine.service';\r\nimport { UserService } from '../user/user.service';\r\nimport { SearchService } from '../search/search.service';\r\nimport { FileStorageService } from '../../common/file-storage/file-storage.service';\r\nimport { UuidResolverService } from '../../common/services/uuid-resolver.service';\r\nimport { NotificationService } from '../notification/notification.service';\r\n\r\n/**\r\n * CorrespondenceService - Document management (CRUD)\r\n */\r\ninterface ResolvedRecipient {\r\n organizationId: number;\r\n type: 'TO' | 'CC';\r\n}\r\n@Injectable()\r\nexport class CorrespondenceService {\r\n private readonly logger = new Logger(CorrespondenceService.name);\r\n\r\n private async hasSystemManageAllPermission(userId: number): Promise {\r\n const permissions = await this.userService.getUserPermissions(userId);\r\n return permissions.includes('system.manage_all');\r\n }\r\n\r\n /**\r\n * Business Rule: Revision Label Strategy\r\n * - RFA, RFI: Use alphabet starting with 'A' (A, B, C...)\r\n * - Other types (LETTER, MEMO, etc.): Use numeric (null for first, then 1, 2, 3...)\r\n */\r\n private getInitialRevisionLabel(typeCode: string): string | null {\r\n const alphabetTypes = ['RFA', 'RFI'];\r\n if (alphabetTypes.includes(typeCode.toUpperCase())) {\r\n return 'A'; // Alphabet for RFA, RFI\r\n }\r\n return null; // Numeric (null for revision 0)\r\n }\r\n\r\n constructor(\r\n @InjectRepository(Correspondence)\r\n private correspondenceRepo: Repository,\r\n @InjectRepository(CorrespondenceRevision)\r\n private revisionRepo: Repository,\r\n @InjectRepository(CorrespondenceType)\r\n private typeRepo: Repository,\r\n @InjectRepository(CorrespondenceStatus)\r\n private statusRepo: Repository,\r\n @InjectRepository(CorrespondenceReference)\r\n private referenceRepo: Repository,\r\n @InjectRepository(CorrespondenceTag)\r\n private tagRepo: Repository,\r\n private numberingService: DocumentNumberingService,\r\n private jsonSchemaService: JsonSchemaService,\r\n private workflowEngine: WorkflowEngineService,\r\n private userService: UserService,\r\n private dataSource: DataSource,\r\n private searchService: SearchService,\r\n private fileStorageService: FileStorageService,\r\n private uuidResolver: UuidResolverService,\r\n private notificationService: NotificationService\r\n ) {}\r\n\r\n /**\r\n * Business Rule Validation: EC-CORR-003 - Correspondence to Self\r\n * Prevent external correspondence to same organization\r\n */\r\n private async validateCorrespondenceRecipients(\r\n createDto: CreateCorrespondenceDto,\r\n user: User\r\n ): Promise {\r\n // Get user's organization\r\n let userOrgId = user.primaryOrganizationId;\r\n if (!userOrgId) {\r\n const fullUser = await this.userService.findOne(user.user_id);\r\n if (fullUser) {\r\n userOrgId = fullUser.primaryOrganizationId;\r\n }\r\n }\r\n\r\n if (!userOrgId) {\r\n if (createDto.originatorId) {\r\n const canManageAll = await this.hasSystemManageAllPermission(\r\n user.user_id\r\n );\r\n if (canManageAll) {\r\n userOrgId = await this.uuidResolver.resolveOrganizationId(\r\n createDto.originatorId\r\n );\r\n }\r\n }\r\n\r\n if (!userOrgId) {\r\n throw new BadRequestException(\r\n 'User must belong to an organization to create documents'\r\n );\r\n }\r\n }\r\n\r\n // For impersonation, use the specified originator\r\n const originatorOrgId = createDto.originatorId\r\n ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId)\r\n : userOrgId;\r\n\r\n // Check if it's internal communication\r\n if (createDto.isInternal) {\r\n // Internal communications should use Circulation instead\r\n throw new BadRequestException(\r\n 'Internal communications should use Circulation Sheet instead of Correspondence'\r\n );\r\n }\r\n\r\n // Validate recipients\r\n if (!createDto.recipients || createDto.recipients.length === 0) {\r\n throw new BadRequestException(\r\n 'At least one recipient (TO or CC) is required'\r\n );\r\n }\r\n\r\n const toRecipients = createDto.recipients.filter((r) => r.type === 'TO');\r\n const ccRecipients = createDto.recipients.filter((r) => r.type === 'CC');\r\n\r\n if (toRecipients.length === 0 && ccRecipients.length === 0) {\r\n throw new BadRequestException(\r\n 'At least one TO or CC recipient is required'\r\n );\r\n }\r\n\r\n // Check for same organization correspondence\r\n for (const recipient of createDto.recipients) {\r\n const recipientOrgId = await this.uuidResolver.resolveOrganizationId(\r\n recipient.organizationId\r\n );\r\n\r\n if (recipientOrgId === originatorOrgId) {\r\n throw new BadRequestException(\r\n 'Cannot send correspondence to your own organization. Use Circulation Sheet for internal communication.'\r\n );\r\n }\r\n }\r\n }\r\n\r\n async create(createDto: CreateCorrespondenceDto, user: User) {\r\n // Business Rule Validation: EC-CORR-003 - Correspondence to Self\r\n await this.validateCorrespondenceRecipients(createDto, user);\r\n // ADR-019: Resolve UUID references to internal INT IDs\r\n const resolvedProjectId = await this.uuidResolver.resolveProjectId(\r\n createDto.projectId\r\n );\r\n const resolvedOriginatorId = createDto.originatorId\r\n ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId)\r\n : undefined;\r\n const resolvedRecipients = createDto.recipients\r\n ? await Promise.all(\r\n createDto.recipients.map(\r\n async (r): Promise => ({\r\n organizationId: await this.uuidResolver.resolveOrganizationId(\r\n r.organizationId\r\n ),\r\n type: r.type,\r\n })\r\n )\r\n )\r\n : undefined;\r\n const type = await this.typeRepo.findOne({\r\n where: { id: createDto.typeId },\r\n });\r\n if (!type) throw new NotFoundException('Document Type not found');\r\n\r\n const statusDraft = await this.statusRepo.findOne({\r\n where: { statusCode: 'DRAFT' },\r\n });\r\n if (!statusDraft) {\r\n throw new InternalServerErrorException(\r\n 'Status DRAFT not found in Master Data'\r\n );\r\n }\r\n\r\n let userOrgId = user.primaryOrganizationId;\r\n\r\n if (!userOrgId) {\r\n const fullUser = await this.userService.findOne(user.user_id);\r\n if (fullUser) {\r\n userOrgId = fullUser.primaryOrganizationId;\r\n }\r\n }\r\n\r\n // Impersonation Logic\r\n if (resolvedOriginatorId && resolvedOriginatorId !== userOrgId) {\r\n const canManageAll = await this.hasSystemManageAllPermission(\r\n user.user_id\r\n );\r\n if (!canManageAll) {\r\n throw new ForbiddenException(\r\n 'You do not have permission to create documents on behalf of other organizations.'\r\n );\r\n }\r\n userOrgId = resolvedOriginatorId;\r\n }\r\n\r\n if (!userOrgId) {\r\n throw new BadRequestException(\r\n 'User must belong to an organization to create documents'\r\n );\r\n }\r\n\r\n if (createDto.details) {\r\n try {\r\n await this.jsonSchemaService.validate(type.typeCode, createDto.details);\r\n } catch (error: unknown) {\r\n this.logger.warn(\r\n `Schema validation warning for ${type.typeCode}: ${(error as Error).message}`\r\n );\r\n }\r\n }\r\n\r\n const queryRunner = this.dataSource.createQueryRunner();\r\n await queryRunner.connect();\r\n await queryRunner.startTransaction();\r\n\r\n try {\r\n // [Fix #6] Fetch real ORG Code from Organization entity\r\n const originatorOrg = await this.dataSource.manager.findOne(\r\n Organization,\r\n {\r\n where: { id: userOrgId },\r\n }\r\n );\r\n const orgCode = originatorOrg?.organizationCode ?? 'UNK';\r\n\r\n // [v1.5.1] Extract recipient organization from recipients array (Primary TO)\r\n const toRecipient = resolvedRecipients?.find((r) => r.type === 'TO');\r\n const recipientOrganizationId = toRecipient?.organizationId;\r\n\r\n let recipientCode = '';\r\n if (recipientOrganizationId) {\r\n const recOrg = await this.dataSource.manager.findOne(Organization, {\r\n where: { id: recipientOrganizationId },\r\n });\r\n if (recOrg) recipientCode = recOrg.organizationCode;\r\n }\r\n\r\n const docNumber = await this.numberingService.generateNextNumber({\r\n projectId: resolvedProjectId,\r\n originatorOrganizationId: userOrgId,\r\n typeId: createDto.typeId,\r\n disciplineId: createDto.disciplineId,\r\n subTypeId: createDto.subTypeId,\r\n recipientOrganizationId, // [v1.5.1] Pass recipient for document number format\r\n year: new Date().getFullYear(),\r\n customTokens: {\r\n TYPE_CODE: type.typeCode,\r\n ORG_CODE: orgCode,\r\n RECIPIENT_CODE: recipientCode,\r\n REC_CODE: recipientCode,\r\n },\r\n });\r\n\r\n const correspondence = queryRunner.manager.create(Correspondence, {\r\n correspondenceNumber: docNumber.number,\r\n correspondenceTypeId: createDto.typeId,\r\n disciplineId: createDto.disciplineId,\r\n projectId: resolvedProjectId,\r\n originatorId: userOrgId,\r\n isInternal: createDto.isInternal || false,\r\n createdBy: user.user_id,\r\n });\r\n const savedCorr = await queryRunner.manager.save(correspondence);\r\n\r\n const revision = queryRunner.manager.create(CorrespondenceRevision, {\r\n correspondenceId: savedCorr.id,\r\n revisionNumber: 0,\r\n revisionLabel: 'A',\r\n isCurrent: true,\r\n statusId: statusDraft.id,\r\n subject: createDto.subject,\r\n body: createDto.body,\r\n remarks: createDto.remarks,\r\n dueDate: createDto.dueDate ? new Date(createDto.dueDate) : undefined,\r\n documentDate: createDto.documentDate\r\n ? new Date(createDto.documentDate)\r\n : undefined,\r\n issuedDate: createDto.issuedDate\r\n ? new Date(createDto.issuedDate)\r\n : undefined,\r\n receivedDate: createDto.receivedDate\r\n ? new Date(createDto.receivedDate)\r\n : undefined,\r\n description: createDto.description,\r\n details: createDto.details,\r\n createdBy: user.user_id,\r\n schemaVersion: 1,\r\n });\r\n await queryRunner.manager.save(revision);\r\n\r\n // Save Recipients (using resolved INT IDs)\r\n if (resolvedRecipients && resolvedRecipients.length > 0) {\r\n const recipients = resolvedRecipients.map((r) =>\r\n queryRunner.manager.create(CorrespondenceRecipient, {\r\n correspondenceId: savedCorr.id,\r\n recipientOrganizationId: r.organizationId,\r\n recipientType: r.type,\r\n })\r\n );\r\n await queryRunner.manager.save(recipients);\r\n }\r\n\r\n // Commit attachments from Temp → Permanent (Two-Phase Storage)\r\n if (createDto.attachmentTempIds?.length) {\r\n const issueDate = createDto.issuedDate\r\n ? new Date(createDto.issuedDate)\r\n : createDto.documentDate\r\n ? new Date(createDto.documentDate)\r\n : undefined;\r\n\r\n await this.fileStorageService.commit(createDto.attachmentTempIds, {\r\n issueDate,\r\n documentType: 'Correspondence',\r\n });\r\n }\r\n\r\n await queryRunner.commitTransaction();\r\n\r\n // Start Workflow Instance (non-blocking)\r\n try {\r\n const workflowCode = `CORRESPONDENCE_${type.typeCode}`;\r\n await this.workflowEngine.createInstance(\r\n workflowCode,\r\n 'correspondence',\r\n savedCorr.id.toString(),\r\n {\r\n projectId: resolvedProjectId,\r\n originatorId: userOrgId,\r\n disciplineId: createDto.disciplineId,\r\n initiatorId: user.user_id,\r\n } as Record\r\n );\r\n } catch (error: unknown) {\r\n this.logger.warn(\r\n `Workflow not started for ${docNumber.number} (Code: CORRESPONDENCE_${type.typeCode}): ${(error as Error).message}`\r\n );\r\n }\r\n\r\n // Fire-and-forget search indexing (non-blocking, void intentional)\r\n void this.searchService.indexDocument({\r\n id: savedCorr.id,\r\n publicId: savedCorr.publicId,\r\n type: 'correspondence',\r\n docNumber: docNumber.number,\r\n title: createDto.subject,\r\n description: createDto.description,\r\n status: 'DRAFT',\r\n projectId: resolvedProjectId,\r\n createdAt: new Date(),\r\n });\r\n\r\n return {\r\n ...savedCorr,\r\n currentRevision: revision,\r\n };\r\n } catch (err) {\r\n await queryRunner.rollbackTransaction();\r\n this.logger.error(\r\n `Failed to create correspondence: ${(err as Error).message}`\r\n );\r\n throw err;\r\n } finally {\r\n await queryRunner.release();\r\n }\r\n }\r\n\r\n async findAll(searchDto: SearchCorrespondenceDto = {}) {\r\n const {\r\n search,\r\n typeId,\r\n projectId,\r\n statusId,\r\n status,\r\n page = 1,\r\n limit = 10,\r\n } = searchDto;\r\n const skip = (page - 1) * limit;\r\n\r\n // Change: Query from Revision Repo\r\n const query = this.revisionRepo\r\n .createQueryBuilder('rev')\r\n .leftJoinAndSelect('rev.correspondence', 'corr')\r\n .leftJoinAndSelect('corr.type', 'type')\r\n .leftJoinAndSelect('corr.project', 'project')\r\n .leftJoinAndSelect('corr.originator', 'org')\r\n .leftJoinAndSelect('rev.status', 'status');\r\n\r\n // Filter by Revision Status\r\n const revStatus = searchDto.revisionStatus || 'CURRENT';\r\n\r\n if (revStatus === 'CURRENT') {\r\n query.where('rev.isCurrent = :isCurrent', { isCurrent: true });\r\n } else if (revStatus === 'OLD') {\r\n query.where('rev.isCurrent = :isCurrent', { isCurrent: false });\r\n }\r\n // If 'ALL', no filter needed on isCurrent\r\n\r\n if (projectId) {\r\n query.andWhere('corr.projectId = :projectId', { projectId });\r\n }\r\n\r\n if (typeId) {\r\n query.andWhere('corr.correspondenceTypeId = :typeId', { typeId });\r\n }\r\n\r\n if (statusId) {\r\n query.andWhere('rev.statusId = :statusId', { statusId });\r\n }\r\n\r\n if (status) {\r\n query.andWhere('status.statusCode = :status', { status });\r\n }\r\n\r\n if (search) {\r\n query.andWhere(\r\n '(corr.correspondenceNumber LIKE :search OR rev.subject LIKE :search)',\r\n { search: `%${search}%` }\r\n );\r\n }\r\n\r\n // Default Sort: Latest Created\r\n query.orderBy('rev.createdAt', 'DESC').skip(skip).take(limit);\r\n\r\n const [items, total] = await query.getManyAndCount();\r\n\r\n return {\r\n data: items,\r\n meta: {\r\n total,\r\n page,\r\n limit,\r\n totalPages: Math.ceil(total / limit),\r\n },\r\n };\r\n }\r\n\r\n async findOne(id: number) {\r\n const correspondence = await this.correspondenceRepo.findOne({\r\n where: { id },\r\n relations: [\r\n 'revisions',\r\n 'revisions.status',\r\n 'type',\r\n 'project',\r\n 'originator',\r\n 'recipients',\r\n 'recipients.recipientOrganization', // [v1.5.1] Fixed relation name\r\n ],\r\n });\r\n\r\n if (!correspondence) {\r\n throw new NotFoundException(`Correspondence with ID ${id} not found`);\r\n }\r\n return correspondence;\r\n }\r\n\r\n async findOneByUuid(publicId: string) {\r\n const correspondence = await this.correspondenceRepo.findOne({\r\n where: { publicId },\r\n relations: [\r\n 'revisions',\r\n 'revisions.status',\r\n 'type',\r\n 'project',\r\n 'originator',\r\n 'recipients',\r\n 'recipients.recipientOrganization',\r\n ],\r\n });\r\n\r\n if (!correspondence) {\r\n throw new NotFoundException(\r\n `Correspondence with UUID ${publicId} not found`\r\n );\r\n }\r\n return correspondence;\r\n }\r\n\r\n async addReference(id: number, dto: AddReferenceDto) {\r\n const source = await this.correspondenceRepo.findOne({ where: { id } });\r\n // ADR-019: Resolve target publicId → internal INT id\r\n const target = await this.correspondenceRepo.findOne({\r\n where: { publicId: dto.targetUuid },\r\n });\r\n\r\n if (!source || !target) {\r\n throw new NotFoundException('Source or Target correspondence not found');\r\n }\r\n\r\n if (source.id === target.id) {\r\n throw new BadRequestException('Cannot reference self');\r\n }\r\n\r\n const exists = await this.referenceRepo.findOne({\r\n where: {\r\n sourceId: id,\r\n targetId: target.id,\r\n },\r\n });\r\n\r\n if (exists) {\r\n return exists;\r\n }\r\n\r\n const ref = this.referenceRepo.create({\r\n sourceId: id,\r\n targetId: target.id,\r\n });\r\n\r\n return this.referenceRepo.save(ref);\r\n }\r\n\r\n async removeReference(id: number, targetId: number) {\r\n const result = await this.referenceRepo.delete({\r\n sourceId: id,\r\n targetId: targetId,\r\n });\r\n\r\n if (result.affected === 0) {\r\n throw new NotFoundException('Reference not found');\r\n }\r\n }\r\n\r\n async getTags(id: number) {\r\n const rows = await this.tagRepo.find({\r\n where: { correspondenceId: id },\r\n relations: ['tag'],\r\n });\r\n return rows.map((r) => r.tag).filter(Boolean);\r\n }\r\n\r\n async addTag(id: number, tagId: number) {\r\n const correspondence = await this.correspondenceRepo.findOne({\r\n where: { id },\r\n });\r\n if (!correspondence) {\r\n throw new NotFoundException(`Correspondence ${id} not found`);\r\n }\r\n\r\n const tag = await this.dataSource.manager.findOne(Tag, {\r\n where: { id: tagId },\r\n });\r\n if (!tag) {\r\n throw new NotFoundException(`Tag ${tagId} not found`);\r\n }\r\n\r\n const exists = await this.tagRepo.findOne({\r\n where: { correspondenceId: id, tagId },\r\n });\r\n if (exists) return exists;\r\n\r\n const row = this.tagRepo.create({ correspondenceId: id, tagId });\r\n return this.tagRepo.save(row);\r\n }\r\n\r\n async removeTag(id: number, tagId: number) {\r\n const result = await this.tagRepo.delete({ correspondenceId: id, tagId });\r\n if (result.affected === 0) {\r\n throw new NotFoundException('Tag assignment not found');\r\n }\r\n }\r\n\r\n async getReferences(id: number) {\r\n const outgoing = await this.referenceRepo.find({\r\n where: { sourceId: id },\r\n relations: ['target', 'target.type'],\r\n });\r\n\r\n const incoming = await this.referenceRepo.find({\r\n where: { targetId: id },\r\n relations: ['source', 'source.type'],\r\n });\r\n\r\n return { outgoing, incoming };\r\n }\r\n\r\n async update(id: number, updateDto: UpdateCorrespondenceDto, user: User) {\r\n // 1. Find Current Revision\r\n const revision = await this.revisionRepo.findOne({\r\n where: {\r\n correspondenceId: id,\r\n isCurrent: true,\r\n },\r\n relations: ['correspondence'],\r\n });\r\n\r\n if (!revision) {\r\n throw new NotFoundException(\r\n `Current revision for correspondence ${id} not found`\r\n );\r\n }\r\n\r\n // 2. Check Permission\r\n if (revision.statusId) {\r\n const status = await this.statusRepo.findOne({\r\n where: { id: revision.statusId },\r\n });\r\n if (status && status.statusCode !== 'DRAFT') {\r\n throw new BadRequestException('Only DRAFT documents can be updated');\r\n }\r\n }\r\n\r\n // ADR-019: Resolve UUID references in update DTO\r\n const updResolvedProjectId = updateDto.projectId\r\n ? await this.uuidResolver.resolveProjectId(updateDto.projectId)\r\n : undefined;\r\n const updResolvedOriginatorId = updateDto.originatorId\r\n ? await this.uuidResolver.resolveOrganizationId(updateDto.originatorId)\r\n : undefined;\r\n const updResolvedRecipients = updateDto.recipients\r\n ? await Promise.all(\r\n updateDto.recipients.map(\r\n async (r): Promise => ({\r\n organizationId: await this.uuidResolver.resolveOrganizationId(\r\n r.organizationId\r\n ),\r\n type: r.type,\r\n })\r\n )\r\n )\r\n : undefined;\r\n\r\n // 3. Update Correspondence Entity if needed\r\n const correspondenceUpdate: Record = {};\r\n if (updateDto.disciplineId)\r\n correspondenceUpdate.disciplineId = updateDto.disciplineId;\r\n if (updResolvedProjectId)\r\n correspondenceUpdate.projectId = updResolvedProjectId;\r\n if (updResolvedOriginatorId)\r\n correspondenceUpdate.originatorId = updResolvedOriginatorId;\r\n\r\n if (Object.keys(correspondenceUpdate).length > 0) {\r\n await this.correspondenceRepo.update(id, correspondenceUpdate);\r\n }\r\n\r\n // 4. Update Revision Entity\r\n const revisionUpdate: Record = {};\r\n if (updateDto.subject) revisionUpdate.subject = updateDto.subject;\r\n if (updateDto.body) revisionUpdate.body = updateDto.body;\r\n if (updateDto.remarks) revisionUpdate.remarks = updateDto.remarks;\r\n // Format Date correctly if string\r\n if (updateDto.dueDate) revisionUpdate.dueDate = new Date(updateDto.dueDate);\r\n if (updateDto.documentDate)\r\n revisionUpdate.documentDate = new Date(updateDto.documentDate);\r\n if (updateDto.issuedDate)\r\n revisionUpdate.issuedDate = new Date(updateDto.issuedDate);\r\n if (updateDto.receivedDate)\r\n revisionUpdate.receivedDate = new Date(updateDto.receivedDate);\r\n if (updateDto.description)\r\n revisionUpdate.description = updateDto.description;\r\n if (updateDto.details) revisionUpdate.details = updateDto.details;\r\n\r\n if (Object.keys(revisionUpdate).length > 0) {\r\n await this.revisionRepo.update(revision.id, revisionUpdate);\r\n }\r\n\r\n // 4.5 Commit new attachments from Temp → Permanent (Two-Phase Storage)\r\n if (updateDto.attachmentTempIds?.length) {\r\n const issueDate = updateDto.issuedDate\r\n ? new Date(updateDto.issuedDate)\r\n : updateDto.documentDate\r\n ? new Date(updateDto.documentDate)\r\n : revision.issuedDate || revision.documentDate || undefined;\r\n\r\n await this.fileStorageService.commit(updateDto.attachmentTempIds, {\r\n issueDate: issueDate ? new Date(issueDate) : undefined,\r\n documentType: 'Correspondence',\r\n });\r\n }\r\n\r\n // 5. Update Recipients if provided\r\n if (updResolvedRecipients) {\r\n const recipientRepo = this.dataSource.getRepository(\r\n CorrespondenceRecipient\r\n );\r\n await recipientRepo.delete({ correspondenceId: id });\r\n\r\n const newRecipients = updResolvedRecipients.map((r) =>\r\n recipientRepo.create({\r\n correspondenceId: id,\r\n recipientOrganizationId: r.organizationId,\r\n recipientType: r.type,\r\n })\r\n );\r\n await recipientRepo.save(newRecipients);\r\n }\r\n\r\n // 6. Regenerate Document Number if structural fields changed (Recipient, Discipline, Type, Project)\r\n // AND it is a DRAFT.\r\n\r\n // Fetch fresh data for context and comparison\r\n const currentCorr = await this.correspondenceRepo.findOne({\r\n where: { id },\r\n relations: ['type', 'recipients', 'recipients.recipientOrganization'],\r\n });\r\n\r\n if (currentCorr) {\r\n const currentToRecipient = currentCorr.recipients?.find(\r\n (r) => r.recipientType === 'TO'\r\n );\r\n const currentRecipientId = currentToRecipient?.recipientOrganizationId;\r\n\r\n // Check for ACTUAL value changes\r\n const isProjectChanged =\r\n updResolvedProjectId !== undefined &&\r\n updResolvedProjectId !== currentCorr.projectId;\r\n const isOriginatorChanged =\r\n updResolvedOriginatorId !== undefined &&\r\n updResolvedOriginatorId !== currentCorr.originatorId;\r\n const isDisciplineChanged =\r\n updateDto.disciplineId !== undefined &&\r\n updateDto.disciplineId !== currentCorr.disciplineId;\r\n const isTypeChanged =\r\n updateDto.typeId !== undefined &&\r\n updateDto.typeId !== currentCorr.correspondenceTypeId;\r\n\r\n let isRecipientChanged = false;\r\n let newRecipientId: number | undefined;\r\n\r\n if (updResolvedRecipients) {\r\n const newToRecipient = updResolvedRecipients.find(\r\n (r) => r.type === 'TO'\r\n );\r\n newRecipientId = newToRecipient?.organizationId;\r\n\r\n if (newRecipientId !== currentRecipientId) {\r\n isRecipientChanged = true;\r\n }\r\n }\r\n\r\n if (\r\n isProjectChanged ||\r\n isDisciplineChanged ||\r\n isTypeChanged ||\r\n isRecipientChanged ||\r\n isOriginatorChanged\r\n ) {\r\n const targetRecipientId = isRecipientChanged\r\n ? newRecipientId\r\n : currentRecipientId;\r\n\r\n // Resolve Recipient Code for the NEW context\r\n let recipientCode = '';\r\n if (targetRecipientId) {\r\n const recOrg = await this.dataSource.manager.findOne(Organization, {\r\n where: { id: targetRecipientId },\r\n });\r\n if (recOrg) recipientCode = recOrg.organizationCode;\r\n }\r\n\r\n // [Fix #6] Fetch real ORG Code from originator organization\r\n const originatorOrgForUpdate = await this.dataSource.manager.findOne(\r\n Organization,\r\n {\r\n where: {\r\n id: updResolvedOriginatorId ?? currentCorr.originatorId ?? 0,\r\n },\r\n }\r\n );\r\n const orgCode = originatorOrgForUpdate?.organizationCode ?? 'UNK';\r\n\r\n // Prepare Contexts\r\n const oldCtx = {\r\n projectId: currentCorr.projectId,\r\n originatorOrganizationId: currentCorr.originatorId ?? 0,\r\n typeId: currentCorr.correspondenceTypeId,\r\n disciplineId: currentCorr.disciplineId,\r\n recipientOrganizationId: currentRecipientId,\r\n year: new Date().getFullYear(),\r\n };\r\n\r\n const newCtx = {\r\n projectId: updResolvedProjectId ?? currentCorr.projectId,\r\n originatorOrganizationId:\r\n updResolvedOriginatorId ?? currentCorr.originatorId ?? 0,\r\n typeId: updateDto.typeId ?? currentCorr.correspondenceTypeId,\r\n disciplineId: updateDto.disciplineId ?? currentCorr.disciplineId,\r\n recipientOrganizationId: targetRecipientId,\r\n year: new Date().getFullYear(),\r\n userId: user.user_id, // Pass User ID for Audit\r\n customTokens: {\r\n TYPE_CODE: currentCorr.type?.typeCode || '',\r\n ORG_CODE: orgCode,\r\n RECIPIENT_CODE: recipientCode,\r\n REC_CODE: recipientCode,\r\n },\r\n };\r\n\r\n // If Type Changed, need NEW Type Code\r\n if (isTypeChanged) {\r\n const newType = await this.typeRepo.findOne({\r\n where: { id: newCtx.typeId },\r\n });\r\n if (newType) newCtx.customTokens.TYPE_CODE = newType.typeCode;\r\n }\r\n\r\n const newDocNumber = await this.numberingService.updateNumberForDraft(\r\n currentCorr.correspondenceNumber,\r\n oldCtx,\r\n newCtx\r\n );\r\n\r\n await this.correspondenceRepo.update(id, {\r\n correspondenceNumber: newDocNumber,\r\n });\r\n }\r\n }\r\n\r\n const updated = await this.findOne(id);\r\n\r\n // Re-index updated document in Elasticsearch (fire-and-forget)\r\n void this.searchService.indexDocument({\r\n id: updated.id,\r\n publicId: updated.publicId,\r\n type: 'correspondence',\r\n docNumber: updated.correspondenceNumber,\r\n title: updateDto.subject ?? updated.revisions?.[0]?.subject,\r\n description: updateDto.description ?? updated.revisions?.[0]?.description,\r\n status: 'DRAFT',\r\n projectId: updated.projectId,\r\n createdAt: updated.createdAt,\r\n });\r\n\r\n return updated;\r\n }\r\n\r\n async previewDocumentNumber(createDto: CreateCorrespondenceDto, user: User) {\r\n // ADR-019: Resolve UUID references\r\n const previewProjectId = await this.uuidResolver.resolveProjectId(\r\n createDto.projectId\r\n );\r\n const previewOriginatorId = createDto.originatorId\r\n ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId)\r\n : undefined;\r\n const previewRecipients = createDto.recipients\r\n ? await Promise.all(\r\n createDto.recipients.map(\r\n async (r): Promise => ({\r\n organizationId: await this.uuidResolver.resolveOrganizationId(\r\n r.organizationId\r\n ),\r\n type: r.type,\r\n })\r\n )\r\n )\r\n : undefined;\r\n\r\n const type = await this.typeRepo.findOne({\r\n where: { id: createDto.typeId },\r\n });\r\n if (!type) throw new NotFoundException('Document Type not found');\r\n\r\n let userOrgId = user.primaryOrganizationId;\r\n if (!userOrgId) {\r\n const fullUser = await this.userService.findOne(user.user_id);\r\n if (fullUser) userOrgId = fullUser.primaryOrganizationId;\r\n }\r\n\r\n if (previewOriginatorId && previewOriginatorId !== userOrgId) {\r\n // Allow impersonation for preview\r\n userOrgId = previewOriginatorId;\r\n }\r\n\r\n // Extract recipient from recipients array\r\n const toRecipient = previewRecipients?.find((r) => r.type === 'TO');\r\n const recipientOrganizationId = toRecipient?.organizationId;\r\n\r\n let recipientCode = '';\r\n if (recipientOrganizationId) {\r\n const recOrg = await this.dataSource.manager.findOne(Organization, {\r\n where: { id: recipientOrganizationId },\r\n });\r\n if (recOrg) recipientCode = recOrg.organizationCode;\r\n }\r\n\r\n return this.numberingService.previewNumber({\r\n projectId: previewProjectId,\r\n originatorOrganizationId: userOrgId!,\r\n typeId: createDto.typeId,\r\n disciplineId: createDto.disciplineId,\r\n subTypeId: createDto.subTypeId,\r\n recipientOrganizationId,\r\n year: new Date().getFullYear(),\r\n customTokens: {\r\n TYPE_CODE: type.typeCode,\r\n RECIPIENT_CODE: recipientCode,\r\n REC_CODE: recipientCode,\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Business Rule Implementation: EC-CORR-001 - Cancel Correspondence with Downstream Circulation\r\n * Cancel correspondence and handle related circulations\r\n */\r\n async cancel(publicId: string, reason: string, user: User) {\r\n const correspondence = await this.findOneByUuid(publicId);\r\n\r\n // Check if user has permission to cancel (Org Admin or Superadmin only)\r\n const permissions = await this.userService.getUserPermissions(user.user_id);\r\n const canCancel =\r\n permissions.includes('correspondence.cancel') ||\r\n permissions.includes('system.manage_all');\r\n\r\n if (!canCancel) {\r\n throw new ForbiddenException(\r\n 'Only administrators can cancel correspondences'\r\n );\r\n }\r\n\r\n // Check if there are any active circulations\r\n const circulationRepo = this.dataSource.getRepository('Circulation');\r\n const activeCirculations = await circulationRepo.find({\r\n where: {\r\n correspondenceId: correspondence.id,\r\n status: 'OPEN',\r\n },\r\n });\r\n\r\n const warningMessage =\r\n activeCirculations.length > 0\r\n ? `There are ${activeCirculations.length} active circulation(s) for this correspondence. Canceling will force close all related circulations.`\r\n : '';\r\n\r\n // Get the current revision to update status\r\n const currentRevision = await this.revisionRepo.findOne({\r\n where: {\r\n correspondenceId: correspondence.id,\r\n isCurrent: true,\r\n },\r\n });\r\n\r\n if (!currentRevision) {\r\n throw new NotFoundException('Current revision not found');\r\n }\r\n\r\n // Get cancelled status\r\n const cancelledStatus = await this.statusRepo.findOne({\r\n where: { statusCode: 'CANCELLED' },\r\n });\r\n\r\n if (!cancelledStatus) {\r\n throw new InternalServerErrorException('CANCELLED status not found');\r\n }\r\n\r\n const queryRunner = this.dataSource.createQueryRunner();\r\n await queryRunner.connect();\r\n await queryRunner.startTransaction();\r\n\r\n try {\r\n // Update correspondence revision status to CANCELLED\r\n await queryRunner.manager.update(\r\n CorrespondenceRevision,\r\n currentRevision.id,\r\n {\r\n statusId: cancelledStatus.id,\r\n remarks: `Cancelled: ${reason}`,\r\n }\r\n );\r\n\r\n // Force close all active circulations\r\n if (activeCirculations.length > 0) {\r\n await queryRunner.manager.update(\r\n 'Circulation',\r\n {\r\n correspondenceId: correspondence.id,\r\n status: 'OPEN',\r\n },\r\n {\r\n status: 'FORCE_CLOSED',\r\n closedAt: new Date(),\r\n closedBy: user.user_id,\r\n closeReason: `Correspondence cancelled: ${reason}`,\r\n }\r\n );\r\n }\r\n\r\n await queryRunner.commitTransaction();\r\n\r\n // Re-index cancelled status in Elasticsearch (fire-and-forget)\r\n void this.searchService.indexDocument({\r\n id: correspondence.id,\r\n publicId: correspondence.publicId,\r\n type: 'correspondence',\r\n docNumber: correspondence.correspondenceNumber,\r\n title: currentRevision.subject,\r\n status: 'CANCELLED',\r\n projectId: correspondence.projectId,\r\n createdAt: correspondence.createdAt,\r\n });\r\n\r\n // Notify originator's doc-control user about cancellation (fire-and-forget)\r\n if (correspondence.originatorId) {\r\n void this.userService\r\n .findDocControlIdByOrg(correspondence.originatorId)\r\n .then((targetUserId) => {\r\n if (targetUserId) {\r\n void this.notificationService.send({\r\n userId: targetUserId,\r\n title: 'Correspondence Cancelled',\r\n message: `${correspondence.correspondenceNumber} — ${currentRevision.subject} has been cancelled. Reason: ${reason}`,\r\n type: 'EMAIL',\r\n entityType: 'correspondence',\r\n entityId: correspondence.id,\r\n link: `/correspondences/${correspondence.publicId}`,\r\n });\r\n }\r\n })\r\n .catch((err: Error) =>\r\n this.logger.warn(`Cancel notification failed: ${err.message}`)\r\n );\r\n }\r\n\r\n return {\r\n success: true,\r\n message: warningMessage || 'Correspondence cancelled successfully',\r\n activeCirculationsCount: activeCirculations.length,\r\n };\r\n } catch (error) {\r\n await queryRunner.rollbackTransaction();\r\n this.logger.error(\r\n `Failed to cancel correspondence: ${(error as Error).message}`\r\n );\r\n throw error;\r\n } finally {\r\n await queryRunner.release();\r\n }\r\n }\r\n\r\n async bulkCancel(\r\n publicIds: string[],\r\n reason: string,\r\n user: User\r\n ): Promise<{ succeeded: string[]; failed: string[] }> {\r\n const succeeded: string[] = [];\r\n const failed: string[] = [];\r\n\r\n for (const publicId of publicIds) {\r\n try {\r\n await this.cancel(publicId, reason, user);\r\n succeeded.push(publicId);\r\n } catch {\r\n failed.push(publicId);\r\n }\r\n }\r\n\r\n return { succeeded, failed };\r\n }\r\n\r\n async exportCsv(searchDto: SearchCorrespondenceDto): Promise {\r\n const { data } = await this.findAll(searchDto);\r\n\r\n const header = [\r\n 'Document No.',\r\n 'Rev',\r\n 'Subject',\r\n 'Type',\r\n 'Status',\r\n 'Project',\r\n 'From',\r\n 'Due Date',\r\n 'Created At',\r\n ];\r\n const rows = data.map((rev) => {\r\n const corr = rev.correspondence ?? (rev as unknown as Correspondence);\r\n return [\r\n this.escapeCsv(corr.correspondenceNumber ?? ''),\r\n this.escapeCsv(rev.revisionLabel ?? String(rev.revisionNumber ?? 0)),\r\n this.escapeCsv(rev.subject ?? ''),\r\n this.escapeCsv(corr.type?.typeCode ?? ''),\r\n this.escapeCsv(rev.status?.statusCode ?? ''),\r\n this.escapeCsv(corr.project?.projectCode ?? ''),\r\n this.escapeCsv(corr.originator?.organizationCode ?? ''),\r\n rev.dueDate ? new Date(rev.dueDate).toISOString().split('T')[0] : '',\r\n new Date(rev.createdAt).toISOString().split('T')[0],\r\n ].join(',');\r\n });\r\n\r\n return [header.join(','), ...rows].join('\\n');\r\n }\r\n\r\n private escapeCsv(value: string): string {\r\n if (value.includes(',') || value.includes('\"') || value.includes('\\n')) {\r\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\r\n }\r\n return value;\r\n }\r\n}\r\n"],"version":3} \ No newline at end of file diff --git a/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/55/correspondenceservice_5585ce2f5626b5a93fd64e63909b087f b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/55/correspondenceservice_5585ce2f5626b5a93fd64e63909b087f new file mode 100644 index 0000000..333767e --- /dev/null +++ b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/55/correspondenceservice_5585ce2f5626b5a93fd64e63909b087f @@ -0,0 +1,893 @@ +f958e3e0fd6fd813cf9552bbff491967 +"use strict"; +// File: src/modules/correspondence/correspondence.service.ts +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +var __param = (this && this.__param) || function (paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +}; +var CorrespondenceService_1; +var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CorrespondenceService = void 0; +const common_1 = require("@nestjs/common"); +const typeorm_1 = require("@nestjs/typeorm"); +const typeorm_2 = require("typeorm"); +// Entities +const correspondence_entity_1 = require("./entities/correspondence.entity"); +const correspondence_revision_entity_1 = require("./entities/correspondence-revision.entity"); +const correspondence_type_entity_1 = require("./entities/correspondence-type.entity"); +const correspondence_status_entity_1 = require("./entities/correspondence-status.entity"); +const correspondence_reference_entity_1 = require("./entities/correspondence-reference.entity"); +const correspondence_recipient_entity_1 = require("./entities/correspondence-recipient.entity"); +const correspondence_tag_entity_1 = require("./entities/correspondence-tag.entity"); +const tag_entity_1 = require("../master/entities/tag.entity"); +const organization_entity_1 = require("../organization/entities/organization.entity"); +// Services +const document_numbering_service_1 = require("../document-numbering/services/document-numbering.service"); +const json_schema_service_1 = require("../json-schema/json-schema.service"); +const workflow_engine_service_1 = require("../workflow-engine/workflow-engine.service"); +const user_service_1 = require("../user/user.service"); +const search_service_1 = require("../search/search.service"); +const file_storage_service_1 = require("../../common/file-storage/file-storage.service"); +const uuid_resolver_service_1 = require("../../common/services/uuid-resolver.service"); +const notification_service_1 = require("../notification/notification.service"); +let CorrespondenceService = CorrespondenceService_1 = class CorrespondenceService { + async hasSystemManageAllPermission(userId) { + const permissions = await this.userService.getUserPermissions(userId); + return permissions.includes('system.manage_all'); + } + /** + * Business Rule: Revision Label Strategy + * - RFA, RFI: Use alphabet starting with 'A' (A, B, C...) + * - Other types (LETTER, MEMO, etc.): Use numeric (null for first, then 1, 2, 3...) + */ + getInitialRevisionLabel(typeCode) { + const alphabetTypes = ['RFA', 'RFI']; + if (alphabetTypes.includes(typeCode.toUpperCase())) { + return 'A'; // Alphabet for RFA, RFI + } + return null; // Numeric (null for revision 0) + } + constructor(correspondenceRepo, revisionRepo, typeRepo, statusRepo, referenceRepo, tagRepo, numberingService, jsonSchemaService, workflowEngine, userService, dataSource, searchService, fileStorageService, uuidResolver, notificationService) { + this.correspondenceRepo = correspondenceRepo; + this.revisionRepo = revisionRepo; + this.typeRepo = typeRepo; + this.statusRepo = statusRepo; + this.referenceRepo = referenceRepo; + this.tagRepo = tagRepo; + this.numberingService = numberingService; + this.jsonSchemaService = jsonSchemaService; + this.workflowEngine = workflowEngine; + this.userService = userService; + this.dataSource = dataSource; + this.searchService = searchService; + this.fileStorageService = fileStorageService; + this.uuidResolver = uuidResolver; + this.notificationService = notificationService; + this.logger = new common_1.Logger(CorrespondenceService_1.name); + } + /** + * Business Rule Validation: EC-CORR-003 - Correspondence to Self + * Prevent external correspondence to same organization + */ + async validateCorrespondenceRecipients(createDto, user) { + // Get user's organization + let userOrgId = user.primaryOrganizationId; + if (!userOrgId) { + const fullUser = await this.userService.findOne(user.user_id); + if (fullUser) { + userOrgId = fullUser.primaryOrganizationId; + } + } + if (!userOrgId) { + if (createDto.originatorId) { + const canManageAll = await this.hasSystemManageAllPermission(user.user_id); + if (canManageAll) { + userOrgId = await this.uuidResolver.resolveOrganizationId(createDto.originatorId); + } + } + if (!userOrgId) { + throw new common_1.BadRequestException('User must belong to an organization to create documents'); + } + } + // For impersonation, use the specified originator + const originatorOrgId = createDto.originatorId + ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId) + : userOrgId; + // Check if it's internal communication + if (createDto.isInternal) { + // Internal communications should use Circulation instead + throw new common_1.BadRequestException('Internal communications should use Circulation Sheet instead of Correspondence'); + } + // Validate recipients + if (!createDto.recipients || createDto.recipients.length === 0) { + throw new common_1.BadRequestException('At least one recipient (TO or CC) is required'); + } + const toRecipients = createDto.recipients.filter((r) => r.type === 'TO'); + const ccRecipients = createDto.recipients.filter((r) => r.type === 'CC'); + if (toRecipients.length === 0 && ccRecipients.length === 0) { + throw new common_1.BadRequestException('At least one TO or CC recipient is required'); + } + // Check for same organization correspondence + for (const recipient of createDto.recipients) { + const recipientOrgId = await this.uuidResolver.resolveOrganizationId(recipient.organizationId); + if (recipientOrgId === originatorOrgId) { + throw new common_1.BadRequestException('Cannot send correspondence to your own organization. Use Circulation Sheet for internal communication.'); + } + } + } + async create(createDto, user) { + // Business Rule Validation: EC-CORR-003 - Correspondence to Self + await this.validateCorrespondenceRecipients(createDto, user); + // ADR-019: Resolve UUID references to internal INT IDs + const resolvedProjectId = await this.uuidResolver.resolveProjectId(createDto.projectId); + const resolvedOriginatorId = createDto.originatorId + ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId) + : undefined; + const resolvedRecipients = createDto.recipients + ? await Promise.all(createDto.recipients.map(async (r) => ({ + organizationId: await this.uuidResolver.resolveOrganizationId(r.organizationId), + type: r.type, + }))) + : undefined; + const type = await this.typeRepo.findOne({ + where: { id: createDto.typeId }, + }); + if (!type) + throw new common_1.NotFoundException('Document Type not found'); + const statusDraft = await this.statusRepo.findOne({ + where: { statusCode: 'DRAFT' }, + }); + if (!statusDraft) { + throw new common_1.InternalServerErrorException('Status DRAFT not found in Master Data'); + } + let userOrgId = user.primaryOrganizationId; + if (!userOrgId) { + const fullUser = await this.userService.findOne(user.user_id); + if (fullUser) { + userOrgId = fullUser.primaryOrganizationId; + } + } + // Impersonation Logic + if (resolvedOriginatorId && resolvedOriginatorId !== userOrgId) { + const canManageAll = await this.hasSystemManageAllPermission(user.user_id); + if (!canManageAll) { + throw new common_1.ForbiddenException('You do not have permission to create documents on behalf of other organizations.'); + } + userOrgId = resolvedOriginatorId; + } + if (!userOrgId) { + throw new common_1.BadRequestException('User must belong to an organization to create documents'); + } + if (createDto.details) { + try { + await this.jsonSchemaService.validate(type.typeCode, createDto.details); + } + catch (error) { + this.logger.warn(`Schema validation warning for ${type.typeCode}: ${error.message}`); + } + } + const queryRunner = this.dataSource.createQueryRunner(); + await queryRunner.connect(); + await queryRunner.startTransaction(); + try { + // [Fix #6] Fetch real ORG Code from Organization entity + const originatorOrg = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { id: userOrgId }, + }); + const orgCode = originatorOrg?.organizationCode ?? 'UNK'; + // [v1.5.1] Extract recipient organization from recipients array (Primary TO) + const toRecipient = resolvedRecipients?.find((r) => r.type === 'TO'); + const recipientOrganizationId = toRecipient?.organizationId; + let recipientCode = ''; + if (recipientOrganizationId) { + const recOrg = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { id: recipientOrganizationId }, + }); + if (recOrg) + recipientCode = recOrg.organizationCode; + } + const docNumber = await this.numberingService.generateNextNumber({ + projectId: resolvedProjectId, + originatorOrganizationId: userOrgId, + typeId: createDto.typeId, + disciplineId: createDto.disciplineId, + subTypeId: createDto.subTypeId, + recipientOrganizationId, // [v1.5.1] Pass recipient for document number format + year: new Date().getFullYear(), + customTokens: { + TYPE_CODE: type.typeCode, + ORG_CODE: orgCode, + RECIPIENT_CODE: recipientCode, + REC_CODE: recipientCode, + }, + }); + const correspondence = queryRunner.manager.create(correspondence_entity_1.Correspondence, { + correspondenceNumber: docNumber.number, + correspondenceTypeId: createDto.typeId, + disciplineId: createDto.disciplineId, + projectId: resolvedProjectId, + originatorId: userOrgId, + isInternal: createDto.isInternal || false, + createdBy: user.user_id, + }); + const savedCorr = await queryRunner.manager.save(correspondence); + const revision = queryRunner.manager.create(correspondence_revision_entity_1.CorrespondenceRevision, { + correspondenceId: savedCorr.id, + revisionNumber: 0, + revisionLabel: this.getInitialRevisionLabel(type.typeCode), + isCurrent: true, + statusId: statusDraft.id, + subject: createDto.subject, + body: createDto.body, + remarks: createDto.remarks, + dueDate: createDto.dueDate ? new Date(createDto.dueDate) : undefined, + documentDate: createDto.documentDate + ? new Date(createDto.documentDate) + : undefined, + issuedDate: createDto.issuedDate + ? new Date(createDto.issuedDate) + : undefined, + receivedDate: createDto.receivedDate + ? new Date(createDto.receivedDate) + : undefined, + description: createDto.description, + details: createDto.details, + createdBy: user.user_id, + schemaVersion: 1, + }); + await queryRunner.manager.save(revision); + // Save Recipients (using resolved INT IDs) + if (resolvedRecipients && resolvedRecipients.length > 0) { + const recipients = resolvedRecipients.map((r) => queryRunner.manager.create(correspondence_recipient_entity_1.CorrespondenceRecipient, { + correspondenceId: savedCorr.id, + recipientOrganizationId: r.organizationId, + recipientType: r.type, + })); + await queryRunner.manager.save(recipients); + } + // Commit attachments from Temp → Permanent (Two-Phase Storage) + if (createDto.attachmentTempIds?.length) { + const issueDate = createDto.issuedDate + ? new Date(createDto.issuedDate) + : createDto.documentDate + ? new Date(createDto.documentDate) + : undefined; + await this.fileStorageService.commit(createDto.attachmentTempIds, { + issueDate, + documentType: 'Correspondence', + }); + } + await queryRunner.commitTransaction(); + // Start Workflow Instance (non-blocking) + try { + const workflowCode = `CORRESPONDENCE_${type.typeCode}`; + await this.workflowEngine.createInstance(workflowCode, 'correspondence', savedCorr.id.toString(), { + projectId: resolvedProjectId, + originatorId: userOrgId, + disciplineId: createDto.disciplineId, + initiatorId: user.user_id, + }); + } + catch (error) { + this.logger.warn(`Workflow not started for ${docNumber.number} (Code: CORRESPONDENCE_${type.typeCode}): ${error.message}`); + } + // Fire-and-forget search indexing (non-blocking, void intentional) + void this.searchService.indexDocument({ + id: savedCorr.id, + publicId: savedCorr.publicId, + type: 'correspondence', + docNumber: docNumber.number, + title: createDto.subject, + description: createDto.description, + status: 'DRAFT', + projectId: resolvedProjectId, + createdAt: new Date(), + }); + return { + ...savedCorr, + currentRevision: revision, + }; + } + catch (err) { + await queryRunner.rollbackTransaction(); + this.logger.error(`Failed to create correspondence: ${err.message}`); + throw err; + } + finally { + await queryRunner.release(); + } + } + async findAll(searchDto = {}) { + const { search, typeId, projectId, statusId, status, page = 1, limit = 10, } = searchDto; + const skip = (page - 1) * limit; + // Change: Query from Revision Repo + const query = this.revisionRepo + .createQueryBuilder('rev') + .leftJoinAndSelect('rev.correspondence', 'corr') + .leftJoinAndSelect('corr.type', 'type') + .leftJoinAndSelect('corr.project', 'project') + .leftJoinAndSelect('corr.originator', 'org') + .leftJoinAndSelect('rev.status', 'status'); + // Filter by Revision Status + const revStatus = searchDto.revisionStatus || 'CURRENT'; + if (revStatus === 'CURRENT') { + query.where('rev.isCurrent = :isCurrent', { isCurrent: true }); + } + else if (revStatus === 'OLD') { + query.where('rev.isCurrent = :isCurrent', { isCurrent: false }); + } + // If 'ALL', no filter needed on isCurrent + if (projectId) { + query.andWhere('corr.projectId = :projectId', { projectId }); + } + if (typeId) { + query.andWhere('corr.correspondenceTypeId = :typeId', { typeId }); + } + if (statusId) { + query.andWhere('rev.statusId = :statusId', { statusId }); + } + if (status) { + query.andWhere('status.statusCode = :status', { status }); + } + if (search) { + query.andWhere('(corr.correspondenceNumber LIKE :search OR rev.subject LIKE :search)', { search: `%${search}%` }); + } + // Default Sort: Latest Created + query.orderBy('rev.createdAt', 'DESC').skip(skip).take(limit); + const [items, total] = await query.getManyAndCount(); + return { + data: items, + meta: { + total, + page, + limit, + totalPages: Math.ceil(total / limit), + }, + }; + } + async findOne(id) { + const correspondence = await this.correspondenceRepo.findOne({ + where: { id }, + relations: [ + 'revisions', + 'revisions.status', + 'type', + 'project', + 'originator', + 'recipients', + 'recipients.recipientOrganization', // [v1.5.1] Fixed relation name + ], + }); + if (!correspondence) { + throw new common_1.NotFoundException(`Correspondence with ID ${id} not found`); + } + return correspondence; + } + async findOneByUuid(publicId) { + const correspondence = await this.correspondenceRepo.findOne({ + where: { publicId }, + relations: [ + 'revisions', + 'revisions.status', + 'type', + 'project', + 'originator', + 'recipients', + 'recipients.recipientOrganization', + ], + }); + if (!correspondence) { + throw new common_1.NotFoundException(`Correspondence with UUID ${publicId} not found`); + } + return correspondence; + } + async addReference(id, dto) { + const source = await this.correspondenceRepo.findOne({ where: { id } }); + // ADR-019: Resolve target publicId → internal INT id + const target = await this.correspondenceRepo.findOne({ + where: { publicId: dto.targetUuid }, + }); + if (!source || !target) { + throw new common_1.NotFoundException('Source or Target correspondence not found'); + } + if (source.id === target.id) { + throw new common_1.BadRequestException('Cannot reference self'); + } + const exists = await this.referenceRepo.findOne({ + where: { + sourceId: id, + targetId: target.id, + }, + }); + if (exists) { + return exists; + } + const ref = this.referenceRepo.create({ + sourceId: id, + targetId: target.id, + }); + return this.referenceRepo.save(ref); + } + async removeReference(id, targetId) { + const result = await this.referenceRepo.delete({ + sourceId: id, + targetId: targetId, + }); + if (result.affected === 0) { + throw new common_1.NotFoundException('Reference not found'); + } + } + async getTags(id) { + const rows = await this.tagRepo.find({ + where: { correspondenceId: id }, + relations: ['tag'], + }); + return rows.map((r) => r.tag).filter(Boolean); + } + async addTag(id, tagId) { + const correspondence = await this.correspondenceRepo.findOne({ + where: { id }, + }); + if (!correspondence) { + throw new common_1.NotFoundException(`Correspondence ${id} not found`); + } + const tag = await this.dataSource.manager.findOne(tag_entity_1.Tag, { + where: { id: tagId }, + }); + if (!tag) { + throw new common_1.NotFoundException(`Tag ${tagId} not found`); + } + const exists = await this.tagRepo.findOne({ + where: { correspondenceId: id, tagId }, + }); + if (exists) + return exists; + const row = this.tagRepo.create({ correspondenceId: id, tagId }); + return this.tagRepo.save(row); + } + async removeTag(id, tagId) { + const result = await this.tagRepo.delete({ correspondenceId: id, tagId }); + if (result.affected === 0) { + throw new common_1.NotFoundException('Tag assignment not found'); + } + } + async getReferences(id) { + const outgoing = await this.referenceRepo.find({ + where: { sourceId: id }, + relations: ['target', 'target.type'], + }); + const incoming = await this.referenceRepo.find({ + where: { targetId: id }, + relations: ['source', 'source.type'], + }); + return { outgoing, incoming }; + } + async update(id, updateDto, user) { + // 1. Find Current Revision + const revision = await this.revisionRepo.findOne({ + where: { + correspondenceId: id, + isCurrent: true, + }, + relations: ['correspondence'], + }); + if (!revision) { + throw new common_1.NotFoundException(`Current revision for correspondence ${id} not found`); + } + // 2. Check Permission + if (revision.statusId) { + const status = await this.statusRepo.findOne({ + where: { id: revision.statusId }, + }); + if (status && status.statusCode !== 'DRAFT') { + throw new common_1.BadRequestException('Only DRAFT documents can be updated'); + } + } + // ADR-019: Resolve UUID references in update DTO + const updResolvedProjectId = updateDto.projectId + ? await this.uuidResolver.resolveProjectId(updateDto.projectId) + : undefined; + const updResolvedOriginatorId = updateDto.originatorId + ? await this.uuidResolver.resolveOrganizationId(updateDto.originatorId) + : undefined; + const updResolvedRecipients = updateDto.recipients + ? await Promise.all(updateDto.recipients.map(async (r) => ({ + organizationId: await this.uuidResolver.resolveOrganizationId(r.organizationId), + type: r.type, + }))) + : undefined; + // 3. Update Correspondence Entity if needed + const correspondenceUpdate = {}; + if (updateDto.disciplineId) + correspondenceUpdate.disciplineId = updateDto.disciplineId; + if (updResolvedProjectId) + correspondenceUpdate.projectId = updResolvedProjectId; + if (updResolvedOriginatorId) + correspondenceUpdate.originatorId = updResolvedOriginatorId; + if (Object.keys(correspondenceUpdate).length > 0) { + await this.correspondenceRepo.update(id, correspondenceUpdate); + } + // 4. Update Revision Entity + const revisionUpdate = {}; + if (updateDto.subject) + revisionUpdate.subject = updateDto.subject; + if (updateDto.body) + revisionUpdate.body = updateDto.body; + if (updateDto.remarks) + revisionUpdate.remarks = updateDto.remarks; + // Format Date correctly if string + if (updateDto.dueDate) + revisionUpdate.dueDate = new Date(updateDto.dueDate); + if (updateDto.documentDate) + revisionUpdate.documentDate = new Date(updateDto.documentDate); + if (updateDto.issuedDate) + revisionUpdate.issuedDate = new Date(updateDto.issuedDate); + if (updateDto.receivedDate) + revisionUpdate.receivedDate = new Date(updateDto.receivedDate); + if (updateDto.description) + revisionUpdate.description = updateDto.description; + if (updateDto.details) + revisionUpdate.details = updateDto.details; + if (Object.keys(revisionUpdate).length > 0) { + await this.revisionRepo.update(revision.id, revisionUpdate); + } + // 4.5 Commit new attachments from Temp → Permanent (Two-Phase Storage) + if (updateDto.attachmentTempIds?.length) { + const issueDate = updateDto.issuedDate + ? new Date(updateDto.issuedDate) + : updateDto.documentDate + ? new Date(updateDto.documentDate) + : revision.issuedDate || revision.documentDate || undefined; + await this.fileStorageService.commit(updateDto.attachmentTempIds, { + issueDate: issueDate ? new Date(issueDate) : undefined, + documentType: 'Correspondence', + }); + } + // 5. Update Recipients if provided + if (updResolvedRecipients) { + const recipientRepo = this.dataSource.getRepository(correspondence_recipient_entity_1.CorrespondenceRecipient); + await recipientRepo.delete({ correspondenceId: id }); + const newRecipients = updResolvedRecipients.map((r) => recipientRepo.create({ + correspondenceId: id, + recipientOrganizationId: r.organizationId, + recipientType: r.type, + })); + await recipientRepo.save(newRecipients); + } + // 6. Regenerate Document Number if structural fields changed (Recipient, Discipline, Type, Project) + // AND it is a DRAFT. + // Fetch fresh data for context and comparison + const currentCorr = await this.correspondenceRepo.findOne({ + where: { id }, + relations: ['type', 'recipients', 'recipients.recipientOrganization'], + }); + if (currentCorr) { + const currentToRecipient = currentCorr.recipients?.find((r) => r.recipientType === 'TO'); + const currentRecipientId = currentToRecipient?.recipientOrganizationId; + // Check for ACTUAL value changes + const isProjectChanged = updResolvedProjectId !== undefined && + updResolvedProjectId !== currentCorr.projectId; + const isOriginatorChanged = updResolvedOriginatorId !== undefined && + updResolvedOriginatorId !== currentCorr.originatorId; + const isDisciplineChanged = updateDto.disciplineId !== undefined && + updateDto.disciplineId !== currentCorr.disciplineId; + const isTypeChanged = updateDto.typeId !== undefined && + updateDto.typeId !== currentCorr.correspondenceTypeId; + let isRecipientChanged = false; + let newRecipientId; + if (updResolvedRecipients) { + const newToRecipient = updResolvedRecipients.find((r) => r.type === 'TO'); + newRecipientId = newToRecipient?.organizationId; + if (newRecipientId !== currentRecipientId) { + isRecipientChanged = true; + } + } + if (isProjectChanged || + isDisciplineChanged || + isTypeChanged || + isRecipientChanged || + isOriginatorChanged) { + const targetRecipientId = isRecipientChanged + ? newRecipientId + : currentRecipientId; + // Resolve Recipient Code for the NEW context + let recipientCode = ''; + if (targetRecipientId) { + const recOrg = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { id: targetRecipientId }, + }); + if (recOrg) + recipientCode = recOrg.organizationCode; + } + // [Fix #6] Fetch real ORG Code from originator organization + const originatorOrgForUpdate = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { + id: updResolvedOriginatorId ?? currentCorr.originatorId ?? 0, + }, + }); + const orgCode = originatorOrgForUpdate?.organizationCode ?? 'UNK'; + // Prepare Contexts + const oldCtx = { + projectId: currentCorr.projectId, + originatorOrganizationId: currentCorr.originatorId ?? 0, + typeId: currentCorr.correspondenceTypeId, + disciplineId: currentCorr.disciplineId, + recipientOrganizationId: currentRecipientId, + year: new Date().getFullYear(), + }; + const newCtx = { + projectId: updResolvedProjectId ?? currentCorr.projectId, + originatorOrganizationId: updResolvedOriginatorId ?? currentCorr.originatorId ?? 0, + typeId: updateDto.typeId ?? currentCorr.correspondenceTypeId, + disciplineId: updateDto.disciplineId ?? currentCorr.disciplineId, + recipientOrganizationId: targetRecipientId, + year: new Date().getFullYear(), + userId: user.user_id, // Pass User ID for Audit + customTokens: { + TYPE_CODE: currentCorr.type?.typeCode || '', + ORG_CODE: orgCode, + RECIPIENT_CODE: recipientCode, + REC_CODE: recipientCode, + }, + }; + // If Type Changed, need NEW Type Code + if (isTypeChanged) { + const newType = await this.typeRepo.findOne({ + where: { id: newCtx.typeId }, + }); + if (newType) + newCtx.customTokens.TYPE_CODE = newType.typeCode; + } + const newDocNumber = await this.numberingService.updateNumberForDraft(currentCorr.correspondenceNumber, oldCtx, newCtx); + await this.correspondenceRepo.update(id, { + correspondenceNumber: newDocNumber, + }); + } + } + const updated = await this.findOne(id); + // Re-index updated document in Elasticsearch (fire-and-forget) + void this.searchService.indexDocument({ + id: updated.id, + publicId: updated.publicId, + type: 'correspondence', + docNumber: updated.correspondenceNumber, + title: updateDto.subject ?? updated.revisions?.[0]?.subject, + description: updateDto.description ?? updated.revisions?.[0]?.description, + status: 'DRAFT', + projectId: updated.projectId, + createdAt: updated.createdAt, + }); + return updated; + } + async previewDocumentNumber(createDto, user) { + // ADR-019: Resolve UUID references + const previewProjectId = await this.uuidResolver.resolveProjectId(createDto.projectId); + const previewOriginatorId = createDto.originatorId + ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId) + : undefined; + const previewRecipients = createDto.recipients + ? await Promise.all(createDto.recipients.map(async (r) => ({ + organizationId: await this.uuidResolver.resolveOrganizationId(r.organizationId), + type: r.type, + }))) + : undefined; + const type = await this.typeRepo.findOne({ + where: { id: createDto.typeId }, + }); + if (!type) + throw new common_1.NotFoundException('Document Type not found'); + let userOrgId = user.primaryOrganizationId; + if (!userOrgId) { + const fullUser = await this.userService.findOne(user.user_id); + if (fullUser) + userOrgId = fullUser.primaryOrganizationId; + } + if (previewOriginatorId && previewOriginatorId !== userOrgId) { + // Allow impersonation for preview + userOrgId = previewOriginatorId; + } + // Extract recipient from recipients array + const toRecipient = previewRecipients?.find((r) => r.type === 'TO'); + const recipientOrganizationId = toRecipient?.organizationId; + let recipientCode = ''; + if (recipientOrganizationId) { + const recOrg = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { id: recipientOrganizationId }, + }); + if (recOrg) + recipientCode = recOrg.organizationCode; + } + return this.numberingService.previewNumber({ + projectId: previewProjectId, + originatorOrganizationId: userOrgId, + typeId: createDto.typeId, + disciplineId: createDto.disciplineId, + subTypeId: createDto.subTypeId, + recipientOrganizationId, + year: new Date().getFullYear(), + customTokens: { + TYPE_CODE: type.typeCode, + RECIPIENT_CODE: recipientCode, + REC_CODE: recipientCode, + }, + }); + } + /** + * Business Rule Implementation: EC-CORR-001 - Cancel Correspondence with Downstream Circulation + * Cancel correspondence and handle related circulations + */ + async cancel(publicId, reason, user) { + const correspondence = await this.findOneByUuid(publicId); + // Check if user has permission to cancel (Org Admin or Superadmin only) + const permissions = await this.userService.getUserPermissions(user.user_id); + const canCancel = permissions.includes('correspondence.cancel') || + permissions.includes('system.manage_all'); + if (!canCancel) { + throw new common_1.ForbiddenException('Only administrators can cancel correspondences'); + } + // Check if there are any active circulations + const circulationRepo = this.dataSource.getRepository('Circulation'); + const activeCirculations = await circulationRepo.find({ + where: { + correspondenceId: correspondence.id, + status: 'OPEN', + }, + }); + const warningMessage = activeCirculations.length > 0 + ? `There are ${activeCirculations.length} active circulation(s) for this correspondence. Canceling will force close all related circulations.` + : ''; + // Get the current revision to update status + const currentRevision = await this.revisionRepo.findOne({ + where: { + correspondenceId: correspondence.id, + isCurrent: true, + }, + }); + if (!currentRevision) { + throw new common_1.NotFoundException('Current revision not found'); + } + // Get cancelled status + const cancelledStatus = await this.statusRepo.findOne({ + where: { statusCode: 'CANCELLED' }, + }); + if (!cancelledStatus) { + throw new common_1.InternalServerErrorException('CANCELLED status not found'); + } + const queryRunner = this.dataSource.createQueryRunner(); + await queryRunner.connect(); + await queryRunner.startTransaction(); + try { + // Update correspondence revision status to CANCELLED + await queryRunner.manager.update(correspondence_revision_entity_1.CorrespondenceRevision, currentRevision.id, { + statusId: cancelledStatus.id, + remarks: `Cancelled: ${reason}`, + }); + // Force close all active circulations + if (activeCirculations.length > 0) { + await queryRunner.manager.update('Circulation', { + correspondenceId: correspondence.id, + status: 'OPEN', + }, { + status: 'FORCE_CLOSED', + closedAt: new Date(), + closedBy: user.user_id, + closeReason: `Correspondence cancelled: ${reason}`, + }); + } + await queryRunner.commitTransaction(); + // Re-index cancelled status in Elasticsearch (fire-and-forget) + void this.searchService.indexDocument({ + id: correspondence.id, + publicId: correspondence.publicId, + type: 'correspondence', + docNumber: correspondence.correspondenceNumber, + title: currentRevision.subject, + status: 'CANCELLED', + projectId: correspondence.projectId, + createdAt: correspondence.createdAt, + }); + // Notify originator's doc-control user about cancellation (fire-and-forget) + if (correspondence.originatorId) { + void this.userService + .findDocControlIdByOrg(correspondence.originatorId) + .then((targetUserId) => { + if (targetUserId) { + void this.notificationService.send({ + userId: targetUserId, + title: 'Correspondence Cancelled', + message: `${correspondence.correspondenceNumber} — ${currentRevision.subject} has been cancelled. Reason: ${reason}`, + type: 'EMAIL', + entityType: 'correspondence', + entityId: correspondence.id, + link: `/correspondences/${correspondence.publicId}`, + }); + } + }) + .catch((err) => this.logger.warn(`Cancel notification failed: ${err.message}`)); + } + return { + success: true, + message: warningMessage || 'Correspondence cancelled successfully', + activeCirculationsCount: activeCirculations.length, + }; + } + catch (error) { + await queryRunner.rollbackTransaction(); + this.logger.error(`Failed to cancel correspondence: ${error.message}`); + throw error; + } + finally { + await queryRunner.release(); + } + } + async bulkCancel(publicIds, reason, user) { + const succeeded = []; + const failed = []; + for (const publicId of publicIds) { + try { + await this.cancel(publicId, reason, user); + succeeded.push(publicId); + } + catch { + failed.push(publicId); + } + } + return { succeeded, failed }; + } + async exportCsv(searchDto) { + const { data } = await this.findAll(searchDto); + const header = [ + 'Document No.', + 'Rev', + 'Subject', + 'Type', + 'Status', + 'Project', + 'From', + 'Due Date', + 'Created At', + ]; + const rows = data.map((rev) => { + const corr = rev.correspondence ?? rev; + return [ + this.escapeCsv(corr.correspondenceNumber ?? ''), + this.escapeCsv(rev.revisionLabel ?? String(rev.revisionNumber ?? 0)), + this.escapeCsv(rev.subject ?? ''), + this.escapeCsv(corr.type?.typeCode ?? ''), + this.escapeCsv(rev.status?.statusCode ?? ''), + this.escapeCsv(corr.project?.projectCode ?? ''), + this.escapeCsv(corr.originator?.organizationCode ?? ''), + rev.dueDate ? new Date(rev.dueDate).toISOString().split('T')[0] : '', + new Date(rev.createdAt).toISOString().split('T')[0], + ].join(','); + }); + return [header.join(','), ...rows].join('\n'); + } + escapeCsv(value) { + if (value.includes(',') || value.includes('"') || value.includes('\n')) { + return `"${value.replace(/"/g, '""')}"`; + } + return value; + } +}; +exports.CorrespondenceService = CorrespondenceService; +exports.CorrespondenceService = CorrespondenceService = CorrespondenceService_1 = __decorate([ + (0, common_1.Injectable)(), + __param(0, (0, typeorm_1.InjectRepository)(correspondence_entity_1.Correspondence)), + __param(1, (0, typeorm_1.InjectRepository)(correspondence_revision_entity_1.CorrespondenceRevision)), + __param(2, (0, typeorm_1.InjectRepository)(correspondence_type_entity_1.CorrespondenceType)), + __param(3, (0, typeorm_1.InjectRepository)(correspondence_status_entity_1.CorrespondenceStatus)), + __param(4, (0, typeorm_1.InjectRepository)(correspondence_reference_entity_1.CorrespondenceReference)), + __param(5, (0, typeorm_1.InjectRepository)(correspondence_tag_entity_1.CorrespondenceTag)), + __metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _a : Object, typeof (_b = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _b : Object, typeof (_c = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _c : Object, typeof (_d = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _d : Object, typeof (_e = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _e : Object, typeof (_f = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _f : Object, typeof (_g = typeof document_numbering_service_1.DocumentNumberingService !== "undefined" && document_numbering_service_1.DocumentNumberingService) === "function" ? _g : Object, typeof (_h = typeof json_schema_service_1.JsonSchemaService !== "undefined" && json_schema_service_1.JsonSchemaService) === "function" ? _h : Object, typeof (_j = typeof workflow_engine_service_1.WorkflowEngineService !== "undefined" && workflow_engine_service_1.WorkflowEngineService) === "function" ? _j : Object, typeof (_k = typeof user_service_1.UserService !== "undefined" && user_service_1.UserService) === "function" ? _k : Object, typeof (_l = typeof typeorm_2.DataSource !== "undefined" && typeorm_2.DataSource) === "function" ? _l : Object, typeof (_m = typeof search_service_1.SearchService !== "undefined" && search_service_1.SearchService) === "function" ? _m : Object, typeof (_o = typeof file_storage_service_1.FileStorageService !== "undefined" && file_storage_service_1.FileStorageService) === "function" ? _o : Object, typeof (_p = typeof uuid_resolver_service_1.UuidResolverService !== "undefined" && uuid_resolver_service_1.UuidResolverService) === "function" ? _p : Object, typeof (_q = typeof notification_service_1.NotificationService !== "undefined" && notification_service_1.NotificationService) === "function" ? _q : Object]) +], CorrespondenceService); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoiRTpcXG5wLWRtc1xcbGNicDNcXGJhY2tlbmRcXHNyY1xcbW9kdWxlc1xcY29ycmVzcG9uZGVuY2VcXGNvcnJlc3BvbmRlbmNlLnNlcnZpY2UudHMiLCJtYXBwaW5ncyI6IjtBQUFBLDZEQUE2RDs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFN0QsMkNBT3dCO0FBQ3hCLDZDQUFtRDtBQUNuRCxxQ0FBaUQ7QUFFakQsV0FBVztBQUNYLDRFQUFrRTtBQUNsRSw4RkFBbUY7QUFDbkYsc0ZBQTJFO0FBQzNFLDBGQUErRTtBQUMvRSxnR0FBcUY7QUFDckYsZ0dBQXFGO0FBQ3JGLG9GQUF5RTtBQUN6RSw4REFBb0Q7QUFFcEQsc0ZBQTRFO0FBUTVFLFdBQVc7QUFDWCwwR0FBcUc7QUFDckcsNEVBQXVFO0FBQ3ZFLHdGQUFtRjtBQUNuRix1REFBbUQ7QUFDbkQsNkRBQXlEO0FBQ3pELHlGQUFvRjtBQUNwRix1RkFBa0Y7QUFDbEYsK0VBQTJFO0FBVXBFLElBQU0scUJBQXFCLDZCQUEzQixNQUFNLHFCQUFxQjtJQUd4QixLQUFLLENBQUMsNEJBQTRCLENBQUMsTUFBYztRQUN2RCxNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDdEUsT0FBTyxXQUFXLENBQUMsUUFBUSxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDbkQsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyx1QkFBdUIsQ0FBQyxRQUFnQjtRQUM5QyxNQUFNLGFBQWEsR0FBRyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNyQyxJQUFJLGFBQWEsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxDQUFDLEVBQUUsQ0FBQztZQUNuRCxPQUFPLEdBQUcsQ0FBQyxDQUFDLHdCQUF3QjtRQUN0QyxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsQ0FBQyxnQ0FBZ0M7SUFDL0MsQ0FBQztJQUVELFlBRUUsa0JBQXNELEVBRXRELFlBQXdELEVBRXhELFFBQWdELEVB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QUFDLENBQUE7SUFFaEMsV0FBQSxJQUFBLDBCQUFnQixFQUFDLHVEQUFzQixDQUFDLENBQUE7SUFFeEMsV0FBQSxJQUFBLDBCQUFnQixFQUFDLCtDQUFrQixDQUFDLENBQUE7SUFFcEMsV0FBQSxJQUFBLDBCQUFnQixFQUFDLG1EQUFvQixDQUFDLENBQUE7SUFFdEMsV0FBQSxJQUFBLDBCQUFnQixFQUFDLHlEQUF1QixDQUFDLENBQUE7SUFFekMsV0FBQSxJQUFBLDBCQUFnQixFQUFDLDZDQUFpQixDQUFDLENBQUE7eURBVFIsb0JBQVUsb0JBQVYsb0JBQVUsb0RBRWhCLG9CQUFVLG9CQUFWLG9CQUFVLG9EQUVkLG9CQUFVLG9CQUFWLG9CQUFVLG9EQUVSLG9CQUFVLG9CQUFWLG9CQUFVLG9EQUVQLG9CQUFVLG9CQUFWLG9CQUFVLG9EQUVoQixvQkFBVSxvQkFBVixvQkFBVSxvREFDRCxxREFBd0Isb0JBQXhCLHFEQUF3QixvREFDdkIsdUNBQWlCLG9CQUFqQix1Q0FBaUIsb0RBQ3BCLCtDQUFxQixvQkFBckIsK0NBQXFCLG9EQUN4QiwwQkFBVyxvQkFBWCwwQkFBVyxvREFDWixvQkFBVSxvQkFBVixvQkFBVSxvREFDUCw4QkFBYSxvQkFBYiw4QkFBYSxvREFDUix5Q0FBa0Isb0JBQWxCLHlDQUFrQixvREFDeEIsMkNBQW1CLG9CQUFuQiwyQ0FBbUIsb0RBQ1osMENBQW1CLG9CQUFuQiwwQ0FBbUI7R0ExQ3ZDLHFCQUFxQixDQWtqQ2pDIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIkU6XFxucC1kbXNcXGxjYnAzXFxiYWNrZW5kXFxzcmNcXG1vZHVsZXNcXGNvcnJlc3BvbmRlbmNlXFxjb3JyZXNwb25kZW5jZS5zZXJ2aWNlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIEZpbGU6IHNyYy9tb2R1bGVzL2NvcnJlc3BvbmRlbmNlL2NvcnJlc3BvbmRlbmNlLnNlcnZpY2UudHNcclxuXHJcbmltcG9ydCB7XHJcbiAgSW5qZWN0YWJsZSxcclxuICBOb3RGb3VuZEV4Y2VwdGlvbixcclxuICBCYWRSZXF1ZXN0RXhjZXB0aW9uLFxyXG4gIEludGVybmFsU2VydmVyRXJyb3JFeGNlcHRpb24sXHJcbiAgRm9yYmlkZGVuRXhjZXB0aW9uLFxyXG4gIExvZ2dlcixcclxufSBmcm9tICdAbmVzdGpzL2NvbW1vbic7XHJcbmltcG9ydCB7IEluamVjdFJlcG9zaXRvcnkgfSBmcm9tICdAbmVzdGpzL3R5cGVvcm0nO1xyXG5pbXBvcnQgeyBSZXBvc2l0b3J5LCBEYXRhU291cmNlIH0gZnJvbSAndHlwZW9ybSc7XHJcblxyXG4vLyBFbnRpdGllc1xyXG5pbXBvcnQgeyBDb3JyZXNwb25kZW5jZSB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2UuZW50aXR5JztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VSZXZpc2lvbiB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2UtcmV2aXNpb24uZW50aXR5JztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VUeXBlIH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS10eXBlLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlU3RhdHVzIH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS1zdGF0dXMuZW50aXR5JztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VSZWZlcmVuY2UgfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLXJlZmVyZW5jZS5lbnRpdHknO1xyXG5pbXBvcnQgeyBDb3JyZXNwb25kZW5jZVJlY2lwaWVudCB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2UtcmVjaXBpZW50LmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlVGFnIH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS10YWcuZW50aXR5JztcclxuaW1wb3J0IHsgVGFnIH0gZnJvbSAnLi4vbWFzdGVyL2VudGl0aWVzL3RhZy5lbnRpdHknO1xyXG5pbXBvcnQgeyBVc2VyIH0gZnJvbSAnLi4vdXNlci9lbnRpdGllcy91c2VyLmVudGl0eSc7XHJcbmltcG9ydCB7IE9yZ2FuaXphdGlvbiB9IGZyb20gJy4uL29yZ2FuaXphdGlvbi9lbnRpdGllcy9vcmdhbml6YXRpb24uZW50aXR5JztcclxuXHJcbi8vIERUT3NcclxuaW1wb3J0IHsgQ3JlYXRlQ29ycmVzcG9uZGVuY2VEdG8gfSBmcm9tICcuL2R0by9jcmVhdGUtY29ycmVzcG9uZGVuY2UuZHRvJztcclxuaW1wb3J0IHsgVXBkYXRlQ29ycmVzcG9uZGVuY2VEdG8gfSBmcm9tICcuL2R0by91cGRhdGUtY29ycmVzcG9uZGVuY2UuZHRvJztcclxuaW1wb3J0IHsgQWRkUmVmZXJlbmNlRHRvIH0gZnJvbSAnLi9kdG8vYWRkLXJlZmVyZW5jZS5kdG8nO1xyXG5pbXBvcnQgeyBTZWFyY2hDb3JyZXNwb25kZW5jZUR0byB9IGZyb20gJy4vZHRvL3NlYXJjaC1jb3JyZXNwb25kZW5jZS5kdG8nO1xyXG5cclxuLy8gU2VydmljZXNcclxuaW1wb3J0IHsgRG9jdW1lbnROdW1iZXJpbmdTZXJ2aWNlIH0gZnJvbSAnLi4vZG9jdW1lbnQtbnVtYmVyaW5nL3NlcnZpY2VzL2RvY3VtZW50LW51bWJlcmluZy5zZXJ2aWNlJztcclxuaW1wb3J0IHsgSnNvblNjaGVtYVNlcnZpY2UgfSBmcm9tICcuLi9qc29uLXNjaGVtYS9qc29uLXNjaGVtYS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgV29ya2Zsb3dFbmdpbmVTZXJ2aWNlIH0gZnJvbSAnLi4vd29ya2Zsb3ctZW5naW5lL3dvcmtmbG93LWVuZ2luZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgVXNlclNlcnZpY2UgfSBmcm9tICcuLi91c2VyL3VzZXIuc2VydmljZSc7XHJcbmltcG9ydCB7IFNlYXJjaFNlcnZpY2UgfSBmcm9tICcuLi9zZWFyY2gvc2VhcmNoLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBGaWxlU3RvcmFnZVNlcnZpY2UgfSBmcm9tICcuLi8uLi9jb21tb24vZmlsZS1zdG9yYWdlL2ZpbGUtc3RvcmFnZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgVXVpZFJlc29sdmVyU2VydmljZSB9IGZyb20gJy4uLy4uL2NvbW1vbi9zZXJ2aWNlcy91dWlkLXJlc29sdmVyLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBOb3RpZmljYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi4vbm90aWZpY2F0aW9uL25vdGlmaWNhdGlvbi5zZXJ2aWNlJztcclxuXHJcbi8qKlxyXG4gKiBDb3JyZXNwb25kZW5jZVNlcnZpY2UgLSBEb2N1bWVudCBtYW5hZ2VtZW50IChDUlVEKVxyXG4gKi9cclxuaW50ZXJmYWNlIFJlc29sdmVkUmVjaXBpZW50IHtcclxuICBvcmdhbml6YXRpb25JZDogbnVtYmVyO1xyXG4gIHR5cGU6ICdUTycgfCAnQ0MnO1xyXG59XHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGNsYXNzIENvcnJlc3BvbmRlbmNlU2VydmljZSB7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBsb2dnZXIgPSBuZXcgTG9nZ2VyKENvcnJlc3BvbmRlbmNlU2VydmljZS5uYW1lKTtcclxuXHJcbiAgcHJpdmF0ZSBhc3luYyBoYXNTeXN0ZW1NYW5hZ2VBbGxQZXJtaXNzaW9uKHVzZXJJZDogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XHJcbiAgICBjb25zdCBwZXJtaXNzaW9ucyA9IGF3YWl0IHRoaXMudXNlclNlcnZpY2UuZ2V0VXNlclBlcm1pc3Npb25zKHVzZXJJZCk7XHJcbiAgICByZXR1cm4gcGVybWlzc2lvbnMuaW5jbHVkZXMoJ3N5c3RlbS5tYW5hZ2VfYWxsJyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBCdXNpbmVzcyBSdWxlOiBSZXZpc2lvbiBMYWJlbCBTdHJhdGVneVxyXG4gICAqIC0gUkZBLCBSRkk6IFVzZSBhbHBoYWJldCBzdGFydGluZyB3aXRoICdBJyAoQSwgQiwgQy4uLilcclxuICAgKiAtIE90aGVyIHR5cGVzIChMRVRURVIsIE1FTU8sIGV0Yy4pOiBVc2UgbnVtZXJpYyAobnVsbCBmb3IgZmlyc3QsIHRoZW4gMSwgMiwgMy4uLilcclxuICAgKi9cclxuICBwcml2YXRlIGdldEluaXRpYWxSZXZpc2lvbkxhYmVsKHR5cGVDb2RlOiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsIHtcclxuICAgIGNvbnN0IGFscGhhYmV0VHlwZXMgPSBbJ1JGQScsICdSRkknXTtcclxuICAgIGlmIChhbHBoYWJldFR5cGVzLmluY2x1ZGVzKHR5cGVDb2RlLnRvVXBwZXJDYXNlKCkpKSB7XHJcbiAgICAgIHJldHVybiAnQSc7IC8vIEFscGhhYmV0IGZvciBSRkEsIFJGSVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIG51bGw7IC8vIE51bWVyaWMgKG51bGwgZm9yIHJldmlzaW9uIDApXHJcbiAgfVxyXG5cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIEBJbmplY3RSZXBvc2l0b3J5KENvcnJlc3BvbmRlbmNlKVxyXG4gICAgcHJpdmF0ZSBjb3JyZXNwb25kZW5jZVJlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2U+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VSZXZpc2lvbilcclxuICAgIHByaXZhdGUgcmV2aXNpb25SZXBvOiBSZXBvc2l0b3J5PENvcnJlc3BvbmRlbmNlUmV2aXNpb24+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VUeXBlKVxyXG4gICAgcHJpdmF0ZSB0eXBlUmVwbzogUmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVR5cGU+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VTdGF0dXMpXHJcbiAgICBwcml2YXRlIHN0YXR1c1JlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VTdGF0dXM+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VSZWZlcmVuY2UpXHJcbiAgICBwcml2YXRlIHJlZmVyZW5jZVJlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VSZWZlcmVuY2U+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VUYWcpXHJcbiAgICBwcml2YXRlIHRhZ1JlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VUYWc+LFxyXG4gICAgcHJpdmF0ZSBudW1iZXJpbmdTZXJ2aWNlOiBEb2N1bWVudE51bWJlcmluZ1NlcnZpY2UsXHJcbiAgICBwcml2YXRlIGpzb25TY2hlbWFTZXJ2aWNlOiBKc29uU2NoZW1hU2VydmljZSxcclxuICAgIHByaXZhdGUgd29ya2Zsb3dFbmdpbmU6IFdvcmtmbG93RW5naW5lU2VydmljZSxcclxuICAgIHByaXZhdGUgdXNlclNlcnZpY2U6IFVzZXJTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBkYXRhU291cmNlOiBEYXRhU291cmNlLFxyXG4gICAgcHJpdmF0ZSBzZWFyY2hTZXJ2aWNlOiBTZWFyY2hTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBmaWxlU3RvcmFnZVNlcnZpY2U6IEZpbGVTdG9yYWdlU2VydmljZSxcclxuICAgIHByaXZhdGUgdXVpZFJlc29sdmVyOiBVdWlkUmVzb2x2ZXJTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBub3RpZmljYXRpb25TZXJ2aWNlOiBOb3RpZmljYXRpb25TZXJ2aWNlXHJcbiAgKSB7fVxyXG5cclxuICAvKipcclxuICAgKiBCdXNpbmVzcyBSdWxlIFZhbGlkYXRpb246IEVDLUNPUlItMDAzIC0gQ29ycmVzcG9uZGVuY2UgdG8gU2VsZlxyXG4gICAqIFByZXZlbnQgZXh0ZXJuYWwgY29ycmVzcG9uZGVuY2UgdG8gc2FtZSBvcmdhbml6YXRpb25cclxuICAgKi9cclxuICBwcml2YXRlIGFzeW5jIHZhbGlkYXRlQ29ycmVzcG9uZGVuY2VSZWNpcGllbnRzKFxyXG4gICAgY3JlYXRlRHRvOiBDcmVhdGVDb3JyZXNwb25kZW5jZUR0byxcclxuICAgIHVzZXI6IFVzZXJcclxuICApOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIC8vIEdldCB1c2VyJ3Mgb3JnYW5pemF0aW9uXHJcbiAgICBsZXQgdXNlck9yZ0lkID0gdXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcbiAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICBjb25zdCBmdWxsVXNlciA9IGF3YWl0IHRoaXMudXNlclNlcnZpY2UuZmluZE9uZSh1c2VyLnVzZXJfaWQpO1xyXG4gICAgICBpZiAoZnVsbFVzZXIpIHtcclxuICAgICAgICB1c2VyT3JnSWQgPSBmdWxsVXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICBpZiAoY3JlYXRlRHRvLm9yaWdpbmF0b3JJZCkge1xyXG4gICAgICAgIGNvbnN0IGNhbk1hbmFnZUFsbCA9IGF3YWl0IHRoaXMuaGFzU3lzdGVtTWFuYWdlQWxsUGVybWlzc2lvbihcclxuICAgICAgICAgIHVzZXIudXNlcl9pZFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgaWYgKGNhbk1hbmFnZUFsbCkge1xyXG4gICAgICAgICAgdXNlck9yZ0lkID0gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKFxyXG4gICAgICAgICAgICBjcmVhdGVEdG8ub3JpZ2luYXRvcklkXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKCF1c2VyT3JnSWQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgQmFkUmVxdWVzdEV4Y2VwdGlvbihcclxuICAgICAgICAgICdVc2VyIG11c3QgYmVsb25nIHRvIGFuIG9yZ2FuaXphdGlvbiB0byBjcmVhdGUgZG9jdW1lbnRzJ1xyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBGb3IgaW1wZXJzb25hdGlvbiwgdXNlIHRoZSBzcGVjaWZpZWQgb3JpZ2luYXRvclxyXG4gICAgY29uc3Qgb3JpZ2luYXRvck9yZ0lkID0gY3JlYXRlRHRvLm9yaWdpbmF0b3JJZFxyXG4gICAgICA/IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZChjcmVhdGVEdG8ub3JpZ2luYXRvcklkKVxyXG4gICAgICA6IHVzZXJPcmdJZDtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGludGVybmFsIGNvbW11bmljYXRpb25cclxuICAgIGlmIChjcmVhdGVEdG8uaXNJbnRlcm5hbCkge1xyXG4gICAgICAvLyBJbnRlcm5hbCBjb21tdW5pY2F0aW9ucyBzaG91bGQgdXNlIENpcmN1bGF0aW9uIGluc3RlYWRcclxuICAgICAgdGhyb3cgbmV3IEJhZFJlcXVlc3RFeGNlcHRpb24oXHJcbiAgICAgICAgJ0ludGVybmFsIGNvbW11bmljYXRpb25zIHNob3VsZCB1c2UgQ2lyY3VsYXRpb24gU2hlZXQgaW5zdGVhZCBvZiBDb3JyZXNwb25kZW5jZSdcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBWYWxpZGF0ZSByZWNpcGllbnRzXHJcbiAgICBpZiAoIWNyZWF0ZUR0by5yZWNpcGllbnRzIHx8IGNyZWF0ZUR0by5yZWNpcGllbnRzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICB0aHJvdyBuZXcgQmFkUmVxdWVzdEV4Y2VwdGlvbihcclxuICAgICAgICAnQXQgbGVhc3Qgb25lIHJlY2lwaWVudCAoVE8gb3IgQ0MpIGlzIHJlcXVpcmVkJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHRvUmVjaXBpZW50cyA9IGNyZWF0ZUR0by5yZWNpcGllbnRzLmZpbHRlcigocikgPT4gci50eXBlID09PSAnVE8nKTtcclxuICAgIGNvbnN0IGNjUmVjaXBpZW50cyA9IGNyZWF0ZUR0by5yZWNpcGllbnRzLmZpbHRlcigocikgPT4gci50eXBlID09PSAnQ0MnKTtcclxuXHJcbiAgICBpZiAodG9SZWNpcGllbnRzLmxlbmd0aCA9PT0gMCAmJiBjY1JlY2lwaWVudHMubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgIHRocm93IG5ldyBCYWRSZXF1ZXN0RXhjZXB0aW9uKFxyXG4gICAgICAgICdBdCBsZWFzdCBvbmUgVE8gb3IgQ0MgcmVjaXBpZW50IGlzIHJlcXVpcmVkJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGZvciBzYW1lIG9yZ2FuaXphdGlvbiBjb3JyZXNwb25kZW5jZVxyXG4gICAgZm9yIChjb25zdCByZWNpcGllbnQgb2YgY3JlYXRlRHRvLnJlY2lwaWVudHMpIHtcclxuICAgICAgY29uc3QgcmVjaXBpZW50T3JnSWQgPSBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlT3JnYW5pemF0aW9uSWQoXHJcbiAgICAgICAgcmVjaXBpZW50Lm9yZ2FuaXphdGlvbklkXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBpZiAocmVjaXBpZW50T3JnSWQgPT09IG9yaWdpbmF0b3JPcmdJZCkge1xyXG4gICAgICAgIHRocm93IG5ldyBCYWRSZXF1ZXN0RXhjZXB0aW9uKFxyXG4gICAgICAgICAgJ0Nhbm5vdCBzZW5kIGNvcnJlc3BvbmRlbmNlIHRvIHlvdXIgb3duIG9yZ2FuaXphdGlvbi4gVXNlIENpcmN1bGF0aW9uIFNoZWV0IGZvciBpbnRlcm5hbCBjb21tdW5pY2F0aW9uLidcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBhc3luYyBjcmVhdGUoY3JlYXRlRHRvOiBDcmVhdGVDb3JyZXNwb25kZW5jZUR0bywgdXNlcjogVXNlcikge1xyXG4gICAgLy8gQnVzaW5lc3MgUnVsZSBWYWxpZGF0aW9uOiBFQy1DT1JSLTAwMyAtIENvcnJlc3BvbmRlbmNlIHRvIFNlbGZcclxuICAgIGF3YWl0IHRoaXMudmFsaWRhdGVDb3JyZXNwb25kZW5jZVJlY2lwaWVudHMoY3JlYXRlRHRvLCB1c2VyKTtcclxuICAgIC8vIEFEUi0wMTk6IFJlc29sdmUgVVVJRCByZWZlcmVuY2VzIHRvIGludGVybmFsIElOVCBJRHNcclxuICAgIGNvbnN0IHJlc29sdmVkUHJvamVjdElkID0gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZVByb2plY3RJZChcclxuICAgICAgY3JlYXRlRHRvLnByb2plY3RJZFxyXG4gICAgKTtcclxuICAgIGNvbnN0IHJlc29sdmVkT3JpZ2luYXRvcklkID0gY3JlYXRlRHRvLm9yaWdpbmF0b3JJZFxyXG4gICAgICA/IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZChjcmVhdGVEdG8ub3JpZ2luYXRvcklkKVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuICAgIGNvbnN0IHJlc29sdmVkUmVjaXBpZW50cyA9IGNyZWF0ZUR0by5yZWNpcGllbnRzXHJcbiAgICAgID8gYXdhaXQgUHJvbWlzZS5hbGwoXHJcbiAgICAgICAgICBjcmVhdGVEdG8ucmVjaXBpZW50cy5tYXAoXHJcbiAgICAgICAgICAgIGFzeW5jIChyKTogUHJvbWlzZTxSZXNvbHZlZFJlY2lwaWVudD4gPT4gKHtcclxuICAgICAgICAgICAgICBvcmdhbml6YXRpb25JZDogYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKFxyXG4gICAgICAgICAgICAgICAgci5vcmdhbml6YXRpb25JZFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgICAgdHlwZTogci50eXBlLFxyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgIClcclxuICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICBjb25zdCB0eXBlID0gYXdhaXQgdGhpcy50eXBlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgaWQ6IGNyZWF0ZUR0by50eXBlSWQgfSxcclxuICAgIH0pO1xyXG4gICAgaWYgKCF0eXBlKSB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oJ0RvY3VtZW50IFR5cGUgbm90IGZvdW5kJyk7XHJcblxyXG4gICAgY29uc3Qgc3RhdHVzRHJhZnQgPSBhd2FpdCB0aGlzLnN0YXR1c1JlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IHN0YXR1c0NvZGU6ICdEUkFGVCcgfSxcclxuICAgIH0pO1xyXG4gICAgaWYgKCFzdGF0dXNEcmFmdCkge1xyXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxTZXJ2ZXJFcnJvckV4Y2VwdGlvbihcclxuICAgICAgICAnU3RhdHVzIERSQUZUIG5vdCBmb3VuZCBpbiBNYXN0ZXIgRGF0YSdcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgdXNlck9yZ0lkID0gdXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcblxyXG4gICAgaWYgKCF1c2VyT3JnSWQpIHtcclxuICAgICAgY29uc3QgZnVsbFVzZXIgPSBhd2FpdCB0aGlzLnVzZXJTZXJ2aWNlLmZpbmRPbmUodXNlci51c2VyX2lkKTtcclxuICAgICAgaWYgKGZ1bGxVc2VyKSB7XHJcbiAgICAgICAgdXNlck9yZ0lkID0gZnVsbFVzZXIucHJpbWFyeU9yZ2FuaXphdGlvbklkO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSW1wZXJzb25hdGlvbiBMb2dpY1xyXG4gICAgaWYgKHJlc29sdmVkT3JpZ2luYXRvcklkICYmIHJlc29sdmVkT3JpZ2luYXRvcklkICE9PSB1c2VyT3JnSWQpIHtcclxuICAgICAgY29uc3QgY2FuTWFuYWdlQWxsID0gYXdhaXQgdGhpcy5oYXNTeXN0ZW1NYW5hZ2VBbGxQZXJtaXNzaW9uKFxyXG4gICAgICAgIHVzZXIudXNlcl9pZFxyXG4gICAgICApO1xyXG4gICAgICBpZiAoIWNhbk1hbmFnZUFsbCkge1xyXG4gICAgICAgIHRocm93IG5ldyBGb3JiaWRkZW5FeGNlcHRpb24oXHJcbiAgICAgICAgICAnWW91IGRvIG5vdCBoYXZlIHBlcm1pc3Npb24gdG8gY3JlYXRlIGRvY3VtZW50cyBvbiBiZWhhbGYgb2Ygb3RoZXIgb3JnYW5pemF0aW9ucy4nXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgICB1c2VyT3JnSWQgPSByZXNvbHZlZE9yaWdpbmF0b3JJZDtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICB0aHJvdyBuZXcgQmFkUmVxdWVzdEV4Y2VwdGlvbihcclxuICAgICAgICAnVXNlciBtdXN0IGJlbG9uZyB0byBhbiBvcmdhbml6YXRpb24gdG8gY3JlYXRlIGRvY3VtZW50cydcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoY3JlYXRlRHRvLmRldGFpbHMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBhd2FpdCB0aGlzLmpzb25TY2hlbWFTZXJ2aWNlLnZhbGlkYXRlKHR5cGUudHlwZUNvZGUsIGNyZWF0ZUR0by5kZXRhaWxzKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcclxuICAgICAgICB0aGlzLmxvZ2dlci53YXJuKFxyXG4gICAgICAgICAgYFNjaGVtYSB2YWxpZGF0aW9uIHdhcm5pbmcgZm9yICR7dHlwZS50eXBlQ29kZX06ICR7KGVycm9yIGFzIEVycm9yKS5tZXNzYWdlfWBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgcXVlcnlSdW5uZXIgPSB0aGlzLmRhdGFTb3VyY2UuY3JlYXRlUXVlcnlSdW5uZXIoKTtcclxuICAgIGF3YWl0IHF1ZXJ5UnVubmVyLmNvbm5lY3QoKTtcclxuICAgIGF3YWl0IHF1ZXJ5UnVubmVyLnN0YXJ0VHJhbnNhY3Rpb24oKTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBbRml4ICM2XSBGZXRjaCByZWFsIE9SRyBDb2RlIGZyb20gT3JnYW5pemF0aW9uIGVudGl0eVxyXG4gICAgICBjb25zdCBvcmlnaW5hdG9yT3JnID0gYXdhaXQgdGhpcy5kYXRhU291cmNlLm1hbmFnZXIuZmluZE9uZShcclxuICAgICAgICBPcmdhbml6YXRpb24sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgd2hlcmU6IHsgaWQ6IHVzZXJPcmdJZCB9LFxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICAgICAgY29uc3Qgb3JnQ29kZSA9IG9yaWdpbmF0b3JPcmc/Lm9yZ2FuaXphdGlvbkNvZGUgPz8gJ1VOSyc7XHJcblxyXG4gICAgICAvLyBbdjEuNS4xXSBFeHRyYWN0IHJlY2lwaWVudCBvcmdhbml6YXRpb24gZnJvbSByZWNpcGllbnRzIGFycmF5IChQcmltYXJ5IFRPKVxyXG4gICAgICBjb25zdCB0b1JlY2lwaWVudCA9IHJlc29sdmVkUmVjaXBpZW50cz8uZmluZCgocikgPT4gci50eXBlID09PSAnVE8nKTtcclxuICAgICAgY29uc3QgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQgPSB0b1JlY2lwaWVudD8ub3JnYW5pemF0aW9uSWQ7XHJcblxyXG4gICAgICBsZXQgcmVjaXBpZW50Q29kZSA9ICcnO1xyXG4gICAgICBpZiAocmVjaXBpZW50T3JnYW5pemF0aW9uSWQpIHtcclxuICAgICAgICBjb25zdCByZWNPcmcgPSBhd2FpdCB0aGlzLmRhdGFTb3VyY2UubWFuYWdlci5maW5kT25lKE9yZ2FuaXphdGlvbiwge1xyXG4gICAgICAgICAgd2hlcmU6IHsgaWQ6IHJlY2lwaWVudE9yZ2FuaXphdGlvbklkIH0sXHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgaWYgKHJlY09yZykgcmVjaXBpZW50Q29kZSA9IHJlY09yZy5vcmdhbml6YXRpb25Db2RlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBjb25zdCBkb2NOdW1iZXIgPSBhd2FpdCB0aGlzLm51bWJlcmluZ1NlcnZpY2UuZ2VuZXJhdGVOZXh0TnVtYmVyKHtcclxuICAgICAgICBwcm9qZWN0SWQ6IHJlc29sdmVkUHJvamVjdElkLFxyXG4gICAgICAgIG9yaWdpbmF0b3JPcmdhbml6YXRpb25JZDogdXNlck9yZ0lkLFxyXG4gICAgICAgIHR5cGVJZDogY3JlYXRlRHRvLnR5cGVJZCxcclxuICAgICAgICBkaXNjaXBsaW5lSWQ6IGNyZWF0ZUR0by5kaXNjaXBsaW5lSWQsXHJcbiAgICAgICAgc3ViVHlwZUlkOiBjcmVhdGVEdG8uc3ViVHlwZUlkLFxyXG4gICAgICAgIHJlY2lwaWVudE9yZ2FuaXphdGlvbklkLCAvLyBbdjEuNS4xXSBQYXNzIHJlY2lwaWVudCBmb3IgZG9jdW1lbnQgbnVtYmVyIGZvcm1hdFxyXG4gICAgICAgIHllYXI6IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKSxcclxuICAgICAgICBjdXN0b21Ub2tlbnM6IHtcclxuICAgICAgICAgIFRZUEVfQ09ERTogdHlwZS50eXBlQ29kZSxcclxuICAgICAgICAgIE9SR19DT0RFOiBvcmdDb2RlLFxyXG4gICAgICAgICAgUkVDSVBJRU5UX0NPREU6IHJlY2lwaWVudENvZGUsXHJcbiAgICAgICAgICBSRUNfQ09ERTogcmVjaXBpZW50Q29kZSxcclxuICAgICAgICB9LFxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGNvbnN0IGNvcnJlc3BvbmRlbmNlID0gcXVlcnlSdW5uZXIubWFuYWdlci5jcmVhdGUoQ29ycmVzcG9uZGVuY2UsIHtcclxuICAgICAgICBjb3JyZXNwb25kZW5jZU51bWJlcjogZG9jTnVtYmVyLm51bWJlcixcclxuICAgICAgICBjb3JyZXNwb25kZW5jZVR5cGVJZDogY3JlYXRlRHRvLnR5cGVJZCxcclxuICAgICAgICBkaXNjaXBsaW5lSWQ6IGNyZWF0ZUR0by5kaXNjaXBsaW5lSWQsXHJcbiAgICAgICAgcHJvamVjdElkOiByZXNvbHZlZFByb2plY3RJZCxcclxuICAgICAgICBvcmlnaW5hdG9ySWQ6IHVzZXJPcmdJZCxcclxuICAgICAgICBpc0ludGVybmFsOiBjcmVhdGVEdG8uaXNJbnRlcm5hbCB8fCBmYWxzZSxcclxuICAgICAgICBjcmVhdGVkQnk6IHVzZXIudXNlcl9pZCxcclxuICAgICAgfSk7XHJcbiAgICAgIGNvbnN0IHNhdmVkQ29yciA9IGF3YWl0IHF1ZXJ5UnVubmVyLm1hbmFnZXIuc2F2ZShjb3JyZXNwb25kZW5jZSk7XHJcblxyXG4gICAgICBjb25zdCByZXZpc2lvbiA9IHF1ZXJ5UnVubmVyLm1hbmFnZXIuY3JlYXRlKENvcnJlc3BvbmRlbmNlUmV2aXNpb24sIHtcclxuICAgICAgICBjb3JyZXNwb25kZW5jZUlkOiBzYXZlZENvcnIuaWQsXHJcbiAgICAgICAgcmV2aXNpb25OdW1iZXI6IDAsXHJcbiAgICAgICAgcmV2aXNpb25MYWJlbDogdGhpcy5nZXRJbml0aWFsUmV2aXNpb25MYWJlbCh0eXBlLnR5cGVDb2RlKSxcclxuICAgICAgICBpc0N1cnJlbnQ6IHRydWUsXHJcbiAgICAgICAgc3RhdHVzSWQ6IHN0YXR1c0RyYWZ0LmlkLFxyXG4gICAgICAgIHN1YmplY3Q6IGNyZWF0ZUR0by5zdWJqZWN0LFxyXG4gICAgICAgIGJvZHk6IGNyZWF0ZUR0by5ib2R5LFxyXG4gICAgICAgIHJlbWFya3M6IGNyZWF0ZUR0by5yZW1hcmtzLFxyXG4gICAgICAgIGR1ZURhdGU6IGNyZWF0ZUR0by5kdWVEYXRlID8gbmV3IERhdGUoY3JlYXRlRHRvLmR1ZURhdGUpIDogdW5kZWZpbmVkLFxyXG4gICAgICAgIGRvY3VtZW50RGF0ZTogY3JlYXRlRHRvLmRvY3VtZW50RGF0ZVxyXG4gICAgICAgICAgPyBuZXcgRGF0ZShjcmVhdGVEdG8uZG9jdW1lbnREYXRlKVxyXG4gICAgICAgICAgOiB1bmRlZmluZWQsXHJcbiAgICAgICAgaXNzdWVkRGF0ZTogY3JlYXRlRHRvLmlzc3VlZERhdGVcclxuICAgICAgICAgID8gbmV3IERhdGUoY3JlYXRlRHRvLmlzc3VlZERhdGUpXHJcbiAgICAgICAgICA6IHVuZGVmaW5lZCxcclxuICAgICAgICByZWNlaXZlZERhdGU6IGNyZWF0ZUR0by5yZWNlaXZlZERhdGVcclxuICAgICAgICAgID8gbmV3IERhdGUoY3JlYXRlRHRvLnJlY2VpdmVkRGF0ZSlcclxuICAgICAgICAgIDogdW5kZWZpbmVkLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiBjcmVhdGVEdG8uZGVzY3JpcHRpb24sXHJcbiAgICAgICAgZGV0YWlsczogY3JlYXRlRHRvLmRldGFpbHMsXHJcbiAgICAgICAgY3JlYXRlZEJ5OiB1c2VyLnVzZXJfaWQsXHJcbiAgICAgICAgc2NoZW1hVmVyc2lvbjogMSxcclxuICAgICAgfSk7XHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLm1hbmFnZXIuc2F2ZShyZXZpc2lvbik7XHJcblxyXG4gICAgICAvLyBTYXZlIFJlY2lwaWVudHMgKHVzaW5nIHJlc29sdmVkIElOVCBJRHMpXHJcbiAgICAgIGlmIChyZXNvbHZlZFJlY2lwaWVudHMgJiYgcmVzb2x2ZWRSZWNpcGllbnRzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICBjb25zdCByZWNpcGllbnRzID0gcmVzb2x2ZWRSZWNpcGllbnRzLm1hcCgocikgPT5cclxuICAgICAgICAgIHF1ZXJ5UnVubmVyLm1hbmFnZXIuY3JlYXRlKENvcnJlc3BvbmRlbmNlUmVjaXBpZW50LCB7XHJcbiAgICAgICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IHNhdmVkQ29yci5pZCxcclxuICAgICAgICAgICAgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQ6IHIub3JnYW5pemF0aW9uSWQsXHJcbiAgICAgICAgICAgIHJlY2lwaWVudFR5cGU6IHIudHlwZSxcclxuICAgICAgICAgIH0pXHJcbiAgICAgICAgKTtcclxuICAgICAgICBhd2FpdCBxdWVyeVJ1bm5lci5tYW5hZ2VyLnNhdmUocmVjaXBpZW50cyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENvbW1pdCBhdHRhY2htZW50cyBmcm9tIFRlbXAg4oaSIFBlcm1hbmVudCAoVHdvLVBoYXNlIFN0b3JhZ2UpXHJcbiAgICAgIGlmIChjcmVhdGVEdG8uYXR0YWNobWVudFRlbXBJZHM/Lmxlbmd0aCkge1xyXG4gICAgICAgIGNvbnN0IGlzc3VlRGF0ZSA9IGNyZWF0ZUR0by5pc3N1ZWREYXRlXHJcbiAgICAgICAgICA/IG5ldyBEYXRlKGNyZWF0ZUR0by5pc3N1ZWREYXRlKVxyXG4gICAgICAgICAgOiBjcmVhdGVEdG8uZG9jdW1lbnREYXRlXHJcbiAgICAgICAgICAgID8gbmV3IERhdGUoY3JlYXRlRHRvLmRvY3VtZW50RGF0ZSlcclxuICAgICAgICAgICAgOiB1bmRlZmluZWQ7XHJcblxyXG4gICAgICAgIGF3YWl0IHRoaXMuZmlsZVN0b3JhZ2VTZXJ2aWNlLmNvbW1pdChjcmVhdGVEdG8uYXR0YWNobWVudFRlbXBJZHMsIHtcclxuICAgICAgICAgIGlzc3VlRGF0ZSxcclxuICAgICAgICAgIGRvY3VtZW50VHlwZTogJ0NvcnJlc3BvbmRlbmNlJyxcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgYXdhaXQgcXVlcnlSdW5uZXIuY29tbWl0VHJhbnNhY3Rpb24oKTtcclxuXHJcbiAgICAgIC8vIFN0YXJ0IFdvcmtmbG93IEluc3RhbmNlIChub24tYmxvY2tpbmcpXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3Qgd29ya2Zsb3dDb2RlID0gYENPUlJFU1BPTkRFTkNFXyR7dHlwZS50eXBlQ29kZX1gO1xyXG4gICAgICAgIGF3YWl0IHRoaXMud29ya2Zsb3dFbmdpbmUuY3JlYXRlSW5zdGFuY2UoXHJcbiAgICAgICAgICB3b3JrZmxvd0NvZGUsXHJcbiAgICAgICAgICAnY29ycmVzcG9uZGVuY2UnLFxyXG4gICAgICAgICAgc2F2ZWRDb3JyLmlkLnRvU3RyaW5nKCksXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIHByb2plY3RJZDogcmVzb2x2ZWRQcm9qZWN0SWQsXHJcbiAgICAgICAgICAgIG9yaWdpbmF0b3JJZDogdXNlck9yZ0lkLFxyXG4gICAgICAgICAgICBkaXNjaXBsaW5lSWQ6IGNyZWF0ZUR0by5kaXNjaXBsaW5lSWQsXHJcbiAgICAgICAgICAgIGluaXRpYXRvcklkOiB1c2VyLnVzZXJfaWQsXHJcbiAgICAgICAgICB9IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+XHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcclxuICAgICAgICB0aGlzLmxvZ2dlci53YXJuKFxyXG4gICAgICAgICAgYFdvcmtmbG93IG5vdCBzdGFydGVkIGZvciAke2RvY051bWJlci5udW1iZXJ9IChDb2RlOiBDT1JSRVNQT05ERU5DRV8ke3R5cGUudHlwZUNvZGV9KTogJHsoZXJyb3IgYXMgRXJyb3IpLm1lc3NhZ2V9YFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEZpcmUtYW5kLWZvcmdldCBzZWFyY2ggaW5kZXhpbmcgKG5vbi1ibG9ja2luZywgdm9pZCBpbnRlbnRpb25hbClcclxuICAgICAgdm9pZCB0aGlzLnNlYXJjaFNlcnZpY2UuaW5kZXhEb2N1bWVudCh7XHJcbiAgICAgICAgaWQ6IHNhdmVkQ29yci5pZCxcclxuICAgICAgICBwdWJsaWNJZDogc2F2ZWRDb3JyLnB1YmxpY0lkLFxyXG4gICAgICAgIHR5cGU6ICdjb3JyZXNwb25kZW5jZScsXHJcbiAgICAgICAgZG9jTnVtYmVyOiBkb2NOdW1iZXIubnVtYmVyLFxyXG4gICAgICAgIHRpdGxlOiBjcmVhdGVEdG8uc3ViamVjdCxcclxuICAgICAgICBkZXNjcmlwdGlvbjogY3JlYXRlRHRvLmRlc2NyaXB0aW9uLFxyXG4gICAgICAgIHN0YXR1czogJ0RSQUZUJyxcclxuICAgICAgICBwcm9qZWN0SWQ6IHJlc29sdmVkUHJvamVjdElkLFxyXG4gICAgICAgIGNyZWF0ZWRBdDogbmV3IERhdGUoKSxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIC4uLnNhdmVkQ29ycixcclxuICAgICAgICBjdXJyZW50UmV2aXNpb246IHJldmlzaW9uLFxyXG4gICAgICB9O1xyXG4gICAgfSBjYXRjaCAoZXJyKSB7XHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLnJvbGxiYWNrVHJhbnNhY3Rpb24oKTtcclxuICAgICAgdGhpcy5sb2dnZXIuZXJyb3IoXHJcbiAgICAgICAgYEZhaWxlZCB0byBjcmVhdGUgY29ycmVzcG9uZGVuY2U6ICR7KGVyciBhcyBFcnJvcikubWVzc2FnZX1gXHJcbiAgICAgICk7XHJcbiAgICAgIHRocm93IGVycjtcclxuICAgIH0gZmluYWxseSB7XHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLnJlbGVhc2UoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFzeW5jIGZpbmRBbGwoc2VhcmNoRHRvOiBTZWFyY2hDb3JyZXNwb25kZW5jZUR0byA9IHt9KSB7XHJcbiAgICBjb25zdCB7XHJcbiAgICAgIHNlYXJjaCxcclxuICAgICAgdHlwZUlkLFxyXG4gICAgICBwcm9qZWN0SWQsXHJcbiAgICAgIHN0YXR1c0lkLFxyXG4gICAgICBzdGF0dXMsXHJcbiAgICAgIHBhZ2UgPSAxLFxyXG4gICAgICBsaW1pdCA9IDEwLFxyXG4gICAgfSA9IHNlYXJjaER0bztcclxuICAgIGNvbnN0IHNraXAgPSAocGFnZSAtIDEpICogbGltaXQ7XHJcblxyXG4gICAgLy8gQ2hhbmdlOiBRdWVyeSBmcm9tIFJldmlzaW9uIFJlcG9cclxuICAgIGNvbnN0IHF1ZXJ5ID0gdGhpcy5yZXZpc2lvblJlcG9cclxuICAgICAgLmNyZWF0ZVF1ZXJ5QnVpbGRlcigncmV2JylcclxuICAgICAgLmxlZnRKb2luQW5kU2VsZWN0KCdyZXYuY29ycmVzcG9uZGVuY2UnLCAnY29ycicpXHJcbiAgICAgIC5sZWZ0Sm9pbkFuZFNlbGVjdCgnY29yci50eXBlJywgJ3R5cGUnKVxyXG4gICAgICAubGVmdEpvaW5BbmRTZWxlY3QoJ2NvcnIucHJvamVjdCcsICdwcm9qZWN0JylcclxuICAgICAgLmxlZnRKb2luQW5kU2VsZWN0KCdjb3JyLm9yaWdpbmF0b3InLCAnb3JnJylcclxuICAgICAgLmxlZnRKb2luQW5kU2VsZWN0KCdyZXYuc3RhdHVzJywgJ3N0YXR1cycpO1xyXG5cclxuICAgIC8vIEZpbHRlciBieSBSZXZpc2lvbiBTdGF0dXNcclxuICAgIGNvbnN0IHJldlN0YXR1cyA9IHNlYXJjaER0by5yZXZpc2lvblN0YXR1cyB8fCAnQ1VSUkVOVCc7XHJcblxyXG4gICAgaWYgKHJldlN0YXR1cyA9PT0gJ0NVUlJFTlQnKSB7XHJcbiAgICAgIHF1ZXJ5LndoZXJlKCdyZXYuaXNDdXJyZW50ID0gOmlzQ3VycmVudCcsIHsgaXNDdXJyZW50OiB0cnVlIH0pO1xyXG4gICAgfSBlbHNlIGlmIChyZXZTdGF0dXMgPT09ICdPTEQnKSB7XHJcbiAgICAgIHF1ZXJ5LndoZXJlKCdyZXYuaXNDdXJyZW50ID0gOmlzQ3VycmVudCcsIHsgaXNDdXJyZW50OiBmYWxzZSB9KTtcclxuICAgIH1cclxuICAgIC8vIElmICdBTEwnLCBubyBmaWx0ZXIgbmVlZGVkIG9uIGlzQ3VycmVudFxyXG5cclxuICAgIGlmIChwcm9qZWN0SWQpIHtcclxuICAgICAgcXVlcnkuYW5kV2hlcmUoJ2NvcnIucHJvamVjdElkID0gOnByb2plY3RJZCcsIHsgcHJvamVjdElkIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0eXBlSWQpIHtcclxuICAgICAgcXVlcnkuYW5kV2hlcmUoJ2NvcnIuY29ycmVzcG9uZGVuY2VUeXBlSWQgPSA6dHlwZUlkJywgeyB0eXBlSWQgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHN0YXR1c0lkKSB7XHJcbiAgICAgIHF1ZXJ5LmFuZFdoZXJlKCdyZXYuc3RhdHVzSWQgPSA6c3RhdHVzSWQnLCB7IHN0YXR1c0lkIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChzdGF0dXMpIHtcclxuICAgICAgcXVlcnkuYW5kV2hlcmUoJ3N0YXR1cy5zdGF0dXNDb2RlID0gOnN0YXR1cycsIHsgc3RhdHVzIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChzZWFyY2gpIHtcclxuICAgICAgcXVlcnkuYW5kV2hlcmUoXHJcbiAgICAgICAgJyhjb3JyLmNvcnJlc3BvbmRlbmNlTnVtYmVyIExJS0UgOnNlYXJjaCBPUiByZXYuc3ViamVjdCBMSUtFIDpzZWFyY2gpJyxcclxuICAgICAgICB7IHNlYXJjaDogYCUke3NlYXJjaH0lYCB9XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVmYXVsdCBTb3J0OiBMYXRlc3QgQ3JlYXRlZFxyXG4gICAgcXVlcnkub3JkZXJCeSgncmV2LmNyZWF0ZWRBdCcsICdERVNDJykuc2tpcChza2lwKS50YWtlKGxpbWl0KTtcclxuXHJcbiAgICBjb25zdCBbaXRlbXMsIHRvdGFsXSA9IGF3YWl0IHF1ZXJ5LmdldE1hbnlBbmRDb3VudCgpO1xyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGRhdGE6IGl0ZW1zLFxyXG4gICAgICBtZXRhOiB7XHJcbiAgICAgICAgdG90YWwsXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICBsaW1pdCxcclxuICAgICAgICB0b3RhbFBhZ2VzOiBNYXRoLmNlaWwodG90YWwgLyBsaW1pdCksXHJcbiAgICAgIH0sXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgZmluZE9uZShpZDogbnVtYmVyKSB7XHJcbiAgICBjb25zdCBjb3JyZXNwb25kZW5jZSA9IGF3YWl0IHRoaXMuY29ycmVzcG9uZGVuY2VSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZTogeyBpZCB9LFxyXG4gICAgICByZWxhdGlvbnM6IFtcclxuICAgICAgICAncmV2aXNpb25zJyxcclxuICAgICAgICAncmV2aXNpb25zLnN0YXR1cycsXHJcbiAgICAgICAgJ3R5cGUnLFxyXG4gICAgICAgICdwcm9qZWN0JyxcclxuICAgICAgICAnb3JpZ2luYXRvcicsXHJcbiAgICAgICAgJ3JlY2lwaWVudHMnLFxyXG4gICAgICAgICdyZWNpcGllbnRzLnJlY2lwaWVudE9yZ2FuaXphdGlvbicsIC8vIFt2MS41LjFdIEZpeGVkIHJlbGF0aW9uIG5hbWVcclxuICAgICAgXSxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmICghY29ycmVzcG9uZGVuY2UpIHtcclxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXhjZXB0aW9uKGBDb3JyZXNwb25kZW5jZSB3aXRoIElEICR7aWR9IG5vdCBmb3VuZGApO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGNvcnJlc3BvbmRlbmNlO1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgZmluZE9uZUJ5VXVpZChwdWJsaWNJZDogc3RyaW5nKSB7XHJcbiAgICBjb25zdCBjb3JyZXNwb25kZW5jZSA9IGF3YWl0IHRoaXMuY29ycmVzcG9uZGVuY2VSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZTogeyBwdWJsaWNJZCB9LFxyXG4gICAgICByZWxhdGlvbnM6IFtcclxuICAgICAgICAncmV2aXNpb25zJyxcclxuICAgICAgICAncmV2aXNpb25zLnN0YXR1cycsXHJcbiAgICAgICAgJ3R5cGUnLFxyXG4gICAgICAgICdwcm9qZWN0JyxcclxuICAgICAgICAnb3JpZ2luYXRvcicsXHJcbiAgICAgICAgJ3JlY2lwaWVudHMnLFxyXG4gICAgICAgICdyZWNpcGllbnRzLnJlY2lwaWVudE9yZ2FuaXphdGlvbicsXHJcbiAgICAgIF0sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoIWNvcnJlc3BvbmRlbmNlKSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbihcclxuICAgICAgICBgQ29ycmVzcG9uZGVuY2Ugd2l0aCBVVUlEICR7cHVibGljSWR9IG5vdCBmb3VuZGBcclxuICAgICAgKTtcclxuICAgIH1cclxuICAgIHJldHVybiBjb3JyZXNwb25kZW5jZTtcclxuICB9XHJcblxyXG4gIGFzeW5jIGFkZFJlZmVyZW5jZShpZDogbnVtYmVyLCBkdG86IEFkZFJlZmVyZW5jZUR0bykge1xyXG4gICAgY29uc3Qgc291cmNlID0gYXdhaXQgdGhpcy5jb3JyZXNwb25kZW5jZVJlcG8uZmluZE9uZSh7IHdoZXJlOiB7IGlkIH0gfSk7XHJcbiAgICAvLyBBRFItMDE5OiBSZXNvbHZlIHRhcmdldCBwdWJsaWNJZCDihpIgaW50ZXJuYWwgSU5UIGlkXHJcbiAgICBjb25zdCB0YXJnZXQgPSBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgcHVibGljSWQ6IGR0by50YXJnZXRVdWlkIH0sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoIXNvdXJjZSB8fCAhdGFyZ2V0KSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbignU291cmNlIG9yIFRhcmdldCBjb3JyZXNwb25kZW5jZSBub3QgZm91bmQnKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoc291cmNlLmlkID09PSB0YXJnZXQuaWQpIHtcclxuICAgICAgdGhyb3cgbmV3IEJhZFJlcXVlc3RFeGNlcHRpb24oJ0Nhbm5vdCByZWZlcmVuY2Ugc2VsZicpO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGV4aXN0cyA9IGF3YWl0IHRoaXMucmVmZXJlbmNlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHtcclxuICAgICAgICBzb3VyY2VJZDogaWQsXHJcbiAgICAgICAgdGFyZ2V0SWQ6IHRhcmdldC5pZCxcclxuICAgICAgfSxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmIChleGlzdHMpIHtcclxuICAgICAgcmV0dXJuIGV4aXN0cztcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCByZWYgPSB0aGlzLnJlZmVyZW5jZVJlcG8uY3JlYXRlKHtcclxuICAgICAgc291cmNlSWQ6IGlkLFxyXG4gICAgICB0YXJnZXRJZDogdGFyZ2V0LmlkLFxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHRoaXMucmVmZXJlbmNlUmVwby5zYXZlKHJlZik7XHJcbiAgfVxyXG5cclxuICBhc3luYyByZW1vdmVSZWZlcmVuY2UoaWQ6IG51bWJlciwgdGFyZ2V0SWQ6IG51bWJlcikge1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5yZWZlcmVuY2VSZXBvLmRlbGV0ZSh7XHJcbiAgICAgIHNvdXJjZUlkOiBpZCxcclxuICAgICAgdGFyZ2V0SWQ6IHRhcmdldElkLFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKHJlc3VsdC5hZmZlY3RlZCA9PT0gMCkge1xyXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oJ1JlZmVyZW5jZSBub3QgZm91bmQnKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFzeW5jIGdldFRhZ3MoaWQ6IG51bWJlcikge1xyXG4gICAgY29uc3Qgcm93cyA9IGF3YWl0IHRoaXMudGFnUmVwby5maW5kKHtcclxuICAgICAgd2hlcmU6IHsgY29ycmVzcG9uZGVuY2VJZDogaWQgfSxcclxuICAgICAgcmVsYXRpb25zOiBbJ3RhZyddLFxyXG4gICAgfSk7XHJcbiAgICByZXR1cm4gcm93cy5tYXAoKHIpID0+IHIudGFnKS5maWx0ZXIoQm9vbGVhbik7XHJcbiAgfVxyXG5cclxuICBhc3luYyBhZGRUYWcoaWQ6IG51bWJlciwgdGFnSWQ6IG51bWJlcikge1xyXG4gICAgY29uc3QgY29ycmVzcG9uZGVuY2UgPSBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgaWQgfSxcclxuICAgIH0pO1xyXG4gICAgaWYgKCFjb3JyZXNwb25kZW5jZSkge1xyXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oYENvcnJlc3BvbmRlbmNlICR7aWR9IG5vdCBmb3VuZGApO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHRhZyA9IGF3YWl0IHRoaXMuZGF0YVNvdXJjZS5tYW5hZ2VyLmZpbmRPbmUoVGFnLCB7XHJcbiAgICAgIHdoZXJlOiB7IGlkOiB0YWdJZCB9LFxyXG4gICAgfSk7XHJcbiAgICBpZiAoIXRhZykge1xyXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oYFRhZyAke3RhZ0lkfSBub3QgZm91bmRgKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBleGlzdHMgPSBhd2FpdCB0aGlzLnRhZ1JlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IGNvcnJlc3BvbmRlbmNlSWQ6IGlkLCB0YWdJZCB9LFxyXG4gICAgfSk7XHJcbiAgICBpZiAoZXhpc3RzKSByZXR1cm4gZXhpc3RzO1xyXG5cclxuICAgIGNvbnN0IHJvdyA9IHRoaXMudGFnUmVwby5jcmVhdGUoeyBjb3JyZXNwb25kZW5jZUlkOiBpZCwgdGFnSWQgfSk7XHJcbiAgICByZXR1cm4gdGhpcy50YWdSZXBvLnNhdmUocm93KTtcclxuICB9XHJcblxyXG4gIGFzeW5jIHJlbW92ZVRhZyhpZDogbnVtYmVyLCB0YWdJZDogbnVtYmVyKSB7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnRhZ1JlcG8uZGVsZXRlKHsgY29ycmVzcG9uZGVuY2VJZDogaWQsIHRhZ0lkIH0pO1xyXG4gICAgaWYgKHJlc3VsdC5hZmZlY3RlZCA9PT0gMCkge1xyXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oJ1RhZyBhc3NpZ25tZW50IG5vdCBmb3VuZCcpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgYXN5bmMgZ2V0UmVmZXJlbmNlcyhpZDogbnVtYmVyKSB7XHJcbiAgICBjb25zdCBvdXRnb2luZyA9IGF3YWl0IHRoaXMucmVmZXJlbmNlUmVwby5maW5kKHtcclxuICAgICAgd2hlcmU6IHsgc291cmNlSWQ6IGlkIH0sXHJcbiAgICAgIHJlbGF0aW9uczogWyd0YXJnZXQnLCAndGFyZ2V0LnR5cGUnXSxcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluY29taW5nID0gYXdhaXQgdGhpcy5yZWZlcmVuY2VSZXBvLmZpbmQoe1xyXG4gICAgICB3aGVyZTogeyB0YXJnZXRJZDogaWQgfSxcclxuICAgICAgcmVsYXRpb25zOiBbJ3NvdXJjZScsICdzb3VyY2UudHlwZSddLFxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHsgb3V0Z29pbmcsIGluY29taW5nIH07XHJcbiAgfVxyXG5cclxuICBhc3luYyB1cGRhdGUoaWQ6IG51bWJlciwgdXBkYXRlRHRvOiBVcGRhdGVDb3JyZXNwb25kZW5jZUR0bywgdXNlcjogVXNlcikge1xyXG4gICAgLy8gMS4gRmluZCBDdXJyZW50IFJldmlzaW9uXHJcbiAgICBjb25zdCByZXZpc2lvbiA9IGF3YWl0IHRoaXMucmV2aXNpb25SZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZToge1xyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IGlkLFxyXG4gICAgICAgIGlzQ3VycmVudDogdHJ1ZSxcclxuICAgICAgfSxcclxuICAgICAgcmVsYXRpb25zOiBbJ2NvcnJlc3BvbmRlbmNlJ10sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoIXJldmlzaW9uKSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbihcclxuICAgICAgICBgQ3VycmVudCByZXZpc2lvbiBmb3IgY29ycmVzcG9uZGVuY2UgJHtpZH0gbm90IGZvdW5kYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIDIuIENoZWNrIFBlcm1pc3Npb25cclxuICAgIGlmIChyZXZpc2lvbi5zdGF0dXNJZCkge1xyXG4gICAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCB0aGlzLnN0YXR1c1JlcG8uZmluZE9uZSh7XHJcbiAgICAgICAgd2hlcmU6IHsgaWQ6IHJldmlzaW9uLnN0YXR1c0lkIH0sXHJcbiAgICAgIH0pO1xyXG4gICAgICBpZiAoc3RhdHVzICYmIHN0YXR1cy5zdGF0dXNDb2RlICE9PSAnRFJBRlQnKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEJhZFJlcXVlc3RFeGNlcHRpb24oJ09ubHkgRFJBRlQgZG9jdW1lbnRzIGNhbiBiZSB1cGRhdGVkJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBBRFItMDE5OiBSZXNvbHZlIFVVSUQgcmVmZXJlbmNlcyBpbiB1cGRhdGUgRFRPXHJcbiAgICBjb25zdCB1cGRSZXNvbHZlZFByb2plY3RJZCA9IHVwZGF0ZUR0by5wcm9qZWN0SWRcclxuICAgICAgPyBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlUHJvamVjdElkKHVwZGF0ZUR0by5wcm9qZWN0SWQpXHJcbiAgICAgIDogdW5kZWZpbmVkO1xyXG4gICAgY29uc3QgdXBkUmVzb2x2ZWRPcmlnaW5hdG9ySWQgPSB1cGRhdGVEdG8ub3JpZ2luYXRvcklkXHJcbiAgICAgID8gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKHVwZGF0ZUR0by5vcmlnaW5hdG9ySWQpXHJcbiAgICAgIDogdW5kZWZpbmVkO1xyXG4gICAgY29uc3QgdXBkUmVzb2x2ZWRSZWNpcGllbnRzID0gdXBkYXRlRHRvLnJlY2lwaWVudHNcclxuICAgICAgPyBhd2FpdCBQcm9taXNlLmFsbChcclxuICAgICAgICAgIHVwZGF0ZUR0by5yZWNpcGllbnRzLm1hcChcclxuICAgICAgICAgICAgYXN5bmMgKHIpOiBQcm9taXNlPFJlc29sdmVkUmVjaXBpZW50PiA9PiAoe1xyXG4gICAgICAgICAgICAgIG9yZ2FuaXphdGlvbklkOiBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlT3JnYW5pemF0aW9uSWQoXHJcbiAgICAgICAgICAgICAgICByLm9yZ2FuaXphdGlvbklkXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgICB0eXBlOiByLnR5cGUsXHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgKVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuXHJcbiAgICAvLyAzLiBVcGRhdGUgQ29ycmVzcG9uZGVuY2UgRW50aXR5IGlmIG5lZWRlZFxyXG4gICAgY29uc3QgY29ycmVzcG9uZGVuY2VVcGRhdGU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XHJcbiAgICBpZiAodXBkYXRlRHRvLmRpc2NpcGxpbmVJZClcclxuICAgICAgY29ycmVzcG9uZGVuY2VVcGRhdGUuZGlzY2lwbGluZUlkID0gdXBkYXRlRHRvLmRpc2NpcGxpbmVJZDtcclxuICAgIGlmICh1cGRSZXNvbHZlZFByb2plY3RJZClcclxuICAgICAgY29ycmVzcG9uZGVuY2VVcGRhdGUucHJvamVjdElkID0gdXBkUmVzb2x2ZWRQcm9qZWN0SWQ7XHJcbiAgICBpZiAodXBkUmVzb2x2ZWRPcmlnaW5hdG9ySWQpXHJcbiAgICAgIGNvcnJlc3BvbmRlbmNlVXBkYXRlLm9yaWdpbmF0b3JJZCA9IHVwZFJlc29sdmVkT3JpZ2luYXRvcklkO1xyXG5cclxuICAgIGlmIChPYmplY3Qua2V5cyhjb3JyZXNwb25kZW5jZVVwZGF0ZSkubGVuZ3RoID4gMCkge1xyXG4gICAgICBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby51cGRhdGUoaWQsIGNvcnJlc3BvbmRlbmNlVXBkYXRlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyA0LiBVcGRhdGUgUmV2aXNpb24gRW50aXR5XHJcbiAgICBjb25zdCByZXZpc2lvblVwZGF0ZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcclxuICAgIGlmICh1cGRhdGVEdG8uc3ViamVjdCkgcmV2aXNpb25VcGRhdGUuc3ViamVjdCA9IHVwZGF0ZUR0by5zdWJqZWN0O1xyXG4gICAgaWYgKHVwZGF0ZUR0by5ib2R5KSByZXZpc2lvblVwZGF0ZS5ib2R5ID0gdXBkYXRlRHRvLmJvZHk7XHJcbiAgICBpZiAodXBkYXRlRHRvLnJlbWFya3MpIHJldmlzaW9uVXBkYXRlLnJlbWFya3MgPSB1cGRhdGVEdG8ucmVtYXJrcztcclxuICAgIC8vIEZvcm1hdCBEYXRlIGNvcnJlY3RseSBpZiBzdHJpbmdcclxuICAgIGlmICh1cGRhdGVEdG8uZHVlRGF0ZSkgcmV2aXNpb25VcGRhdGUuZHVlRGF0ZSA9IG5ldyBEYXRlKHVwZGF0ZUR0by5kdWVEYXRlKTtcclxuICAgIGlmICh1cGRhdGVEdG8uZG9jdW1lbnREYXRlKVxyXG4gICAgICByZXZpc2lvblVwZGF0ZS5kb2N1bWVudERhdGUgPSBuZXcgRGF0ZSh1cGRhdGVEdG8uZG9jdW1lbnREYXRlKTtcclxuICAgIGlmICh1cGRhdGVEdG8uaXNzdWVkRGF0ZSlcclxuICAgICAgcmV2aXNpb25VcGRhdGUuaXNzdWVkRGF0ZSA9IG5ldyBEYXRlKHVwZGF0ZUR0by5pc3N1ZWREYXRlKTtcclxuICAgIGlmICh1cGRhdGVEdG8ucmVjZWl2ZWREYXRlKVxyXG4gICAgICByZXZpc2lvblVwZGF0ZS5yZWNlaXZlZERhdGUgPSBuZXcgRGF0ZSh1cGRhdGVEdG8ucmVjZWl2ZWREYXRlKTtcclxuICAgIGlmICh1cGRhdGVEdG8uZGVzY3JpcHRpb24pXHJcbiAgICAgIHJldmlzaW9uVXBkYXRlLmRlc2NyaXB0aW9uID0gdXBkYXRlRHRvLmRlc2NyaXB0aW9uO1xyXG4gICAgaWYgKHVwZGF0ZUR0by5kZXRhaWxzKSByZXZpc2lvblVwZGF0ZS5kZXRhaWxzID0gdXBkYXRlRHRvLmRldGFpbHM7XHJcblxyXG4gICAgaWYgKE9iamVjdC5rZXlzKHJldmlzaW9uVXBkYXRlKS5sZW5ndGggPiAwKSB7XHJcbiAgICAgIGF3YWl0IHRoaXMucmV2aXNpb25SZXBvLnVwZGF0ZShyZXZpc2lvbi5pZCwgcmV2aXNpb25VcGRhdGUpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIDQuNSBDb21taXQgbmV3IGF0dGFjaG1lbnRzIGZyb20gVGVtcCDihpIgUGVybWFuZW50IChUd28tUGhhc2UgU3RvcmFnZSlcclxuICAgIGlmICh1cGRhdGVEdG8uYXR0YWNobWVudFRlbXBJZHM/Lmxlbmd0aCkge1xyXG4gICAgICBjb25zdCBpc3N1ZURhdGUgPSB1cGRhdGVEdG8uaXNzdWVkRGF0ZVxyXG4gICAgICAgID8gbmV3IERhdGUodXBkYXRlRHRvLmlzc3VlZERhdGUpXHJcbiAgICAgICAgOiB1cGRhdGVEdG8uZG9jdW1lbnREYXRlXHJcbiAgICAgICAgICA/IG5ldyBEYXRlKHVwZGF0ZUR0by5kb2N1bWVudERhdGUpXHJcbiAgICAgICAgICA6IHJldmlzaW9uLmlzc3VlZERhdGUgfHwgcmV2aXNpb24uZG9jdW1lbnREYXRlIHx8IHVuZGVmaW5lZDtcclxuXHJcbiAgICAgIGF3YWl0IHRoaXMuZmlsZVN0b3JhZ2VTZXJ2aWNlLmNvbW1pdCh1cGRhdGVEdG8uYXR0YWNobWVudFRlbXBJZHMsIHtcclxuICAgICAgICBpc3N1ZURhdGU6IGlzc3VlRGF0ZSA/IG5ldyBEYXRlKGlzc3VlRGF0ZSkgOiB1bmRlZmluZWQsXHJcbiAgICAgICAgZG9jdW1lbnRUeXBlOiAnQ29ycmVzcG9uZGVuY2UnLFxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyA1LiBVcGRhdGUgUmVjaXBpZW50cyBpZiBwcm92aWRlZFxyXG4gICAgaWYgKHVwZFJlc29sdmVkUmVjaXBpZW50cykge1xyXG4gICAgICBjb25zdCByZWNpcGllbnRSZXBvID0gdGhpcy5kYXRhU291cmNlLmdldFJlcG9zaXRvcnkoXHJcbiAgICAgICAgQ29ycmVzcG9uZGVuY2VSZWNpcGllbnRcclxuICAgICAgKTtcclxuICAgICAgYXdhaXQgcmVjaXBpZW50UmVwby5kZWxldGUoeyBjb3JyZXNwb25kZW5jZUlkOiBpZCB9KTtcclxuXHJcbiAgICAgIGNvbnN0IG5ld1JlY2lwaWVudHMgPSB1cGRSZXNvbHZlZFJlY2lwaWVudHMubWFwKChyKSA9PlxyXG4gICAgICAgIHJlY2lwaWVudFJlcG8uY3JlYXRlKHtcclxuICAgICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IGlkLFxyXG4gICAgICAgICAgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQ6IHIub3JnYW5pemF0aW9uSWQsXHJcbiAgICAgICAgICByZWNpcGllbnRUeXBlOiByLnR5cGUsXHJcbiAgICAgICAgfSlcclxuICAgICAgKTtcclxuICAgICAgYXdhaXQgcmVjaXBpZW50UmVwby5zYXZlKG5ld1JlY2lwaWVudHMpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIDYuIFJlZ2VuZXJhdGUgRG9jdW1lbnQgTnVtYmVyIGlmIHN0cnVjdHVyYWwgZmllbGRzIGNoYW5nZWQgKFJlY2lwaWVudCwgRGlzY2lwbGluZSwgVHlwZSwgUHJvamVjdClcclxuICAgIC8vIEFORCBpdCBpcyBhIERSQUZULlxyXG5cclxuICAgIC8vIEZldGNoIGZyZXNoIGRhdGEgZm9yIGNvbnRleHQgYW5kIGNvbXBhcmlzb25cclxuICAgIGNvbnN0IGN1cnJlbnRDb3JyID0gYXdhaXQgdGhpcy5jb3JyZXNwb25kZW5jZVJlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IGlkIH0sXHJcbiAgICAgIHJlbGF0aW9uczogWyd0eXBlJywgJ3JlY2lwaWVudHMnLCAncmVjaXBpZW50cy5yZWNpcGllbnRPcmdhbml6YXRpb24nXSxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmIChjdXJyZW50Q29ycikge1xyXG4gICAgICBjb25zdCBjdXJyZW50VG9SZWNpcGllbnQgPSBjdXJyZW50Q29yci5yZWNpcGllbnRzPy5maW5kKFxyXG4gICAgICAgIChyKSA9PiByLnJlY2lwaWVudFR5cGUgPT09ICdUTydcclxuICAgICAgKTtcclxuICAgICAgY29uc3QgY3VycmVudFJlY2lwaWVudElkID0gY3VycmVudFRvUmVjaXBpZW50Py5yZWNpcGllbnRPcmdhbml6YXRpb25JZDtcclxuXHJcbiAgICAgIC8vIENoZWNrIGZvciBBQ1RVQUwgdmFsdWUgY2hhbmdlc1xyXG4gICAgICBjb25zdCBpc1Byb2plY3RDaGFuZ2VkID1cclxuICAgICAgICB1cGRSZXNvbHZlZFByb2plY3RJZCAhPT0gdW5kZWZpbmVkICYmXHJcbiAgICAgICAgdXBkUmVzb2x2ZWRQcm9qZWN0SWQgIT09IGN1cnJlbnRDb3JyLnByb2plY3RJZDtcclxuICAgICAgY29uc3QgaXNPcmlnaW5hdG9yQ2hhbmdlZCA9XHJcbiAgICAgICAgdXBkUmVzb2x2ZWRPcmlnaW5hdG9ySWQgIT09IHVuZGVmaW5lZCAmJlxyXG4gICAgICAgIHVwZFJlc29sdmVkT3JpZ2luYXRvcklkICE9PSBjdXJyZW50Q29yci5vcmlnaW5hdG9ySWQ7XHJcbiAgICAgIGNvbnN0IGlzRGlzY2lwbGluZUNoYW5nZWQgPVxyXG4gICAgICAgIHVwZGF0ZUR0by5kaXNjaXBsaW5lSWQgIT09IHVuZGVmaW5lZCAmJlxyXG4gICAgICAgIHVwZGF0ZUR0by5kaXNjaXBsaW5lSWQgIT09IGN1cnJlbnRDb3JyLmRpc2NpcGxpbmVJZDtcclxuICAgICAgY29uc3QgaXNUeXBlQ2hhbmdlZCA9XHJcbiAgICAgICAgdXBkYXRlRHRvLnR5cGVJZCAhPT0gdW5kZWZpbmVkICYmXHJcbiAgICAgICAgdXBkYXRlRHRvLnR5cGVJZCAhPT0gY3VycmVudENvcnIuY29ycmVzcG9uZGVuY2VUeXBlSWQ7XHJcblxyXG4gICAgICBsZXQgaXNSZWNpcGllbnRDaGFuZ2VkID0gZmFsc2U7XHJcbiAgICAgIGxldCBuZXdSZWNpcGllbnRJZDogbnVtYmVyIHwgdW5kZWZpbmVkO1xyXG5cclxuICAgICAgaWYgKHVwZFJlc29sdmVkUmVjaXBpZW50cykge1xyXG4gICAgICAgIGNvbnN0IG5ld1RvUmVjaXBpZW50ID0gdXBkUmVzb2x2ZWRSZWNpcGllbnRzLmZpbmQoXHJcbiAgICAgICAgICAocikgPT4gci50eXBlID09PSAnVE8nXHJcbiAgICAgICAgKTtcclxuICAgICAgICBuZXdSZWNpcGllbnRJZCA9IG5ld1RvUmVjaXBpZW50Py5vcmdhbml6YXRpb25JZDtcclxuXHJcbiAgICAgICAgaWYgKG5ld1JlY2lwaWVudElkICE9PSBjdXJyZW50UmVjaXBpZW50SWQpIHtcclxuICAgICAgICAgIGlzUmVjaXBpZW50Q2hhbmdlZCA9IHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgaXNQcm9qZWN0Q2hhbmdlZCB8fFxyXG4gICAgICAgIGlzRGlzY2lwbGluZUNoYW5nZWQgfHxcclxuICAgICAgICBpc1R5cGVDaGFuZ2VkIHx8XHJcbiAgICAgICAgaXNSZWNpcGllbnRDaGFuZ2VkIHx8XHJcbiAgICAgICAgaXNPcmlnaW5hdG9yQ2hhbmdlZFxyXG4gICAgICApIHtcclxuICAgICAgICBjb25zdCB0YXJnZXRSZWNpcGllbnRJZCA9IGlzUmVjaXBpZW50Q2hhbmdlZFxyXG4gICAgICAgICAgPyBuZXdSZWNpcGllbnRJZFxyXG4gICAgICAgICAgOiBjdXJyZW50UmVjaXBpZW50SWQ7XHJcblxyXG4gICAgICAgIC8vIFJlc29sdmUgUmVjaXBpZW50IENvZGUgZm9yIHRoZSBORVcgY29udGV4dFxyXG4gICAgICAgIGxldCByZWNpcGllbnRDb2RlID0gJyc7XHJcbiAgICAgICAgaWYgKHRhcmdldFJlY2lwaWVudElkKSB7XHJcbiAgICAgICAgICBjb25zdCByZWNPcmcgPSBhd2FpdCB0aGlzLmRhdGFTb3VyY2UubWFuYWdlci5maW5kT25lKE9yZ2FuaXphdGlvbiwge1xyXG4gICAgICAgICAgICB3aGVyZTogeyBpZDogdGFyZ2V0UmVjaXBpZW50SWQgfSxcclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgaWYgKHJlY09yZykgcmVjaXBpZW50Q29kZSA9IHJlY09yZy5vcmdhbml6YXRpb25Db2RlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gW0ZpeCAjNl0gRmV0Y2ggcmVhbCBPUkcgQ29kZSBmcm9tIG9yaWdpbmF0b3Igb3JnYW5pemF0aW9uXHJcbiAgICAgICAgY29uc3Qgb3JpZ2luYXRvck9yZ0ZvclVwZGF0ZSA9IGF3YWl0IHRoaXMuZGF0YVNvdXJjZS5tYW5hZ2VyLmZpbmRPbmUoXHJcbiAgICAgICAgICBPcmdhbml6YXRpb24sXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIHdoZXJlOiB7XHJcbiAgICAgICAgICAgICAgaWQ6IHVwZFJlc29sdmVkT3JpZ2luYXRvcklkID8/IGN1cnJlbnRDb3JyLm9yaWdpbmF0b3JJZCA/PyAwLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgfVxyXG4gICAgICAgICk7XHJcbiAgICAgICAgY29uc3Qgb3JnQ29kZSA9IG9yaWdpbmF0b3JPcmdGb3JVcGRhdGU/Lm9yZ2FuaXphdGlvbkNvZGUgPz8gJ1VOSyc7XHJcblxyXG4gICAgICAgIC8vIFByZXBhcmUgQ29udGV4dHNcclxuICAgICAgICBjb25zdCBvbGRDdHggPSB7XHJcbiAgICAgICAgICBwcm9qZWN0SWQ6IGN1cnJlbnRDb3JyLnByb2plY3RJZCxcclxuICAgICAgICAgIG9yaWdpbmF0b3JPcmdhbml6YXRpb25JZDogY3VycmVudENvcnIub3JpZ2luYXRvcklkID8/IDAsXHJcbiAgICAgICAgICB0eXBlSWQ6IGN1cnJlbnRDb3JyLmNvcnJlc3BvbmRlbmNlVHlwZUlkLFxyXG4gICAgICAgICAgZGlzY2lwbGluZUlkOiBjdXJyZW50Q29yci5kaXNjaXBsaW5lSWQsXHJcbiAgICAgICAgICByZWNpcGllbnRPcmdhbml6YXRpb25JZDogY3VycmVudFJlY2lwaWVudElkLFxyXG4gICAgICAgICAgeWVhcjogbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpLFxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIGNvbnN0IG5ld0N0eCA9IHtcclxuICAgICAgICAgIHByb2plY3RJZDogdXBkUmVzb2x2ZWRQcm9qZWN0SWQgPz8gY3VycmVudENvcnIucHJvamVjdElkLFxyXG4gICAgICAgICAgb3JpZ2luYXRvck9yZ2FuaXphdGlvbklkOlxyXG4gICAgICAgICAgICB1cGRSZXNvbHZlZE9yaWdpbmF0b3JJZCA/PyBjdXJyZW50Q29yci5vcmlnaW5hdG9ySWQgPz8gMCxcclxuICAgICAgICAgIHR5cGVJZDogdXBkYXRlRHRvLnR5cGVJZCA/PyBjdXJyZW50Q29yci5jb3JyZXNwb25kZW5jZVR5cGVJZCxcclxuICAgICAgICAgIGRpc2NpcGxpbmVJZDogdXBkYXRlRHRvLmRpc2NpcGxpbmVJZCA/PyBjdXJyZW50Q29yci5kaXNjaXBsaW5lSWQsXHJcbiAgICAgICAgICByZWNpcGllbnRPcmdhbml6YXRpb25JZDogdGFyZ2V0UmVjaXBpZW50SWQsXHJcbiAgICAgICAgICB5ZWFyOiBuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCksXHJcbiAgICAgICAgICB1c2VySWQ6IHVzZXIudXNlcl9pZCwgLy8gUGFzcyBVc2VyIElEIGZvciBBdWRpdFxyXG4gICAgICAgICAgY3VzdG9tVG9rZW5zOiB7XHJcbiAgICAgICAgICAgIFRZUEVfQ09ERTogY3VycmVudENvcnIudHlwZT8udHlwZUNvZGUgfHwgJycsXHJcbiAgICAgICAgICAgIE9SR19DT0RFOiBvcmdDb2RlLFxyXG4gICAgICAgICAgICBSRUNJUElFTlRfQ09ERTogcmVjaXBpZW50Q29kZSxcclxuICAgICAgICAgICAgUkVDX0NPREU6IHJlY2lwaWVudENvZGUsXHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIC8vIElmIFR5cGUgQ2hhbmdlZCwgbmVlZCBORVcgVHlwZSBDb2RlXHJcbiAgICAgICAgaWYgKGlzVHlwZUNoYW5nZWQpIHtcclxuICAgICAgICAgIGNvbnN0IG5ld1R5cGUgPSBhd2FpdCB0aGlzLnR5cGVSZXBvLmZpbmRPbmUoe1xyXG4gICAgICAgICAgICB3aGVyZTogeyBpZDogbmV3Q3R4LnR5cGVJZCB9LFxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgICBpZiAobmV3VHlwZSkgbmV3Q3R4LmN1c3RvbVRva2Vucy5UWVBFX0NPREUgPSBuZXdUeXBlLnR5cGVDb2RlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uc3QgbmV3RG9jTnVtYmVyID0gYXdhaXQgdGhpcy5udW1iZXJpbmdTZXJ2aWNlLnVwZGF0ZU51bWJlckZvckRyYWZ0KFxyXG4gICAgICAgICAgY3VycmVudENvcnIuY29ycmVzcG9uZGVuY2VOdW1iZXIsXHJcbiAgICAgICAgICBvbGRDdHgsXHJcbiAgICAgICAgICBuZXdDdHhcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby51cGRhdGUoaWQsIHtcclxuICAgICAgICAgIGNvcnJlc3BvbmRlbmNlTnVtYmVyOiBuZXdEb2NOdW1iZXIsXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB1cGRhdGVkID0gYXdhaXQgdGhpcy5maW5kT25lKGlkKTtcclxuXHJcbiAgICAvLyBSZS1pbmRleCB1cGRhdGVkIGRvY3VtZW50IGluIEVsYXN0aWNzZWFyY2ggKGZpcmUtYW5kLWZvcmdldClcclxuICAgIHZvaWQgdGhpcy5zZWFyY2hTZXJ2aWNlLmluZGV4RG9jdW1lbnQoe1xyXG4gICAgICBpZDogdXBkYXRlZC5pZCxcclxuICAgICAgcHVibGljSWQ6IHVwZGF0ZWQucHVibGljSWQsXHJcbiAgICAgIHR5cGU6ICdjb3JyZXNwb25kZW5jZScsXHJcbiAgICAgIGRvY051bWJlcjogdXBkYXRlZC5jb3JyZXNwb25kZW5jZU51bWJlcixcclxuICAgICAgdGl0bGU6IHVwZGF0ZUR0by5zdWJqZWN0ID8/IHVwZGF0ZWQucmV2aXNpb25zPy5bMF0/LnN1YmplY3QsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiB1cGRhdGVEdG8uZGVzY3JpcHRpb24gPz8gdXBkYXRlZC5yZXZpc2lvbnM/LlswXT8uZGVzY3JpcHRpb24sXHJcbiAgICAgIHN0YXR1czogJ0RSQUZUJyxcclxuICAgICAgcHJvamVjdElkOiB1cGRhdGVkLnByb2plY3RJZCxcclxuICAgICAgY3JlYXRlZEF0OiB1cGRhdGVkLmNyZWF0ZWRBdCxcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB1cGRhdGVkO1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgcHJldmlld0RvY3VtZW50TnVtYmVyKGNyZWF0ZUR0bzogQ3JlYXRlQ29ycmVzcG9uZGVuY2VEdG8sIHVzZXI6IFVzZXIpIHtcclxuICAgIC8vIEFEUi0wMTk6IFJlc29sdmUgVVVJRCByZWZlcmVuY2VzXHJcbiAgICBjb25zdCBwcmV2aWV3UHJvamVjdElkID0gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZVByb2plY3RJZChcclxuICAgICAgY3JlYXRlRHRvLnByb2plY3RJZFxyXG4gICAgKTtcclxuICAgIGNvbnN0IHByZXZpZXdPcmlnaW5hdG9ySWQgPSBjcmVhdGVEdG8ub3JpZ2luYXRvcklkXHJcbiAgICAgID8gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKGNyZWF0ZUR0by5vcmlnaW5hdG9ySWQpXHJcbiAgICAgIDogdW5kZWZpbmVkO1xyXG4gICAgY29uc3QgcHJldmlld1JlY2lwaWVudHMgPSBjcmVhdGVEdG8ucmVjaXBpZW50c1xyXG4gICAgICA/IGF3YWl0IFByb21pc2UuYWxsKFxyXG4gICAgICAgICAgY3JlYXRlRHRvLnJlY2lwaWVudHMubWFwKFxyXG4gICAgICAgICAgICBhc3luYyAocik6IFByb21pc2U8UmVzb2x2ZWRSZWNpcGllbnQ+ID0+ICh7XHJcbiAgICAgICAgICAgICAgb3JnYW5pemF0aW9uSWQ6IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZChcclxuICAgICAgICAgICAgICAgIHIub3JnYW5pemF0aW9uSWRcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICAgIHR5cGU6IHIudHlwZSxcclxuICAgICAgICAgICAgfSlcclxuICAgICAgICAgIClcclxuICAgICAgICApXHJcbiAgICAgIDogdW5kZWZpbmVkO1xyXG5cclxuICAgIGNvbnN0IHR5cGUgPSBhd2FpdCB0aGlzLnR5cGVSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZTogeyBpZDogY3JlYXRlRHRvLnR5cGVJZCB9LFxyXG4gICAgfSk7XHJcbiAgICBpZiAoIXR5cGUpIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbignRG9jdW1lbnQgVHlwZSBub3QgZm91bmQnKTtcclxuXHJcbiAgICBsZXQgdXNlck9yZ0lkID0gdXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcbiAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICBjb25zdCBmdWxsVXNlciA9IGF3YWl0IHRoaXMudXNlclNlcnZpY2UuZmluZE9uZSh1c2VyLnVzZXJfaWQpO1xyXG4gICAgICBpZiAoZnVsbFVzZXIpIHVzZXJPcmdJZCA9IGZ1bGxVc2VyLnByaW1hcnlPcmdhbml6YXRpb25JZDtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocHJldmlld09yaWdpbmF0b3JJZCAmJiBwcmV2aWV3T3JpZ2luYXRvcklkICE9PSB1c2VyT3JnSWQpIHtcclxuICAgICAgLy8gQWxsb3cgaW1wZXJzb25hdGlvbiBmb3IgcHJldmlld1xyXG4gICAgICB1c2VyT3JnSWQgPSBwcmV2aWV3T3JpZ2luYXRvcklkO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEV4dHJhY3QgcmVjaXBpZW50IGZyb20gcmVjaXBpZW50cyBhcnJheVxyXG4gICAgY29uc3QgdG9SZWNpcGllbnQgPSBwcmV2aWV3UmVjaXBpZW50cz8uZmluZCgocikgPT4gci50eXBlID09PSAnVE8nKTtcclxuICAgIGNvbnN0IHJlY2lwaWVudE9yZ2FuaXphdGlvbklkID0gdG9SZWNpcGllbnQ/Lm9yZ2FuaXphdGlvbklkO1xyXG5cclxuICAgIGxldCByZWNpcGllbnRDb2RlID0gJyc7XHJcbiAgICBpZiAocmVjaXBpZW50T3JnYW5pemF0aW9uSWQpIHtcclxuICAgICAgY29uc3QgcmVjT3JnID0gYXdhaXQgdGhpcy5kYXRhU291cmNlLm1hbmFnZXIuZmluZE9uZShPcmdhbml6YXRpb24sIHtcclxuICAgICAgICB3aGVyZTogeyBpZDogcmVjaXBpZW50T3JnYW5pemF0aW9uSWQgfSxcclxuICAgICAgfSk7XHJcbiAgICAgIGlmIChyZWNPcmcpIHJlY2lwaWVudENvZGUgPSByZWNPcmcub3JnYW5pemF0aW9uQ29kZTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdGhpcy5udW1iZXJpbmdTZXJ2aWNlLnByZXZpZXdOdW1iZXIoe1xyXG4gICAgICBwcm9qZWN0SWQ6IHByZXZpZXdQcm9qZWN0SWQsXHJcbiAgICAgIG9yaWdpbmF0b3JPcmdhbml6YXRpb25JZDogdXNlck9yZ0lkISxcclxuICAgICAgdHlwZUlkOiBjcmVhdGVEdG8udHlwZUlkLFxyXG4gICAgICBkaXNjaXBsaW5lSWQ6IGNyZWF0ZUR0by5kaXNjaXBsaW5lSWQsXHJcbiAgICAgIHN1YlR5cGVJZDogY3JlYXRlRHRvLnN1YlR5cGVJZCxcclxuICAgICAgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQsXHJcbiAgICAgIHllYXI6IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKSxcclxuICAgICAgY3VzdG9tVG9rZW5zOiB7XHJcbiAgICAgICAgVFlQRV9DT0RFOiB0eXBlLnR5cGVDb2RlLFxyXG4gICAgICAgIFJFQ0lQSUVOVF9DT0RFOiByZWNpcGllbnRDb2RlLFxyXG4gICAgICAgIFJFQ19DT0RFOiByZWNpcGllbnRDb2RlLFxyXG4gICAgICB9LFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBCdXNpbmVzcyBSdWxlIEltcGxlbWVudGF0aW9uOiBFQy1DT1JSLTAwMSAtIENhbmNlbCBDb3JyZXNwb25kZW5jZSB3aXRoIERvd25zdHJlYW0gQ2lyY3VsYXRpb25cclxuICAgKiBDYW5jZWwgY29ycmVzcG9uZGVuY2UgYW5kIGhhbmRsZSByZWxhdGVkIGNpcmN1bGF0aW9uc1xyXG4gICAqL1xyXG4gIGFzeW5jIGNhbmNlbChwdWJsaWNJZDogc3RyaW5nLCByZWFzb246IHN0cmluZywgdXNlcjogVXNlcikge1xyXG4gICAgY29uc3QgY29ycmVzcG9uZGVuY2UgPSBhd2FpdCB0aGlzLmZpbmRPbmVCeVV1aWQocHVibGljSWQpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHVzZXIgaGFzIHBlcm1pc3Npb24gdG8gY2FuY2VsIChPcmcgQWRtaW4gb3IgU3VwZXJhZG1pbiBvbmx5KVxyXG4gICAgY29uc3QgcGVybWlzc2lvbnMgPSBhd2FpdCB0aGlzLnVzZXJTZXJ2aWNlLmdldFVzZXJQZXJtaXNzaW9ucyh1c2VyLnVzZXJfaWQpO1xyXG4gICAgY29uc3QgY2FuQ2FuY2VsID1cclxuICAgICAgcGVybWlzc2lvbnMuaW5jbHVkZXMoJ2NvcnJlc3BvbmRlbmNlLmNhbmNlbCcpIHx8XHJcbiAgICAgIHBlcm1pc3Npb25zLmluY2x1ZGVzKCdzeXN0ZW0ubWFuYWdlX2FsbCcpO1xyXG5cclxuICAgIGlmICghY2FuQ2FuY2VsKSB7XHJcbiAgICAgIHRocm93IG5ldyBGb3JiaWRkZW5FeGNlcHRpb24oXHJcbiAgICAgICAgJ09ubHkgYWRtaW5pc3RyYXRvcnMgY2FuIGNhbmNlbCBjb3JyZXNwb25kZW5jZXMnXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIGFueSBhY3RpdmUgY2lyY3VsYXRpb25zXHJcbiAgICBjb25zdCBjaXJjdWxhdGlvblJlcG8gPSB0aGlzLmRhdGFTb3VyY2UuZ2V0UmVwb3NpdG9yeSgnQ2lyY3VsYXRpb24nKTtcclxuICAgIGNvbnN0IGFjdGl2ZUNpcmN1bGF0aW9ucyA9IGF3YWl0IGNpcmN1bGF0aW9uUmVwby5maW5kKHtcclxuICAgICAgd2hlcmU6IHtcclxuICAgICAgICBjb3JyZXNwb25kZW5jZUlkOiBjb3JyZXNwb25kZW5jZS5pZCxcclxuICAgICAgICBzdGF0dXM6ICdPUEVOJyxcclxuICAgICAgfSxcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IHdhcm5pbmdNZXNzYWdlID1cclxuICAgICAgYWN0aXZlQ2lyY3VsYXRpb25zLmxlbmd0aCA+IDBcclxuICAgICAgICA/IGBUaGVyZSBhcmUgJHthY3RpdmVDaXJjdWxhdGlvbnMubGVuZ3RofSBhY3RpdmUgY2lyY3VsYXRpb24ocykgZm9yIHRoaXMgY29ycmVzcG9uZGVuY2UuIENhbmNlbGluZyB3aWxsIGZvcmNlIGNsb3NlIGFsbCByZWxhdGVkIGNpcmN1bGF0aW9ucy5gXHJcbiAgICAgICAgOiAnJztcclxuXHJcbiAgICAvLyBHZXQgdGhlIGN1cnJlbnQgcmV2aXNpb24gdG8gdXBkYXRlIHN0YXR1c1xyXG4gICAgY29uc3QgY3VycmVudFJldmlzaW9uID0gYXdhaXQgdGhpcy5yZXZpc2lvblJlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7XHJcbiAgICAgICAgY29ycmVzcG9uZGVuY2VJZDogY29ycmVzcG9uZGVuY2UuaWQsXHJcbiAgICAgICAgaXNDdXJyZW50OiB0cnVlLFxyXG4gICAgICB9LFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKCFjdXJyZW50UmV2aXNpb24pIHtcclxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXhjZXB0aW9uKCdDdXJyZW50IHJldmlzaW9uIG5vdCBmb3VuZCcpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCBjYW5jZWxsZWQgc3RhdHVzXHJcbiAgICBjb25zdCBjYW5jZWxsZWRTdGF0dXMgPSBhd2FpdCB0aGlzLnN0YXR1c1JlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IHN0YXR1c0NvZGU6ICdDQU5DRUxMRUQnIH0sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoIWNhbmNlbGxlZFN0YXR1cykge1xyXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxTZXJ2ZXJFcnJvckV4Y2VwdGlvbignQ0FOQ0VMTEVEIHN0YXR1cyBub3QgZm91bmQnKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBxdWVyeVJ1bm5lciA9IHRoaXMuZGF0YVNvdXJjZS5jcmVhdGVRdWVyeVJ1bm5lcigpO1xyXG4gICAgYXdhaXQgcXVlcnlSdW5uZXIuY29ubmVjdCgpO1xyXG4gICAgYXdhaXQgcXVlcnlSdW5uZXIuc3RhcnRUcmFuc2FjdGlvbigpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFVwZGF0ZSBjb3JyZXNwb25kZW5jZSByZXZpc2lvbiBzdGF0dXMgdG8gQ0FOQ0VMTEVEXHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLm1hbmFnZXIudXBkYXRlKFxyXG4gICAgICAgIENvcnJlc3BvbmRlbmNlUmV2aXNpb24sXHJcbiAgICAgICAgY3VycmVudFJldmlzaW9uLmlkLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHN0YXR1c0lkOiBjYW5jZWxsZWRTdGF0dXMuaWQsXHJcbiAgICAgICAgICByZW1hcmtzOiBgQ2FuY2VsbGVkOiAke3JlYXNvbn1gLFxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIEZvcmNlIGNsb3NlIGFsbCBhY3RpdmUgY2lyY3VsYXRpb25zXHJcbiAgICAgIGlmIChhY3RpdmVDaXJjdWxhdGlvbnMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLm1hbmFnZXIudXBkYXRlKFxyXG4gICAgICAgICAgJ0NpcmN1bGF0aW9uJyxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgY29ycmVzcG9uZGVuY2VJZDogY29ycmVzcG9uZGVuY2UuaWQsXHJcbiAgICAgICAgICAgIHN0YXR1czogJ09QRU4nLFxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgc3RhdHVzOiAnRk9SQ0VfQ0xPU0VEJyxcclxuICAgICAgICAgICAgY2xvc2VkQXQ6IG5ldyBEYXRlKCksXHJcbiAgICAgICAgICAgIGNsb3NlZEJ5OiB1c2VyLnVzZXJfaWQsXHJcbiAgICAgICAgICAgIGNsb3NlUmVhc29uOiBgQ29ycmVzcG9uZGVuY2UgY2FuY2VsbGVkOiAke3JlYXNvbn1gLFxyXG4gICAgICAgICAgfVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLmNvbW1pdFRyYW5zYWN0aW9uKCk7XHJcblxyXG4gICAgICAvLyBSZS1pbmRleCBjYW5jZWxsZWQgc3RhdHVzIGluIEVsYXN0aWNzZWFyY2ggKGZpcmUtYW5kLWZvcmdldClcclxuICAgICAgdm9pZCB0aGlzLnNlYXJjaFNlcnZpY2UuaW5kZXhEb2N1bWVudCh7XHJcbiAgICAgICAgaWQ6IGNvcnJlc3BvbmRlbmNlLmlkLFxyXG4gICAgICAgIHB1YmxpY0lkOiBjb3JyZXNwb25kZW5jZS5wdWJsaWNJZCxcclxuICAgICAgICB0eXBlOiAnY29ycmVzcG9uZGVuY2UnLFxyXG4gICAgICAgIGRvY051bWJlcjogY29ycmVzcG9uZGVuY2UuY29ycmVzcG9uZGVuY2VOdW1iZXIsXHJcbiAgICAgICAgdGl0bGU6IGN1cnJlbnRSZXZpc2lvbi5zdWJqZWN0LFxyXG4gICAgICAgIHN0YXR1czogJ0NBTkNFTExFRCcsXHJcbiAgICAgICAgcHJvamVjdElkOiBjb3JyZXNwb25kZW5jZS5wcm9qZWN0SWQsXHJcbiAgICAgICAgY3JlYXRlZEF0OiBjb3JyZXNwb25kZW5jZS5jcmVhdGVkQXQsXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgLy8gTm90aWZ5IG9yaWdpbmF0b3IncyBkb2MtY29udHJvbCB1c2VyIGFib3V0IGNhbmNlbGxhdGlvbiAoZmlyZS1hbmQtZm9yZ2V0KVxyXG4gICAgICBpZiAoY29ycmVzcG9uZGVuY2Uub3JpZ2luYXRvcklkKSB7XHJcbiAgICAgICAgdm9pZCB0aGlzLnVzZXJTZXJ2aWNlXHJcbiAgICAgICAgICAuZmluZERvY0NvbnRyb2xJZEJ5T3JnKGNvcnJlc3BvbmRlbmNlLm9yaWdpbmF0b3JJZClcclxuICAgICAgICAgIC50aGVuKCh0YXJnZXRVc2VySWQpID0+IHtcclxuICAgICAgICAgICAgaWYgKHRhcmdldFVzZXJJZCkge1xyXG4gICAgICAgICAgICAgIHZvaWQgdGhpcy5ub3RpZmljYXRpb25TZXJ2aWNlLnNlbmQoe1xyXG4gICAgICAgICAgICAgICAgdXNlcklkOiB0YXJnZXRVc2VySWQsXHJcbiAgICAgICAgICAgICAgICB0aXRsZTogJ0NvcnJlc3BvbmRlbmNlIENhbmNlbGxlZCcsXHJcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgJHtjb3JyZXNwb25kZW5jZS5jb3JyZXNwb25kZW5jZU51bWJlcn0g4oCUICR7Y3VycmVudFJldmlzaW9uLnN1YmplY3R9IGhhcyBiZWVuIGNhbmNlbGxlZC4gUmVhc29uOiAke3JlYXNvbn1gLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogJ0VNQUlMJyxcclxuICAgICAgICAgICAgICAgIGVudGl0eVR5cGU6ICdjb3JyZXNwb25kZW5jZScsXHJcbiAgICAgICAgICAgICAgICBlbnRpdHlJZDogY29ycmVzcG9uZGVuY2UuaWQsXHJcbiAgICAgICAgICAgICAgICBsaW5rOiBgL2NvcnJlc3BvbmRlbmNlcy8ke2NvcnJlc3BvbmRlbmNlLnB1YmxpY0lkfWAsXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pXHJcbiAgICAgICAgICAuY2F0Y2goKGVycjogRXJyb3IpID0+XHJcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyLndhcm4oYENhbmNlbCBub3RpZmljYXRpb24gZmFpbGVkOiAke2Vyci5tZXNzYWdlfWApXHJcbiAgICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIHN1Y2Nlc3M6IHRydWUsXHJcbiAgICAgICAgbWVzc2FnZTogd2FybmluZ01lc3NhZ2UgfHwgJ0NvcnJlc3BvbmRlbmNlIGNhbmNlbGxlZCBzdWNjZXNzZnVsbHknLFxyXG4gICAgICAgIGFjdGl2ZUNpcmN1bGF0aW9uc0NvdW50OiBhY3RpdmVDaXJjdWxhdGlvbnMubGVuZ3RoLFxyXG4gICAgICB9O1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgYXdhaXQgcXVlcnlSdW5uZXIucm9sbGJhY2tUcmFuc2FjdGlvbigpO1xyXG4gICAgICB0aGlzLmxvZ2dlci5lcnJvcihcclxuICAgICAgICBgRmFpbGVkIHRvIGNhbmNlbCBjb3JyZXNwb25kZW5jZTogJHsoZXJyb3IgYXMgRXJyb3IpLm1lc3NhZ2V9YFxyXG4gICAgICApO1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH0gZmluYWxseSB7XHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLnJlbGVhc2UoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFzeW5jIGJ1bGtDYW5jZWwoXHJcbiAgICBwdWJsaWNJZHM6IHN0cmluZ1tdLFxyXG4gICAgcmVhc29uOiBzdHJpbmcsXHJcbiAgICB1c2VyOiBVc2VyXHJcbiAgKTogUHJvbWlzZTx7IHN1Y2NlZWRlZDogc3RyaW5nW107IGZhaWxlZDogc3RyaW5nW10gfT4ge1xyXG4gICAgY29uc3Qgc3VjY2VlZGVkOiBzdHJpbmdbXSA9IFtdO1xyXG4gICAgY29uc3QgZmFpbGVkOiBzdHJpbmdbXSA9IFtdO1xyXG5cclxuICAgIGZvciAoY29uc3QgcHVibGljSWQgb2YgcHVibGljSWRzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgYXdhaXQgdGhpcy5jYW5jZWwocHVibGljSWQsIHJlYXNvbiwgdXNlcik7XHJcbiAgICAgICAgc3VjY2VlZGVkLnB1c2gocHVibGljSWQpO1xyXG4gICAgICB9IGNhdGNoIHtcclxuICAgICAgICBmYWlsZWQucHVzaChwdWJsaWNJZCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4geyBzdWNjZWVkZWQsIGZhaWxlZCB9O1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgZXhwb3J0Q3N2KHNlYXJjaER0bzogU2VhcmNoQ29ycmVzcG9uZGVuY2VEdG8pOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgY29uc3QgeyBkYXRhIH0gPSBhd2FpdCB0aGlzLmZpbmRBbGwoc2VhcmNoRHRvKTtcclxuXHJcbiAgICBjb25zdCBoZWFkZXIgPSBbXHJcbiAgICAgICdEb2N1bWVudCBOby4nLFxyXG4gICAgICAnUmV2JyxcclxuICAgICAgJ1N1YmplY3QnLFxyXG4gICAgICAnVHlwZScsXHJcbiAgICAgICdTdGF0dXMnLFxyXG4gICAgICAnUHJvamVjdCcsXHJcbiAgICAgICdGcm9tJyxcclxuICAgICAgJ0R1ZSBEYXRlJyxcclxuICAgICAgJ0NyZWF0ZWQgQXQnLFxyXG4gICAgXTtcclxuICAgIGNvbnN0IHJvd3MgPSBkYXRhLm1hcCgocmV2KSA9PiB7XHJcbiAgICAgIGNvbnN0IGNvcnIgPSByZXYuY29ycmVzcG9uZGVuY2UgPz8gKHJldiBhcyB1bmtub3duIGFzIENvcnJlc3BvbmRlbmNlKTtcclxuICAgICAgcmV0dXJuIFtcclxuICAgICAgICB0aGlzLmVzY2FwZUNzdihjb3JyLmNvcnJlc3BvbmRlbmNlTnVtYmVyID8/ICcnKSxcclxuICAgICAgICB0aGlzLmVzY2FwZUNzdihyZXYucmV2aXNpb25MYWJlbCA/PyBTdHJpbmcocmV2LnJldmlzaW9uTnVtYmVyID8/IDApKSxcclxuICAgICAgICB0aGlzLmVzY2FwZUNzdihyZXYuc3ViamVjdCA/PyAnJyksXHJcbiAgICAgICAgdGhpcy5lc2NhcGVDc3YoY29yci50eXBlPy50eXBlQ29kZSA/PyAnJyksXHJcbiAgICAgICAgdGhpcy5lc2NhcGVDc3YocmV2LnN0YXR1cz8uc3RhdHVzQ29kZSA/PyAnJyksXHJcbiAgICAgICAgdGhpcy5lc2NhcGVDc3YoY29yci5wcm9qZWN0Py5wcm9qZWN0Q29kZSA/PyAnJyksXHJcbiAgICAgICAgdGhpcy5lc2NhcGVDc3YoY29yci5vcmlnaW5hdG9yPy5vcmdhbml6YXRpb25Db2RlID8/ICcnKSxcclxuICAgICAgICByZXYuZHVlRGF0ZSA/IG5ldyBEYXRlKHJldi5kdWVEYXRlKS50b0lTT1N0cmluZygpLnNwbGl0KCdUJylbMF0gOiAnJyxcclxuICAgICAgICBuZXcgRGF0ZShyZXYuY3JlYXRlZEF0KS50b0lTT1N0cmluZygpLnNwbGl0KCdUJylbMF0sXHJcbiAgICAgIF0uam9pbignLCcpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIFtoZWFkZXIuam9pbignLCcpLCAuLi5yb3dzXS5qb2luKCdcXG4nKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgZXNjYXBlQ3N2KHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgaWYgKHZhbHVlLmluY2x1ZGVzKCcsJykgfHwgdmFsdWUuaW5jbHVkZXMoJ1wiJykgfHwgdmFsdWUuaW5jbHVkZXMoJ1xcbicpKSB7XHJcbiAgICAgIHJldHVybiBgXCIke3ZhbHVlLnJlcGxhY2UoL1wiL2csICdcIlwiJyl9XCJgO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHZhbHVlO1xyXG4gIH1cclxufVxyXG4iXSwidmVyc2lvbiI6M30= \ No newline at end of file diff --git a/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/55/correspondenceservice_5585ce2f5626b5a93fd64e63909b087f.map b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/55/correspondenceservice_5585ce2f5626b5a93fd64e63909b087f.map new file mode 100644 index 0000000..1de2baa --- /dev/null +++ b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/55/correspondenceservice_5585ce2f5626b5a93fd64e63909b087f.map @@ -0,0 +1 @@ +{"file":"E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.ts","mappings":"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","names":[],"sources":["E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.ts"],"sourcesContent":["// File: src/modules/correspondence/correspondence.service.ts\r\n\r\nimport {\r\n Injectable,\r\n NotFoundException,\r\n BadRequestException,\r\n InternalServerErrorException,\r\n ForbiddenException,\r\n Logger,\r\n} from '@nestjs/common';\r\nimport { InjectRepository } from '@nestjs/typeorm';\r\nimport { Repository, DataSource } from 'typeorm';\r\n\r\n// Entities\r\nimport { Correspondence } from './entities/correspondence.entity';\r\nimport { CorrespondenceRevision } from './entities/correspondence-revision.entity';\r\nimport { CorrespondenceType } from './entities/correspondence-type.entity';\r\nimport { CorrespondenceStatus } from './entities/correspondence-status.entity';\r\nimport { CorrespondenceReference } from './entities/correspondence-reference.entity';\r\nimport { CorrespondenceRecipient } from './entities/correspondence-recipient.entity';\r\nimport { CorrespondenceTag } from './entities/correspondence-tag.entity';\r\nimport { Tag } from '../master/entities/tag.entity';\r\nimport { User } from '../user/entities/user.entity';\r\nimport { Organization } from '../organization/entities/organization.entity';\r\n\r\n// DTOs\r\nimport { CreateCorrespondenceDto } from './dto/create-correspondence.dto';\r\nimport { UpdateCorrespondenceDto } from './dto/update-correspondence.dto';\r\nimport { AddReferenceDto } from './dto/add-reference.dto';\r\nimport { SearchCorrespondenceDto } from './dto/search-correspondence.dto';\r\n\r\n// Services\r\nimport { DocumentNumberingService } from '../document-numbering/services/document-numbering.service';\r\nimport { JsonSchemaService } from '../json-schema/json-schema.service';\r\nimport { WorkflowEngineService } from '../workflow-engine/workflow-engine.service';\r\nimport { UserService } from '../user/user.service';\r\nimport { SearchService } from '../search/search.service';\r\nimport { FileStorageService } from '../../common/file-storage/file-storage.service';\r\nimport { UuidResolverService } from '../../common/services/uuid-resolver.service';\r\nimport { NotificationService } from '../notification/notification.service';\r\n\r\n/**\r\n * CorrespondenceService - Document management (CRUD)\r\n */\r\ninterface ResolvedRecipient {\r\n organizationId: number;\r\n type: 'TO' | 'CC';\r\n}\r\n@Injectable()\r\nexport class CorrespondenceService {\r\n private readonly logger = new Logger(CorrespondenceService.name);\r\n\r\n private async hasSystemManageAllPermission(userId: number): Promise {\r\n const permissions = await this.userService.getUserPermissions(userId);\r\n return permissions.includes('system.manage_all');\r\n }\r\n\r\n /**\r\n * Business Rule: Revision Label Strategy\r\n * - RFA, RFI: Use alphabet starting with 'A' (A, B, C...)\r\n * - Other types (LETTER, MEMO, etc.): Use numeric (null for first, then 1, 2, 3...)\r\n */\r\n private getInitialRevisionLabel(typeCode: string): string | null {\r\n const alphabetTypes = ['RFA', 'RFI'];\r\n if (alphabetTypes.includes(typeCode.toUpperCase())) {\r\n return 'A'; // Alphabet for RFA, RFI\r\n }\r\n return null; // Numeric (null for revision 0)\r\n }\r\n\r\n constructor(\r\n @InjectRepository(Correspondence)\r\n private correspondenceRepo: Repository,\r\n @InjectRepository(CorrespondenceRevision)\r\n private revisionRepo: Repository,\r\n @InjectRepository(CorrespondenceType)\r\n private typeRepo: Repository,\r\n @InjectRepository(CorrespondenceStatus)\r\n private statusRepo: Repository,\r\n @InjectRepository(CorrespondenceReference)\r\n private referenceRepo: Repository,\r\n @InjectRepository(CorrespondenceTag)\r\n private tagRepo: Repository,\r\n private numberingService: DocumentNumberingService,\r\n private jsonSchemaService: JsonSchemaService,\r\n private workflowEngine: WorkflowEngineService,\r\n private userService: UserService,\r\n private dataSource: DataSource,\r\n private searchService: SearchService,\r\n private fileStorageService: FileStorageService,\r\n private uuidResolver: UuidResolverService,\r\n private notificationService: NotificationService\r\n ) {}\r\n\r\n /**\r\n * Business Rule Validation: EC-CORR-003 - Correspondence to Self\r\n * Prevent external correspondence to same organization\r\n */\r\n private async validateCorrespondenceRecipients(\r\n createDto: CreateCorrespondenceDto,\r\n user: User\r\n ): Promise {\r\n // Get user's organization\r\n let userOrgId = user.primaryOrganizationId;\r\n if (!userOrgId) {\r\n const fullUser = await this.userService.findOne(user.user_id);\r\n if (fullUser) {\r\n userOrgId = fullUser.primaryOrganizationId;\r\n }\r\n }\r\n\r\n if (!userOrgId) {\r\n if (createDto.originatorId) {\r\n const canManageAll = await this.hasSystemManageAllPermission(\r\n user.user_id\r\n );\r\n if (canManageAll) {\r\n userOrgId = await this.uuidResolver.resolveOrganizationId(\r\n createDto.originatorId\r\n );\r\n }\r\n }\r\n\r\n if (!userOrgId) {\r\n throw new BadRequestException(\r\n 'User must belong to an organization to create documents'\r\n );\r\n }\r\n }\r\n\r\n // For impersonation, use the specified originator\r\n const originatorOrgId = createDto.originatorId\r\n ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId)\r\n : userOrgId;\r\n\r\n // Check if it's internal communication\r\n if (createDto.isInternal) {\r\n // Internal communications should use Circulation instead\r\n throw new BadRequestException(\r\n 'Internal communications should use Circulation Sheet instead of Correspondence'\r\n );\r\n }\r\n\r\n // Validate recipients\r\n if (!createDto.recipients || createDto.recipients.length === 0) {\r\n throw new BadRequestException(\r\n 'At least one recipient (TO or CC) is required'\r\n );\r\n }\r\n\r\n const toRecipients = createDto.recipients.filter((r) => r.type === 'TO');\r\n const ccRecipients = createDto.recipients.filter((r) => r.type === 'CC');\r\n\r\n if (toRecipients.length === 0 && ccRecipients.length === 0) {\r\n throw new BadRequestException(\r\n 'At least one TO or CC recipient is required'\r\n );\r\n }\r\n\r\n // Check for same organization correspondence\r\n for (const recipient of createDto.recipients) {\r\n const recipientOrgId = await this.uuidResolver.resolveOrganizationId(\r\n recipient.organizationId\r\n );\r\n\r\n if (recipientOrgId === originatorOrgId) {\r\n throw new BadRequestException(\r\n 'Cannot send correspondence to your own organization. Use Circulation Sheet for internal communication.'\r\n );\r\n }\r\n }\r\n }\r\n\r\n async create(createDto: CreateCorrespondenceDto, user: User) {\r\n // Business Rule Validation: EC-CORR-003 - Correspondence to Self\r\n await this.validateCorrespondenceRecipients(createDto, user);\r\n // ADR-019: Resolve UUID references to internal INT IDs\r\n const resolvedProjectId = await this.uuidResolver.resolveProjectId(\r\n createDto.projectId\r\n );\r\n const resolvedOriginatorId = createDto.originatorId\r\n ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId)\r\n : undefined;\r\n const resolvedRecipients = createDto.recipients\r\n ? await Promise.all(\r\n createDto.recipients.map(\r\n async (r): Promise => ({\r\n organizationId: await this.uuidResolver.resolveOrganizationId(\r\n r.organizationId\r\n ),\r\n type: r.type,\r\n })\r\n )\r\n )\r\n : undefined;\r\n const type = await this.typeRepo.findOne({\r\n where: { id: createDto.typeId },\r\n });\r\n if (!type) throw new NotFoundException('Document Type not found');\r\n\r\n const statusDraft = await this.statusRepo.findOne({\r\n where: { statusCode: 'DRAFT' },\r\n });\r\n if (!statusDraft) {\r\n throw new InternalServerErrorException(\r\n 'Status DRAFT not found in Master Data'\r\n );\r\n }\r\n\r\n let userOrgId = user.primaryOrganizationId;\r\n\r\n if (!userOrgId) {\r\n const fullUser = await this.userService.findOne(user.user_id);\r\n if (fullUser) {\r\n userOrgId = fullUser.primaryOrganizationId;\r\n }\r\n }\r\n\r\n // Impersonation Logic\r\n if (resolvedOriginatorId && resolvedOriginatorId !== userOrgId) {\r\n const canManageAll = await this.hasSystemManageAllPermission(\r\n user.user_id\r\n );\r\n if (!canManageAll) {\r\n throw new ForbiddenException(\r\n 'You do not have permission to create documents on behalf of other organizations.'\r\n );\r\n }\r\n userOrgId = resolvedOriginatorId;\r\n }\r\n\r\n if (!userOrgId) {\r\n throw new BadRequestException(\r\n 'User must belong to an organization to create documents'\r\n );\r\n }\r\n\r\n if (createDto.details) {\r\n try {\r\n await this.jsonSchemaService.validate(type.typeCode, createDto.details);\r\n } catch (error: unknown) {\r\n this.logger.warn(\r\n `Schema validation warning for ${type.typeCode}: ${(error as Error).message}`\r\n );\r\n }\r\n }\r\n\r\n const queryRunner = this.dataSource.createQueryRunner();\r\n await queryRunner.connect();\r\n await queryRunner.startTransaction();\r\n\r\n try {\r\n // [Fix #6] Fetch real ORG Code from Organization entity\r\n const originatorOrg = await this.dataSource.manager.findOne(\r\n Organization,\r\n {\r\n where: { id: userOrgId },\r\n }\r\n );\r\n const orgCode = originatorOrg?.organizationCode ?? 'UNK';\r\n\r\n // [v1.5.1] Extract recipient organization from recipients array (Primary TO)\r\n const toRecipient = resolvedRecipients?.find((r) => r.type === 'TO');\r\n const recipientOrganizationId = toRecipient?.organizationId;\r\n\r\n let recipientCode = '';\r\n if (recipientOrganizationId) {\r\n const recOrg = await this.dataSource.manager.findOne(Organization, {\r\n where: { id: recipientOrganizationId },\r\n });\r\n if (recOrg) recipientCode = recOrg.organizationCode;\r\n }\r\n\r\n const docNumber = await this.numberingService.generateNextNumber({\r\n projectId: resolvedProjectId,\r\n originatorOrganizationId: userOrgId,\r\n typeId: createDto.typeId,\r\n disciplineId: createDto.disciplineId,\r\n subTypeId: createDto.subTypeId,\r\n recipientOrganizationId, // [v1.5.1] Pass recipient for document number format\r\n year: new Date().getFullYear(),\r\n customTokens: {\r\n TYPE_CODE: type.typeCode,\r\n ORG_CODE: orgCode,\r\n RECIPIENT_CODE: recipientCode,\r\n REC_CODE: recipientCode,\r\n },\r\n });\r\n\r\n const correspondence = queryRunner.manager.create(Correspondence, {\r\n correspondenceNumber: docNumber.number,\r\n correspondenceTypeId: createDto.typeId,\r\n disciplineId: createDto.disciplineId,\r\n projectId: resolvedProjectId,\r\n originatorId: userOrgId,\r\n isInternal: createDto.isInternal || false,\r\n createdBy: user.user_id,\r\n });\r\n const savedCorr = await queryRunner.manager.save(correspondence);\r\n\r\n const revision = queryRunner.manager.create(CorrespondenceRevision, {\r\n correspondenceId: savedCorr.id,\r\n revisionNumber: 0,\r\n revisionLabel: this.getInitialRevisionLabel(type.typeCode),\r\n isCurrent: true,\r\n statusId: statusDraft.id,\r\n subject: createDto.subject,\r\n body: createDto.body,\r\n remarks: createDto.remarks,\r\n dueDate: createDto.dueDate ? new Date(createDto.dueDate) : undefined,\r\n documentDate: createDto.documentDate\r\n ? new Date(createDto.documentDate)\r\n : undefined,\r\n issuedDate: createDto.issuedDate\r\n ? new Date(createDto.issuedDate)\r\n : undefined,\r\n receivedDate: createDto.receivedDate\r\n ? new Date(createDto.receivedDate)\r\n : undefined,\r\n description: createDto.description,\r\n details: createDto.details,\r\n createdBy: user.user_id,\r\n schemaVersion: 1,\r\n });\r\n await queryRunner.manager.save(revision);\r\n\r\n // Save Recipients (using resolved INT IDs)\r\n if (resolvedRecipients && resolvedRecipients.length > 0) {\r\n const recipients = resolvedRecipients.map((r) =>\r\n queryRunner.manager.create(CorrespondenceRecipient, {\r\n correspondenceId: savedCorr.id,\r\n recipientOrganizationId: r.organizationId,\r\n recipientType: r.type,\r\n })\r\n );\r\n await queryRunner.manager.save(recipients);\r\n }\r\n\r\n // Commit attachments from Temp → Permanent (Two-Phase Storage)\r\n if (createDto.attachmentTempIds?.length) {\r\n const issueDate = createDto.issuedDate\r\n ? new Date(createDto.issuedDate)\r\n : createDto.documentDate\r\n ? new Date(createDto.documentDate)\r\n : undefined;\r\n\r\n await this.fileStorageService.commit(createDto.attachmentTempIds, {\r\n issueDate,\r\n documentType: 'Correspondence',\r\n });\r\n }\r\n\r\n await queryRunner.commitTransaction();\r\n\r\n // Start Workflow Instance (non-blocking)\r\n try {\r\n const workflowCode = `CORRESPONDENCE_${type.typeCode}`;\r\n await this.workflowEngine.createInstance(\r\n workflowCode,\r\n 'correspondence',\r\n savedCorr.id.toString(),\r\n {\r\n projectId: resolvedProjectId,\r\n originatorId: userOrgId,\r\n disciplineId: createDto.disciplineId,\r\n initiatorId: user.user_id,\r\n } as Record\r\n );\r\n } catch (error: unknown) {\r\n this.logger.warn(\r\n `Workflow not started for ${docNumber.number} (Code: CORRESPONDENCE_${type.typeCode}): ${(error as Error).message}`\r\n );\r\n }\r\n\r\n // Fire-and-forget search indexing (non-blocking, void intentional)\r\n void this.searchService.indexDocument({\r\n id: savedCorr.id,\r\n publicId: savedCorr.publicId,\r\n type: 'correspondence',\r\n docNumber: docNumber.number,\r\n title: createDto.subject,\r\n description: createDto.description,\r\n status: 'DRAFT',\r\n projectId: resolvedProjectId,\r\n createdAt: new Date(),\r\n });\r\n\r\n return {\r\n ...savedCorr,\r\n currentRevision: revision,\r\n };\r\n } catch (err) {\r\n await queryRunner.rollbackTransaction();\r\n this.logger.error(\r\n `Failed to create correspondence: ${(err as Error).message}`\r\n );\r\n throw err;\r\n } finally {\r\n await queryRunner.release();\r\n }\r\n }\r\n\r\n async findAll(searchDto: SearchCorrespondenceDto = {}) {\r\n const {\r\n search,\r\n typeId,\r\n projectId,\r\n statusId,\r\n status,\r\n page = 1,\r\n limit = 10,\r\n } = searchDto;\r\n const skip = (page - 1) * limit;\r\n\r\n // Change: Query from Revision Repo\r\n const query = this.revisionRepo\r\n .createQueryBuilder('rev')\r\n .leftJoinAndSelect('rev.correspondence', 'corr')\r\n .leftJoinAndSelect('corr.type', 'type')\r\n .leftJoinAndSelect('corr.project', 'project')\r\n .leftJoinAndSelect('corr.originator', 'org')\r\n .leftJoinAndSelect('rev.status', 'status');\r\n\r\n // Filter by Revision Status\r\n const revStatus = searchDto.revisionStatus || 'CURRENT';\r\n\r\n if (revStatus === 'CURRENT') {\r\n query.where('rev.isCurrent = :isCurrent', { isCurrent: true });\r\n } else if (revStatus === 'OLD') {\r\n query.where('rev.isCurrent = :isCurrent', { isCurrent: false });\r\n }\r\n // If 'ALL', no filter needed on isCurrent\r\n\r\n if (projectId) {\r\n query.andWhere('corr.projectId = :projectId', { projectId });\r\n }\r\n\r\n if (typeId) {\r\n query.andWhere('corr.correspondenceTypeId = :typeId', { typeId });\r\n }\r\n\r\n if (statusId) {\r\n query.andWhere('rev.statusId = :statusId', { statusId });\r\n }\r\n\r\n if (status) {\r\n query.andWhere('status.statusCode = :status', { status });\r\n }\r\n\r\n if (search) {\r\n query.andWhere(\r\n '(corr.correspondenceNumber LIKE :search OR rev.subject LIKE :search)',\r\n { search: `%${search}%` }\r\n );\r\n }\r\n\r\n // Default Sort: Latest Created\r\n query.orderBy('rev.createdAt', 'DESC').skip(skip).take(limit);\r\n\r\n const [items, total] = await query.getManyAndCount();\r\n\r\n return {\r\n data: items,\r\n meta: {\r\n total,\r\n page,\r\n limit,\r\n totalPages: Math.ceil(total / limit),\r\n },\r\n };\r\n }\r\n\r\n async findOne(id: number) {\r\n const correspondence = await this.correspondenceRepo.findOne({\r\n where: { id },\r\n relations: [\r\n 'revisions',\r\n 'revisions.status',\r\n 'type',\r\n 'project',\r\n 'originator',\r\n 'recipients',\r\n 'recipients.recipientOrganization', // [v1.5.1] Fixed relation name\r\n ],\r\n });\r\n\r\n if (!correspondence) {\r\n throw new NotFoundException(`Correspondence with ID ${id} not found`);\r\n }\r\n return correspondence;\r\n }\r\n\r\n async findOneByUuid(publicId: string) {\r\n const correspondence = await this.correspondenceRepo.findOne({\r\n where: { publicId },\r\n relations: [\r\n 'revisions',\r\n 'revisions.status',\r\n 'type',\r\n 'project',\r\n 'originator',\r\n 'recipients',\r\n 'recipients.recipientOrganization',\r\n ],\r\n });\r\n\r\n if (!correspondence) {\r\n throw new NotFoundException(\r\n `Correspondence with UUID ${publicId} not found`\r\n );\r\n }\r\n return correspondence;\r\n }\r\n\r\n async addReference(id: number, dto: AddReferenceDto) {\r\n const source = await this.correspondenceRepo.findOne({ where: { id } });\r\n // ADR-019: Resolve target publicId → internal INT id\r\n const target = await this.correspondenceRepo.findOne({\r\n where: { publicId: dto.targetUuid },\r\n });\r\n\r\n if (!source || !target) {\r\n throw new NotFoundException('Source or Target correspondence not found');\r\n }\r\n\r\n if (source.id === target.id) {\r\n throw new BadRequestException('Cannot reference self');\r\n }\r\n\r\n const exists = await this.referenceRepo.findOne({\r\n where: {\r\n sourceId: id,\r\n targetId: target.id,\r\n },\r\n });\r\n\r\n if (exists) {\r\n return exists;\r\n }\r\n\r\n const ref = this.referenceRepo.create({\r\n sourceId: id,\r\n targetId: target.id,\r\n });\r\n\r\n return this.referenceRepo.save(ref);\r\n }\r\n\r\n async removeReference(id: number, targetId: number) {\r\n const result = await this.referenceRepo.delete({\r\n sourceId: id,\r\n targetId: targetId,\r\n });\r\n\r\n if (result.affected === 0) {\r\n throw new NotFoundException('Reference not found');\r\n }\r\n }\r\n\r\n async getTags(id: number) {\r\n const rows = await this.tagRepo.find({\r\n where: { correspondenceId: id },\r\n relations: ['tag'],\r\n });\r\n return rows.map((r) => r.tag).filter(Boolean);\r\n }\r\n\r\n async addTag(id: number, tagId: number) {\r\n const correspondence = await this.correspondenceRepo.findOne({\r\n where: { id },\r\n });\r\n if (!correspondence) {\r\n throw new NotFoundException(`Correspondence ${id} not found`);\r\n }\r\n\r\n const tag = await this.dataSource.manager.findOne(Tag, {\r\n where: { id: tagId },\r\n });\r\n if (!tag) {\r\n throw new NotFoundException(`Tag ${tagId} not found`);\r\n }\r\n\r\n const exists = await this.tagRepo.findOne({\r\n where: { correspondenceId: id, tagId },\r\n });\r\n if (exists) return exists;\r\n\r\n const row = this.tagRepo.create({ correspondenceId: id, tagId });\r\n return this.tagRepo.save(row);\r\n }\r\n\r\n async removeTag(id: number, tagId: number) {\r\n const result = await this.tagRepo.delete({ correspondenceId: id, tagId });\r\n if (result.affected === 0) {\r\n throw new NotFoundException('Tag assignment not found');\r\n }\r\n }\r\n\r\n async getReferences(id: number) {\r\n const outgoing = await this.referenceRepo.find({\r\n where: { sourceId: id },\r\n relations: ['target', 'target.type'],\r\n });\r\n\r\n const incoming = await this.referenceRepo.find({\r\n where: { targetId: id },\r\n relations: ['source', 'source.type'],\r\n });\r\n\r\n return { outgoing, incoming };\r\n }\r\n\r\n async update(id: number, updateDto: UpdateCorrespondenceDto, user: User) {\r\n // 1. Find Current Revision\r\n const revision = await this.revisionRepo.findOne({\r\n where: {\r\n correspondenceId: id,\r\n isCurrent: true,\r\n },\r\n relations: ['correspondence'],\r\n });\r\n\r\n if (!revision) {\r\n throw new NotFoundException(\r\n `Current revision for correspondence ${id} not found`\r\n );\r\n }\r\n\r\n // 2. Check Permission\r\n if (revision.statusId) {\r\n const status = await this.statusRepo.findOne({\r\n where: { id: revision.statusId },\r\n });\r\n if (status && status.statusCode !== 'DRAFT') {\r\n throw new BadRequestException('Only DRAFT documents can be updated');\r\n }\r\n }\r\n\r\n // ADR-019: Resolve UUID references in update DTO\r\n const updResolvedProjectId = updateDto.projectId\r\n ? await this.uuidResolver.resolveProjectId(updateDto.projectId)\r\n : undefined;\r\n const updResolvedOriginatorId = updateDto.originatorId\r\n ? await this.uuidResolver.resolveOrganizationId(updateDto.originatorId)\r\n : undefined;\r\n const updResolvedRecipients = updateDto.recipients\r\n ? await Promise.all(\r\n updateDto.recipients.map(\r\n async (r): Promise => ({\r\n organizationId: await this.uuidResolver.resolveOrganizationId(\r\n r.organizationId\r\n ),\r\n type: r.type,\r\n })\r\n )\r\n )\r\n : undefined;\r\n\r\n // 3. Update Correspondence Entity if needed\r\n const correspondenceUpdate: Record = {};\r\n if (updateDto.disciplineId)\r\n correspondenceUpdate.disciplineId = updateDto.disciplineId;\r\n if (updResolvedProjectId)\r\n correspondenceUpdate.projectId = updResolvedProjectId;\r\n if (updResolvedOriginatorId)\r\n correspondenceUpdate.originatorId = updResolvedOriginatorId;\r\n\r\n if (Object.keys(correspondenceUpdate).length > 0) {\r\n await this.correspondenceRepo.update(id, correspondenceUpdate);\r\n }\r\n\r\n // 4. Update Revision Entity\r\n const revisionUpdate: Record = {};\r\n if (updateDto.subject) revisionUpdate.subject = updateDto.subject;\r\n if (updateDto.body) revisionUpdate.body = updateDto.body;\r\n if (updateDto.remarks) revisionUpdate.remarks = updateDto.remarks;\r\n // Format Date correctly if string\r\n if (updateDto.dueDate) revisionUpdate.dueDate = new Date(updateDto.dueDate);\r\n if (updateDto.documentDate)\r\n revisionUpdate.documentDate = new Date(updateDto.documentDate);\r\n if (updateDto.issuedDate)\r\n revisionUpdate.issuedDate = new Date(updateDto.issuedDate);\r\n if (updateDto.receivedDate)\r\n revisionUpdate.receivedDate = new Date(updateDto.receivedDate);\r\n if (updateDto.description)\r\n revisionUpdate.description = updateDto.description;\r\n if (updateDto.details) revisionUpdate.details = updateDto.details;\r\n\r\n if (Object.keys(revisionUpdate).length > 0) {\r\n await this.revisionRepo.update(revision.id, revisionUpdate);\r\n }\r\n\r\n // 4.5 Commit new attachments from Temp → Permanent (Two-Phase Storage)\r\n if (updateDto.attachmentTempIds?.length) {\r\n const issueDate = updateDto.issuedDate\r\n ? new Date(updateDto.issuedDate)\r\n : updateDto.documentDate\r\n ? new Date(updateDto.documentDate)\r\n : revision.issuedDate || revision.documentDate || undefined;\r\n\r\n await this.fileStorageService.commit(updateDto.attachmentTempIds, {\r\n issueDate: issueDate ? new Date(issueDate) : undefined,\r\n documentType: 'Correspondence',\r\n });\r\n }\r\n\r\n // 5. Update Recipients if provided\r\n if (updResolvedRecipients) {\r\n const recipientRepo = this.dataSource.getRepository(\r\n CorrespondenceRecipient\r\n );\r\n await recipientRepo.delete({ correspondenceId: id });\r\n\r\n const newRecipients = updResolvedRecipients.map((r) =>\r\n recipientRepo.create({\r\n correspondenceId: id,\r\n recipientOrganizationId: r.organizationId,\r\n recipientType: r.type,\r\n })\r\n );\r\n await recipientRepo.save(newRecipients);\r\n }\r\n\r\n // 6. Regenerate Document Number if structural fields changed (Recipient, Discipline, Type, Project)\r\n // AND it is a DRAFT.\r\n\r\n // Fetch fresh data for context and comparison\r\n const currentCorr = await this.correspondenceRepo.findOne({\r\n where: { id },\r\n relations: ['type', 'recipients', 'recipients.recipientOrganization'],\r\n });\r\n\r\n if (currentCorr) {\r\n const currentToRecipient = currentCorr.recipients?.find(\r\n (r) => r.recipientType === 'TO'\r\n );\r\n const currentRecipientId = currentToRecipient?.recipientOrganizationId;\r\n\r\n // Check for ACTUAL value changes\r\n const isProjectChanged =\r\n updResolvedProjectId !== undefined &&\r\n updResolvedProjectId !== currentCorr.projectId;\r\n const isOriginatorChanged =\r\n updResolvedOriginatorId !== undefined &&\r\n updResolvedOriginatorId !== currentCorr.originatorId;\r\n const isDisciplineChanged =\r\n updateDto.disciplineId !== undefined &&\r\n updateDto.disciplineId !== currentCorr.disciplineId;\r\n const isTypeChanged =\r\n updateDto.typeId !== undefined &&\r\n updateDto.typeId !== currentCorr.correspondenceTypeId;\r\n\r\n let isRecipientChanged = false;\r\n let newRecipientId: number | undefined;\r\n\r\n if (updResolvedRecipients) {\r\n const newToRecipient = updResolvedRecipients.find(\r\n (r) => r.type === 'TO'\r\n );\r\n newRecipientId = newToRecipient?.organizationId;\r\n\r\n if (newRecipientId !== currentRecipientId) {\r\n isRecipientChanged = true;\r\n }\r\n }\r\n\r\n if (\r\n isProjectChanged ||\r\n isDisciplineChanged ||\r\n isTypeChanged ||\r\n isRecipientChanged ||\r\n isOriginatorChanged\r\n ) {\r\n const targetRecipientId = isRecipientChanged\r\n ? newRecipientId\r\n : currentRecipientId;\r\n\r\n // Resolve Recipient Code for the NEW context\r\n let recipientCode = '';\r\n if (targetRecipientId) {\r\n const recOrg = await this.dataSource.manager.findOne(Organization, {\r\n where: { id: targetRecipientId },\r\n });\r\n if (recOrg) recipientCode = recOrg.organizationCode;\r\n }\r\n\r\n // [Fix #6] Fetch real ORG Code from originator organization\r\n const originatorOrgForUpdate = await this.dataSource.manager.findOne(\r\n Organization,\r\n {\r\n where: {\r\n id: updResolvedOriginatorId ?? currentCorr.originatorId ?? 0,\r\n },\r\n }\r\n );\r\n const orgCode = originatorOrgForUpdate?.organizationCode ?? 'UNK';\r\n\r\n // Prepare Contexts\r\n const oldCtx = {\r\n projectId: currentCorr.projectId,\r\n originatorOrganizationId: currentCorr.originatorId ?? 0,\r\n typeId: currentCorr.correspondenceTypeId,\r\n disciplineId: currentCorr.disciplineId,\r\n recipientOrganizationId: currentRecipientId,\r\n year: new Date().getFullYear(),\r\n };\r\n\r\n const newCtx = {\r\n projectId: updResolvedProjectId ?? currentCorr.projectId,\r\n originatorOrganizationId:\r\n updResolvedOriginatorId ?? currentCorr.originatorId ?? 0,\r\n typeId: updateDto.typeId ?? currentCorr.correspondenceTypeId,\r\n disciplineId: updateDto.disciplineId ?? currentCorr.disciplineId,\r\n recipientOrganizationId: targetRecipientId,\r\n year: new Date().getFullYear(),\r\n userId: user.user_id, // Pass User ID for Audit\r\n customTokens: {\r\n TYPE_CODE: currentCorr.type?.typeCode || '',\r\n ORG_CODE: orgCode,\r\n RECIPIENT_CODE: recipientCode,\r\n REC_CODE: recipientCode,\r\n },\r\n };\r\n\r\n // If Type Changed, need NEW Type Code\r\n if (isTypeChanged) {\r\n const newType = await this.typeRepo.findOne({\r\n where: { id: newCtx.typeId },\r\n });\r\n if (newType) newCtx.customTokens.TYPE_CODE = newType.typeCode;\r\n }\r\n\r\n const newDocNumber = await this.numberingService.updateNumberForDraft(\r\n currentCorr.correspondenceNumber,\r\n oldCtx,\r\n newCtx\r\n );\r\n\r\n await this.correspondenceRepo.update(id, {\r\n correspondenceNumber: newDocNumber,\r\n });\r\n }\r\n }\r\n\r\n const updated = await this.findOne(id);\r\n\r\n // Re-index updated document in Elasticsearch (fire-and-forget)\r\n void this.searchService.indexDocument({\r\n id: updated.id,\r\n publicId: updated.publicId,\r\n type: 'correspondence',\r\n docNumber: updated.correspondenceNumber,\r\n title: updateDto.subject ?? updated.revisions?.[0]?.subject,\r\n description: updateDto.description ?? updated.revisions?.[0]?.description,\r\n status: 'DRAFT',\r\n projectId: updated.projectId,\r\n createdAt: updated.createdAt,\r\n });\r\n\r\n return updated;\r\n }\r\n\r\n async previewDocumentNumber(createDto: CreateCorrespondenceDto, user: User) {\r\n // ADR-019: Resolve UUID references\r\n const previewProjectId = await this.uuidResolver.resolveProjectId(\r\n createDto.projectId\r\n );\r\n const previewOriginatorId = createDto.originatorId\r\n ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId)\r\n : undefined;\r\n const previewRecipients = createDto.recipients\r\n ? await Promise.all(\r\n createDto.recipients.map(\r\n async (r): Promise => ({\r\n organizationId: await this.uuidResolver.resolveOrganizationId(\r\n r.organizationId\r\n ),\r\n type: r.type,\r\n })\r\n )\r\n )\r\n : undefined;\r\n\r\n const type = await this.typeRepo.findOne({\r\n where: { id: createDto.typeId },\r\n });\r\n if (!type) throw new NotFoundException('Document Type not found');\r\n\r\n let userOrgId = user.primaryOrganizationId;\r\n if (!userOrgId) {\r\n const fullUser = await this.userService.findOne(user.user_id);\r\n if (fullUser) userOrgId = fullUser.primaryOrganizationId;\r\n }\r\n\r\n if (previewOriginatorId && previewOriginatorId !== userOrgId) {\r\n // Allow impersonation for preview\r\n userOrgId = previewOriginatorId;\r\n }\r\n\r\n // Extract recipient from recipients array\r\n const toRecipient = previewRecipients?.find((r) => r.type === 'TO');\r\n const recipientOrganizationId = toRecipient?.organizationId;\r\n\r\n let recipientCode = '';\r\n if (recipientOrganizationId) {\r\n const recOrg = await this.dataSource.manager.findOne(Organization, {\r\n where: { id: recipientOrganizationId },\r\n });\r\n if (recOrg) recipientCode = recOrg.organizationCode;\r\n }\r\n\r\n return this.numberingService.previewNumber({\r\n projectId: previewProjectId,\r\n originatorOrganizationId: userOrgId!,\r\n typeId: createDto.typeId,\r\n disciplineId: createDto.disciplineId,\r\n subTypeId: createDto.subTypeId,\r\n recipientOrganizationId,\r\n year: new Date().getFullYear(),\r\n customTokens: {\r\n TYPE_CODE: type.typeCode,\r\n RECIPIENT_CODE: recipientCode,\r\n REC_CODE: recipientCode,\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Business Rule Implementation: EC-CORR-001 - Cancel Correspondence with Downstream Circulation\r\n * Cancel correspondence and handle related circulations\r\n */\r\n async cancel(publicId: string, reason: string, user: User) {\r\n const correspondence = await this.findOneByUuid(publicId);\r\n\r\n // Check if user has permission to cancel (Org Admin or Superadmin only)\r\n const permissions = await this.userService.getUserPermissions(user.user_id);\r\n const canCancel =\r\n permissions.includes('correspondence.cancel') ||\r\n permissions.includes('system.manage_all');\r\n\r\n if (!canCancel) {\r\n throw new ForbiddenException(\r\n 'Only administrators can cancel correspondences'\r\n );\r\n }\r\n\r\n // Check if there are any active circulations\r\n const circulationRepo = this.dataSource.getRepository('Circulation');\r\n const activeCirculations = await circulationRepo.find({\r\n where: {\r\n correspondenceId: correspondence.id,\r\n status: 'OPEN',\r\n },\r\n });\r\n\r\n const warningMessage =\r\n activeCirculations.length > 0\r\n ? `There are ${activeCirculations.length} active circulation(s) for this correspondence. Canceling will force close all related circulations.`\r\n : '';\r\n\r\n // Get the current revision to update status\r\n const currentRevision = await this.revisionRepo.findOne({\r\n where: {\r\n correspondenceId: correspondence.id,\r\n isCurrent: true,\r\n },\r\n });\r\n\r\n if (!currentRevision) {\r\n throw new NotFoundException('Current revision not found');\r\n }\r\n\r\n // Get cancelled status\r\n const cancelledStatus = await this.statusRepo.findOne({\r\n where: { statusCode: 'CANCELLED' },\r\n });\r\n\r\n if (!cancelledStatus) {\r\n throw new InternalServerErrorException('CANCELLED status not found');\r\n }\r\n\r\n const queryRunner = this.dataSource.createQueryRunner();\r\n await queryRunner.connect();\r\n await queryRunner.startTransaction();\r\n\r\n try {\r\n // Update correspondence revision status to CANCELLED\r\n await queryRunner.manager.update(\r\n CorrespondenceRevision,\r\n currentRevision.id,\r\n {\r\n statusId: cancelledStatus.id,\r\n remarks: `Cancelled: ${reason}`,\r\n }\r\n );\r\n\r\n // Force close all active circulations\r\n if (activeCirculations.length > 0) {\r\n await queryRunner.manager.update(\r\n 'Circulation',\r\n {\r\n correspondenceId: correspondence.id,\r\n status: 'OPEN',\r\n },\r\n {\r\n status: 'FORCE_CLOSED',\r\n closedAt: new Date(),\r\n closedBy: user.user_id,\r\n closeReason: `Correspondence cancelled: ${reason}`,\r\n }\r\n );\r\n }\r\n\r\n await queryRunner.commitTransaction();\r\n\r\n // Re-index cancelled status in Elasticsearch (fire-and-forget)\r\n void this.searchService.indexDocument({\r\n id: correspondence.id,\r\n publicId: correspondence.publicId,\r\n type: 'correspondence',\r\n docNumber: correspondence.correspondenceNumber,\r\n title: currentRevision.subject,\r\n status: 'CANCELLED',\r\n projectId: correspondence.projectId,\r\n createdAt: correspondence.createdAt,\r\n });\r\n\r\n // Notify originator's doc-control user about cancellation (fire-and-forget)\r\n if (correspondence.originatorId) {\r\n void this.userService\r\n .findDocControlIdByOrg(correspondence.originatorId)\r\n .then((targetUserId) => {\r\n if (targetUserId) {\r\n void this.notificationService.send({\r\n userId: targetUserId,\r\n title: 'Correspondence Cancelled',\r\n message: `${correspondence.correspondenceNumber} — ${currentRevision.subject} has been cancelled. Reason: ${reason}`,\r\n type: 'EMAIL',\r\n entityType: 'correspondence',\r\n entityId: correspondence.id,\r\n link: `/correspondences/${correspondence.publicId}`,\r\n });\r\n }\r\n })\r\n .catch((err: Error) =>\r\n this.logger.warn(`Cancel notification failed: ${err.message}`)\r\n );\r\n }\r\n\r\n return {\r\n success: true,\r\n message: warningMessage || 'Correspondence cancelled successfully',\r\n activeCirculationsCount: activeCirculations.length,\r\n };\r\n } catch (error) {\r\n await queryRunner.rollbackTransaction();\r\n this.logger.error(\r\n `Failed to cancel correspondence: ${(error as Error).message}`\r\n );\r\n throw error;\r\n } finally {\r\n await queryRunner.release();\r\n }\r\n }\r\n\r\n async bulkCancel(\r\n publicIds: string[],\r\n reason: string,\r\n user: User\r\n ): Promise<{ succeeded: string[]; failed: string[] }> {\r\n const succeeded: string[] = [];\r\n const failed: string[] = [];\r\n\r\n for (const publicId of publicIds) {\r\n try {\r\n await this.cancel(publicId, reason, user);\r\n succeeded.push(publicId);\r\n } catch {\r\n failed.push(publicId);\r\n }\r\n }\r\n\r\n return { succeeded, failed };\r\n }\r\n\r\n async exportCsv(searchDto: SearchCorrespondenceDto): Promise {\r\n const { data } = await this.findAll(searchDto);\r\n\r\n const header = [\r\n 'Document No.',\r\n 'Rev',\r\n 'Subject',\r\n 'Type',\r\n 'Status',\r\n 'Project',\r\n 'From',\r\n 'Due Date',\r\n 'Created At',\r\n ];\r\n const rows = data.map((rev) => {\r\n const corr = rev.correspondence ?? (rev as unknown as Correspondence);\r\n return [\r\n this.escapeCsv(corr.correspondenceNumber ?? ''),\r\n this.escapeCsv(rev.revisionLabel ?? String(rev.revisionNumber ?? 0)),\r\n this.escapeCsv(rev.subject ?? ''),\r\n this.escapeCsv(corr.type?.typeCode ?? ''),\r\n this.escapeCsv(rev.status?.statusCode ?? ''),\r\n this.escapeCsv(corr.project?.projectCode ?? ''),\r\n this.escapeCsv(corr.originator?.organizationCode ?? ''),\r\n rev.dueDate ? new Date(rev.dueDate).toISOString().split('T')[0] : '',\r\n new Date(rev.createdAt).toISOString().split('T')[0],\r\n ].join(',');\r\n });\r\n\r\n return [header.join(','), ...rows].join('\\n');\r\n }\r\n\r\n private escapeCsv(value: string): string {\r\n if (value.includes(',') || value.includes('\"') || value.includes('\\n')) {\r\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\r\n }\r\n return value;\r\n }\r\n}\r\n"],"version":3} \ No newline at end of file diff --git a/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/6e/correspondenceservicespec_6e17e53289c744ad0b09ce4420c50e0e b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/6e/correspondenceservicespec_6e17e53289c744ad0b09ce4420c50e0e new file mode 100644 index 0000000..4ad2f15 --- /dev/null +++ b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/6e/correspondenceservicespec_6e17e53289c744ad0b09ce4420c50e0e @@ -0,0 +1,561 @@ +418931856593ad4d29dae51441c354ab +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const testing_1 = require("@nestjs/testing"); +const typeorm_1 = require("@nestjs/typeorm"); +const typeorm_2 = require("typeorm"); +const correspondence_service_1 = require("./correspondence.service"); +const correspondence_entity_1 = require("./entities/correspondence.entity"); +const correspondence_revision_entity_1 = require("./entities/correspondence-revision.entity"); +const correspondence_type_entity_1 = require("./entities/correspondence-type.entity"); +const correspondence_status_entity_1 = require("./entities/correspondence-status.entity"); +const correspondence_reference_entity_1 = require("./entities/correspondence-reference.entity"); +const correspondence_tag_entity_1 = require("./entities/correspondence-tag.entity"); +const organization_entity_1 = require("../organization/entities/organization.entity"); +const correspondence_recipient_entity_1 = require("./entities/correspondence-recipient.entity"); +const document_numbering_service_1 = require("../document-numbering/services/document-numbering.service"); +const json_schema_service_1 = require("../json-schema/json-schema.service"); +const workflow_engine_service_1 = require("../workflow-engine/workflow-engine.service"); +const user_service_1 = require("../user/user.service"); +const search_service_1 = require("../search/search.service"); +const file_storage_service_1 = require("../../common/file-storage/file-storage.service"); +const uuid_resolver_service_1 = require("../../common/services/uuid-resolver.service"); +const notification_service_1 = require("../notification/notification.service"); +describe('CorrespondenceService', () => { + let service; + let numberingService; + let correspondenceRepo; + let revisionRepo; + let testingModule; + let _dataSource; + const createMockRepository = () => ({ + find: jest.fn(), + findOne: jest.fn(), + create: jest.fn(), + save: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + softDelete: jest.fn(), + createQueryBuilder: jest.fn(() => ({ + leftJoinAndSelect: jest.fn().mockReturnThis(), + where: jest.fn().mockReturnThis(), + andWhere: jest.fn().mockReturnThis(), + orderBy: jest.fn().mockReturnThis(), + skip: jest.fn().mockReturnThis(), + take: jest.fn().mockReturnThis(), + getOne: jest.fn().mockResolvedValue(null), + getMany: jest.fn().mockResolvedValue([]), + getManyAndCount: jest.fn().mockResolvedValue([[], 0]), + })), + }); + const mockDataSource = { + createQueryRunner: jest.fn(() => ({ + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn(), + save: jest.fn(), + findOne: jest.fn(), + }, + })), + getRepository: jest.fn(() => createMockRepository()), + manager: { + findOne: jest.fn(), + }, + }; + beforeEach(async () => { + testingModule = await testing_1.Test.createTestingModule({ + providers: [ + correspondence_service_1.CorrespondenceService, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_entity_1.Correspondence), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_revision_entity_1.CorrespondenceRevision), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_status_entity_1.CorrespondenceStatus), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_reference_entity_1.CorrespondenceReference), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_tag_entity_1.CorrespondenceTag), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(organization_entity_1.Organization), + useValue: createMockRepository(), + }, + { + provide: (0, typeorm_1.getRepositoryToken)(correspondence_recipient_entity_1.CorrespondenceRecipient), + useValue: createMockRepository(), + }, + { + provide: document_numbering_service_1.DocumentNumberingService, + useValue: { + generateNextNumber: jest.fn(), + updateNumberForDraft: jest.fn(), + previewNextNumber: jest.fn(), + }, + }, + { + provide: json_schema_service_1.JsonSchemaService, + useValue: { validate: jest.fn() }, + }, + { + provide: workflow_engine_service_1.WorkflowEngineService, + useValue: { createInstance: jest.fn() }, + }, + { + provide: user_service_1.UserService, + useValue: { + findOne: jest.fn(), + getUserPermissions: jest.fn().mockResolvedValue([]), + }, + }, + { + provide: typeorm_2.DataSource, + useValue: mockDataSource, + }, + { + provide: search_service_1.SearchService, + useValue: { indexDocument: jest.fn() }, + }, + { + provide: file_storage_service_1.FileStorageService, + useValue: { commit: jest.fn().mockResolvedValue([]) }, + }, + { + provide: uuid_resolver_service_1.UuidResolverService, + useValue: { + resolveProjectId: jest.fn().mockResolvedValue(1), + resolveOrganizationId: jest.fn().mockResolvedValue(1), + }, + }, + { + provide: notification_service_1.NotificationService, + useValue: { send: jest.fn().mockResolvedValue(undefined) }, + }, + ], + }).compile(); + service = testingModule.get(correspondence_service_1.CorrespondenceService); + numberingService = testingModule.get(document_numbering_service_1.DocumentNumberingService); + correspondenceRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_entity_1.Correspondence)); + revisionRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_revision_entity_1.CorrespondenceRevision)); + _dataSource = testingModule.get(typeorm_2.DataSource); + }); + it('should be defined', () => { + expect(service).toBeDefined(); + }); + describe('update', () => { + it('should NOT regenerate number if critical fields unchanged', async () => { + const mockUser = { id: 1, primaryOrganizationId: 10 }; + const mockRevision = { + id: 100, + correspondenceId: 1, + isCurrent: true, + statusId: 5, + }; + jest + .spyOn(revisionRepo, 'findOne') + .mockResolvedValue(mockRevision); + const mockCorr = { + id: 1, + projectId: 1, + correspondenceTypeId: 2, + disciplineId: 3, + originatorId: 10, + correspondenceNumber: 'OLD-NUM', + recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }], + }; + jest + .spyOn(correspondenceRepo, 'findOne') + .mockResolvedValue(mockCorr); + const updateDto = { + projectId: 1, + disciplineId: 3, + }; + await service.update(1, updateDto, mockUser); + expect(numberingService.updateNumberForDraft).not.toHaveBeenCalled(); + }); + it('should regenerate number if Project ID changes', async () => { + const mockUser = { id: 1, primaryOrganizationId: 10 }; + const mockRevision = { + id: 100, + correspondenceId: 1, + isCurrent: true, + statusId: 5, + }; + jest + .spyOn(revisionRepo, 'findOne') + .mockResolvedValue(mockRevision); + const mockCorr = { + id: 1, + projectId: 1, + correspondenceTypeId: 2, + disciplineId: 3, + originatorId: 10, + correspondenceNumber: 'OLD-NUM', + recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }], + }; + jest + .spyOn(correspondenceRepo, 'findOne') + .mockResolvedValue(mockCorr); + const updateDto = { + projectId: 2, + }; + const uuidResolver = testingModule.get(uuid_resolver_service_1.UuidResolverService); + uuidResolver.resolveProjectId.mockResolvedValue(2); + await service.update(1, updateDto, mockUser); + expect(numberingService.updateNumberForDraft).toHaveBeenCalled(); + }); + it('should regenerate number if Document Type changes', async () => { + const mockUser = { id: 1, primaryOrganizationId: 10 }; + const mockRevision = { + id: 100, + correspondenceId: 1, + isCurrent: true, + statusId: 5, + }; + jest + .spyOn(revisionRepo, 'findOne') + .mockResolvedValue(mockRevision); + const mockCorr = { + id: 1, + projectId: 1, + correspondenceTypeId: 2, + disciplineId: 3, + originatorId: 10, + correspondenceNumber: 'OLD-NUM', + recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }], + }; + jest + .spyOn(correspondenceRepo, 'findOne') + .mockResolvedValue(mockCorr); + const updateDto = { + typeId: 999, + }; + const typeRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType)); + typeRepo.findOne.mockResolvedValue({ + id: 999, + typeCode: 'NEW-TYPE', + }); + await service.update(1, updateDto, mockUser); + expect(numberingService.updateNumberForDraft).toHaveBeenCalled(); + }); + it('should regenerate number if Recipient Organization changes', async () => { + const mockUser = { id: 1, primaryOrganizationId: 10 }; + const mockRevision = { + id: 100, + correspondenceId: 1, + isCurrent: true, + statusId: 5, + }; + jest + .spyOn(revisionRepo, 'findOne') + .mockResolvedValue(mockRevision); + const mockCorr = { + id: 1, + projectId: 1, + correspondenceTypeId: 2, + disciplineId: 3, + originatorId: 10, + correspondenceNumber: 'OLD-NUM', + recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }], + }; + jest + .spyOn(correspondenceRepo, 'findOne') + .mockResolvedValue(mockCorr); + // Access DataSource manager for mocking + mockDataSource.manager.findOne.mockResolvedValue({ + id: 88, + organizationCode: 'NEW-ORG', + }); + const updateDto = { + recipients: [{ type: 'TO', organizationId: 88 }], + }; + await service.update(1, updateDto, mockUser); + expect(numberingService.updateNumberForDraft).toHaveBeenCalled(); + }); + }); + describe('create', () => { + it('should allow system.manage_all user without primaryOrganizationId when originatorId is provided', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: null, + }; + const createDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + originatorId: 'originator-uuid', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + const userService = testingModule.get(user_service_1.UserService); + const typeRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType)); + const statusRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_status_entity_1.CorrespondenceStatus)); + const uuidResolver = testingModule.get(uuid_resolver_service_1.UuidResolverService); + userService.findOne.mockResolvedValue({ + user_id: 1, + primaryOrganizationId: null, + }); + userService.getUserPermissions.mockResolvedValue([ + 'system.manage_all', + ]); + uuidResolver.resolveProjectId.mockResolvedValue(100); + uuidResolver.resolveOrganizationId.mockImplementation((value) => { + if (value === 'originator-uuid') + return 10; + if (value === 'recipient-uuid') + return 20; + return 0; + }); + typeRepo.findOne.mockResolvedValue({ + id: 1, + typeCode: 'LTR', + }); + statusRepo.findOne.mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + numberingService.generateNextNumber.mockResolvedValue({ + number: 'DOC-001', + }); + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn((_entity, payload) => payload), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + mockDataSource.createQueryRunner.mockReturnValue(queryRunner); + await service.create(createDto, mockUser); + expect(queryRunner.manager.create).toHaveBeenCalledWith(correspondence_entity_1.Correspondence, expect.objectContaining({ originatorId: 10 })); + }); + it('should set revisionLabel to "A" for RFA type', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: 10, + }; + const createDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + const typeRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType)); + const statusRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_status_entity_1.CorrespondenceStatus)); + const uuidResolver = testingModule.get(uuid_resolver_service_1.UuidResolverService); + uuidResolver.resolveProjectId.mockResolvedValue(100); + uuidResolver.resolveOrganizationId.mockResolvedValue(20); + typeRepo.findOne.mockResolvedValue({ + id: 1, + typeCode: 'RFA', + }); + statusRepo.findOne.mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + numberingService.generateNextNumber.mockResolvedValue({ + number: 'DOC-001', + }); + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn((_entity, payload) => payload), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + mockDataSource.createQueryRunner.mockReturnValue(queryRunner); + await service.create(createDto, mockUser); + expect(queryRunner.manager.create).toHaveBeenCalledWith(correspondence_revision_entity_1.CorrespondenceRevision, expect.objectContaining({ revisionLabel: 'A' })); + }); + it('should set revisionLabel to "A" for RFI type', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: 10, + }; + const createDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + const typeRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType)); + const statusRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_status_entity_1.CorrespondenceStatus)); + const uuidResolver = testingModule.get(uuid_resolver_service_1.UuidResolverService); + uuidResolver.resolveProjectId.mockResolvedValue(100); + uuidResolver.resolveOrganizationId.mockResolvedValue(20); + typeRepo.findOne.mockResolvedValue({ + id: 1, + typeCode: 'RFI', + }); + statusRepo.findOne.mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + numberingService.generateNextNumber.mockResolvedValue({ + number: 'DOC-001', + }); + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn((_entity, payload) => payload), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + mockDataSource.createQueryRunner.mockReturnValue(queryRunner); + await service.create(createDto, mockUser); + expect(queryRunner.manager.create).toHaveBeenCalledWith(correspondence_revision_entity_1.CorrespondenceRevision, expect.objectContaining({ revisionLabel: 'A' })); + }); + it('should set revisionLabel to null for LETTER type', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: 10, + }; + const createDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + const typeRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType)); + const statusRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_status_entity_1.CorrespondenceStatus)); + const uuidResolver = testingModule.get(uuid_resolver_service_1.UuidResolverService); + uuidResolver.resolveProjectId.mockResolvedValue(100); + uuidResolver.resolveOrganizationId.mockResolvedValue(20); + typeRepo.findOne.mockResolvedValue({ + id: 1, + typeCode: 'LETTER', + }); + statusRepo.findOne.mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + numberingService.generateNextNumber.mockResolvedValue({ + number: 'DOC-001', + }); + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn((_entity, payload) => payload), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + mockDataSource.createQueryRunner.mockReturnValue(queryRunner); + await service.create(createDto, mockUser); + expect(queryRunner.manager.create).toHaveBeenCalledWith(correspondence_revision_entity_1.CorrespondenceRevision, expect.objectContaining({ revisionLabel: null })); + }); + it('should set revisionLabel to null for MEMO type', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: 10, + }; + const createDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + const typeRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_type_entity_1.CorrespondenceType)); + const statusRepo = testingModule.get((0, typeorm_1.getRepositoryToken)(correspondence_status_entity_1.CorrespondenceStatus)); + const uuidResolver = testingModule.get(uuid_resolver_service_1.UuidResolverService); + uuidResolver.resolveProjectId.mockResolvedValue(100); + uuidResolver.resolveOrganizationId.mockResolvedValue(20); + typeRepo.findOne.mockResolvedValue({ + id: 1, + typeCode: 'MEMO', + }); + statusRepo.findOne.mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + numberingService.generateNextNumber.mockResolvedValue({ + number: 'DOC-001', + }); + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn((_entity, payload) => payload), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + mockDataSource.createQueryRunner.mockReturnValue(queryRunner); + await service.create(createDto, mockUser); + expect(queryRunner.manager.create).toHaveBeenCalledWith(correspondence_revision_entity_1.CorrespondenceRevision, expect.objectContaining({ revisionLabel: null })); + }); + }); +}); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoiRTpcXG5wLWRtc1xcbGNicDNcXGJhY2tlbmRcXHNyY1xcbW9kdWxlc1xcY29ycmVzcG9uZGVuY2VcXGNvcnJlc3BvbmRlbmNlLnNlcnZpY2Uuc3BlYy50cyIsIm1hcHBpbmdzIjoiOztBQUFBLDZDQUFzRDtBQUN0RCw2Q0FBcUQ7QUFDckQscUNBQWlEO0FBQ2pELHFFQUFpRTtBQUNqRSw0RUFBa0U7QUFDbEUsOEZBQW1GO0FBQ25GLHNGQUEyRTtBQUMzRSwwRkFBK0U7QUFDL0UsZ0dBQXFGO0FBQ3JGLG9GQUF5RTtBQUN6RSxzRkFBNEU7QUFDNUUsZ0dBQXFGO0FBQ3JGLDBHQUFxRztBQUNyRyw0RUFBdUU7QUFDdkUsd0ZBQW1GO0FBQ25GLHVEQUFtRDtBQUNuRCw2REFBeUQ7QUFDekQseUZBQW9GO0FBQ3BGLHVGQUFrRjtBQUNsRiwrRUFBMkU7QUFLM0UsUUFBUSxDQUFDLHVCQUF1QixFQUFFLEdBQUcsRUFBRTtJQUNyQyxJQUFJLE9BQThCLENBQUM7SUFDbkMsSUFBSSxnQkFBMEMsQ0FBQztJQUMvQyxJQUFJLGtCQUE4QyxDQUFDO0lBQ25ELElBQUksWUFBZ0QsQ0FBQztJQUNyRCxJQUFJLGFBQTRCLENBQUM7SUFDakMsSUFBSSxXQUF1QixDQUFDO0lBRTVCLE1BQU0sb0JBQW9CLEdBQUcsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUNsQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtRQUNmLE9BQU8sRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO1FBQ2xCLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO1FBQ2pCLElBQUksRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO1FBQ2YsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7UUFDakIsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7UUFDakIsVUFBVSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7UUFDckIsa0JBQWtCLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1lBQ2pD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QUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxvQkFBb0IsQ0FDckQsdURBQXNCLEVBQ3RCLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUNqRCxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIkU6XFxucC1kbXNcXGxjYnAzXFxiYWNrZW5kXFxzcmNcXG1vZHVsZXNcXGNvcnJlc3BvbmRlbmNlXFxjb3JyZXNwb25kZW5jZS5zZXJ2aWNlLnNwZWMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgVGVzdCwgVGVzdGluZ01vZHVsZSB9IGZyb20gJ0BuZXN0anMvdGVzdGluZyc7XHJcbmltcG9ydCB7IGdldFJlcG9zaXRvcnlUb2tlbiB9IGZyb20gJ0BuZXN0anMvdHlwZW9ybSc7XHJcbmltcG9ydCB7IERhdGFTb3VyY2UsIFJlcG9zaXRvcnkgfSBmcm9tICd0eXBlb3JtJztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VTZXJ2aWNlIH0gZnJvbSAnLi9jb3JyZXNwb25kZW5jZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2UgfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlUmV2aXNpb24gfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLXJldmlzaW9uLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlVHlwZSB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2UtdHlwZS5lbnRpdHknO1xyXG5pbXBvcnQgeyBDb3JyZXNwb25kZW5jZVN0YXR1cyB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2Utc3RhdHVzLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlUmVmZXJlbmNlIH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS1yZWZlcmVuY2UuZW50aXR5JztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VUYWcgfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLXRhZy5lbnRpdHknO1xyXG5pbXBvcnQgeyBPcmdhbml6YXRpb24gfSBmcm9tICcuLi9vcmdhbml6YXRpb24vZW50aXRpZXMvb3JnYW5pemF0aW9uLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlUmVjaXBpZW50IH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS1yZWNpcGllbnQuZW50aXR5JztcclxuaW1wb3J0IHsgRG9jdW1lbnROdW1iZXJpbmdTZXJ2aWNlIH0gZnJvbSAnLi4vZG9jdW1lbnQtbnVtYmVyaW5nL3NlcnZpY2VzL2RvY3VtZW50LW51bWJlcmluZy5zZXJ2aWNlJztcclxuaW1wb3J0IHsgSnNvblNjaGVtYVNlcnZpY2UgfSBmcm9tICcuLi9qc29uLXNjaGVtYS9qc29uLXNjaGVtYS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgV29ya2Zsb3dFbmdpbmVTZXJ2aWNlIH0gZnJvbSAnLi4vd29ya2Zsb3ctZW5naW5lL3dvcmtmbG93LWVuZ2luZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgVXNlclNlcnZpY2UgfSBmcm9tICcuLi91c2VyL3VzZXIuc2VydmljZSc7XHJcbmltcG9ydCB7IFNlYXJjaFNlcnZpY2UgfSBmcm9tICcuLi9zZWFyY2gvc2VhcmNoLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBGaWxlU3RvcmFnZVNlcnZpY2UgfSBmcm9tICcuLi8uLi9jb21tb24vZmlsZS1zdG9yYWdlL2ZpbGUtc3RvcmFnZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgVXVpZFJlc29sdmVyU2VydmljZSB9IGZyb20gJy4uLy4uL2NvbW1vbi9zZXJ2aWNlcy91dWlkLXJlc29sdmVyLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBOb3RpZmljYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi4vbm90aWZpY2F0aW9uL25vdGlmaWNhdGlvbi5zZXJ2aWNlJztcclxuaW1wb3J0IHsgVXBkYXRlQ29ycmVzcG9uZGVuY2VEdG8gfSBmcm9tICcuL2R0by91cGRhdGUtY29ycmVzcG9uZGVuY2UuZHRvJztcclxuaW1wb3J0IHsgQ3JlYXRlQ29ycmVzcG9uZGVuY2VEdG8gfSBmcm9tICcuL2R0by9jcmVhdGUtY29ycmVzcG9uZGVuY2UuZHRvJztcclxuaW1wb3J0IHsgVXNlciB9IGZyb20gJy4uL3VzZXIvZW50aXRpZXMvdXNlci5lbnRpdHknO1xyXG5cclxuZGVzY3JpYmUoJ0NvcnJlc3BvbmRlbmNlU2VydmljZScsICgpID0+IHtcclxuICBsZXQgc2VydmljZTogQ29ycmVzcG9uZGVuY2VTZXJ2aWNlO1xyXG4gIGxldCBudW1iZXJpbmdTZXJ2aWNlOiBEb2N1bWVudE51bWJlcmluZ1NlcnZpY2U7XHJcbiAgbGV0IGNvcnJlc3BvbmRlbmNlUmVwbzogUmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZT47XHJcbiAgbGV0IHJldmlzaW9uUmVwbzogUmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVJldmlzaW9uPjtcclxuICBsZXQgdGVzdGluZ01vZHVsZTogVGVzdGluZ01vZHVsZTtcclxuICBsZXQgX2RhdGFTb3VyY2U6IERhdGFTb3VyY2U7XHJcblxyXG4gIGNvbnN0IGNyZWF0ZU1vY2tSZXBvc2l0b3J5ID0gKCkgPT4gKHtcclxuICAgIGZpbmQ6IGplc3QuZm4oKSxcclxuICAgIGZpbmRPbmU6IGplc3QuZm4oKSxcclxuICAgIGNyZWF0ZTogamVzdC5mbigpLFxyXG4gICAgc2F2ZTogamVzdC5mbigpLFxyXG4gICAgdXBkYXRlOiBqZXN0LmZuKCksXHJcbiAgICBkZWxldGU6IGplc3QuZm4oKSxcclxuICAgIHNvZnREZWxldGU6IGplc3QuZm4oKSxcclxuICAgIGNyZWF0ZVF1ZXJ5QnVpbGRlcjogamVzdC5mbigoKSA9PiAoe1xyXG4gICAgICBsZWZ0Sm9pbkFuZFNlbGVjdDogamVzdC5mbigpLm1vY2tSZXR1cm5UaGlzKCksXHJcbiAgICAgIHdoZXJlOiBqZXN0LmZuKCkubW9ja1JldHVyblRoaXMoKSxcclxuICAgICAgYW5kV2hlcmU6IGplc3QuZm4oKS5tb2NrUmV0dXJuVGhpcygpLFxyXG4gICAgICBvcmRlckJ5OiBqZXN0LmZuKCkubW9ja1JldHVyblRoaXMoKSxcclxuICAgICAgc2tpcDogamVzdC5mbigpLm1vY2tSZXR1cm5UaGlzKCksXHJcbiAgICAgIHRha2U6IGplc3QuZm4oKS5tb2NrUmV0dXJuVGhpcygpLFxyXG4gICAgICBnZXRPbmU6IGplc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZShudWxsKSxcclxuICAgICAgZ2V0TWFueTogamVzdC5mbigpLm1vY2tSZXNvbHZlZFZhbHVlKFtdKSxcclxuICAgICAgZ2V0TWFueUFuZENvdW50OiBqZXN0LmZuKCkubW9ja1Jlc29sdmVkVmFsdWUoW1tdLCAwXSksXHJcbiAgICB9KSksXHJcbiAgfSk7XHJcblxyXG4gIGNvbnN0IG1vY2tEYXRhU291cmNlID0ge1xyXG4gICAgY3JlYXRlUXVlcnlSdW5uZXI6IGplc3QuZm4oKCkgPT4gKHtcclxuICAgICAgY29ubmVjdDogamVzdC5mbigpLFxyXG4gICAgICBzdGFydFRyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgIGNvbW1pdFRyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgIHJvbGxiYWNrVHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgcmVsZWFzZTogamVzdC5mbigpLFxyXG4gICAgICBtYW5hZ2VyOiB7XHJcbiAgICAgICAgY3JlYXRlOiBqZXN0LmZuKCksXHJcbiAgICAgICAgc2F2ZTogamVzdC5mbigpLFxyXG4gICAgICAgIGZpbmRPbmU6IGplc3QuZm4oKSxcclxuICAgICAgfSxcclxuICAgIH0pKSxcclxuICAgIGdldFJlcG9zaXRvcnk6IGplc3QuZm4oKCkgPT4gY3JlYXRlTW9ja1JlcG9zaXRvcnkoKSksXHJcbiAgICBtYW5hZ2VyOiB7XHJcbiAgICAgIGZpbmRPbmU6IGplc3QuZm4oKSxcclxuICAgIH0sXHJcbiAgfTtcclxuXHJcbiAgYmVmb3JlRWFjaChhc3luYyAoKSA9PiB7XHJcbiAgICB0ZXN0aW5nTW9kdWxlID0gYXdhaXQgVGVzdC5jcmVhdGVUZXN0aW5nTW9kdWxlKHtcclxuICAgICAgcHJvdmlkZXJzOiBbXHJcbiAgICAgICAgQ29ycmVzcG9uZGVuY2VTZXJ2aWNlLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZSksXHJcbiAgICAgICAgICB1c2VWYWx1ZTogY3JlYXRlTW9ja1JlcG9zaXRvcnkoKSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVJldmlzaW9uKSxcclxuICAgICAgICAgIHVzZVZhbHVlOiBjcmVhdGVNb2NrUmVwb3NpdG9yeSgpLFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcHJvdmlkZTogZ2V0UmVwb3NpdG9yeVRva2VuKENvcnJlc3BvbmRlbmNlVHlwZSksXHJcbiAgICAgICAgICB1c2VWYWx1ZTogY3JlYXRlTW9ja1JlcG9zaXRvcnkoKSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVN0YXR1cyksXHJcbiAgICAgICAgICB1c2VWYWx1ZTogY3JlYXRlTW9ja1JlcG9zaXRvcnkoKSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVJlZmVyZW5jZSksXHJcbiAgICAgICAgICB1c2VWYWx1ZTogY3JlYXRlTW9ja1JlcG9zaXRvcnkoKSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVRhZyksXHJcbiAgICAgICAgICB1c2VWYWx1ZTogY3JlYXRlTW9ja1JlcG9zaXRvcnkoKSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IGdldFJlcG9zaXRvcnlUb2tlbihPcmdhbml6YXRpb24pLFxyXG4gICAgICAgICAgdXNlVmFsdWU6IGNyZWF0ZU1vY2tSZXBvc2l0b3J5KCksXHJcbiAgICAgICAgfSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwcm92aWRlOiBnZXRSZXBvc2l0b3J5VG9rZW4oQ29ycmVzcG9uZGVuY2VSZWNpcGllbnQpLFxyXG4gICAgICAgICAgdXNlVmFsdWU6IGNyZWF0ZU1vY2tSZXBvc2l0b3J5KCksXHJcbiAgICAgICAgfSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwcm92aWRlOiBEb2N1bWVudE51bWJlcmluZ1NlcnZpY2UsXHJcbiAgICAgICAgICB1c2VWYWx1ZToge1xyXG4gICAgICAgICAgICBnZW5lcmF0ZU5leHROdW1iZXI6IGplc3QuZm4oKSxcclxuICAgICAgICAgICAgdXBkYXRlTnVtYmVyRm9yRHJhZnQ6IGplc3QuZm4oKSxcclxuICAgICAgICAgICAgcHJldmlld05leHROdW1iZXI6IGplc3QuZm4oKSxcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgfSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwcm92aWRlOiBKc29uU2NoZW1hU2VydmljZSxcclxuICAgICAgICAgIHVzZVZhbHVlOiB7IHZhbGlkYXRlOiBqZXN0LmZuKCkgfSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IFdvcmtmbG93RW5naW5lU2VydmljZSxcclxuICAgICAgICAgIHVzZVZhbHVlOiB7IGNyZWF0ZUluc3RhbmNlOiBqZXN0LmZuKCkgfSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IFVzZXJTZXJ2aWNlLFxyXG4gICAgICAgICAgdXNlVmFsdWU6IHtcclxuICAgICAgICAgICAgZmluZE9uZTogamVzdC5mbigpLFxyXG4gICAgICAgICAgICBnZXRVc2VyUGVybWlzc2lvbnM6IGplc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZShbXSksXHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcHJvdmlkZTogRGF0YVNvdXJjZSxcclxuICAgICAgICAgIHVzZVZhbHVlOiBtb2NrRGF0YVNvdXJjZSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IFNlYXJjaFNlcnZpY2UsXHJcbiAgICAgICAgICB1c2VWYWx1ZTogeyBpbmRleERvY3VtZW50OiBqZXN0LmZuKCkgfSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3ZpZGU6IEZpbGVTdG9yYWdlU2VydmljZSxcclxuICAgICAgICAgIHVzZVZhbHVlOiB7IGNvbW1pdDogamVzdC5mbigpLm1vY2tSZXNvbHZlZFZhbHVlKFtdKSB9LFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcHJvdmlkZTogVXVpZFJlc29sdmVyU2VydmljZSxcclxuICAgICAgICAgIHVzZVZhbHVlOiB7XHJcbiAgICAgICAgICAgIHJlc29sdmVQcm9qZWN0SWQ6IGplc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZSgxKSxcclxuICAgICAgICAgICAgcmVzb2x2ZU9yZ2FuaXphdGlvbklkOiBqZXN0LmZuKCkubW9ja1Jlc29sdmVkVmFsdWUoMSksXHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcHJvdmlkZTogTm90aWZpY2F0aW9uU2VydmljZSxcclxuICAgICAgICAgIHVzZVZhbHVlOiB7IHNlbmQ6IGplc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZSh1bmRlZmluZWQpIH0sXHJcbiAgICAgICAgfSxcclxuICAgICAgXSxcclxuICAgIH0pLmNvbXBpbGUoKTtcclxuXHJcbiAgICBzZXJ2aWNlID0gdGVzdGluZ01vZHVsZS5nZXQ8Q29ycmVzcG9uZGVuY2VTZXJ2aWNlPihDb3JyZXNwb25kZW5jZVNlcnZpY2UpO1xyXG4gICAgbnVtYmVyaW5nU2VydmljZSA9IHRlc3RpbmdNb2R1bGUuZ2V0PERvY3VtZW50TnVtYmVyaW5nU2VydmljZT4oXHJcbiAgICAgIERvY3VtZW50TnVtYmVyaW5nU2VydmljZVxyXG4gICAgKTtcclxuICAgIGNvcnJlc3BvbmRlbmNlUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2U+PihcclxuICAgICAgZ2V0UmVwb3NpdG9yeVRva2VuKENvcnJlc3BvbmRlbmNlKVxyXG4gICAgKTtcclxuICAgIHJldmlzaW9uUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VSZXZpc2lvbj4+KFxyXG4gICAgICBnZXRSZXBvc2l0b3J5VG9rZW4oQ29ycmVzcG9uZGVuY2VSZXZpc2lvbilcclxuICAgICk7XHJcbiAgICBfZGF0YVNvdXJjZSA9IHRlc3RpbmdNb2R1bGUuZ2V0PERhdGFTb3VyY2U+KERhdGFTb3VyY2UpO1xyXG4gIH0pO1xyXG5cclxuICBpdCgnc2hvdWxkIGJlIGRlZmluZWQnLCAoKSA9PiB7XHJcbiAgICBleHBlY3Qoc2VydmljZSkudG9CZURlZmluZWQoKTtcclxuICB9KTtcclxuXHJcbiAgZGVzY3JpYmUoJ3VwZGF0ZScsICgpID0+IHtcclxuICAgIGl0KCdzaG91bGQgTk9UIHJlZ2VuZXJhdGUgbnVtYmVyIGlmIGNyaXRpY2FsIGZpZWxkcyB1bmNoYW5nZWQnLCBhc3luYyAoKSA9PiB7XHJcbiAgICAgIGNvbnN0IG1vY2tVc2VyID0geyBpZDogMSwgcHJpbWFyeU9yZ2FuaXphdGlvbklkOiAxMCB9IGFzIHVua25vd24gYXMgVXNlcjtcclxuICAgICAgY29uc3QgbW9ja1JldmlzaW9uID0ge1xyXG4gICAgICAgIGlkOiAxMDAsXHJcbiAgICAgICAgY29ycmVzcG9uZGVuY2VJZDogMSxcclxuICAgICAgICBpc0N1cnJlbnQ6IHRydWUsXHJcbiAgICAgICAgc3RhdHVzSWQ6IDUsXHJcbiAgICAgIH07XHJcblxyXG4gICAgICBqZXN0XHJcbiAgICAgICAgLnNweU9uKHJldmlzaW9uUmVwbywgJ2ZpbmRPbmUnKVxyXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZShtb2NrUmV2aXNpb24gYXMgdW5rbm93biBhcyBDb3JyZXNwb25kZW5jZVJldmlzaW9uKTtcclxuXHJcbiAgICAgIGNvbnN0IG1vY2tDb3JyID0ge1xyXG4gICAgICAgIGlkOiAxLFxyXG4gICAgICAgIHByb2plY3RJZDogMSxcclxuICAgICAgICBjb3JyZXNwb25kZW5jZVR5cGVJZDogMixcclxuICAgICAgICBkaXNjaXBsaW5lSWQ6IDMsXHJcbiAgICAgICAgb3JpZ2luYXRvcklkOiAxMCxcclxuICAgICAgICBjb3JyZXNwb25kZW5jZU51bWJlcjogJ09MRC1OVU0nLFxyXG4gICAgICAgIHJlY2lwaWVudHM6IFt7IHJlY2lwaWVudFR5cGU6ICdUTycsIHJlY2lwaWVudE9yZ2FuaXphdGlvbklkOiA5OSB9XSxcclxuICAgICAgfTtcclxuICAgICAgamVzdFxyXG4gICAgICAgIC5zcHlPbihjb3JyZXNwb25kZW5jZVJlcG8sICdmaW5kT25lJylcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWUobW9ja0NvcnIgYXMgdW5rbm93biBhcyBDb3JyZXNwb25kZW5jZSk7XHJcblxyXG4gICAgICBjb25zdCB1cGRhdGVEdG86IFVwZGF0ZUNvcnJlc3BvbmRlbmNlRHRvID0ge1xyXG4gICAgICAgIHByb2plY3RJZDogMSxcclxuICAgICAgICBkaXNjaXBsaW5lSWQ6IDMsXHJcbiAgICAgIH07XHJcblxyXG4gICAgICBhd2FpdCBzZXJ2aWNlLnVwZGF0ZSgxLCB1cGRhdGVEdG8sIG1vY2tVc2VyKTtcclxuXHJcbiAgICAgIGV4cGVjdChcclxuICAgICAgICBudW1iZXJpbmdTZXJ2aWNlLnVwZGF0ZU51bWJlckZvckRyYWZ0IGFzIGplc3QuTW9ja1xyXG4gICAgICApLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBpdCgnc2hvdWxkIHJlZ2VuZXJhdGUgbnVtYmVyIGlmIFByb2plY3QgSUQgY2hhbmdlcycsIGFzeW5jICgpID0+IHtcclxuICAgICAgY29uc3QgbW9ja1VzZXIgPSB7IGlkOiAxLCBwcmltYXJ5T3JnYW5pemF0aW9uSWQ6IDEwIH0gYXMgdW5rbm93biBhcyBVc2VyO1xyXG4gICAgICBjb25zdCBtb2NrUmV2aXNpb24gPSB7XHJcbiAgICAgICAgaWQ6IDEwMCxcclxuICAgICAgICBjb3JyZXNwb25kZW5jZUlkOiAxLFxyXG4gICAgICAgIGlzQ3VycmVudDogdHJ1ZSxcclxuICAgICAgICBzdGF0dXNJZDogNSxcclxuICAgICAgfTtcclxuICAgICAgamVzdFxyXG4gICAgICAgIC5zcHlPbihyZXZpc2lvblJlcG8sICdmaW5kT25lJylcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWUobW9ja1JldmlzaW9uIGFzIHVua25vd24gYXMgQ29ycmVzcG9uZGVuY2VSZXZpc2lvbik7XHJcblxyXG4gICAgICBjb25zdCBtb2NrQ29yciA9IHtcclxuICAgICAgICBpZDogMSxcclxuICAgICAgICBwcm9qZWN0SWQ6IDEsXHJcbiAgICAgICAgY29ycmVzcG9uZGVuY2VUeXBlSWQ6IDIsXHJcbiAgICAgICAgZGlzY2lwbGluZUlkOiAzLFxyXG4gICAgICAgIG9yaWdpbmF0b3JJZDogMTAsXHJcbiAgICAgICAgY29ycmVzcG9uZGVuY2VOdW1iZXI6ICdPTEQtTlVNJyxcclxuICAgICAgICByZWNpcGllbnRzOiBbeyByZWNpcGllbnRUeXBlOiAnVE8nLCByZWNpcGllbnRPcmdhbml6YXRpb25JZDogOTkgfV0sXHJcbiAgICAgIH07XHJcbiAgICAgIGplc3RcclxuICAgICAgICAuc3B5T24oY29ycmVzcG9uZGVuY2VSZXBvLCAnZmluZE9uZScpXHJcbiAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlKG1vY2tDb3JyIGFzIHVua25vd24gYXMgQ29ycmVzcG9uZGVuY2UpO1xyXG5cclxuICAgICAgY29uc3QgdXBkYXRlRHRvOiBVcGRhdGVDb3JyZXNwb25kZW5jZUR0byA9IHtcclxuICAgICAgICBwcm9qZWN0SWQ6IDIsXHJcbiAgICAgIH07XHJcblxyXG4gICAgICBjb25zdCB1dWlkUmVzb2x2ZXIgPVxyXG4gICAgICAgIHRlc3RpbmdNb2R1bGUuZ2V0PFV1aWRSZXNvbHZlclNlcnZpY2U+KFV1aWRSZXNvbHZlclNlcnZpY2UpO1xyXG4gICAgICAodXVpZFJlc29sdmVyLnJlc29sdmVQcm9qZWN0SWQgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSgyKTtcclxuXHJcbiAgICAgIGF3YWl0IHNlcnZpY2UudXBkYXRlKDEsIHVwZGF0ZUR0bywgbW9ja1VzZXIpO1xyXG5cclxuICAgICAgZXhwZWN0KFxyXG4gICAgICAgIG51bWJlcmluZ1NlcnZpY2UudXBkYXRlTnVtYmVyRm9yRHJhZnQgYXMgamVzdC5Nb2NrXHJcbiAgICAgICkudG9IYXZlQmVlbkNhbGxlZCgpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgaXQoJ3Nob3VsZCByZWdlbmVyYXRlIG51bWJlciBpZiBEb2N1bWVudCBUeXBlIGNoYW5nZXMnLCBhc3luYyAoKSA9PiB7XHJcbiAgICAgIGNvbnN0IG1vY2tVc2VyID0geyBpZDogMSwgcHJpbWFyeU9yZ2FuaXphdGlvbklkOiAxMCB9IGFzIHVua25vd24gYXMgVXNlcjtcclxuICAgICAgY29uc3QgbW9ja1JldmlzaW9uID0ge1xyXG4gICAgICAgIGlkOiAxMDAsXHJcbiAgICAgICAgY29ycmVzcG9uZGVuY2VJZDogMSxcclxuICAgICAgICBpc0N1cnJlbnQ6IHRydWUsXHJcbiAgICAgICAgc3RhdHVzSWQ6IDUsXHJcbiAgICAgIH07XHJcbiAgICAgIGplc3RcclxuICAgICAgICAuc3B5T24ocmV2aXNpb25SZXBvLCAnZmluZE9uZScpXHJcbiAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlKG1vY2tSZXZpc2lvbiBhcyB1bmtub3duIGFzIENvcnJlc3BvbmRlbmNlUmV2aXNpb24pO1xyXG5cclxuICAgICAgY29uc3QgbW9ja0NvcnIgPSB7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgcHJvamVjdElkOiAxLFxyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlVHlwZUlkOiAyLFxyXG4gICAgICAgIGRpc2NpcGxpbmVJZDogMyxcclxuICAgICAgICBvcmlnaW5hdG9ySWQ6IDEwLFxyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlTnVtYmVyOiAnT0xELU5VTScsXHJcbiAgICAgICAgcmVjaXBpZW50czogW3sgcmVjaXBpZW50VHlwZTogJ1RPJywgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQ6IDk5IH1dLFxyXG4gICAgICB9O1xyXG4gICAgICBqZXN0XHJcbiAgICAgICAgLnNweU9uKGNvcnJlc3BvbmRlbmNlUmVwbywgJ2ZpbmRPbmUnKVxyXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZShtb2NrQ29yciBhcyB1bmtub3duIGFzIENvcnJlc3BvbmRlbmNlKTtcclxuXHJcbiAgICAgIGNvbnN0IHVwZGF0ZUR0bzogVXBkYXRlQ29ycmVzcG9uZGVuY2VEdG8gPSB7XHJcbiAgICAgICAgdHlwZUlkOiA5OTksXHJcbiAgICAgIH07XHJcblxyXG4gICAgICBjb25zdCB0eXBlUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VUeXBlPj4oXHJcbiAgICAgICAgZ2V0UmVwb3NpdG9yeVRva2VuKENvcnJlc3BvbmRlbmNlVHlwZSlcclxuICAgICAgKTtcclxuICAgICAgKHR5cGVSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDk5OSxcclxuICAgICAgICB0eXBlQ29kZTogJ05FVy1UWVBFJyxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBhd2FpdCBzZXJ2aWNlLnVwZGF0ZSgxLCB1cGRhdGVEdG8sIG1vY2tVc2VyKTtcclxuXHJcbiAgICAgIGV4cGVjdChcclxuICAgICAgICBudW1iZXJpbmdTZXJ2aWNlLnVwZGF0ZU51bWJlckZvckRyYWZ0IGFzIGplc3QuTW9ja1xyXG4gICAgICApLnRvSGF2ZUJlZW5DYWxsZWQoKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGl0KCdzaG91bGQgcmVnZW5lcmF0ZSBudW1iZXIgaWYgUmVjaXBpZW50IE9yZ2FuaXphdGlvbiBjaGFuZ2VzJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgICBjb25zdCBtb2NrVXNlciA9IHsgaWQ6IDEsIHByaW1hcnlPcmdhbml6YXRpb25JZDogMTAgfSBhcyB1bmtub3duIGFzIFVzZXI7XHJcbiAgICAgIGNvbnN0IG1vY2tSZXZpc2lvbiA9IHtcclxuICAgICAgICBpZDogMTAwLFxyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IDEsXHJcbiAgICAgICAgaXNDdXJyZW50OiB0cnVlLFxyXG4gICAgICAgIHN0YXR1c0lkOiA1LFxyXG4gICAgICB9O1xyXG4gICAgICBqZXN0XHJcbiAgICAgICAgLnNweU9uKHJldmlzaW9uUmVwbywgJ2ZpbmRPbmUnKVxyXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZShtb2NrUmV2aXNpb24gYXMgdW5rbm93biBhcyBDb3JyZXNwb25kZW5jZVJldmlzaW9uKTtcclxuXHJcbiAgICAgIGNvbnN0IG1vY2tDb3JyID0ge1xyXG4gICAgICAgIGlkOiAxLFxyXG4gICAgICAgIHByb2plY3RJZDogMSxcclxuICAgICAgICBjb3JyZXNwb25kZW5jZVR5cGVJZDogMixcclxuICAgICAgICBkaXNjaXBsaW5lSWQ6IDMsXHJcbiAgICAgICAgb3JpZ2luYXRvcklkOiAxMCxcclxuICAgICAgICBjb3JyZXNwb25kZW5jZU51bWJlcjogJ09MRC1OVU0nLFxyXG4gICAgICAgIHJlY2lwaWVudHM6IFt7IHJlY2lwaWVudFR5cGU6ICdUTycsIHJlY2lwaWVudE9yZ2FuaXphdGlvbklkOiA5OSB9XSxcclxuICAgICAgfTtcclxuICAgICAgamVzdFxyXG4gICAgICAgIC5zcHlPbihjb3JyZXNwb25kZW5jZVJlcG8sICdmaW5kT25lJylcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWUobW9ja0NvcnIgYXMgdW5rbm93biBhcyBDb3JyZXNwb25kZW5jZSk7XHJcblxyXG4gICAgICAvLyBBY2Nlc3MgRGF0YVNvdXJjZSBtYW5hZ2VyIGZvciBtb2NraW5nXHJcbiAgICAgIG1vY2tEYXRhU291cmNlLm1hbmFnZXIuZmluZE9uZS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDg4LFxyXG4gICAgICAgIG9yZ2FuaXphdGlvbkNvZGU6ICdORVctT1JHJyxcclxuICAgICAgfSBhcyB1bmtub3duIGFzIE9yZ2FuaXphdGlvbik7XHJcblxyXG4gICAgICBjb25zdCB1cGRhdGVEdG86IFVwZGF0ZUNvcnJlc3BvbmRlbmNlRHRvID0ge1xyXG4gICAgICAgIHJlY2lwaWVudHM6IFt7IHR5cGU6ICdUTycsIG9yZ2FuaXphdGlvbklkOiA4OCB9XSxcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGF3YWl0IHNlcnZpY2UudXBkYXRlKDEsIHVwZGF0ZUR0bywgbW9ja1VzZXIpO1xyXG5cclxuICAgICAgZXhwZWN0KFxyXG4gICAgICAgIG51bWJlcmluZ1NlcnZpY2UudXBkYXRlTnVtYmVyRm9yRHJhZnQgYXMgamVzdC5Nb2NrXHJcbiAgICAgICkudG9IYXZlQmVlbkNhbGxlZCgpO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcblxyXG4gIGRlc2NyaWJlKCdjcmVhdGUnLCAoKSA9PiB7XHJcbiAgICBpdCgnc2hvdWxkIGFsbG93IHN5c3RlbS5tYW5hZ2VfYWxsIHVzZXIgd2l0aG91dCBwcmltYXJ5T3JnYW5pemF0aW9uSWQgd2hlbiBvcmlnaW5hdG9ySWQgaXMgcHJvdmlkZWQnLCBhc3luYyAoKSA9PiB7XHJcbiAgICAgIGNvbnN0IG1vY2tVc2VyID0ge1xyXG4gICAgICAgIHVzZXJfaWQ6IDEsXHJcbiAgICAgICAgcHJpbWFyeU9yZ2FuaXphdGlvbklkOiBudWxsLFxyXG4gICAgICB9IGFzIHVua25vd24gYXMgVXNlcjtcclxuXHJcbiAgICAgIGNvbnN0IGNyZWF0ZUR0bzogQ3JlYXRlQ29ycmVzcG9uZGVuY2VEdG8gPSB7XHJcbiAgICAgICAgcHJvamVjdElkOiAncHJvamVjdC11dWlkJyxcclxuICAgICAgICB0eXBlSWQ6IDEsXHJcbiAgICAgICAgc3ViamVjdDogJ1Rlc3QgU3ViamVjdCcsXHJcbiAgICAgICAgb3JpZ2luYXRvcklkOiAnb3JpZ2luYXRvci11dWlkJyxcclxuICAgICAgICByZWNpcGllbnRzOiBbeyBvcmdhbml6YXRpb25JZDogJ3JlY2lwaWVudC11dWlkJywgdHlwZTogJ1RPJyB9XSxcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGNvbnN0IHVzZXJTZXJ2aWNlID0gdGVzdGluZ01vZHVsZS5nZXQ8VXNlclNlcnZpY2U+KFVzZXJTZXJ2aWNlKTtcclxuICAgICAgY29uc3QgdHlwZVJlcG8gPSB0ZXN0aW5nTW9kdWxlLmdldDxSZXBvc2l0b3J5PENvcnJlc3BvbmRlbmNlVHlwZT4+KFxyXG4gICAgICAgIGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVR5cGUpXHJcbiAgICAgICk7XHJcbiAgICAgIGNvbnN0IHN0YXR1c1JlcG8gPSB0ZXN0aW5nTW9kdWxlLmdldDxSZXBvc2l0b3J5PENvcnJlc3BvbmRlbmNlU3RhdHVzPj4oXHJcbiAgICAgICAgZ2V0UmVwb3NpdG9yeVRva2VuKENvcnJlc3BvbmRlbmNlU3RhdHVzKVxyXG4gICAgICApO1xyXG4gICAgICBjb25zdCB1dWlkUmVzb2x2ZXIgPVxyXG4gICAgICAgIHRlc3RpbmdNb2R1bGUuZ2V0PFV1aWRSZXNvbHZlclNlcnZpY2U+KFV1aWRSZXNvbHZlclNlcnZpY2UpO1xyXG5cclxuICAgICAgKHVzZXJTZXJ2aWNlLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgdXNlcl9pZDogMSxcclxuICAgICAgICBwcmltYXJ5T3JnYW5pemF0aW9uSWQ6IG51bGwsXHJcbiAgICAgIH0pO1xyXG4gICAgICAodXNlclNlcnZpY2UuZ2V0VXNlclBlcm1pc3Npb25zIGFzIGplc3QuTW9jaykubW9ja1Jlc29sdmVkVmFsdWUoW1xyXG4gICAgICAgICdzeXN0ZW0ubWFuYWdlX2FsbCcsXHJcbiAgICAgIF0pO1xyXG5cclxuICAgICAgKHV1aWRSZXNvbHZlci5yZXNvbHZlUHJvamVjdElkIGFzIGplc3QuTW9jaykubW9ja1Jlc29sdmVkVmFsdWUoMTAwKTtcclxuICAgICAgKHV1aWRSZXNvbHZlci5yZXNvbHZlT3JnYW5pemF0aW9uSWQgYXMgamVzdC5Nb2NrKS5tb2NrSW1wbGVtZW50YXRpb24oXHJcbiAgICAgICAgKHZhbHVlOiBudW1iZXIgfCBzdHJpbmcpID0+IHtcclxuICAgICAgICAgIGlmICh2YWx1ZSA9PT0gJ29yaWdpbmF0b3ItdXVpZCcpIHJldHVybiAxMDtcclxuICAgICAgICAgIGlmICh2YWx1ZSA9PT0gJ3JlY2lwaWVudC11dWlkJykgcmV0dXJuIDIwO1xyXG4gICAgICAgICAgcmV0dXJuIDA7XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgICAgKHR5cGVSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgdHlwZUNvZGU6ICdMVFInLFxyXG4gICAgICB9KTtcclxuICAgICAgKHN0YXR1c1JlcG8uZmluZE9uZSBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKHtcclxuICAgICAgICBpZDogMSxcclxuICAgICAgICBzdGF0dXNDb2RlOiAnRFJBRlQnLFxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIChudW1iZXJpbmdTZXJ2aWNlLmdlbmVyYXRlTmV4dE51bWJlciBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKHtcclxuICAgICAgICBudW1iZXI6ICdET0MtMDAxJyxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBtb2NrRGF0YVNvdXJjZS5tYW5hZ2VyLmZpbmRPbmVcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDEwLCBvcmdhbml6YXRpb25Db2RlOiAnT1JHJyB9KVxyXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogMjAsIG9yZ2FuaXphdGlvbkNvZGU6ICdSRUMnIH0pO1xyXG5cclxuICAgICAgY29uc3QgcXVlcnlSdW5uZXIgPSB7XHJcbiAgICAgICAgY29ubmVjdDogamVzdC5mbigpLFxyXG4gICAgICAgIHN0YXJ0VHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICBjb21taXRUcmFuc2FjdGlvbjogamVzdC5mbigpLFxyXG4gICAgICAgIHJvbGxiYWNrVHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICByZWxlYXNlOiBqZXN0LmZuKCksXHJcbiAgICAgICAgbWFuYWdlcjoge1xyXG4gICAgICAgICAgY3JlYXRlOiBqZXN0LmZuKFxyXG4gICAgICAgICAgICAoX2VudGl0eTogdW5rbm93biwgcGF5bG9hZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pID0+IHBheWxvYWRcclxuICAgICAgICAgICksXHJcbiAgICAgICAgICBzYXZlOiBqZXN0XHJcbiAgICAgICAgICAgIC5mbigpXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogOTk5LCBwdWJsaWNJZDogJ2NvcnItdXVpZCcgfSlcclxuICAgICAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7IGlkOiAxMDAwIH0pXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoW10pLFxyXG4gICAgICAgICAgZmluZE9uZTogamVzdC5mbigpLFxyXG4gICAgICAgIH0sXHJcbiAgICAgIH07XHJcblxyXG4gICAgICAobW9ja0RhdGFTb3VyY2UuY3JlYXRlUXVlcnlSdW5uZXIgYXMgamVzdC5Nb2NrKS5tb2NrUmV0dXJuVmFsdWUoXHJcbiAgICAgICAgcXVlcnlSdW5uZXJcclxuICAgICAgKTtcclxuXHJcbiAgICAgIGF3YWl0IHNlcnZpY2UuY3JlYXRlKGNyZWF0ZUR0bywgbW9ja1VzZXIpO1xyXG5cclxuICAgICAgZXhwZWN0KHF1ZXJ5UnVubmVyLm1hbmFnZXIuY3JlYXRlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcclxuICAgICAgICBDb3JyZXNwb25kZW5jZSxcclxuICAgICAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7IG9yaWdpbmF0b3JJZDogMTAgfSlcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGl0KCdzaG91bGQgc2V0IHJldmlzaW9uTGFiZWwgdG8gXCJBXCIgZm9yIFJGQSB0eXBlJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgICBjb25zdCBtb2NrVXNlciA9IHtcclxuICAgICAgICB1c2VyX2lkOiAxLFxyXG4gICAgICAgIHByaW1hcnlPcmdhbml6YXRpb25JZDogMTAsXHJcbiAgICAgIH0gYXMgdW5rbm93biBhcyBVc2VyO1xyXG5cclxuICAgICAgY29uc3QgY3JlYXRlRHRvOiBDcmVhdGVDb3JyZXNwb25kZW5jZUR0byA9IHtcclxuICAgICAgICBwcm9qZWN0SWQ6ICdwcm9qZWN0LXV1aWQnLFxyXG4gICAgICAgIHR5cGVJZDogMSxcclxuICAgICAgICBzdWJqZWN0OiAnVGVzdCBTdWJqZWN0JyxcclxuICAgICAgICByZWNpcGllbnRzOiBbeyBvcmdhbml6YXRpb25JZDogJ3JlY2lwaWVudC11dWlkJywgdHlwZTogJ1RPJyB9XSxcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGNvbnN0IHR5cGVSZXBvID0gdGVzdGluZ01vZHVsZS5nZXQ8UmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVR5cGU+PihcclxuICAgICAgICBnZXRSZXBvc2l0b3J5VG9rZW4oQ29ycmVzcG9uZGVuY2VUeXBlKVxyXG4gICAgICApO1xyXG4gICAgICBjb25zdCBzdGF0dXNSZXBvID0gdGVzdGluZ01vZHVsZS5nZXQ8UmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVN0YXR1cz4+KFxyXG4gICAgICAgIGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVN0YXR1cylcclxuICAgICAgKTtcclxuICAgICAgY29uc3QgdXVpZFJlc29sdmVyID1cclxuICAgICAgICB0ZXN0aW5nTW9kdWxlLmdldDxVdWlkUmVzb2x2ZXJTZXJ2aWNlPihVdWlkUmVzb2x2ZXJTZXJ2aWNlKTtcclxuXHJcbiAgICAgICh1dWlkUmVzb2x2ZXIucmVzb2x2ZVByb2plY3RJZCBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKDEwMCk7XHJcbiAgICAgICh1dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkIGFzIGplc3QuTW9jaykubW9ja1Jlc29sdmVkVmFsdWUoMjApO1xyXG5cclxuICAgICAgKHR5cGVSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgdHlwZUNvZGU6ICdSRkEnLFxyXG4gICAgICB9KTtcclxuICAgICAgKHN0YXR1c1JlcG8uZmluZE9uZSBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKHtcclxuICAgICAgICBpZDogMSxcclxuICAgICAgICBzdGF0dXNDb2RlOiAnRFJBRlQnLFxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIChudW1iZXJpbmdTZXJ2aWNlLmdlbmVyYXRlTmV4dE51bWJlciBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKHtcclxuICAgICAgICBudW1iZXI6ICdET0MtMDAxJyxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBtb2NrRGF0YVNvdXJjZS5tYW5hZ2VyLmZpbmRPbmVcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDEwLCBvcmdhbml6YXRpb25Db2RlOiAnT1JHJyB9KVxyXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogMjAsIG9yZ2FuaXphdGlvbkNvZGU6ICdSRUMnIH0pO1xyXG5cclxuICAgICAgY29uc3QgcXVlcnlSdW5uZXIgPSB7XHJcbiAgICAgICAgY29ubmVjdDogamVzdC5mbigpLFxyXG4gICAgICAgIHN0YXJ0VHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICBjb21taXRUcmFuc2FjdGlvbjogamVzdC5mbigpLFxyXG4gICAgICAgIHJvbGxiYWNrVHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICByZWxlYXNlOiBqZXN0LmZuKCksXHJcbiAgICAgICAgbWFuYWdlcjoge1xyXG4gICAgICAgICAgY3JlYXRlOiBqZXN0LmZuKFxyXG4gICAgICAgICAgICAoX2VudGl0eTogdW5rbm93biwgcGF5bG9hZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pID0+IHBheWxvYWRcclxuICAgICAgICAgICksXHJcbiAgICAgICAgICBzYXZlOiBqZXN0XHJcbiAgICAgICAgICAgIC5mbigpXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogOTk5LCBwdWJsaWNJZDogJ2NvcnItdXVpZCcgfSlcclxuICAgICAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7IGlkOiAxMDAwIH0pXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoW10pLFxyXG4gICAgICAgICAgZmluZE9uZTogamVzdC5mbigpLFxyXG4gICAgICAgIH0sXHJcbiAgICAgIH07XHJcblxyXG4gICAgICAobW9ja0RhdGFTb3VyY2UuY3JlYXRlUXVlcnlSdW5uZXIgYXMgamVzdC5Nb2NrKS5tb2NrUmV0dXJuVmFsdWUoXHJcbiAgICAgICAgcXVlcnlSdW5uZXJcclxuICAgICAgKTtcclxuXHJcbiAgICAgIGF3YWl0IHNlcnZpY2UuY3JlYXRlKGNyZWF0ZUR0bywgbW9ja1VzZXIpO1xyXG5cclxuICAgICAgZXhwZWN0KHF1ZXJ5UnVubmVyLm1hbmFnZXIuY3JlYXRlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcclxuICAgICAgICBDb3JyZXNwb25kZW5jZVJldmlzaW9uLFxyXG4gICAgICAgIGV4cGVjdC5vYmplY3RDb250YWluaW5nKHsgcmV2aXNpb25MYWJlbDogJ0EnIH0pXHJcbiAgICAgICk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBpdCgnc2hvdWxkIHNldCByZXZpc2lvbkxhYmVsIHRvIFwiQVwiIGZvciBSRkkgdHlwZScsIGFzeW5jICgpID0+IHtcclxuICAgICAgY29uc3QgbW9ja1VzZXIgPSB7XHJcbiAgICAgICAgdXNlcl9pZDogMSxcclxuICAgICAgICBwcmltYXJ5T3JnYW5pemF0aW9uSWQ6IDEwLFxyXG4gICAgICB9IGFzIHVua25vd24gYXMgVXNlcjtcclxuXHJcbiAgICAgIGNvbnN0IGNyZWF0ZUR0bzogQ3JlYXRlQ29ycmVzcG9uZGVuY2VEdG8gPSB7XHJcbiAgICAgICAgcHJvamVjdElkOiAncHJvamVjdC11dWlkJyxcclxuICAgICAgICB0eXBlSWQ6IDEsXHJcbiAgICAgICAgc3ViamVjdDogJ1Rlc3QgU3ViamVjdCcsXHJcbiAgICAgICAgcmVjaXBpZW50czogW3sgb3JnYW5pemF0aW9uSWQ6ICdyZWNpcGllbnQtdXVpZCcsIHR5cGU6ICdUTycgfV0sXHJcbiAgICAgIH07XHJcblxyXG4gICAgICBjb25zdCB0eXBlUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VUeXBlPj4oXHJcbiAgICAgICAgZ2V0UmVwb3NpdG9yeVRva2VuKENvcnJlc3BvbmRlbmNlVHlwZSlcclxuICAgICAgKTtcclxuICAgICAgY29uc3Qgc3RhdHVzUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VTdGF0dXM+PihcclxuICAgICAgICBnZXRSZXBvc2l0b3J5VG9rZW4oQ29ycmVzcG9uZGVuY2VTdGF0dXMpXHJcbiAgICAgICk7XHJcbiAgICAgIGNvbnN0IHV1aWRSZXNvbHZlciA9XHJcbiAgICAgICAgdGVzdGluZ01vZHVsZS5nZXQ8VXVpZFJlc29sdmVyU2VydmljZT4oVXVpZFJlc29sdmVyU2VydmljZSk7XHJcblxyXG4gICAgICAodXVpZFJlc29sdmVyLnJlc29sdmVQcm9qZWN0SWQgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSgxMDApO1xyXG4gICAgICAodXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZCBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKDIwKTtcclxuXHJcbiAgICAgICh0eXBlUmVwby5maW5kT25lIGFzIGplc3QuTW9jaykubW9ja1Jlc29sdmVkVmFsdWUoe1xyXG4gICAgICAgIGlkOiAxLFxyXG4gICAgICAgIHR5cGVDb2RlOiAnUkZJJyxcclxuICAgICAgfSk7XHJcbiAgICAgIChzdGF0dXNSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgc3RhdHVzQ29kZTogJ0RSQUZUJyxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAobnVtYmVyaW5nU2VydmljZS5nZW5lcmF0ZU5leHROdW1iZXIgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgbnVtYmVyOiAnRE9DLTAwMScsXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgbW9ja0RhdGFTb3VyY2UubWFuYWdlci5maW5kT25lXHJcbiAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7IGlkOiAxMCwgb3JnYW5pemF0aW9uQ29kZTogJ09SRycgfSlcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDIwLCBvcmdhbml6YXRpb25Db2RlOiAnUkVDJyB9KTtcclxuXHJcbiAgICAgIGNvbnN0IHF1ZXJ5UnVubmVyID0ge1xyXG4gICAgICAgIGNvbm5lY3Q6IGplc3QuZm4oKSxcclxuICAgICAgICBzdGFydFRyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgICAgY29tbWl0VHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICByb2xsYmFja1RyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgICAgcmVsZWFzZTogamVzdC5mbigpLFxyXG4gICAgICAgIG1hbmFnZXI6IHtcclxuICAgICAgICAgIGNyZWF0ZTogamVzdC5mbihcclxuICAgICAgICAgICAgKF9lbnRpdHk6IHVua25vd24sIHBheWxvYWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiBwYXlsb2FkXHJcbiAgICAgICAgICApLFxyXG4gICAgICAgICAgc2F2ZTogamVzdFxyXG4gICAgICAgICAgICAuZm4oKVxyXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDk5OSwgcHVibGljSWQ6ICdjb3JyLXV1aWQnIH0pXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogMTAwMCB9KVxyXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKFtdKSxcclxuICAgICAgICAgIGZpbmRPbmU6IGplc3QuZm4oKSxcclxuICAgICAgICB9LFxyXG4gICAgICB9O1xyXG5cclxuICAgICAgKG1vY2tEYXRhU291cmNlLmNyZWF0ZVF1ZXJ5UnVubmVyIGFzIGplc3QuTW9jaykubW9ja1JldHVyblZhbHVlKFxyXG4gICAgICAgIHF1ZXJ5UnVubmVyXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBhd2FpdCBzZXJ2aWNlLmNyZWF0ZShjcmVhdGVEdG8sIG1vY2tVc2VyKTtcclxuXHJcbiAgICAgIGV4cGVjdChxdWVyeVJ1bm5lci5tYW5hZ2VyLmNyZWF0ZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoXHJcbiAgICAgICAgQ29ycmVzcG9uZGVuY2VSZXZpc2lvbixcclxuICAgICAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7IHJldmlzaW9uTGFiZWw6ICdBJyB9KVxyXG4gICAgICApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgaXQoJ3Nob3VsZCBzZXQgcmV2aXNpb25MYWJlbCB0byBudWxsIGZvciBMRVRURVIgdHlwZScsIGFzeW5jICgpID0+IHtcclxuICAgICAgY29uc3QgbW9ja1VzZXIgPSB7XHJcbiAgICAgICAgdXNlcl9pZDogMSxcclxuICAgICAgICBwcmltYXJ5T3JnYW5pemF0aW9uSWQ6IDEwLFxyXG4gICAgICB9IGFzIHVua25vd24gYXMgVXNlcjtcclxuXHJcbiAgICAgIGNvbnN0IGNyZWF0ZUR0bzogQ3JlYXRlQ29ycmVzcG9uZGVuY2VEdG8gPSB7XHJcbiAgICAgICAgcHJvamVjdElkOiAncHJvamVjdC11dWlkJyxcclxuICAgICAgICB0eXBlSWQ6IDEsXHJcbiAgICAgICAgc3ViamVjdDogJ1Rlc3QgU3ViamVjdCcsXHJcbiAgICAgICAgcmVjaXBpZW50czogW3sgb3JnYW5pemF0aW9uSWQ6ICdyZWNpcGllbnQtdXVpZCcsIHR5cGU6ICdUTycgfV0sXHJcbiAgICAgIH07XHJcblxyXG4gICAgICBjb25zdCB0eXBlUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VUeXBlPj4oXHJcbiAgICAgICAgZ2V0UmVwb3NpdG9yeVRva2VuKENvcnJlc3BvbmRlbmNlVHlwZSlcclxuICAgICAgKTtcclxuICAgICAgY29uc3Qgc3RhdHVzUmVwbyA9IHRlc3RpbmdNb2R1bGUuZ2V0PFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VTdGF0dXM+PihcclxuICAgICAgICBnZXRSZXBvc2l0b3J5VG9rZW4oQ29ycmVzcG9uZGVuY2VTdGF0dXMpXHJcbiAgICAgICk7XHJcbiAgICAgIGNvbnN0IHV1aWRSZXNvbHZlciA9XHJcbiAgICAgICAgdGVzdGluZ01vZHVsZS5nZXQ8VXVpZFJlc29sdmVyU2VydmljZT4oVXVpZFJlc29sdmVyU2VydmljZSk7XHJcblxyXG4gICAgICAodXVpZFJlc29sdmVyLnJlc29sdmVQcm9qZWN0SWQgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSgxMDApO1xyXG4gICAgICAodXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZCBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKDIwKTtcclxuXHJcbiAgICAgICh0eXBlUmVwby5maW5kT25lIGFzIGplc3QuTW9jaykubW9ja1Jlc29sdmVkVmFsdWUoe1xyXG4gICAgICAgIGlkOiAxLFxyXG4gICAgICAgIHR5cGVDb2RlOiAnTEVUVEVSJyxcclxuICAgICAgfSk7XHJcbiAgICAgIChzdGF0dXNSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgc3RhdHVzQ29kZTogJ0RSQUZUJyxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAobnVtYmVyaW5nU2VydmljZS5nZW5lcmF0ZU5leHROdW1iZXIgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgbnVtYmVyOiAnRE9DLTAwMScsXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgbW9ja0RhdGFTb3VyY2UubWFuYWdlci5maW5kT25lXHJcbiAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7IGlkOiAxMCwgb3JnYW5pemF0aW9uQ29kZTogJ09SRycgfSlcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDIwLCBvcmdhbml6YXRpb25Db2RlOiAnUkVDJyB9KTtcclxuXHJcbiAgICAgIGNvbnN0IHF1ZXJ5UnVubmVyID0ge1xyXG4gICAgICAgIGNvbm5lY3Q6IGplc3QuZm4oKSxcclxuICAgICAgICBzdGFydFRyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgICAgY29tbWl0VHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICByb2xsYmFja1RyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgICAgcmVsZWFzZTogamVzdC5mbigpLFxyXG4gICAgICAgIG1hbmFnZXI6IHtcclxuICAgICAgICAgIGNyZWF0ZTogamVzdC5mbihcclxuICAgICAgICAgICAgKF9lbnRpdHk6IHVua25vd24sIHBheWxvYWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiBwYXlsb2FkXHJcbiAgICAgICAgICApLFxyXG4gICAgICAgICAgc2F2ZTogamVzdFxyXG4gICAgICAgICAgICAuZm4oKVxyXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDk5OSwgcHVibGljSWQ6ICdjb3JyLXV1aWQnIH0pXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogMTAwMCB9KVxyXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKFtdKSxcclxuICAgICAgICAgIGZpbmRPbmU6IGplc3QuZm4oKSxcclxuICAgICAgICB9LFxyXG4gICAgICB9O1xyXG5cclxuICAgICAgKG1vY2tEYXRhU291cmNlLmNyZWF0ZVF1ZXJ5UnVubmVyIGFzIGplc3QuTW9jaykubW9ja1JldHVyblZhbHVlKFxyXG4gICAgICAgIHF1ZXJ5UnVubmVyXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBhd2FpdCBzZXJ2aWNlLmNyZWF0ZShjcmVhdGVEdG8sIG1vY2tVc2VyKTtcclxuXHJcbiAgICAgIGV4cGVjdChxdWVyeVJ1bm5lci5tYW5hZ2VyLmNyZWF0ZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoXHJcbiAgICAgICAgQ29ycmVzcG9uZGVuY2VSZXZpc2lvbixcclxuICAgICAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7IHJldmlzaW9uTGFiZWw6IG51bGwgfSlcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGl0KCdzaG91bGQgc2V0IHJldmlzaW9uTGFiZWwgdG8gbnVsbCBmb3IgTUVNTyB0eXBlJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgICBjb25zdCBtb2NrVXNlciA9IHtcclxuICAgICAgICB1c2VyX2lkOiAxLFxyXG4gICAgICAgIHByaW1hcnlPcmdhbml6YXRpb25JZDogMTAsXHJcbiAgICAgIH0gYXMgdW5rbm93biBhcyBVc2VyO1xyXG5cclxuICAgICAgY29uc3QgY3JlYXRlRHRvOiBDcmVhdGVDb3JyZXNwb25kZW5jZUR0byA9IHtcclxuICAgICAgICBwcm9qZWN0SWQ6ICdwcm9qZWN0LXV1aWQnLFxyXG4gICAgICAgIHR5cGVJZDogMSxcclxuICAgICAgICBzdWJqZWN0OiAnVGVzdCBTdWJqZWN0JyxcclxuICAgICAgICByZWNpcGllbnRzOiBbeyBvcmdhbml6YXRpb25JZDogJ3JlY2lwaWVudC11dWlkJywgdHlwZTogJ1RPJyB9XSxcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGNvbnN0IHR5cGVSZXBvID0gdGVzdGluZ01vZHVsZS5nZXQ8UmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVR5cGU+PihcclxuICAgICAgICBnZXRSZXBvc2l0b3J5VG9rZW4oQ29ycmVzcG9uZGVuY2VUeXBlKVxyXG4gICAgICApO1xyXG4gICAgICBjb25zdCBzdGF0dXNSZXBvID0gdGVzdGluZ01vZHVsZS5nZXQ8UmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVN0YXR1cz4+KFxyXG4gICAgICAgIGdldFJlcG9zaXRvcnlUb2tlbihDb3JyZXNwb25kZW5jZVN0YXR1cylcclxuICAgICAgKTtcclxuICAgICAgY29uc3QgdXVpZFJlc29sdmVyID1cclxuICAgICAgICB0ZXN0aW5nTW9kdWxlLmdldDxVdWlkUmVzb2x2ZXJTZXJ2aWNlPihVdWlkUmVzb2x2ZXJTZXJ2aWNlKTtcclxuXHJcbiAgICAgICh1dWlkUmVzb2x2ZXIucmVzb2x2ZVByb2plY3RJZCBhcyBqZXN0Lk1vY2spLm1vY2tSZXNvbHZlZFZhbHVlKDEwMCk7XHJcbiAgICAgICh1dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkIGFzIGplc3QuTW9jaykubW9ja1Jlc29sdmVkVmFsdWUoMjApO1xyXG5cclxuICAgICAgKHR5cGVSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgdHlwZUNvZGU6ICdNRU1PJyxcclxuICAgICAgfSk7XHJcbiAgICAgIChzdGF0dXNSZXBvLmZpbmRPbmUgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgaWQ6IDEsXHJcbiAgICAgICAgc3RhdHVzQ29kZTogJ0RSQUZUJyxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAobnVtYmVyaW5nU2VydmljZS5nZW5lcmF0ZU5leHROdW1iZXIgYXMgamVzdC5Nb2NrKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XHJcbiAgICAgICAgbnVtYmVyOiAnRE9DLTAwMScsXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgbW9ja0RhdGFTb3VyY2UubWFuYWdlci5maW5kT25lXHJcbiAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7IGlkOiAxMCwgb3JnYW5pemF0aW9uQ29kZTogJ09SRycgfSlcclxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDIwLCBvcmdhbml6YXRpb25Db2RlOiAnUkVDJyB9KTtcclxuXHJcbiAgICAgIGNvbnN0IHF1ZXJ5UnVubmVyID0ge1xyXG4gICAgICAgIGNvbm5lY3Q6IGplc3QuZm4oKSxcclxuICAgICAgICBzdGFydFRyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgICAgY29tbWl0VHJhbnNhY3Rpb246IGplc3QuZm4oKSxcclxuICAgICAgICByb2xsYmFja1RyYW5zYWN0aW9uOiBqZXN0LmZuKCksXHJcbiAgICAgICAgcmVsZWFzZTogamVzdC5mbigpLFxyXG4gICAgICAgIG1hbmFnZXI6IHtcclxuICAgICAgICAgIGNyZWF0ZTogamVzdC5mbihcclxuICAgICAgICAgICAgKF9lbnRpdHk6IHVua25vd24sIHBheWxvYWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiBwYXlsb2FkXHJcbiAgICAgICAgICApLFxyXG4gICAgICAgICAgc2F2ZTogamVzdFxyXG4gICAgICAgICAgICAuZm4oKVxyXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKHsgaWQ6IDk5OSwgcHVibGljSWQ6ICdjb3JyLXV1aWQnIH0pXHJcbiAgICAgICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoeyBpZDogMTAwMCB9KVxyXG4gICAgICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKFtdKSxcclxuICAgICAgICAgIGZpbmRPbmU6IGplc3QuZm4oKSxcclxuICAgICAgICB9LFxyXG4gICAgICB9O1xyXG5cclxuICAgICAgKG1vY2tEYXRhU291cmNlLmNyZWF0ZVF1ZXJ5UnVubmVyIGFzIGplc3QuTW9jaykubW9ja1JldHVyblZhbHVlKFxyXG4gICAgICAgIHF1ZXJ5UnVubmVyXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBhd2FpdCBzZXJ2aWNlLmNyZWF0ZShjcmVhdGVEdG8sIG1vY2tVc2VyKTtcclxuXHJcbiAgICAgIGV4cGVjdChxdWVyeVJ1bm5lci5tYW5hZ2VyLmNyZWF0ZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoXHJcbiAgICAgICAgQ29ycmVzcG9uZGVuY2VSZXZpc2lvbixcclxuICAgICAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7IHJldmlzaW9uTGFiZWw6IG51bGwgfSlcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59KTtcclxuIl0sInZlcnNpb24iOjN9 \ No newline at end of file diff --git a/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/6e/correspondenceservicespec_6e17e53289c744ad0b09ce4420c50e0e.map b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/6e/correspondenceservicespec_6e17e53289c744ad0b09ce4420c50e0e.map new file mode 100644 index 0000000..53056ca --- /dev/null +++ b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/6e/correspondenceservicespec_6e17e53289c744ad0b09ce4420c50e0e.map @@ -0,0 +1 @@ +{"file":"E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.spec.ts","mappings":"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","names":[],"sources":["E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.spec.ts"],"sourcesContent":["import { Test, TestingModule } from '@nestjs/testing';\r\nimport { getRepositoryToken } from '@nestjs/typeorm';\r\nimport { DataSource, Repository } from 'typeorm';\r\nimport { CorrespondenceService } from './correspondence.service';\r\nimport { Correspondence } from './entities/correspondence.entity';\r\nimport { CorrespondenceRevision } from './entities/correspondence-revision.entity';\r\nimport { CorrespondenceType } from './entities/correspondence-type.entity';\r\nimport { CorrespondenceStatus } from './entities/correspondence-status.entity';\r\nimport { CorrespondenceReference } from './entities/correspondence-reference.entity';\r\nimport { CorrespondenceTag } from './entities/correspondence-tag.entity';\r\nimport { Organization } from '../organization/entities/organization.entity';\r\nimport { CorrespondenceRecipient } from './entities/correspondence-recipient.entity';\r\nimport { DocumentNumberingService } from '../document-numbering/services/document-numbering.service';\r\nimport { JsonSchemaService } from '../json-schema/json-schema.service';\r\nimport { WorkflowEngineService } from '../workflow-engine/workflow-engine.service';\r\nimport { UserService } from '../user/user.service';\r\nimport { SearchService } from '../search/search.service';\r\nimport { FileStorageService } from '../../common/file-storage/file-storage.service';\r\nimport { UuidResolverService } from '../../common/services/uuid-resolver.service';\r\nimport { NotificationService } from '../notification/notification.service';\r\nimport { UpdateCorrespondenceDto } from './dto/update-correspondence.dto';\r\nimport { CreateCorrespondenceDto } from './dto/create-correspondence.dto';\r\nimport { User } from '../user/entities/user.entity';\r\n\r\ndescribe('CorrespondenceService', () => {\r\n let service: CorrespondenceService;\r\n let numberingService: DocumentNumberingService;\r\n let correspondenceRepo: Repository;\r\n let revisionRepo: Repository;\r\n let testingModule: TestingModule;\r\n let _dataSource: DataSource;\r\n\r\n const createMockRepository = () => ({\r\n find: jest.fn(),\r\n findOne: jest.fn(),\r\n create: jest.fn(),\r\n save: jest.fn(),\r\n update: jest.fn(),\r\n delete: jest.fn(),\r\n softDelete: jest.fn(),\r\n createQueryBuilder: jest.fn(() => ({\r\n leftJoinAndSelect: jest.fn().mockReturnThis(),\r\n where: jest.fn().mockReturnThis(),\r\n andWhere: jest.fn().mockReturnThis(),\r\n orderBy: jest.fn().mockReturnThis(),\r\n skip: jest.fn().mockReturnThis(),\r\n take: jest.fn().mockReturnThis(),\r\n getOne: jest.fn().mockResolvedValue(null),\r\n getMany: jest.fn().mockResolvedValue([]),\r\n getManyAndCount: jest.fn().mockResolvedValue([[], 0]),\r\n })),\r\n });\r\n\r\n const mockDataSource = {\r\n createQueryRunner: jest.fn(() => ({\r\n connect: jest.fn(),\r\n startTransaction: jest.fn(),\r\n commitTransaction: jest.fn(),\r\n rollbackTransaction: jest.fn(),\r\n release: jest.fn(),\r\n manager: {\r\n create: jest.fn(),\r\n save: jest.fn(),\r\n findOne: jest.fn(),\r\n },\r\n })),\r\n getRepository: jest.fn(() => createMockRepository()),\r\n manager: {\r\n findOne: jest.fn(),\r\n },\r\n };\r\n\r\n beforeEach(async () => {\r\n testingModule = await Test.createTestingModule({\r\n providers: [\r\n CorrespondenceService,\r\n {\r\n provide: getRepositoryToken(Correspondence),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(CorrespondenceRevision),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(CorrespondenceType),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(CorrespondenceStatus),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(CorrespondenceReference),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(CorrespondenceTag),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(Organization),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: getRepositoryToken(CorrespondenceRecipient),\r\n useValue: createMockRepository(),\r\n },\r\n {\r\n provide: DocumentNumberingService,\r\n useValue: {\r\n generateNextNumber: jest.fn(),\r\n updateNumberForDraft: jest.fn(),\r\n previewNextNumber: jest.fn(),\r\n },\r\n },\r\n {\r\n provide: JsonSchemaService,\r\n useValue: { validate: jest.fn() },\r\n },\r\n {\r\n provide: WorkflowEngineService,\r\n useValue: { createInstance: jest.fn() },\r\n },\r\n {\r\n provide: UserService,\r\n useValue: {\r\n findOne: jest.fn(),\r\n getUserPermissions: jest.fn().mockResolvedValue([]),\r\n },\r\n },\r\n {\r\n provide: DataSource,\r\n useValue: mockDataSource,\r\n },\r\n {\r\n provide: SearchService,\r\n useValue: { indexDocument: jest.fn() },\r\n },\r\n {\r\n provide: FileStorageService,\r\n useValue: { commit: jest.fn().mockResolvedValue([]) },\r\n },\r\n {\r\n provide: UuidResolverService,\r\n useValue: {\r\n resolveProjectId: jest.fn().mockResolvedValue(1),\r\n resolveOrganizationId: jest.fn().mockResolvedValue(1),\r\n },\r\n },\r\n {\r\n provide: NotificationService,\r\n useValue: { send: jest.fn().mockResolvedValue(undefined) },\r\n },\r\n ],\r\n }).compile();\r\n\r\n service = testingModule.get(CorrespondenceService);\r\n numberingService = testingModule.get(\r\n DocumentNumberingService\r\n );\r\n correspondenceRepo = testingModule.get>(\r\n getRepositoryToken(Correspondence)\r\n );\r\n revisionRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceRevision)\r\n );\r\n _dataSource = testingModule.get(DataSource);\r\n });\r\n\r\n it('should be defined', () => {\r\n expect(service).toBeDefined();\r\n });\r\n\r\n describe('update', () => {\r\n it('should NOT regenerate number if critical fields unchanged', async () => {\r\n const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;\r\n const mockRevision = {\r\n id: 100,\r\n correspondenceId: 1,\r\n isCurrent: true,\r\n statusId: 5,\r\n };\r\n\r\n jest\r\n .spyOn(revisionRepo, 'findOne')\r\n .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);\r\n\r\n const mockCorr = {\r\n id: 1,\r\n projectId: 1,\r\n correspondenceTypeId: 2,\r\n disciplineId: 3,\r\n originatorId: 10,\r\n correspondenceNumber: 'OLD-NUM',\r\n recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],\r\n };\r\n jest\r\n .spyOn(correspondenceRepo, 'findOne')\r\n .mockResolvedValue(mockCorr as unknown as Correspondence);\r\n\r\n const updateDto: UpdateCorrespondenceDto = {\r\n projectId: 1,\r\n disciplineId: 3,\r\n };\r\n\r\n await service.update(1, updateDto, mockUser);\r\n\r\n expect(\r\n numberingService.updateNumberForDraft as jest.Mock\r\n ).not.toHaveBeenCalled();\r\n });\r\n\r\n it('should regenerate number if Project ID changes', async () => {\r\n const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;\r\n const mockRevision = {\r\n id: 100,\r\n correspondenceId: 1,\r\n isCurrent: true,\r\n statusId: 5,\r\n };\r\n jest\r\n .spyOn(revisionRepo, 'findOne')\r\n .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);\r\n\r\n const mockCorr = {\r\n id: 1,\r\n projectId: 1,\r\n correspondenceTypeId: 2,\r\n disciplineId: 3,\r\n originatorId: 10,\r\n correspondenceNumber: 'OLD-NUM',\r\n recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],\r\n };\r\n jest\r\n .spyOn(correspondenceRepo, 'findOne')\r\n .mockResolvedValue(mockCorr as unknown as Correspondence);\r\n\r\n const updateDto: UpdateCorrespondenceDto = {\r\n projectId: 2,\r\n };\r\n\r\n const uuidResolver =\r\n testingModule.get(UuidResolverService);\r\n (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(2);\r\n\r\n await service.update(1, updateDto, mockUser);\r\n\r\n expect(\r\n numberingService.updateNumberForDraft as jest.Mock\r\n ).toHaveBeenCalled();\r\n });\r\n\r\n it('should regenerate number if Document Type changes', async () => {\r\n const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;\r\n const mockRevision = {\r\n id: 100,\r\n correspondenceId: 1,\r\n isCurrent: true,\r\n statusId: 5,\r\n };\r\n jest\r\n .spyOn(revisionRepo, 'findOne')\r\n .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);\r\n\r\n const mockCorr = {\r\n id: 1,\r\n projectId: 1,\r\n correspondenceTypeId: 2,\r\n disciplineId: 3,\r\n originatorId: 10,\r\n correspondenceNumber: 'OLD-NUM',\r\n recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],\r\n };\r\n jest\r\n .spyOn(correspondenceRepo, 'findOne')\r\n .mockResolvedValue(mockCorr as unknown as Correspondence);\r\n\r\n const updateDto: UpdateCorrespondenceDto = {\r\n typeId: 999,\r\n };\r\n\r\n const typeRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceType)\r\n );\r\n (typeRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 999,\r\n typeCode: 'NEW-TYPE',\r\n });\r\n\r\n await service.update(1, updateDto, mockUser);\r\n\r\n expect(\r\n numberingService.updateNumberForDraft as jest.Mock\r\n ).toHaveBeenCalled();\r\n });\r\n\r\n it('should regenerate number if Recipient Organization changes', async () => {\r\n const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;\r\n const mockRevision = {\r\n id: 100,\r\n correspondenceId: 1,\r\n isCurrent: true,\r\n statusId: 5,\r\n };\r\n jest\r\n .spyOn(revisionRepo, 'findOne')\r\n .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);\r\n\r\n const mockCorr = {\r\n id: 1,\r\n projectId: 1,\r\n correspondenceTypeId: 2,\r\n disciplineId: 3,\r\n originatorId: 10,\r\n correspondenceNumber: 'OLD-NUM',\r\n recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],\r\n };\r\n jest\r\n .spyOn(correspondenceRepo, 'findOne')\r\n .mockResolvedValue(mockCorr as unknown as Correspondence);\r\n\r\n // Access DataSource manager for mocking\r\n mockDataSource.manager.findOne.mockResolvedValue({\r\n id: 88,\r\n organizationCode: 'NEW-ORG',\r\n } as unknown as Organization);\r\n\r\n const updateDto: UpdateCorrespondenceDto = {\r\n recipients: [{ type: 'TO', organizationId: 88 }],\r\n };\r\n\r\n await service.update(1, updateDto, mockUser);\r\n\r\n expect(\r\n numberingService.updateNumberForDraft as jest.Mock\r\n ).toHaveBeenCalled();\r\n });\r\n });\r\n\r\n describe('create', () => {\r\n it('should allow system.manage_all user without primaryOrganizationId when originatorId is provided', async () => {\r\n const mockUser = {\r\n user_id: 1,\r\n primaryOrganizationId: null,\r\n } as unknown as User;\r\n\r\n const createDto: CreateCorrespondenceDto = {\r\n projectId: 'project-uuid',\r\n typeId: 1,\r\n subject: 'Test Subject',\r\n originatorId: 'originator-uuid',\r\n recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],\r\n };\r\n\r\n const userService = testingModule.get(UserService);\r\n const typeRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceType)\r\n );\r\n const statusRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceStatus)\r\n );\r\n const uuidResolver =\r\n testingModule.get(UuidResolverService);\r\n\r\n (userService.findOne as jest.Mock).mockResolvedValue({\r\n user_id: 1,\r\n primaryOrganizationId: null,\r\n });\r\n (userService.getUserPermissions as jest.Mock).mockResolvedValue([\r\n 'system.manage_all',\r\n ]);\r\n\r\n (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);\r\n (uuidResolver.resolveOrganizationId as jest.Mock).mockImplementation(\r\n (value: number | string) => {\r\n if (value === 'originator-uuid') return 10;\r\n if (value === 'recipient-uuid') return 20;\r\n return 0;\r\n }\r\n );\r\n\r\n (typeRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n typeCode: 'LTR',\r\n });\r\n (statusRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n statusCode: 'DRAFT',\r\n });\r\n\r\n (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({\r\n number: 'DOC-001',\r\n });\r\n\r\n mockDataSource.manager.findOne\r\n .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })\r\n .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });\r\n\r\n const queryRunner = {\r\n connect: jest.fn(),\r\n startTransaction: jest.fn(),\r\n commitTransaction: jest.fn(),\r\n rollbackTransaction: jest.fn(),\r\n release: jest.fn(),\r\n manager: {\r\n create: jest.fn(\r\n (_entity: unknown, payload: Record) => payload\r\n ),\r\n save: jest\r\n .fn()\r\n .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })\r\n .mockResolvedValueOnce({ id: 1000 })\r\n .mockResolvedValueOnce([]),\r\n findOne: jest.fn(),\r\n },\r\n };\r\n\r\n (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(\r\n queryRunner\r\n );\r\n\r\n await service.create(createDto, mockUser);\r\n\r\n expect(queryRunner.manager.create).toHaveBeenCalledWith(\r\n Correspondence,\r\n expect.objectContaining({ originatorId: 10 })\r\n );\r\n });\r\n\r\n it('should set revisionLabel to \"A\" for RFA type', async () => {\r\n const mockUser = {\r\n user_id: 1,\r\n primaryOrganizationId: 10,\r\n } as unknown as User;\r\n\r\n const createDto: CreateCorrespondenceDto = {\r\n projectId: 'project-uuid',\r\n typeId: 1,\r\n subject: 'Test Subject',\r\n recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],\r\n };\r\n\r\n const typeRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceType)\r\n );\r\n const statusRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceStatus)\r\n );\r\n const uuidResolver =\r\n testingModule.get(UuidResolverService);\r\n\r\n (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);\r\n (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20);\r\n\r\n (typeRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n typeCode: 'RFA',\r\n });\r\n (statusRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n statusCode: 'DRAFT',\r\n });\r\n\r\n (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({\r\n number: 'DOC-001',\r\n });\r\n\r\n mockDataSource.manager.findOne\r\n .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })\r\n .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });\r\n\r\n const queryRunner = {\r\n connect: jest.fn(),\r\n startTransaction: jest.fn(),\r\n commitTransaction: jest.fn(),\r\n rollbackTransaction: jest.fn(),\r\n release: jest.fn(),\r\n manager: {\r\n create: jest.fn(\r\n (_entity: unknown, payload: Record) => payload\r\n ),\r\n save: jest\r\n .fn()\r\n .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })\r\n .mockResolvedValueOnce({ id: 1000 })\r\n .mockResolvedValueOnce([]),\r\n findOne: jest.fn(),\r\n },\r\n };\r\n\r\n (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(\r\n queryRunner\r\n );\r\n\r\n await service.create(createDto, mockUser);\r\n\r\n expect(queryRunner.manager.create).toHaveBeenCalledWith(\r\n CorrespondenceRevision,\r\n expect.objectContaining({ revisionLabel: 'A' })\r\n );\r\n });\r\n\r\n it('should set revisionLabel to \"A\" for RFI type', async () => {\r\n const mockUser = {\r\n user_id: 1,\r\n primaryOrganizationId: 10,\r\n } as unknown as User;\r\n\r\n const createDto: CreateCorrespondenceDto = {\r\n projectId: 'project-uuid',\r\n typeId: 1,\r\n subject: 'Test Subject',\r\n recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],\r\n };\r\n\r\n const typeRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceType)\r\n );\r\n const statusRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceStatus)\r\n );\r\n const uuidResolver =\r\n testingModule.get(UuidResolverService);\r\n\r\n (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);\r\n (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20);\r\n\r\n (typeRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n typeCode: 'RFI',\r\n });\r\n (statusRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n statusCode: 'DRAFT',\r\n });\r\n\r\n (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({\r\n number: 'DOC-001',\r\n });\r\n\r\n mockDataSource.manager.findOne\r\n .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })\r\n .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });\r\n\r\n const queryRunner = {\r\n connect: jest.fn(),\r\n startTransaction: jest.fn(),\r\n commitTransaction: jest.fn(),\r\n rollbackTransaction: jest.fn(),\r\n release: jest.fn(),\r\n manager: {\r\n create: jest.fn(\r\n (_entity: unknown, payload: Record) => payload\r\n ),\r\n save: jest\r\n .fn()\r\n .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })\r\n .mockResolvedValueOnce({ id: 1000 })\r\n .mockResolvedValueOnce([]),\r\n findOne: jest.fn(),\r\n },\r\n };\r\n\r\n (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(\r\n queryRunner\r\n );\r\n\r\n await service.create(createDto, mockUser);\r\n\r\n expect(queryRunner.manager.create).toHaveBeenCalledWith(\r\n CorrespondenceRevision,\r\n expect.objectContaining({ revisionLabel: 'A' })\r\n );\r\n });\r\n\r\n it('should set revisionLabel to null for LETTER type', async () => {\r\n const mockUser = {\r\n user_id: 1,\r\n primaryOrganizationId: 10,\r\n } as unknown as User;\r\n\r\n const createDto: CreateCorrespondenceDto = {\r\n projectId: 'project-uuid',\r\n typeId: 1,\r\n subject: 'Test Subject',\r\n recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],\r\n };\r\n\r\n const typeRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceType)\r\n );\r\n const statusRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceStatus)\r\n );\r\n const uuidResolver =\r\n testingModule.get(UuidResolverService);\r\n\r\n (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);\r\n (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20);\r\n\r\n (typeRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n typeCode: 'LETTER',\r\n });\r\n (statusRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n statusCode: 'DRAFT',\r\n });\r\n\r\n (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({\r\n number: 'DOC-001',\r\n });\r\n\r\n mockDataSource.manager.findOne\r\n .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })\r\n .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });\r\n\r\n const queryRunner = {\r\n connect: jest.fn(),\r\n startTransaction: jest.fn(),\r\n commitTransaction: jest.fn(),\r\n rollbackTransaction: jest.fn(),\r\n release: jest.fn(),\r\n manager: {\r\n create: jest.fn(\r\n (_entity: unknown, payload: Record) => payload\r\n ),\r\n save: jest\r\n .fn()\r\n .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })\r\n .mockResolvedValueOnce({ id: 1000 })\r\n .mockResolvedValueOnce([]),\r\n findOne: jest.fn(),\r\n },\r\n };\r\n\r\n (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(\r\n queryRunner\r\n );\r\n\r\n await service.create(createDto, mockUser);\r\n\r\n expect(queryRunner.manager.create).toHaveBeenCalledWith(\r\n CorrespondenceRevision,\r\n expect.objectContaining({ revisionLabel: null })\r\n );\r\n });\r\n\r\n it('should set revisionLabel to null for MEMO type', async () => {\r\n const mockUser = {\r\n user_id: 1,\r\n primaryOrganizationId: 10,\r\n } as unknown as User;\r\n\r\n const createDto: CreateCorrespondenceDto = {\r\n projectId: 'project-uuid',\r\n typeId: 1,\r\n subject: 'Test Subject',\r\n recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],\r\n };\r\n\r\n const typeRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceType)\r\n );\r\n const statusRepo = testingModule.get>(\r\n getRepositoryToken(CorrespondenceStatus)\r\n );\r\n const uuidResolver =\r\n testingModule.get(UuidResolverService);\r\n\r\n (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);\r\n (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20);\r\n\r\n (typeRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n typeCode: 'MEMO',\r\n });\r\n (statusRepo.findOne as jest.Mock).mockResolvedValue({\r\n id: 1,\r\n statusCode: 'DRAFT',\r\n });\r\n\r\n (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({\r\n number: 'DOC-001',\r\n });\r\n\r\n mockDataSource.manager.findOne\r\n .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })\r\n .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });\r\n\r\n const queryRunner = {\r\n connect: jest.fn(),\r\n startTransaction: jest.fn(),\r\n commitTransaction: jest.fn(),\r\n rollbackTransaction: jest.fn(),\r\n release: jest.fn(),\r\n manager: {\r\n create: jest.fn(\r\n (_entity: unknown, payload: Record) => payload\r\n ),\r\n save: jest\r\n .fn()\r\n .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })\r\n .mockResolvedValueOnce({ id: 1000 })\r\n .mockResolvedValueOnce([]),\r\n findOne: jest.fn(),\r\n },\r\n };\r\n\r\n (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(\r\n queryRunner\r\n );\r\n\r\n await service.create(createDto, mockUser);\r\n\r\n expect(queryRunner.manager.create).toHaveBeenCalledWith(\r\n CorrespondenceRevision,\r\n expect.objectContaining({ revisionLabel: null })\r\n );\r\n });\r\n });\r\n});\r\n"],"version":3} \ No newline at end of file diff --git a/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/d8/correspondenceservice_d8463801745469340085197633f7ae6b b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/d8/correspondenceservice_d8463801745469340085197633f7ae6b new file mode 100644 index 0000000..333767e --- /dev/null +++ b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/d8/correspondenceservice_d8463801745469340085197633f7ae6b @@ -0,0 +1,893 @@ +f958e3e0fd6fd813cf9552bbff491967 +"use strict"; +// File: src/modules/correspondence/correspondence.service.ts +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +var __param = (this && this.__param) || function (paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +}; +var CorrespondenceService_1; +var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CorrespondenceService = void 0; +const common_1 = require("@nestjs/common"); +const typeorm_1 = require("@nestjs/typeorm"); +const typeorm_2 = require("typeorm"); +// Entities +const correspondence_entity_1 = require("./entities/correspondence.entity"); +const correspondence_revision_entity_1 = require("./entities/correspondence-revision.entity"); +const correspondence_type_entity_1 = require("./entities/correspondence-type.entity"); +const correspondence_status_entity_1 = require("./entities/correspondence-status.entity"); +const correspondence_reference_entity_1 = require("./entities/correspondence-reference.entity"); +const correspondence_recipient_entity_1 = require("./entities/correspondence-recipient.entity"); +const correspondence_tag_entity_1 = require("./entities/correspondence-tag.entity"); +const tag_entity_1 = require("../master/entities/tag.entity"); +const organization_entity_1 = require("../organization/entities/organization.entity"); +// Services +const document_numbering_service_1 = require("../document-numbering/services/document-numbering.service"); +const json_schema_service_1 = require("../json-schema/json-schema.service"); +const workflow_engine_service_1 = require("../workflow-engine/workflow-engine.service"); +const user_service_1 = require("../user/user.service"); +const search_service_1 = require("../search/search.service"); +const file_storage_service_1 = require("../../common/file-storage/file-storage.service"); +const uuid_resolver_service_1 = require("../../common/services/uuid-resolver.service"); +const notification_service_1 = require("../notification/notification.service"); +let CorrespondenceService = CorrespondenceService_1 = class CorrespondenceService { + async hasSystemManageAllPermission(userId) { + const permissions = await this.userService.getUserPermissions(userId); + return permissions.includes('system.manage_all'); + } + /** + * Business Rule: Revision Label Strategy + * - RFA, RFI: Use alphabet starting with 'A' (A, B, C...) + * - Other types (LETTER, MEMO, etc.): Use numeric (null for first, then 1, 2, 3...) + */ + getInitialRevisionLabel(typeCode) { + const alphabetTypes = ['RFA', 'RFI']; + if (alphabetTypes.includes(typeCode.toUpperCase())) { + return 'A'; // Alphabet for RFA, RFI + } + return null; // Numeric (null for revision 0) + } + constructor(correspondenceRepo, revisionRepo, typeRepo, statusRepo, referenceRepo, tagRepo, numberingService, jsonSchemaService, workflowEngine, userService, dataSource, searchService, fileStorageService, uuidResolver, notificationService) { + this.correspondenceRepo = correspondenceRepo; + this.revisionRepo = revisionRepo; + this.typeRepo = typeRepo; + this.statusRepo = statusRepo; + this.referenceRepo = referenceRepo; + this.tagRepo = tagRepo; + this.numberingService = numberingService; + this.jsonSchemaService = jsonSchemaService; + this.workflowEngine = workflowEngine; + this.userService = userService; + this.dataSource = dataSource; + this.searchService = searchService; + this.fileStorageService = fileStorageService; + this.uuidResolver = uuidResolver; + this.notificationService = notificationService; + this.logger = new common_1.Logger(CorrespondenceService_1.name); + } + /** + * Business Rule Validation: EC-CORR-003 - Correspondence to Self + * Prevent external correspondence to same organization + */ + async validateCorrespondenceRecipients(createDto, user) { + // Get user's organization + let userOrgId = user.primaryOrganizationId; + if (!userOrgId) { + const fullUser = await this.userService.findOne(user.user_id); + if (fullUser) { + userOrgId = fullUser.primaryOrganizationId; + } + } + if (!userOrgId) { + if (createDto.originatorId) { + const canManageAll = await this.hasSystemManageAllPermission(user.user_id); + if (canManageAll) { + userOrgId = await this.uuidResolver.resolveOrganizationId(createDto.originatorId); + } + } + if (!userOrgId) { + throw new common_1.BadRequestException('User must belong to an organization to create documents'); + } + } + // For impersonation, use the specified originator + const originatorOrgId = createDto.originatorId + ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId) + : userOrgId; + // Check if it's internal communication + if (createDto.isInternal) { + // Internal communications should use Circulation instead + throw new common_1.BadRequestException('Internal communications should use Circulation Sheet instead of Correspondence'); + } + // Validate recipients + if (!createDto.recipients || createDto.recipients.length === 0) { + throw new common_1.BadRequestException('At least one recipient (TO or CC) is required'); + } + const toRecipients = createDto.recipients.filter((r) => r.type === 'TO'); + const ccRecipients = createDto.recipients.filter((r) => r.type === 'CC'); + if (toRecipients.length === 0 && ccRecipients.length === 0) { + throw new common_1.BadRequestException('At least one TO or CC recipient is required'); + } + // Check for same organization correspondence + for (const recipient of createDto.recipients) { + const recipientOrgId = await this.uuidResolver.resolveOrganizationId(recipient.organizationId); + if (recipientOrgId === originatorOrgId) { + throw new common_1.BadRequestException('Cannot send correspondence to your own organization. Use Circulation Sheet for internal communication.'); + } + } + } + async create(createDto, user) { + // Business Rule Validation: EC-CORR-003 - Correspondence to Self + await this.validateCorrespondenceRecipients(createDto, user); + // ADR-019: Resolve UUID references to internal INT IDs + const resolvedProjectId = await this.uuidResolver.resolveProjectId(createDto.projectId); + const resolvedOriginatorId = createDto.originatorId + ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId) + : undefined; + const resolvedRecipients = createDto.recipients + ? await Promise.all(createDto.recipients.map(async (r) => ({ + organizationId: await this.uuidResolver.resolveOrganizationId(r.organizationId), + type: r.type, + }))) + : undefined; + const type = await this.typeRepo.findOne({ + where: { id: createDto.typeId }, + }); + if (!type) + throw new common_1.NotFoundException('Document Type not found'); + const statusDraft = await this.statusRepo.findOne({ + where: { statusCode: 'DRAFT' }, + }); + if (!statusDraft) { + throw new common_1.InternalServerErrorException('Status DRAFT not found in Master Data'); + } + let userOrgId = user.primaryOrganizationId; + if (!userOrgId) { + const fullUser = await this.userService.findOne(user.user_id); + if (fullUser) { + userOrgId = fullUser.primaryOrganizationId; + } + } + // Impersonation Logic + if (resolvedOriginatorId && resolvedOriginatorId !== userOrgId) { + const canManageAll = await this.hasSystemManageAllPermission(user.user_id); + if (!canManageAll) { + throw new common_1.ForbiddenException('You do not have permission to create documents on behalf of other organizations.'); + } + userOrgId = resolvedOriginatorId; + } + if (!userOrgId) { + throw new common_1.BadRequestException('User must belong to an organization to create documents'); + } + if (createDto.details) { + try { + await this.jsonSchemaService.validate(type.typeCode, createDto.details); + } + catch (error) { + this.logger.warn(`Schema validation warning for ${type.typeCode}: ${error.message}`); + } + } + const queryRunner = this.dataSource.createQueryRunner(); + await queryRunner.connect(); + await queryRunner.startTransaction(); + try { + // [Fix #6] Fetch real ORG Code from Organization entity + const originatorOrg = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { id: userOrgId }, + }); + const orgCode = originatorOrg?.organizationCode ?? 'UNK'; + // [v1.5.1] Extract recipient organization from recipients array (Primary TO) + const toRecipient = resolvedRecipients?.find((r) => r.type === 'TO'); + const recipientOrganizationId = toRecipient?.organizationId; + let recipientCode = ''; + if (recipientOrganizationId) { + const recOrg = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { id: recipientOrganizationId }, + }); + if (recOrg) + recipientCode = recOrg.organizationCode; + } + const docNumber = await this.numberingService.generateNextNumber({ + projectId: resolvedProjectId, + originatorOrganizationId: userOrgId, + typeId: createDto.typeId, + disciplineId: createDto.disciplineId, + subTypeId: createDto.subTypeId, + recipientOrganizationId, // [v1.5.1] Pass recipient for document number format + year: new Date().getFullYear(), + customTokens: { + TYPE_CODE: type.typeCode, + ORG_CODE: orgCode, + RECIPIENT_CODE: recipientCode, + REC_CODE: recipientCode, + }, + }); + const correspondence = queryRunner.manager.create(correspondence_entity_1.Correspondence, { + correspondenceNumber: docNumber.number, + correspondenceTypeId: createDto.typeId, + disciplineId: createDto.disciplineId, + projectId: resolvedProjectId, + originatorId: userOrgId, + isInternal: createDto.isInternal || false, + createdBy: user.user_id, + }); + const savedCorr = await queryRunner.manager.save(correspondence); + const revision = queryRunner.manager.create(correspondence_revision_entity_1.CorrespondenceRevision, { + correspondenceId: savedCorr.id, + revisionNumber: 0, + revisionLabel: this.getInitialRevisionLabel(type.typeCode), + isCurrent: true, + statusId: statusDraft.id, + subject: createDto.subject, + body: createDto.body, + remarks: createDto.remarks, + dueDate: createDto.dueDate ? new Date(createDto.dueDate) : undefined, + documentDate: createDto.documentDate + ? new Date(createDto.documentDate) + : undefined, + issuedDate: createDto.issuedDate + ? new Date(createDto.issuedDate) + : undefined, + receivedDate: createDto.receivedDate + ? new Date(createDto.receivedDate) + : undefined, + description: createDto.description, + details: createDto.details, + createdBy: user.user_id, + schemaVersion: 1, + }); + await queryRunner.manager.save(revision); + // Save Recipients (using resolved INT IDs) + if (resolvedRecipients && resolvedRecipients.length > 0) { + const recipients = resolvedRecipients.map((r) => queryRunner.manager.create(correspondence_recipient_entity_1.CorrespondenceRecipient, { + correspondenceId: savedCorr.id, + recipientOrganizationId: r.organizationId, + recipientType: r.type, + })); + await queryRunner.manager.save(recipients); + } + // Commit attachments from Temp → Permanent (Two-Phase Storage) + if (createDto.attachmentTempIds?.length) { + const issueDate = createDto.issuedDate + ? new Date(createDto.issuedDate) + : createDto.documentDate + ? new Date(createDto.documentDate) + : undefined; + await this.fileStorageService.commit(createDto.attachmentTempIds, { + issueDate, + documentType: 'Correspondence', + }); + } + await queryRunner.commitTransaction(); + // Start Workflow Instance (non-blocking) + try { + const workflowCode = `CORRESPONDENCE_${type.typeCode}`; + await this.workflowEngine.createInstance(workflowCode, 'correspondence', savedCorr.id.toString(), { + projectId: resolvedProjectId, + originatorId: userOrgId, + disciplineId: createDto.disciplineId, + initiatorId: user.user_id, + }); + } + catch (error) { + this.logger.warn(`Workflow not started for ${docNumber.number} (Code: CORRESPONDENCE_${type.typeCode}): ${error.message}`); + } + // Fire-and-forget search indexing (non-blocking, void intentional) + void this.searchService.indexDocument({ + id: savedCorr.id, + publicId: savedCorr.publicId, + type: 'correspondence', + docNumber: docNumber.number, + title: createDto.subject, + description: createDto.description, + status: 'DRAFT', + projectId: resolvedProjectId, + createdAt: new Date(), + }); + return { + ...savedCorr, + currentRevision: revision, + }; + } + catch (err) { + await queryRunner.rollbackTransaction(); + this.logger.error(`Failed to create correspondence: ${err.message}`); + throw err; + } + finally { + await queryRunner.release(); + } + } + async findAll(searchDto = {}) { + const { search, typeId, projectId, statusId, status, page = 1, limit = 10, } = searchDto; + const skip = (page - 1) * limit; + // Change: Query from Revision Repo + const query = this.revisionRepo + .createQueryBuilder('rev') + .leftJoinAndSelect('rev.correspondence', 'corr') + .leftJoinAndSelect('corr.type', 'type') + .leftJoinAndSelect('corr.project', 'project') + .leftJoinAndSelect('corr.originator', 'org') + .leftJoinAndSelect('rev.status', 'status'); + // Filter by Revision Status + const revStatus = searchDto.revisionStatus || 'CURRENT'; + if (revStatus === 'CURRENT') { + query.where('rev.isCurrent = :isCurrent', { isCurrent: true }); + } + else if (revStatus === 'OLD') { + query.where('rev.isCurrent = :isCurrent', { isCurrent: false }); + } + // If 'ALL', no filter needed on isCurrent + if (projectId) { + query.andWhere('corr.projectId = :projectId', { projectId }); + } + if (typeId) { + query.andWhere('corr.correspondenceTypeId = :typeId', { typeId }); + } + if (statusId) { + query.andWhere('rev.statusId = :statusId', { statusId }); + } + if (status) { + query.andWhere('status.statusCode = :status', { status }); + } + if (search) { + query.andWhere('(corr.correspondenceNumber LIKE :search OR rev.subject LIKE :search)', { search: `%${search}%` }); + } + // Default Sort: Latest Created + query.orderBy('rev.createdAt', 'DESC').skip(skip).take(limit); + const [items, total] = await query.getManyAndCount(); + return { + data: items, + meta: { + total, + page, + limit, + totalPages: Math.ceil(total / limit), + }, + }; + } + async findOne(id) { + const correspondence = await this.correspondenceRepo.findOne({ + where: { id }, + relations: [ + 'revisions', + 'revisions.status', + 'type', + 'project', + 'originator', + 'recipients', + 'recipients.recipientOrganization', // [v1.5.1] Fixed relation name + ], + }); + if (!correspondence) { + throw new common_1.NotFoundException(`Correspondence with ID ${id} not found`); + } + return correspondence; + } + async findOneByUuid(publicId) { + const correspondence = await this.correspondenceRepo.findOne({ + where: { publicId }, + relations: [ + 'revisions', + 'revisions.status', + 'type', + 'project', + 'originator', + 'recipients', + 'recipients.recipientOrganization', + ], + }); + if (!correspondence) { + throw new common_1.NotFoundException(`Correspondence with UUID ${publicId} not found`); + } + return correspondence; + } + async addReference(id, dto) { + const source = await this.correspondenceRepo.findOne({ where: { id } }); + // ADR-019: Resolve target publicId → internal INT id + const target = await this.correspondenceRepo.findOne({ + where: { publicId: dto.targetUuid }, + }); + if (!source || !target) { + throw new common_1.NotFoundException('Source or Target correspondence not found'); + } + if (source.id === target.id) { + throw new common_1.BadRequestException('Cannot reference self'); + } + const exists = await this.referenceRepo.findOne({ + where: { + sourceId: id, + targetId: target.id, + }, + }); + if (exists) { + return exists; + } + const ref = this.referenceRepo.create({ + sourceId: id, + targetId: target.id, + }); + return this.referenceRepo.save(ref); + } + async removeReference(id, targetId) { + const result = await this.referenceRepo.delete({ + sourceId: id, + targetId: targetId, + }); + if (result.affected === 0) { + throw new common_1.NotFoundException('Reference not found'); + } + } + async getTags(id) { + const rows = await this.tagRepo.find({ + where: { correspondenceId: id }, + relations: ['tag'], + }); + return rows.map((r) => r.tag).filter(Boolean); + } + async addTag(id, tagId) { + const correspondence = await this.correspondenceRepo.findOne({ + where: { id }, + }); + if (!correspondence) { + throw new common_1.NotFoundException(`Correspondence ${id} not found`); + } + const tag = await this.dataSource.manager.findOne(tag_entity_1.Tag, { + where: { id: tagId }, + }); + if (!tag) { + throw new common_1.NotFoundException(`Tag ${tagId} not found`); + } + const exists = await this.tagRepo.findOne({ + where: { correspondenceId: id, tagId }, + }); + if (exists) + return exists; + const row = this.tagRepo.create({ correspondenceId: id, tagId }); + return this.tagRepo.save(row); + } + async removeTag(id, tagId) { + const result = await this.tagRepo.delete({ correspondenceId: id, tagId }); + if (result.affected === 0) { + throw new common_1.NotFoundException('Tag assignment not found'); + } + } + async getReferences(id) { + const outgoing = await this.referenceRepo.find({ + where: { sourceId: id }, + relations: ['target', 'target.type'], + }); + const incoming = await this.referenceRepo.find({ + where: { targetId: id }, + relations: ['source', 'source.type'], + }); + return { outgoing, incoming }; + } + async update(id, updateDto, user) { + // 1. Find Current Revision + const revision = await this.revisionRepo.findOne({ + where: { + correspondenceId: id, + isCurrent: true, + }, + relations: ['correspondence'], + }); + if (!revision) { + throw new common_1.NotFoundException(`Current revision for correspondence ${id} not found`); + } + // 2. Check Permission + if (revision.statusId) { + const status = await this.statusRepo.findOne({ + where: { id: revision.statusId }, + }); + if (status && status.statusCode !== 'DRAFT') { + throw new common_1.BadRequestException('Only DRAFT documents can be updated'); + } + } + // ADR-019: Resolve UUID references in update DTO + const updResolvedProjectId = updateDto.projectId + ? await this.uuidResolver.resolveProjectId(updateDto.projectId) + : undefined; + const updResolvedOriginatorId = updateDto.originatorId + ? await this.uuidResolver.resolveOrganizationId(updateDto.originatorId) + : undefined; + const updResolvedRecipients = updateDto.recipients + ? await Promise.all(updateDto.recipients.map(async (r) => ({ + organizationId: await this.uuidResolver.resolveOrganizationId(r.organizationId), + type: r.type, + }))) + : undefined; + // 3. Update Correspondence Entity if needed + const correspondenceUpdate = {}; + if (updateDto.disciplineId) + correspondenceUpdate.disciplineId = updateDto.disciplineId; + if (updResolvedProjectId) + correspondenceUpdate.projectId = updResolvedProjectId; + if (updResolvedOriginatorId) + correspondenceUpdate.originatorId = updResolvedOriginatorId; + if (Object.keys(correspondenceUpdate).length > 0) { + await this.correspondenceRepo.update(id, correspondenceUpdate); + } + // 4. Update Revision Entity + const revisionUpdate = {}; + if (updateDto.subject) + revisionUpdate.subject = updateDto.subject; + if (updateDto.body) + revisionUpdate.body = updateDto.body; + if (updateDto.remarks) + revisionUpdate.remarks = updateDto.remarks; + // Format Date correctly if string + if (updateDto.dueDate) + revisionUpdate.dueDate = new Date(updateDto.dueDate); + if (updateDto.documentDate) + revisionUpdate.documentDate = new Date(updateDto.documentDate); + if (updateDto.issuedDate) + revisionUpdate.issuedDate = new Date(updateDto.issuedDate); + if (updateDto.receivedDate) + revisionUpdate.receivedDate = new Date(updateDto.receivedDate); + if (updateDto.description) + revisionUpdate.description = updateDto.description; + if (updateDto.details) + revisionUpdate.details = updateDto.details; + if (Object.keys(revisionUpdate).length > 0) { + await this.revisionRepo.update(revision.id, revisionUpdate); + } + // 4.5 Commit new attachments from Temp → Permanent (Two-Phase Storage) + if (updateDto.attachmentTempIds?.length) { + const issueDate = updateDto.issuedDate + ? new Date(updateDto.issuedDate) + : updateDto.documentDate + ? new Date(updateDto.documentDate) + : revision.issuedDate || revision.documentDate || undefined; + await this.fileStorageService.commit(updateDto.attachmentTempIds, { + issueDate: issueDate ? new Date(issueDate) : undefined, + documentType: 'Correspondence', + }); + } + // 5. Update Recipients if provided + if (updResolvedRecipients) { + const recipientRepo = this.dataSource.getRepository(correspondence_recipient_entity_1.CorrespondenceRecipient); + await recipientRepo.delete({ correspondenceId: id }); + const newRecipients = updResolvedRecipients.map((r) => recipientRepo.create({ + correspondenceId: id, + recipientOrganizationId: r.organizationId, + recipientType: r.type, + })); + await recipientRepo.save(newRecipients); + } + // 6. Regenerate Document Number if structural fields changed (Recipient, Discipline, Type, Project) + // AND it is a DRAFT. + // Fetch fresh data for context and comparison + const currentCorr = await this.correspondenceRepo.findOne({ + where: { id }, + relations: ['type', 'recipients', 'recipients.recipientOrganization'], + }); + if (currentCorr) { + const currentToRecipient = currentCorr.recipients?.find((r) => r.recipientType === 'TO'); + const currentRecipientId = currentToRecipient?.recipientOrganizationId; + // Check for ACTUAL value changes + const isProjectChanged = updResolvedProjectId !== undefined && + updResolvedProjectId !== currentCorr.projectId; + const isOriginatorChanged = updResolvedOriginatorId !== undefined && + updResolvedOriginatorId !== currentCorr.originatorId; + const isDisciplineChanged = updateDto.disciplineId !== undefined && + updateDto.disciplineId !== currentCorr.disciplineId; + const isTypeChanged = updateDto.typeId !== undefined && + updateDto.typeId !== currentCorr.correspondenceTypeId; + let isRecipientChanged = false; + let newRecipientId; + if (updResolvedRecipients) { + const newToRecipient = updResolvedRecipients.find((r) => r.type === 'TO'); + newRecipientId = newToRecipient?.organizationId; + if (newRecipientId !== currentRecipientId) { + isRecipientChanged = true; + } + } + if (isProjectChanged || + isDisciplineChanged || + isTypeChanged || + isRecipientChanged || + isOriginatorChanged) { + const targetRecipientId = isRecipientChanged + ? newRecipientId + : currentRecipientId; + // Resolve Recipient Code for the NEW context + let recipientCode = ''; + if (targetRecipientId) { + const recOrg = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { id: targetRecipientId }, + }); + if (recOrg) + recipientCode = recOrg.organizationCode; + } + // [Fix #6] Fetch real ORG Code from originator organization + const originatorOrgForUpdate = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { + id: updResolvedOriginatorId ?? currentCorr.originatorId ?? 0, + }, + }); + const orgCode = originatorOrgForUpdate?.organizationCode ?? 'UNK'; + // Prepare Contexts + const oldCtx = { + projectId: currentCorr.projectId, + originatorOrganizationId: currentCorr.originatorId ?? 0, + typeId: currentCorr.correspondenceTypeId, + disciplineId: currentCorr.disciplineId, + recipientOrganizationId: currentRecipientId, + year: new Date().getFullYear(), + }; + const newCtx = { + projectId: updResolvedProjectId ?? currentCorr.projectId, + originatorOrganizationId: updResolvedOriginatorId ?? currentCorr.originatorId ?? 0, + typeId: updateDto.typeId ?? currentCorr.correspondenceTypeId, + disciplineId: updateDto.disciplineId ?? currentCorr.disciplineId, + recipientOrganizationId: targetRecipientId, + year: new Date().getFullYear(), + userId: user.user_id, // Pass User ID for Audit + customTokens: { + TYPE_CODE: currentCorr.type?.typeCode || '', + ORG_CODE: orgCode, + RECIPIENT_CODE: recipientCode, + REC_CODE: recipientCode, + }, + }; + // If Type Changed, need NEW Type Code + if (isTypeChanged) { + const newType = await this.typeRepo.findOne({ + where: { id: newCtx.typeId }, + }); + if (newType) + newCtx.customTokens.TYPE_CODE = newType.typeCode; + } + const newDocNumber = await this.numberingService.updateNumberForDraft(currentCorr.correspondenceNumber, oldCtx, newCtx); + await this.correspondenceRepo.update(id, { + correspondenceNumber: newDocNumber, + }); + } + } + const updated = await this.findOne(id); + // Re-index updated document in Elasticsearch (fire-and-forget) + void this.searchService.indexDocument({ + id: updated.id, + publicId: updated.publicId, + type: 'correspondence', + docNumber: updated.correspondenceNumber, + title: updateDto.subject ?? updated.revisions?.[0]?.subject, + description: updateDto.description ?? updated.revisions?.[0]?.description, + status: 'DRAFT', + projectId: updated.projectId, + createdAt: updated.createdAt, + }); + return updated; + } + async previewDocumentNumber(createDto, user) { + // ADR-019: Resolve UUID references + const previewProjectId = await this.uuidResolver.resolveProjectId(createDto.projectId); + const previewOriginatorId = createDto.originatorId + ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId) + : undefined; + const previewRecipients = createDto.recipients + ? await Promise.all(createDto.recipients.map(async (r) => ({ + organizationId: await this.uuidResolver.resolveOrganizationId(r.organizationId), + type: r.type, + }))) + : undefined; + const type = await this.typeRepo.findOne({ + where: { id: createDto.typeId }, + }); + if (!type) + throw new common_1.NotFoundException('Document Type not found'); + let userOrgId = user.primaryOrganizationId; + if (!userOrgId) { + const fullUser = await this.userService.findOne(user.user_id); + if (fullUser) + userOrgId = fullUser.primaryOrganizationId; + } + if (previewOriginatorId && previewOriginatorId !== userOrgId) { + // Allow impersonation for preview + userOrgId = previewOriginatorId; + } + // Extract recipient from recipients array + const toRecipient = previewRecipients?.find((r) => r.type === 'TO'); + const recipientOrganizationId = toRecipient?.organizationId; + let recipientCode = ''; + if (recipientOrganizationId) { + const recOrg = await this.dataSource.manager.findOne(organization_entity_1.Organization, { + where: { id: recipientOrganizationId }, + }); + if (recOrg) + recipientCode = recOrg.organizationCode; + } + return this.numberingService.previewNumber({ + projectId: previewProjectId, + originatorOrganizationId: userOrgId, + typeId: createDto.typeId, + disciplineId: createDto.disciplineId, + subTypeId: createDto.subTypeId, + recipientOrganizationId, + year: new Date().getFullYear(), + customTokens: { + TYPE_CODE: type.typeCode, + RECIPIENT_CODE: recipientCode, + REC_CODE: recipientCode, + }, + }); + } + /** + * Business Rule Implementation: EC-CORR-001 - Cancel Correspondence with Downstream Circulation + * Cancel correspondence and handle related circulations + */ + async cancel(publicId, reason, user) { + const correspondence = await this.findOneByUuid(publicId); + // Check if user has permission to cancel (Org Admin or Superadmin only) + const permissions = await this.userService.getUserPermissions(user.user_id); + const canCancel = permissions.includes('correspondence.cancel') || + permissions.includes('system.manage_all'); + if (!canCancel) { + throw new common_1.ForbiddenException('Only administrators can cancel correspondences'); + } + // Check if there are any active circulations + const circulationRepo = this.dataSource.getRepository('Circulation'); + const activeCirculations = await circulationRepo.find({ + where: { + correspondenceId: correspondence.id, + status: 'OPEN', + }, + }); + const warningMessage = activeCirculations.length > 0 + ? `There are ${activeCirculations.length} active circulation(s) for this correspondence. Canceling will force close all related circulations.` + : ''; + // Get the current revision to update status + const currentRevision = await this.revisionRepo.findOne({ + where: { + correspondenceId: correspondence.id, + isCurrent: true, + }, + }); + if (!currentRevision) { + throw new common_1.NotFoundException('Current revision not found'); + } + // Get cancelled status + const cancelledStatus = await this.statusRepo.findOne({ + where: { statusCode: 'CANCELLED' }, + }); + if (!cancelledStatus) { + throw new common_1.InternalServerErrorException('CANCELLED status not found'); + } + const queryRunner = this.dataSource.createQueryRunner(); + await queryRunner.connect(); + await queryRunner.startTransaction(); + try { + // Update correspondence revision status to CANCELLED + await queryRunner.manager.update(correspondence_revision_entity_1.CorrespondenceRevision, currentRevision.id, { + statusId: cancelledStatus.id, + remarks: `Cancelled: ${reason}`, + }); + // Force close all active circulations + if (activeCirculations.length > 0) { + await queryRunner.manager.update('Circulation', { + correspondenceId: correspondence.id, + status: 'OPEN', + }, { + status: 'FORCE_CLOSED', + closedAt: new Date(), + closedBy: user.user_id, + closeReason: `Correspondence cancelled: ${reason}`, + }); + } + await queryRunner.commitTransaction(); + // Re-index cancelled status in Elasticsearch (fire-and-forget) + void this.searchService.indexDocument({ + id: correspondence.id, + publicId: correspondence.publicId, + type: 'correspondence', + docNumber: correspondence.correspondenceNumber, + title: currentRevision.subject, + status: 'CANCELLED', + projectId: correspondence.projectId, + createdAt: correspondence.createdAt, + }); + // Notify originator's doc-control user about cancellation (fire-and-forget) + if (correspondence.originatorId) { + void this.userService + .findDocControlIdByOrg(correspondence.originatorId) + .then((targetUserId) => { + if (targetUserId) { + void this.notificationService.send({ + userId: targetUserId, + title: 'Correspondence Cancelled', + message: `${correspondence.correspondenceNumber} — ${currentRevision.subject} has been cancelled. Reason: ${reason}`, + type: 'EMAIL', + entityType: 'correspondence', + entityId: correspondence.id, + link: `/correspondences/${correspondence.publicId}`, + }); + } + }) + .catch((err) => this.logger.warn(`Cancel notification failed: ${err.message}`)); + } + return { + success: true, + message: warningMessage || 'Correspondence cancelled successfully', + activeCirculationsCount: activeCirculations.length, + }; + } + catch (error) { + await queryRunner.rollbackTransaction(); + this.logger.error(`Failed to cancel correspondence: ${error.message}`); + throw error; + } + finally { + await queryRunner.release(); + } + } + async bulkCancel(publicIds, reason, user) { + const succeeded = []; + const failed = []; + for (const publicId of publicIds) { + try { + await this.cancel(publicId, reason, user); + succeeded.push(publicId); + } + catch { + failed.push(publicId); + } + } + return { succeeded, failed }; + } + async exportCsv(searchDto) { + const { data } = await this.findAll(searchDto); + const header = [ + 'Document No.', + 'Rev', + 'Subject', + 'Type', + 'Status', + 'Project', + 'From', + 'Due Date', + 'Created At', + ]; + const rows = data.map((rev) => { + const corr = rev.correspondence ?? rev; + return [ + this.escapeCsv(corr.correspondenceNumber ?? ''), + this.escapeCsv(rev.revisionLabel ?? String(rev.revisionNumber ?? 0)), + this.escapeCsv(rev.subject ?? ''), + this.escapeCsv(corr.type?.typeCode ?? ''), + this.escapeCsv(rev.status?.statusCode ?? ''), + this.escapeCsv(corr.project?.projectCode ?? ''), + this.escapeCsv(corr.originator?.organizationCode ?? ''), + rev.dueDate ? new Date(rev.dueDate).toISOString().split('T')[0] : '', + new Date(rev.createdAt).toISOString().split('T')[0], + ].join(','); + }); + return [header.join(','), ...rows].join('\n'); + } + escapeCsv(value) { + if (value.includes(',') || value.includes('"') || value.includes('\n')) { + return `"${value.replace(/"/g, '""')}"`; + } + return value; + } +}; +exports.CorrespondenceService = CorrespondenceService; +exports.CorrespondenceService = CorrespondenceService = CorrespondenceService_1 = __decorate([ + (0, common_1.Injectable)(), + __param(0, (0, typeorm_1.InjectRepository)(correspondence_entity_1.Correspondence)), + __param(1, (0, typeorm_1.InjectRepository)(correspondence_revision_entity_1.CorrespondenceRevision)), + __param(2, (0, typeorm_1.InjectRepository)(correspondence_type_entity_1.CorrespondenceType)), + __param(3, (0, typeorm_1.InjectRepository)(correspondence_status_entity_1.CorrespondenceStatus)), + __param(4, (0, typeorm_1.InjectRepository)(correspondence_reference_entity_1.CorrespondenceReference)), + __param(5, (0, typeorm_1.InjectRepository)(correspondence_tag_entity_1.CorrespondenceTag)), + __metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _a : Object, typeof (_b = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _b : Object, typeof (_c = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _c : Object, typeof (_d = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _d : Object, typeof (_e = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _e : Object, typeof (_f = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _f : Object, typeof (_g = typeof document_numbering_service_1.DocumentNumberingService !== "undefined" && document_numbering_service_1.DocumentNumberingService) === "function" ? _g : Object, typeof (_h = typeof json_schema_service_1.JsonSchemaService !== "undefined" && json_schema_service_1.JsonSchemaService) === "function" ? _h : Object, typeof (_j = typeof workflow_engine_service_1.WorkflowEngineService !== "undefined" && workflow_engine_service_1.WorkflowEngineService) === "function" ? _j : Object, typeof (_k = typeof user_service_1.UserService !== "undefined" && user_service_1.UserService) === "function" ? _k : Object, typeof (_l = typeof typeorm_2.DataSource !== "undefined" && typeorm_2.DataSource) === "function" ? _l : Object, typeof (_m = typeof search_service_1.SearchService !== "undefined" && search_service_1.SearchService) === "function" ? _m : Object, typeof (_o = typeof file_storage_service_1.FileStorageService !== "undefined" && file_storage_service_1.FileStorageService) === "function" ? _o : Object, typeof (_p = typeof uuid_resolver_service_1.UuidResolverService !== "undefined" && uuid_resolver_service_1.UuidResolverService) === "function" ? _p : Object, typeof (_q = typeof notification_service_1.NotificationService !== "undefined" && notification_service_1.NotificationService) === "function" ? _q : Object]) +], CorrespondenceService); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoiRTpcXG5wLWRtc1xcbGNicDNcXGJhY2tlbmRcXHNyY1xcbW9kdWxlc1xcY29ycmVzcG9uZGVuY2VcXGNvcnJlc3BvbmRlbmNlLnNlcnZpY2UudHMiLCJtYXBwaW5ncyI6IjtBQUFBLDZEQUE2RDs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFN0QsMkNBT3dCO0FBQ3hCLDZDQUFtRDtBQUNuRCxxQ0FBaUQ7QUFFakQsV0FBVztBQUNYLDRFQUFrRTtBQUNsRSw4RkFBbUY7QUFDbkYsc0ZBQTJFO0FBQzNFLDBGQUErRTtBQUMvRSxnR0FBcUY7QUFDckYsZ0dBQXFGO0FBQ3JGLG9GQUF5RTtBQUN6RSw4REFBb0Q7QUFFcEQsc0ZBQTRFO0FBUTVFLFdBQVc7QUFDWCwwR0FBcUc7QUFDckcsNEVBQXVFO0FBQ3ZFLHdGQUFtRjtBQUNuRix1REFBbUQ7QUFDbkQsNkRBQXlEO0FBQ3pELHlGQUFvRjtBQUNwRix1RkFBa0Y7QUFDbEYsK0VBQTJFO0FBVXBFLElBQU0scUJBQXFCLDZCQUEzQixNQUFNLHFCQUFxQjtJQUd4QixLQUFLLENBQUMsNEJBQTRCLENBQUMsTUFBYztRQUN2RCxNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDdEUsT0FBTyxXQUFXLENBQUMsUUFBUSxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDbkQsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyx1QkFBdUIsQ0FBQyxRQUFnQjtRQUM5QyxNQUFNLGFBQWEsR0FBRyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNyQyxJQUFJLGFBQWEsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxDQUFDLEVBQUUsQ0FBQztZQUNuRCxPQUFPLEdBQUcsQ0FBQyxDQUFDLHdCQUF3QjtRQUN0QyxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsQ0FBQyxnQ0FBZ0M7SUFDL0MsQ0FBQztJQUVELFlBRUUsa0JBQXNELEVBRXRELFlBQXdELEVBRXhELFFBQWdELEVB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QUFDLENBQUE7SUFFaEMsV0FBQSxJQUFBLDBCQUFnQixFQUFDLHVEQUFzQixDQUFDLENBQUE7SUFFeEMsV0FBQSxJQUFBLDBCQUFnQixFQUFDLCtDQUFrQixDQUFDLENBQUE7SUFFcEMsV0FBQSxJQUFBLDBCQUFnQixFQUFDLG1EQUFvQixDQUFDLENBQUE7SUFFdEMsV0FBQSxJQUFBLDBCQUFnQixFQUFDLHlEQUF1QixDQUFDLENBQUE7SUFFekMsV0FBQSxJQUFBLDBCQUFnQixFQUFDLDZDQUFpQixDQUFDLENBQUE7eURBVFIsb0JBQVUsb0JBQVYsb0JBQVUsb0RBRWhCLG9CQUFVLG9CQUFWLG9CQUFVLG9EQUVkLG9CQUFVLG9CQUFWLG9CQUFVLG9EQUVSLG9CQUFVLG9CQUFWLG9CQUFVLG9EQUVQLG9CQUFVLG9CQUFWLG9CQUFVLG9EQUVoQixvQkFBVSxvQkFBVixvQkFBVSxvREFDRCxxREFBd0Isb0JBQXhCLHFEQUF3QixvREFDdkIsdUNBQWlCLG9CQUFqQix1Q0FBaUIsb0RBQ3BCLCtDQUFxQixvQkFBckIsK0NBQXFCLG9EQUN4QiwwQkFBVyxvQkFBWCwwQkFBVyxvREFDWixvQkFBVSxvQkFBVixvQkFBVSxvREFDUCw4QkFBYSxvQkFBYiw4QkFBYSxvREFDUix5Q0FBa0Isb0JBQWxCLHlDQUFrQixvREFDeEIsMkNBQW1CLG9CQUFuQiwyQ0FBbUIsb0RBQ1osMENBQW1CLG9CQUFuQiwwQ0FBbUI7R0ExQ3ZDLHFCQUFxQixDQWtqQ2pDIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIkU6XFxucC1kbXNcXGxjYnAzXFxiYWNrZW5kXFxzcmNcXG1vZHVsZXNcXGNvcnJlc3BvbmRlbmNlXFxjb3JyZXNwb25kZW5jZS5zZXJ2aWNlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIEZpbGU6IHNyYy9tb2R1bGVzL2NvcnJlc3BvbmRlbmNlL2NvcnJlc3BvbmRlbmNlLnNlcnZpY2UudHNcclxuXHJcbmltcG9ydCB7XHJcbiAgSW5qZWN0YWJsZSxcclxuICBOb3RGb3VuZEV4Y2VwdGlvbixcclxuICBCYWRSZXF1ZXN0RXhjZXB0aW9uLFxyXG4gIEludGVybmFsU2VydmVyRXJyb3JFeGNlcHRpb24sXHJcbiAgRm9yYmlkZGVuRXhjZXB0aW9uLFxyXG4gIExvZ2dlcixcclxufSBmcm9tICdAbmVzdGpzL2NvbW1vbic7XHJcbmltcG9ydCB7IEluamVjdFJlcG9zaXRvcnkgfSBmcm9tICdAbmVzdGpzL3R5cGVvcm0nO1xyXG5pbXBvcnQgeyBSZXBvc2l0b3J5LCBEYXRhU291cmNlIH0gZnJvbSAndHlwZW9ybSc7XHJcblxyXG4vLyBFbnRpdGllc1xyXG5pbXBvcnQgeyBDb3JyZXNwb25kZW5jZSB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2UuZW50aXR5JztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VSZXZpc2lvbiB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2UtcmV2aXNpb24uZW50aXR5JztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VUeXBlIH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS10eXBlLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlU3RhdHVzIH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS1zdGF0dXMuZW50aXR5JztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VSZWZlcmVuY2UgfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLXJlZmVyZW5jZS5lbnRpdHknO1xyXG5pbXBvcnQgeyBDb3JyZXNwb25kZW5jZVJlY2lwaWVudCB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2UtcmVjaXBpZW50LmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlVGFnIH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS10YWcuZW50aXR5JztcclxuaW1wb3J0IHsgVGFnIH0gZnJvbSAnLi4vbWFzdGVyL2VudGl0aWVzL3RhZy5lbnRpdHknO1xyXG5pbXBvcnQgeyBVc2VyIH0gZnJvbSAnLi4vdXNlci9lbnRpdGllcy91c2VyLmVudGl0eSc7XHJcbmltcG9ydCB7IE9yZ2FuaXphdGlvbiB9IGZyb20gJy4uL29yZ2FuaXphdGlvbi9lbnRpdGllcy9vcmdhbml6YXRpb24uZW50aXR5JztcclxuXHJcbi8vIERUT3NcclxuaW1wb3J0IHsgQ3JlYXRlQ29ycmVzcG9uZGVuY2VEdG8gfSBmcm9tICcuL2R0by9jcmVhdGUtY29ycmVzcG9uZGVuY2UuZHRvJztcclxuaW1wb3J0IHsgVXBkYXRlQ29ycmVzcG9uZGVuY2VEdG8gfSBmcm9tICcuL2R0by91cGRhdGUtY29ycmVzcG9uZGVuY2UuZHRvJztcclxuaW1wb3J0IHsgQWRkUmVmZXJlbmNlRHRvIH0gZnJvbSAnLi9kdG8vYWRkLXJlZmVyZW5jZS5kdG8nO1xyXG5pbXBvcnQgeyBTZWFyY2hDb3JyZXNwb25kZW5jZUR0byB9IGZyb20gJy4vZHRvL3NlYXJjaC1jb3JyZXNwb25kZW5jZS5kdG8nO1xyXG5cclxuLy8gU2VydmljZXNcclxuaW1wb3J0IHsgRG9jdW1lbnROdW1iZXJpbmdTZXJ2aWNlIH0gZnJvbSAnLi4vZG9jdW1lbnQtbnVtYmVyaW5nL3NlcnZpY2VzL2RvY3VtZW50LW51bWJlcmluZy5zZXJ2aWNlJztcclxuaW1wb3J0IHsgSnNvblNjaGVtYVNlcnZpY2UgfSBmcm9tICcuLi9qc29uLXNjaGVtYS9qc29uLXNjaGVtYS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgV29ya2Zsb3dFbmdpbmVTZXJ2aWNlIH0gZnJvbSAnLi4vd29ya2Zsb3ctZW5naW5lL3dvcmtmbG93LWVuZ2luZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgVXNlclNlcnZpY2UgfSBmcm9tICcuLi91c2VyL3VzZXIuc2VydmljZSc7XHJcbmltcG9ydCB7IFNlYXJjaFNlcnZpY2UgfSBmcm9tICcuLi9zZWFyY2gvc2VhcmNoLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBGaWxlU3RvcmFnZVNlcnZpY2UgfSBmcm9tICcuLi8uLi9jb21tb24vZmlsZS1zdG9yYWdlL2ZpbGUtc3RvcmFnZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgVXVpZFJlc29sdmVyU2VydmljZSB9IGZyb20gJy4uLy4uL2NvbW1vbi9zZXJ2aWNlcy91dWlkLXJlc29sdmVyLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBOb3RpZmljYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi4vbm90aWZpY2F0aW9uL25vdGlmaWNhdGlvbi5zZXJ2aWNlJztcclxuXHJcbi8qKlxyXG4gKiBDb3JyZXNwb25kZW5jZVNlcnZpY2UgLSBEb2N1bWVudCBtYW5hZ2VtZW50IChDUlVEKVxyXG4gKi9cclxuaW50ZXJmYWNlIFJlc29sdmVkUmVjaXBpZW50IHtcclxuICBvcmdhbml6YXRpb25JZDogbnVtYmVyO1xyXG4gIHR5cGU6ICdUTycgfCAnQ0MnO1xyXG59XHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGNsYXNzIENvcnJlc3BvbmRlbmNlU2VydmljZSB7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBsb2dnZXIgPSBuZXcgTG9nZ2VyKENvcnJlc3BvbmRlbmNlU2VydmljZS5uYW1lKTtcclxuXHJcbiAgcHJpdmF0ZSBhc3luYyBoYXNTeXN0ZW1NYW5hZ2VBbGxQZXJtaXNzaW9uKHVzZXJJZDogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XHJcbiAgICBjb25zdCBwZXJtaXNzaW9ucyA9IGF3YWl0IHRoaXMudXNlclNlcnZpY2UuZ2V0VXNlclBlcm1pc3Npb25zKHVzZXJJZCk7XHJcbiAgICByZXR1cm4gcGVybWlzc2lvbnMuaW5jbHVkZXMoJ3N5c3RlbS5tYW5hZ2VfYWxsJyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBCdXNpbmVzcyBSdWxlOiBSZXZpc2lvbiBMYWJlbCBTdHJhdGVneVxyXG4gICAqIC0gUkZBLCBSRkk6IFVzZSBhbHBoYWJldCBzdGFydGluZyB3aXRoICdBJyAoQSwgQiwgQy4uLilcclxuICAgKiAtIE90aGVyIHR5cGVzIChMRVRURVIsIE1FTU8sIGV0Yy4pOiBVc2UgbnVtZXJpYyAobnVsbCBmb3IgZmlyc3QsIHRoZW4gMSwgMiwgMy4uLilcclxuICAgKi9cclxuICBwcml2YXRlIGdldEluaXRpYWxSZXZpc2lvbkxhYmVsKHR5cGVDb2RlOiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsIHtcclxuICAgIGNvbnN0IGFscGhhYmV0VHlwZXMgPSBbJ1JGQScsICdSRkknXTtcclxuICAgIGlmIChhbHBoYWJldFR5cGVzLmluY2x1ZGVzKHR5cGVDb2RlLnRvVXBwZXJDYXNlKCkpKSB7XHJcbiAgICAgIHJldHVybiAnQSc7IC8vIEFscGhhYmV0IGZvciBSRkEsIFJGSVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIG51bGw7IC8vIE51bWVyaWMgKG51bGwgZm9yIHJldmlzaW9uIDApXHJcbiAgfVxyXG5cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIEBJbmplY3RSZXBvc2l0b3J5KENvcnJlc3BvbmRlbmNlKVxyXG4gICAgcHJpdmF0ZSBjb3JyZXNwb25kZW5jZVJlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2U+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VSZXZpc2lvbilcclxuICAgIHByaXZhdGUgcmV2aXNpb25SZXBvOiBSZXBvc2l0b3J5PENvcnJlc3BvbmRlbmNlUmV2aXNpb24+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VUeXBlKVxyXG4gICAgcHJpdmF0ZSB0eXBlUmVwbzogUmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVR5cGU+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VTdGF0dXMpXHJcbiAgICBwcml2YXRlIHN0YXR1c1JlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VTdGF0dXM+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VSZWZlcmVuY2UpXHJcbiAgICBwcml2YXRlIHJlZmVyZW5jZVJlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VSZWZlcmVuY2U+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VUYWcpXHJcbiAgICBwcml2YXRlIHRhZ1JlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VUYWc+LFxyXG4gICAgcHJpdmF0ZSBudW1iZXJpbmdTZXJ2aWNlOiBEb2N1bWVudE51bWJlcmluZ1NlcnZpY2UsXHJcbiAgICBwcml2YXRlIGpzb25TY2hlbWFTZXJ2aWNlOiBKc29uU2NoZW1hU2VydmljZSxcclxuICAgIHByaXZhdGUgd29ya2Zsb3dFbmdpbmU6IFdvcmtmbG93RW5naW5lU2VydmljZSxcclxuICAgIHByaXZhdGUgdXNlclNlcnZpY2U6IFVzZXJTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBkYXRhU291cmNlOiBEYXRhU291cmNlLFxyXG4gICAgcHJpdmF0ZSBzZWFyY2hTZXJ2aWNlOiBTZWFyY2hTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBmaWxlU3RvcmFnZVNlcnZpY2U6IEZpbGVTdG9yYWdlU2VydmljZSxcclxuICAgIHByaXZhdGUgdXVpZFJlc29sdmVyOiBVdWlkUmVzb2x2ZXJTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBub3RpZmljYXRpb25TZXJ2aWNlOiBOb3RpZmljYXRpb25TZXJ2aWNlXHJcbiAgKSB7fVxyXG5cclxuICAvKipcclxuICAgKiBCdXNpbmVzcyBSdWxlIFZhbGlkYXRpb246IEVDLUNPUlItMDAzIC0gQ29ycmVzcG9uZGVuY2UgdG8gU2VsZlxyXG4gICAqIFByZXZlbnQgZXh0ZXJuYWwgY29ycmVzcG9uZGVuY2UgdG8gc2FtZSBvcmdhbml6YXRpb25cclxuICAgKi9cclxuICBwcml2YXRlIGFzeW5jIHZhbGlkYXRlQ29ycmVzcG9uZGVuY2VSZWNpcGllbnRzKFxyXG4gICAgY3JlYXRlRHRvOiBDcmVhdGVDb3JyZXNwb25kZW5jZUR0byxcclxuICAgIHVzZXI6IFVzZXJcclxuICApOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIC8vIEdldCB1c2VyJ3Mgb3JnYW5pemF0aW9uXHJcbiAgICBsZXQgdXNlck9yZ0lkID0gdXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcbiAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICBjb25zdCBmdWxsVXNlciA9IGF3YWl0IHRoaXMudXNlclNlcnZpY2UuZmluZE9uZSh1c2VyLnVzZXJfaWQpO1xyXG4gICAgICBpZiAoZnVsbFVzZXIpIHtcclxuICAgICAgICB1c2VyT3JnSWQgPSBmdWxsVXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICBpZiAoY3JlYXRlRHRvLm9yaWdpbmF0b3JJZCkge1xyXG4gICAgICAgIGNvbnN0IGNhbk1hbmFnZUFsbCA9IGF3YWl0IHRoaXMuaGFzU3lzdGVtTWFuYWdlQWxsUGVybWlzc2lvbihcclxuICAgICAgICAgIHVzZXIudXNlcl9pZFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgaWYgKGNhbk1hbmFnZUFsbCkge1xyXG4gICAgICAgICAgdXNlck9yZ0lkID0gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKFxyXG4gICAgICAgICAgICBjcmVhdGVEdG8ub3JpZ2luYXRvcklkXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKCF1c2VyT3JnSWQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgQmFkUmVxdWVzdEV4Y2VwdGlvbihcclxuICAgICAgICAgICdVc2VyIG11c3QgYmVsb25nIHRvIGFuIG9yZ2FuaXphdGlvbiB0byBjcmVhdGUgZG9jdW1lbnRzJ1xyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBGb3IgaW1wZXJzb25hdGlvbiwgdXNlIHRoZSBzcGVjaWZpZWQgb3JpZ2luYXRvclxyXG4gICAgY29uc3Qgb3JpZ2luYXRvck9yZ0lkID0gY3JlYXRlRHRvLm9yaWdpbmF0b3JJZFxyXG4gICAgICA/IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZChjcmVhdGVEdG8ub3JpZ2luYXRvcklkKVxyXG4gICAgICA6IHVzZXJPcmdJZDtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGludGVybmFsIGNvbW11bmljYXRpb25cclxuICAgIGlmIChjcmVhdGVEdG8uaXNJbnRlcm5hbCkge1xyXG4gICAgICAvLyBJbnRlcm5hbCBjb21tdW5pY2F0aW9ucyBzaG91bGQgdXNlIENpcmN1bGF0aW9uIGluc3RlYWRcclxuICAgICAgdGhyb3cgbmV3IEJhZFJlcXVlc3RFeGNlcHRpb24oXHJcbiAgICAgICAgJ0ludGVybmFsIGNvbW11bmljYXRpb25zIHNob3VsZCB1c2UgQ2lyY3VsYXRpb24gU2hlZXQgaW5zdGVhZCBvZiBDb3JyZXNwb25kZW5jZSdcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBWYWxpZGF0ZSByZWNpcGllbnRzXHJcbiAgICBpZiAoIWNyZWF0ZUR0by5yZWNpcGllbnRzIHx8IGNyZWF0ZUR0by5yZWNpcGllbnRzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICB0aHJvdyBuZXcgQmFkUmVxdWVzdEV4Y2VwdGlvbihcclxuICAgICAgICAnQXQgbGVhc3Qgb25lIHJlY2lwaWVudCAoVE8gb3IgQ0MpIGlzIHJlcXVpcmVkJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHRvUmVjaXBpZW50cyA9IGNyZWF0ZUR0by5yZWNpcGllbnRzLmZpbHRlcigocikgPT4gci50eXBlID09PSAnVE8nKTtcclxuICAgIGNvbnN0IGNjUmVjaXBpZW50cyA9IGNyZWF0ZUR0by5yZWNpcGllbnRzLmZpbHRlcigocikgPT4gci50eXBlID09PSAnQ0MnKTtcclxuXHJcbiAgICBpZiAodG9SZWNpcGllbnRzLmxlbmd0aCA9PT0gMCAmJiBjY1JlY2lwaWVudHMubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgIHRocm93IG5ldyBCYWRSZXF1ZXN0RXhjZXB0aW9uKFxyXG4gICAgICAgICdBdCBsZWFzdCBvbmUgVE8gb3IgQ0MgcmVjaXBpZW50IGlzIHJlcXVpcmVkJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGZvciBzYW1lIG9yZ2FuaXphdGlvbiBjb3JyZXNwb25kZW5jZVxyXG4gICAgZm9yIChjb25zdCByZWNpcGllbnQgb2YgY3JlYXRlRHRvLnJlY2lwaWVudHMpIHtcclxuICAgICAgY29uc3QgcmVjaXBpZW50T3JnSWQgPSBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlT3JnYW5pemF0aW9uSWQoXHJcbiAgICAgICAgcmVjaXBpZW50Lm9yZ2FuaXphdGlvbklkXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBpZiAocmVjaXBpZW50T3JnSWQgPT09IG9yaWdpbmF0b3JPcmdJZCkge1xyXG4gICAgICAgIHRocm93IG5ldyBCYWRSZXF1ZXN0RXhjZXB0aW9uKFxyXG4gICAgICAgICAgJ0Nhbm5vdCBzZW5kIGNvcnJlc3BvbmRlbmNlIHRvIHlvdXIgb3duIG9yZ2FuaXphdGlvbi4gVXNlIENpcmN1bGF0aW9uIFNoZWV0IGZvciBpbnRlcm5hbCBjb21tdW5pY2F0aW9uLidcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBhc3luYyBjcmVhdGUoY3JlYXRlRHRvOiBDcmVhdGVDb3JyZXNwb25kZW5jZUR0bywgdXNlcjogVXNlcikge1xyXG4gICAgLy8gQnVzaW5lc3MgUnVsZSBWYWxpZGF0aW9uOiBFQy1DT1JSLTAwMyAtIENvcnJlc3BvbmRlbmNlIHRvIFNlbGZcclxuICAgIGF3YWl0IHRoaXMudmFsaWRhdGVDb3JyZXNwb25kZW5jZVJlY2lwaWVudHMoY3JlYXRlRHRvLCB1c2VyKTtcclxuICAgIC8vIEFEUi0wMTk6IFJlc29sdmUgVVVJRCByZWZlcmVuY2VzIHRvIGludGVybmFsIElOVCBJRHNcclxuICAgIGNvbnN0IHJlc29sdmVkUHJvamVjdElkID0gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZVByb2plY3RJZChcclxuICAgICAgY3JlYXRlRHRvLnByb2plY3RJZFxyXG4gICAgKTtcclxuICAgIGNvbnN0IHJlc29sdmVkT3JpZ2luYXRvcklkID0gY3JlYXRlRHRvLm9yaWdpbmF0b3JJZFxyXG4gICAgICA/IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZChjcmVhdGVEdG8ub3JpZ2luYXRvcklkKVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuICAgIGNvbnN0IHJlc29sdmVkUmVjaXBpZW50cyA9IGNyZWF0ZUR0by5yZWNpcGllbnRzXHJcbiAgICAgID8gYXdhaXQgUHJvbWlzZS5hbGwoXHJcbiAgICAgICAgICBjcmVhdGVEdG8ucmVjaXBpZW50cy5tYXAoXHJcbiAgICAgICAgICAgIGFzeW5jIChyKTogUHJvbWlzZTxSZXNvbHZlZFJlY2lwaWVudD4gPT4gKHtcclxuICAgICAgICAgICAgICBvcmdhbml6YXRpb25JZDogYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKFxyXG4gICAgICAgICAgICAgICAgci5vcmdhbml6YXRpb25JZFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgICAgdHlwZTogci50eXBlLFxyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgIClcclxuICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICBjb25zdCB0eXBlID0gYXdhaXQgdGhpcy50eXBlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgaWQ6IGNyZWF0ZUR0by50eXBlSWQgfSxcclxuICAgIH0pO1xyXG4gICAgaWYgKCF0eXBlKSB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oJ0RvY3VtZW50IFR5cGUgbm90IGZvdW5kJyk7XHJcblxyXG4gICAgY29uc3Qgc3RhdHVzRHJhZnQgPSBhd2FpdCB0aGlzLnN0YXR1c1JlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IHN0YXR1c0NvZGU6ICdEUkFGVCcgfSxcclxuICAgIH0pO1xyXG4gICAgaWYgKCFzdGF0dXNEcmFmdCkge1xyXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxTZXJ2ZXJFcnJvckV4Y2VwdGlvbihcclxuICAgICAgICAnU3RhdHVzIERSQUZUIG5vdCBmb3VuZCBpbiBNYXN0ZXIgRGF0YSdcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgdXNlck9yZ0lkID0gdXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcblxyXG4gICAgaWYgKCF1c2VyT3JnSWQpIHtcclxuICAgICAgY29uc3QgZnVsbFVzZXIgPSBhd2FpdCB0aGlzLnVzZXJTZXJ2aWNlLmZpbmRPbmUodXNlci51c2VyX2lkKTtcclxuICAgICAgaWYgKGZ1bGxVc2VyKSB7XHJcbiAgICAgICAgdXNlck9yZ0lkID0gZnVsbFVzZXIucHJpbWFyeU9yZ2FuaXphdGlvbklkO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSW1wZXJzb25hdGlvbiBMb2dpY1xyXG4gICAgaWYgKHJlc29sdmVkT3JpZ2luYXRvcklkICYmIHJlc29sdmVkT3JpZ2luYXRvcklkICE9PSB1c2VyT3JnSWQpIHtcclxuICAgICAgY29uc3QgY2FuTWFuYWdlQWxsID0gYXdhaXQgdGhpcy5oYXNTeXN0ZW1NYW5hZ2VBbGxQZXJtaXNzaW9uKFxyXG4gICAgICAgIHVzZXIudXNlcl9pZFxyXG4gICAgICApO1xyXG4gICAgICBpZiAoIWNhbk1hbmFnZUFsbCkge1xyXG4gICAgICAgIHRocm93IG5ldyBGb3JiaWRkZW5FeGNlcHRpb24oXHJcbiAgICAgICAgICAnWW91IGRvIG5vdCBoYXZlIHBlcm1pc3Npb24gdG8gY3JlYXRlIGRvY3VtZW50cyBvbiBiZWhhbGYgb2Ygb3RoZXIgb3JnYW5pemF0aW9ucy4nXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgICB1c2VyT3JnSWQgPSByZXNvbHZlZE9yaWdpbmF0b3JJZDtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICB0aHJvdyBuZXcgQmFkUmVxdWVzdEV4Y2VwdGlvbihcclxuICAgICAgICAnVXNlciBtdXN0IGJlbG9uZyB0byBhbiBvcmdhbml6YXRpb24gdG8gY3JlYXRlIGRvY3VtZW50cydcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoY3JlYXRlRHRvLmRldGFpbHMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBhd2FpdCB0aGlzLmpzb25TY2hlbWFTZXJ2aWNlLnZhbGlkYXRlKHR5cGUudHlwZUNvZGUsIGNyZWF0ZUR0by5kZXRhaWxzKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcclxuICAgICAgICB0aGlzLmxvZ2dlci53YXJuKFxyXG4gICAgICAgICAgYFNjaGVtYSB2YWxpZGF0aW9uIHdhcm5pbmcgZm9yICR7dHlwZS50eXBlQ29kZX06ICR7KGVycm9yIGFzIEVycm9yKS5tZXNzYWdlfWBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgcXVlcnlSdW5uZXIgPSB0aGlzLmRhdGFTb3VyY2UuY3JlYXRlUXVlcnlSdW5uZXIoKTtcclxuICAgIGF3YWl0IHF1ZXJ5UnVubmVyLmNvbm5lY3QoKTtcclxuICAgIGF3YWl0IHF1ZXJ5UnVubmVyLnN0YXJ0VHJhbnNhY3Rpb24oKTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBbRml4ICM2XSBGZXRjaCByZWFsIE9SRyBDb2RlIGZyb20gT3JnYW5pemF0aW9uIGVudGl0eVxyXG4gICAgICBjb25zdCBvcmlnaW5hdG9yT3JnID0gYXdhaXQgdGhpcy5kYXRhU291cmNlLm1hbmFnZXIuZmluZE9uZShcclxuICAgICAgICBPcmdhbml6YXRpb24sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgd2hlcmU6IHsgaWQ6IHVzZXJPcmdJZCB9LFxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICAgICAgY29uc3Qgb3JnQ29kZSA9IG9yaWdpbmF0b3JPcmc/Lm9yZ2FuaXphdGlvbkNvZGUgPz8gJ1VOSyc7XHJcblxyXG4gICAgICAvLyBbdjEuNS4xXSBFeHRyYWN0IHJlY2lwaWVudCBvcmdhbml6YXRpb24gZnJvbSByZWNpcGllbnRzIGFycmF5IChQcmltYXJ5IFRPKVxyXG4gICAgICBjb25zdCB0b1JlY2lwaWVudCA9IHJlc29sdmVkUmVjaXBpZW50cz8uZmluZCgocikgPT4gci50eXBlID09PSAnVE8nKTtcclxuICAgICAgY29uc3QgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQgPSB0b1JlY2lwaWVudD8ub3JnYW5pemF0aW9uSWQ7XHJcblxyXG4gICAgICBsZXQgcmVjaXBpZW50Q29kZSA9ICcnO1xyXG4gICAgICBpZiAocmVjaXBpZW50T3JnYW5pemF0aW9uSWQpIHtcclxuICAgICAgICBjb25zdCByZWNPcmcgPSBhd2FpdCB0aGlzLmRhdGFTb3VyY2UubWFuYWdlci5maW5kT25lKE9yZ2FuaXphdGlvbiwge1xyXG4gICAgICAgICAgd2hlcmU6IHsgaWQ6IHJlY2lwaWVudE9yZ2FuaXphdGlvbklkIH0sXHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgaWYgKHJlY09yZykgcmVjaXBpZW50Q29kZSA9IHJlY09yZy5vcmdhbml6YXRpb25Db2RlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBjb25zdCBkb2NOdW1iZXIgPSBhd2FpdCB0aGlzLm51bWJlcmluZ1NlcnZpY2UuZ2VuZXJhdGVOZXh0TnVtYmVyKHtcclxuICAgICAgICBwcm9qZWN0SWQ6IHJlc29sdmVkUHJvamVjdElkLFxyXG4gICAgICAgIG9yaWdpbmF0b3JPcmdhbml6YXRpb25JZDogdXNlck9yZ0lkLFxyXG4gICAgICAgIHR5cGVJZDogY3JlYXRlRHRvLnR5cGVJZCxcclxuICAgICAgICBkaXNjaXBsaW5lSWQ6IGNyZWF0ZUR0by5kaXNjaXBsaW5lSWQsXHJcbiAgICAgICAgc3ViVHlwZUlkOiBjcmVhdGVEdG8uc3ViVHlwZUlkLFxyXG4gICAgICAgIHJlY2lwaWVudE9yZ2FuaXphdGlvbklkLCAvLyBbdjEuNS4xXSBQYXNzIHJlY2lwaWVudCBmb3IgZG9jdW1lbnQgbnVtYmVyIGZvcm1hdFxyXG4gICAgICAgIHllYXI6IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKSxcclxuICAgICAgICBjdXN0b21Ub2tlbnM6IHtcclxuICAgICAgICAgIFRZUEVfQ09ERTogdHlwZS50eXBlQ29kZSxcclxuICAgICAgICAgIE9SR19DT0RFOiBvcmdDb2RlLFxyXG4gICAgICAgICAgUkVDSVBJRU5UX0NPREU6IHJlY2lwaWVudENvZGUsXHJcbiAgICAgICAgICBSRUNfQ09ERTogcmVjaXBpZW50Q29kZSxcclxuICAgICAgICB9LFxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGNvbnN0IGNvcnJlc3BvbmRlbmNlID0gcXVlcnlSdW5uZXIubWFuYWdlci5jcmVhdGUoQ29ycmVzcG9uZGVuY2UsIHtcclxuICAgICAgICBjb3JyZXNwb25kZW5jZU51bWJlcjogZG9jTnVtYmVyLm51bWJlcixcclxuICAgICAgICBjb3JyZXNwb25kZW5jZVR5cGVJZDogY3JlYXRlRHRvLnR5cGVJZCxcclxuICAgICAgICBkaXNjaXBsaW5lSWQ6IGNyZWF0ZUR0by5kaXNjaXBsaW5lSWQsXHJcbiAgICAgICAgcHJvamVjdElkOiByZXNvbHZlZFByb2plY3RJZCxcclxuICAgICAgICBvcmlnaW5hdG9ySWQ6IHVzZXJPcmdJZCxcclxuICAgICAgICBpc0ludGVybmFsOiBjcmVhdGVEdG8uaXNJbnRlcm5hbCB8fCBmYWxzZSxcclxuICAgICAgICBjcmVhdGVkQnk6IHVzZXIudXNlcl9pZCxcclxuICAgICAgfSk7XHJcbiAgICAgIGNvbnN0IHNhdmVkQ29yciA9IGF3YWl0IHF1ZXJ5UnVubmVyLm1hbmFnZXIuc2F2ZShjb3JyZXNwb25kZW5jZSk7XHJcblxyXG4gICAgICBjb25zdCByZXZpc2lvbiA9IHF1ZXJ5UnVubmVyLm1hbmFnZXIuY3JlYXRlKENvcnJlc3BvbmRlbmNlUmV2aXNpb24sIHtcclxuICAgICAgICBjb3JyZXNwb25kZW5jZUlkOiBzYXZlZENvcnIuaWQsXHJcbiAgICAgICAgcmV2aXNpb25OdW1iZXI6IDAsXHJcbiAgICAgICAgcmV2aXNpb25MYWJlbDogdGhpcy5nZXRJbml0aWFsUmV2aXNpb25MYWJlbCh0eXBlLnR5cGVDb2RlKSxcclxuICAgICAgICBpc0N1cnJlbnQ6IHRydWUsXHJcbiAgICAgICAgc3RhdHVzSWQ6IHN0YXR1c0RyYWZ0LmlkLFxyXG4gICAgICAgIHN1YmplY3Q6IGNyZWF0ZUR0by5zdWJqZWN0LFxyXG4gICAgICAgIGJvZHk6IGNyZWF0ZUR0by5ib2R5LFxyXG4gICAgICAgIHJlbWFya3M6IGNyZWF0ZUR0by5yZW1hcmtzLFxyXG4gICAgICAgIGR1ZURhdGU6IGNyZWF0ZUR0by5kdWVEYXRlID8gbmV3IERhdGUoY3JlYXRlRHRvLmR1ZURhdGUpIDogdW5kZWZpbmVkLFxyXG4gICAgICAgIGRvY3VtZW50RGF0ZTogY3JlYXRlRHRvLmRvY3VtZW50RGF0ZVxyXG4gICAgICAgICAgPyBuZXcgRGF0ZShjcmVhdGVEdG8uZG9jdW1lbnREYXRlKVxyXG4gICAgICAgICAgOiB1bmRlZmluZWQsXHJcbiAgICAgICAgaXNzdWVkRGF0ZTogY3JlYXRlRHRvLmlzc3VlZERhdGVcclxuICAgICAgICAgID8gbmV3IERhdGUoY3JlYXRlRHRvLmlzc3VlZERhdGUpXHJcbiAgICAgICAgICA6IHVuZGVmaW5lZCxcclxuICAgICAgICByZWNlaXZlZERhdGU6IGNyZWF0ZUR0by5yZWNlaXZlZERhdGVcclxuICAgICAgICAgID8gbmV3IERhdGUoY3JlYXRlRHRvLnJlY2VpdmVkRGF0ZSlcclxuICAgICAgICAgIDogdW5kZWZpbmVkLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiBjcmVhdGVEdG8uZGVzY3JpcHRpb24sXHJcbiAgICAgICAgZGV0YWlsczogY3JlYXRlRHRvLmRldGFpbHMsXHJcbiAgICAgICAgY3JlYXRlZEJ5OiB1c2VyLnVzZXJfaWQsXHJcbiAgICAgICAgc2NoZW1hVmVyc2lvbjogMSxcclxuICAgICAgfSk7XHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLm1hbmFnZXIuc2F2ZShyZXZpc2lvbik7XHJcblxyXG4gICAgICAvLyBTYXZlIFJlY2lwaWVudHMgKHVzaW5nIHJlc29sdmVkIElOVCBJRHMpXHJcbiAgICAgIGlmIChyZXNvbHZlZFJlY2lwaWVudHMgJiYgcmVzb2x2ZWRSZWNpcGllbnRzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICBjb25zdCByZWNpcGllbnRzID0gcmVzb2x2ZWRSZWNpcGllbnRzLm1hcCgocikgPT5cclxuICAgICAgICAgIHF1ZXJ5UnVubmVyLm1hbmFnZXIuY3JlYXRlKENvcnJlc3BvbmRlbmNlUmVjaXBpZW50LCB7XHJcbiAgICAgICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IHNhdmVkQ29yci5pZCxcclxuICAgICAgICAgICAgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQ6IHIub3JnYW5pemF0aW9uSWQsXHJcbiAgICAgICAgICAgIHJlY2lwaWVudFR5cGU6IHIudHlwZSxcclxuICAgICAgICAgIH0pXHJcbiAgICAgICAgKTtcclxuICAgICAgICBhd2FpdCBxdWVyeVJ1bm5lci5tYW5hZ2VyLnNhdmUocmVjaXBpZW50cyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENvbW1pdCBhdHRhY2htZW50cyBmcm9tIFRlbXAg4oaSIFBlcm1hbmVudCAoVHdvLVBoYXNlIFN0b3JhZ2UpXHJcbiAgICAgIGlmIChjcmVhdGVEdG8uYXR0YWNobWVudFRlbXBJZHM/Lmxlbmd0aCkge1xyXG4gICAgICAgIGNvbnN0IGlzc3VlRGF0ZSA9IGNyZWF0ZUR0by5pc3N1ZWREYXRlXHJcbiAgICAgICAgICA/IG5ldyBEYXRlKGNyZWF0ZUR0by5pc3N1ZWREYXRlKVxyXG4gICAgICAgICAgOiBjcmVhdGVEdG8uZG9jdW1lbnREYXRlXHJcbiAgICAgICAgICAgID8gbmV3IERhdGUoY3JlYXRlRHRvLmRvY3VtZW50RGF0ZSlcclxuICAgICAgICAgICAgOiB1bmRlZmluZWQ7XHJcblxyXG4gICAgICAgIGF3YWl0IHRoaXMuZmlsZVN0b3JhZ2VTZXJ2aWNlLmNvbW1pdChjcmVhdGVEdG8uYXR0YWNobWVudFRlbXBJZHMsIHtcclxuICAgICAgICAgIGlzc3VlRGF0ZSxcclxuICAgICAgICAgIGRvY3VtZW50VHlwZTogJ0NvcnJlc3BvbmRlbmNlJyxcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgYXdhaXQgcXVlcnlSdW5uZXIuY29tbWl0VHJhbnNhY3Rpb24oKTtcclxuXHJcbiAgICAgIC8vIFN0YXJ0IFdvcmtmbG93IEluc3RhbmNlIChub24tYmxvY2tpbmcpXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3Qgd29ya2Zsb3dDb2RlID0gYENPUlJFU1BPTkRFTkNFXyR7dHlwZS50eXBlQ29kZX1gO1xyXG4gICAgICAgIGF3YWl0IHRoaXMud29ya2Zsb3dFbmdpbmUuY3JlYXRlSW5zdGFuY2UoXHJcbiAgICAgICAgICB3b3JrZmxvd0NvZGUsXHJcbiAgICAgICAgICAnY29ycmVzcG9uZGVuY2UnLFxyXG4gICAgICAgICAgc2F2ZWRDb3JyLmlkLnRvU3RyaW5nKCksXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIHByb2plY3RJZDogcmVzb2x2ZWRQcm9qZWN0SWQsXHJcbiAgICAgICAgICAgIG9yaWdpbmF0b3JJZDogdXNlck9yZ0lkLFxyXG4gICAgICAgICAgICBkaXNjaXBsaW5lSWQ6IGNyZWF0ZUR0by5kaXNjaXBsaW5lSWQsXHJcbiAgICAgICAgICAgIGluaXRpYXRvcklkOiB1c2VyLnVzZXJfaWQsXHJcbiAgICAgICAgICB9IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+XHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcclxuICAgICAgICB0aGlzLmxvZ2dlci53YXJuKFxyXG4gICAgICAgICAgYFdvcmtmbG93IG5vdCBzdGFydGVkIGZvciAke2RvY051bWJlci5udW1iZXJ9IChDb2RlOiBDT1JSRVNQT05ERU5DRV8ke3R5cGUudHlwZUNvZGV9KTogJHsoZXJyb3IgYXMgRXJyb3IpLm1lc3NhZ2V9YFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEZpcmUtYW5kLWZvcmdldCBzZWFyY2ggaW5kZXhpbmcgKG5vbi1ibG9ja2luZywgdm9pZCBpbnRlbnRpb25hbClcclxuICAgICAgdm9pZCB0aGlzLnNlYXJjaFNlcnZpY2UuaW5kZXhEb2N1bWVudCh7XHJcbiAgICAgICAgaWQ6IHNhdmVkQ29yci5pZCxcclxuICAgICAgICBwdWJsaWNJZDogc2F2ZWRDb3JyLnB1YmxpY0lkLFxyXG4gICAgICAgIHR5cGU6ICdjb3JyZXNwb25kZW5jZScsXHJcbiAgICAgICAgZG9jTnVtYmVyOiBkb2NOdW1iZXIubnVtYmVyLFxyXG4gICAgICAgIHRpdGxlOiBjcmVhdGVEdG8uc3ViamVjdCxcclxuICAgICAgICBkZXNjcmlwdGlvbjogY3JlYXRlRHRvLmRlc2NyaXB0aW9uLFxyXG4gICAgICAgIHN0YXR1czogJ0RSQUZUJyxcclxuICAgICAgICBwcm9qZWN0SWQ6IHJlc29sdmVkUHJvamVjdElkLFxyXG4gICAgICAgIGNyZWF0ZWRBdDogbmV3IERhdGUoKSxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIC4uLnNhdmVkQ29ycixcclxuICAgICAgICBjdXJyZW50UmV2aXNpb246IHJldmlzaW9uLFxyXG4gICAgICB9O1xyXG4gICAgfSBjYXRjaCAoZXJyKSB7XHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLnJvbGxiYWNrVHJhbnNhY3Rpb24oKTtcclxuICAgICAgdGhpcy5sb2dnZXIuZXJyb3IoXHJcbiAgICAgICAgYEZhaWxlZCB0byBjcmVhdGUgY29ycmVzcG9uZGVuY2U6ICR7KGVyciBhcyBFcnJvcikubWVzc2FnZX1gXHJcbiAgICAgICk7XHJcbiAgICAgIHRocm93IGVycjtcclxuICAgIH0gZmluYWxseSB7XHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLnJlbGVhc2UoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFzeW5jIGZpbmRBbGwoc2VhcmNoRHRvOiBTZWFyY2hDb3JyZXNwb25kZW5jZUR0byA9IHt9KSB7XHJcbiAgICBjb25zdCB7XHJcbiAgICAgIHNlYXJjaCxcclxuICAgICAgdHlwZUlkLFxyXG4gICAgICBwcm9qZWN0SWQsXHJcbiAgICAgIHN0YXR1c0lkLFxyXG4gICAgICBzdGF0dXMsXHJcbiAgICAgIHBhZ2UgPSAxLFxyXG4gICAgICBsaW1pdCA9IDEwLFxyXG4gICAgfSA9IHNlYXJjaER0bztcclxuICAgIGNvbnN0IHNraXAgPSAocGFnZSAtIDEpICogbGltaXQ7XHJcblxyXG4gICAgLy8gQ2hhbmdlOiBRdWVyeSBmcm9tIFJldmlzaW9uIFJlcG9cclxuICAgIGNvbnN0IHF1ZXJ5ID0gdGhpcy5yZXZpc2lvblJlcG9cclxuICAgICAgLmNyZWF0ZVF1ZXJ5QnVpbGRlcigncmV2JylcclxuICAgICAgLmxlZnRKb2luQW5kU2VsZWN0KCdyZXYuY29ycmVzcG9uZGVuY2UnLCAnY29ycicpXHJcbiAgICAgIC5sZWZ0Sm9pbkFuZFNlbGVjdCgnY29yci50eXBlJywgJ3R5cGUnKVxyXG4gICAgICAubGVmdEpvaW5BbmRTZWxlY3QoJ2NvcnIucHJvamVjdCcsICdwcm9qZWN0JylcclxuICAgICAgLmxlZnRKb2luQW5kU2VsZWN0KCdjb3JyLm9yaWdpbmF0b3InLCAnb3JnJylcclxuICAgICAgLmxlZnRKb2luQW5kU2VsZWN0KCdyZXYuc3RhdHVzJywgJ3N0YXR1cycpO1xyXG5cclxuICAgIC8vIEZpbHRlciBieSBSZXZpc2lvbiBTdGF0dXNcclxuICAgIGNvbnN0IHJldlN0YXR1cyA9IHNlYXJjaER0by5yZXZpc2lvblN0YXR1cyB8fCAnQ1VSUkVOVCc7XHJcblxyXG4gICAgaWYgKHJldlN0YXR1cyA9PT0gJ0NVUlJFTlQnKSB7XHJcbiAgICAgIHF1ZXJ5LndoZXJlKCdyZXYuaXNDdXJyZW50ID0gOmlzQ3VycmVudCcsIHsgaXNDdXJyZW50OiB0cnVlIH0pO1xyXG4gICAgfSBlbHNlIGlmIChyZXZTdGF0dXMgPT09ICdPTEQnKSB7XHJcbiAgICAgIHF1ZXJ5LndoZXJlKCdyZXYuaXNDdXJyZW50ID0gOmlzQ3VycmVudCcsIHsgaXNDdXJyZW50OiBmYWxzZSB9KTtcclxuICAgIH1cclxuICAgIC8vIElmICdBTEwnLCBubyBmaWx0ZXIgbmVlZGVkIG9uIGlzQ3VycmVudFxyXG5cclxuICAgIGlmIChwcm9qZWN0SWQpIHtcclxuICAgICAgcXVlcnkuYW5kV2hlcmUoJ2NvcnIucHJvamVjdElkID0gOnByb2plY3RJZCcsIHsgcHJvamVjdElkIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0eXBlSWQpIHtcclxuICAgICAgcXVlcnkuYW5kV2hlcmUoJ2NvcnIuY29ycmVzcG9uZGVuY2VUeXBlSWQgPSA6dHlwZUlkJywgeyB0eXBlSWQgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHN0YXR1c0lkKSB7XHJcbiAgICAgIHF1ZXJ5LmFuZFdoZXJlKCdyZXYuc3RhdHVzSWQgPSA6c3RhdHVzSWQnLCB7IHN0YXR1c0lkIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChzdGF0dXMpIHtcclxuICAgICAgcXVlcnkuYW5kV2hlcmUoJ3N0YXR1cy5zdGF0dXNDb2RlID0gOnN0YXR1cycsIHsgc3RhdHVzIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChzZWFyY2gpIHtcclxuICAgICAgcXVlcnkuYW5kV2hlcmUoXHJcbiAgICAgICAgJyhjb3JyLmNvcnJlc3BvbmRlbmNlTnVtYmVyIExJS0UgOnNlYXJjaCBPUiByZXYuc3ViamVjdCBMSUtFIDpzZWFyY2gpJyxcclxuICAgICAgICB7IHNlYXJjaDogYCUke3NlYXJjaH0lYCB9XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVmYXVsdCBTb3J0OiBMYXRlc3QgQ3JlYXRlZFxyXG4gICAgcXVlcnkub3JkZXJCeSgncmV2LmNyZWF0ZWRBdCcsICdERVNDJykuc2tpcChza2lwKS50YWtlKGxpbWl0KTtcclxuXHJcbiAgICBjb25zdCBbaXRlbXMsIHRvdGFsXSA9IGF3YWl0IHF1ZXJ5LmdldE1hbnlBbmRDb3VudCgpO1xyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGRhdGE6IGl0ZW1zLFxyXG4gICAgICBtZXRhOiB7XHJcbiAgICAgICAgdG90YWwsXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICBsaW1pdCxcclxuICAgICAgICB0b3RhbFBhZ2VzOiBNYXRoLmNlaWwodG90YWwgLyBsaW1pdCksXHJcbiAgICAgIH0sXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgZmluZE9uZShpZDogbnVtYmVyKSB7XHJcbiAgICBjb25zdCBjb3JyZXNwb25kZW5jZSA9IGF3YWl0IHRoaXMuY29ycmVzcG9uZGVuY2VSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZTogeyBpZCB9LFxyXG4gICAgICByZWxhdGlvbnM6IFtcclxuICAgICAgICAncmV2aXNpb25zJyxcclxuICAgICAgICAncmV2aXNpb25zLnN0YXR1cycsXHJcbiAgICAgICAgJ3R5cGUnLFxyXG4gICAgICAgICdwcm9qZWN0JyxcclxuICAgICAgICAnb3JpZ2luYXRvcicsXHJcbiAgICAgICAgJ3JlY2lwaWVudHMnLFxyXG4gICAgICAgICdyZWNpcGllbnRzLnJlY2lwaWVudE9yZ2FuaXphdGlvbicsIC8vIFt2MS41LjFdIEZpeGVkIHJlbGF0aW9uIG5hbWVcclxuICAgICAgXSxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmICghY29ycmVzcG9uZGVuY2UpIHtcclxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXhjZXB0aW9uKGBDb3JyZXNwb25kZW5jZSB3aXRoIElEICR7aWR9IG5vdCBmb3VuZGApO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGNvcnJlc3BvbmRlbmNlO1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgZmluZE9uZUJ5VXVpZChwdWJsaWNJZDogc3RyaW5nKSB7XHJcbiAgICBjb25zdCBjb3JyZXNwb25kZW5jZSA9IGF3YWl0IHRoaXMuY29ycmVzcG9uZGVuY2VSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZTogeyBwdWJsaWNJZCB9LFxyXG4gICAgICByZWxhdGlvbnM6IFtcclxuICAgICAgICAncmV2aXNpb25zJyxcclxuICAgICAgICAncmV2aXNpb25zLnN0YXR1cycsXHJcbiAgICAgICAgJ3R5cGUnLFxyXG4gICAgICAgICdwcm9qZWN0JyxcclxuICAgICAgICAnb3JpZ2luYXRvcicsXHJcbiAgICAgICAgJ3JlY2lwaWVudHMnLFxyXG4gICAgICAgICdyZWNpcGllbnRzLnJlY2lwaWVudE9yZ2FuaXphdGlvbicsXHJcbiAgICAgIF0sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoIWNvcnJlc3BvbmRlbmNlKSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbihcclxuICAgICAgICBgQ29ycmVzcG9uZGVuY2Ugd2l0aCBVVUlEICR7cHVibGljSWR9IG5vdCBmb3VuZGBcclxuICAgICAgKTtcclxuICAgIH1cclxuICAgIHJldHVybiBjb3JyZXNwb25kZW5jZTtcclxuICB9XHJcblxyXG4gIGFzeW5jIGFkZFJlZmVyZW5jZShpZDogbnVtYmVyLCBkdG86IEFkZFJlZmVyZW5jZUR0bykge1xyXG4gICAgY29uc3Qgc291cmNlID0gYXdhaXQgdGhpcy5jb3JyZXNwb25kZW5jZVJlcG8uZmluZE9uZSh7IHdoZXJlOiB7IGlkIH0gfSk7XHJcbiAgICAvLyBBRFItMDE5OiBSZXNvbHZlIHRhcmdldCBwdWJsaWNJZCDihpIgaW50ZXJuYWwgSU5UIGlkXHJcbiAgICBjb25zdCB0YXJnZXQgPSBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgcHVibGljSWQ6IGR0by50YXJnZXRVdWlkIH0sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoIXNvdXJjZSB8fCAhdGFyZ2V0KSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbignU291cmNlIG9yIFRhcmdldCBjb3JyZXNwb25kZW5jZSBub3QgZm91bmQnKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoc291cmNlLmlkID09PSB0YXJnZXQuaWQpIHtcclxuICAgICAgdGhyb3cgbmV3IEJhZFJlcXVlc3RFeGNlcHRpb24oJ0Nhbm5vdCByZWZlcmVuY2Ugc2VsZicpO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGV4aXN0cyA9IGF3YWl0IHRoaXMucmVmZXJlbmNlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHtcclxuICAgICAgICBzb3VyY2VJZDogaWQsXHJcbiAgICAgICAgdGFyZ2V0SWQ6IHRhcmdldC5pZCxcclxuICAgICAgfSxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmIChleGlzdHMpIHtcclxuICAgICAgcmV0dXJuIGV4aXN0cztcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCByZWYgPSB0aGlzLnJlZmVyZW5jZVJlcG8uY3JlYXRlKHtcclxuICAgICAgc291cmNlSWQ6IGlkLFxyXG4gICAgICB0YXJnZXRJZDogdGFyZ2V0LmlkLFxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHRoaXMucmVmZXJlbmNlUmVwby5zYXZlKHJlZik7XHJcbiAgfVxyXG5cclxuICBhc3luYyByZW1vdmVSZWZlcmVuY2UoaWQ6IG51bWJlciwgdGFyZ2V0SWQ6IG51bWJlcikge1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5yZWZlcmVuY2VSZXBvLmRlbGV0ZSh7XHJcbiAgICAgIHNvdXJjZUlkOiBpZCxcclxuICAgICAgdGFyZ2V0SWQ6IHRhcmdldElkLFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKHJlc3VsdC5hZmZlY3RlZCA9PT0gMCkge1xyXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oJ1JlZmVyZW5jZSBub3QgZm91bmQnKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFzeW5jIGdldFRhZ3MoaWQ6IG51bWJlcikge1xyXG4gICAgY29uc3Qgcm93cyA9IGF3YWl0IHRoaXMudGFnUmVwby5maW5kKHtcclxuICAgICAgd2hlcmU6IHsgY29ycmVzcG9uZGVuY2VJZDogaWQgfSxcclxuICAgICAgcmVsYXRpb25zOiBbJ3RhZyddLFxyXG4gICAgfSk7XHJcbiAgICByZXR1cm4gcm93cy5tYXAoKHIpID0+IHIudGFnKS5maWx0ZXIoQm9vbGVhbik7XHJcbiAgfVxyXG5cclxuICBhc3luYyBhZGRUYWcoaWQ6IG51bWJlciwgdGFnSWQ6IG51bWJlcikge1xyXG4gICAgY29uc3QgY29ycmVzcG9uZGVuY2UgPSBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgaWQgfSxcclxuICAgIH0pO1xyXG4gICAgaWYgKCFjb3JyZXNwb25kZW5jZSkge1xyXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oYENvcnJlc3BvbmRlbmNlICR7aWR9IG5vdCBmb3VuZGApO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHRhZyA9IGF3YWl0IHRoaXMuZGF0YVNvdXJjZS5tYW5hZ2VyLmZpbmRPbmUoVGFnLCB7XHJcbiAgICAgIHdoZXJlOiB7IGlkOiB0YWdJZCB9LFxyXG4gICAgfSk7XHJcbiAgICBpZiAoIXRhZykge1xyXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oYFRhZyAke3RhZ0lkfSBub3QgZm91bmRgKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBleGlzdHMgPSBhd2FpdCB0aGlzLnRhZ1JlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IGNvcnJlc3BvbmRlbmNlSWQ6IGlkLCB0YWdJZCB9LFxyXG4gICAgfSk7XHJcbiAgICBpZiAoZXhpc3RzKSByZXR1cm4gZXhpc3RzO1xyXG5cclxuICAgIGNvbnN0IHJvdyA9IHRoaXMudGFnUmVwby5jcmVhdGUoeyBjb3JyZXNwb25kZW5jZUlkOiBpZCwgdGFnSWQgfSk7XHJcbiAgICByZXR1cm4gdGhpcy50YWdSZXBvLnNhdmUocm93KTtcclxuICB9XHJcblxyXG4gIGFzeW5jIHJlbW92ZVRhZyhpZDogbnVtYmVyLCB0YWdJZDogbnVtYmVyKSB7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnRhZ1JlcG8uZGVsZXRlKHsgY29ycmVzcG9uZGVuY2VJZDogaWQsIHRhZ0lkIH0pO1xyXG4gICAgaWYgKHJlc3VsdC5hZmZlY3RlZCA9PT0gMCkge1xyXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oJ1RhZyBhc3NpZ25tZW50IG5vdCBmb3VuZCcpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgYXN5bmMgZ2V0UmVmZXJlbmNlcyhpZDogbnVtYmVyKSB7XHJcbiAgICBjb25zdCBvdXRnb2luZyA9IGF3YWl0IHRoaXMucmVmZXJlbmNlUmVwby5maW5kKHtcclxuICAgICAgd2hlcmU6IHsgc291cmNlSWQ6IGlkIH0sXHJcbiAgICAgIHJlbGF0aW9uczogWyd0YXJnZXQnLCAndGFyZ2V0LnR5cGUnXSxcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluY29taW5nID0gYXdhaXQgdGhpcy5yZWZlcmVuY2VSZXBvLmZpbmQoe1xyXG4gICAgICB3aGVyZTogeyB0YXJnZXRJZDogaWQgfSxcclxuICAgICAgcmVsYXRpb25zOiBbJ3NvdXJjZScsICdzb3VyY2UudHlwZSddLFxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHsgb3V0Z29pbmcsIGluY29taW5nIH07XHJcbiAgfVxyXG5cclxuICBhc3luYyB1cGRhdGUoaWQ6IG51bWJlciwgdXBkYXRlRHRvOiBVcGRhdGVDb3JyZXNwb25kZW5jZUR0bywgdXNlcjogVXNlcikge1xyXG4gICAgLy8gMS4gRmluZCBDdXJyZW50IFJldmlzaW9uXHJcbiAgICBjb25zdCByZXZpc2lvbiA9IGF3YWl0IHRoaXMucmV2aXNpb25SZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZToge1xyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IGlkLFxyXG4gICAgICAgIGlzQ3VycmVudDogdHJ1ZSxcclxuICAgICAgfSxcclxuICAgICAgcmVsYXRpb25zOiBbJ2NvcnJlc3BvbmRlbmNlJ10sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoIXJldmlzaW9uKSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbihcclxuICAgICAgICBgQ3VycmVudCByZXZpc2lvbiBmb3IgY29ycmVzcG9uZGVuY2UgJHtpZH0gbm90IGZvdW5kYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIDIuIENoZWNrIFBlcm1pc3Npb25cclxuICAgIGlmIChyZXZpc2lvbi5zdGF0dXNJZCkge1xyXG4gICAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCB0aGlzLnN0YXR1c1JlcG8uZmluZE9uZSh7XHJcbiAgICAgICAgd2hlcmU6IHsgaWQ6IHJldmlzaW9uLnN0YXR1c0lkIH0sXHJcbiAgICAgIH0pO1xyXG4gICAgICBpZiAoc3RhdHVzICYmIHN0YXR1cy5zdGF0dXNDb2RlICE9PSAnRFJBRlQnKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEJhZFJlcXVlc3RFeGNlcHRpb24oJ09ubHkgRFJBRlQgZG9jdW1lbnRzIGNhbiBiZSB1cGRhdGVkJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBBRFItMDE5OiBSZXNvbHZlIFVVSUQgcmVmZXJlbmNlcyBpbiB1cGRhdGUgRFRPXHJcbiAgICBjb25zdCB1cGRSZXNvbHZlZFByb2plY3RJZCA9IHVwZGF0ZUR0by5wcm9qZWN0SWRcclxuICAgICAgPyBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlUHJvamVjdElkKHVwZGF0ZUR0by5wcm9qZWN0SWQpXHJcbiAgICAgIDogdW5kZWZpbmVkO1xyXG4gICAgY29uc3QgdXBkUmVzb2x2ZWRPcmlnaW5hdG9ySWQgPSB1cGRhdGVEdG8ub3JpZ2luYXRvcklkXHJcbiAgICAgID8gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKHVwZGF0ZUR0by5vcmlnaW5hdG9ySWQpXHJcbiAgICAgIDogdW5kZWZpbmVkO1xyXG4gICAgY29uc3QgdXBkUmVzb2x2ZWRSZWNpcGllbnRzID0gdXBkYXRlRHRvLnJlY2lwaWVudHNcclxuICAgICAgPyBhd2FpdCBQcm9taXNlLmFsbChcclxuICAgICAgICAgIHVwZGF0ZUR0by5yZWNpcGllbnRzLm1hcChcclxuICAgICAgICAgICAgYXN5bmMgKHIpOiBQcm9taXNlPFJlc29sdmVkUmVjaXBpZW50PiA9PiAoe1xyXG4gICAgICAgICAgICAgIG9yZ2FuaXphdGlvbklkOiBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlT3JnYW5pemF0aW9uSWQoXHJcbiAgICAgICAgICAgICAgICByLm9yZ2FuaXphdGlvbklkXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgICB0eXBlOiByLnR5cGUsXHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgKVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuXHJcbiAgICAvLyAzLiBVcGRhdGUgQ29ycmVzcG9uZGVuY2UgRW50aXR5IGlmIG5lZWRlZFxyXG4gICAgY29uc3QgY29ycmVzcG9uZGVuY2VVcGRhdGU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XHJcbiAgICBpZiAodXBkYXRlRHRvLmRpc2NpcGxpbmVJZClcclxuICAgICAgY29ycmVzcG9uZGVuY2VVcGRhdGUuZGlzY2lwbGluZUlkID0gdXBkYXRlRHRvLmRpc2NpcGxpbmVJZDtcclxuICAgIGlmICh1cGRSZXNvbHZlZFByb2plY3RJZClcclxuICAgICAgY29ycmVzcG9uZGVuY2VVcGRhdGUucHJvamVjdElkID0gdXBkUmVzb2x2ZWRQcm9qZWN0SWQ7XHJcbiAgICBpZiAodXBkUmVzb2x2ZWRPcmlnaW5hdG9ySWQpXHJcbiAgICAgIGNvcnJlc3BvbmRlbmNlVXBkYXRlLm9yaWdpbmF0b3JJZCA9IHVwZFJlc29sdmVkT3JpZ2luYXRvcklkO1xyXG5cclxuICAgIGlmIChPYmplY3Qua2V5cyhjb3JyZXNwb25kZW5jZVVwZGF0ZSkubGVuZ3RoID4gMCkge1xyXG4gICAgICBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby51cGRhdGUoaWQsIGNvcnJlc3BvbmRlbmNlVXBkYXRlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyA0LiBVcGRhdGUgUmV2aXNpb24gRW50aXR5XHJcbiAgICBjb25zdCByZXZpc2lvblVwZGF0ZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcclxuICAgIGlmICh1cGRhdGVEdG8uc3ViamVjdCkgcmV2aXNpb25VcGRhdGUuc3ViamVjdCA9IHVwZGF0ZUR0by5zdWJqZWN0O1xyXG4gICAgaWYgKHVwZGF0ZUR0by5ib2R5KSByZXZpc2lvblVwZGF0ZS5ib2R5ID0gdXBkYXRlRHRvLmJvZHk7XHJcbiAgICBpZiAodXBkYXRlRHRvLnJlbWFya3MpIHJldmlzaW9uVXBkYXRlLnJlbWFya3MgPSB1cGRhdGVEdG8ucmVtYXJrcztcclxuICAgIC8vIEZvcm1hdCBEYXRlIGNvcnJlY3RseSBpZiBzdHJpbmdcclxuICAgIGlmICh1cGRhdGVEdG8uZHVlRGF0ZSkgcmV2aXNpb25VcGRhdGUuZHVlRGF0ZSA9IG5ldyBEYXRlKHVwZGF0ZUR0by5kdWVEYXRlKTtcclxuICAgIGlmICh1cGRhdGVEdG8uZG9jdW1lbnREYXRlKVxyXG4gICAgICByZXZpc2lvblVwZGF0ZS5kb2N1bWVudERhdGUgPSBuZXcgRGF0ZSh1cGRhdGVEdG8uZG9jdW1lbnREYXRlKTtcclxuICAgIGlmICh1cGRhdGVEdG8uaXNzdWVkRGF0ZSlcclxuICAgICAgcmV2aXNpb25VcGRhdGUuaXNzdWVkRGF0ZSA9IG5ldyBEYXRlKHVwZGF0ZUR0by5pc3N1ZWREYXRlKTtcclxuICAgIGlmICh1cGRhdGVEdG8ucmVjZWl2ZWREYXRlKVxyXG4gICAgICByZXZpc2lvblVwZGF0ZS5yZWNlaXZlZERhdGUgPSBuZXcgRGF0ZSh1cGRhdGVEdG8ucmVjZWl2ZWREYXRlKTtcclxuICAgIGlmICh1cGRhdGVEdG8uZGVzY3JpcHRpb24pXHJcbiAgICAgIHJldmlzaW9uVXBkYXRlLmRlc2NyaXB0aW9uID0gdXBkYXRlRHRvLmRlc2NyaXB0aW9uO1xyXG4gICAgaWYgKHVwZGF0ZUR0by5kZXRhaWxzKSByZXZpc2lvblVwZGF0ZS5kZXRhaWxzID0gdXBkYXRlRHRvLmRldGFpbHM7XHJcblxyXG4gICAgaWYgKE9iamVjdC5rZXlzKHJldmlzaW9uVXBkYXRlKS5sZW5ndGggPiAwKSB7XHJcbiAgICAgIGF3YWl0IHRoaXMucmV2aXNpb25SZXBvLnVwZGF0ZShyZXZpc2lvbi5pZCwgcmV2aXNpb25VcGRhdGUpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIDQuNSBDb21taXQgbmV3IGF0dGFjaG1lbnRzIGZyb20gVGVtcCDihpIgUGVybWFuZW50IChUd28tUGhhc2UgU3RvcmFnZSlcclxuICAgIGlmICh1cGRhdGVEdG8uYXR0YWNobWVudFRlbXBJZHM/Lmxlbmd0aCkge1xyXG4gICAgICBjb25zdCBpc3N1ZURhdGUgPSB1cGRhdGVEdG8uaXNzdWVkRGF0ZVxyXG4gICAgICAgID8gbmV3IERhdGUodXBkYXRlRHRvLmlzc3VlZERhdGUpXHJcbiAgICAgICAgOiB1cGRhdGVEdG8uZG9jdW1lbnREYXRlXHJcbiAgICAgICAgICA/IG5ldyBEYXRlKHVwZGF0ZUR0by5kb2N1bWVudERhdGUpXHJcbiAgICAgICAgICA6IHJldmlzaW9uLmlzc3VlZERhdGUgfHwgcmV2aXNpb24uZG9jdW1lbnREYXRlIHx8IHVuZGVmaW5lZDtcclxuXHJcbiAgICAgIGF3YWl0IHRoaXMuZmlsZVN0b3JhZ2VTZXJ2aWNlLmNvbW1pdCh1cGRhdGVEdG8uYXR0YWNobWVudFRlbXBJZHMsIHtcclxuICAgICAgICBpc3N1ZURhdGU6IGlzc3VlRGF0ZSA/IG5ldyBEYXRlKGlzc3VlRGF0ZSkgOiB1bmRlZmluZWQsXHJcbiAgICAgICAgZG9jdW1lbnRUeXBlOiAnQ29ycmVzcG9uZGVuY2UnLFxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyA1LiBVcGRhdGUgUmVjaXBpZW50cyBpZiBwcm92aWRlZFxyXG4gICAgaWYgKHVwZFJlc29sdmVkUmVjaXBpZW50cykge1xyXG4gICAgICBjb25zdCByZWNpcGllbnRSZXBvID0gdGhpcy5kYXRhU291cmNlLmdldFJlcG9zaXRvcnkoXHJcbiAgICAgICAgQ29ycmVzcG9uZGVuY2VSZWNpcGllbnRcclxuICAgICAgKTtcclxuICAgICAgYXdhaXQgcmVjaXBpZW50UmVwby5kZWxldGUoeyBjb3JyZXNwb25kZW5jZUlkOiBpZCB9KTtcclxuXHJcbiAgICAgIGNvbnN0IG5ld1JlY2lwaWVudHMgPSB1cGRSZXNvbHZlZFJlY2lwaWVudHMubWFwKChyKSA9PlxyXG4gICAgICAgIHJlY2lwaWVudFJlcG8uY3JlYXRlKHtcclxuICAgICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IGlkLFxyXG4gICAgICAgICAgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQ6IHIub3JnYW5pemF0aW9uSWQsXHJcbiAgICAgICAgICByZWNpcGllbnRUeXBlOiByLnR5cGUsXHJcbiAgICAgICAgfSlcclxuICAgICAgKTtcclxuICAgICAgYXdhaXQgcmVjaXBpZW50UmVwby5zYXZlKG5ld1JlY2lwaWVudHMpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIDYuIFJlZ2VuZXJhdGUgRG9jdW1lbnQgTnVtYmVyIGlmIHN0cnVjdHVyYWwgZmllbGRzIGNoYW5nZWQgKFJlY2lwaWVudCwgRGlzY2lwbGluZSwgVHlwZSwgUHJvamVjdClcclxuICAgIC8vIEFORCBpdCBpcyBhIERSQUZULlxyXG5cclxuICAgIC8vIEZldGNoIGZyZXNoIGRhdGEgZm9yIGNvbnRleHQgYW5kIGNvbXBhcmlzb25cclxuICAgIGNvbnN0IGN1cnJlbnRDb3JyID0gYXdhaXQgdGhpcy5jb3JyZXNwb25kZW5jZVJlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IGlkIH0sXHJcbiAgICAgIHJlbGF0aW9uczogWyd0eXBlJywgJ3JlY2lwaWVudHMnLCAncmVjaXBpZW50cy5yZWNpcGllbnRPcmdhbml6YXRpb24nXSxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmIChjdXJyZW50Q29ycikge1xyXG4gICAgICBjb25zdCBjdXJyZW50VG9SZWNpcGllbnQgPSBjdXJyZW50Q29yci5yZWNpcGllbnRzPy5maW5kKFxyXG4gICAgICAgIChyKSA9PiByLnJlY2lwaWVudFR5cGUgPT09ICdUTydcclxuICAgICAgKTtcclxuICAgICAgY29uc3QgY3VycmVudFJlY2lwaWVudElkID0gY3VycmVudFRvUmVjaXBpZW50Py5yZWNpcGllbnRPcmdhbml6YXRpb25JZDtcclxuXHJcbiAgICAgIC8vIENoZWNrIGZvciBBQ1RVQUwgdmFsdWUgY2hhbmdlc1xyXG4gICAgICBjb25zdCBpc1Byb2plY3RDaGFuZ2VkID1cclxuICAgICAgICB1cGRSZXNvbHZlZFByb2plY3RJZCAhPT0gdW5kZWZpbmVkICYmXHJcbiAgICAgICAgdXBkUmVzb2x2ZWRQcm9qZWN0SWQgIT09IGN1cnJlbnRDb3JyLnByb2plY3RJZDtcclxuICAgICAgY29uc3QgaXNPcmlnaW5hdG9yQ2hhbmdlZCA9XHJcbiAgICAgICAgdXBkUmVzb2x2ZWRPcmlnaW5hdG9ySWQgIT09IHVuZGVmaW5lZCAmJlxyXG4gICAgICAgIHVwZFJlc29sdmVkT3JpZ2luYXRvcklkICE9PSBjdXJyZW50Q29yci5vcmlnaW5hdG9ySWQ7XHJcbiAgICAgIGNvbnN0IGlzRGlzY2lwbGluZUNoYW5nZWQgPVxyXG4gICAgICAgIHVwZGF0ZUR0by5kaXNjaXBsaW5lSWQgIT09IHVuZGVmaW5lZCAmJlxyXG4gICAgICAgIHVwZGF0ZUR0by5kaXNjaXBsaW5lSWQgIT09IGN1cnJlbnRDb3JyLmRpc2NpcGxpbmVJZDtcclxuICAgICAgY29uc3QgaXNUeXBlQ2hhbmdlZCA9XHJcbiAgICAgICAgdXBkYXRlRHRvLnR5cGVJZCAhPT0gdW5kZWZpbmVkICYmXHJcbiAgICAgICAgdXBkYXRlRHRvLnR5cGVJZCAhPT0gY3VycmVudENvcnIuY29ycmVzcG9uZGVuY2VUeXBlSWQ7XHJcblxyXG4gICAgICBsZXQgaXNSZWNpcGllbnRDaGFuZ2VkID0gZmFsc2U7XHJcbiAgICAgIGxldCBuZXdSZWNpcGllbnRJZDogbnVtYmVyIHwgdW5kZWZpbmVkO1xyXG5cclxuICAgICAgaWYgKHVwZFJlc29sdmVkUmVjaXBpZW50cykge1xyXG4gICAgICAgIGNvbnN0IG5ld1RvUmVjaXBpZW50ID0gdXBkUmVzb2x2ZWRSZWNpcGllbnRzLmZpbmQoXHJcbiAgICAgICAgICAocikgPT4gci50eXBlID09PSAnVE8nXHJcbiAgICAgICAgKTtcclxuICAgICAgICBuZXdSZWNpcGllbnRJZCA9IG5ld1RvUmVjaXBpZW50Py5vcmdhbml6YXRpb25JZDtcclxuXHJcbiAgICAgICAgaWYgKG5ld1JlY2lwaWVudElkICE9PSBjdXJyZW50UmVjaXBpZW50SWQpIHtcclxuICAgICAgICAgIGlzUmVjaXBpZW50Q2hhbmdlZCA9IHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgaXNQcm9qZWN0Q2hhbmdlZCB8fFxyXG4gICAgICAgIGlzRGlzY2lwbGluZUNoYW5nZWQgfHxcclxuICAgICAgICBpc1R5cGVDaGFuZ2VkIHx8XHJcbiAgICAgICAgaXNSZWNpcGllbnRDaGFuZ2VkIHx8XHJcbiAgICAgICAgaXNPcmlnaW5hdG9yQ2hhbmdlZFxyXG4gICAgICApIHtcclxuICAgICAgICBjb25zdCB0YXJnZXRSZWNpcGllbnRJZCA9IGlzUmVjaXBpZW50Q2hhbmdlZFxyXG4gICAgICAgICAgPyBuZXdSZWNpcGllbnRJZFxyXG4gICAgICAgICAgOiBjdXJyZW50UmVjaXBpZW50SWQ7XHJcblxyXG4gICAgICAgIC8vIFJlc29sdmUgUmVjaXBpZW50IENvZGUgZm9yIHRoZSBORVcgY29udGV4dFxyXG4gICAgICAgIGxldCByZWNpcGllbnRDb2RlID0gJyc7XHJcbiAgICAgICAgaWYgKHRhcmdldFJlY2lwaWVudElkKSB7XHJcbiAgICAgICAgICBjb25zdCByZWNPcmcgPSBhd2FpdCB0aGlzLmRhdGFTb3VyY2UubWFuYWdlci5maW5kT25lKE9yZ2FuaXphdGlvbiwge1xyXG4gICAgICAgICAgICB3aGVyZTogeyBpZDogdGFyZ2V0UmVjaXBpZW50SWQgfSxcclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgaWYgKHJlY09yZykgcmVjaXBpZW50Q29kZSA9IHJlY09yZy5vcmdhbml6YXRpb25Db2RlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gW0ZpeCAjNl0gRmV0Y2ggcmVhbCBPUkcgQ29kZSBmcm9tIG9yaWdpbmF0b3Igb3JnYW5pemF0aW9uXHJcbiAgICAgICAgY29uc3Qgb3JpZ2luYXRvck9yZ0ZvclVwZGF0ZSA9IGF3YWl0IHRoaXMuZGF0YVNvdXJjZS5tYW5hZ2VyLmZpbmRPbmUoXHJcbiAgICAgICAgICBPcmdhbml6YXRpb24sXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIHdoZXJlOiB7XHJcbiAgICAgICAgICAgICAgaWQ6IHVwZFJlc29sdmVkT3JpZ2luYXRvcklkID8/IGN1cnJlbnRDb3JyLm9yaWdpbmF0b3JJZCA/PyAwLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgfVxyXG4gICAgICAgICk7XHJcbiAgICAgICAgY29uc3Qgb3JnQ29kZSA9IG9yaWdpbmF0b3JPcmdGb3JVcGRhdGU/Lm9yZ2FuaXphdGlvbkNvZGUgPz8gJ1VOSyc7XHJcblxyXG4gICAgICAgIC8vIFByZXBhcmUgQ29udGV4dHNcclxuICAgICAgICBjb25zdCBvbGRDdHggPSB7XHJcbiAgICAgICAgICBwcm9qZWN0SWQ6IGN1cnJlbnRDb3JyLnByb2plY3RJZCxcclxuICAgICAgICAgIG9yaWdpbmF0b3JPcmdhbml6YXRpb25JZDogY3VycmVudENvcnIub3JpZ2luYXRvcklkID8/IDAsXHJcbiAgICAgICAgICB0eXBlSWQ6IGN1cnJlbnRDb3JyLmNvcnJlc3BvbmRlbmNlVHlwZUlkLFxyXG4gICAgICAgICAgZGlzY2lwbGluZUlkOiBjdXJyZW50Q29yci5kaXNjaXBsaW5lSWQsXHJcbiAgICAgICAgICByZWNpcGllbnRPcmdhbml6YXRpb25JZDogY3VycmVudFJlY2lwaWVudElkLFxyXG4gICAgICAgICAgeWVhcjogbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpLFxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIGNvbnN0IG5ld0N0eCA9IHtcclxuICAgICAgICAgIHByb2plY3RJZDogdXBkUmVzb2x2ZWRQcm9qZWN0SWQgPz8gY3VycmVudENvcnIucHJvamVjdElkLFxyXG4gICAgICAgICAgb3JpZ2luYXRvck9yZ2FuaXphdGlvbklkOlxyXG4gICAgICAgICAgICB1cGRSZXNvbHZlZE9yaWdpbmF0b3JJZCA/PyBjdXJyZW50Q29yci5vcmlnaW5hdG9ySWQgPz8gMCxcclxuICAgICAgICAgIHR5cGVJZDogdXBkYXRlRHRvLnR5cGVJZCA/PyBjdXJyZW50Q29yci5jb3JyZXNwb25kZW5jZVR5cGVJZCxcclxuICAgICAgICAgIGRpc2NpcGxpbmVJZDogdXBkYXRlRHRvLmRpc2NpcGxpbmVJZCA/PyBjdXJyZW50Q29yci5kaXNjaXBsaW5lSWQsXHJcbiAgICAgICAgICByZWNpcGllbnRPcmdhbml6YXRpb25JZDogdGFyZ2V0UmVjaXBpZW50SWQsXHJcbiAgICAgICAgICB5ZWFyOiBuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCksXHJcbiAgICAgICAgICB1c2VySWQ6IHVzZXIudXNlcl9pZCwgLy8gUGFzcyBVc2VyIElEIGZvciBBdWRpdFxyXG4gICAgICAgICAgY3VzdG9tVG9rZW5zOiB7XHJcbiAgICAgICAgICAgIFRZUEVfQ09ERTogY3VycmVudENvcnIudHlwZT8udHlwZUNvZGUgfHwgJycsXHJcbiAgICAgICAgICAgIE9SR19DT0RFOiBvcmdDb2RlLFxyXG4gICAgICAgICAgICBSRUNJUElFTlRfQ09ERTogcmVjaXBpZW50Q29kZSxcclxuICAgICAgICAgICAgUkVDX0NPREU6IHJlY2lwaWVudENvZGUsXHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIC8vIElmIFR5cGUgQ2hhbmdlZCwgbmVlZCBORVcgVHlwZSBDb2RlXHJcbiAgICAgICAgaWYgKGlzVHlwZUNoYW5nZWQpIHtcclxuICAgICAgICAgIGNvbnN0IG5ld1R5cGUgPSBhd2FpdCB0aGlzLnR5cGVSZXBvLmZpbmRPbmUoe1xyXG4gICAgICAgICAgICB3aGVyZTogeyBpZDogbmV3Q3R4LnR5cGVJZCB9LFxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgICBpZiAobmV3VHlwZSkgbmV3Q3R4LmN1c3RvbVRva2Vucy5UWVBFX0NPREUgPSBuZXdUeXBlLnR5cGVDb2RlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uc3QgbmV3RG9jTnVtYmVyID0gYXdhaXQgdGhpcy5udW1iZXJpbmdTZXJ2aWNlLnVwZGF0ZU51bWJlckZvckRyYWZ0KFxyXG4gICAgICAgICAgY3VycmVudENvcnIuY29ycmVzcG9uZGVuY2VOdW1iZXIsXHJcbiAgICAgICAgICBvbGRDdHgsXHJcbiAgICAgICAgICBuZXdDdHhcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby51cGRhdGUoaWQsIHtcclxuICAgICAgICAgIGNvcnJlc3BvbmRlbmNlTnVtYmVyOiBuZXdEb2NOdW1iZXIsXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB1cGRhdGVkID0gYXdhaXQgdGhpcy5maW5kT25lKGlkKTtcclxuXHJcbiAgICAvLyBSZS1pbmRleCB1cGRhdGVkIGRvY3VtZW50IGluIEVsYXN0aWNzZWFyY2ggKGZpcmUtYW5kLWZvcmdldClcclxuICAgIHZvaWQgdGhpcy5zZWFyY2hTZXJ2aWNlLmluZGV4RG9jdW1lbnQoe1xyXG4gICAgICBpZDogdXBkYXRlZC5pZCxcclxuICAgICAgcHVibGljSWQ6IHVwZGF0ZWQucHVibGljSWQsXHJcbiAgICAgIHR5cGU6ICdjb3JyZXNwb25kZW5jZScsXHJcbiAgICAgIGRvY051bWJlcjogdXBkYXRlZC5jb3JyZXNwb25kZW5jZU51bWJlcixcclxuICAgICAgdGl0bGU6IHVwZGF0ZUR0by5zdWJqZWN0ID8/IHVwZGF0ZWQucmV2aXNpb25zPy5bMF0/LnN1YmplY3QsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiB1cGRhdGVEdG8uZGVzY3JpcHRpb24gPz8gdXBkYXRlZC5yZXZpc2lvbnM/LlswXT8uZGVzY3JpcHRpb24sXHJcbiAgICAgIHN0YXR1czogJ0RSQUZUJyxcclxuICAgICAgcHJvamVjdElkOiB1cGRhdGVkLnByb2plY3RJZCxcclxuICAgICAgY3JlYXRlZEF0OiB1cGRhdGVkLmNyZWF0ZWRBdCxcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB1cGRhdGVkO1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgcHJldmlld0RvY3VtZW50TnVtYmVyKGNyZWF0ZUR0bzogQ3JlYXRlQ29ycmVzcG9uZGVuY2VEdG8sIHVzZXI6IFVzZXIpIHtcclxuICAgIC8vIEFEUi0wMTk6IFJlc29sdmUgVVVJRCByZWZlcmVuY2VzXHJcbiAgICBjb25zdCBwcmV2aWV3UHJvamVjdElkID0gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZVByb2plY3RJZChcclxuICAgICAgY3JlYXRlRHRvLnByb2plY3RJZFxyXG4gICAgKTtcclxuICAgIGNvbnN0IHByZXZpZXdPcmlnaW5hdG9ySWQgPSBjcmVhdGVEdG8ub3JpZ2luYXRvcklkXHJcbiAgICAgID8gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKGNyZWF0ZUR0by5vcmlnaW5hdG9ySWQpXHJcbiAgICAgIDogdW5kZWZpbmVkO1xyXG4gICAgY29uc3QgcHJldmlld1JlY2lwaWVudHMgPSBjcmVhdGVEdG8ucmVjaXBpZW50c1xyXG4gICAgICA/IGF3YWl0IFByb21pc2UuYWxsKFxyXG4gICAgICAgICAgY3JlYXRlRHRvLnJlY2lwaWVudHMubWFwKFxyXG4gICAgICAgICAgICBhc3luYyAocik6IFByb21pc2U8UmVzb2x2ZWRSZWNpcGllbnQ+ID0+ICh7XHJcbiAgICAgICAgICAgICAgb3JnYW5pemF0aW9uSWQ6IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZChcclxuICAgICAgICAgICAgICAgIHIub3JnYW5pemF0aW9uSWRcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICAgIHR5cGU6IHIudHlwZSxcclxuICAgICAgICAgICAgfSlcclxuICAgICAgICAgIClcclxuICAgICAgICApXHJcbiAgICAgIDogdW5kZWZpbmVkO1xyXG5cclxuICAgIGNvbnN0IHR5cGUgPSBhd2FpdCB0aGlzLnR5cGVSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZTogeyBpZDogY3JlYXRlRHRvLnR5cGVJZCB9LFxyXG4gICAgfSk7XHJcbiAgICBpZiAoIXR5cGUpIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbignRG9jdW1lbnQgVHlwZSBub3QgZm91bmQnKTtcclxuXHJcbiAgICBsZXQgdXNlck9yZ0lkID0gdXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcbiAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICBjb25zdCBmdWxsVXNlciA9IGF3YWl0IHRoaXMudXNlclNlcnZpY2UuZmluZE9uZSh1c2VyLnVzZXJfaWQpO1xyXG4gICAgICBpZiAoZnVsbFVzZXIpIHVzZXJPcmdJZCA9IGZ1bGxVc2VyLnByaW1hcnlPcmdhbml6YXRpb25JZDtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocHJldmlld09yaWdpbmF0b3JJZCAmJiBwcmV2aWV3T3JpZ2luYXRvcklkICE9PSB1c2VyT3JnSWQpIHtcclxuICAgICAgLy8gQWxsb3cgaW1wZXJzb25hdGlvbiBmb3IgcHJldmlld1xyXG4gICAgICB1c2VyT3JnSWQgPSBwcmV2aWV3T3JpZ2luYXRvcklkO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEV4dHJhY3QgcmVjaXBpZW50IGZyb20gcmVjaXBpZW50cyBhcnJheVxyXG4gICAgY29uc3QgdG9SZWNpcGllbnQgPSBwcmV2aWV3UmVjaXBpZW50cz8uZmluZCgocikgPT4gci50eXBlID09PSAnVE8nKTtcclxuICAgIGNvbnN0IHJlY2lwaWVudE9yZ2FuaXphdGlvbklkID0gdG9SZWNpcGllbnQ/Lm9yZ2FuaXphdGlvbklkO1xyXG5cclxuICAgIGxldCByZWNpcGllbnRDb2RlID0gJyc7XHJcbiAgICBpZiAocmVjaXBpZW50T3JnYW5pemF0aW9uSWQpIHtcclxuICAgICAgY29uc3QgcmVjT3JnID0gYXdhaXQgdGhpcy5kYXRhU291cmNlLm1hbmFnZXIuZmluZE9uZShPcmdhbml6YXRpb24sIHtcclxuICAgICAgICB3aGVyZTogeyBpZDogcmVjaXBpZW50T3JnYW5pemF0aW9uSWQgfSxcclxuICAgICAgfSk7XHJcbiAgICAgIGlmIChyZWNPcmcpIHJlY2lwaWVudENvZGUgPSByZWNPcmcub3JnYW5pemF0aW9uQ29kZTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdGhpcy5udW1iZXJpbmdTZXJ2aWNlLnByZXZpZXdOdW1iZXIoe1xyXG4gICAgICBwcm9qZWN0SWQ6IHByZXZpZXdQcm9qZWN0SWQsXHJcbiAgICAgIG9yaWdpbmF0b3JPcmdhbml6YXRpb25JZDogdXNlck9yZ0lkISxcclxuICAgICAgdHlwZUlkOiBjcmVhdGVEdG8udHlwZUlkLFxyXG4gICAgICBkaXNjaXBsaW5lSWQ6IGNyZWF0ZUR0by5kaXNjaXBsaW5lSWQsXHJcbiAgICAgIHN1YlR5cGVJZDogY3JlYXRlRHRvLnN1YlR5cGVJZCxcclxuICAgICAgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQsXHJcbiAgICAgIHllYXI6IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKSxcclxuICAgICAgY3VzdG9tVG9rZW5zOiB7XHJcbiAgICAgICAgVFlQRV9DT0RFOiB0eXBlLnR5cGVDb2RlLFxyXG4gICAgICAgIFJFQ0lQSUVOVF9DT0RFOiByZWNpcGllbnRDb2RlLFxyXG4gICAgICAgIFJFQ19DT0RFOiByZWNpcGllbnRDb2RlLFxyXG4gICAgICB9LFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBCdXNpbmVzcyBSdWxlIEltcGxlbWVudGF0aW9uOiBFQy1DT1JSLTAwMSAtIENhbmNlbCBDb3JyZXNwb25kZW5jZSB3aXRoIERvd25zdHJlYW0gQ2lyY3VsYXRpb25cclxuICAgKiBDYW5jZWwgY29ycmVzcG9uZGVuY2UgYW5kIGhhbmRsZSByZWxhdGVkIGNpcmN1bGF0aW9uc1xyXG4gICAqL1xyXG4gIGFzeW5jIGNhbmNlbChwdWJsaWNJZDogc3RyaW5nLCByZWFzb246IHN0cmluZywgdXNlcjogVXNlcikge1xyXG4gICAgY29uc3QgY29ycmVzcG9uZGVuY2UgPSBhd2FpdCB0aGlzLmZpbmRPbmVCeVV1aWQocHVibGljSWQpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHVzZXIgaGFzIHBlcm1pc3Npb24gdG8gY2FuY2VsIChPcmcgQWRtaW4gb3IgU3VwZXJhZG1pbiBvbmx5KVxyXG4gICAgY29uc3QgcGVybWlzc2lvbnMgPSBhd2FpdCB0aGlzLnVzZXJTZXJ2aWNlLmdldFVzZXJQZXJtaXNzaW9ucyh1c2VyLnVzZXJfaWQpO1xyXG4gICAgY29uc3QgY2FuQ2FuY2VsID1cclxuICAgICAgcGVybWlzc2lvbnMuaW5jbHVkZXMoJ2NvcnJlc3BvbmRlbmNlLmNhbmNlbCcpIHx8XHJcbiAgICAgIHBlcm1pc3Npb25zLmluY2x1ZGVzKCdzeXN0ZW0ubWFuYWdlX2FsbCcpO1xyXG5cclxuICAgIGlmICghY2FuQ2FuY2VsKSB7XHJcbiAgICAgIHRocm93IG5ldyBGb3JiaWRkZW5FeGNlcHRpb24oXHJcbiAgICAgICAgJ09ubHkgYWRtaW5pc3RyYXRvcnMgY2FuIGNhbmNlbCBjb3JyZXNwb25kZW5jZXMnXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIGFueSBhY3RpdmUgY2lyY3VsYXRpb25zXHJcbiAgICBjb25zdCBjaXJjdWxhdGlvblJlcG8gPSB0aGlzLmRhdGFTb3VyY2UuZ2V0UmVwb3NpdG9yeSgnQ2lyY3VsYXRpb24nKTtcclxuICAgIGNvbnN0IGFjdGl2ZUNpcmN1bGF0aW9ucyA9IGF3YWl0IGNpcmN1bGF0aW9uUmVwby5maW5kKHtcclxuICAgICAgd2hlcmU6IHtcclxuICAgICAgICBjb3JyZXNwb25kZW5jZUlkOiBjb3JyZXNwb25kZW5jZS5pZCxcclxuICAgICAgICBzdGF0dXM6ICdPUEVOJyxcclxuICAgICAgfSxcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IHdhcm5pbmdNZXNzYWdlID1cclxuICAgICAgYWN0aXZlQ2lyY3VsYXRpb25zLmxlbmd0aCA+IDBcclxuICAgICAgICA/IGBUaGVyZSBhcmUgJHthY3RpdmVDaXJjdWxhdGlvbnMubGVuZ3RofSBhY3RpdmUgY2lyY3VsYXRpb24ocykgZm9yIHRoaXMgY29ycmVzcG9uZGVuY2UuIENhbmNlbGluZyB3aWxsIGZvcmNlIGNsb3NlIGFsbCByZWxhdGVkIGNpcmN1bGF0aW9ucy5gXHJcbiAgICAgICAgOiAnJztcclxuXHJcbiAgICAvLyBHZXQgdGhlIGN1cnJlbnQgcmV2aXNpb24gdG8gdXBkYXRlIHN0YXR1c1xyXG4gICAgY29uc3QgY3VycmVudFJldmlzaW9uID0gYXdhaXQgdGhpcy5yZXZpc2lvblJlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7XHJcbiAgICAgICAgY29ycmVzcG9uZGVuY2VJZDogY29ycmVzcG9uZGVuY2UuaWQsXHJcbiAgICAgICAgaXNDdXJyZW50OiB0cnVlLFxyXG4gICAgICB9LFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKCFjdXJyZW50UmV2aXNpb24pIHtcclxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXhjZXB0aW9uKCdDdXJyZW50IHJldmlzaW9uIG5vdCBmb3VuZCcpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCBjYW5jZWxsZWQgc3RhdHVzXHJcbiAgICBjb25zdCBjYW5jZWxsZWRTdGF0dXMgPSBhd2FpdCB0aGlzLnN0YXR1c1JlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IHN0YXR1c0NvZGU6ICdDQU5DRUxMRUQnIH0sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoIWNhbmNlbGxlZFN0YXR1cykge1xyXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxTZXJ2ZXJFcnJvckV4Y2VwdGlvbignQ0FOQ0VMTEVEIHN0YXR1cyBub3QgZm91bmQnKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBxdWVyeVJ1bm5lciA9IHRoaXMuZGF0YVNvdXJjZS5jcmVhdGVRdWVyeVJ1bm5lcigpO1xyXG4gICAgYXdhaXQgcXVlcnlSdW5uZXIuY29ubmVjdCgpO1xyXG4gICAgYXdhaXQgcXVlcnlSdW5uZXIuc3RhcnRUcmFuc2FjdGlvbigpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFVwZGF0ZSBjb3JyZXNwb25kZW5jZSByZXZpc2lvbiBzdGF0dXMgdG8gQ0FOQ0VMTEVEXHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLm1hbmFnZXIudXBkYXRlKFxyXG4gICAgICAgIENvcnJlc3BvbmRlbmNlUmV2aXNpb24sXHJcbiAgICAgICAgY3VycmVudFJldmlzaW9uLmlkLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHN0YXR1c0lkOiBjYW5jZWxsZWRTdGF0dXMuaWQsXHJcbiAgICAgICAgICByZW1hcmtzOiBgQ2FuY2VsbGVkOiAke3JlYXNvbn1gLFxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIEZvcmNlIGNsb3NlIGFsbCBhY3RpdmUgY2lyY3VsYXRpb25zXHJcbiAgICAgIGlmIChhY3RpdmVDaXJjdWxhdGlvbnMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLm1hbmFnZXIudXBkYXRlKFxyXG4gICAgICAgICAgJ0NpcmN1bGF0aW9uJyxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgY29ycmVzcG9uZGVuY2VJZDogY29ycmVzcG9uZGVuY2UuaWQsXHJcbiAgICAgICAgICAgIHN0YXR1czogJ09QRU4nLFxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgc3RhdHVzOiAnRk9SQ0VfQ0xPU0VEJyxcclxuICAgICAgICAgICAgY2xvc2VkQXQ6IG5ldyBEYXRlKCksXHJcbiAgICAgICAgICAgIGNsb3NlZEJ5OiB1c2VyLnVzZXJfaWQsXHJcbiAgICAgICAgICAgIGNsb3NlUmVhc29uOiBgQ29ycmVzcG9uZGVuY2UgY2FuY2VsbGVkOiAke3JlYXNvbn1gLFxyXG4gICAgICAgICAgfVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLmNvbW1pdFRyYW5zYWN0aW9uKCk7XHJcblxyXG4gICAgICAvLyBSZS1pbmRleCBjYW5jZWxsZWQgc3RhdHVzIGluIEVsYXN0aWNzZWFyY2ggKGZpcmUtYW5kLWZvcmdldClcclxuICAgICAgdm9pZCB0aGlzLnNlYXJjaFNlcnZpY2UuaW5kZXhEb2N1bWVudCh7XHJcbiAgICAgICAgaWQ6IGNvcnJlc3BvbmRlbmNlLmlkLFxyXG4gICAgICAgIHB1YmxpY0lkOiBjb3JyZXNwb25kZW5jZS5wdWJsaWNJZCxcclxuICAgICAgICB0eXBlOiAnY29ycmVzcG9uZGVuY2UnLFxyXG4gICAgICAgIGRvY051bWJlcjogY29ycmVzcG9uZGVuY2UuY29ycmVzcG9uZGVuY2VOdW1iZXIsXHJcbiAgICAgICAgdGl0bGU6IGN1cnJlbnRSZXZpc2lvbi5zdWJqZWN0LFxyXG4gICAgICAgIHN0YXR1czogJ0NBTkNFTExFRCcsXHJcbiAgICAgICAgcHJvamVjdElkOiBjb3JyZXNwb25kZW5jZS5wcm9qZWN0SWQsXHJcbiAgICAgICAgY3JlYXRlZEF0OiBjb3JyZXNwb25kZW5jZS5jcmVhdGVkQXQsXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgLy8gTm90aWZ5IG9yaWdpbmF0b3IncyBkb2MtY29udHJvbCB1c2VyIGFib3V0IGNhbmNlbGxhdGlvbiAoZmlyZS1hbmQtZm9yZ2V0KVxyXG4gICAgICBpZiAoY29ycmVzcG9uZGVuY2Uub3JpZ2luYXRvcklkKSB7XHJcbiAgICAgICAgdm9pZCB0aGlzLnVzZXJTZXJ2aWNlXHJcbiAgICAgICAgICAuZmluZERvY0NvbnRyb2xJZEJ5T3JnKGNvcnJlc3BvbmRlbmNlLm9yaWdpbmF0b3JJZClcclxuICAgICAgICAgIC50aGVuKCh0YXJnZXRVc2VySWQpID0+IHtcclxuICAgICAgICAgICAgaWYgKHRhcmdldFVzZXJJZCkge1xyXG4gICAgICAgICAgICAgIHZvaWQgdGhpcy5ub3RpZmljYXRpb25TZXJ2aWNlLnNlbmQoe1xyXG4gICAgICAgICAgICAgICAgdXNlcklkOiB0YXJnZXRVc2VySWQsXHJcbiAgICAgICAgICAgICAgICB0aXRsZTogJ0NvcnJlc3BvbmRlbmNlIENhbmNlbGxlZCcsXHJcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgJHtjb3JyZXNwb25kZW5jZS5jb3JyZXNwb25kZW5jZU51bWJlcn0g4oCUICR7Y3VycmVudFJldmlzaW9uLnN1YmplY3R9IGhhcyBiZWVuIGNhbmNlbGxlZC4gUmVhc29uOiAke3JlYXNvbn1gLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogJ0VNQUlMJyxcclxuICAgICAgICAgICAgICAgIGVudGl0eVR5cGU6ICdjb3JyZXNwb25kZW5jZScsXHJcbiAgICAgICAgICAgICAgICBlbnRpdHlJZDogY29ycmVzcG9uZGVuY2UuaWQsXHJcbiAgICAgICAgICAgICAgICBsaW5rOiBgL2NvcnJlc3BvbmRlbmNlcy8ke2NvcnJlc3BvbmRlbmNlLnB1YmxpY0lkfWAsXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pXHJcbiAgICAgICAgICAuY2F0Y2goKGVycjogRXJyb3IpID0+XHJcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyLndhcm4oYENhbmNlbCBub3RpZmljYXRpb24gZmFpbGVkOiAke2Vyci5tZXNzYWdlfWApXHJcbiAgICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIHN1Y2Nlc3M6IHRydWUsXHJcbiAgICAgICAgbWVzc2FnZTogd2FybmluZ01lc3NhZ2UgfHwgJ0NvcnJlc3BvbmRlbmNlIGNhbmNlbGxlZCBzdWNjZXNzZnVsbHknLFxyXG4gICAgICAgIGFjdGl2ZUNpcmN1bGF0aW9uc0NvdW50OiBhY3RpdmVDaXJjdWxhdGlvbnMubGVuZ3RoLFxyXG4gICAgICB9O1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgYXdhaXQgcXVlcnlSdW5uZXIucm9sbGJhY2tUcmFuc2FjdGlvbigpO1xyXG4gICAgICB0aGlzLmxvZ2dlci5lcnJvcihcclxuICAgICAgICBgRmFpbGVkIHRvIGNhbmNlbCBjb3JyZXNwb25kZW5jZTogJHsoZXJyb3IgYXMgRXJyb3IpLm1lc3NhZ2V9YFxyXG4gICAgICApO1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH0gZmluYWxseSB7XHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLnJlbGVhc2UoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFzeW5jIGJ1bGtDYW5jZWwoXHJcbiAgICBwdWJsaWNJZHM6IHN0cmluZ1tdLFxyXG4gICAgcmVhc29uOiBzdHJpbmcsXHJcbiAgICB1c2VyOiBVc2VyXHJcbiAgKTogUHJvbWlzZTx7IHN1Y2NlZWRlZDogc3RyaW5nW107IGZhaWxlZDogc3RyaW5nW10gfT4ge1xyXG4gICAgY29uc3Qgc3VjY2VlZGVkOiBzdHJpbmdbXSA9IFtdO1xyXG4gICAgY29uc3QgZmFpbGVkOiBzdHJpbmdbXSA9IFtdO1xyXG5cclxuICAgIGZvciAoY29uc3QgcHVibGljSWQgb2YgcHVibGljSWRzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgYXdhaXQgdGhpcy5jYW5jZWwocHVibGljSWQsIHJlYXNvbiwgdXNlcik7XHJcbiAgICAgICAgc3VjY2VlZGVkLnB1c2gocHVibGljSWQpO1xyXG4gICAgICB9IGNhdGNoIHtcclxuICAgICAgICBmYWlsZWQucHVzaChwdWJsaWNJZCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4geyBzdWNjZWVkZWQsIGZhaWxlZCB9O1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgZXhwb3J0Q3N2KHNlYXJjaER0bzogU2VhcmNoQ29ycmVzcG9uZGVuY2VEdG8pOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgY29uc3QgeyBkYXRhIH0gPSBhd2FpdCB0aGlzLmZpbmRBbGwoc2VhcmNoRHRvKTtcclxuXHJcbiAgICBjb25zdCBoZWFkZXIgPSBbXHJcbiAgICAgICdEb2N1bWVudCBOby4nLFxyXG4gICAgICAnUmV2JyxcclxuICAgICAgJ1N1YmplY3QnLFxyXG4gICAgICAnVHlwZScsXHJcbiAgICAgICdTdGF0dXMnLFxyXG4gICAgICAnUHJvamVjdCcsXHJcbiAgICAgICdGcm9tJyxcclxuICAgICAgJ0R1ZSBEYXRlJyxcclxuICAgICAgJ0NyZWF0ZWQgQXQnLFxyXG4gICAgXTtcclxuICAgIGNvbnN0IHJvd3MgPSBkYXRhLm1hcCgocmV2KSA9PiB7XHJcbiAgICAgIGNvbnN0IGNvcnIgPSByZXYuY29ycmVzcG9uZGVuY2UgPz8gKHJldiBhcyB1bmtub3duIGFzIENvcnJlc3BvbmRlbmNlKTtcclxuICAgICAgcmV0dXJuIFtcclxuICAgICAgICB0aGlzLmVzY2FwZUNzdihjb3JyLmNvcnJlc3BvbmRlbmNlTnVtYmVyID8/ICcnKSxcclxuICAgICAgICB0aGlzLmVzY2FwZUNzdihyZXYucmV2aXNpb25MYWJlbCA/PyBTdHJpbmcocmV2LnJldmlzaW9uTnVtYmVyID8/IDApKSxcclxuICAgICAgICB0aGlzLmVzY2FwZUNzdihyZXYuc3ViamVjdCA/PyAnJyksXHJcbiAgICAgICAgdGhpcy5lc2NhcGVDc3YoY29yci50eXBlPy50eXBlQ29kZSA/PyAnJyksXHJcbiAgICAgICAgdGhpcy5lc2NhcGVDc3YocmV2LnN0YXR1cz8uc3RhdHVzQ29kZSA/PyAnJyksXHJcbiAgICAgICAgdGhpcy5lc2NhcGVDc3YoY29yci5wcm9qZWN0Py5wcm9qZWN0Q29kZSA/PyAnJyksXHJcbiAgICAgICAgdGhpcy5lc2NhcGVDc3YoY29yci5vcmlnaW5hdG9yPy5vcmdhbml6YXRpb25Db2RlID8/ICcnKSxcclxuICAgICAgICByZXYuZHVlRGF0ZSA/IG5ldyBEYXRlKHJldi5kdWVEYXRlKS50b0lTT1N0cmluZygpLnNwbGl0KCdUJylbMF0gOiAnJyxcclxuICAgICAgICBuZXcgRGF0ZShyZXYuY3JlYXRlZEF0KS50b0lTT1N0cmluZygpLnNwbGl0KCdUJylbMF0sXHJcbiAgICAgIF0uam9pbignLCcpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIFtoZWFkZXIuam9pbignLCcpLCAuLi5yb3dzXS5qb2luKCdcXG4nKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgZXNjYXBlQ3N2KHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgaWYgKHZhbHVlLmluY2x1ZGVzKCcsJykgfHwgdmFsdWUuaW5jbHVkZXMoJ1wiJykgfHwgdmFsdWUuaW5jbHVkZXMoJ1xcbicpKSB7XHJcbiAgICAgIHJldHVybiBgXCIke3ZhbHVlLnJlcGxhY2UoL1wiL2csICdcIlwiJyl9XCJgO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHZhbHVlO1xyXG4gIH1cclxufVxyXG4iXSwidmVyc2lvbiI6M30= \ No newline at end of file diff --git a/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/d8/correspondenceservice_d8463801745469340085197633f7ae6b.map b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/d8/correspondenceservice_d8463801745469340085197633f7ae6b.map new file mode 100644 index 0000000..1de2baa --- /dev/null +++ b/backend/src/.jest-cache/jest-transform-cache-60cab15b743c6776f41d29bcac696b99-12533232bd0f05f65688e7a7764bf3fb/d8/correspondenceservice_d8463801745469340085197633f7ae6b.map @@ -0,0 +1 @@ +{"file":"E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.ts","mappings":"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","names":[],"sources":["E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.ts"],"sourcesContent":["// File: src/modules/correspondence/correspondence.service.ts\r\n\r\nimport {\r\n Injectable,\r\n NotFoundException,\r\n BadRequestException,\r\n InternalServerErrorException,\r\n ForbiddenException,\r\n Logger,\r\n} from '@nestjs/common';\r\nimport { InjectRepository } from '@nestjs/typeorm';\r\nimport { Repository, DataSource } from 'typeorm';\r\n\r\n// Entities\r\nimport { Correspondence } from './entities/correspondence.entity';\r\nimport { CorrespondenceRevision } from './entities/correspondence-revision.entity';\r\nimport { CorrespondenceType } from './entities/correspondence-type.entity';\r\nimport { CorrespondenceStatus } from './entities/correspondence-status.entity';\r\nimport { CorrespondenceReference } from './entities/correspondence-reference.entity';\r\nimport { CorrespondenceRecipient } from './entities/correspondence-recipient.entity';\r\nimport { CorrespondenceTag } from './entities/correspondence-tag.entity';\r\nimport { Tag } from '../master/entities/tag.entity';\r\nimport { User } from '../user/entities/user.entity';\r\nimport { Organization } from '../organization/entities/organization.entity';\r\n\r\n// DTOs\r\nimport { CreateCorrespondenceDto } from './dto/create-correspondence.dto';\r\nimport { UpdateCorrespondenceDto } from './dto/update-correspondence.dto';\r\nimport { AddReferenceDto } from './dto/add-reference.dto';\r\nimport { SearchCorrespondenceDto } from './dto/search-correspondence.dto';\r\n\r\n// Services\r\nimport { DocumentNumberingService } from '../document-numbering/services/document-numbering.service';\r\nimport { JsonSchemaService } from '../json-schema/json-schema.service';\r\nimport { WorkflowEngineService } from '../workflow-engine/workflow-engine.service';\r\nimport { UserService } from '../user/user.service';\r\nimport { SearchService } from '../search/search.service';\r\nimport { FileStorageService } from '../../common/file-storage/file-storage.service';\r\nimport { UuidResolverService } from '../../common/services/uuid-resolver.service';\r\nimport { NotificationService } from '../notification/notification.service';\r\n\r\n/**\r\n * CorrespondenceService - Document management (CRUD)\r\n */\r\ninterface ResolvedRecipient {\r\n organizationId: number;\r\n type: 'TO' | 'CC';\r\n}\r\n@Injectable()\r\nexport class CorrespondenceService {\r\n private readonly logger = new Logger(CorrespondenceService.name);\r\n\r\n private async hasSystemManageAllPermission(userId: number): Promise {\r\n const permissions = await this.userService.getUserPermissions(userId);\r\n return permissions.includes('system.manage_all');\r\n }\r\n\r\n /**\r\n * Business Rule: Revision Label Strategy\r\n * - RFA, RFI: Use alphabet starting with 'A' (A, B, C...)\r\n * - Other types (LETTER, MEMO, etc.): Use numeric (null for first, then 1, 2, 3...)\r\n */\r\n private getInitialRevisionLabel(typeCode: string): string | null {\r\n const alphabetTypes = ['RFA', 'RFI'];\r\n if (alphabetTypes.includes(typeCode.toUpperCase())) {\r\n return 'A'; // Alphabet for RFA, RFI\r\n }\r\n return null; // Numeric (null for revision 0)\r\n }\r\n\r\n constructor(\r\n @InjectRepository(Correspondence)\r\n private correspondenceRepo: Repository,\r\n @InjectRepository(CorrespondenceRevision)\r\n private revisionRepo: Repository,\r\n @InjectRepository(CorrespondenceType)\r\n private typeRepo: Repository,\r\n @InjectRepository(CorrespondenceStatus)\r\n private statusRepo: Repository,\r\n @InjectRepository(CorrespondenceReference)\r\n private referenceRepo: Repository,\r\n @InjectRepository(CorrespondenceTag)\r\n private tagRepo: Repository,\r\n private numberingService: DocumentNumberingService,\r\n private jsonSchemaService: JsonSchemaService,\r\n private workflowEngine: WorkflowEngineService,\r\n private userService: UserService,\r\n private dataSource: DataSource,\r\n private searchService: SearchService,\r\n private fileStorageService: FileStorageService,\r\n private uuidResolver: UuidResolverService,\r\n private notificationService: NotificationService\r\n ) {}\r\n\r\n /**\r\n * Business Rule Validation: EC-CORR-003 - Correspondence to Self\r\n * Prevent external correspondence to same organization\r\n */\r\n private async validateCorrespondenceRecipients(\r\n createDto: CreateCorrespondenceDto,\r\n user: User\r\n ): Promise {\r\n // Get user's organization\r\n let userOrgId = user.primaryOrganizationId;\r\n if (!userOrgId) {\r\n const fullUser = await this.userService.findOne(user.user_id);\r\n if (fullUser) {\r\n userOrgId = fullUser.primaryOrganizationId;\r\n }\r\n }\r\n\r\n if (!userOrgId) {\r\n if (createDto.originatorId) {\r\n const canManageAll = await this.hasSystemManageAllPermission(\r\n user.user_id\r\n );\r\n if (canManageAll) {\r\n userOrgId = await this.uuidResolver.resolveOrganizationId(\r\n createDto.originatorId\r\n );\r\n }\r\n }\r\n\r\n if (!userOrgId) {\r\n throw new BadRequestException(\r\n 'User must belong to an organization to create documents'\r\n );\r\n }\r\n }\r\n\r\n // For impersonation, use the specified originator\r\n const originatorOrgId = createDto.originatorId\r\n ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId)\r\n : userOrgId;\r\n\r\n // Check if it's internal communication\r\n if (createDto.isInternal) {\r\n // Internal communications should use Circulation instead\r\n throw new BadRequestException(\r\n 'Internal communications should use Circulation Sheet instead of Correspondence'\r\n );\r\n }\r\n\r\n // Validate recipients\r\n if (!createDto.recipients || createDto.recipients.length === 0) {\r\n throw new BadRequestException(\r\n 'At least one recipient (TO or CC) is required'\r\n );\r\n }\r\n\r\n const toRecipients = createDto.recipients.filter((r) => r.type === 'TO');\r\n const ccRecipients = createDto.recipients.filter((r) => r.type === 'CC');\r\n\r\n if (toRecipients.length === 0 && ccRecipients.length === 0) {\r\n throw new BadRequestException(\r\n 'At least one TO or CC recipient is required'\r\n );\r\n }\r\n\r\n // Check for same organization correspondence\r\n for (const recipient of createDto.recipients) {\r\n const recipientOrgId = await this.uuidResolver.resolveOrganizationId(\r\n recipient.organizationId\r\n );\r\n\r\n if (recipientOrgId === originatorOrgId) {\r\n throw new BadRequestException(\r\n 'Cannot send correspondence to your own organization. Use Circulation Sheet for internal communication.'\r\n );\r\n }\r\n }\r\n }\r\n\r\n async create(createDto: CreateCorrespondenceDto, user: User) {\r\n // Business Rule Validation: EC-CORR-003 - Correspondence to Self\r\n await this.validateCorrespondenceRecipients(createDto, user);\r\n // ADR-019: Resolve UUID references to internal INT IDs\r\n const resolvedProjectId = await this.uuidResolver.resolveProjectId(\r\n createDto.projectId\r\n );\r\n const resolvedOriginatorId = createDto.originatorId\r\n ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId)\r\n : undefined;\r\n const resolvedRecipients = createDto.recipients\r\n ? await Promise.all(\r\n createDto.recipients.map(\r\n async (r): Promise => ({\r\n organizationId: await this.uuidResolver.resolveOrganizationId(\r\n r.organizationId\r\n ),\r\n type: r.type,\r\n })\r\n )\r\n )\r\n : undefined;\r\n const type = await this.typeRepo.findOne({\r\n where: { id: createDto.typeId },\r\n });\r\n if (!type) throw new NotFoundException('Document Type not found');\r\n\r\n const statusDraft = await this.statusRepo.findOne({\r\n where: { statusCode: 'DRAFT' },\r\n });\r\n if (!statusDraft) {\r\n throw new InternalServerErrorException(\r\n 'Status DRAFT not found in Master Data'\r\n );\r\n }\r\n\r\n let userOrgId = user.primaryOrganizationId;\r\n\r\n if (!userOrgId) {\r\n const fullUser = await this.userService.findOne(user.user_id);\r\n if (fullUser) {\r\n userOrgId = fullUser.primaryOrganizationId;\r\n }\r\n }\r\n\r\n // Impersonation Logic\r\n if (resolvedOriginatorId && resolvedOriginatorId !== userOrgId) {\r\n const canManageAll = await this.hasSystemManageAllPermission(\r\n user.user_id\r\n );\r\n if (!canManageAll) {\r\n throw new ForbiddenException(\r\n 'You do not have permission to create documents on behalf of other organizations.'\r\n );\r\n }\r\n userOrgId = resolvedOriginatorId;\r\n }\r\n\r\n if (!userOrgId) {\r\n throw new BadRequestException(\r\n 'User must belong to an organization to create documents'\r\n );\r\n }\r\n\r\n if (createDto.details) {\r\n try {\r\n await this.jsonSchemaService.validate(type.typeCode, createDto.details);\r\n } catch (error: unknown) {\r\n this.logger.warn(\r\n `Schema validation warning for ${type.typeCode}: ${(error as Error).message}`\r\n );\r\n }\r\n }\r\n\r\n const queryRunner = this.dataSource.createQueryRunner();\r\n await queryRunner.connect();\r\n await queryRunner.startTransaction();\r\n\r\n try {\r\n // [Fix #6] Fetch real ORG Code from Organization entity\r\n const originatorOrg = await this.dataSource.manager.findOne(\r\n Organization,\r\n {\r\n where: { id: userOrgId },\r\n }\r\n );\r\n const orgCode = originatorOrg?.organizationCode ?? 'UNK';\r\n\r\n // [v1.5.1] Extract recipient organization from recipients array (Primary TO)\r\n const toRecipient = resolvedRecipients?.find((r) => r.type === 'TO');\r\n const recipientOrganizationId = toRecipient?.organizationId;\r\n\r\n let recipientCode = '';\r\n if (recipientOrganizationId) {\r\n const recOrg = await this.dataSource.manager.findOne(Organization, {\r\n where: { id: recipientOrganizationId },\r\n });\r\n if (recOrg) recipientCode = recOrg.organizationCode;\r\n }\r\n\r\n const docNumber = await this.numberingService.generateNextNumber({\r\n projectId: resolvedProjectId,\r\n originatorOrganizationId: userOrgId,\r\n typeId: createDto.typeId,\r\n disciplineId: createDto.disciplineId,\r\n subTypeId: createDto.subTypeId,\r\n recipientOrganizationId, // [v1.5.1] Pass recipient for document number format\r\n year: new Date().getFullYear(),\r\n customTokens: {\r\n TYPE_CODE: type.typeCode,\r\n ORG_CODE: orgCode,\r\n RECIPIENT_CODE: recipientCode,\r\n REC_CODE: recipientCode,\r\n },\r\n });\r\n\r\n const correspondence = queryRunner.manager.create(Correspondence, {\r\n correspondenceNumber: docNumber.number,\r\n correspondenceTypeId: createDto.typeId,\r\n disciplineId: createDto.disciplineId,\r\n projectId: resolvedProjectId,\r\n originatorId: userOrgId,\r\n isInternal: createDto.isInternal || false,\r\n createdBy: user.user_id,\r\n });\r\n const savedCorr = await queryRunner.manager.save(correspondence);\r\n\r\n const revision = queryRunner.manager.create(CorrespondenceRevision, {\r\n correspondenceId: savedCorr.id,\r\n revisionNumber: 0,\r\n revisionLabel: this.getInitialRevisionLabel(type.typeCode),\r\n isCurrent: true,\r\n statusId: statusDraft.id,\r\n subject: createDto.subject,\r\n body: createDto.body,\r\n remarks: createDto.remarks,\r\n dueDate: createDto.dueDate ? new Date(createDto.dueDate) : undefined,\r\n documentDate: createDto.documentDate\r\n ? new Date(createDto.documentDate)\r\n : undefined,\r\n issuedDate: createDto.issuedDate\r\n ? new Date(createDto.issuedDate)\r\n : undefined,\r\n receivedDate: createDto.receivedDate\r\n ? new Date(createDto.receivedDate)\r\n : undefined,\r\n description: createDto.description,\r\n details: createDto.details,\r\n createdBy: user.user_id,\r\n schemaVersion: 1,\r\n });\r\n await queryRunner.manager.save(revision);\r\n\r\n // Save Recipients (using resolved INT IDs)\r\n if (resolvedRecipients && resolvedRecipients.length > 0) {\r\n const recipients = resolvedRecipients.map((r) =>\r\n queryRunner.manager.create(CorrespondenceRecipient, {\r\n correspondenceId: savedCorr.id,\r\n recipientOrganizationId: r.organizationId,\r\n recipientType: r.type,\r\n })\r\n );\r\n await queryRunner.manager.save(recipients);\r\n }\r\n\r\n // Commit attachments from Temp → Permanent (Two-Phase Storage)\r\n if (createDto.attachmentTempIds?.length) {\r\n const issueDate = createDto.issuedDate\r\n ? new Date(createDto.issuedDate)\r\n : createDto.documentDate\r\n ? new Date(createDto.documentDate)\r\n : undefined;\r\n\r\n await this.fileStorageService.commit(createDto.attachmentTempIds, {\r\n issueDate,\r\n documentType: 'Correspondence',\r\n });\r\n }\r\n\r\n await queryRunner.commitTransaction();\r\n\r\n // Start Workflow Instance (non-blocking)\r\n try {\r\n const workflowCode = `CORRESPONDENCE_${type.typeCode}`;\r\n await this.workflowEngine.createInstance(\r\n workflowCode,\r\n 'correspondence',\r\n savedCorr.id.toString(),\r\n {\r\n projectId: resolvedProjectId,\r\n originatorId: userOrgId,\r\n disciplineId: createDto.disciplineId,\r\n initiatorId: user.user_id,\r\n } as Record\r\n );\r\n } catch (error: unknown) {\r\n this.logger.warn(\r\n `Workflow not started for ${docNumber.number} (Code: CORRESPONDENCE_${type.typeCode}): ${(error as Error).message}`\r\n );\r\n }\r\n\r\n // Fire-and-forget search indexing (non-blocking, void intentional)\r\n void this.searchService.indexDocument({\r\n id: savedCorr.id,\r\n publicId: savedCorr.publicId,\r\n type: 'correspondence',\r\n docNumber: docNumber.number,\r\n title: createDto.subject,\r\n description: createDto.description,\r\n status: 'DRAFT',\r\n projectId: resolvedProjectId,\r\n createdAt: new Date(),\r\n });\r\n\r\n return {\r\n ...savedCorr,\r\n currentRevision: revision,\r\n };\r\n } catch (err) {\r\n await queryRunner.rollbackTransaction();\r\n this.logger.error(\r\n `Failed to create correspondence: ${(err as Error).message}`\r\n );\r\n throw err;\r\n } finally {\r\n await queryRunner.release();\r\n }\r\n }\r\n\r\n async findAll(searchDto: SearchCorrespondenceDto = {}) {\r\n const {\r\n search,\r\n typeId,\r\n projectId,\r\n statusId,\r\n status,\r\n page = 1,\r\n limit = 10,\r\n } = searchDto;\r\n const skip = (page - 1) * limit;\r\n\r\n // Change: Query from Revision Repo\r\n const query = this.revisionRepo\r\n .createQueryBuilder('rev')\r\n .leftJoinAndSelect('rev.correspondence', 'corr')\r\n .leftJoinAndSelect('corr.type', 'type')\r\n .leftJoinAndSelect('corr.project', 'project')\r\n .leftJoinAndSelect('corr.originator', 'org')\r\n .leftJoinAndSelect('rev.status', 'status');\r\n\r\n // Filter by Revision Status\r\n const revStatus = searchDto.revisionStatus || 'CURRENT';\r\n\r\n if (revStatus === 'CURRENT') {\r\n query.where('rev.isCurrent = :isCurrent', { isCurrent: true });\r\n } else if (revStatus === 'OLD') {\r\n query.where('rev.isCurrent = :isCurrent', { isCurrent: false });\r\n }\r\n // If 'ALL', no filter needed on isCurrent\r\n\r\n if (projectId) {\r\n query.andWhere('corr.projectId = :projectId', { projectId });\r\n }\r\n\r\n if (typeId) {\r\n query.andWhere('corr.correspondenceTypeId = :typeId', { typeId });\r\n }\r\n\r\n if (statusId) {\r\n query.andWhere('rev.statusId = :statusId', { statusId });\r\n }\r\n\r\n if (status) {\r\n query.andWhere('status.statusCode = :status', { status });\r\n }\r\n\r\n if (search) {\r\n query.andWhere(\r\n '(corr.correspondenceNumber LIKE :search OR rev.subject LIKE :search)',\r\n { search: `%${search}%` }\r\n );\r\n }\r\n\r\n // Default Sort: Latest Created\r\n query.orderBy('rev.createdAt', 'DESC').skip(skip).take(limit);\r\n\r\n const [items, total] = await query.getManyAndCount();\r\n\r\n return {\r\n data: items,\r\n meta: {\r\n total,\r\n page,\r\n limit,\r\n totalPages: Math.ceil(total / limit),\r\n },\r\n };\r\n }\r\n\r\n async findOne(id: number) {\r\n const correspondence = await this.correspondenceRepo.findOne({\r\n where: { id },\r\n relations: [\r\n 'revisions',\r\n 'revisions.status',\r\n 'type',\r\n 'project',\r\n 'originator',\r\n 'recipients',\r\n 'recipients.recipientOrganization', // [v1.5.1] Fixed relation name\r\n ],\r\n });\r\n\r\n if (!correspondence) {\r\n throw new NotFoundException(`Correspondence with ID ${id} not found`);\r\n }\r\n return correspondence;\r\n }\r\n\r\n async findOneByUuid(publicId: string) {\r\n const correspondence = await this.correspondenceRepo.findOne({\r\n where: { publicId },\r\n relations: [\r\n 'revisions',\r\n 'revisions.status',\r\n 'type',\r\n 'project',\r\n 'originator',\r\n 'recipients',\r\n 'recipients.recipientOrganization',\r\n ],\r\n });\r\n\r\n if (!correspondence) {\r\n throw new NotFoundException(\r\n `Correspondence with UUID ${publicId} not found`\r\n );\r\n }\r\n return correspondence;\r\n }\r\n\r\n async addReference(id: number, dto: AddReferenceDto) {\r\n const source = await this.correspondenceRepo.findOne({ where: { id } });\r\n // ADR-019: Resolve target publicId → internal INT id\r\n const target = await this.correspondenceRepo.findOne({\r\n where: { publicId: dto.targetUuid },\r\n });\r\n\r\n if (!source || !target) {\r\n throw new NotFoundException('Source or Target correspondence not found');\r\n }\r\n\r\n if (source.id === target.id) {\r\n throw new BadRequestException('Cannot reference self');\r\n }\r\n\r\n const exists = await this.referenceRepo.findOne({\r\n where: {\r\n sourceId: id,\r\n targetId: target.id,\r\n },\r\n });\r\n\r\n if (exists) {\r\n return exists;\r\n }\r\n\r\n const ref = this.referenceRepo.create({\r\n sourceId: id,\r\n targetId: target.id,\r\n });\r\n\r\n return this.referenceRepo.save(ref);\r\n }\r\n\r\n async removeReference(id: number, targetId: number) {\r\n const result = await this.referenceRepo.delete({\r\n sourceId: id,\r\n targetId: targetId,\r\n });\r\n\r\n if (result.affected === 0) {\r\n throw new NotFoundException('Reference not found');\r\n }\r\n }\r\n\r\n async getTags(id: number) {\r\n const rows = await this.tagRepo.find({\r\n where: { correspondenceId: id },\r\n relations: ['tag'],\r\n });\r\n return rows.map((r) => r.tag).filter(Boolean);\r\n }\r\n\r\n async addTag(id: number, tagId: number) {\r\n const correspondence = await this.correspondenceRepo.findOne({\r\n where: { id },\r\n });\r\n if (!correspondence) {\r\n throw new NotFoundException(`Correspondence ${id} not found`);\r\n }\r\n\r\n const tag = await this.dataSource.manager.findOne(Tag, {\r\n where: { id: tagId },\r\n });\r\n if (!tag) {\r\n throw new NotFoundException(`Tag ${tagId} not found`);\r\n }\r\n\r\n const exists = await this.tagRepo.findOne({\r\n where: { correspondenceId: id, tagId },\r\n });\r\n if (exists) return exists;\r\n\r\n const row = this.tagRepo.create({ correspondenceId: id, tagId });\r\n return this.tagRepo.save(row);\r\n }\r\n\r\n async removeTag(id: number, tagId: number) {\r\n const result = await this.tagRepo.delete({ correspondenceId: id, tagId });\r\n if (result.affected === 0) {\r\n throw new NotFoundException('Tag assignment not found');\r\n }\r\n }\r\n\r\n async getReferences(id: number) {\r\n const outgoing = await this.referenceRepo.find({\r\n where: { sourceId: id },\r\n relations: ['target', 'target.type'],\r\n });\r\n\r\n const incoming = await this.referenceRepo.find({\r\n where: { targetId: id },\r\n relations: ['source', 'source.type'],\r\n });\r\n\r\n return { outgoing, incoming };\r\n }\r\n\r\n async update(id: number, updateDto: UpdateCorrespondenceDto, user: User) {\r\n // 1. Find Current Revision\r\n const revision = await this.revisionRepo.findOne({\r\n where: {\r\n correspondenceId: id,\r\n isCurrent: true,\r\n },\r\n relations: ['correspondence'],\r\n });\r\n\r\n if (!revision) {\r\n throw new NotFoundException(\r\n `Current revision for correspondence ${id} not found`\r\n );\r\n }\r\n\r\n // 2. Check Permission\r\n if (revision.statusId) {\r\n const status = await this.statusRepo.findOne({\r\n where: { id: revision.statusId },\r\n });\r\n if (status && status.statusCode !== 'DRAFT') {\r\n throw new BadRequestException('Only DRAFT documents can be updated');\r\n }\r\n }\r\n\r\n // ADR-019: Resolve UUID references in update DTO\r\n const updResolvedProjectId = updateDto.projectId\r\n ? await this.uuidResolver.resolveProjectId(updateDto.projectId)\r\n : undefined;\r\n const updResolvedOriginatorId = updateDto.originatorId\r\n ? await this.uuidResolver.resolveOrganizationId(updateDto.originatorId)\r\n : undefined;\r\n const updResolvedRecipients = updateDto.recipients\r\n ? await Promise.all(\r\n updateDto.recipients.map(\r\n async (r): Promise => ({\r\n organizationId: await this.uuidResolver.resolveOrganizationId(\r\n r.organizationId\r\n ),\r\n type: r.type,\r\n })\r\n )\r\n )\r\n : undefined;\r\n\r\n // 3. Update Correspondence Entity if needed\r\n const correspondenceUpdate: Record = {};\r\n if (updateDto.disciplineId)\r\n correspondenceUpdate.disciplineId = updateDto.disciplineId;\r\n if (updResolvedProjectId)\r\n correspondenceUpdate.projectId = updResolvedProjectId;\r\n if (updResolvedOriginatorId)\r\n correspondenceUpdate.originatorId = updResolvedOriginatorId;\r\n\r\n if (Object.keys(correspondenceUpdate).length > 0) {\r\n await this.correspondenceRepo.update(id, correspondenceUpdate);\r\n }\r\n\r\n // 4. Update Revision Entity\r\n const revisionUpdate: Record = {};\r\n if (updateDto.subject) revisionUpdate.subject = updateDto.subject;\r\n if (updateDto.body) revisionUpdate.body = updateDto.body;\r\n if (updateDto.remarks) revisionUpdate.remarks = updateDto.remarks;\r\n // Format Date correctly if string\r\n if (updateDto.dueDate) revisionUpdate.dueDate = new Date(updateDto.dueDate);\r\n if (updateDto.documentDate)\r\n revisionUpdate.documentDate = new Date(updateDto.documentDate);\r\n if (updateDto.issuedDate)\r\n revisionUpdate.issuedDate = new Date(updateDto.issuedDate);\r\n if (updateDto.receivedDate)\r\n revisionUpdate.receivedDate = new Date(updateDto.receivedDate);\r\n if (updateDto.description)\r\n revisionUpdate.description = updateDto.description;\r\n if (updateDto.details) revisionUpdate.details = updateDto.details;\r\n\r\n if (Object.keys(revisionUpdate).length > 0) {\r\n await this.revisionRepo.update(revision.id, revisionUpdate);\r\n }\r\n\r\n // 4.5 Commit new attachments from Temp → Permanent (Two-Phase Storage)\r\n if (updateDto.attachmentTempIds?.length) {\r\n const issueDate = updateDto.issuedDate\r\n ? new Date(updateDto.issuedDate)\r\n : updateDto.documentDate\r\n ? new Date(updateDto.documentDate)\r\n : revision.issuedDate || revision.documentDate || undefined;\r\n\r\n await this.fileStorageService.commit(updateDto.attachmentTempIds, {\r\n issueDate: issueDate ? new Date(issueDate) : undefined,\r\n documentType: 'Correspondence',\r\n });\r\n }\r\n\r\n // 5. Update Recipients if provided\r\n if (updResolvedRecipients) {\r\n const recipientRepo = this.dataSource.getRepository(\r\n CorrespondenceRecipient\r\n );\r\n await recipientRepo.delete({ correspondenceId: id });\r\n\r\n const newRecipients = updResolvedRecipients.map((r) =>\r\n recipientRepo.create({\r\n correspondenceId: id,\r\n recipientOrganizationId: r.organizationId,\r\n recipientType: r.type,\r\n })\r\n );\r\n await recipientRepo.save(newRecipients);\r\n }\r\n\r\n // 6. Regenerate Document Number if structural fields changed (Recipient, Discipline, Type, Project)\r\n // AND it is a DRAFT.\r\n\r\n // Fetch fresh data for context and comparison\r\n const currentCorr = await this.correspondenceRepo.findOne({\r\n where: { id },\r\n relations: ['type', 'recipients', 'recipients.recipientOrganization'],\r\n });\r\n\r\n if (currentCorr) {\r\n const currentToRecipient = currentCorr.recipients?.find(\r\n (r) => r.recipientType === 'TO'\r\n );\r\n const currentRecipientId = currentToRecipient?.recipientOrganizationId;\r\n\r\n // Check for ACTUAL value changes\r\n const isProjectChanged =\r\n updResolvedProjectId !== undefined &&\r\n updResolvedProjectId !== currentCorr.projectId;\r\n const isOriginatorChanged =\r\n updResolvedOriginatorId !== undefined &&\r\n updResolvedOriginatorId !== currentCorr.originatorId;\r\n const isDisciplineChanged =\r\n updateDto.disciplineId !== undefined &&\r\n updateDto.disciplineId !== currentCorr.disciplineId;\r\n const isTypeChanged =\r\n updateDto.typeId !== undefined &&\r\n updateDto.typeId !== currentCorr.correspondenceTypeId;\r\n\r\n let isRecipientChanged = false;\r\n let newRecipientId: number | undefined;\r\n\r\n if (updResolvedRecipients) {\r\n const newToRecipient = updResolvedRecipients.find(\r\n (r) => r.type === 'TO'\r\n );\r\n newRecipientId = newToRecipient?.organizationId;\r\n\r\n if (newRecipientId !== currentRecipientId) {\r\n isRecipientChanged = true;\r\n }\r\n }\r\n\r\n if (\r\n isProjectChanged ||\r\n isDisciplineChanged ||\r\n isTypeChanged ||\r\n isRecipientChanged ||\r\n isOriginatorChanged\r\n ) {\r\n const targetRecipientId = isRecipientChanged\r\n ? newRecipientId\r\n : currentRecipientId;\r\n\r\n // Resolve Recipient Code for the NEW context\r\n let recipientCode = '';\r\n if (targetRecipientId) {\r\n const recOrg = await this.dataSource.manager.findOne(Organization, {\r\n where: { id: targetRecipientId },\r\n });\r\n if (recOrg) recipientCode = recOrg.organizationCode;\r\n }\r\n\r\n // [Fix #6] Fetch real ORG Code from originator organization\r\n const originatorOrgForUpdate = await this.dataSource.manager.findOne(\r\n Organization,\r\n {\r\n where: {\r\n id: updResolvedOriginatorId ?? currentCorr.originatorId ?? 0,\r\n },\r\n }\r\n );\r\n const orgCode = originatorOrgForUpdate?.organizationCode ?? 'UNK';\r\n\r\n // Prepare Contexts\r\n const oldCtx = {\r\n projectId: currentCorr.projectId,\r\n originatorOrganizationId: currentCorr.originatorId ?? 0,\r\n typeId: currentCorr.correspondenceTypeId,\r\n disciplineId: currentCorr.disciplineId,\r\n recipientOrganizationId: currentRecipientId,\r\n year: new Date().getFullYear(),\r\n };\r\n\r\n const newCtx = {\r\n projectId: updResolvedProjectId ?? currentCorr.projectId,\r\n originatorOrganizationId:\r\n updResolvedOriginatorId ?? currentCorr.originatorId ?? 0,\r\n typeId: updateDto.typeId ?? currentCorr.correspondenceTypeId,\r\n disciplineId: updateDto.disciplineId ?? currentCorr.disciplineId,\r\n recipientOrganizationId: targetRecipientId,\r\n year: new Date().getFullYear(),\r\n userId: user.user_id, // Pass User ID for Audit\r\n customTokens: {\r\n TYPE_CODE: currentCorr.type?.typeCode || '',\r\n ORG_CODE: orgCode,\r\n RECIPIENT_CODE: recipientCode,\r\n REC_CODE: recipientCode,\r\n },\r\n };\r\n\r\n // If Type Changed, need NEW Type Code\r\n if (isTypeChanged) {\r\n const newType = await this.typeRepo.findOne({\r\n where: { id: newCtx.typeId },\r\n });\r\n if (newType) newCtx.customTokens.TYPE_CODE = newType.typeCode;\r\n }\r\n\r\n const newDocNumber = await this.numberingService.updateNumberForDraft(\r\n currentCorr.correspondenceNumber,\r\n oldCtx,\r\n newCtx\r\n );\r\n\r\n await this.correspondenceRepo.update(id, {\r\n correspondenceNumber: newDocNumber,\r\n });\r\n }\r\n }\r\n\r\n const updated = await this.findOne(id);\r\n\r\n // Re-index updated document in Elasticsearch (fire-and-forget)\r\n void this.searchService.indexDocument({\r\n id: updated.id,\r\n publicId: updated.publicId,\r\n type: 'correspondence',\r\n docNumber: updated.correspondenceNumber,\r\n title: updateDto.subject ?? updated.revisions?.[0]?.subject,\r\n description: updateDto.description ?? updated.revisions?.[0]?.description,\r\n status: 'DRAFT',\r\n projectId: updated.projectId,\r\n createdAt: updated.createdAt,\r\n });\r\n\r\n return updated;\r\n }\r\n\r\n async previewDocumentNumber(createDto: CreateCorrespondenceDto, user: User) {\r\n // ADR-019: Resolve UUID references\r\n const previewProjectId = await this.uuidResolver.resolveProjectId(\r\n createDto.projectId\r\n );\r\n const previewOriginatorId = createDto.originatorId\r\n ? await this.uuidResolver.resolveOrganizationId(createDto.originatorId)\r\n : undefined;\r\n const previewRecipients = createDto.recipients\r\n ? await Promise.all(\r\n createDto.recipients.map(\r\n async (r): Promise => ({\r\n organizationId: await this.uuidResolver.resolveOrganizationId(\r\n r.organizationId\r\n ),\r\n type: r.type,\r\n })\r\n )\r\n )\r\n : undefined;\r\n\r\n const type = await this.typeRepo.findOne({\r\n where: { id: createDto.typeId },\r\n });\r\n if (!type) throw new NotFoundException('Document Type not found');\r\n\r\n let userOrgId = user.primaryOrganizationId;\r\n if (!userOrgId) {\r\n const fullUser = await this.userService.findOne(user.user_id);\r\n if (fullUser) userOrgId = fullUser.primaryOrganizationId;\r\n }\r\n\r\n if (previewOriginatorId && previewOriginatorId !== userOrgId) {\r\n // Allow impersonation for preview\r\n userOrgId = previewOriginatorId;\r\n }\r\n\r\n // Extract recipient from recipients array\r\n const toRecipient = previewRecipients?.find((r) => r.type === 'TO');\r\n const recipientOrganizationId = toRecipient?.organizationId;\r\n\r\n let recipientCode = '';\r\n if (recipientOrganizationId) {\r\n const recOrg = await this.dataSource.manager.findOne(Organization, {\r\n where: { id: recipientOrganizationId },\r\n });\r\n if (recOrg) recipientCode = recOrg.organizationCode;\r\n }\r\n\r\n return this.numberingService.previewNumber({\r\n projectId: previewProjectId,\r\n originatorOrganizationId: userOrgId!,\r\n typeId: createDto.typeId,\r\n disciplineId: createDto.disciplineId,\r\n subTypeId: createDto.subTypeId,\r\n recipientOrganizationId,\r\n year: new Date().getFullYear(),\r\n customTokens: {\r\n TYPE_CODE: type.typeCode,\r\n RECIPIENT_CODE: recipientCode,\r\n REC_CODE: recipientCode,\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Business Rule Implementation: EC-CORR-001 - Cancel Correspondence with Downstream Circulation\r\n * Cancel correspondence and handle related circulations\r\n */\r\n async cancel(publicId: string, reason: string, user: User) {\r\n const correspondence = await this.findOneByUuid(publicId);\r\n\r\n // Check if user has permission to cancel (Org Admin or Superadmin only)\r\n const permissions = await this.userService.getUserPermissions(user.user_id);\r\n const canCancel =\r\n permissions.includes('correspondence.cancel') ||\r\n permissions.includes('system.manage_all');\r\n\r\n if (!canCancel) {\r\n throw new ForbiddenException(\r\n 'Only administrators can cancel correspondences'\r\n );\r\n }\r\n\r\n // Check if there are any active circulations\r\n const circulationRepo = this.dataSource.getRepository('Circulation');\r\n const activeCirculations = await circulationRepo.find({\r\n where: {\r\n correspondenceId: correspondence.id,\r\n status: 'OPEN',\r\n },\r\n });\r\n\r\n const warningMessage =\r\n activeCirculations.length > 0\r\n ? `There are ${activeCirculations.length} active circulation(s) for this correspondence. Canceling will force close all related circulations.`\r\n : '';\r\n\r\n // Get the current revision to update status\r\n const currentRevision = await this.revisionRepo.findOne({\r\n where: {\r\n correspondenceId: correspondence.id,\r\n isCurrent: true,\r\n },\r\n });\r\n\r\n if (!currentRevision) {\r\n throw new NotFoundException('Current revision not found');\r\n }\r\n\r\n // Get cancelled status\r\n const cancelledStatus = await this.statusRepo.findOne({\r\n where: { statusCode: 'CANCELLED' },\r\n });\r\n\r\n if (!cancelledStatus) {\r\n throw new InternalServerErrorException('CANCELLED status not found');\r\n }\r\n\r\n const queryRunner = this.dataSource.createQueryRunner();\r\n await queryRunner.connect();\r\n await queryRunner.startTransaction();\r\n\r\n try {\r\n // Update correspondence revision status to CANCELLED\r\n await queryRunner.manager.update(\r\n CorrespondenceRevision,\r\n currentRevision.id,\r\n {\r\n statusId: cancelledStatus.id,\r\n remarks: `Cancelled: ${reason}`,\r\n }\r\n );\r\n\r\n // Force close all active circulations\r\n if (activeCirculations.length > 0) {\r\n await queryRunner.manager.update(\r\n 'Circulation',\r\n {\r\n correspondenceId: correspondence.id,\r\n status: 'OPEN',\r\n },\r\n {\r\n status: 'FORCE_CLOSED',\r\n closedAt: new Date(),\r\n closedBy: user.user_id,\r\n closeReason: `Correspondence cancelled: ${reason}`,\r\n }\r\n );\r\n }\r\n\r\n await queryRunner.commitTransaction();\r\n\r\n // Re-index cancelled status in Elasticsearch (fire-and-forget)\r\n void this.searchService.indexDocument({\r\n id: correspondence.id,\r\n publicId: correspondence.publicId,\r\n type: 'correspondence',\r\n docNumber: correspondence.correspondenceNumber,\r\n title: currentRevision.subject,\r\n status: 'CANCELLED',\r\n projectId: correspondence.projectId,\r\n createdAt: correspondence.createdAt,\r\n });\r\n\r\n // Notify originator's doc-control user about cancellation (fire-and-forget)\r\n if (correspondence.originatorId) {\r\n void this.userService\r\n .findDocControlIdByOrg(correspondence.originatorId)\r\n .then((targetUserId) => {\r\n if (targetUserId) {\r\n void this.notificationService.send({\r\n userId: targetUserId,\r\n title: 'Correspondence Cancelled',\r\n message: `${correspondence.correspondenceNumber} — ${currentRevision.subject} has been cancelled. Reason: ${reason}`,\r\n type: 'EMAIL',\r\n entityType: 'correspondence',\r\n entityId: correspondence.id,\r\n link: `/correspondences/${correspondence.publicId}`,\r\n });\r\n }\r\n })\r\n .catch((err: Error) =>\r\n this.logger.warn(`Cancel notification failed: ${err.message}`)\r\n );\r\n }\r\n\r\n return {\r\n success: true,\r\n message: warningMessage || 'Correspondence cancelled successfully',\r\n activeCirculationsCount: activeCirculations.length,\r\n };\r\n } catch (error) {\r\n await queryRunner.rollbackTransaction();\r\n this.logger.error(\r\n `Failed to cancel correspondence: ${(error as Error).message}`\r\n );\r\n throw error;\r\n } finally {\r\n await queryRunner.release();\r\n }\r\n }\r\n\r\n async bulkCancel(\r\n publicIds: string[],\r\n reason: string,\r\n user: User\r\n ): Promise<{ succeeded: string[]; failed: string[] }> {\r\n const succeeded: string[] = [];\r\n const failed: string[] = [];\r\n\r\n for (const publicId of publicIds) {\r\n try {\r\n await this.cancel(publicId, reason, user);\r\n succeeded.push(publicId);\r\n } catch {\r\n failed.push(publicId);\r\n }\r\n }\r\n\r\n return { succeeded, failed };\r\n }\r\n\r\n async exportCsv(searchDto: SearchCorrespondenceDto): Promise {\r\n const { data } = await this.findAll(searchDto);\r\n\r\n const header = [\r\n 'Document No.',\r\n 'Rev',\r\n 'Subject',\r\n 'Type',\r\n 'Status',\r\n 'Project',\r\n 'From',\r\n 'Due Date',\r\n 'Created At',\r\n ];\r\n const rows = data.map((rev) => {\r\n const corr = rev.correspondence ?? (rev as unknown as Correspondence);\r\n return [\r\n this.escapeCsv(corr.correspondenceNumber ?? ''),\r\n this.escapeCsv(rev.revisionLabel ?? String(rev.revisionNumber ?? 0)),\r\n this.escapeCsv(rev.subject ?? ''),\r\n this.escapeCsv(corr.type?.typeCode ?? ''),\r\n this.escapeCsv(rev.status?.statusCode ?? ''),\r\n this.escapeCsv(corr.project?.projectCode ?? ''),\r\n this.escapeCsv(corr.originator?.organizationCode ?? ''),\r\n rev.dueDate ? new Date(rev.dueDate).toISOString().split('T')[0] : '',\r\n new Date(rev.createdAt).toISOString().split('T')[0],\r\n ].join(',');\r\n });\r\n\r\n return [header.join(','), ...rows].join('\\n');\r\n }\r\n\r\n private escapeCsv(value: string): string {\r\n if (value.includes(',') || value.includes('\"') || value.includes('\\n')) {\r\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\r\n }\r\n return value;\r\n }\r\n}\r\n"],"version":3} \ No newline at end of file diff --git a/backend/src/.jest-cache/perf-cache-60cab15b743c6776f41d29bcac696b99-da39a3ee5e6b4b0d3255bfef95601890 b/backend/src/.jest-cache/perf-cache-60cab15b743c6776f41d29bcac696b99-da39a3ee5e6b4b0d3255bfef95601890 index 7284c83..1b31b15 100644 --- a/backend/src/.jest-cache/perf-cache-60cab15b743c6776f41d29bcac696b99-da39a3ee5e6b4b0d3255bfef95601890 +++ b/backend/src/.jest-cache/perf-cache-60cab15b743c6776f41d29bcac696b99-da39a3ee5e6b4b0d3255bfef95601890 @@ -1 +1 @@ -{"E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\due-date-reminder.service.spec.ts":[1,1723],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.spec.ts":[1,7901],"E:\\np-dms\\lcbp3\\backend\\src\\common\\auth\\auth.service.spec.ts":[1,1538],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\document-numbering\\document-numbering.service.spec.ts":[1,2037],"E:\\np-dms\\lcbp3\\backend\\src\\common\\auth\\casl\\ability.factory.spec.ts":[1,1294],"E:\\np-dms\\lcbp3\\backend\\src\\common\\services\\uuid-resolver.service.spec.ts":[1,5491],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\workflow-engine\\workflow-engine.service.spec.ts":[1,5639],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\workflow-engine\\dsl\\parser.service.spec.ts":[1,5818],"E:\\np-dms\\lcbp3\\backend\\src\\common\\pipes\\parse-uuid.pipe.spec.ts":[1,355],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\user\\user.service.spec.ts":[1,1270],"E:\\np-dms\\lcbp3\\backend\\src\\common\\file-storage\\file-storage.service.spec.ts":[1,1187],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.controller.spec.ts":[1,8495],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\migration\\migration.service.spec.ts":[1,1296],"E:\\np-dms\\lcbp3\\backend\\src\\common\\entities\\uuid-base.entity.spec.ts":[1,430],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\project\\project.service.spec.ts":[1,1109],"E:\\np-dms\\lcbp3\\backend\\src\\common\\auth\\auth.controller.spec.ts":[1,2191],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\document-numbering\\services\\manual-override.service.spec.ts":[1,5256],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\project\\project.controller.spec.ts":[1,1827],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\migration\\migration.controller.spec.ts":[1,6380],"E:\\np-dms\\lcbp3\\backend\\src\\common\\file-storage\\file-storage.controller.spec.ts":[1,1482],"E:\\np-dms\\lcbp3\\backend\\src\\app.controller.spec.ts":[1,587],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\json-schema\\json-schema.controller.spec.ts":[1,5062]} \ No newline at end of file +{"E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\due-date-reminder.service.spec.ts":[1,1723],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.spec.ts":[1,10118],"E:\\np-dms\\lcbp3\\backend\\src\\common\\auth\\auth.service.spec.ts":[1,1538],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\document-numbering\\document-numbering.service.spec.ts":[1,2037],"E:\\np-dms\\lcbp3\\backend\\src\\common\\auth\\casl\\ability.factory.spec.ts":[1,1294],"E:\\np-dms\\lcbp3\\backend\\src\\common\\services\\uuid-resolver.service.spec.ts":[1,5491],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\workflow-engine\\workflow-engine.service.spec.ts":[1,5639],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\workflow-engine\\dsl\\parser.service.spec.ts":[1,5818],"E:\\np-dms\\lcbp3\\backend\\src\\common\\pipes\\parse-uuid.pipe.spec.ts":[1,355],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\user\\user.service.spec.ts":[1,1270],"E:\\np-dms\\lcbp3\\backend\\src\\common\\file-storage\\file-storage.service.spec.ts":[1,1187],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\correspondence\\correspondence.controller.spec.ts":[1,10937],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\migration\\migration.service.spec.ts":[1,1296],"E:\\np-dms\\lcbp3\\backend\\src\\common\\entities\\uuid-base.entity.spec.ts":[1,430],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\project\\project.service.spec.ts":[1,1109],"E:\\np-dms\\lcbp3\\backend\\src\\common\\auth\\auth.controller.spec.ts":[1,2191],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\document-numbering\\services\\manual-override.service.spec.ts":[1,5256],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\project\\project.controller.spec.ts":[1,1827],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\migration\\migration.controller.spec.ts":[1,6380],"E:\\np-dms\\lcbp3\\backend\\src\\common\\file-storage\\file-storage.controller.spec.ts":[1,1482],"E:\\np-dms\\lcbp3\\backend\\src\\app.controller.spec.ts":[1,587],"E:\\np-dms\\lcbp3\\backend\\src\\modules\\json-schema\\json-schema.controller.spec.ts":[1,5062]} \ No newline at end of file diff --git a/backend/src/modules/correspondence/correspondence.service.spec.ts b/backend/src/modules/correspondence/correspondence.service.spec.ts index 2f3d9b7..72ab08e 100644 --- a/backend/src/modules/correspondence/correspondence.service.spec.ts +++ b/backend/src/modules/correspondence/correspondence.service.spec.ts @@ -427,5 +427,297 @@ describe('CorrespondenceService', () => { expect.objectContaining({ originatorId: 10 }) ); }); + + it('should set revisionLabel to "A" for RFA type', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: 10, + } as unknown as User; + + const createDto: CreateCorrespondenceDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + + const typeRepo = testingModule.get>( + getRepositoryToken(CorrespondenceType) + ); + const statusRepo = testingModule.get>( + getRepositoryToken(CorrespondenceStatus) + ); + const uuidResolver = + testingModule.get(UuidResolverService); + + (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100); + (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20); + + (typeRepo.findOne as jest.Mock).mockResolvedValue({ + id: 1, + typeCode: 'RFA', + }); + (statusRepo.findOne as jest.Mock).mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + + (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({ + number: 'DOC-001', + }); + + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn( + (_entity: unknown, payload: Record) => payload + ), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + + (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue( + queryRunner + ); + + await service.create(createDto, mockUser); + + expect(queryRunner.manager.create).toHaveBeenCalledWith( + CorrespondenceRevision, + expect.objectContaining({ revisionLabel: 'A' }) + ); + }); + + it('should set revisionLabel to "A" for RFI type', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: 10, + } as unknown as User; + + const createDto: CreateCorrespondenceDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + + const typeRepo = testingModule.get>( + getRepositoryToken(CorrespondenceType) + ); + const statusRepo = testingModule.get>( + getRepositoryToken(CorrespondenceStatus) + ); + const uuidResolver = + testingModule.get(UuidResolverService); + + (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100); + (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20); + + (typeRepo.findOne as jest.Mock).mockResolvedValue({ + id: 1, + typeCode: 'RFI', + }); + (statusRepo.findOne as jest.Mock).mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + + (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({ + number: 'DOC-001', + }); + + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn( + (_entity: unknown, payload: Record) => payload + ), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + + (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue( + queryRunner + ); + + await service.create(createDto, mockUser); + + expect(queryRunner.manager.create).toHaveBeenCalledWith( + CorrespondenceRevision, + expect.objectContaining({ revisionLabel: 'A' }) + ); + }); + + it('should set revisionLabel to null for LETTER type', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: 10, + } as unknown as User; + + const createDto: CreateCorrespondenceDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + + const typeRepo = testingModule.get>( + getRepositoryToken(CorrespondenceType) + ); + const statusRepo = testingModule.get>( + getRepositoryToken(CorrespondenceStatus) + ); + const uuidResolver = + testingModule.get(UuidResolverService); + + (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100); + (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20); + + (typeRepo.findOne as jest.Mock).mockResolvedValue({ + id: 1, + typeCode: 'LETTER', + }); + (statusRepo.findOne as jest.Mock).mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + + (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({ + number: 'DOC-001', + }); + + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn( + (_entity: unknown, payload: Record) => payload + ), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + + (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue( + queryRunner + ); + + await service.create(createDto, mockUser); + + expect(queryRunner.manager.create).toHaveBeenCalledWith( + CorrespondenceRevision, + expect.objectContaining({ revisionLabel: null }) + ); + }); + + it('should set revisionLabel to null for MEMO type', async () => { + const mockUser = { + user_id: 1, + primaryOrganizationId: 10, + } as unknown as User; + + const createDto: CreateCorrespondenceDto = { + projectId: 'project-uuid', + typeId: 1, + subject: 'Test Subject', + recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }], + }; + + const typeRepo = testingModule.get>( + getRepositoryToken(CorrespondenceType) + ); + const statusRepo = testingModule.get>( + getRepositoryToken(CorrespondenceStatus) + ); + const uuidResolver = + testingModule.get(UuidResolverService); + + (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100); + (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20); + + (typeRepo.findOne as jest.Mock).mockResolvedValue({ + id: 1, + typeCode: 'MEMO', + }); + (statusRepo.findOne as jest.Mock).mockResolvedValue({ + id: 1, + statusCode: 'DRAFT', + }); + + (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({ + number: 'DOC-001', + }); + + mockDataSource.manager.findOne + .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' }) + .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' }); + + const queryRunner = { + connect: jest.fn(), + startTransaction: jest.fn(), + commitTransaction: jest.fn(), + rollbackTransaction: jest.fn(), + release: jest.fn(), + manager: { + create: jest.fn( + (_entity: unknown, payload: Record) => payload + ), + save: jest + .fn() + .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' }) + .mockResolvedValueOnce({ id: 1000 }) + .mockResolvedValueOnce([]), + findOne: jest.fn(), + }, + }; + + (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue( + queryRunner + ); + + await service.create(createDto, mockUser); + + expect(queryRunner.manager.create).toHaveBeenCalledWith( + CorrespondenceRevision, + expect.objectContaining({ revisionLabel: null }) + ); + }); }); }); diff --git a/backend/src/modules/correspondence/correspondence.service.ts b/backend/src/modules/correspondence/correspondence.service.ts index 7955c25..83384d5 100644 --- a/backend/src/modules/correspondence/correspondence.service.ts +++ b/backend/src/modules/correspondence/correspondence.service.ts @@ -55,6 +55,19 @@ export class CorrespondenceService { return permissions.includes('system.manage_all'); } + /** + * Business Rule: Revision Label Strategy + * - RFA, RFI: Use alphabet starting with 'A' (A, B, C...) + * - Other types (LETTER, MEMO, etc.): Use numeric (null for first, then 1, 2, 3...) + */ + private getInitialRevisionLabel(typeCode: string): string | null { + const alphabetTypes = ['RFA', 'RFI']; + if (alphabetTypes.includes(typeCode.toUpperCase())) { + return 'A'; // Alphabet for RFA, RFI + } + return null; // Numeric (null for revision 0) + } + constructor( @InjectRepository(Correspondence) private correspondenceRepo: Repository, @@ -288,7 +301,7 @@ export class CorrespondenceService { const revision = queryRunner.manager.create(CorrespondenceRevision, { correspondenceId: savedCorr.id, revisionNumber: 0, - revisionLabel: 'A', + revisionLabel: this.getInitialRevisionLabel(type.typeCode), isCurrent: true, statusId: statusDraft.id, subject: createDto.subject, diff --git a/specs/01-requirements/01-03-modules/01-03-02-correspondence.md b/specs/01-requirements/01-03-modules/01-03-02-correspondence.md index b333aa5..1293cbf 100644 --- a/specs/01-requirements/01-03-modules/01-03-02-correspondence.md +++ b/specs/01-requirements/01-03-modules/01-03-02-correspondence.md @@ -146,8 +146,14 @@ related: - 1 Correspondence Master → หลาย Revision (1:N) - `is_current = TRUE` มีได้เพียง 1 แถวต่อ correspondence (UNIQUE constraint) -- `revision_label`: A, B, C, ... (หรือ 1.1, 1.2 แล้วแต่ type) - `revision_number`: 0-based integer สำหรับ sorting +- `revision_label`: กำหนดตามประเภทเอกสารดังนี้: + | Type | Initial Label | ลำดับถัดไป | Format | + |------|--------------|------------|--------| + | **RFA, RFI** | `A` | B, C, D... | Alphabet | + | **LETTER, MEMO, TRANSMITTAL, EMAIL, INSTRUCTION, NOTICE, MOM, OTHER** | `null` | 1, 2, 3... | Numeric | + +**หมายเหตุ:** Shop Drawing และ As-Built Drawing ใช้ revision label แยกตามกฎของ Drawing Module (numeric '0', '1', '2'... หรือ user กำหนดเอง) ---