From 2d9bbdbfa468b26f6881299e3dccece675f340d9 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 30 Mar 2026 14:24:18 +0700 Subject: [PATCH] 260330:1424 Addied correspondence_revieion_attcahments table table #03 --- ...ceservice_aa616b6e2768e82b10627448176b8243 | 922 ++++++++++++++++++ ...rvice_aa616b6e2768e82b10627448176b8243.map | 1 + ...c4f4e1366-da39a3ee5e6b4b0d3255bfef95601890 | 2 +- .../correspondence/correspondence.service.ts | 4 + frontend/components/correspondences/form.tsx | 7 +- frontend/types/correspondence.ts | 9 + 6 files changed, 942 insertions(+), 3 deletions(-) create mode 100644 backend/src/.jest-cache/jest-transform-cache-51fed4c0665a260afb7eef9c4f4e1366-12533232bd0f05f65688e7a7764bf3fb/aa/correspondenceservice_aa616b6e2768e82b10627448176b8243 create mode 100644 backend/src/.jest-cache/jest-transform-cache-51fed4c0665a260afb7eef9c4f4e1366-12533232bd0f05f65688e7a7764bf3fb/aa/correspondenceservice_aa616b6e2768e82b10627448176b8243.map diff --git a/backend/src/.jest-cache/jest-transform-cache-51fed4c0665a260afb7eef9c4f4e1366-12533232bd0f05f65688e7a7764bf3fb/aa/correspondenceservice_aa616b6e2768e82b10627448176b8243 b/backend/src/.jest-cache/jest-transform-cache-51fed4c0665a260afb7eef9c4f4e1366-12533232bd0f05f65688e7a7764bf3fb/aa/correspondenceservice_aa616b6e2768e82b10627448176b8243 new file mode 100644 index 0000000..23347f3 --- /dev/null +++ b/backend/src/.jest-cache/jest-transform-cache-51fed4c0665a260afb7eef9c4f4e1366-12533232bd0f05f65688e7a7764bf3fb/aa/correspondenceservice_aa616b6e2768e82b10627448176b8243 @@ -0,0 +1,922 @@ +544230ec4f93cf2a8789f24473b31124 +"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, _r; +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"); +const correspondence_revision_attachment_entity_1 = require("./entities/correspondence-revision-attachment.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 undefined; // Numeric (no label for revision 0) + } + constructor(correspondenceRepo, revisionRepo, typeRepo, statusRepo, referenceRepo, tagRepo, numberingService, jsonSchemaService, workflowEngine, userService, dataSource, searchService, fileStorageService, uuidResolver, notificationService, revAttachRepo) { + 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.revAttachRepo = revAttachRepo; + 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; + // [FIX v1.8.1] commit ได้ Attachment records กลับมา → บันทึก junction + const committed = await this.fileStorageService.commit(createDto.attachmentTempIds, { issueDate, documentType: 'Correspondence' }); + if (committed.length > 0) { + const links = committed.map((att, idx) => queryRunner.manager.create(correspondence_revision_attachment_entity_1.CorrespondenceRevisionAttachment, { + correspondenceRevisionId: revision.id, + attachmentId: att.id, + isMainDocument: idx === 0, // ไฟล์แรกเป็น main document + })); + await queryRunner.manager.save(correspondence_revision_attachment_entity_1.CorrespondenceRevisionAttachment, links); + } + } + 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 + 'discipline', + 'discipline.contract', + ], + }); + 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', + 'revisions.attachmentLinks', // [FIX v1.8.1] โหลด junction + 'revisions.attachmentLinks.attachment', // [FIX v1.8.1] โหลด attachment จริง + 'type', + 'project', + 'originator', + 'recipients', + 'recipients.recipientOrganization', + 'discipline', + 'discipline.contract', + ], + }); + 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') { + const permissions = await this.userService.getUserPermissions(user.user_id); + const canEditSubmittedOrLater = permissions.includes('correspondence.cancel') || + permissions.includes('system.manage_all'); + if (!canEditSubmittedOrLater) { + throw new common_1.ForbiddenException('Only Org Admin or Superadmin can edit non-draft correspondences'); + } + } + } + // 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; + // [FIX v1.8.1] commit ได้ Attachment records กลับมา → บันทึก junction + const committed = await this.fileStorageService.commit(updateDto.attachmentTempIds, { + issueDate: issueDate ? new Date(issueDate) : undefined, + documentType: 'Correspondence', + }); + if (committed.length > 0) { + const links = committed.map((att) => this.revAttachRepo.create({ + correspondenceRevisionId: revision.id, + attachmentId: att.id, + isMainDocument: false, // ไฟล์ที่ upload เพิ่มเติมไม่ใช่ main + })); + await this.revAttachRepo.save(links); + } + } + // 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)), + __param(15, (0, typeorm_1.InjectRepository)(correspondence_revision_attachment_entity_1.CorrespondenceRevisionAttachment)), + __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, typeof (_r = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _r : Object]) +], CorrespondenceService); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJmaWxlIjoiRDpcXG5hcC1kbXMubGNicDNcXGJhY2tlbmRcXHNyY1xcbW9kdWxlc1xcY29ycmVzcG9uZGVuY2VcXGNvcnJlc3BvbmRlbmNlLnNlcnZpY2UudHMiLCJtYXBwaW5ncyI6IjtBQUFBLDZEQUE2RDs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFN0QsMkNBT3dCO0FBQ3hCLDZDQUFtRDtBQUNuRCxxQ0FBaUQ7QUFFakQsV0FBVztBQUNYLDRFQUFrRTtBQUNsRSw4RkFBbUY7QUFDbkYsc0ZBQTJFO0FBQzNFLDBGQUErRTtBQUMvRSxnR0FBcUY7QUFDckYsZ0dBQXFGO0FBQ3JGLG9GQUF5RTtBQUN6RSw4REFBb0Q7QUFFcEQsc0ZBQTRFO0FBQzVFLG9IQUF3RztBQVF4RyxXQUFXO0FBQ1gsMEdBQXFHO0FBQ3JHLDRFQUF1RTtBQUN2RSx3RkFBbUY7QUFDbkYsdURBQW1EO0FBQ25ELDZEQUF5RDtBQUN6RCx5RkFBb0Y7QUFDcEYsdUZBQWtGO0FBQ2xGLCtFQUEyRTtBQVVwRSxJQUFNLHFCQUFxQiw2QkFBM0IsTUFBTSxxQkFBcUI7SUFHeEIsS0FBSyxDQUFDLDRCQUE0QixDQUFDLE1BQWM7UUFDdkQsTUFBTSxXQUFXLEdBQUcsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLGtCQUFrQixDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3RFLE9BQU8sV0FBVyxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFRDs7OztPQUlHO0lBQ0ssdUJBQXVCLENBQUMsUUFBZ0I7UUFDOUMsTUFBTSxhQUFhLEdBQUcsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDckMsSUFBSSxhQUFhLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDbkQsT0FBTyxHQUFHLENBQUMsQ0FBQyx3QkFBd0I7UUFDdEMsQ0FBQztRQUNELE9BQU8sU0FBUyxDQUFDLENBQUMsb0NBQW9DO0lBQ3hELENBQUM7SUFFRCxZQUVFLGtCQUFzRCxFQUV0RCxZQUF3RCxF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QW1CLG9CQUFuQiwwQ0FBbUIsb0RBRXpCLG9CQUFVLG9CQUFWLG9CQUFVO0dBNUN4QixxQkFBcUIsQ0FvbUNqQyIsIm5hbWVzIjpbXSwic291cmNlcyI6WyJEOlxcbmFwLWRtcy5sY2JwM1xcYmFja2VuZFxcc3JjXFxtb2R1bGVzXFxjb3JyZXNwb25kZW5jZVxcY29ycmVzcG9uZGVuY2Uuc2VydmljZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBGaWxlOiBzcmMvbW9kdWxlcy9jb3JyZXNwb25kZW5jZS9jb3JyZXNwb25kZW5jZS5zZXJ2aWNlLnRzXHJcblxyXG5pbXBvcnQge1xyXG4gIEluamVjdGFibGUsXHJcbiAgTm90Rm91bmRFeGNlcHRpb24sXHJcbiAgQmFkUmVxdWVzdEV4Y2VwdGlvbixcclxuICBJbnRlcm5hbFNlcnZlckVycm9yRXhjZXB0aW9uLFxyXG4gIEZvcmJpZGRlbkV4Y2VwdGlvbixcclxuICBMb2dnZXIsXHJcbn0gZnJvbSAnQG5lc3Rqcy9jb21tb24nO1xyXG5pbXBvcnQgeyBJbmplY3RSZXBvc2l0b3J5IH0gZnJvbSAnQG5lc3Rqcy90eXBlb3JtJztcclxuaW1wb3J0IHsgUmVwb3NpdG9yeSwgRGF0YVNvdXJjZSB9IGZyb20gJ3R5cGVvcm0nO1xyXG5cclxuLy8gRW50aXRpZXNcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2UgfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlUmV2aXNpb24gfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLXJldmlzaW9uLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlVHlwZSB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2UtdHlwZS5lbnRpdHknO1xyXG5pbXBvcnQgeyBDb3JyZXNwb25kZW5jZVN0YXR1cyB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2Utc3RhdHVzLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlUmVmZXJlbmNlIH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS1yZWZlcmVuY2UuZW50aXR5JztcclxuaW1wb3J0IHsgQ29ycmVzcG9uZGVuY2VSZWNpcGllbnQgfSBmcm9tICcuL2VudGl0aWVzL2NvcnJlc3BvbmRlbmNlLXJlY2lwaWVudC5lbnRpdHknO1xyXG5pbXBvcnQgeyBDb3JyZXNwb25kZW5jZVRhZyB9IGZyb20gJy4vZW50aXRpZXMvY29ycmVzcG9uZGVuY2UtdGFnLmVudGl0eSc7XHJcbmltcG9ydCB7IFRhZyB9IGZyb20gJy4uL21hc3Rlci9lbnRpdGllcy90YWcuZW50aXR5JztcclxuaW1wb3J0IHsgVXNlciB9IGZyb20gJy4uL3VzZXIvZW50aXRpZXMvdXNlci5lbnRpdHknO1xyXG5pbXBvcnQgeyBPcmdhbml6YXRpb24gfSBmcm9tICcuLi9vcmdhbml6YXRpb24vZW50aXRpZXMvb3JnYW5pemF0aW9uLmVudGl0eSc7XHJcbmltcG9ydCB7IENvcnJlc3BvbmRlbmNlUmV2aXNpb25BdHRhY2htZW50IH0gZnJvbSAnLi9lbnRpdGllcy9jb3JyZXNwb25kZW5jZS1yZXZpc2lvbi1hdHRhY2htZW50LmVudGl0eSc7XHJcblxyXG4vLyBEVE9zXHJcbmltcG9ydCB7IENyZWF0ZUNvcnJlc3BvbmRlbmNlRHRvIH0gZnJvbSAnLi9kdG8vY3JlYXRlLWNvcnJlc3BvbmRlbmNlLmR0byc7XHJcbmltcG9ydCB7IFVwZGF0ZUNvcnJlc3BvbmRlbmNlRHRvIH0gZnJvbSAnLi9kdG8vdXBkYXRlLWNvcnJlc3BvbmRlbmNlLmR0byc7XHJcbmltcG9ydCB7IEFkZFJlZmVyZW5jZUR0byB9IGZyb20gJy4vZHRvL2FkZC1yZWZlcmVuY2UuZHRvJztcclxuaW1wb3J0IHsgU2VhcmNoQ29ycmVzcG9uZGVuY2VEdG8gfSBmcm9tICcuL2R0by9zZWFyY2gtY29ycmVzcG9uZGVuY2UuZHRvJztcclxuXHJcbi8vIFNlcnZpY2VzXHJcbmltcG9ydCB7IERvY3VtZW50TnVtYmVyaW5nU2VydmljZSB9IGZyb20gJy4uL2RvY3VtZW50LW51bWJlcmluZy9zZXJ2aWNlcy9kb2N1bWVudC1udW1iZXJpbmcuc2VydmljZSc7XHJcbmltcG9ydCB7IEpzb25TY2hlbWFTZXJ2aWNlIH0gZnJvbSAnLi4vanNvbi1zY2hlbWEvanNvbi1zY2hlbWEuc2VydmljZSc7XHJcbmltcG9ydCB7IFdvcmtmbG93RW5naW5lU2VydmljZSB9IGZyb20gJy4uL3dvcmtmbG93LWVuZ2luZS93b3JrZmxvdy1lbmdpbmUuc2VydmljZSc7XHJcbmltcG9ydCB7IFVzZXJTZXJ2aWNlIH0gZnJvbSAnLi4vdXNlci91c2VyLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBTZWFyY2hTZXJ2aWNlIH0gZnJvbSAnLi4vc2VhcmNoL3NlYXJjaC5zZXJ2aWNlJztcclxuaW1wb3J0IHsgRmlsZVN0b3JhZ2VTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vY29tbW9uL2ZpbGUtc3RvcmFnZS9maWxlLXN0b3JhZ2Uuc2VydmljZSc7XHJcbmltcG9ydCB7IFV1aWRSZXNvbHZlclNlcnZpY2UgfSBmcm9tICcuLi8uLi9jb21tb24vc2VydmljZXMvdXVpZC1yZXNvbHZlci5zZXJ2aWNlJztcclxuaW1wb3J0IHsgTm90aWZpY2F0aW9uU2VydmljZSB9IGZyb20gJy4uL25vdGlmaWNhdGlvbi9ub3RpZmljYXRpb24uc2VydmljZSc7XHJcblxyXG4vKipcclxuICogQ29ycmVzcG9uZGVuY2VTZXJ2aWNlIC0gRG9jdW1lbnQgbWFuYWdlbWVudCAoQ1JVRClcclxuICovXHJcbmludGVyZmFjZSBSZXNvbHZlZFJlY2lwaWVudCB7XHJcbiAgb3JnYW5pemF0aW9uSWQ6IG51bWJlcjtcclxuICB0eXBlOiAnVE8nIHwgJ0NDJztcclxufVxyXG5ASW5qZWN0YWJsZSgpXHJcbmV4cG9ydCBjbGFzcyBDb3JyZXNwb25kZW5jZVNlcnZpY2Uge1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgbG9nZ2VyID0gbmV3IExvZ2dlcihDb3JyZXNwb25kZW5jZVNlcnZpY2UubmFtZSk7XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgaGFzU3lzdGVtTWFuYWdlQWxsUGVybWlzc2lvbih1c2VySWQ6IG51bWJlcik6IFByb21pc2U8Ym9vbGVhbj4ge1xyXG4gICAgY29uc3QgcGVybWlzc2lvbnMgPSBhd2FpdCB0aGlzLnVzZXJTZXJ2aWNlLmdldFVzZXJQZXJtaXNzaW9ucyh1c2VySWQpO1xyXG4gICAgcmV0dXJuIHBlcm1pc3Npb25zLmluY2x1ZGVzKCdzeXN0ZW0ubWFuYWdlX2FsbCcpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQnVzaW5lc3MgUnVsZTogUmV2aXNpb24gTGFiZWwgU3RyYXRlZ3lcclxuICAgKiAtIFJGQSwgUkZJOiBVc2UgYWxwaGFiZXQgc3RhcnRpbmcgd2l0aCAnQScgKEEsIEIsIEMuLi4pXHJcbiAgICogLSBPdGhlciB0eXBlcyAoTEVUVEVSLCBNRU1PLCBldGMuKTogVXNlIG51bWVyaWMgKG51bGwgZm9yIGZpcnN0LCB0aGVuIDEsIDIsIDMuLi4pXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXRJbml0aWFsUmV2aXNpb25MYWJlbCh0eXBlQ29kZTogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcclxuICAgIGNvbnN0IGFscGhhYmV0VHlwZXMgPSBbJ1JGQScsICdSRkknXTtcclxuICAgIGlmIChhbHBoYWJldFR5cGVzLmluY2x1ZGVzKHR5cGVDb2RlLnRvVXBwZXJDYXNlKCkpKSB7XHJcbiAgICAgIHJldHVybiAnQSc7IC8vIEFscGhhYmV0IGZvciBSRkEsIFJGSVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIHVuZGVmaW5lZDsgLy8gTnVtZXJpYyAobm8gbGFiZWwgZm9yIHJldmlzaW9uIDApXHJcbiAgfVxyXG5cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIEBJbmplY3RSZXBvc2l0b3J5KENvcnJlc3BvbmRlbmNlKVxyXG4gICAgcHJpdmF0ZSBjb3JyZXNwb25kZW5jZVJlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2U+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VSZXZpc2lvbilcclxuICAgIHByaXZhdGUgcmV2aXNpb25SZXBvOiBSZXBvc2l0b3J5PENvcnJlc3BvbmRlbmNlUmV2aXNpb24+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VUeXBlKVxyXG4gICAgcHJpdmF0ZSB0eXBlUmVwbzogUmVwb3NpdG9yeTxDb3JyZXNwb25kZW5jZVR5cGU+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VTdGF0dXMpXHJcbiAgICBwcml2YXRlIHN0YXR1c1JlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VTdGF0dXM+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VSZWZlcmVuY2UpXHJcbiAgICBwcml2YXRlIHJlZmVyZW5jZVJlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VSZWZlcmVuY2U+LFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VUYWcpXHJcbiAgICBwcml2YXRlIHRhZ1JlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VUYWc+LFxyXG4gICAgcHJpdmF0ZSBudW1iZXJpbmdTZXJ2aWNlOiBEb2N1bWVudE51bWJlcmluZ1NlcnZpY2UsXHJcbiAgICBwcml2YXRlIGpzb25TY2hlbWFTZXJ2aWNlOiBKc29uU2NoZW1hU2VydmljZSxcclxuICAgIHByaXZhdGUgd29ya2Zsb3dFbmdpbmU6IFdvcmtmbG93RW5naW5lU2VydmljZSxcclxuICAgIHByaXZhdGUgdXNlclNlcnZpY2U6IFVzZXJTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBkYXRhU291cmNlOiBEYXRhU291cmNlLFxyXG4gICAgcHJpdmF0ZSBzZWFyY2hTZXJ2aWNlOiBTZWFyY2hTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBmaWxlU3RvcmFnZVNlcnZpY2U6IEZpbGVTdG9yYWdlU2VydmljZSxcclxuICAgIHByaXZhdGUgdXVpZFJlc29sdmVyOiBVdWlkUmVzb2x2ZXJTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBub3RpZmljYXRpb25TZXJ2aWNlOiBOb3RpZmljYXRpb25TZXJ2aWNlLFxyXG4gICAgQEluamVjdFJlcG9zaXRvcnkoQ29ycmVzcG9uZGVuY2VSZXZpc2lvbkF0dGFjaG1lbnQpXHJcbiAgICBwcml2YXRlIHJldkF0dGFjaFJlcG86IFJlcG9zaXRvcnk8Q29ycmVzcG9uZGVuY2VSZXZpc2lvbkF0dGFjaG1lbnQ+XHJcbiAgKSB7fVxyXG5cclxuICAvKipcclxuICAgKiBCdXNpbmVzcyBSdWxlIFZhbGlkYXRpb246IEVDLUNPUlItMDAzIC0gQ29ycmVzcG9uZGVuY2UgdG8gU2VsZlxyXG4gICAqIFByZXZlbnQgZXh0ZXJuYWwgY29ycmVzcG9uZGVuY2UgdG8gc2FtZSBvcmdhbml6YXRpb25cclxuICAgKi9cclxuICBwcml2YXRlIGFzeW5jIHZhbGlkYXRlQ29ycmVzcG9uZGVuY2VSZWNpcGllbnRzKFxyXG4gICAgY3JlYXRlRHRvOiBDcmVhdGVDb3JyZXNwb25kZW5jZUR0byxcclxuICAgIHVzZXI6IFVzZXJcclxuICApOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIC8vIEdldCB1c2VyJ3Mgb3JnYW5pemF0aW9uXHJcbiAgICBsZXQgdXNlck9yZ0lkID0gdXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcbiAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICBjb25zdCBmdWxsVXNlciA9IGF3YWl0IHRoaXMudXNlclNlcnZpY2UuZmluZE9uZSh1c2VyLnVzZXJfaWQpO1xyXG4gICAgICBpZiAoZnVsbFVzZXIpIHtcclxuICAgICAgICB1c2VyT3JnSWQgPSBmdWxsVXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICBpZiAoY3JlYXRlRHRvLm9yaWdpbmF0b3JJZCkge1xyXG4gICAgICAgIGNvbnN0IGNhbk1hbmFnZUFsbCA9IGF3YWl0IHRoaXMuaGFzU3lzdGVtTWFuYWdlQWxsUGVybWlzc2lvbihcclxuICAgICAgICAgIHVzZXIudXNlcl9pZFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgaWYgKGNhbk1hbmFnZUFsbCkge1xyXG4gICAgICAgICAgdXNlck9yZ0lkID0gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKFxyXG4gICAgICAgICAgICBjcmVhdGVEdG8ub3JpZ2luYXRvcklkXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKCF1c2VyT3JnSWQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgQmFkUmVxdWVzdEV4Y2VwdGlvbihcclxuICAgICAgICAgICdVc2VyIG11c3QgYmVsb25nIHRvIGFuIG9yZ2FuaXphdGlvbiB0byBjcmVhdGUgZG9jdW1lbnRzJ1xyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBGb3IgaW1wZXJzb25hdGlvbiwgdXNlIHRoZSBzcGVjaWZpZWQgb3JpZ2luYXRvclxyXG4gICAgY29uc3Qgb3JpZ2luYXRvck9yZ0lkID0gY3JlYXRlRHRvLm9yaWdpbmF0b3JJZFxyXG4gICAgICA/IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZChjcmVhdGVEdG8ub3JpZ2luYXRvcklkKVxyXG4gICAgICA6IHVzZXJPcmdJZDtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGludGVybmFsIGNvbW11bmljYXRpb25cclxuICAgIGlmIChjcmVhdGVEdG8uaXNJbnRlcm5hbCkge1xyXG4gICAgICAvLyBJbnRlcm5hbCBjb21tdW5pY2F0aW9ucyBzaG91bGQgdXNlIENpcmN1bGF0aW9uIGluc3RlYWRcclxuICAgICAgdGhyb3cgbmV3IEJhZFJlcXVlc3RFeGNlcHRpb24oXHJcbiAgICAgICAgJ0ludGVybmFsIGNvbW11bmljYXRpb25zIHNob3VsZCB1c2UgQ2lyY3VsYXRpb24gU2hlZXQgaW5zdGVhZCBvZiBDb3JyZXNwb25kZW5jZSdcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBWYWxpZGF0ZSByZWNpcGllbnRzXHJcbiAgICBpZiAoIWNyZWF0ZUR0by5yZWNpcGllbnRzIHx8IGNyZWF0ZUR0by5yZWNpcGllbnRzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICB0aHJvdyBuZXcgQmFkUmVxdWVzdEV4Y2VwdGlvbihcclxuICAgICAgICAnQXQgbGVhc3Qgb25lIHJlY2lwaWVudCAoVE8gb3IgQ0MpIGlzIHJlcXVpcmVkJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHRvUmVjaXBpZW50cyA9IGNyZWF0ZUR0by5yZWNpcGllbnRzLmZpbHRlcigocikgPT4gci50eXBlID09PSAnVE8nKTtcclxuICAgIGNvbnN0IGNjUmVjaXBpZW50cyA9IGNyZWF0ZUR0by5yZWNpcGllbnRzLmZpbHRlcigocikgPT4gci50eXBlID09PSAnQ0MnKTtcclxuXHJcbiAgICBpZiAodG9SZWNpcGllbnRzLmxlbmd0aCA9PT0gMCAmJiBjY1JlY2lwaWVudHMubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgIHRocm93IG5ldyBCYWRSZXF1ZXN0RXhjZXB0aW9uKFxyXG4gICAgICAgICdBdCBsZWFzdCBvbmUgVE8gb3IgQ0MgcmVjaXBpZW50IGlzIHJlcXVpcmVkJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGZvciBzYW1lIG9yZ2FuaXphdGlvbiBjb3JyZXNwb25kZW5jZVxyXG4gICAgZm9yIChjb25zdCByZWNpcGllbnQgb2YgY3JlYXRlRHRvLnJlY2lwaWVudHMpIHtcclxuICAgICAgY29uc3QgcmVjaXBpZW50T3JnSWQgPSBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlT3JnYW5pemF0aW9uSWQoXHJcbiAgICAgICAgcmVjaXBpZW50Lm9yZ2FuaXphdGlvbklkXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBpZiAocmVjaXBpZW50T3JnSWQgPT09IG9yaWdpbmF0b3JPcmdJZCkge1xyXG4gICAgICAgIHRocm93IG5ldyBCYWRSZXF1ZXN0RXhjZXB0aW9uKFxyXG4gICAgICAgICAgJ0Nhbm5vdCBzZW5kIGNvcnJlc3BvbmRlbmNlIHRvIHlvdXIgb3duIG9yZ2FuaXphdGlvbi4gVXNlIENpcmN1bGF0aW9uIFNoZWV0IGZvciBpbnRlcm5hbCBjb21tdW5pY2F0aW9uLidcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBhc3luYyBjcmVhdGUoY3JlYXRlRHRvOiBDcmVhdGVDb3JyZXNwb25kZW5jZUR0bywgdXNlcjogVXNlcikge1xyXG4gICAgLy8gQnVzaW5lc3MgUnVsZSBWYWxpZGF0aW9uOiBFQy1DT1JSLTAwMyAtIENvcnJlc3BvbmRlbmNlIHRvIFNlbGZcclxuICAgIGF3YWl0IHRoaXMudmFsaWRhdGVDb3JyZXNwb25kZW5jZVJlY2lwaWVudHMoY3JlYXRlRHRvLCB1c2VyKTtcclxuICAgIC8vIEFEUi0wMTk6IFJlc29sdmUgVVVJRCByZWZlcmVuY2VzIHRvIGludGVybmFsIElOVCBJRHNcclxuICAgIGNvbnN0IHJlc29sdmVkUHJvamVjdElkID0gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZVByb2plY3RJZChcclxuICAgICAgY3JlYXRlRHRvLnByb2plY3RJZFxyXG4gICAgKTtcclxuICAgIGNvbnN0IHJlc29sdmVkT3JpZ2luYXRvcklkID0gY3JlYXRlRHRvLm9yaWdpbmF0b3JJZFxyXG4gICAgICA/IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZChjcmVhdGVEdG8ub3JpZ2luYXRvcklkKVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuICAgIGNvbnN0IHJlc29sdmVkUmVjaXBpZW50cyA9IGNyZWF0ZUR0by5yZWNpcGllbnRzXHJcbiAgICAgID8gYXdhaXQgUHJvbWlzZS5hbGwoXHJcbiAgICAgICAgICBjcmVhdGVEdG8ucmVjaXBpZW50cy5tYXAoXHJcbiAgICAgICAgICAgIGFzeW5jIChyKTogUHJvbWlzZTxSZXNvbHZlZFJlY2lwaWVudD4gPT4gKHtcclxuICAgICAgICAgICAgICBvcmdhbml6YXRpb25JZDogYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKFxyXG4gICAgICAgICAgICAgICAgci5vcmdhbml6YXRpb25JZFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgICAgdHlwZTogci50eXBlLFxyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgIClcclxuICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICBjb25zdCB0eXBlID0gYXdhaXQgdGhpcy50eXBlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgaWQ6IGNyZWF0ZUR0by50eXBlSWQgfSxcclxuICAgIH0pO1xyXG4gICAgaWYgKCF0eXBlKSB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oJ0RvY3VtZW50IFR5cGUgbm90IGZvdW5kJyk7XHJcblxyXG4gICAgY29uc3Qgc3RhdHVzRHJhZnQgPSBhd2FpdCB0aGlzLnN0YXR1c1JlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IHN0YXR1c0NvZGU6ICdEUkFGVCcgfSxcclxuICAgIH0pO1xyXG4gICAgaWYgKCFzdGF0dXNEcmFmdCkge1xyXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxTZXJ2ZXJFcnJvckV4Y2VwdGlvbihcclxuICAgICAgICAnU3RhdHVzIERSQUZUIG5vdCBmb3VuZCBpbiBNYXN0ZXIgRGF0YSdcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgdXNlck9yZ0lkID0gdXNlci5wcmltYXJ5T3JnYW5pemF0aW9uSWQ7XHJcblxyXG4gICAgaWYgKCF1c2VyT3JnSWQpIHtcclxuICAgICAgY29uc3QgZnVsbFVzZXIgPSBhd2FpdCB0aGlzLnVzZXJTZXJ2aWNlLmZpbmRPbmUodXNlci51c2VyX2lkKTtcclxuICAgICAgaWYgKGZ1bGxVc2VyKSB7XHJcbiAgICAgICAgdXNlck9yZ0lkID0gZnVsbFVzZXIucHJpbWFyeU9yZ2FuaXphdGlvbklkO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSW1wZXJzb25hdGlvbiBMb2dpY1xyXG4gICAgaWYgKHJlc29sdmVkT3JpZ2luYXRvcklkICYmIHJlc29sdmVkT3JpZ2luYXRvcklkICE9PSB1c2VyT3JnSWQpIHtcclxuICAgICAgY29uc3QgY2FuTWFuYWdlQWxsID0gYXdhaXQgdGhpcy5oYXNTeXN0ZW1NYW5hZ2VBbGxQZXJtaXNzaW9uKFxyXG4gICAgICAgIHVzZXIudXNlcl9pZFxyXG4gICAgICApO1xyXG4gICAgICBpZiAoIWNhbk1hbmFnZUFsbCkge1xyXG4gICAgICAgIHRocm93IG5ldyBGb3JiaWRkZW5FeGNlcHRpb24oXHJcbiAgICAgICAgICAnWW91IGRvIG5vdCBoYXZlIHBlcm1pc3Npb24gdG8gY3JlYXRlIGRvY3VtZW50cyBvbiBiZWhhbGYgb2Ygb3RoZXIgb3JnYW5pemF0aW9ucy4nXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgICB1c2VyT3JnSWQgPSByZXNvbHZlZE9yaWdpbmF0b3JJZDtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXVzZXJPcmdJZCkge1xyXG4gICAgICB0aHJvdyBuZXcgQmFkUmVxdWVzdEV4Y2VwdGlvbihcclxuICAgICAgICAnVXNlciBtdXN0IGJlbG9uZyB0byBhbiBvcmdhbml6YXRpb24gdG8gY3JlYXRlIGRvY3VtZW50cydcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoY3JlYXRlRHRvLmRldGFpbHMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBhd2FpdCB0aGlzLmpzb25TY2hlbWFTZXJ2aWNlLnZhbGlkYXRlKHR5cGUudHlwZUNvZGUsIGNyZWF0ZUR0by5kZXRhaWxzKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcclxuICAgICAgICB0aGlzLmxvZ2dlci53YXJuKFxyXG4gICAgICAgICAgYFNjaGVtYSB2YWxpZGF0aW9uIHdhcm5pbmcgZm9yICR7dHlwZS50eXBlQ29kZX06ICR7KGVycm9yIGFzIEVycm9yKS5tZXNzYWdlfWBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgcXVlcnlSdW5uZXIgPSB0aGlzLmRhdGFTb3VyY2UuY3JlYXRlUXVlcnlSdW5uZXIoKTtcclxuICAgIGF3YWl0IHF1ZXJ5UnVubmVyLmNvbm5lY3QoKTtcclxuICAgIGF3YWl0IHF1ZXJ5UnVubmVyLnN0YXJ0VHJhbnNhY3Rpb24oKTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBbRml4ICM2XSBGZXRjaCByZWFsIE9SRyBDb2RlIGZyb20gT3JnYW5pemF0aW9uIGVudGl0eVxyXG4gICAgICBjb25zdCBvcmlnaW5hdG9yT3JnID0gYXdhaXQgdGhpcy5kYXRhU291cmNlLm1hbmFnZXIuZmluZE9uZShcclxuICAgICAgICBPcmdhbml6YXRpb24sXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgd2hlcmU6IHsgaWQ6IHVzZXJPcmdJZCB9LFxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICAgICAgY29uc3Qgb3JnQ29kZSA9IG9yaWdpbmF0b3JPcmc/Lm9yZ2FuaXphdGlvbkNvZGUgPz8gJ1VOSyc7XHJcblxyXG4gICAgICAvLyBbdjEuNS4xXSBFeHRyYWN0IHJlY2lwaWVudCBvcmdhbml6YXRpb24gZnJvbSByZWNpcGllbnRzIGFycmF5IChQcmltYXJ5IFRPKVxyXG4gICAgICBjb25zdCB0b1JlY2lwaWVudCA9IHJlc29sdmVkUmVjaXBpZW50cz8uZmluZCgocikgPT4gci50eXBlID09PSAnVE8nKTtcclxuICAgICAgY29uc3QgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQgPSB0b1JlY2lwaWVudD8ub3JnYW5pemF0aW9uSWQ7XHJcblxyXG4gICAgICBsZXQgcmVjaXBpZW50Q29kZSA9ICcnO1xyXG4gICAgICBpZiAocmVjaXBpZW50T3JnYW5pemF0aW9uSWQpIHtcclxuICAgICAgICBjb25zdCByZWNPcmcgPSBhd2FpdCB0aGlzLmRhdGFTb3VyY2UubWFuYWdlci5maW5kT25lKE9yZ2FuaXphdGlvbiwge1xyXG4gICAgICAgICAgd2hlcmU6IHsgaWQ6IHJlY2lwaWVudE9yZ2FuaXphdGlvbklkIH0sXHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgaWYgKHJlY09yZykgcmVjaXBpZW50Q29kZSA9IHJlY09yZy5vcmdhbml6YXRpb25Db2RlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBjb25zdCBkb2NOdW1iZXIgPSBhd2FpdCB0aGlzLm51bWJlcmluZ1NlcnZpY2UuZ2VuZXJhdGVOZXh0TnVtYmVyKHtcclxuICAgICAgICBwcm9qZWN0SWQ6IHJlc29sdmVkUHJvamVjdElkLFxyXG4gICAgICAgIG9yaWdpbmF0b3JPcmdhbml6YXRpb25JZDogdXNlck9yZ0lkLFxyXG4gICAgICAgIHR5cGVJZDogY3JlYXRlRHRvLnR5cGVJZCxcclxuICAgICAgICBkaXNjaXBsaW5lSWQ6IGNyZWF0ZUR0by5kaXNjaXBsaW5lSWQsXHJcbiAgICAgICAgc3ViVHlwZUlkOiBjcmVhdGVEdG8uc3ViVHlwZUlkLFxyXG4gICAgICAgIHJlY2lwaWVudE9yZ2FuaXphdGlvbklkLCAvLyBbdjEuNS4xXSBQYXNzIHJlY2lwaWVudCBmb3IgZG9jdW1lbnQgbnVtYmVyIGZvcm1hdFxyXG4gICAgICAgIHllYXI6IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKSxcclxuICAgICAgICBjdXN0b21Ub2tlbnM6IHtcclxuICAgICAgICAgIFRZUEVfQ09ERTogdHlwZS50eXBlQ29kZSxcclxuICAgICAgICAgIE9SR19DT0RFOiBvcmdDb2RlLFxyXG4gICAgICAgICAgUkVDSVBJRU5UX0NPREU6IHJlY2lwaWVudENvZGUsXHJcbiAgICAgICAgICBSRUNfQ09ERTogcmVjaXBpZW50Q29kZSxcclxuICAgICAgICB9LFxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGNvbnN0IGNvcnJlc3BvbmRlbmNlID0gcXVlcnlSdW5uZXIubWFuYWdlci5jcmVhdGUoQ29ycmVzcG9uZGVuY2UsIHtcclxuICAgICAgICBjb3JyZXNwb25kZW5jZU51bWJlcjogZG9jTnVtYmVyLm51bWJlcixcclxuICAgICAgICBjb3JyZXNwb25kZW5jZVR5cGVJZDogY3JlYXRlRHRvLnR5cGVJZCxcclxuICAgICAgICBkaXNjaXBsaW5lSWQ6IGNyZWF0ZUR0by5kaXNjaXBsaW5lSWQsXHJcbiAgICAgICAgcHJvamVjdElkOiByZXNvbHZlZFByb2plY3RJZCxcclxuICAgICAgICBvcmlnaW5hdG9ySWQ6IHVzZXJPcmdJZCxcclxuICAgICAgICBpc0ludGVybmFsOiBjcmVhdGVEdG8uaXNJbnRlcm5hbCB8fCBmYWxzZSxcclxuICAgICAgICBjcmVhdGVkQnk6IHVzZXIudXNlcl9pZCxcclxuICAgICAgfSk7XHJcbiAgICAgIGNvbnN0IHNhdmVkQ29yciA9IGF3YWl0IHF1ZXJ5UnVubmVyLm1hbmFnZXIuc2F2ZShjb3JyZXNwb25kZW5jZSk7XHJcblxyXG4gICAgICBjb25zdCByZXZpc2lvbiA9IHF1ZXJ5UnVubmVyLm1hbmFnZXIuY3JlYXRlKENvcnJlc3BvbmRlbmNlUmV2aXNpb24sIHtcclxuICAgICAgICBjb3JyZXNwb25kZW5jZUlkOiBzYXZlZENvcnIuaWQsXHJcbiAgICAgICAgcmV2aXNpb25OdW1iZXI6IDAsXHJcbiAgICAgICAgcmV2aXNpb25MYWJlbDogdGhpcy5nZXRJbml0aWFsUmV2aXNpb25MYWJlbCh0eXBlLnR5cGVDb2RlKSxcclxuICAgICAgICBpc0N1cnJlbnQ6IHRydWUsXHJcbiAgICAgICAgc3RhdHVzSWQ6IHN0YXR1c0RyYWZ0LmlkLFxyXG4gICAgICAgIHN1YmplY3Q6IGNyZWF0ZUR0by5zdWJqZWN0LFxyXG4gICAgICAgIGJvZHk6IGNyZWF0ZUR0by5ib2R5LFxyXG4gICAgICAgIHJlbWFya3M6IGNyZWF0ZUR0by5yZW1hcmtzLFxyXG4gICAgICAgIGR1ZURhdGU6IGNyZWF0ZUR0by5kdWVEYXRlID8gbmV3IERhdGUoY3JlYXRlRHRvLmR1ZURhdGUpIDogdW5kZWZpbmVkLFxyXG4gICAgICAgIGRvY3VtZW50RGF0ZTogY3JlYXRlRHRvLmRvY3VtZW50RGF0ZVxyXG4gICAgICAgICAgPyBuZXcgRGF0ZShjcmVhdGVEdG8uZG9jdW1lbnREYXRlKVxyXG4gICAgICAgICAgOiB1bmRlZmluZWQsXHJcbiAgICAgICAgaXNzdWVkRGF0ZTogY3JlYXRlRHRvLmlzc3VlZERhdGVcclxuICAgICAgICAgID8gbmV3IERhdGUoY3JlYXRlRHRvLmlzc3VlZERhdGUpXHJcbiAgICAgICAgICA6IHVuZGVmaW5lZCxcclxuICAgICAgICByZWNlaXZlZERhdGU6IGNyZWF0ZUR0by5yZWNlaXZlZERhdGVcclxuICAgICAgICAgID8gbmV3IERhdGUoY3JlYXRlRHRvLnJlY2VpdmVkRGF0ZSlcclxuICAgICAgICAgIDogdW5kZWZpbmVkLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiBjcmVhdGVEdG8uZGVzY3JpcHRpb24sXHJcbiAgICAgICAgZGV0YWlsczogY3JlYXRlRHRvLmRldGFpbHMsXHJcbiAgICAgICAgY3JlYXRlZEJ5OiB1c2VyLnVzZXJfaWQsXHJcbiAgICAgICAgc2NoZW1hVmVyc2lvbjogMSxcclxuICAgICAgfSk7XHJcbiAgICAgIGF3YWl0IHF1ZXJ5UnVubmVyLm1hbmFnZXIuc2F2ZShyZXZpc2lvbik7XHJcblxyXG4gICAgICAvLyBTYXZlIFJlY2lwaWVudHMgKHVzaW5nIHJlc29sdmVkIElOVCBJRHMpXHJcbiAgICAgIGlmIChyZXNvbHZlZFJlY2lwaWVudHMgJiYgcmVzb2x2ZWRSZWNpcGllbnRzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICBjb25zdCByZWNpcGllbnRzID0gcmVzb2x2ZWRSZWNpcGllbnRzLm1hcCgocikgPT5cclxuICAgICAgICAgIHF1ZXJ5UnVubmVyLm1hbmFnZXIuY3JlYXRlKENvcnJlc3BvbmRlbmNlUmVjaXBpZW50LCB7XHJcbiAgICAgICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IHNhdmVkQ29yci5pZCxcclxuICAgICAgICAgICAgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQ6IHIub3JnYW5pemF0aW9uSWQsXHJcbiAgICAgICAgICAgIHJlY2lwaWVudFR5cGU6IHIudHlwZSxcclxuICAgICAgICAgIH0pXHJcbiAgICAgICAgKTtcclxuICAgICAgICBhd2FpdCBxdWVyeVJ1bm5lci5tYW5hZ2VyLnNhdmUocmVjaXBpZW50cyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENvbW1pdCBhdHRhY2htZW50cyBmcm9tIFRlbXAg4oaSIFBlcm1hbmVudCAoVHdvLVBoYXNlIFN0b3JhZ2UpXHJcbiAgICAgIGlmIChjcmVhdGVEdG8uYXR0YWNobWVudFRlbXBJZHM/Lmxlbmd0aCkge1xyXG4gICAgICAgIGNvbnN0IGlzc3VlRGF0ZSA9IGNyZWF0ZUR0by5pc3N1ZWREYXRlXHJcbiAgICAgICAgICA/IG5ldyBEYXRlKGNyZWF0ZUR0by5pc3N1ZWREYXRlKVxyXG4gICAgICAgICAgOiBjcmVhdGVEdG8uZG9jdW1lbnREYXRlXHJcbiAgICAgICAgICAgID8gbmV3IERhdGUoY3JlYXRlRHRvLmRvY3VtZW50RGF0ZSlcclxuICAgICAgICAgICAgOiB1bmRlZmluZWQ7XHJcblxyXG4gICAgICAgIC8vIFtGSVggdjEuOC4xXSBjb21taXQg4LmE4LiU4LmJIEF0dGFjaG1lbnQgcmVjb3JkcyDguIHguKXguLHguJrguKHguLIg4oaSIOC4muC4seC4meC4l+C4tuC4gSBqdW5jdGlvblxyXG4gICAgICAgIGNvbnN0IGNvbW1pdHRlZCA9IGF3YWl0IHRoaXMuZmlsZVN0b3JhZ2VTZXJ2aWNlLmNvbW1pdChcclxuICAgICAgICAgIGNyZWF0ZUR0by5hdHRhY2htZW50VGVtcElkcyxcclxuICAgICAgICAgIHsgaXNzdWVEYXRlLCBkb2N1bWVudFR5cGU6ICdDb3JyZXNwb25kZW5jZScgfVxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIGlmIChjb21taXR0ZWQubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgY29uc3QgbGlua3MgPSBjb21taXR0ZWQubWFwKChhdHQsIGlkeCkgPT5cclxuICAgICAgICAgICAgcXVlcnlSdW5uZXIubWFuYWdlci5jcmVhdGUoQ29ycmVzcG9uZGVuY2VSZXZpc2lvbkF0dGFjaG1lbnQsIHtcclxuICAgICAgICAgICAgICBjb3JyZXNwb25kZW5jZVJldmlzaW9uSWQ6IHJldmlzaW9uLmlkLFxyXG4gICAgICAgICAgICAgIGF0dGFjaG1lbnRJZDogYXR0LmlkLFxyXG4gICAgICAgICAgICAgIGlzTWFpbkRvY3VtZW50OiBpZHggPT09IDAsIC8vIOC5hOC4n+C4peC5jOC5geC4o+C4geC5gOC4m+C5h+C4mSBtYWluIGRvY3VtZW50XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgYXdhaXQgcXVlcnlSdW5uZXIubWFuYWdlci5zYXZlKFxyXG4gICAgICAgICAgICBDb3JyZXNwb25kZW5jZVJldmlzaW9uQXR0YWNobWVudCxcclxuICAgICAgICAgICAgbGlua3NcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBhd2FpdCBxdWVyeVJ1bm5lci5jb21taXRUcmFuc2FjdGlvbigpO1xyXG5cclxuICAgICAgLy8gU3RhcnQgV29ya2Zsb3cgSW5zdGFuY2UgKG5vbi1ibG9ja2luZylcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCB3b3JrZmxvd0NvZGUgPSBgQ09SUkVTUE9OREVOQ0VfJHt0eXBlLnR5cGVDb2RlfWA7XHJcbiAgICAgICAgYXdhaXQgdGhpcy53b3JrZmxvd0VuZ2luZS5jcmVhdGVJbnN0YW5jZShcclxuICAgICAgICAgIHdvcmtmbG93Q29kZSxcclxuICAgICAgICAgICdjb3JyZXNwb25kZW5jZScsXHJcbiAgICAgICAgICBzYXZlZENvcnIuaWQudG9TdHJpbmcoKSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgcHJvamVjdElkOiByZXNvbHZlZFByb2plY3RJZCxcclxuICAgICAgICAgICAgb3JpZ2luYXRvcklkOiB1c2VyT3JnSWQsXHJcbiAgICAgICAgICAgIGRpc2NpcGxpbmVJZDogY3JlYXRlRHRvLmRpc2NpcGxpbmVJZCxcclxuICAgICAgICAgICAgaW5pdGlhdG9ySWQ6IHVzZXIudXNlcl9pZCxcclxuICAgICAgICAgIH0gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj5cclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xyXG4gICAgICAgIHRoaXMubG9nZ2VyLndhcm4oXHJcbiAgICAgICAgICBgV29ya2Zsb3cgbm90IHN0YXJ0ZWQgZm9yICR7ZG9jTnVtYmVyLm51bWJlcn0gKENvZGU6IENPUlJFU1BPTkRFTkNFXyR7dHlwZS50eXBlQ29kZX0pOiAkeyhlcnJvciBhcyBFcnJvcikubWVzc2FnZX1gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRmlyZS1hbmQtZm9yZ2V0IHNlYXJjaCBpbmRleGluZyAobm9uLWJsb2NraW5nLCB2b2lkIGludGVudGlvbmFsKVxyXG4gICAgICB2b2lkIHRoaXMuc2VhcmNoU2VydmljZS5pbmRleERvY3VtZW50KHtcclxuICAgICAgICBpZDogc2F2ZWRDb3JyLmlkLFxyXG4gICAgICAgIHB1YmxpY0lkOiBzYXZlZENvcnIucHVibGljSWQsXHJcbiAgICAgICAgdHlwZTogJ2NvcnJlc3BvbmRlbmNlJyxcclxuICAgICAgICBkb2NOdW1iZXI6IGRvY051bWJlci5udW1iZXIsXHJcbiAgICAgICAgdGl0bGU6IGNyZWF0ZUR0by5zdWJqZWN0LFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiBjcmVhdGVEdG8uZGVzY3JpcHRpb24sXHJcbiAgICAgICAgc3RhdHVzOiAnRFJBRlQnLFxyXG4gICAgICAgIHByb2plY3RJZDogcmVzb2x2ZWRQcm9qZWN0SWQsXHJcbiAgICAgICAgY3JlYXRlZEF0OiBuZXcgRGF0ZSgpLFxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIHJldHVybiB7XHJcbiAgICAgICAgLi4uc2F2ZWRDb3JyLFxyXG4gICAgICAgIGN1cnJlbnRSZXZpc2lvbjogcmV2aXNpb24sXHJcbiAgICAgIH07XHJcbiAgICB9IGNhdGNoIChlcnIpIHtcclxuICAgICAgYXdhaXQgcXVlcnlSdW5uZXIucm9sbGJhY2tUcmFuc2FjdGlvbigpO1xyXG4gICAgICB0aGlzLmxvZ2dlci5lcnJvcihcclxuICAgICAgICBgRmFpbGVkIHRvIGNyZWF0ZSBjb3JyZXNwb25kZW5jZTogJHsoZXJyIGFzIEVycm9yKS5tZXNzYWdlfWBcclxuICAgICAgKTtcclxuICAgICAgdGhyb3cgZXJyO1xyXG4gICAgfSBmaW5hbGx5IHtcclxuICAgICAgYXdhaXQgcXVlcnlSdW5uZXIucmVsZWFzZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgYXN5bmMgZmluZEFsbChzZWFyY2hEdG86IFNlYXJjaENvcnJlc3BvbmRlbmNlRHRvID0ge30pIHtcclxuICAgIGNvbnN0IHtcclxuICAgICAgc2VhcmNoLFxyXG4gICAgICB0eXBlSWQsXHJcbiAgICAgIHByb2plY3RJZCxcclxuICAgICAgc3RhdHVzSWQsXHJcbiAgICAgIHN0YXR1cyxcclxuICAgICAgcGFnZSA9IDEsXHJcbiAgICAgIGxpbWl0ID0gMTAsXHJcbiAgICB9ID0gc2VhcmNoRHRvO1xyXG4gICAgY29uc3Qgc2tpcCA9IChwYWdlIC0gMSkgKiBsaW1pdDtcclxuXHJcbiAgICAvLyBDaGFuZ2U6IFF1ZXJ5IGZyb20gUmV2aXNpb24gUmVwb1xyXG4gICAgY29uc3QgcXVlcnkgPSB0aGlzLnJldmlzaW9uUmVwb1xyXG4gICAgICAuY3JlYXRlUXVlcnlCdWlsZGVyKCdyZXYnKVxyXG4gICAgICAubGVmdEpvaW5BbmRTZWxlY3QoJ3Jldi5jb3JyZXNwb25kZW5jZScsICdjb3JyJylcclxuICAgICAgLmxlZnRKb2luQW5kU2VsZWN0KCdjb3JyLnR5cGUnLCAndHlwZScpXHJcbiAgICAgIC5sZWZ0Sm9pbkFuZFNlbGVjdCgnY29yci5wcm9qZWN0JywgJ3Byb2plY3QnKVxyXG4gICAgICAubGVmdEpvaW5BbmRTZWxlY3QoJ2NvcnIub3JpZ2luYXRvcicsICdvcmcnKVxyXG4gICAgICAubGVmdEpvaW5BbmRTZWxlY3QoJ3Jldi5zdGF0dXMnLCAnc3RhdHVzJyk7XHJcblxyXG4gICAgLy8gRmlsdGVyIGJ5IFJldmlzaW9uIFN0YXR1c1xyXG4gICAgY29uc3QgcmV2U3RhdHVzID0gc2VhcmNoRHRvLnJldmlzaW9uU3RhdHVzIHx8ICdDVVJSRU5UJztcclxuXHJcbiAgICBpZiAocmV2U3RhdHVzID09PSAnQ1VSUkVOVCcpIHtcclxuICAgICAgcXVlcnkud2hlcmUoJ3Jldi5pc0N1cnJlbnQgPSA6aXNDdXJyZW50JywgeyBpc0N1cnJlbnQ6IHRydWUgfSk7XHJcbiAgICB9IGVsc2UgaWYgKHJldlN0YXR1cyA9PT0gJ09MRCcpIHtcclxuICAgICAgcXVlcnkud2hlcmUoJ3Jldi5pc0N1cnJlbnQgPSA6aXNDdXJyZW50JywgeyBpc0N1cnJlbnQ6IGZhbHNlIH0pO1xyXG4gICAgfVxyXG4gICAgLy8gSWYgJ0FMTCcsIG5vIGZpbHRlciBuZWVkZWQgb24gaXNDdXJyZW50XHJcblxyXG4gICAgaWYgKHByb2plY3RJZCkge1xyXG4gICAgICBxdWVyeS5hbmRXaGVyZSgnY29yci5wcm9qZWN0SWQgPSA6cHJvamVjdElkJywgeyBwcm9qZWN0SWQgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHR5cGVJZCkge1xyXG4gICAgICBxdWVyeS5hbmRXaGVyZSgnY29yci5jb3JyZXNwb25kZW5jZVR5cGVJZCA9IDp0eXBlSWQnLCB7IHR5cGVJZCB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoc3RhdHVzSWQpIHtcclxuICAgICAgcXVlcnkuYW5kV2hlcmUoJ3Jldi5zdGF0dXNJZCA9IDpzdGF0dXNJZCcsIHsgc3RhdHVzSWQgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHN0YXR1cykge1xyXG4gICAgICBxdWVyeS5hbmRXaGVyZSgnc3RhdHVzLnN0YXR1c0NvZGUgPSA6c3RhdHVzJywgeyBzdGF0dXMgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHNlYXJjaCkge1xyXG4gICAgICBxdWVyeS5hbmRXaGVyZShcclxuICAgICAgICAnKGNvcnIuY29ycmVzcG9uZGVuY2VOdW1iZXIgTElLRSA6c2VhcmNoIE9SIHJldi5zdWJqZWN0IExJS0UgOnNlYXJjaCknLFxyXG4gICAgICAgIHsgc2VhcmNoOiBgJSR7c2VhcmNofSVgIH1cclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZWZhdWx0IFNvcnQ6IExhdGVzdCBDcmVhdGVkXHJcbiAgICBxdWVyeS5vcmRlckJ5KCdyZXYuY3JlYXRlZEF0JywgJ0RFU0MnKS5za2lwKHNraXApLnRha2UobGltaXQpO1xyXG5cclxuICAgIGNvbnN0IFtpdGVtcywgdG90YWxdID0gYXdhaXQgcXVlcnkuZ2V0TWFueUFuZENvdW50KCk7XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgZGF0YTogaXRlbXMsXHJcbiAgICAgIG1ldGE6IHtcclxuICAgICAgICB0b3RhbCxcclxuICAgICAgICBwYWdlLFxyXG4gICAgICAgIGxpbWl0LFxyXG4gICAgICAgIHRvdGFsUGFnZXM6IE1hdGguY2VpbCh0b3RhbCAvIGxpbWl0KSxcclxuICAgICAgfSxcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBhc3luYyBmaW5kT25lKGlkOiBudW1iZXIpIHtcclxuICAgIGNvbnN0IGNvcnJlc3BvbmRlbmNlID0gYXdhaXQgdGhpcy5jb3JyZXNwb25kZW5jZVJlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IGlkIH0sXHJcbiAgICAgIHJlbGF0aW9uczogW1xyXG4gICAgICAgICdyZXZpc2lvbnMnLFxyXG4gICAgICAgICdyZXZpc2lvbnMuc3RhdHVzJyxcclxuICAgICAgICAndHlwZScsXHJcbiAgICAgICAgJ3Byb2plY3QnLFxyXG4gICAgICAgICdvcmlnaW5hdG9yJyxcclxuICAgICAgICAncmVjaXBpZW50cycsXHJcbiAgICAgICAgJ3JlY2lwaWVudHMucmVjaXBpZW50T3JnYW5pemF0aW9uJywgLy8gW3YxLjUuMV0gRml4ZWQgcmVsYXRpb24gbmFtZVxyXG4gICAgICAgICdkaXNjaXBsaW5lJyxcclxuICAgICAgICAnZGlzY2lwbGluZS5jb250cmFjdCcsXHJcbiAgICAgIF0sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoIWNvcnJlc3BvbmRlbmNlKSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbihgQ29ycmVzcG9uZGVuY2Ugd2l0aCBJRCAke2lkfSBub3QgZm91bmRgKTtcclxuICAgIH1cclxuICAgIHJldHVybiBjb3JyZXNwb25kZW5jZTtcclxuICB9XHJcblxyXG4gIGFzeW5jIGZpbmRPbmVCeVV1aWQocHVibGljSWQ6IHN0cmluZykge1xyXG4gICAgY29uc3QgY29ycmVzcG9uZGVuY2UgPSBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgcHVibGljSWQgfSxcclxuICAgICAgcmVsYXRpb25zOiBbXHJcbiAgICAgICAgJ3JldmlzaW9ucycsXHJcbiAgICAgICAgJ3JldmlzaW9ucy5zdGF0dXMnLFxyXG4gICAgICAgICdyZXZpc2lvbnMuYXR0YWNobWVudExpbmtzJywgLy8gW0ZJWCB2MS44LjFdIOC5guC4q+C4peC4lCBqdW5jdGlvblxyXG4gICAgICAgICdyZXZpc2lvbnMuYXR0YWNobWVudExpbmtzLmF0dGFjaG1lbnQnLCAvLyBbRklYIHYxLjguMV0g4LmC4Lir4Lil4LiUIGF0dGFjaG1lbnQg4LiI4Lij4Li04LiHXHJcbiAgICAgICAgJ3R5cGUnLFxyXG4gICAgICAgICdwcm9qZWN0JyxcclxuICAgICAgICAnb3JpZ2luYXRvcicsXHJcbiAgICAgICAgJ3JlY2lwaWVudHMnLFxyXG4gICAgICAgICdyZWNpcGllbnRzLnJlY2lwaWVudE9yZ2FuaXphdGlvbicsXHJcbiAgICAgICAgJ2Rpc2NpcGxpbmUnLFxyXG4gICAgICAgICdkaXNjaXBsaW5lLmNvbnRyYWN0JyxcclxuICAgICAgXSxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmICghY29ycmVzcG9uZGVuY2UpIHtcclxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXhjZXB0aW9uKFxyXG4gICAgICAgIGBDb3JyZXNwb25kZW5jZSB3aXRoIFVVSUQgJHtwdWJsaWNJZH0gbm90IGZvdW5kYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGNvcnJlc3BvbmRlbmNlO1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgYWRkUmVmZXJlbmNlKGlkOiBudW1iZXIsIGR0bzogQWRkUmVmZXJlbmNlRHRvKSB7XHJcbiAgICBjb25zdCBzb3VyY2UgPSBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby5maW5kT25lKHsgd2hlcmU6IHsgaWQgfSB9KTtcclxuICAgIC8vIEFEUi0wMTk6IFJlc29sdmUgdGFyZ2V0IHB1YmxpY0lkIOKGkiBpbnRlcm5hbCBJTlQgaWRcclxuICAgIGNvbnN0IHRhcmdldCA9IGF3YWl0IHRoaXMuY29ycmVzcG9uZGVuY2VSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZTogeyBwdWJsaWNJZDogZHRvLnRhcmdldFV1aWQgfSxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmICghc291cmNlIHx8ICF0YXJnZXQpIHtcclxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXhjZXB0aW9uKCdTb3VyY2Ugb3IgVGFyZ2V0IGNvcnJlc3BvbmRlbmNlIG5vdCBmb3VuZCcpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChzb3VyY2UuaWQgPT09IHRhcmdldC5pZCkge1xyXG4gICAgICB0aHJvdyBuZXcgQmFkUmVxdWVzdEV4Y2VwdGlvbignQ2Fubm90IHJlZmVyZW5jZSBzZWxmJyk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgZXhpc3RzID0gYXdhaXQgdGhpcy5yZWZlcmVuY2VSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZToge1xyXG4gICAgICAgIHNvdXJjZUlkOiBpZCxcclxuICAgICAgICB0YXJnZXRJZDogdGFyZ2V0LmlkLFxyXG4gICAgICB9LFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKGV4aXN0cykge1xyXG4gICAgICByZXR1cm4gZXhpc3RzO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHJlZiA9IHRoaXMucmVmZXJlbmNlUmVwby5jcmVhdGUoe1xyXG4gICAgICBzb3VyY2VJZDogaWQsXHJcbiAgICAgIHRhcmdldElkOiB0YXJnZXQuaWQsXHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4gdGhpcy5yZWZlcmVuY2VSZXBvLnNhdmUocmVmKTtcclxuICB9XHJcblxyXG4gIGFzeW5jIHJlbW92ZVJlZmVyZW5jZShpZDogbnVtYmVyLCB0YXJnZXRJZDogbnVtYmVyKSB7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJlZmVyZW5jZVJlcG8uZGVsZXRlKHtcclxuICAgICAgc291cmNlSWQ6IGlkLFxyXG4gICAgICB0YXJnZXRJZDogdGFyZ2V0SWQsXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAocmVzdWx0LmFmZmVjdGVkID09PSAwKSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbignUmVmZXJlbmNlIG5vdCBmb3VuZCcpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgYXN5bmMgZ2V0VGFncyhpZDogbnVtYmVyKSB7XHJcbiAgICBjb25zdCByb3dzID0gYXdhaXQgdGhpcy50YWdSZXBvLmZpbmQoe1xyXG4gICAgICB3aGVyZTogeyBjb3JyZXNwb25kZW5jZUlkOiBpZCB9LFxyXG4gICAgICByZWxhdGlvbnM6IFsndGFnJ10sXHJcbiAgICB9KTtcclxuICAgIHJldHVybiByb3dzLm1hcCgocikgPT4gci50YWcpLmZpbHRlcihCb29sZWFuKTtcclxuICB9XHJcblxyXG4gIGFzeW5jIGFkZFRhZyhpZDogbnVtYmVyLCB0YWdJZDogbnVtYmVyKSB7XHJcbiAgICBjb25zdCBjb3JyZXNwb25kZW5jZSA9IGF3YWl0IHRoaXMuY29ycmVzcG9uZGVuY2VSZXBvLmZpbmRPbmUoe1xyXG4gICAgICB3aGVyZTogeyBpZCB9LFxyXG4gICAgfSk7XHJcbiAgICBpZiAoIWNvcnJlc3BvbmRlbmNlKSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbihgQ29ycmVzcG9uZGVuY2UgJHtpZH0gbm90IGZvdW5kYCk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgdGFnID0gYXdhaXQgdGhpcy5kYXRhU291cmNlLm1hbmFnZXIuZmluZE9uZShUYWcsIHtcclxuICAgICAgd2hlcmU6IHsgaWQ6IHRhZ0lkIH0sXHJcbiAgICB9KTtcclxuICAgIGlmICghdGFnKSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbihgVGFnICR7dGFnSWR9IG5vdCBmb3VuZGApO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGV4aXN0cyA9IGF3YWl0IHRoaXMudGFnUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgY29ycmVzcG9uZGVuY2VJZDogaWQsIHRhZ0lkIH0sXHJcbiAgICB9KTtcclxuICAgIGlmIChleGlzdHMpIHJldHVybiBleGlzdHM7XHJcblxyXG4gICAgY29uc3Qgcm93ID0gdGhpcy50YWdSZXBvLmNyZWF0ZSh7IGNvcnJlc3BvbmRlbmNlSWQ6IGlkLCB0YWdJZCB9KTtcclxuICAgIHJldHVybiB0aGlzLnRhZ1JlcG8uc2F2ZShyb3cpO1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgcmVtb3ZlVGFnKGlkOiBudW1iZXIsIHRhZ0lkOiBudW1iZXIpIHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMudGFnUmVwby5kZWxldGUoeyBjb3JyZXNwb25kZW5jZUlkOiBpZCwgdGFnSWQgfSk7XHJcbiAgICBpZiAocmVzdWx0LmFmZmVjdGVkID09PSAwKSB7XHJcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEV4Y2VwdGlvbignVGFnIGFzc2lnbm1lbnQgbm90IGZvdW5kJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBhc3luYyBnZXRSZWZlcmVuY2VzKGlkOiBudW1iZXIpIHtcclxuICAgIGNvbnN0IG91dGdvaW5nID0gYXdhaXQgdGhpcy5yZWZlcmVuY2VSZXBvLmZpbmQoe1xyXG4gICAgICB3aGVyZTogeyBzb3VyY2VJZDogaWQgfSxcclxuICAgICAgcmVsYXRpb25zOiBbJ3RhcmdldCcsICd0YXJnZXQudHlwZSddLFxyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3QgaW5jb21pbmcgPSBhd2FpdCB0aGlzLnJlZmVyZW5jZVJlcG8uZmluZCh7XHJcbiAgICAgIHdoZXJlOiB7IHRhcmdldElkOiBpZCB9LFxyXG4gICAgICByZWxhdGlvbnM6IFsnc291cmNlJywgJ3NvdXJjZS50eXBlJ10sXHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4geyBvdXRnb2luZywgaW5jb21pbmcgfTtcclxuICB9XHJcblxyXG4gIGFzeW5jIHVwZGF0ZShpZDogbnVtYmVyLCB1cGRhdGVEdG86IFVwZGF0ZUNvcnJlc3BvbmRlbmNlRHRvLCB1c2VyOiBVc2VyKSB7XHJcbiAgICAvLyAxLiBGaW5kIEN1cnJlbnQgUmV2aXNpb25cclxuICAgIGNvbnN0IHJldmlzaW9uID0gYXdhaXQgdGhpcy5yZXZpc2lvblJlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7XHJcbiAgICAgICAgY29ycmVzcG9uZGVuY2VJZDogaWQsXHJcbiAgICAgICAgaXNDdXJyZW50OiB0cnVlLFxyXG4gICAgICB9LFxyXG4gICAgICByZWxhdGlvbnM6IFsnY29ycmVzcG9uZGVuY2UnXSxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmICghcmV2aXNpb24pIHtcclxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXhjZXB0aW9uKFxyXG4gICAgICAgIGBDdXJyZW50IHJldmlzaW9uIGZvciBjb3JyZXNwb25kZW5jZSAke2lkfSBub3QgZm91bmRgXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gMi4gQ2hlY2sgUGVybWlzc2lvblxyXG4gICAgaWYgKHJldmlzaW9uLnN0YXR1c0lkKSB7XHJcbiAgICAgIGNvbnN0IHN0YXR1cyA9IGF3YWl0IHRoaXMuc3RhdHVzUmVwby5maW5kT25lKHtcclxuICAgICAgICB3aGVyZTogeyBpZDogcmV2aXNpb24uc3RhdHVzSWQgfSxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBpZiAoc3RhdHVzICYmIHN0YXR1cy5zdGF0dXNDb2RlICE9PSAnRFJBRlQnKSB7XHJcbiAgICAgICAgY29uc3QgcGVybWlzc2lvbnMgPSBhd2FpdCB0aGlzLnVzZXJTZXJ2aWNlLmdldFVzZXJQZXJtaXNzaW9ucyhcclxuICAgICAgICAgIHVzZXIudXNlcl9pZFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgY29uc3QgY2FuRWRpdFN1Ym1pdHRlZE9yTGF0ZXIgPVxyXG4gICAgICAgICAgcGVybWlzc2lvbnMuaW5jbHVkZXMoJ2NvcnJlc3BvbmRlbmNlLmNhbmNlbCcpIHx8XHJcbiAgICAgICAgICBwZXJtaXNzaW9ucy5pbmNsdWRlcygnc3lzdGVtLm1hbmFnZV9hbGwnKTtcclxuXHJcbiAgICAgICAgaWYgKCFjYW5FZGl0U3VibWl0dGVkT3JMYXRlcikge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IEZvcmJpZGRlbkV4Y2VwdGlvbihcclxuICAgICAgICAgICAgJ09ubHkgT3JnIEFkbWluIG9yIFN1cGVyYWRtaW4gY2FuIGVkaXQgbm9uLWRyYWZ0IGNvcnJlc3BvbmRlbmNlcydcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQURSLTAxOTogUmVzb2x2ZSBVVUlEIHJlZmVyZW5jZXMgaW4gdXBkYXRlIERUT1xyXG4gICAgY29uc3QgdXBkUmVzb2x2ZWRQcm9qZWN0SWQgPSB1cGRhdGVEdG8ucHJvamVjdElkXHJcbiAgICAgID8gYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZVByb2plY3RJZCh1cGRhdGVEdG8ucHJvamVjdElkKVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuICAgIGNvbnN0IHVwZFJlc29sdmVkT3JpZ2luYXRvcklkID0gdXBkYXRlRHRvLm9yaWdpbmF0b3JJZFxyXG4gICAgICA/IGF3YWl0IHRoaXMudXVpZFJlc29sdmVyLnJlc29sdmVPcmdhbml6YXRpb25JZCh1cGRhdGVEdG8ub3JpZ2luYXRvcklkKVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuICAgIGNvbnN0IHVwZFJlc29sdmVkUmVjaXBpZW50cyA9IHVwZGF0ZUR0by5yZWNpcGllbnRzXHJcbiAgICAgID8gYXdhaXQgUHJvbWlzZS5hbGwoXHJcbiAgICAgICAgICB1cGRhdGVEdG8ucmVjaXBpZW50cy5tYXAoXHJcbiAgICAgICAgICAgIGFzeW5jIChyKTogUHJvbWlzZTxSZXNvbHZlZFJlY2lwaWVudD4gPT4gKHtcclxuICAgICAgICAgICAgICBvcmdhbml6YXRpb25JZDogYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKFxyXG4gICAgICAgICAgICAgICAgci5vcmdhbml6YXRpb25JZFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgICAgdHlwZTogci50eXBlLFxyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgIClcclxuICAgICAgOiB1bmRlZmluZWQ7XHJcblxyXG4gICAgLy8gMy4gVXBkYXRlIENvcnJlc3BvbmRlbmNlIEVudGl0eSBpZiBuZWVkZWRcclxuICAgIGNvbnN0IGNvcnJlc3BvbmRlbmNlVXBkYXRlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xyXG4gICAgaWYgKHVwZGF0ZUR0by5kaXNjaXBsaW5lSWQpXHJcbiAgICAgIGNvcnJlc3BvbmRlbmNlVXBkYXRlLmRpc2NpcGxpbmVJZCA9IHVwZGF0ZUR0by5kaXNjaXBsaW5lSWQ7XHJcbiAgICBpZiAodXBkUmVzb2x2ZWRQcm9qZWN0SWQpXHJcbiAgICAgIGNvcnJlc3BvbmRlbmNlVXBkYXRlLnByb2plY3RJZCA9IHVwZFJlc29sdmVkUHJvamVjdElkO1xyXG4gICAgaWYgKHVwZFJlc29sdmVkT3JpZ2luYXRvcklkKVxyXG4gICAgICBjb3JyZXNwb25kZW5jZVVwZGF0ZS5vcmlnaW5hdG9ySWQgPSB1cGRSZXNvbHZlZE9yaWdpbmF0b3JJZDtcclxuXHJcbiAgICBpZiAoT2JqZWN0LmtleXMoY29ycmVzcG9uZGVuY2VVcGRhdGUpLmxlbmd0aCA+IDApIHtcclxuICAgICAgYXdhaXQgdGhpcy5jb3JyZXNwb25kZW5jZVJlcG8udXBkYXRlKGlkLCBjb3JyZXNwb25kZW5jZVVwZGF0ZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gNC4gVXBkYXRlIFJldmlzaW9uIEVudGl0eVxyXG4gICAgY29uc3QgcmV2aXNpb25VcGRhdGU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XHJcbiAgICBpZiAodXBkYXRlRHRvLnN1YmplY3QpIHJldmlzaW9uVXBkYXRlLnN1YmplY3QgPSB1cGRhdGVEdG8uc3ViamVjdDtcclxuICAgIGlmICh1cGRhdGVEdG8uYm9keSkgcmV2aXNpb25VcGRhdGUuYm9keSA9IHVwZGF0ZUR0by5ib2R5O1xyXG4gICAgaWYgKHVwZGF0ZUR0by5yZW1hcmtzKSByZXZpc2lvblVwZGF0ZS5yZW1hcmtzID0gdXBkYXRlRHRvLnJlbWFya3M7XHJcbiAgICAvLyBGb3JtYXQgRGF0ZSBjb3JyZWN0bHkgaWYgc3RyaW5nXHJcbiAgICBpZiAodXBkYXRlRHRvLmR1ZURhdGUpIHJldmlzaW9uVXBkYXRlLmR1ZURhdGUgPSBuZXcgRGF0ZSh1cGRhdGVEdG8uZHVlRGF0ZSk7XHJcbiAgICBpZiAodXBkYXRlRHRvLmRvY3VtZW50RGF0ZSlcclxuICAgICAgcmV2aXNpb25VcGRhdGUuZG9jdW1lbnREYXRlID0gbmV3IERhdGUodXBkYXRlRHRvLmRvY3VtZW50RGF0ZSk7XHJcbiAgICBpZiAodXBkYXRlRHRvLmlzc3VlZERhdGUpXHJcbiAgICAgIHJldmlzaW9uVXBkYXRlLmlzc3VlZERhdGUgPSBuZXcgRGF0ZSh1cGRhdGVEdG8uaXNzdWVkRGF0ZSk7XHJcbiAgICBpZiAodXBkYXRlRHRvLnJlY2VpdmVkRGF0ZSlcclxuICAgICAgcmV2aXNpb25VcGRhdGUucmVjZWl2ZWREYXRlID0gbmV3IERhdGUodXBkYXRlRHRvLnJlY2VpdmVkRGF0ZSk7XHJcbiAgICBpZiAodXBkYXRlRHRvLmRlc2NyaXB0aW9uKVxyXG4gICAgICByZXZpc2lvblVwZGF0ZS5kZXNjcmlwdGlvbiA9IHVwZGF0ZUR0by5kZXNjcmlwdGlvbjtcclxuICAgIGlmICh1cGRhdGVEdG8uZGV0YWlscykgcmV2aXNpb25VcGRhdGUuZGV0YWlscyA9IHVwZGF0ZUR0by5kZXRhaWxzO1xyXG5cclxuICAgIGlmIChPYmplY3Qua2V5cyhyZXZpc2lvblVwZGF0ZSkubGVuZ3RoID4gMCkge1xyXG4gICAgICBhd2FpdCB0aGlzLnJldmlzaW9uUmVwby51cGRhdGUocmV2aXNpb24uaWQsIHJldmlzaW9uVXBkYXRlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyA0LjUgQ29tbWl0IG5ldyBhdHRhY2htZW50cyBmcm9tIFRlbXAg4oaSIFBlcm1hbmVudCAoVHdvLVBoYXNlIFN0b3JhZ2UpXHJcbiAgICBpZiAodXBkYXRlRHRvLmF0dGFjaG1lbnRUZW1wSWRzPy5sZW5ndGgpIHtcclxuICAgICAgY29uc3QgaXNzdWVEYXRlID0gdXBkYXRlRHRvLmlzc3VlZERhdGVcclxuICAgICAgICA/IG5ldyBEYXRlKHVwZGF0ZUR0by5pc3N1ZWREYXRlKVxyXG4gICAgICAgIDogdXBkYXRlRHRvLmRvY3VtZW50RGF0ZVxyXG4gICAgICAgICAgPyBuZXcgRGF0ZSh1cGRhdGVEdG8uZG9jdW1lbnREYXRlKVxyXG4gICAgICAgICAgOiByZXZpc2lvbi5pc3N1ZWREYXRlIHx8IHJldmlzaW9uLmRvY3VtZW50RGF0ZSB8fCB1bmRlZmluZWQ7XHJcblxyXG4gICAgICAvLyBbRklYIHYxLjguMV0gY29tbWl0IOC5hOC4lOC5iSBBdHRhY2htZW50IHJlY29yZHMg4LiB4Lil4Lix4Lia4Lih4LiyIOKGkiDguJrguLHguJnguJfguLbguIEganVuY3Rpb25cclxuICAgICAgY29uc3QgY29tbWl0dGVkID0gYXdhaXQgdGhpcy5maWxlU3RvcmFnZVNlcnZpY2UuY29tbWl0KFxyXG4gICAgICAgIHVwZGF0ZUR0by5hdHRhY2htZW50VGVtcElkcyxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBpc3N1ZURhdGU6IGlzc3VlRGF0ZSA/IG5ldyBEYXRlKGlzc3VlRGF0ZSkgOiB1bmRlZmluZWQsXHJcbiAgICAgICAgICBkb2N1bWVudFR5cGU6ICdDb3JyZXNwb25kZW5jZScsXHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgICAgaWYgKGNvbW1pdHRlZC5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgY29uc3QgbGlua3MgPSBjb21taXR0ZWQubWFwKChhdHQpID0+XHJcbiAgICAgICAgICB0aGlzLnJldkF0dGFjaFJlcG8uY3JlYXRlKHtcclxuICAgICAgICAgICAgY29ycmVzcG9uZGVuY2VSZXZpc2lvbklkOiByZXZpc2lvbi5pZCxcclxuICAgICAgICAgICAgYXR0YWNobWVudElkOiBhdHQuaWQsXHJcbiAgICAgICAgICAgIGlzTWFpbkRvY3VtZW50OiBmYWxzZSwgLy8g4LmE4Lif4Lil4LmM4LiX4Li14LmIIHVwbG9hZCDguYDguJ7guLTguYjguKHguYDguJXguLTguKHguYTguKHguYjguYPguIrguYggbWFpblxyXG4gICAgICAgICAgfSlcclxuICAgICAgICApO1xyXG4gICAgICAgIGF3YWl0IHRoaXMucmV2QXR0YWNoUmVwby5zYXZlKGxpbmtzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIDUuIFVwZGF0ZSBSZWNpcGllbnRzIGlmIHByb3ZpZGVkXHJcbiAgICBpZiAodXBkUmVzb2x2ZWRSZWNpcGllbnRzKSB7XHJcbiAgICAgIGNvbnN0IHJlY2lwaWVudFJlcG8gPSB0aGlzLmRhdGFTb3VyY2UuZ2V0UmVwb3NpdG9yeShcclxuICAgICAgICBDb3JyZXNwb25kZW5jZVJlY2lwaWVudFxyXG4gICAgICApO1xyXG4gICAgICBhd2FpdCByZWNpcGllbnRSZXBvLmRlbGV0ZSh7IGNvcnJlc3BvbmRlbmNlSWQ6IGlkIH0pO1xyXG5cclxuICAgICAgY29uc3QgbmV3UmVjaXBpZW50cyA9IHVwZFJlc29sdmVkUmVjaXBpZW50cy5tYXAoKHIpID0+XHJcbiAgICAgICAgcmVjaXBpZW50UmVwby5jcmVhdGUoe1xyXG4gICAgICAgICAgY29ycmVzcG9uZGVuY2VJZDogaWQsXHJcbiAgICAgICAgICByZWNpcGllbnRPcmdhbml6YXRpb25JZDogci5vcmdhbml6YXRpb25JZCxcclxuICAgICAgICAgIHJlY2lwaWVudFR5cGU6IHIudHlwZSxcclxuICAgICAgICB9KVxyXG4gICAgICApO1xyXG4gICAgICBhd2FpdCByZWNpcGllbnRSZXBvLnNhdmUobmV3UmVjaXBpZW50cyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gNi4gUmVnZW5lcmF0ZSBEb2N1bWVudCBOdW1iZXIgaWYgc3RydWN0dXJhbCBmaWVsZHMgY2hhbmdlZCAoUmVjaXBpZW50LCBEaXNjaXBsaW5lLCBUeXBlLCBQcm9qZWN0KVxyXG4gICAgLy8gQU5EIGl0IGlzIGEgRFJBRlQuXHJcblxyXG4gICAgLy8gRmV0Y2ggZnJlc2ggZGF0YSBmb3IgY29udGV4dCBhbmQgY29tcGFyaXNvblxyXG4gICAgY29uc3QgY3VycmVudENvcnIgPSBhd2FpdCB0aGlzLmNvcnJlc3BvbmRlbmNlUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgaWQgfSxcclxuICAgICAgcmVsYXRpb25zOiBbJ3R5cGUnLCAncmVjaXBpZW50cycsICdyZWNpcGllbnRzLnJlY2lwaWVudE9yZ2FuaXphdGlvbiddLFxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKGN1cnJlbnRDb3JyKSB7XHJcbiAgICAgIGNvbnN0IGN1cnJlbnRUb1JlY2lwaWVudCA9IGN1cnJlbnRDb3JyLnJlY2lwaWVudHM/LmZpbmQoXHJcbiAgICAgICAgKHIpID0+IHIucmVjaXBpZW50VHlwZSA9PT0gJ1RPJ1xyXG4gICAgICApO1xyXG4gICAgICBjb25zdCBjdXJyZW50UmVjaXBpZW50SWQgPSBjdXJyZW50VG9SZWNpcGllbnQ/LnJlY2lwaWVudE9yZ2FuaXphdGlvbklkO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgZm9yIEFDVFVBTCB2YWx1ZSBjaGFuZ2VzXHJcbiAgICAgIGNvbnN0IGlzUHJvamVjdENoYW5nZWQgPVxyXG4gICAgICAgIHVwZFJlc29sdmVkUHJvamVjdElkICE9PSB1bmRlZmluZWQgJiZcclxuICAgICAgICB1cGRSZXNvbHZlZFByb2plY3RJZCAhPT0gY3VycmVudENvcnIucHJvamVjdElkO1xyXG4gICAgICBjb25zdCBpc09yaWdpbmF0b3JDaGFuZ2VkID1cclxuICAgICAgICB1cGRSZXNvbHZlZE9yaWdpbmF0b3JJZCAhPT0gdW5kZWZpbmVkICYmXHJcbiAgICAgICAgdXBkUmVzb2x2ZWRPcmlnaW5hdG9ySWQgIT09IGN1cnJlbnRDb3JyLm9yaWdpbmF0b3JJZDtcclxuICAgICAgY29uc3QgaXNEaXNjaXBsaW5lQ2hhbmdlZCA9XHJcbiAgICAgICAgdXBkYXRlRHRvLmRpc2NpcGxpbmVJZCAhPT0gdW5kZWZpbmVkICYmXHJcbiAgICAgICAgdXBkYXRlRHRvLmRpc2NpcGxpbmVJZCAhPT0gY3VycmVudENvcnIuZGlzY2lwbGluZUlkO1xyXG4gICAgICBjb25zdCBpc1R5cGVDaGFuZ2VkID1cclxuICAgICAgICB1cGRhdGVEdG8udHlwZUlkICE9PSB1bmRlZmluZWQgJiZcclxuICAgICAgICB1cGRhdGVEdG8udHlwZUlkICE9PSBjdXJyZW50Q29yci5jb3JyZXNwb25kZW5jZVR5cGVJZDtcclxuXHJcbiAgICAgIGxldCBpc1JlY2lwaWVudENoYW5nZWQgPSBmYWxzZTtcclxuICAgICAgbGV0IG5ld1JlY2lwaWVudElkOiBudW1iZXIgfCB1bmRlZmluZWQ7XHJcblxyXG4gICAgICBpZiAodXBkUmVzb2x2ZWRSZWNpcGllbnRzKSB7XHJcbiAgICAgICAgY29uc3QgbmV3VG9SZWNpcGllbnQgPSB1cGRSZXNvbHZlZFJlY2lwaWVudHMuZmluZChcclxuICAgICAgICAgIChyKSA9PiByLnR5cGUgPT09ICdUTydcclxuICAgICAgICApO1xyXG4gICAgICAgIG5ld1JlY2lwaWVudElkID0gbmV3VG9SZWNpcGllbnQ/Lm9yZ2FuaXphdGlvbklkO1xyXG5cclxuICAgICAgICBpZiAobmV3UmVjaXBpZW50SWQgIT09IGN1cnJlbnRSZWNpcGllbnRJZCkge1xyXG4gICAgICAgICAgaXNSZWNpcGllbnRDaGFuZ2VkID0gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChcclxuICAgICAgICBpc1Byb2plY3RDaGFuZ2VkIHx8XHJcbiAgICAgICAgaXNEaXNjaXBsaW5lQ2hhbmdlZCB8fFxyXG4gICAgICAgIGlzVHlwZUNoYW5nZWQgfHxcclxuICAgICAgICBpc1JlY2lwaWVudENoYW5nZWQgfHxcclxuICAgICAgICBpc09yaWdpbmF0b3JDaGFuZ2VkXHJcbiAgICAgICkge1xyXG4gICAgICAgIGNvbnN0IHRhcmdldFJlY2lwaWVudElkID0gaXNSZWNpcGllbnRDaGFuZ2VkXHJcbiAgICAgICAgICA/IG5ld1JlY2lwaWVudElkXHJcbiAgICAgICAgICA6IGN1cnJlbnRSZWNpcGllbnRJZDtcclxuXHJcbiAgICAgICAgLy8gUmVzb2x2ZSBSZWNpcGllbnQgQ29kZSBmb3IgdGhlIE5FVyBjb250ZXh0XHJcbiAgICAgICAgbGV0IHJlY2lwaWVudENvZGUgPSAnJztcclxuICAgICAgICBpZiAodGFyZ2V0UmVjaXBpZW50SWQpIHtcclxuICAgICAgICAgIGNvbnN0IHJlY09yZyA9IGF3YWl0IHRoaXMuZGF0YVNvdXJjZS5tYW5hZ2VyLmZpbmRPbmUoT3JnYW5pemF0aW9uLCB7XHJcbiAgICAgICAgICAgIHdoZXJlOiB7IGlkOiB0YXJnZXRSZWNpcGllbnRJZCB9LFxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgICBpZiAocmVjT3JnKSByZWNpcGllbnRDb2RlID0gcmVjT3JnLm9yZ2FuaXphdGlvbkNvZGU7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBbRml4ICM2XSBGZXRjaCByZWFsIE9SRyBDb2RlIGZyb20gb3JpZ2luYXRvciBvcmdhbml6YXRpb25cclxuICAgICAgICBjb25zdCBvcmlnaW5hdG9yT3JnRm9yVXBkYXRlID0gYXdhaXQgdGhpcy5kYXRhU291cmNlLm1hbmFnZXIuZmluZE9uZShcclxuICAgICAgICAgIE9yZ2FuaXphdGlvbixcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgd2hlcmU6IHtcclxuICAgICAgICAgICAgICBpZDogdXBkUmVzb2x2ZWRPcmlnaW5hdG9ySWQgPz8gY3VycmVudENvcnIub3JpZ2luYXRvcklkID8/IDAsXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgKTtcclxuICAgICAgICBjb25zdCBvcmdDb2RlID0gb3JpZ2luYXRvck9yZ0ZvclVwZGF0ZT8ub3JnYW5pemF0aW9uQ29kZSA/PyAnVU5LJztcclxuXHJcbiAgICAgICAgLy8gUHJlcGFyZSBDb250ZXh0c1xyXG4gICAgICAgIGNvbnN0IG9sZEN0eCA9IHtcclxuICAgICAgICAgIHByb2plY3RJZDogY3VycmVudENvcnIucHJvamVjdElkLFxyXG4gICAgICAgICAgb3JpZ2luYXRvck9yZ2FuaXphdGlvbklkOiBjdXJyZW50Q29yci5vcmlnaW5hdG9ySWQgPz8gMCxcclxuICAgICAgICAgIHR5cGVJZDogY3VycmVudENvcnIuY29ycmVzcG9uZGVuY2VUeXBlSWQsXHJcbiAgICAgICAgICBkaXNjaXBsaW5lSWQ6IGN1cnJlbnRDb3JyLmRpc2NpcGxpbmVJZCxcclxuICAgICAgICAgIHJlY2lwaWVudE9yZ2FuaXphdGlvbklkOiBjdXJyZW50UmVjaXBpZW50SWQsXHJcbiAgICAgICAgICB5ZWFyOiBuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCksXHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgY29uc3QgbmV3Q3R4ID0ge1xyXG4gICAgICAgICAgcHJvamVjdElkOiB1cGRSZXNvbHZlZFByb2plY3RJZCA/PyBjdXJyZW50Q29yci5wcm9qZWN0SWQsXHJcbiAgICAgICAgICBvcmlnaW5hdG9yT3JnYW5pemF0aW9uSWQ6XHJcbiAgICAgICAgICAgIHVwZFJlc29sdmVkT3JpZ2luYXRvcklkID8/IGN1cnJlbnRDb3JyLm9yaWdpbmF0b3JJZCA/PyAwLFxyXG4gICAgICAgICAgdHlwZUlkOiB1cGRhdGVEdG8udHlwZUlkID8/IGN1cnJlbnRDb3JyLmNvcnJlc3BvbmRlbmNlVHlwZUlkLFxyXG4gICAgICAgICAgZGlzY2lwbGluZUlkOiB1cGRhdGVEdG8uZGlzY2lwbGluZUlkID8/IGN1cnJlbnRDb3JyLmRpc2NpcGxpbmVJZCxcclxuICAgICAgICAgIHJlY2lwaWVudE9yZ2FuaXphdGlvbklkOiB0YXJnZXRSZWNpcGllbnRJZCxcclxuICAgICAgICAgIHllYXI6IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKSxcclxuICAgICAgICAgIHVzZXJJZDogdXNlci51c2VyX2lkLCAvLyBQYXNzIFVzZXIgSUQgZm9yIEF1ZGl0XHJcbiAgICAgICAgICBjdXN0b21Ub2tlbnM6IHtcclxuICAgICAgICAgICAgVFlQRV9DT0RFOiBjdXJyZW50Q29yci50eXBlPy50eXBlQ29kZSB8fCAnJyxcclxuICAgICAgICAgICAgT1JHX0NPREU6IG9yZ0NvZGUsXHJcbiAgICAgICAgICAgIFJFQ0lQSUVOVF9DT0RFOiByZWNpcGllbnRDb2RlLFxyXG4gICAgICAgICAgICBSRUNfQ09ERTogcmVjaXBpZW50Q29kZSxcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgLy8gSWYgVHlwZSBDaGFuZ2VkLCBuZWVkIE5FVyBUeXBlIENvZGVcclxuICAgICAgICBpZiAoaXNUeXBlQ2hhbmdlZCkge1xyXG4gICAgICAgICAgY29uc3QgbmV3VHlwZSA9IGF3YWl0IHRoaXMudHlwZVJlcG8uZmluZE9uZSh7XHJcbiAgICAgICAgICAgIHdoZXJlOiB7IGlkOiBuZXdDdHgudHlwZUlkIH0sXHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICAgIGlmIChuZXdUeXBlKSBuZXdDdHguY3VzdG9tVG9rZW5zLlRZUEVfQ09ERSA9IG5ld1R5cGUudHlwZUNvZGU7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25zdCBuZXdEb2NOdW1iZXIgPSBhd2FpdCB0aGlzLm51bWJlcmluZ1NlcnZpY2UudXBkYXRlTnVtYmVyRm9yRHJhZnQoXHJcbiAgICAgICAgICBjdXJyZW50Q29yci5jb3JyZXNwb25kZW5jZU51bWJlcixcclxuICAgICAgICAgIG9sZEN0eCxcclxuICAgICAgICAgIG5ld0N0eFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIGF3YWl0IHRoaXMuY29ycmVzcG9uZGVuY2VSZXBvLnVwZGF0ZShpZCwge1xyXG4gICAgICAgICAgY29ycmVzcG9uZGVuY2VOdW1iZXI6IG5ld0RvY051bWJlcixcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHVwZGF0ZWQgPSBhd2FpdCB0aGlzLmZpbmRPbmUoaWQpO1xyXG5cclxuICAgIC8vIFJlLWluZGV4IHVwZGF0ZWQgZG9jdW1lbnQgaW4gRWxhc3RpY3NlYXJjaCAoZmlyZS1hbmQtZm9yZ2V0KVxyXG4gICAgdm9pZCB0aGlzLnNlYXJjaFNlcnZpY2UuaW5kZXhEb2N1bWVudCh7XHJcbiAgICAgIGlkOiB1cGRhdGVkLmlkLFxyXG4gICAgICBwdWJsaWNJZDogdXBkYXRlZC5wdWJsaWNJZCxcclxuICAgICAgdHlwZTogJ2NvcnJlc3BvbmRlbmNlJyxcclxuICAgICAgZG9jTnVtYmVyOiB1cGRhdGVkLmNvcnJlc3BvbmRlbmNlTnVtYmVyLFxyXG4gICAgICB0aXRsZTogdXBkYXRlRHRvLnN1YmplY3QgPz8gdXBkYXRlZC5yZXZpc2lvbnM/LlswXT8uc3ViamVjdCxcclxuICAgICAgZGVzY3JpcHRpb246IHVwZGF0ZUR0by5kZXNjcmlwdGlvbiA/PyB1cGRhdGVkLnJldmlzaW9ucz8uWzBdPy5kZXNjcmlwdGlvbixcclxuICAgICAgc3RhdHVzOiAnRFJBRlQnLFxyXG4gICAgICBwcm9qZWN0SWQ6IHVwZGF0ZWQucHJvamVjdElkLFxyXG4gICAgICBjcmVhdGVkQXQ6IHVwZGF0ZWQuY3JlYXRlZEF0LFxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHVwZGF0ZWQ7XHJcbiAgfVxyXG5cclxuICBhc3luYyBwcmV2aWV3RG9jdW1lbnROdW1iZXIoY3JlYXRlRHRvOiBDcmVhdGVDb3JyZXNwb25kZW5jZUR0bywgdXNlcjogVXNlcikge1xyXG4gICAgLy8gQURSLTAxOTogUmVzb2x2ZSBVVUlEIHJlZmVyZW5jZXNcclxuICAgIGNvbnN0IHByZXZpZXdQcm9qZWN0SWQgPSBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlUHJvamVjdElkKFxyXG4gICAgICBjcmVhdGVEdG8ucHJvamVjdElkXHJcbiAgICApO1xyXG4gICAgY29uc3QgcHJldmlld09yaWdpbmF0b3JJZCA9IGNyZWF0ZUR0by5vcmlnaW5hdG9ySWRcclxuICAgICAgPyBhd2FpdCB0aGlzLnV1aWRSZXNvbHZlci5yZXNvbHZlT3JnYW5pemF0aW9uSWQoY3JlYXRlRHRvLm9yaWdpbmF0b3JJZClcclxuICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICBjb25zdCBwcmV2aWV3UmVjaXBpZW50cyA9IGNyZWF0ZUR0by5yZWNpcGllbnRzXHJcbiAgICAgID8gYXdhaXQgUHJvbWlzZS5hbGwoXHJcbiAgICAgICAgICBjcmVhdGVEdG8ucmVjaXBpZW50cy5tYXAoXHJcbiAgICAgICAgICAgIGFzeW5jIChyKTogUHJvbWlzZTxSZXNvbHZlZFJlY2lwaWVudD4gPT4gKHtcclxuICAgICAgICAgICAgICBvcmdhbml6YXRpb25JZDogYXdhaXQgdGhpcy51dWlkUmVzb2x2ZXIucmVzb2x2ZU9yZ2FuaXphdGlvbklkKFxyXG4gICAgICAgICAgICAgICAgci5vcmdhbml6YXRpb25JZFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgICAgdHlwZTogci50eXBlLFxyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgIClcclxuICAgICAgOiB1bmRlZmluZWQ7XHJcblxyXG4gICAgY29uc3QgdHlwZSA9IGF3YWl0IHRoaXMudHlwZVJlcG8uZmluZE9uZSh7XHJcbiAgICAgIHdoZXJlOiB7IGlkOiBjcmVhdGVEdG8udHlwZUlkIH0sXHJcbiAgICB9KTtcclxuICAgIGlmICghdHlwZSkgdGhyb3cgbmV3IE5vdEZvdW5kRXhjZXB0aW9uKCdEb2N1bWVudCBUeXBlIG5vdCBmb3VuZCcpO1xyXG5cclxuICAgIGxldCB1c2VyT3JnSWQgPSB1c2VyLnByaW1hcnlPcmdhbml6YXRpb25JZDtcclxuICAgIGlmICghdXNlck9yZ0lkKSB7XHJcbiAgICAgIGNvbnN0IGZ1bGxVc2VyID0gYXdhaXQgdGhpcy51c2VyU2VydmljZS5maW5kT25lKHVzZXIudXNlcl9pZCk7XHJcbiAgICAgIGlmIChmdWxsVXNlcikgdXNlck9yZ0lkID0gZnVsbFVzZXIucHJpbWFyeU9yZ2FuaXphdGlvbklkO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChwcmV2aWV3T3JpZ2luYXRvcklkICYmIHByZXZpZXdPcmlnaW5hdG9ySWQgIT09IHVzZXJPcmdJZCkge1xyXG4gICAgICAvLyBBbGxvdyBpbXBlcnNvbmF0aW9uIGZvciBwcmV2aWV3XHJcbiAgICAgIHVzZXJPcmdJZCA9IHByZXZpZXdPcmlnaW5hdG9ySWQ7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXh0cmFjdCByZWNpcGllbnQgZnJvbSByZWNpcGllbnRzIGFycmF5XHJcbiAgICBjb25zdCB0b1JlY2lwaWVudCA9IHByZXZpZXdSZWNpcGllbnRzPy5maW5kKChyKSA9PiByLnR5cGUgPT09ICdUTycpO1xyXG4gICAgY29uc3QgcmVjaXBpZW50T3JnYW5pemF0aW9uSWQgPSB0b1JlY2lwaWVudD8ub3JnYW5pemF0aW9uSWQ7XHJcblxyXG4gICAgbGV0IHJlY2lwaWVudENvZGUgPSAnJztcclxuICAgIGlmIChyZWNpcGllbnRPcmdhbml6YXRpb25JZCkge1xyXG4gICAgICBjb25zdCByZWNPcmcgPSBhd2FpdCB0aGlzLmRhdGFTb3VyY2UubWFuYWdlci5maW5kT25lKE9yZ2FuaXphdGlvbiwge1xyXG4gICAgICAgIHdoZXJlOiB7IGlkOiByZWNpcGllbnRPcmdhbml6YXRpb25JZCB9LFxyXG4gICAgICB9KTtcclxuICAgICAgaWYgKHJlY09yZykgcmVjaXBpZW50Q29kZSA9IHJlY09yZy5vcmdhbml6YXRpb25Db2RlO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0aGlzLm51bWJlcmluZ1NlcnZpY2UucHJldmlld051bWJlcih7XHJcbiAgICAgIHByb2plY3RJZDogcHJldmlld1Byb2plY3RJZCxcclxuICAgICAgb3JpZ2luYXRvck9yZ2FuaXphdGlvbklkOiB1c2VyT3JnSWQhLFxyXG4gICAgICB0eXBlSWQ6IGNyZWF0ZUR0by50eXBlSWQsXHJcbiAgICAgIGRpc2NpcGxpbmVJZDogY3JlYXRlRHRvLmRpc2NpcGxpbmVJZCxcclxuICAgICAgc3ViVHlwZUlkOiBjcmVhdGVEdG8uc3ViVHlwZUlkLFxyXG4gICAgICByZWNpcGllbnRPcmdhbml6YXRpb25JZCxcclxuICAgICAgeWVhcjogbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpLFxyXG4gICAgICBjdXN0b21Ub2tlbnM6IHtcclxuICAgICAgICBUWVBFX0NPREU6IHR5cGUudHlwZUNvZGUsXHJcbiAgICAgICAgUkVDSVBJRU5UX0NPREU6IHJlY2lwaWVudENvZGUsXHJcbiAgICAgICAgUkVDX0NPREU6IHJlY2lwaWVudENvZGUsXHJcbiAgICAgIH0sXHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEJ1c2luZXNzIFJ1bGUgSW1wbGVtZW50YXRpb246IEVDLUNPUlItMDAxIC0gQ2FuY2VsIENvcnJlc3BvbmRlbmNlIHdpdGggRG93bnN0cmVhbSBDaXJjdWxhdGlvblxyXG4gICAqIENhbmNlbCBjb3JyZXNwb25kZW5jZSBhbmQgaGFuZGxlIHJlbGF0ZWQgY2lyY3VsYXRpb25zXHJcbiAgICovXHJcbiAgYXN5bmMgY2FuY2VsKHB1YmxpY0lkOiBzdHJpbmcsIHJlYXNvbjogc3RyaW5nLCB1c2VyOiBVc2VyKSB7XHJcbiAgICBjb25zdCBjb3JyZXNwb25kZW5jZSA9IGF3YWl0IHRoaXMuZmluZE9uZUJ5VXVpZChwdWJsaWNJZCk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdXNlciBoYXMgcGVybWlzc2lvbiB0byBjYW5jZWwgKE9yZyBBZG1pbiBvciBTdXBlcmFkbWluIG9ubHkpXHJcbiAgICBjb25zdCBwZXJtaXNzaW9ucyA9IGF3YWl0IHRoaXMudXNlclNlcnZpY2UuZ2V0VXNlclBlcm1pc3Npb25zKHVzZXIudXNlcl9pZCk7XHJcbiAgICBjb25zdCBjYW5DYW5jZWwgPVxyXG4gICAgICBwZXJtaXNzaW9ucy5pbmNsdWRlcygnY29ycmVzcG9uZGVuY2UuY2FuY2VsJykgfHxcclxuICAgICAgcGVybWlzc2lvbnMuaW5jbHVkZXMoJ3N5c3RlbS5tYW5hZ2VfYWxsJyk7XHJcblxyXG4gICAgaWYgKCFjYW5DYW5jZWwpIHtcclxuICAgICAgdGhyb3cgbmV3IEZvcmJpZGRlbkV4Y2VwdGlvbihcclxuICAgICAgICAnT25seSBhZG1pbmlzdHJhdG9ycyBjYW4gY2FuY2VsIGNvcnJlc3BvbmRlbmNlcydcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBhcmUgYW55IGFjdGl2ZSBjaXJjdWxhdGlvbnNcclxuICAgIGNvbnN0IGNpcmN1bGF0aW9uUmVwbyA9IHRoaXMuZGF0YVNvdXJjZS5nZXRSZXBvc2l0b3J5KCdDaXJjdWxhdGlvbicpO1xyXG4gICAgY29uc3QgYWN0aXZlQ2lyY3VsYXRpb25zID0gYXdhaXQgY2lyY3VsYXRpb25SZXBvLmZpbmQoe1xyXG4gICAgICB3aGVyZToge1xyXG4gICAgICAgIGNvcnJlc3BvbmRlbmNlSWQ6IGNvcnJlc3BvbmRlbmNlLmlkLFxyXG4gICAgICAgIHN0YXR1czogJ09QRU4nLFxyXG4gICAgICB9LFxyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3Qgd2FybmluZ01lc3NhZ2UgPVxyXG4gICAgICBhY3RpdmVDaXJjdWxhdGlvbnMubGVuZ3RoID4gMFxyXG4gICAgICAgID8gYFRoZXJlIGFyZSAke2FjdGl2ZUNpcmN1bGF0aW9ucy5sZW5ndGh9IGFjdGl2ZSBjaXJjdWxhdGlvbihzKSBmb3IgdGhpcyBjb3JyZXNwb25kZW5jZS4gQ2FuY2VsaW5nIHdpbGwgZm9yY2UgY2xvc2UgYWxsIHJlbGF0ZWQgY2lyY3VsYXRpb25zLmBcclxuICAgICAgICA6ICcnO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY3VycmVudCByZXZpc2lvbiB0byB1cGRhdGUgc3RhdHVzXHJcbiAgICBjb25zdCBjdXJyZW50UmV2aXNpb24gPSBhd2FpdCB0aGlzLnJldmlzaW9uUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHtcclxuICAgICAgICBjb3JyZXNwb25kZW5jZUlkOiBjb3JyZXNwb25kZW5jZS5pZCxcclxuICAgICAgICBpc0N1cnJlbnQ6IHRydWUsXHJcbiAgICAgIH0sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoIWN1cnJlbnRSZXZpc2lvbikge1xyXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFeGNlcHRpb24oJ0N1cnJlbnQgcmV2aXNpb24gbm90IGZvdW5kJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IGNhbmNlbGxlZCBzdGF0dXNcclxuICAgIGNvbnN0IGNhbmNlbGxlZFN0YXR1cyA9IGF3YWl0IHRoaXMuc3RhdHVzUmVwby5maW5kT25lKHtcclxuICAgICAgd2hlcmU6IHsgc3RhdHVzQ29kZTogJ0NBTkNFTExFRCcgfSxcclxuICAgIH0pO1xyXG5cclxuICAgIGlmICghY2FuY2VsbGVkU3RhdHVzKSB7XHJcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbFNlcnZlckVycm9yRXhjZXB0aW9uKCdDQU5DRUxMRUQgc3RhdHVzIG5vdCBmb3VuZCcpO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHF1ZXJ5UnVubmVyID0gdGhpcy5kYXRhU291cmNlLmNyZWF0ZVF1ZXJ5UnVubmVyKCk7XHJcbiAgICBhd2FpdCBxdWVyeVJ1bm5lci5jb25uZWN0KCk7XHJcbiAgICBhd2FpdCBxdWVyeVJ1bm5lci5zdGFydFRyYW5zYWN0aW9uKCk7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVXBkYXRlIGNvcnJlc3BvbmRlbmNlIHJldmlzaW9uIHN0YXR1cyB0byBDQU5DRUxMRURcclxuICAgICAgYXdhaXQgcXVlcnlSdW5uZXIubWFuYWdlci51cGRhdGUoXHJcbiAgICAgICAgQ29ycmVzcG9uZGVuY2VSZXZpc2lvbixcclxuICAgICAgICBjdXJyZW50UmV2aXNpb24uaWQsXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgc3RhdHVzSWQ6IGNhbmNlbGxlZFN0YXR1cy5pZCxcclxuICAgICAgICAgIHJlbWFya3M6IGBDYW5jZWxsZWQ6ICR7cmVhc29ufWAsXHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gRm9yY2UgY2xvc2UgYWxsIGFjdGl2ZSBjaXJjdWxhdGlvbnNcclxuICAgICAgaWYgKGFjdGl2ZUNpcmN1bGF0aW9ucy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgYXdhaXQgcXVlcnlSdW5uZXIubWFuYWdlci51cGRhdGUoXHJcbiAgICAgICAgICAnQ2lyY3VsYXRpb24nLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICBjb3JyZXNwb25kZW5jZUlkOiBjb3JyZXNwb25kZW5jZS5pZCxcclxuICAgICAgICAgICAgc3RhdHVzOiAnT1BFTicsXHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICBzdGF0dXM6ICdGT1JDRV9DTE9TRUQnLFxyXG4gICAgICAgICAgICBjbG9zZWRBdDogbmV3IERhdGUoKSxcclxuICAgICAgICAgICAgY2xvc2VkQnk6IHVzZXIudXNlcl9pZCxcclxuICAgICAgICAgICAgY2xvc2VSZWFzb246IGBDb3JyZXNwb25kZW5jZSBjYW5jZWxsZWQ6ICR7cmVhc29ufWAsXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgYXdhaXQgcXVlcnlSdW5uZXIuY29tbWl0VHJhbnNhY3Rpb24oKTtcclxuXHJcbiAgICAgIC8vIFJlLWluZGV4IGNhbmNlbGxlZCBzdGF0dXMgaW4gRWxhc3RpY3NlYXJjaCAoZmlyZS1hbmQtZm9yZ2V0KVxyXG4gICAgICB2b2lkIHRoaXMuc2VhcmNoU2VydmljZS5pbmRleERvY3VtZW50KHtcclxuICAgICAgICBpZDogY29ycmVzcG9uZGVuY2UuaWQsXHJcbiAgICAgICAgcHVibGljSWQ6IGNvcnJlc3BvbmRlbmNlLnB1YmxpY0lkLFxyXG4gICAgICAgIHR5cGU6ICdjb3JyZXNwb25kZW5jZScsXHJcbiAgICAgICAgZG9jTnVtYmVyOiBjb3JyZXNwb25kZW5jZS5jb3JyZXNwb25kZW5jZU51bWJlcixcclxuICAgICAgICB0aXRsZTogY3VycmVudFJldmlzaW9uLnN1YmplY3QsXHJcbiAgICAgICAgc3RhdHVzOiAnQ0FOQ0VMTEVEJyxcclxuICAgICAgICBwcm9qZWN0SWQ6IGNvcnJlc3BvbmRlbmNlLnByb2plY3RJZCxcclxuICAgICAgICBjcmVhdGVkQXQ6IGNvcnJlc3BvbmRlbmNlLmNyZWF0ZWRBdCxcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBOb3RpZnkgb3JpZ2luYXRvcidzIGRvYy1jb250cm9sIHVzZXIgYWJvdXQgY2FuY2VsbGF0aW9uIChmaXJlLWFuZC1mb3JnZXQpXHJcbiAgICAgIGlmIChjb3JyZXNwb25kZW5jZS5vcmlnaW5hdG9ySWQpIHtcclxuICAgICAgICB2b2lkIHRoaXMudXNlclNlcnZpY2VcclxuICAgICAgICAgIC5maW5kRG9jQ29udHJvbElkQnlPcmcoY29ycmVzcG9uZGVuY2Uub3JpZ2luYXRvcklkKVxyXG4gICAgICAgICAgLnRoZW4oKHRhcmdldFVzZXJJZCkgPT4ge1xyXG4gICAgICAgICAgICBpZiAodGFyZ2V0VXNlcklkKSB7XHJcbiAgICAgICAgICAgICAgdm9pZCB0aGlzLm5vdGlmaWNhdGlvblNlcnZpY2Uuc2VuZCh7XHJcbiAgICAgICAgICAgICAgICB1c2VySWQ6IHRhcmdldFVzZXJJZCxcclxuICAgICAgICAgICAgICAgIHRpdGxlOiAnQ29ycmVzcG9uZGVuY2UgQ2FuY2VsbGVkJyxcclxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGAke2NvcnJlc3BvbmRlbmNlLmNvcnJlc3BvbmRlbmNlTnVtYmVyfSDigJQgJHtjdXJyZW50UmV2aXNpb24uc3ViamVjdH0gaGFzIGJlZW4gY2FuY2VsbGVkLiBSZWFzb246ICR7cmVhc29ufWAsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiAnRU1BSUwnLFxyXG4gICAgICAgICAgICAgICAgZW50aXR5VHlwZTogJ2NvcnJlc3BvbmRlbmNlJyxcclxuICAgICAgICAgICAgICAgIGVudGl0eUlkOiBjb3JyZXNwb25kZW5jZS5pZCxcclxuICAgICAgICAgICAgICAgIGxpbms6IGAvY29ycmVzcG9uZGVuY2VzLyR7Y29ycmVzcG9uZGVuY2UucHVibGljSWR9YCxcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSlcclxuICAgICAgICAgIC5jYXRjaCgoZXJyOiBFcnJvcikgPT5cclxuICAgICAgICAgICAgdGhpcy5sb2dnZXIud2FybihgQ2FuY2VsIG5vdGlmaWNhdGlvbiBmYWlsZWQ6ICR7ZXJyLm1lc3NhZ2V9YClcclxuICAgICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiB7XHJcbiAgICAgICAgc3VjY2VzczogdHJ1ZSxcclxuICAgICAgICBtZXNzYWdlOiB3YXJuaW5nTWVzc2FnZSB8fCAnQ29ycmVzcG9uZGVuY2UgY2FuY2VsbGVkIHN1Y2Nlc3NmdWxseScsXHJcbiAgICAgICAgYWN0aXZlQ2lyY3VsYXRpb25zQ291bnQ6IGFjdGl2ZUNpcmN1bGF0aW9ucy5sZW5ndGgsXHJcbiAgICAgIH07XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBhd2FpdCBxdWVyeVJ1bm5lci5yb2xsYmFja1RyYW5zYWN0aW9uKCk7XHJcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKFxyXG4gICAgICAgIGBGYWlsZWQgdG8gY2FuY2VsIGNvcnJlc3BvbmRlbmNlOiAkeyhlcnJvciBhcyBFcnJvcikubWVzc2FnZX1gXHJcbiAgICAgICk7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfSBmaW5hbGx5IHtcclxuICAgICAgYXdhaXQgcXVlcnlSdW5uZXIucmVsZWFzZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgYXN5bmMgYnVsa0NhbmNlbChcclxuICAgIHB1YmxpY0lkczogc3RyaW5nW10sXHJcbiAgICByZWFzb246IHN0cmluZyxcclxuICAgIHVzZXI6IFVzZXJcclxuICApOiBQcm9taXNlPHsgc3VjY2VlZGVkOiBzdHJpbmdbXTsgZmFpbGVkOiBzdHJpbmdbXSB9PiB7XHJcbiAgICBjb25zdCBzdWNjZWVkZWQ6IHN0cmluZ1tdID0gW107XHJcbiAgICBjb25zdCBmYWlsZWQ6IHN0cmluZ1tdID0gW107XHJcblxyXG4gICAgZm9yIChjb25zdCBwdWJsaWNJZCBvZiBwdWJsaWNJZHMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBhd2FpdCB0aGlzLmNhbmNlbChwdWJsaWNJZCwgcmVhc29uLCB1c2VyKTtcclxuICAgICAgICBzdWNjZWVkZWQucHVzaChwdWJsaWNJZCk7XHJcbiAgICAgIH0gY2F0Y2gge1xyXG4gICAgICAgIGZhaWxlZC5wdXNoKHB1YmxpY0lkKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB7IHN1Y2NlZWRlZCwgZmFpbGVkIH07XHJcbiAgfVxyXG5cclxuICBhc3luYyBleHBvcnRDc3Yoc2VhcmNoRHRvOiBTZWFyY2hDb3JyZXNwb25kZW5jZUR0byk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICBjb25zdCB7IGRhdGEgfSA9IGF3YWl0IHRoaXMuZmluZEFsbChzZWFyY2hEdG8pO1xyXG5cclxuICAgIGNvbnN0IGhlYWRlciA9IFtcclxuICAgICAgJ0RvY3VtZW50IE5vLicsXHJcbiAgICAgICdSZXYnLFxyXG4gICAgICAnU3ViamVjdCcsXHJcbiAgICAgICdUeXBlJyxcclxuICAgICAgJ1N0YXR1cycsXHJcbiAgICAgICdQcm9qZWN0JyxcclxuICAgICAgJ0Zyb20nLFxyXG4gICAgICAnRHVlIERhdGUnLFxyXG4gICAgICAnQ3JlYXRlZCBBdCcsXHJcbiAgICBdO1xyXG4gICAgY29uc3Qgcm93cyA9IGRhdGEubWFwKChyZXYpID0+IHtcclxuICAgICAgY29uc3QgY29yciA9IHJldi5jb3JyZXNwb25kZW5jZSA/PyAocmV2IGFzIHVua25vd24gYXMgQ29ycmVzcG9uZGVuY2UpO1xyXG4gICAgICByZXR1cm4gW1xyXG4gICAgICAgIHRoaXMuZXNjYXBlQ3N2KGNvcnIuY29ycmVzcG9uZGVuY2VOdW1iZXIgPz8gJycpLFxyXG4gICAgICAgIHRoaXMuZXNjYXBlQ3N2KHJldi5yZXZpc2lvbkxhYmVsID8/IFN0cmluZyhyZXYucmV2aXNpb25OdW1iZXIgPz8gMCkpLFxyXG4gICAgICAgIHRoaXMuZXNjYXBlQ3N2KHJldi5zdWJqZWN0ID8/ICcnKSxcclxuICAgICAgICB0aGlzLmVzY2FwZUNzdihjb3JyLnR5cGU/LnR5cGVDb2RlID8/ICcnKSxcclxuICAgICAgICB0aGlzLmVzY2FwZUNzdihyZXYuc3RhdHVzPy5zdGF0dXNDb2RlID8/ICcnKSxcclxuICAgICAgICB0aGlzLmVzY2FwZUNzdihjb3JyLnByb2plY3Q/LnByb2plY3RDb2RlID8/ICcnKSxcclxuICAgICAgICB0aGlzLmVzY2FwZUNzdihjb3JyLm9yaWdpbmF0b3I/Lm9yZ2FuaXphdGlvbkNvZGUgPz8gJycpLFxyXG4gICAgICAgIHJldi5kdWVEYXRlID8gbmV3IERhdGUocmV2LmR1ZURhdGUpLnRvSVNPU3RyaW5nKCkuc3BsaXQoJ1QnKVswXSA6ICcnLFxyXG4gICAgICAgIG5ldyBEYXRlKHJldi5jcmVhdGVkQXQpLnRvSVNPU3RyaW5nKCkuc3BsaXQoJ1QnKVswXSxcclxuICAgICAgXS5qb2luKCcsJyk7XHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4gW2hlYWRlci5qb2luKCcsJyksIC4uLnJvd3NdLmpvaW4oJ1xcbicpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBlc2NhcGVDc3YodmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICBpZiAodmFsdWUuaW5jbHVkZXMoJywnKSB8fCB2YWx1ZS5pbmNsdWRlcygnXCInKSB8fCB2YWx1ZS5pbmNsdWRlcygnXFxuJykpIHtcclxuICAgICAgcmV0dXJuIGBcIiR7dmFsdWUucmVwbGFjZSgvXCIvZywgJ1wiXCInKX1cImA7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdmFsdWU7XHJcbiAgfVxyXG59XHJcbiJdLCJ2ZXJzaW9uIjozfQ== \ No newline at end of file diff --git a/backend/src/.jest-cache/jest-transform-cache-51fed4c0665a260afb7eef9c4f4e1366-12533232bd0f05f65688e7a7764bf3fb/aa/correspondenceservice_aa616b6e2768e82b10627448176b8243.map b/backend/src/.jest-cache/jest-transform-cache-51fed4c0665a260afb7eef9c4f4e1366-12533232bd0f05f65688e7a7764bf3fb/aa/correspondenceservice_aa616b6e2768e82b10627448176b8243.map new file mode 100644 index 0000000..a36aedd --- /dev/null +++ b/backend/src/.jest-cache/jest-transform-cache-51fed4c0665a260afb7eef9c4f4e1366-12533232bd0f05f65688e7a7764bf3fb/aa/correspondenceservice_aa616b6e2768e82b10627448176b8243.map @@ -0,0 +1 @@ +{"file":"D:\\nap-dms.lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.ts","mappings":"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","names":[],"sources":["D:\\nap-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\nimport { CorrespondenceRevisionAttachment } from './entities/correspondence-revision-attachment.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 | undefined {\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 undefined; // Numeric (no label 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 @InjectRepository(CorrespondenceRevisionAttachment)\r\n private revAttachRepo: Repository\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 // [FIX v1.8.1] commit ได้ Attachment records กลับมา → บันทึก junction\r\n const committed = await this.fileStorageService.commit(\r\n createDto.attachmentTempIds,\r\n { issueDate, documentType: 'Correspondence' }\r\n );\r\n\r\n if (committed.length > 0) {\r\n const links = committed.map((att, idx) =>\r\n queryRunner.manager.create(CorrespondenceRevisionAttachment, {\r\n correspondenceRevisionId: revision.id,\r\n attachmentId: att.id,\r\n isMainDocument: idx === 0, // ไฟล์แรกเป็น main document\r\n })\r\n );\r\n await queryRunner.manager.save(\r\n CorrespondenceRevisionAttachment,\r\n links\r\n );\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 'discipline',\r\n 'discipline.contract',\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 'revisions.attachmentLinks', // [FIX v1.8.1] โหลด junction\r\n 'revisions.attachmentLinks.attachment', // [FIX v1.8.1] โหลด attachment จริง\r\n 'type',\r\n 'project',\r\n 'originator',\r\n 'recipients',\r\n 'recipients.recipientOrganization',\r\n 'discipline',\r\n 'discipline.contract',\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\r\n if (status && status.statusCode !== 'DRAFT') {\r\n const permissions = await this.userService.getUserPermissions(\r\n user.user_id\r\n );\r\n const canEditSubmittedOrLater =\r\n permissions.includes('correspondence.cancel') ||\r\n permissions.includes('system.manage_all');\r\n\r\n if (!canEditSubmittedOrLater) {\r\n throw new ForbiddenException(\r\n 'Only Org Admin or Superadmin can edit non-draft correspondences'\r\n );\r\n }\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 // [FIX v1.8.1] commit ได้ Attachment records กลับมา → บันทึก junction\r\n const committed = await this.fileStorageService.commit(\r\n updateDto.attachmentTempIds,\r\n {\r\n issueDate: issueDate ? new Date(issueDate) : undefined,\r\n documentType: 'Correspondence',\r\n }\r\n );\r\n\r\n if (committed.length > 0) {\r\n const links = committed.map((att) =>\r\n this.revAttachRepo.create({\r\n correspondenceRevisionId: revision.id,\r\n attachmentId: att.id,\r\n isMainDocument: false, // ไฟล์ที่ upload เพิ่มเติมไม่ใช่ main\r\n })\r\n );\r\n await this.revAttachRepo.save(links);\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-51fed4c0665a260afb7eef9c4f4e1366-da39a3ee5e6b4b0d3255bfef95601890 b/backend/src/.jest-cache/perf-cache-51fed4c0665a260afb7eef9c4f4e1366-da39a3ee5e6b4b0d3255bfef95601890 index b7ff333..1d4f05d 100644 --- a/backend/src/.jest-cache/perf-cache-51fed4c0665a260afb7eef9c4f4e1366-da39a3ee5e6b4b0d3255bfef95601890 +++ b/backend/src/.jest-cache/perf-cache-51fed4c0665a260afb7eef9c4f4e1366-da39a3ee5e6b4b0d3255bfef95601890 @@ -1 +1 @@ -{"D:\\nap-dms.lcbp3\\backend\\src\\modules\\document-numbering\\document-numbering.service.spec.ts":[1,852],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.spec.ts":[1,1935],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\correspondence\\correspondence.controller.spec.ts":[1,2180],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\migration\\migration.service.spec.ts":[1,628],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\correspondence\\due-date-reminder.service.spec.ts":[1,1141],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\migration\\migration.controller.spec.ts":[1,1507],"D:\\nap-dms.lcbp3\\backend\\src\\common\\pipes\\parse-uuid.pipe.spec.ts":[1,1043],"D:\\nap-dms.lcbp3\\backend\\src\\common\\services\\uuid-resolver.service.spec.ts":[1,2018],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\workflow-engine\\workflow-engine.service.spec.ts":[1,2079],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\user\\user.service.spec.ts":[1,2089],"D:\\nap-dms.lcbp3\\backend\\src\\common\\auth\\casl\\ability.factory.spec.ts":[1,2135],"D:\\nap-dms.lcbp3\\backend\\src\\common\\file-storage\\file-storage.service.spec.ts":[1,2194],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\project\\project.service.spec.ts":[1,1198],"D:\\nap-dms.lcbp3\\backend\\src\\common\\entities\\uuid-base.entity.spec.ts":[1,267],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\workflow-engine\\dsl\\parser.service.spec.ts":[1,2354],"D:\\nap-dms.lcbp3\\backend\\src\\common\\auth\\auth.service.spec.ts":[1,2520],"D:\\nap-dms.lcbp3\\backend\\src\\app.controller.spec.ts":[1,362],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\document-numbering\\services\\manual-override.service.spec.ts":[1,566],"D:\\nap-dms.lcbp3\\backend\\src\\common\\file-storage\\file-storage.controller.spec.ts":[1,1091],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\project\\project.controller.spec.ts":[1,1249],"D:\\nap-dms.lcbp3\\backend\\src\\common\\auth\\auth.controller.spec.ts":[1,1564],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\json-schema\\json-schema.controller.spec.ts":[1,1508]} \ No newline at end of file +{"D:\\nap-dms.lcbp3\\backend\\src\\modules\\document-numbering\\document-numbering.service.spec.ts":[1,852],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\correspondence\\correspondence.service.spec.ts":[1,2248],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\correspondence\\correspondence.controller.spec.ts":[1,2610],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\migration\\migration.service.spec.ts":[1,628],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\correspondence\\due-date-reminder.service.spec.ts":[1,1141],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\migration\\migration.controller.spec.ts":[1,1507],"D:\\nap-dms.lcbp3\\backend\\src\\common\\pipes\\parse-uuid.pipe.spec.ts":[1,1043],"D:\\nap-dms.lcbp3\\backend\\src\\common\\services\\uuid-resolver.service.spec.ts":[1,2018],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\workflow-engine\\workflow-engine.service.spec.ts":[1,2079],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\user\\user.service.spec.ts":[1,2089],"D:\\nap-dms.lcbp3\\backend\\src\\common\\auth\\casl\\ability.factory.spec.ts":[1,2135],"D:\\nap-dms.lcbp3\\backend\\src\\common\\file-storage\\file-storage.service.spec.ts":[1,2194],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\project\\project.service.spec.ts":[1,1198],"D:\\nap-dms.lcbp3\\backend\\src\\common\\entities\\uuid-base.entity.spec.ts":[1,267],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\workflow-engine\\dsl\\parser.service.spec.ts":[1,2354],"D:\\nap-dms.lcbp3\\backend\\src\\common\\auth\\auth.service.spec.ts":[1,2520],"D:\\nap-dms.lcbp3\\backend\\src\\app.controller.spec.ts":[1,362],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\document-numbering\\services\\manual-override.service.spec.ts":[1,566],"D:\\nap-dms.lcbp3\\backend\\src\\common\\file-storage\\file-storage.controller.spec.ts":[1,1091],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\project\\project.controller.spec.ts":[1,1249],"D:\\nap-dms.lcbp3\\backend\\src\\common\\auth\\auth.controller.spec.ts":[1,1564],"D:\\nap-dms.lcbp3\\backend\\src\\modules\\json-schema\\json-schema.controller.spec.ts":[1,1508]} \ No newline at end of file diff --git a/backend/src/modules/correspondence/correspondence.service.ts b/backend/src/modules/correspondence/correspondence.service.ts index 40d9293..e8dd3ae 100644 --- a/backend/src/modules/correspondence/correspondence.service.ts +++ b/backend/src/modules/correspondence/correspondence.service.ts @@ -499,6 +499,8 @@ export class CorrespondenceService { 'originator', 'recipients', 'recipients.recipientOrganization', // [v1.5.1] Fixed relation name + 'discipline', + 'discipline.contract', ], }); @@ -521,6 +523,8 @@ export class CorrespondenceService { 'originator', 'recipients', 'recipients.recipientOrganization', + 'discipline', + 'discipline.contract', ], }); diff --git a/frontend/components/correspondences/form.tsx b/frontend/components/correspondences/form.tsx index f01b1d8..667e78a 100644 --- a/frontend/components/correspondences/form.tsx +++ b/frontend/components/correspondences/form.tsx @@ -176,8 +176,11 @@ export function CorrespondenceForm({ projectId: normalizePublicId(initialData?.project?.publicId) ?? normalizePublicId(initialData?.projectId), - // [FIX v1.8.1] correspondences ไม่มี contract_id โดยตรง → จะ auto-populate จาก discipline useEffect - contractId: undefined, + // [FIX v1.8.1] correspondences ไม่มี contract_id โดยตรง → จะ auto-populate จาก discipline useEffect หรือจาก object contract เองในกรณี mock/test + contractId: + normalizePublicId(initialData?.contract?.publicId) ?? + normalizePublicId(initialData?.discipline?.contract?.publicId) ?? + normalizePublicId((initialData as Record)?.contractId as string), documentTypeId: initialData?.correspondenceTypeId || undefined, disciplineId: initialData?.disciplineId || undefined, subject: currentRev?.subject || currentRev?.title || '', diff --git a/frontend/types/correspondence.ts b/frontend/types/correspondence.ts index 78ac9cb..cbde384 100644 --- a/frontend/types/correspondence.ts +++ b/frontend/types/correspondence.ts @@ -65,6 +65,7 @@ export interface Correspondence { projectId: number; originatorId?: number; correspondenceTypeId: number; + disciplineId?: number; isInternal: boolean; createdAt: string; @@ -79,6 +80,14 @@ export interface Correspondence { recipientType: 'TO' | 'CC'; recipientOrganization?: Organization; }[]; + contract?: { publicId: string; contractName: string; contractCode: string }; + discipline?: { + id: number; + disciplineCode: string; + codeNameEn?: string; + codeNameTh?: string; + contract?: { publicId: string; contractName: string; contractCode: string }; + }; } export interface CreateCorrespondenceDto {