UNPKG

@netgrif/components-core

Version:

Netgrif Application engine frontend core Angular library

579 lines 98.1 kB
import { Inject, Injectable, Optional } from '@angular/core'; import { Subject } from 'rxjs'; import { TaskHandlingService } from './task-handling-service'; import { NAE_TASK_OPERATIONS } from '../models/task-operations-injection-token'; import { HttpErrorResponse } from '@angular/common/http'; import { FileField } from '../../data-fields/file-field/models/file-field'; import { FileListField } from '../../data-fields/file-list-field/models/file-list-field'; import { createTaskEventNotification } from '../../task-content/model/task-event-notification'; import { TaskEvent } from '../../task-content/model/task-event'; import { take } from 'rxjs/operators'; import { DynamicEnumerationField } from '../../data-fields/enumeration-field/models/dynamic-enumeration-field'; import { QueuedEvent } from '../../event-queue/model/queued-event'; import { AfterAction } from '../../utility/call-chain/after-action'; import { EnumerationField } from "../../data-fields/enumeration-field/models/enumeration-field"; import * as i0 from "@angular/core"; import * as i1 from "./task-request-state.service"; import * as i2 from "@ngx-translate/core"; import * as i3 from "../../logger/services/logger.service"; import * as i4 from "../../snack-bar/services/snack-bar.service"; import * as i5 from "../../resources/engine-endpoint/task-resource.service"; import * as i6 from "../../task-content/services/field-converter.service"; import * as i7 from "../../task-content/services/task-event.service"; import * as i8 from "./selected-case.service"; import * as i9 from "../../task-content/services/task-content.service"; import * as i10 from "../../utility/call-chain/call-chain.service"; import * as i11 from "../../event-queue/services/event-queue.service"; import * as i12 from "../../user/services/user-comparator.service"; import * as i13 from "../../event/services/event.service"; import * as i14 from "../../changed-fields/services/changed-fields.service"; import * as i15 from "../../actions/services/front-action.service"; /** * Handles the loading and updating of data fields and behaviour of * a single Task object managed by a {@link TaskContentService} instance. */ export class TaskDataService extends TaskHandlingService { _taskState; _translate; _log; _snackBar; _taskResourceService; _fieldConverterService; _taskEvent; _taskOperations; _afterActionFactory; _eventQueue; _userComparator; _eventService; _changedFieldsService; _frontActionService; _updateSuccess$; _dataReloadSubscription; constructor(_taskState, _translate, _log, _snackBar, _taskResourceService, _fieldConverterService, _taskEvent, _taskOperations, _selectedCaseService, _taskContentService, _afterActionFactory, _eventQueue, _userComparator, _eventService, _changedFieldsService, _frontActionService) { super(_taskContentService, _selectedCaseService); this._taskState = _taskState; this._translate = _translate; this._log = _log; this._snackBar = _snackBar; this._taskResourceService = _taskResourceService; this._fieldConverterService = _fieldConverterService; this._taskEvent = _taskEvent; this._taskOperations = _taskOperations; this._afterActionFactory = _afterActionFactory; this._eventQueue = _eventQueue; this._userComparator = _userComparator; this._eventService = _eventService; this._changedFieldsService = _changedFieldsService; this._frontActionService = _frontActionService; this._updateSuccess$ = new Subject(); this._dataReloadSubscription = this._taskContentService.taskDataReloadRequest$.subscribe(queuedFrontendAction => { this.initializeTaskDataFields(new AfterAction(), true); }); } ngOnDestroy() { this._updateSuccess$.complete(); this._dataReloadSubscription.unsubscribe(); if (this.isTaskPresent() && this._safeTask.dataGroups) { this._safeTask.dataGroups.forEach(group => { if (group && group.fields) { group.fields.forEach(field => field.destroy()); } }); } } /** * Contains information about the success or failure of backend * calls in [updateTaskDataFields]{@link TaskDataService#updateTaskDataFields} method. */ get updateSuccess$() { return this._updateSuccess$.asObservable(); } /** * Loads the Data Fields of an uninitialized Task from backend * and populates the Task managed by {@link TaskContentService} with the appropriate objects. * * Beware that if the Task has some data already loaded this function does nothing * and only passes `true` to the `afterAction` argument. * * If the task held within the {@link TaskContentService} changes before a response is received, the response will be ignored * and the `afterAction` will not be executed. * * @param afterAction if the request completes successfully emits `true` into the Subject, otherwise `false` will be emitted * @param force set to `true` if you need force reload of all task data */ initializeTaskDataFields(afterAction = new AfterAction(), force = false) { this._eventQueue.scheduleEvent(new QueuedEvent(() => { return this.isTaskPresent(); }, nextEvent => { this.performGetDataRequest(afterAction, force, nextEvent); }, nextEvent => { afterAction.resolve(false); nextEvent.resolve(false); })); } /** * Performs a `getData` request on the task currently stored in the `taskContent` service * @param afterAction the action that should be performed after the request is processed * @param force set to `true` if you need force reload of all task data * @param nextEvent indicates to the event queue that the next event can be processed */ performGetDataRequest(afterAction, force, nextEvent) { if (this._safeTask.dataSize > 0 && !force) { this.sendNotification(TaskEvent.GET_DATA, true); afterAction.resolve(true); this._taskContentService.$shouldCreate.next(this._safeTask.dataGroups); nextEvent.resolve(true); return; } if (force) { this._safeTask.dataSize = 0; } const gottenTaskId = this._safeTask.stringId; this._taskState.startLoading(gottenTaskId); this._taskResourceService.getData(gottenTaskId).pipe(take(1)).subscribe(dataGroups => { this.processSuccessfulGetDataRequest(gottenTaskId, dataGroups, afterAction, nextEvent); }, error => { this.processErroneousGetDataRequest(gottenTaskId, error, afterAction, nextEvent); }); } /** * Processes a successful outcome of a `getData` request * @param gottenTaskId the ID of the task whose data was requested * @param dataGroups the returned data groups of the task * @param afterAction the action that should be performed after the request is processed * @param nextEvent indicates to the event queue that the next event can be processed */ processSuccessfulGetDataRequest(gottenTaskId, dataGroups, afterAction, nextEvent) { if (!this.isTaskRelevant(gottenTaskId)) { this._log.debug('current task changed before the get data response could be received, discarding...'); this._taskState.stopLoading(gottenTaskId); afterAction.complete(); nextEvent.resolve(false); return; } this._taskContentService.referencedTaskAndCaseIds = {}; this._taskContentService.taskFieldsIndex = {}; this._safeTask.dataGroups = dataGroups; if (dataGroups.length === 0) { this._log.info('Task has no data ' + this._safeTask); this._safeTask.dataSize = 0; this._taskContentService.taskFieldsIndex[this._safeTask.stringId] = {}; } else { this._taskContentService.referencedTaskAndCaseIds[this._safeTask.caseId] = [this._safeTask.stringId]; dataGroups.forEach(group => { const dataGroupParentCaseId = group.parentCaseId === undefined ? this._safeTask.caseId : group.parentCaseId; const parentTaskId = group.parentTaskId === undefined ? this._safeTask.stringId : group.parentTaskId; const parentTransitionId = group.parentTransitionId === undefined ? this._safeTask.transitionId : group.parentTransitionId; if (dataGroupParentCaseId !== this._safeTask.caseId) { if (!this._taskContentService.referencedTaskAndCaseIds[dataGroupParentCaseId]) { this._taskContentService.referencedTaskAndCaseIds[dataGroupParentCaseId] = [group.parentTaskId]; } else { this._taskContentService.referencedTaskAndCaseIds[dataGroupParentCaseId].push(group.parentTaskId); } } else if (dataGroupParentCaseId === this._safeTask.caseId && parentTaskId !== this._safeTask.stringId && !this._taskContentService.referencedTaskAndCaseIds[dataGroupParentCaseId]?.includes(parentTaskId)) { this._taskContentService.referencedTaskAndCaseIds[dataGroupParentCaseId].push(group.parentTaskId); } if (group.fields.length > 0 && !this._taskContentService.taskFieldsIndex[parentTaskId]) { this._taskContentService.taskFieldsIndex[parentTaskId] = {}; } if (group.fields.length > 0 && !this._taskContentService.taskFieldsIndex[parentTaskId].fields) { this._taskContentService.taskFieldsIndex[parentTaskId].fields = {}; } group.fields.forEach(field => { this._taskContentService.taskFieldsIndex[parentTaskId].transitionId = parentTransitionId; this._taskContentService.taskFieldsIndex[parentTaskId].fields[field.stringId] = field; field.valueChanges().subscribe(() => { if (this.wasFieldUpdated(field)) { if (field instanceof DynamicEnumerationField) { field.loading = true; this.updateTaskDataFields(this._afterActionFactory.create(bool => { field.loading = false; })); } else { this.updateTaskDataFields(); } } }); if (field instanceof FileField || field instanceof FileListField) { field.changedFields$.subscribe((change) => { this._changedFieldsService.emitChangedFields(change); }); } }); this._safeTask.dataSize === undefined ? this._safeTask.dataSize = group.fields.length : this._safeTask.dataSize += group.fields.length; }); } this._taskState.stopLoading(gottenTaskId); this.sendNotification(TaskEvent.GET_DATA, true); afterAction.resolve(true); nextEvent.resolve(true); this._taskContentService.$shouldCreate.next(this._safeTask.dataGroups); this._taskContentService.$shouldCreateCounter.next(this._taskContentService.$shouldCreateCounter.getValue() + 1); } /** * Processes an erroneous outcome of a `getData` request * @param gottenTaskId the ID of the task whose data was requested * @param error the returned error * @param afterAction the action that should be performed after the request is processed * @param nextEvent indicates to the event queue that the next event can be processed */ processErroneousGetDataRequest(gottenTaskId, error, afterAction, nextEvent) { this._taskState.stopLoading(gottenTaskId); this._log.debug('getting task data failed', error); if (!this.isTaskRelevant(gottenTaskId)) { this._log.debug('current task changed before the get data error could be received'); afterAction.complete(); nextEvent.resolve(false); return; } if (error instanceof HttpErrorResponse && error.status === 500 && error.error.message && error.error.message.startsWith('Could not find task with id')) { this._snackBar.openWarningSnackBar(this._translate.instant('tasks.snackbar.noLongerExists')); this._taskOperations.reload(); } else if (error instanceof Error) { this._snackBar.openErrorSnackBar(this._translate.instant(error.message)); } else { this._snackBar.openErrorSnackBar(`${this._translate.instant('tasks.snackbar.noGroup')} ${this._taskContentService.task.title} ${this._translate.instant('tasks.snackbar.failedToLoad')}`); } this.sendNotification(TaskEvent.GET_DATA, false); afterAction.resolve(false); nextEvent.resolve(false); } /** * Collects all changed data fields and notifies the backend of the changes. * * If the request is successful clears the [changed]{@link DataField#changed} flag on all data fields that were a part of the request * and emits a {@link ChangedFields} object into this object's [changedFields$]{@link TaskDataService#changedFields$} stream. * * If the task held within the {@link TaskContentService} changes before a response is received, the response will be ignored * and the `afterAction` will not be executed. * * @param afterAction if the request completes successfully emits `true` into the Subject, otherwise `false` will be emitted */ updateTaskDataFields(afterAction = new AfterAction()) { if (!this.isTaskPresent()) { this._log.debug('Task is not present. Update request ignored.'); afterAction.resolve(false); return; } if (this._safeTask.userId === undefined) { this._log.debug('current task is not assigned...'); afterAction.resolve(false); return; } const setTaskId = this._safeTask.stringId; if (this._safeTask.dataSize <= 0) { afterAction.resolve(true); return; } const requestContext = this.createUpdateRequestContext(); this._eventQueue.scheduleEvent(new QueuedEvent(() => this.isSetDataRequestStillValid(requestContext.body), nextEvent => { this.performSetDataRequest(setTaskId, requestContext, afterAction, nextEvent); }, nextEvent => { this.revertSetDataRequest(requestContext); nextEvent.resolve(false); })); } /** * @ignore * Goes over all the data fields in the managed Task and if they are valid and changed adds them to the set data request */ createUpdateRequestContext() { const context = { body: {}, previousValues: {} }; this._safeTask.dataGroups.filter(dataGroup => dataGroup.parentTaskId === undefined).forEach(dataGroup => { dataGroup.fields.filter(field => this.wasFieldUpdated(field)).forEach(field => { context.body[this._task.stringId] = {}; this.addFieldToSetDataRequestBody(context, this._task.stringId, field); }); }); this._safeTask.dataGroups.filter(dataGroup => dataGroup.parentTaskId !== undefined).forEach(dataGroup => { if (dataGroup.fields.some(field => this.wasFieldUpdated(field))) { context.body[dataGroup.parentTaskId] = {}; } else { return; } dataGroup.fields.filter(field => this.wasFieldUpdated(field)).forEach(field => { this.addFieldToSetDataRequestBody(context, dataGroup.parentTaskId, field); }); }); return context; } addFieldToSetDataRequestBody(context, taskId, field) { context.body[taskId][field.stringId] = { type: this._fieldConverterService.resolveType(field), value: this._fieldConverterService.formatValueForBackend(field, field.value) }; context.previousValues[field.stringId] = field.previousValue; field.changed = false; } isAutocompleteEnumException(field) { return (field instanceof EnumerationField) && (field.getComponentType() === 'autocomplete') && !(field.valid || field.value === null); } /** * @param field the checked field * @returns whether the field was updated on frontend and thus the backend should be notified */ wasFieldUpdated(field) { return field.initialized && field.changed && (field.valid || field.sendInvalidValues) && (!this.isAutocompleteEnumException(field)); } /** * Checks whether the request could still be performed by the logged user * @param request */ isSetDataRequestStillValid(request) { if (!this.isTaskPresent()) { return false; } if (this._safeTask.userId === undefined) { return false; } if (!this._userComparator.compareUsers(this._safeTask.userId)) { return false; } const taskIdsInRequest = Object.keys(request); for (const taskId of taskIdsInRequest) { if (!Object.keys(this._taskContentService.taskFieldsIndex)?.includes(taskId)) { this._log.error(`Task id ${taskId} is not present in task fields index`); return false; } const fieldIdsOfRequest = Object.keys(request[taskId]); for (const fieldId of fieldIdsOfRequest) { const field = this._taskContentService.taskFieldsIndex[taskId].fields[fieldId]; if (field === undefined) { this._log.error(`Unexpected state. Datafield ${fieldId} of task ${taskId} in setData request is not present in the task.`); return false; } if (!field.behavior.editable) { this._log.debug(`Field ${fieldId}, was meant to be set to ${JSON.stringify(request[taskId][fieldId])}, but is no loner editable.`); return false; } } } return true; } /** * Performs a `setData` request on the task currently stored in the `taskContent` service * @param setTaskId ID of the task * @param context context of the `setData` request * @param afterAction the action that should be performed after the request is processed * @param nextEvent indicates to the event queue that the next event can be processed */ performSetDataRequest(setTaskId, context, afterAction, nextEvent) { if (Object.keys(context.body).length === 0) { this.sendNotification(TaskEvent.SET_DATA, true); afterAction.resolve(true); nextEvent.resolve(true); return; } this._taskState.startLoading(setTaskId); this._taskState.startUpdating(setTaskId); this._taskResourceService.setData(this._safeTask.stringId, context.body).pipe(take(1)) .subscribe((response) => { if (!this.isTaskRelevant(setTaskId)) { this._log.debug('current task changed before the set data response could be received, discarding...'); this._taskState.stopLoading(setTaskId); this._taskState.stopUpdating(setTaskId); afterAction.complete(); nextEvent.resolve(false); return; } if (response.success) { this.processSuccessfulSetDataRequest(setTaskId, response, afterAction, nextEvent, context); } else if (response.error !== undefined) { this.processUnsuccessfulSetDataRequest(setTaskId, response, afterAction, nextEvent, context); } }, error => { this.processErroneousSetDataRequest(setTaskId, error, afterAction, nextEvent, context); }); } /** * Processes an unsuccessful outcome of a `setData` request * @param setTaskId the ID of the task whose data was set * @param response the resulting Event outcome of the set data request * @param afterAction the action that should be performed after the request is processed * @param nextEvent indicates to the event queue that the next event can be processed * @param body hold the data that was sent in request */ processUnsuccessfulSetDataRequest(setTaskId, response, afterAction, nextEvent, context) { if (response.error !== '') { this._snackBar.openErrorSnackBar(this._translate.instant(response.error)); } else { this._snackBar.openErrorSnackBar(this._translate.instant('tasks.snackbar.failedSave')); } if (response.outcome) { const outcome = response.outcome; const changedFieldsMap = this._eventService.parseChangedFieldsFromOutcomeTree(outcome); if (Object.keys(changedFieldsMap).length > 0) { this._changedFieldsService.emitChangedFields(changedFieldsMap); } } this.revertToPreviousValue(context); this.clearWaitingForResponseFlag(context.body); this.updateStateInfo(afterAction, false, setTaskId); nextEvent.resolve(false); this._taskOperations.reload(); } /** * Processes a successful outcome of a `setData` request * @param setTaskId the ID of the task whose data was set * @param response the resulting Event outcome of the set data request * @param afterAction the action that should be performed after the request is processed * @param nextEvent indicates to the event queue that the next event can be processed * @param context hold the data that was sent in request */ processSuccessfulSetDataRequest(setTaskId, response, afterAction, nextEvent, context) { const outcome = response.outcome; const changedFieldsMap = this._eventService.parseChangedFieldsFromOutcomeTree(outcome); const frontActions = this._eventService.parseFrontActionsFromOutcomeTree(outcome); if (Object.keys(changedFieldsMap).length > 0) { this._changedFieldsService.emitChangedFields(changedFieldsMap); } if (frontActions?.length > 0) { this._frontActionService.runAll(frontActions); } this.clearWaitingForResponseFlag(context.body); this._snackBar.openSuccessSnackBar(!!outcome.message ? outcome.message : this._translate.instant('tasks.snackbar.dataSaved')); this.updateStateInfo(afterAction, true, setTaskId); nextEvent.resolve(true); } /** * Processes an erroneous outcome of a `setData` request * @param setTaskId the ID of the task whose data was set * @param error the returned error * @param afterAction the action that should be performed after the request is processed * @param nextEvent indicates to the event queue that the next event can be processed * @param body hold the data that was sent in request */ processErroneousSetDataRequest(setTaskId, error, afterAction, nextEvent, context) { this._log.debug('setting task data failed', error); if (!this.isTaskRelevant(setTaskId)) { this._log.debug('current task changed before the get data error could be received'); this._taskState.stopLoading(setTaskId); this._taskState.stopUpdating(setTaskId); afterAction.complete(); nextEvent.resolve(false); return; } this.revertToPreviousValue(context); this.clearWaitingForResponseFlag(context.body); this._snackBar.openErrorSnackBar(this._translate.instant('tasks.snackbar.failedSave')); this.updateStateInfo(afterAction, false, setTaskId); nextEvent.resolve(false); this._taskOperations.reload(); } /** * Reverts the effects of a failed `setData` request, so that the user sees current values. * @param context the context of the failed request */ revertSetDataRequest(context) { // this iteration could be improved if we had a map of all the data fields in a task const totalCount = Object.keys(context.body).length; let foundCount = 0; for (const datagroup of this._safeTask.dataGroups) { for (const field of datagroup.fields) { if (!context.body[field.stringId]) { continue; } if (this.compareBackendFormattedFieldValues(this._fieldConverterService.formatValueForBackend(field, field.value), context.body[field.stringId].value)) { field.valueWithoutChange(context.previousValues[field.stringId]); } foundCount++; if (foundCount === totalCount) { return; } } } this._log.error(`Invalid state. Some data fields of task ${this._safeTask.stringId}, are no longer present in it!`); } /** * Compares the values that are in the backend compatible format as given by the {@link FieldConverterService} * and determines whether they are the same value, or not. * @param current the current value (can also be called `value1` or `left`) * @param old the new value (can also be called `value2` or `right`) * @returns `true` if the values are the same and `false` otherwise */ compareBackendFormattedFieldValues(current, old) { if (Array.isArray(current)) { if (!Array.isArray(old)) { throw new Error('Illegal arguments! Cannot compare array value to non-array value'); } if (current.length !== old.length) { return false; } return current.every((value, index) => old[index] === value); } return current === old; } /** * @ignore * * stops loading and updating indicators, and emits the `result` value * to both the `afterAction` and [_updateSuccess$]{@link TaskDataService#_updateSuccess$} streams. * * @param afterAction the call chain steam of the update data method * @param result result of the update data request * @param setTaskId the ID of the {@link Task}, who's state should be updated */ updateStateInfo(afterAction, result, setTaskId) { this._taskState.stopLoading(setTaskId); this._taskState.stopUpdating(setTaskId); if (this._updateSuccess$.observers.length !== 0) { this._updateSuccess$.next(result); } this.sendNotification(TaskEvent.SET_DATA, result); afterAction.resolve(result); } /** * Publishes a get/set data notification to the {@link TaskEventService} * @param event the event that occurred to the task * @param success whether the get/set data operation was successful or not */ sendNotification(event, success) { this._taskEvent.publishTaskEvent(createTaskEventNotification(this._safeTask, event, success)); } revertToPreviousValue(context) { this._safeTask.dataGroups.forEach(dataGroup => { dataGroup.fields.forEach(field => { if (field.initialized && field.valid && Object.keys(context.previousValues)?.includes(field.stringId)) { field.revertToPreviousValue(); } }); }); } clearWaitingForResponseFlag(body) { Object.keys(body).forEach(taskId => { Object.keys(body[taskId]).forEach(fieldId => { this._taskContentService.taskFieldsIndex[taskId].fields[fieldId].waitingForResponse = false; }); }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TaskDataService, deps: [{ token: i1.TaskRequestStateService }, { token: i2.TranslateService }, { token: i3.LoggerService }, { token: i4.SnackBarService }, { token: i5.TaskResourceService }, { token: i6.FieldConverterService }, { token: i7.TaskEventService }, { token: NAE_TASK_OPERATIONS }, { token: i8.SelectedCaseService, optional: true }, { token: i9.TaskContentService }, { token: i10.CallChainService }, { token: i11.EventQueueService }, { token: i12.UserComparatorService }, { token: i13.EventService }, { token: i14.ChangedFieldsService }, { token: i15.FrontActionService }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TaskDataService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TaskDataService, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: i1.TaskRequestStateService }, { type: i2.TranslateService }, { type: i3.LoggerService }, { type: i4.SnackBarService }, { type: i5.TaskResourceService }, { type: i6.FieldConverterService }, { type: i7.TaskEventService }, { type: undefined, decorators: [{ type: Inject, args: [NAE_TASK_OPERATIONS] }] }, { type: i8.SelectedCaseService, decorators: [{ type: Optional }] }, { type: i9.TaskContentService }, { type: i10.CallChainService }, { type: i11.EventQueueService }, { type: i12.UserComparatorService }, { type: i13.EventService }, { type: i14.ChangedFieldsService }, { type: i15.FrontActionService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFzay1kYXRhLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZXRncmlmLWNvbXBvbmVudHMtY29yZS9zcmMvbGliL3Rhc2svc2VydmljZXMvdGFzay1kYXRhLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLE1BQU0sRUFBRSxVQUFVLEVBQWEsUUFBUSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQ3RFLE9BQU8sRUFBYSxPQUFPLEVBQWUsTUFBTSxNQUFNLENBQUM7QUFVdkQsT0FBTyxFQUFDLG1CQUFtQixFQUFDLE1BQU0seUJBQXlCLENBQUM7QUFDNUQsT0FBTyxFQUFDLG1CQUFtQixFQUFDLE1BQU0sMkNBQTJDLENBQUM7QUFFOUUsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0sc0JBQXNCLENBQUM7QUFDdkQsT0FBTyxFQUFDLFNBQVMsRUFBQyxNQUFNLGdEQUFnRCxDQUFDO0FBRXpFLE9BQU8sRUFBQyxhQUFhLEVBQUMsTUFBTSwwREFBMEQsQ0FBQztBQUN2RixPQUFPLEVBQUMsMkJBQTJCLEVBQUMsTUFBTSxrREFBa0QsQ0FBQztBQUM3RixPQUFPLEVBQUMsU0FBUyxFQUFDLE1BQU0scUNBQXFDLENBQUM7QUFJOUQsT0FBTyxFQUFDLElBQUksRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3BDLE9BQU8sRUFBQyx1QkFBdUIsRUFBQyxNQUFNLHNFQUFzRSxDQUFDO0FBRzdHLE9BQU8sRUFBQyxXQUFXLEVBQUMsTUFBTSxzQ0FBc0MsQ0FBQztBQUNqRSxPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0sdUNBQXVDLENBQUM7QUFRbEUsT0FBTyxFQUFDLGdCQUFnQixFQUFDLE1BQU0sOERBQThELENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRzlGOzs7R0FHRztBQUVILE1BQU0sT0FBTyxlQUFnQixTQUFRLG1CQUFtQjtJQUs5QjtJQUNBO0lBQ0E7SUFD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