@testgorilla/tgo-coding-test 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -2
- package/esm2022/index.mjs +12 -0
- package/esm2022/lib/components/code-editor/code-editor.component.mjs +335 -0
- package/esm2022/lib/components/code-editor/code-editor.service.mjs +72 -0
- package/esm2022/lib/components/code-editor/helpers/c-helper.mjs +40 -0
- package/esm2022/lib/components/code-editor/helpers/code-editor-helper.base.mjs +11 -0
- package/esm2022/lib/components/code-editor/helpers/code-editor-helper.model.mjs +2 -0
- package/esm2022/lib/components/code-editor/helpers/cpp-helper.mjs +41 -0
- package/esm2022/lib/components/code-editor/helpers/csharp-helper.mjs +42 -0
- package/esm2022/lib/components/code-editor/helpers/go-helper.mjs +42 -0
- package/esm2022/lib/components/code-editor/helpers/index.mjs +16 -0
- package/esm2022/lib/components/code-editor/helpers/java-helper.mjs +42 -0
- package/esm2022/lib/components/code-editor/helpers/javascript-helper.mjs +26 -0
- package/esm2022/lib/components/code-editor/helpers/kotlin-helper.mjs +42 -0
- package/esm2022/lib/components/code-editor/helpers/php-helper.mjs +26 -0
- package/esm2022/lib/components/code-editor/helpers/python-helper.mjs +26 -0
- package/esm2022/lib/components/code-editor/helpers/r-helper.mjs +26 -0
- package/esm2022/lib/components/code-editor/helpers/ruby-helper.mjs +26 -0
- package/esm2022/lib/components/code-editor/helpers/scala-helper.mjs +41 -0
- package/esm2022/lib/components/code-editor/helpers/sql-helper.mjs +34 -0
- package/esm2022/lib/components/code-editor/helpers/swift-helper.mjs +40 -0
- package/esm2022/lib/components/code-editor/helpers/typescript-helper.mjs +41 -0
- package/esm2022/lib/components/code-editor/models/code-editor.model.mjs +2 -0
- package/esm2022/lib/components/code-editor/models/coding-snapshot.model.mjs +2 -0
- package/esm2022/lib/components/coding-question/coding-question.component.mjs +126 -0
- package/esm2022/lib/components/coding-section/coding-section.component.mjs +188 -0
- package/esm2022/lib/components/common/truncated-text/truncated-text.component.mjs +38 -0
- package/esm2022/lib/components/configurations/configurations.component.mjs +97 -0
- package/esm2022/lib/components/instructions/instructions.component.mjs +139 -0
- package/esm2022/lib/components/panel/panel.component.mjs +34 -0
- package/esm2022/lib/components/runnable-editor/runnable-editor.component.mjs +169 -0
- package/esm2022/lib/components/tests/test-cases/test-cases.component.mjs +198 -0
- package/esm2022/lib/components/tests/test-cases-content/test-cases-content.component.mjs +96 -0
- package/esm2022/lib/components/tests/test-cases-status/test-cases-status.component.mjs +21 -0
- package/esm2022/lib/components/tests/test-results.component.mjs +127 -0
- package/esm2022/lib/components/tgo-coding-test/tgo-coding-test.component.mjs +280 -0
- package/esm2022/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.mjs +476 -0
- package/esm2022/lib/config/index.mjs +2 -0
- package/esm2022/lib/config/tgo-coding-test.config.mjs +2 -0
- package/esm2022/lib/config/tgo-coding-test.provider.mjs +34 -0
- package/esm2022/lib/config/tgo-coding-test.token.mjs +14 -0
- package/esm2022/lib/models/auto-saved-data.mjs +2 -0
- package/esm2022/lib/models/code-event.mjs +2 -0
- package/esm2022/lib/models/coderunner-execution-results.mjs +2 -0
- package/esm2022/lib/models/configs.mjs +2 -0
- package/esm2022/lib/models/language-change-action.mjs +2 -0
- package/esm2022/lib/models/lat-languages.mjs +3 -0
- package/esm2022/lib/models/mixpanel-events.mjs +2 -0
- package/esm2022/lib/models/mode.mjs +2 -0
- package/esm2022/lib/models/paste-data.mjs +2 -0
- package/esm2022/lib/models/programming-language.mjs +2 -0
- package/esm2022/lib/models/test-cases.mjs +7 -0
- package/esm2022/lib/models/theme.mjs +2 -0
- package/esm2022/lib/models/translations.mjs +2 -0
- package/esm2022/lib/models/view-mode.mjs +8 -0
- package/esm2022/lib/pipes/memoize-func.pipe.mjs +39 -0
- package/esm2022/lib/services/candidate-coding-test-services/candidature-api.service.mjs +19 -0
- package/esm2022/lib/services/candidate-coding-test-services/coderunner-api.service.mjs +58 -0
- package/esm2022/lib/services/candidate-coding-test-services/coding-test-tour.service.mjs +89 -0
- package/esm2022/lib/services/candidate-coding-test-services/coding-test.service.mjs +490 -0
- package/esm2022/lib/services/candidate-coding-test-services/index.mjs +5 -0
- package/esm2022/lib/services/coding-test-config.service.mjs +51 -0
- package/esm2022/lib/services/configurations.service.mjs +89 -0
- package/esm2022/lib/services/lib-coding-test.service.mjs +106 -0
- package/esm2022/lib/services/storage.service.mjs +624 -0
- package/esm2022/lib/services/test-cases.service.mjs +30 -0
- package/esm2022/lib/services/theme.service.mjs +36 -0
- package/esm2022/lib/utils/additional-languages/erlang.mjs +103 -0
- package/esm2022/lib/utils/resize-element.mjs +13 -0
- package/esm2022/lib/utils/time-to-ms.util.mjs +11 -0
- package/esm2022/shared/index.mjs +5 -0
- package/esm2022/shared/lib/components/audio-animation/audio-animation.component.mjs +114 -0
- package/esm2022/shared/lib/components/audio-animation/index.mjs +2 -0
- package/esm2022/shared/lib/components/index.mjs +3 -0
- package/esm2022/shared/lib/components/vimeo-video/index.mjs +2 -0
- package/esm2022/shared/lib/components/vimeo-video/vimeo-video.component.mjs +101 -0
- package/esm2022/shared/lib/models/answer.mjs +2 -0
- package/esm2022/shared/lib/models/assessment.mjs +2 -0
- package/esm2022/shared/lib/models/environment.mjs +2 -0
- package/esm2022/shared/lib/models/index.mjs +9 -0
- package/esm2022/shared/lib/models/question-component.mjs +2 -0
- package/esm2022/shared/lib/models/question.mjs +2 -0
- package/esm2022/shared/lib/models/test.mjs +2 -0
- package/esm2022/shared/lib/models/translations.mjs +2 -0
- package/esm2022/shared/lib/models/window.mjs +2 -0
- package/esm2022/shared/lib/services/api/api.service.mjs +97 -0
- package/esm2022/shared/lib/services/api/mocked-api.service.mjs +131 -0
- package/esm2022/shared/lib/services/environment/environment.service.mjs +13 -0
- package/esm2022/shared/lib/services/index.mjs +10 -0
- package/esm2022/shared/lib/services/localization/languages.model.mjs +19 -0
- package/esm2022/shared/lib/services/localization/transloco-lazy-module-utils.mjs +27 -0
- package/esm2022/shared/lib/services/localization/transloco-testing.module.mjs +11 -0
- package/esm2022/shared/lib/services/media/media.service.mjs +129 -0
- package/esm2022/shared/lib/services/mixpanel/mixpanel.service.mjs +30 -0
- package/esm2022/shared/lib/services/theme/theme.service.mjs +24 -0
- package/esm2022/shared/test-mocks/assessment-test.mock.mjs +112 -0
- package/esm2022/shared/test-mocks/index.mjs +3 -0
- package/esm2022/shared/test-mocks/tgo-ui.mock.mjs +39 -0
- package/esm2022/testgorilla-tgo-coding-test.mjs +5 -0
- package/fesm2022/testgorilla-tgo-coding-test.mjs +4526 -0
- package/fesm2022/testgorilla-tgo-coding-test.mjs.map +1 -0
- package/{src/index.ts → index.d.ts} +2 -19
- package/lib/components/code-editor/code-editor.component.d.ts +54 -0
- package/lib/components/code-editor/code-editor.service.d.ts +12 -0
- package/lib/components/code-editor/helpers/c-helper.d.ts +11 -0
- package/lib/components/code-editor/helpers/code-editor-helper.base.d.ts +8 -0
- package/lib/components/code-editor/helpers/code-editor-helper.model.d.ts +62 -0
- package/lib/components/code-editor/helpers/cpp-helper.d.ts +11 -0
- package/lib/components/code-editor/helpers/csharp-helper.d.ts +12 -0
- package/lib/components/code-editor/helpers/go-helper.d.ts +12 -0
- package/lib/components/code-editor/helpers/java-helper.d.ts +12 -0
- package/lib/components/code-editor/helpers/javascript-helper.d.ts +10 -0
- package/lib/components/code-editor/helpers/kotlin-helper.d.ts +12 -0
- package/lib/components/code-editor/helpers/php-helper.d.ts +10 -0
- package/lib/components/code-editor/helpers/python-helper.d.ts +10 -0
- package/lib/components/code-editor/helpers/r-helper.d.ts +10 -0
- package/lib/components/code-editor/helpers/ruby-helper.d.ts +10 -0
- package/lib/components/code-editor/helpers/scala-helper.d.ts +12 -0
- package/lib/components/code-editor/helpers/sql-helper.d.ts +10 -0
- package/lib/components/code-editor/helpers/swift-helper.d.ts +11 -0
- package/lib/components/code-editor/helpers/typescript-helper.d.ts +11 -0
- package/lib/components/code-editor/models/code-editor.model.d.ts +8 -0
- package/lib/components/code-editor/models/coding-snapshot.model.d.ts +4 -0
- package/lib/components/coding-question/coding-question.component.d.ts +45 -0
- package/lib/components/coding-section/coding-section.component.d.ts +52 -0
- package/lib/components/common/truncated-text/truncated-text.component.d.ts +13 -0
- package/lib/components/configurations/configurations.component.d.ts +40 -0
- package/lib/components/instructions/instructions.component.d.ts +48 -0
- package/lib/components/panel/panel.component.d.ts +12 -0
- package/lib/components/runnable-editor/runnable-editor.component.d.ts +53 -0
- package/lib/components/tests/test-cases/test-cases.component.d.ts +46 -0
- package/lib/components/tests/test-cases-content/test-cases-content.component.d.ts +26 -0
- package/lib/components/tests/test-cases-status/test-cases-status.component.d.ts +9 -0
- package/lib/components/tests/test-results.component.d.ts +33 -0
- package/lib/components/tgo-coding-test/tgo-coding-test.component.d.ts +69 -0
- package/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.d.ts +101 -0
- package/{src/lib/config/index.ts → lib/config/index.d.ts} +0 -1
- package/lib/config/tgo-coding-test.config.d.ts +24 -0
- package/{src/lib/config/tgo-coding-test.provider.ts → lib/config/tgo-coding-test.provider.d.ts} +6 -18
- package/lib/config/tgo-coding-test.token.d.ts +9 -0
- package/lib/models/auto-saved-data.d.ts +42 -0
- package/lib/models/code-event.d.ts +15 -0
- package/lib/models/coderunner-execution-results.d.ts +51 -0
- package/lib/models/configs.d.ts +15 -0
- package/lib/models/language-change-action.d.ts +4 -0
- package/lib/models/lat-languages.d.ts +8 -0
- package/lib/models/mixpanel-events.d.ts +3 -0
- package/lib/models/mode.d.ts +5 -0
- package/lib/models/paste-data.d.ts +4 -0
- package/lib/models/programming-language.d.ts +8 -0
- package/lib/models/test-cases.d.ts +67 -0
- package/lib/models/theme.d.ts +4 -0
- package/lib/models/translations.d.ts +1 -0
- package/lib/models/view-mode.d.ts +6 -0
- package/{src/lib/pipes/memoize-func.pipe.ts → lib/pipes/memoize-func.pipe.d.ts} +6 -14
- package/lib/services/candidate-coding-test-services/candidature-api.service.d.ts +10 -0
- package/lib/services/candidate-coding-test-services/coderunner-api.service.d.ts +18 -0
- package/lib/services/candidate-coding-test-services/coding-test-tour.service.d.ts +22 -0
- package/lib/services/candidate-coding-test-services/coding-test.service.d.ts +68 -0
- package/{src/lib/services/candidate-coding-test-services/index.ts → lib/services/candidate-coding-test-services/index.d.ts} +1 -1
- package/lib/services/coding-test-config.service.d.ts +38 -0
- package/lib/services/configurations.service.d.ts +37 -0
- package/lib/services/lib-coding-test.service.d.ts +69 -0
- package/lib/services/storage.service.d.ts +83 -0
- package/lib/services/test-cases.service.d.ts +12 -0
- package/lib/services/theme.service.d.ts +17 -0
- package/lib/utils/additional-languages/erlang.d.ts +37 -0
- package/lib/utils/resize-element.d.ts +2 -0
- package/lib/utils/time-to-ms.util.d.ts +1 -0
- package/package.json +18 -7
- package/shared/index.d.ts +4 -0
- package/shared/lib/components/audio-animation/audio-animation.component.d.ts +27 -0
- package/shared/lib/components/audio-animation/index.d.ts +1 -0
- package/shared/lib/components/index.d.ts +2 -0
- package/shared/lib/components/vimeo-video/index.d.ts +1 -0
- package/shared/lib/components/vimeo-video/vimeo-video.component.d.ts +24 -0
- package/shared/lib/models/answer.d.ts +17 -0
- package/shared/lib/models/assessment.d.ts +80 -0
- package/shared/lib/models/environment.d.ts +1 -0
- package/shared/lib/models/index.d.ts +8 -0
- package/shared/lib/models/question-component.d.ts +54 -0
- package/shared/lib/models/question.d.ts +102 -0
- package/shared/lib/models/test.d.ts +81 -0
- package/shared/lib/models/translations.d.ts +1 -0
- package/shared/lib/models/window.d.ts +6 -0
- package/shared/lib/services/api/api.service.d.ts +25 -0
- package/shared/lib/services/api/mocked-api.service.d.ts +35 -0
- package/shared/lib/services/environment/environment.service.d.ts +6 -0
- package/shared/lib/services/index.d.ts +9 -0
- package/shared/lib/services/localization/languages.model.d.ts +15 -0
- package/shared/lib/services/localization/transloco-lazy-module-utils.d.ts +11 -0
- package/shared/lib/services/localization/transloco-testing.module.d.ts +2 -0
- package/shared/lib/services/media/media.service.d.ts +29 -0
- package/shared/lib/services/mixpanel/mixpanel.service.d.ts +10 -0
- package/shared/lib/services/theme/theme.service.d.ts +8 -0
- package/shared/test-mocks/assessment-test.mock.d.ts +21 -0
- package/shared/test-mocks/index.d.ts +2 -0
- package/shared/test-mocks/tgo-ui.mock.d.ts +21 -0
- package/.eslintrc.json +0 -45
- package/jest.config.ts +0 -21
- package/ng-package.json +0 -14
- package/project.json +0 -36
- package/src/lib/components/.gitkeep +0 -0
- package/src/lib/components/code-editor/code-editor.component.html +0 -10
- package/src/lib/components/code-editor/code-editor.component.scss +0 -21
- package/src/lib/components/code-editor/code-editor.component.spec.ts +0 -136
- package/src/lib/components/code-editor/code-editor.component.ts +0 -369
- package/src/lib/components/code-editor/code-editor.mocks.ts +0 -28
- package/src/lib/components/code-editor/code-editor.service.spec.ts +0 -160
- package/src/lib/components/code-editor/code-editor.service.ts +0 -94
- package/src/lib/components/code-editor/helpers/c-helper.spec.ts +0 -39
- package/src/lib/components/code-editor/helpers/c-helper.ts +0 -51
- package/src/lib/components/code-editor/helpers/code-editor-helper.base.spec.ts +0 -30
- package/src/lib/components/code-editor/helpers/code-editor-helper.base.ts +0 -16
- package/src/lib/components/code-editor/helpers/code-editor-helper.mocks.ts +0 -24
- package/src/lib/components/code-editor/helpers/code-editor-helper.model.ts +0 -67
- package/src/lib/components/code-editor/helpers/cpp-helper.spec.ts +0 -40
- package/src/lib/components/code-editor/helpers/cpp-helper.ts +0 -52
- package/src/lib/components/code-editor/helpers/csharp-helper.spec.ts +0 -42
- package/src/lib/components/code-editor/helpers/csharp-helper.ts +0 -55
- package/src/lib/components/code-editor/helpers/go-helper.spec.ts +0 -41
- package/src/lib/components/code-editor/helpers/go-helper.ts +0 -54
- package/src/lib/components/code-editor/helpers/java-helper.spec.ts +0 -41
- package/src/lib/components/code-editor/helpers/java-helper.ts +0 -54
- package/src/lib/components/code-editor/helpers/javascript-helper.spec.ts +0 -39
- package/src/lib/components/code-editor/helpers/javascript-helper.ts +0 -32
- package/src/lib/components/code-editor/helpers/kotlin-helper.spec.ts +0 -41
- package/src/lib/components/code-editor/helpers/kotlin-helper.ts +0 -54
- package/src/lib/components/code-editor/helpers/php-helper.spec.ts +0 -39
- package/src/lib/components/code-editor/helpers/php-helper.ts +0 -32
- package/src/lib/components/code-editor/helpers/python-helper.spec.ts +0 -39
- package/src/lib/components/code-editor/helpers/python-helper.ts +0 -32
- package/src/lib/components/code-editor/helpers/r-helper.spec.ts +0 -39
- package/src/lib/components/code-editor/helpers/r-helper.ts +0 -32
- package/src/lib/components/code-editor/helpers/ruby-helper.spec.ts +0 -39
- package/src/lib/components/code-editor/helpers/ruby-helper.ts +0 -32
- package/src/lib/components/code-editor/helpers/scala-helper.spec.ts +0 -41
- package/src/lib/components/code-editor/helpers/scala-helper.ts +0 -53
- package/src/lib/components/code-editor/helpers/sql-helper.spec.ts +0 -87
- package/src/lib/components/code-editor/helpers/sql-helper.ts +0 -44
- package/src/lib/components/code-editor/helpers/swift-helper.spec.ts +0 -40
- package/src/lib/components/code-editor/helpers/swift-helper.ts +0 -51
- package/src/lib/components/code-editor/helpers/typescript-helper.spec.ts +0 -40
- package/src/lib/components/code-editor/helpers/typescript-helper.ts +0 -52
- package/src/lib/components/code-editor/models/code-editor.model.ts +0 -9
- package/src/lib/components/code-editor/models/coding-snapshot.model.ts +0 -4
- package/src/lib/components/coding-question/coding-question.component.html +0 -78
- package/src/lib/components/coding-question/coding-question.component.scss +0 -76
- package/src/lib/components/coding-question/coding-question.component.spec.ts +0 -85
- package/src/lib/components/coding-question/coding-question.component.ts +0 -102
- package/src/lib/components/coding-section/coding-section.component.html +0 -82
- package/src/lib/components/coding-section/coding-section.component.scss +0 -64
- package/src/lib/components/coding-section/coding-section.component.spec.ts +0 -257
- package/src/lib/components/coding-section/coding-section.component.ts +0 -187
- package/src/lib/components/coding-test.module.ts +0 -124
- package/src/lib/components/common/truncated-text/truncated-text.component.html +0 -6
- package/src/lib/components/common/truncated-text/truncated-text.component.scss +0 -18
- package/src/lib/components/common/truncated-text/truncated-text.component.spec.ts +0 -84
- package/src/lib/components/common/truncated-text/truncated-text.component.ts +0 -37
- package/src/lib/components/configurations/configurations.component.html +0 -57
- package/src/lib/components/configurations/configurations.component.scss +0 -42
- package/src/lib/components/configurations/configurations.component.spec.ts +0 -186
- package/src/lib/components/configurations/configurations.component.ts +0 -98
- package/src/lib/components/instructions/instructions.component.html +0 -41
- package/src/lib/components/instructions/instructions.component.scss +0 -167
- package/src/lib/components/instructions/instructions.component.spec.ts +0 -106
- package/src/lib/components/instructions/instructions.component.ts +0 -138
- package/src/lib/components/panel/panel.component.html +0 -19
- package/src/lib/components/panel/panel.component.scss +0 -41
- package/src/lib/components/panel/panel.component.spec.ts +0 -40
- package/src/lib/components/panel/panel.component.ts +0 -34
- package/src/lib/components/runnable-editor/runnable-editor.component.html +0 -75
- package/src/lib/components/runnable-editor/runnable-editor.component.scss +0 -55
- package/src/lib/components/runnable-editor/runnable-editor.component.spec.ts +0 -124
- package/src/lib/components/runnable-editor/runnable-editor.component.ts +0 -155
- package/src/lib/components/tests/test-cases/test-cases.component.html +0 -135
- package/src/lib/components/tests/test-cases/test-cases.component.scss +0 -220
- package/src/lib/components/tests/test-cases/test-cases.component.spec.ts +0 -401
- package/src/lib/components/tests/test-cases/test-cases.component.ts +0 -205
- package/src/lib/components/tests/test-cases-content/test-cases-content.component.html +0 -94
- package/src/lib/components/tests/test-cases-content/test-cases-content.component.scss +0 -103
- package/src/lib/components/tests/test-cases-content/test-cases-content.component.spec.ts +0 -122
- package/src/lib/components/tests/test-cases-content/test-cases-content.component.ts +0 -102
- package/src/lib/components/tests/test-cases-status/test-cases-status.component.html +0 -16
- package/src/lib/components/tests/test-cases-status/test-cases-status.component.scss +0 -49
- package/src/lib/components/tests/test-cases-status/test-cases-status.component.spec.ts +0 -22
- package/src/lib/components/tests/test-cases-status/test-cases-status.component.ts +0 -18
- package/src/lib/components/tests/test-results.component.html +0 -119
- package/src/lib/components/tests/test-results.component.scss +0 -189
- package/src/lib/components/tests/test-results.component.spec.ts +0 -140
- package/src/lib/components/tests/test-results.component.ts +0 -98
- package/src/lib/components/tgo-coding-test/tgo-coding-test.component.html +0 -96
- package/src/lib/components/tgo-coding-test/tgo-coding-test.component.scss +0 -6
- package/src/lib/components/tgo-coding-test/tgo-coding-test.component.spec.ts +0 -599
- package/src/lib/components/tgo-coding-test/tgo-coding-test.component.ts +0 -279
- package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.html +0 -36
- package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.scss +0 -183
- package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.spec.ts +0 -883
- package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.ts +0 -575
- package/src/lib/config/tgo-coding-test.config.ts +0 -26
- package/src/lib/config/tgo-coding-test.token.ts +0 -21
- package/src/lib/models/.gitkeep +0 -0
- package/src/lib/models/auto-saved-data.ts +0 -51
- package/src/lib/models/code-event.ts +0 -17
- package/src/lib/models/coderunner-execution-results.ts +0 -58
- package/src/lib/models/coding-lib.mocks.ts +0 -246
- package/src/lib/models/configs.ts +0 -18
- package/src/lib/models/language-change-action.ts +0 -4
- package/src/lib/models/lat-languages.ts +0 -12
- package/src/lib/models/mixpanel-events.ts +0 -3
- package/src/lib/models/mode.ts +0 -5
- package/src/lib/models/paste-data.ts +0 -4
- package/src/lib/models/programming-language.ts +0 -9
- package/src/lib/models/test-cases.ts +0 -74
- package/src/lib/models/theme.ts +0 -5
- package/src/lib/models/translations.ts +0 -1
- package/src/lib/models/view-mode.ts +0 -6
- package/src/lib/services/.gitkeep +0 -0
- package/src/lib/services/candidate-coding-test-services/candidature-api.service.spec.ts +0 -40
- package/src/lib/services/candidate-coding-test-services/candidature-api.service.ts +0 -15
- package/src/lib/services/candidate-coding-test-services/coderunner-api.service.spec.ts +0 -134
- package/src/lib/services/candidate-coding-test-services/coderunner-api.service.ts +0 -105
- package/src/lib/services/candidate-coding-test-services/coding-test-tour.service.spec.ts +0 -161
- package/src/lib/services/candidate-coding-test-services/coding-test-tour.service.ts +0 -100
- package/src/lib/services/candidate-coding-test-services/coding-test.service.spec.ts +0 -1524
- package/src/lib/services/candidate-coding-test-services/coding-test.service.ts +0 -843
- package/src/lib/services/coding-test-config.service.ts +0 -48
- package/src/lib/services/configurations.service.mocks.ts +0 -77
- package/src/lib/services/configurations.service.spec.ts +0 -79
- package/src/lib/services/configurations.service.ts +0 -111
- package/src/lib/services/index.ts +0 -0
- package/src/lib/services/lib-coding-test.service.spec.ts +0 -265
- package/src/lib/services/lib-coding-test.service.ts +0 -157
- package/src/lib/services/local-storage.service.mocks.ts +0 -22
- package/src/lib/services/storage.service.spec.ts +0 -1120
- package/src/lib/services/storage.service.ts +0 -729
- package/src/lib/services/test-cases.service.spec.ts +0 -53
- package/src/lib/services/test-cases.service.ts +0 -29
- package/src/lib/services/theme.service.spec.ts +0 -76
- package/src/lib/services/theme.service.ts +0 -34
- package/src/lib/styles/mixins.scss +0 -86
- package/src/lib/styles/styles.scss +0 -112
- package/src/lib/styles/variables.scss +0 -105
- package/src/lib/utils/.gitkeep +0 -0
- package/src/lib/utils/additional-languages/erlang.ts +0 -115
- package/src/lib/utils/resize-element.ts +0 -15
- package/src/lib/utils/time-to-ms.util.ts +0 -10
- package/src/test-setup.ts +0 -1
- package/tsconfig.json +0 -16
- package/tsconfig.lib.json +0 -12
- package/tsconfig.lib.prod.json +0 -9
- package/tsconfig.spec.json +0 -13
- /package/{src/assets → assets}/i18n/en.json +0 -0
- /package/{src/lib/components/code-editor/helpers/index.ts → lib/components/code-editor/helpers/index.d.ts} +0 -0
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { LocalStorageService } from 'ngx-webstorage';
|
|
3
|
+
import { filter } from 'rxjs';
|
|
4
|
+
import { AssessmentIdPreview } from '../models/lat-languages';
|
|
5
|
+
import { ConfigurationsService } from './configurations.service';
|
|
6
|
+
import { LibCodingTestService } from './lib-coding-test.service';
|
|
7
|
+
import { timeToMs } from '../utils/time-to-ms.util';
|
|
8
|
+
import * as i0 from "@angular/core";
|
|
9
|
+
import * as i1 from "ngx-webstorage";
|
|
10
|
+
import * as i2 from "./lib-coding-test.service";
|
|
11
|
+
import * as i3 from "./configurations.service";
|
|
12
|
+
export class StorageCodingService {
|
|
13
|
+
storage;
|
|
14
|
+
libCodingTestService;
|
|
15
|
+
configurationsService;
|
|
16
|
+
CURRENT_STORAGE_VERSION = 2;
|
|
17
|
+
autoSavedData = {
|
|
18
|
+
version: this.CURRENT_STORAGE_VERSION,
|
|
19
|
+
config: {},
|
|
20
|
+
isFullscreen: false,
|
|
21
|
+
assessments: {},
|
|
22
|
+
lastModified: Date.now(),
|
|
23
|
+
};
|
|
24
|
+
key = 'savedData';
|
|
25
|
+
assessmentId;
|
|
26
|
+
questionId;
|
|
27
|
+
language;
|
|
28
|
+
codeSaveEnabled;
|
|
29
|
+
testCasesSaveEnabled;
|
|
30
|
+
isLAT;
|
|
31
|
+
currentMode;
|
|
32
|
+
isPreview;
|
|
33
|
+
codeChangeSubscription;
|
|
34
|
+
configSubscription;
|
|
35
|
+
isFullscreenSubscription;
|
|
36
|
+
currentLanguageSubscription;
|
|
37
|
+
isCodeComponentAlive = filter(() => !this.configurationsService.getCodeComponentDestroyed());
|
|
38
|
+
// Maximum age of entire storage data in days
|
|
39
|
+
MAX_STORAGE_AGE_DAYS = 7;
|
|
40
|
+
// Maximum age for assessment inner data in days
|
|
41
|
+
MAX_QUESTION_DATA_AGE_DAYS = 1;
|
|
42
|
+
// Maximum number of assessments to keep
|
|
43
|
+
MAX_ASSESSMENTS = 10;
|
|
44
|
+
// The default question ID used for migrated v1 data
|
|
45
|
+
DEFAULT_MIGRATION_QUESTION_ID = 'default-question';
|
|
46
|
+
// todo: remove
|
|
47
|
+
// storage = {
|
|
48
|
+
// retrieve: (key: string) => {
|
|
49
|
+
// return {} as any;
|
|
50
|
+
// },
|
|
51
|
+
// store: (key: string, value: any) => {
|
|
52
|
+
// return {} as any;
|
|
53
|
+
// },
|
|
54
|
+
// clear: (key: string) => {
|
|
55
|
+
// return {} as any;
|
|
56
|
+
// },
|
|
57
|
+
// };
|
|
58
|
+
constructor(
|
|
59
|
+
// todo
|
|
60
|
+
storage, libCodingTestService, configurationsService) {
|
|
61
|
+
this.storage = storage;
|
|
62
|
+
this.libCodingTestService = libCodingTestService;
|
|
63
|
+
this.configurationsService = configurationsService;
|
|
64
|
+
// Perform safety check on localStorage data
|
|
65
|
+
this.performStorageSafetyCheck();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Performs a safety check on localStorage data.
|
|
69
|
+
* This is called at service initialization to ensure data integrity.
|
|
70
|
+
*/
|
|
71
|
+
performStorageSafetyCheck() {
|
|
72
|
+
try {
|
|
73
|
+
const savedData = this.storage.retrieve(this.key);
|
|
74
|
+
// If no data, nothing to check
|
|
75
|
+
if (!savedData) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Check storage format and migrate if needed
|
|
79
|
+
if (!('version' in savedData)) {
|
|
80
|
+
// It's v1 format, so we'll migrate it when it's actually needed
|
|
81
|
+
// No need to do anything right now
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
// It's v2 format, so we can perform cleanup right away
|
|
85
|
+
this.autoSavedData = savedData;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
// If any error occurs during safety check, reset storage to avoid issues
|
|
90
|
+
console.error('Error during storage safety check, resetting storage:', error);
|
|
91
|
+
this.autoSavedData = {
|
|
92
|
+
version: this.CURRENT_STORAGE_VERSION,
|
|
93
|
+
config: {},
|
|
94
|
+
isFullscreen: false,
|
|
95
|
+
assessments: {},
|
|
96
|
+
lastModified: Date.now(),
|
|
97
|
+
};
|
|
98
|
+
this.storeData();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
initializeSaving() {
|
|
102
|
+
if (!this.codeChangeSubscription) {
|
|
103
|
+
this.codeChangeSubscription = this.libCodingTestService.codeChange$
|
|
104
|
+
.pipe(this.isCodeComponentAlive)
|
|
105
|
+
.subscribe((code) => {
|
|
106
|
+
if (this.codeSaveEnabled && this.assessmentId && this.questionId) {
|
|
107
|
+
this.ensureDataStructure();
|
|
108
|
+
const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
|
|
109
|
+
const targetTestData = this.isPreview ? questionData.preview : questionData.actual;
|
|
110
|
+
targetTestData.code[this.language] = code;
|
|
111
|
+
this.updateLastModified(targetTestData);
|
|
112
|
+
this.storeData();
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
if (!this.configSubscription) {
|
|
117
|
+
this.configSubscription = this.configurationsService.config$
|
|
118
|
+
.pipe(this.isCodeComponentAlive)
|
|
119
|
+
.subscribe((config) => {
|
|
120
|
+
this.autoSavedData.config = { ...config };
|
|
121
|
+
this.updateLastModified(this.autoSavedData);
|
|
122
|
+
this.storeData();
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
if (!this.isFullscreenSubscription) {
|
|
126
|
+
this.isFullscreenSubscription = this.libCodingTestService.isFullscreen$
|
|
127
|
+
.pipe(this.isCodeComponentAlive)
|
|
128
|
+
.subscribe((isFullscreen) => {
|
|
129
|
+
this.autoSavedData.isFullscreen = isFullscreen;
|
|
130
|
+
this.updateLastModified(this.autoSavedData);
|
|
131
|
+
this.storeData();
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
if (!this.currentLanguageSubscription && this.isLAT) {
|
|
135
|
+
this.currentLanguageSubscription = this.libCodingTestService.currentLanguage$
|
|
136
|
+
.pipe(this.isCodeComponentAlive)
|
|
137
|
+
.subscribe((language) => {
|
|
138
|
+
this.autoSavedData.lastLanguageLAT = {
|
|
139
|
+
value: language,
|
|
140
|
+
version: this.libCodingTestService.getVersion(),
|
|
141
|
+
};
|
|
142
|
+
this.updateLastModified(this.autoSavedData);
|
|
143
|
+
this.storeData();
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
setupAutoSavedData(language, assessmentId, questionId, codeSaveEnabled, testCasesSaveEnabled, isLAT, mode) {
|
|
148
|
+
this.language = language;
|
|
149
|
+
this.assessmentId = assessmentId;
|
|
150
|
+
this.questionId = questionId;
|
|
151
|
+
this.codeSaveEnabled = codeSaveEnabled;
|
|
152
|
+
this.testCasesSaveEnabled = testCasesSaveEnabled;
|
|
153
|
+
this.isLAT = isLAT;
|
|
154
|
+
this.currentMode = mode;
|
|
155
|
+
this.isPreview = mode === "preview" /* Modes.Preview */ || mode === "non-assessment-preview" /* Modes.NonAssessmentPreview */;
|
|
156
|
+
// Get saved data
|
|
157
|
+
const savedData = this.storage.retrieve(this.key);
|
|
158
|
+
// Handle migration if needed
|
|
159
|
+
if (savedData) {
|
|
160
|
+
// Check if it's v1 schema (no version field)
|
|
161
|
+
if (!('version' in savedData)) {
|
|
162
|
+
this.migrateFromV1ToV2(savedData);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
this.autoSavedData = savedData;
|
|
166
|
+
}
|
|
167
|
+
// Apply loaded config and fullscreen setting
|
|
168
|
+
this.configurationsService.setConfig(this.autoSavedData.config);
|
|
169
|
+
this.libCodingTestService.setFullscreen(this.autoSavedData.isFullscreen);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
migrateFromV1ToV2(v1Data) {
|
|
173
|
+
// Create a new v2 data structure
|
|
174
|
+
const v2Data = {
|
|
175
|
+
version: this.CURRENT_STORAGE_VERSION,
|
|
176
|
+
config: v1Data.config,
|
|
177
|
+
isFullscreen: v1Data.isFullscreen,
|
|
178
|
+
lastLanguageLAT: v1Data.lastLanguageLAT,
|
|
179
|
+
assessments: {},
|
|
180
|
+
lastModified: Date.now(),
|
|
181
|
+
};
|
|
182
|
+
// Migrate assessment data
|
|
183
|
+
// In v1, assessments were directly mapped to TestData
|
|
184
|
+
// In v2, we need to organize by questionId
|
|
185
|
+
for (const [assessmentId, testData] of Object.entries(v1Data.assessments)) {
|
|
186
|
+
if (assessmentId === AssessmentIdPreview) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
// We use a consistent default questionId for migration to ensure backward compatibility
|
|
190
|
+
const defaultQuestionId = this.DEFAULT_MIGRATION_QUESTION_ID;
|
|
191
|
+
// Initialize the assessment entry if it doesn't exist
|
|
192
|
+
if (!v2Data.assessments[assessmentId]) {
|
|
193
|
+
v2Data.assessments[assessmentId] = {};
|
|
194
|
+
}
|
|
195
|
+
// Create question data with the migrated test data
|
|
196
|
+
const questionData = {};
|
|
197
|
+
questionData.actual = {
|
|
198
|
+
...testData,
|
|
199
|
+
lastModified: Date.now(),
|
|
200
|
+
};
|
|
201
|
+
// Set last modified time for the question data
|
|
202
|
+
questionData.lastModified = Date.now();
|
|
203
|
+
// Add to the v2 structure
|
|
204
|
+
v2Data.assessments[assessmentId][defaultQuestionId] = questionData;
|
|
205
|
+
}
|
|
206
|
+
// Update our instance with migrated data
|
|
207
|
+
this.autoSavedData = { ...v2Data };
|
|
208
|
+
// Save the migrated data
|
|
209
|
+
this.storeData();
|
|
210
|
+
}
|
|
211
|
+
ensureDataStructure() {
|
|
212
|
+
// Make sure assessment exists
|
|
213
|
+
if (!this.autoSavedData.assessments[this.assessmentId]) {
|
|
214
|
+
this.autoSavedData.assessments[this.assessmentId] = {};
|
|
215
|
+
}
|
|
216
|
+
// Make sure question exists
|
|
217
|
+
if (!this.autoSavedData.assessments[this.assessmentId][this.questionId]) {
|
|
218
|
+
this.autoSavedData.assessments[this.assessmentId][this.questionId] = {
|
|
219
|
+
lastModified: Date.now(),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
|
|
223
|
+
// Ensure preview or actual exists based on current mode
|
|
224
|
+
if (this.isPreview && !questionData.preview) {
|
|
225
|
+
questionData.preview = {
|
|
226
|
+
code: {},
|
|
227
|
+
testCasesLAT: [],
|
|
228
|
+
lastModified: Date.now(),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
else if (!this.isPreview && !questionData.actual) {
|
|
232
|
+
questionData.actual = {
|
|
233
|
+
code: {},
|
|
234
|
+
testCasesLAT: [],
|
|
235
|
+
lastModified: Date.now(),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
updateLastModified(data) {
|
|
240
|
+
const now = Date.now();
|
|
241
|
+
data.lastModified = now;
|
|
242
|
+
// If updating a TestData, also update its parent QuestionData
|
|
243
|
+
if ('code' in data && this.assessmentId && this.questionId) {
|
|
244
|
+
this.autoSavedData.assessments[this.assessmentId][this.questionId].lastModified = now;
|
|
245
|
+
}
|
|
246
|
+
// Always update root timestamp regardless of the object being modified
|
|
247
|
+
this.autoSavedData.lastModified = now;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Cleanup with a temporary age threshold
|
|
251
|
+
* @param maxAgeDays Maximum age in days for data to be considered valid
|
|
252
|
+
*/
|
|
253
|
+
cleanupWithReducedThreshold(maxAgeDays) {
|
|
254
|
+
// Call the unified cleanup method with more aggressive parameters
|
|
255
|
+
this.cleanupStorageData({
|
|
256
|
+
storageAgeMultiplier: 2, // More aggressive multiplier
|
|
257
|
+
customStorageAgeDays: maxAgeDays, // Use the provided custom age
|
|
258
|
+
minQuestionDataAgeDays: 0.5, // 12 hours minimum
|
|
259
|
+
assessmentLimitMultiplier: 0.5, // Half the normal assessment limit
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Unified method to clean up localStorage data with configurable intensity
|
|
264
|
+
* @param options Cleanup options to control the aggressiveness of the cleanup
|
|
265
|
+
*/
|
|
266
|
+
cleanupStorageData(options) {
|
|
267
|
+
const now = Date.now();
|
|
268
|
+
// Determine the storage age threshold
|
|
269
|
+
const storageAgeDays = options.customStorageAgeDays ?? this.MAX_STORAGE_AGE_DAYS;
|
|
270
|
+
const storageAgeThreshold = timeToMs(storageAgeDays); // Convert days to milliseconds
|
|
271
|
+
const multiplier = options.storageAgeMultiplier ?? 1;
|
|
272
|
+
// Check if the entire storage is too old and needs cleanup
|
|
273
|
+
if (this.autoSavedData.lastModified && now - this.autoSavedData.lastModified > storageAgeThreshold * multiplier) {
|
|
274
|
+
// If the entire storage is very old, just reset everything
|
|
275
|
+
this.autoSavedData = {
|
|
276
|
+
version: this.CURRENT_STORAGE_VERSION,
|
|
277
|
+
config: this.autoSavedData.config, // Keep the config settings
|
|
278
|
+
isFullscreen: this.autoSavedData.isFullscreen, // Keep fullscreen setting
|
|
279
|
+
assessments: {},
|
|
280
|
+
lastModified: now,
|
|
281
|
+
};
|
|
282
|
+
this.storeData();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const assessmentMetadata = [];
|
|
286
|
+
// Determine the question data age threshold
|
|
287
|
+
let questionDataAgeThreshold;
|
|
288
|
+
if (options.useStandardQuestionDataAge) {
|
|
289
|
+
// Use the standard threshold for normal cleanup
|
|
290
|
+
questionDataAgeThreshold = timeToMs(this.MAX_QUESTION_DATA_AGE_DAYS);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
// For maintenance/aggressive cleanup, use a custom threshold
|
|
294
|
+
const minAgeHours = (options.minQuestionDataAgeDays ?? 0.5) * 24; // Convert days to hours
|
|
295
|
+
questionDataAgeThreshold = Math.max(timeToMs(this.MAX_QUESTION_DATA_AGE_DAYS), // Standard age in milliseconds
|
|
296
|
+
timeToMs(minAgeHours, 'hours') // Minimum age in milliseconds
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
// Collect assessments with their latest modification times
|
|
300
|
+
for (const [assessmentId, questions] of Object.entries(this.autoSavedData.assessments)) {
|
|
301
|
+
let assessmentLastModified = 0;
|
|
302
|
+
// Check all questions in this assessment
|
|
303
|
+
let hasValidQuestions = false;
|
|
304
|
+
for (const [questionId, questionData] of Object.entries(questions)) {
|
|
305
|
+
// Skip if undefined
|
|
306
|
+
if (!questionData) {
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
// Get the latest modification time from preview and actual
|
|
310
|
+
const previewTime = questionData.preview?.lastModified || 0;
|
|
311
|
+
const actualTime = questionData.actual?.lastModified || 0;
|
|
312
|
+
const questionLastModified = Math.max(previewTime, actualTime, questionData.lastModified || 0);
|
|
313
|
+
// Check if data is too old - using configured threshold
|
|
314
|
+
const isPreviewTooOld = previewTime > 0 && now - previewTime > questionDataAgeThreshold;
|
|
315
|
+
const isActualTooOld = actualTime > 0 && now - actualTime > questionDataAgeThreshold;
|
|
316
|
+
// Clean up old data within the question
|
|
317
|
+
if (isPreviewTooOld && questionData.preview) {
|
|
318
|
+
delete questionData.preview;
|
|
319
|
+
}
|
|
320
|
+
if (isActualTooOld && questionData.actual) {
|
|
321
|
+
delete questionData.actual;
|
|
322
|
+
}
|
|
323
|
+
// If neither preview nor actual exists, remove the question
|
|
324
|
+
if (!questionData.preview && !questionData.actual) {
|
|
325
|
+
delete questions[questionId];
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
hasValidQuestions = true;
|
|
329
|
+
assessmentLastModified = Math.max(assessmentLastModified, questionLastModified);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// If no valid questions, remove the assessment
|
|
333
|
+
if (!hasValidQuestions) {
|
|
334
|
+
delete this.autoSavedData.assessments[assessmentId];
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
// Add to our list for potential size-based cleanup
|
|
338
|
+
assessmentMetadata.push({
|
|
339
|
+
id: assessmentId,
|
|
340
|
+
lastModified: assessmentLastModified,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
// Determine the assessment limit based on the multiplier
|
|
345
|
+
const limitMultiplier = options.assessmentLimitMultiplier ?? 1;
|
|
346
|
+
const assessmentLimit = Math.ceil(this.MAX_ASSESSMENTS * limitMultiplier);
|
|
347
|
+
// If we have too many assessments, remove the oldest ones
|
|
348
|
+
if (assessmentMetadata.length > assessmentLimit) {
|
|
349
|
+
// Sort by lastModified (most recent first)
|
|
350
|
+
assessmentMetadata.sort((a, b) => b.lastModified - a.lastModified);
|
|
351
|
+
// Remove oldest assessments that exceed our limit
|
|
352
|
+
for (let i = assessmentLimit; i < assessmentMetadata.length; i++) {
|
|
353
|
+
delete this.autoSavedData.assessments[assessmentMetadata[i].id];
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
// Save the cleaned data
|
|
357
|
+
this.storeData();
|
|
358
|
+
}
|
|
359
|
+
changeLanguage(language) {
|
|
360
|
+
this.language = language;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Gets data from v1 schema format
|
|
364
|
+
* Used for backward compatibility when retrieving data
|
|
365
|
+
*/
|
|
366
|
+
getDataFromV1Schema(retrievedData) {
|
|
367
|
+
// For v1, we need to handle the case where we don't have questionId
|
|
368
|
+
// We're now using questionId in the app, but stored data might still be in v1 format
|
|
369
|
+
// For preview data, the assessment ID would be AssessmentIdPreview
|
|
370
|
+
if (this.assessmentId === AssessmentIdPreview) {
|
|
371
|
+
if (this.isPreview) {
|
|
372
|
+
// For preview mode on preview assessment, get the code directly
|
|
373
|
+
const code = retrievedData.assessments[this.assessmentId]?.code;
|
|
374
|
+
if (code && this.language in code) {
|
|
375
|
+
return code[this.language];
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
// We don't expect actual/non-preview data for AssessmentIdPreview
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
// For regular assessments, v1 only had code in the "actual" section
|
|
383
|
+
if (!this.isPreview) {
|
|
384
|
+
const code = retrievedData.assessments[this.assessmentId]?.code;
|
|
385
|
+
if (code && this.language in code) {
|
|
386
|
+
return code[this.language];
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// We don't have preview data for regular assessments in v1
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
getSavedCode() {
|
|
394
|
+
const retrievedData = this.retrieveData();
|
|
395
|
+
if (!retrievedData) {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
// Check if using v2 schema
|
|
399
|
+
if ('version' in retrievedData) {
|
|
400
|
+
// Handle v2 schema
|
|
401
|
+
const v2Data = retrievedData;
|
|
402
|
+
const assessmentData = v2Data.assessments[this.assessmentId];
|
|
403
|
+
if (!assessmentData) {
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
// First try with provided questionId
|
|
407
|
+
if (this.questionId && assessmentData[this.questionId]) {
|
|
408
|
+
const questionData = assessmentData[this.questionId];
|
|
409
|
+
const testData = this.isPreview ? questionData.preview : questionData.actual;
|
|
410
|
+
if (testData?.code && this.language in testData.code) {
|
|
411
|
+
return testData.code[this.language];
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (this.questionId !== this.DEFAULT_MIGRATION_QUESTION_ID &&
|
|
415
|
+
assessmentData[this.DEFAULT_MIGRATION_QUESTION_ID]) {
|
|
416
|
+
const questionData = assessmentData[this.DEFAULT_MIGRATION_QUESTION_ID];
|
|
417
|
+
const testData = this.isPreview ? questionData.preview : questionData.actual;
|
|
418
|
+
if (testData?.code && this.language in testData.code) {
|
|
419
|
+
return testData.code[this.language];
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
// Handle v1 schema for backward compatibility
|
|
426
|
+
return this.getDataFromV1Schema(retrievedData);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
getLastLanguageLAT() {
|
|
430
|
+
const retrievedData = this.retrieveData();
|
|
431
|
+
if (!retrievedData) {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
return retrievedData.lastLanguageLAT || null;
|
|
435
|
+
}
|
|
436
|
+
getSavedTestCases() {
|
|
437
|
+
const retrievedData = this.retrieveData();
|
|
438
|
+
if (!retrievedData) {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
// Check if using v2 schema
|
|
442
|
+
if ('version' in retrievedData) {
|
|
443
|
+
// Handle v2 schema
|
|
444
|
+
const v2Data = retrievedData;
|
|
445
|
+
const assessmentData = v2Data.assessments[this.assessmentId];
|
|
446
|
+
if (!assessmentData) {
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
// First try with provided questionId
|
|
450
|
+
if (this.questionId && assessmentData[this.questionId]) {
|
|
451
|
+
const questionData = assessmentData[this.questionId];
|
|
452
|
+
const testData = this.isPreview ? questionData.preview : questionData.actual;
|
|
453
|
+
if (testData?.testCasesLAT) {
|
|
454
|
+
return testData.testCasesLAT;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
// If not found and questionId != DEFAULT_MIGRATION_QUESTION_ID,
|
|
458
|
+
// also try with the default migration ID as a fallback
|
|
459
|
+
if (this.questionId !== this.DEFAULT_MIGRATION_QUESTION_ID &&
|
|
460
|
+
assessmentData[this.DEFAULT_MIGRATION_QUESTION_ID]) {
|
|
461
|
+
const questionData = assessmentData[this.DEFAULT_MIGRATION_QUESTION_ID];
|
|
462
|
+
const testData = this.isPreview ? questionData.preview : questionData.actual;
|
|
463
|
+
if (testData?.testCasesLAT) {
|
|
464
|
+
return testData.testCasesLAT;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
// Handle v1 schema test cases (test cases were only in the actual mode)
|
|
471
|
+
const v1Data = retrievedData;
|
|
472
|
+
if (!this.isPreview && v1Data.assessments[this.assessmentId]?.testCasesLAT) {
|
|
473
|
+
return v1Data.assessments[this.assessmentId].testCasesLAT;
|
|
474
|
+
}
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
getSavedConfig() {
|
|
479
|
+
const retrievedData = this.retrieveData();
|
|
480
|
+
return retrievedData?.config ? { ...retrievedData.config } : null;
|
|
481
|
+
}
|
|
482
|
+
getSavedFullScreenMode() {
|
|
483
|
+
const retrievedData = this.retrieveData();
|
|
484
|
+
return retrievedData?.isFullscreen !== undefined ? retrievedData.isFullscreen : null;
|
|
485
|
+
}
|
|
486
|
+
clearSavedCode() {
|
|
487
|
+
this.ensureDataStructure();
|
|
488
|
+
const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
|
|
489
|
+
const targetTestData = this.isPreview ? [questionData.preview] : [questionData.preview, questionData.actual];
|
|
490
|
+
let hasChanged = false;
|
|
491
|
+
targetTestData.forEach(testData => {
|
|
492
|
+
if (testData) {
|
|
493
|
+
testData.code = {};
|
|
494
|
+
this.updateLastModified(testData);
|
|
495
|
+
hasChanged = true;
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
if (hasChanged) {
|
|
499
|
+
this.storeData();
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
clearLastLang() {
|
|
503
|
+
this.autoSavedData.lastLanguageLAT = null;
|
|
504
|
+
this.updateLastModified(this.autoSavedData);
|
|
505
|
+
this.storeData();
|
|
506
|
+
}
|
|
507
|
+
clearSavedTestCases() {
|
|
508
|
+
this.ensureDataStructure();
|
|
509
|
+
const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
|
|
510
|
+
const targetTestData = this.isPreview ? questionData.preview : questionData.actual;
|
|
511
|
+
if (targetTestData) {
|
|
512
|
+
const hasNoCode = !Object.keys(targetTestData.code ?? {}).length;
|
|
513
|
+
if (this.isPreview) {
|
|
514
|
+
targetTestData.testCasesLAT = [];
|
|
515
|
+
this.updateLastModified(targetTestData);
|
|
516
|
+
}
|
|
517
|
+
else if (hasNoCode) {
|
|
518
|
+
const allQuestions = this.autoSavedData.assessments[this.assessmentId];
|
|
519
|
+
delete allQuestions[this.questionId];
|
|
520
|
+
this.autoSavedData.assessments[this.assessmentId] = { ...allQuestions };
|
|
521
|
+
this.updateLastModified(this.autoSavedData);
|
|
522
|
+
}
|
|
523
|
+
this.storeData();
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
updateVersion(version) {
|
|
527
|
+
if (this.autoSavedData.lastLanguageLAT) {
|
|
528
|
+
this.autoSavedData.lastLanguageLAT.version = version;
|
|
529
|
+
this.updateLastModified(this.autoSavedData);
|
|
530
|
+
this.storeData();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
updateTestCases(testCases) {
|
|
534
|
+
if (this.assessmentId && this.questionId && this.testCasesSaveEnabled) {
|
|
535
|
+
this.ensureDataStructure();
|
|
536
|
+
const questionData = this.autoSavedData.assessments[this.assessmentId][this.questionId];
|
|
537
|
+
const targetTestData = this.isPreview ? questionData.preview : questionData.actual;
|
|
538
|
+
if (targetTestData) {
|
|
539
|
+
targetTestData.testCasesLAT = testCases;
|
|
540
|
+
this.updateLastModified(targetTestData);
|
|
541
|
+
this.storeData();
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
storeData() {
|
|
546
|
+
this.storage.store(this.key, this.autoSavedData);
|
|
547
|
+
}
|
|
548
|
+
retrieveData() {
|
|
549
|
+
return this.storage.retrieve(this.key);
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Manually triggers data cleanup and migration.
|
|
553
|
+
* Useful for handling large localStorage or migration when needed.
|
|
554
|
+
* This can be called from application startup or after major events.
|
|
555
|
+
*/
|
|
556
|
+
performMaintenanceAndCleanup() {
|
|
557
|
+
// Get current data
|
|
558
|
+
const savedData = this.storage.retrieve(this.key);
|
|
559
|
+
// If no data, nothing to do
|
|
560
|
+
if (!savedData) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
// Check if migration needed
|
|
564
|
+
if (!('version' in savedData)) {
|
|
565
|
+
this.migrateFromV1ToV2(savedData);
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
// Already migrated, just perform cleanup
|
|
569
|
+
this.autoSavedData = savedData;
|
|
570
|
+
// Perform a more aggressive cleanup for manual maintenance
|
|
571
|
+
// by temporarily modifying the cleanup thresholds
|
|
572
|
+
const originalMaxAge = this.MAX_STORAGE_AGE_DAYS;
|
|
573
|
+
const halfAge = Math.floor(originalMaxAge / 2); // Cut threshold in half
|
|
574
|
+
// Create a custom cleanup function with reduced threshold
|
|
575
|
+
this.cleanupWithReducedThreshold(halfAge);
|
|
576
|
+
}
|
|
577
|
+
// Verify localStorage size is manageable
|
|
578
|
+
try {
|
|
579
|
+
const serializedData = JSON.stringify(this.autoSavedData);
|
|
580
|
+
const sizeInKB = Math.round(serializedData.length / 1024);
|
|
581
|
+
// If data is too large (over 2MB), perform more aggressive cleanup
|
|
582
|
+
if (sizeInKB > 2048) {
|
|
583
|
+
console.warn(`Local storage data is large (${sizeInKB}KB), performing deep cleanup`);
|
|
584
|
+
// Use extremely aggressive cleanup settings
|
|
585
|
+
this.cleanupStorageData({
|
|
586
|
+
storageAgeMultiplier: 0.5, // Even more aggressive - half the normal age
|
|
587
|
+
minQuestionDataAgeDays: 0.25, // 6 hours minimum
|
|
588
|
+
assessmentLimitMultiplier: 0.2, // Keep only 20% of assessments
|
|
589
|
+
});
|
|
590
|
+
// If still too large, keep only a few most recent assessments
|
|
591
|
+
const newSerializedData = JSON.stringify(this.autoSavedData);
|
|
592
|
+
const newSizeInKB = Math.round(newSerializedData.length / 1024);
|
|
593
|
+
if (newSizeInKB > 1024) {
|
|
594
|
+
// Keep only recent assessments
|
|
595
|
+
const assessments = this.autoSavedData.assessments;
|
|
596
|
+
// Find the newest timestamp in each assessment
|
|
597
|
+
const getNewestTimestamp = (obj) => Object.values(obj).reduce((max, questionData) => Math.max(max, questionData?.lastModified || 0), 0);
|
|
598
|
+
const entries = Object.entries(assessments).sort(([, a], [, b]) => getNewestTimestamp(b) -
|
|
599
|
+
getNewestTimestamp(a));
|
|
600
|
+
// Keep only the 5 most recent assessments
|
|
601
|
+
const keepCount = Math.min(5, entries.length);
|
|
602
|
+
this.autoSavedData.assessments = {};
|
|
603
|
+
for (let i = 0; i < keepCount; i++) {
|
|
604
|
+
const [id, data] = entries[i];
|
|
605
|
+
this.autoSavedData.assessments[id] = data;
|
|
606
|
+
}
|
|
607
|
+
this.storeData();
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
catch (error) {
|
|
612
|
+
console.error('Error checking localStorage size', error);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StorageCodingService, deps: [{ token: i1.LocalStorageService }, { token: i2.LibCodingTestService }, { token: i3.ConfigurationsService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
616
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StorageCodingService, providedIn: 'root' });
|
|
617
|
+
}
|
|
618
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StorageCodingService, decorators: [{
|
|
619
|
+
type: Injectable,
|
|
620
|
+
args: [{
|
|
621
|
+
providedIn: 'root',
|
|
622
|
+
}]
|
|
623
|
+
}], ctorParameters: () => [{ type: i1.LocalStorageService }, { type: i2.LibCodingTestService }, { type: i3.ConfigurationsService }] });
|
|
624
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmFnZS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvdGdvLWNvZGluZy10ZXN0L3NyYy9saWIvc2VydmljZXMvc3RvcmFnZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDckQsT0FBTyxFQUFFLE1BQU0sRUFBZ0IsTUFBTSxNQUFNLENBQUM7QUFJNUMsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFHOUQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDakUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDakUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDBCQUEwQixDQUFDOzs7OztBQUtwRCxNQUFNLE9BQU8sb0JBQW9CO0lBZ0RyQjtJQUNBO0lBQ0E7SUFqRE8sdUJBQXVCLEdBQUcsQ0FBQyxDQUFDO0lBQ3JDLGFBQWEsR0FBa0I7UUFDckMsT0FBTyxFQUFFLElBQUksQ0FBQyx1QkFBdUI7UUFDckMsTUFBTSxFQUFFLEVBQVk7UUFDcEIsWUFBWSxFQUFFLEtBQUs7UUFDbkIsV0FBVyxFQUFFLEVBQUU7UUFDZixZQUFZLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRTtLQUN6QixDQUFDO0lBQ2UsR0FBRyxHQUFHLFdBQVcsQ0FBQztJQUMzQixZQUFZLENBQVM7SUFDckIsVUFBVSxDQUFTO0lBQ25CLFFBQVEsQ0FBc0I7SUFDOUIsZUFBZSxDQUFVO0lBQ3pCLG9CQUFvQixDQUFVO0lBQzlCLEtBQUssQ0FBVTtJQUNmLFdBQVcsQ0FBUTtJQUNuQixTQUFTLENBQVU7SUFDbkIsc0JBQXNCLENBQWU7SUFDckMsa0JBQWtCLENBQWU7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LENBQUMsYUFBYSxDQUFDLFdBQVcsR0FBRyxFQUFFLENBQUM7b0JBRXBDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQzt3QkFDbkMsTUFBTSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7d0JBQzlCLElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQW9DLENBQUM7b0JBQzVFLENBQUM7b0JBRUQsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsT0FBTyxDQUFDLEtBQUssQ0FBQyxrQ0FBa0MsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMzRCxDQUFDO0lBQ0gsQ0FBQzt3R0F2c0JVLG9CQUFvQjs0R0FBcEIsb0JBQW9CLGNBRm5CLE1BQU07OzRGQUVQLG9CQUFvQjtrQkFIaEMsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBMb2NhbFN0b3JhZ2VTZXJ2aWNlIH0gZnJvbSAnbmd4LXdlYnN0b3JhZ2UnO1xuaW1wb3J0IHsgZmlsdGVyLCBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IENvZGVFZGl0b3JMYW5ndWFnZXMgfSBmcm9tICcuLi9jb21wb25lbnRzL2NvZGUtZWRpdG9yL2hlbHBlcnMvY29kZS1lZGl0b3ItaGVscGVyLm1vZGVsJztcbmltcG9ydCB7IEF1dG9TYXZlZERhdGEsIEF1dG9TYXZlZERhdGFWMSwgQXV0b1NhdmVkRGF0YVYyLCBRdWVzdGlvbkRhdGEsIFRlc3REYXRhIH0gZnJvbSAnLi4vbW9kZWxzL2F1dG8tc2F2ZWQtZGF0YSc7XG5pbXBvcnQgeyBDb25maWcgfSBmcm9tICcuLi9tb2RlbHMvY29uZmlncyc7XG5pbXBvcnQgeyBBc3Nlc3NtZW50SWRQcmV2aWV3IH0gZnJvbSAnLi4vbW9kZWxzL2xhdC1sYW5ndWFnZXMnO1xuaW1wb3J0IHsgTW9kZXMgfSBmcm9tICcuLi9tb2RlbHMvbW9kZSc7XG5pbXBvcnQgeyBDdXN0b21UZXN0Q2FzZSwgRXhhbXBsZVRlc3RDYXNlIH0gZnJvbSAnLi4vbW9kZWxzL3Rlc3QtY2FzZXMnO1xuaW1wb3J0IHsgQ29uZmlndXJhdGlvbnNTZXJ2aWNlIH0gZnJvbSAnLi9jb25maWd1cmF0aW9ucy5zZXJ2aWNlJztcbmltcG9ydCB7IExpYkNvZGluZ1Rlc3RTZXJ2aWNlIH0gZnJvbSAnLi9saWItY29kaW5nLXRlc3Quc2VydmljZSc7XG5pbXBvcnQgeyB0aW1lVG9NcyB9IGZyb20gJy4uL3V0aWxzL3RpbWUtdG8tbXMudXRpbCc7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxufSlcbmV4cG9ydCBjbGFzcyBTdG9yYWdlQ29kaW5nU2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgQ1VSUkVOVF9TVE9SQUdFX1ZFUlNJT04gPSAyO1xuICBwcml2YXRlIGF1dG9TYXZlZERhdGE6IEF1dG9TYXZlZERhdGEgPSB7XG4gICAgdmVyc2lvbjogdGhpcy5DVVJSRU5UX1NUT1JBR0VfVkVSU0lPTixcbiAgICBjb25maWc6IHt9IGFzIENvbmZpZyxcbiAgICBpc0Z1bGxzY3JlZW46IGZhbHNlLFxuICAgIGFzc2Vzc21lbnRzOiB7fSxcbiAgICBsYXN0TW9kaWZpZWQ6IERhdGUubm93KCksXG4gIH07XG4gIHByaXZhdGUgcmVhZG9ubHkga2V5ID0gJ3NhdmVkRGF0YSc7XG4gIHByaXZhdGUgYXNzZXNzbWVudElkOiBzdHJpbmc7XG4gIHByaXZhdGUgcXVlc3Rpb25JZDogc3RyaW5nO1xuICBwcml2YXRlIGxhbmd1YWdlOiBDb2RlRWRpdG9yTGFuZ3VhZ2VzO1xuICBwcml2YXRlIGNvZGVTYXZlRW5hYmxlZDogYm9vbGVhbjtcbiAgcHJpdmF0ZSB0ZXN0Q2FzZXNTYXZlRW5hYmxlZDogYm9vbGVhbjtcbiAgcHJpdmF0ZSBpc0xBVDogYm9vbGVhbjtcbiAgcHJpdmF0ZSBjdXJyZW50TW9kZTogTW9kZXM7XG4gIHByaXZhdGUgaXNQcmV2aWV3OiBib29sZWFuO1xuICBwcml2YXRlIGNvZGVDaGFuZ2VTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBjb25maWdTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBpc0Z1bGxzY3JlZW5TdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBjdXJyZW50TGFuZ3VhZ2VTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBpc0NvZGVDb21wb25lbnRBbGl2ZSA9IGZpbHRlcigoKSA9PiAhdGhpcy5jb25maWd1cmF0aW9uc1NlcnZpY2UuZ2V0Q29kZUNvbXBvbmVudERlc3Ryb3llZCgpKTtcblxuICAvLyBNYXhpbXVtIGFnZSBvZiBlbnRpcmUgc3RvcmFnZSBkYXRhIGluIGRheXNcbiAgcHJpdmF0ZSByZWFkb25seSBNQVhfU1RPUkFHRV9BR0VfREFZUyA9IDc7XG4gIC8vIE1heGltdW0gYWdlIGZvciBhc3Nlc3NtZW50IGlubmVyIGRhdGEgaW4gZGF5c1xuICBwcml2YXRlIHJlYWRvbmx5IE1BWF9RVUVTVElPTl9EQVRBX0FHRV9EQVlTID0gMTtcbiAgLy8gTWF4aW11bSBudW1iZXIgb2YgYXNzZXNzbWVudHMgdG8ga2VlcFxuICBwcml2YXRlIHJlYWRvbmx5IE1BWF9BU1NFU1NNRU5UUyA9IDEwO1xuICAvLyBUaGUgZGVmYXVsdCBxdWVzdGlvbiBJRCB1c2VkIGZvciBtaWdyYXRlZCB2MSBkYXRhXG4gIHByaXZhdGUgcmVhZG9ubHkgREVGQVVMVF9NSUdSQVRJT05fUVVFU1RJT05fSUQgPSAnZGVmYXVsdC1xdWVzdGlvbic7XG5cbiAgLy8gdG9kbzogcmVtb3ZlXG4gIC8vIHN0b3JhZ2UgPSB7XG4gIC8vICAgcmV0cmlldmU6IChrZXk6IHN0cmluZykgPT4ge1xuICAvLyAgICAgcmV0dXJuIHt9IGFzIGFueTtcbiAgLy8gICB9LFxuICAvLyAgIHN0b3JlOiAoa2V5OiBzdHJpbmcsIHZhbHVlOiBhbnkpID0+IHtcbiAgLy8gICAgIHJldHVybiB7fSBhcyBhbnk7XG4gIC8vICAgfSxcbiAgLy8gICBjbGVhcjogKGtleTogc3RyaW5nKSA9PiB7XG4gIC8vICAgICByZXR1cm4ge30gYXMgYW55O1xuICAvLyAgIH0sXG4gIC8vIH07XG5cbiAgY29uc3RydWN0b3IoXG4gICAgLy8gdG9kb1xuICAgIHByaXZhdGUgc3RvcmFnZTogTG9jYWxTdG9yYWdlU2VydmljZSxcbiAgICBwcml2YXRlIGxpYkNvZGluZ1Rlc3RTZXJ2aWNlOiBMaWJDb2RpbmdUZXN0U2VydmljZSxcbiAgICBwcml2YXRlIGNvbmZpZ3VyYXRpb25zU2VydmljZTogQ29uZmlndXJhdGlvbnNTZXJ2aWNlXG4gICkge1xuICAgIC8vIFBlcmZvcm0gc2FmZXR5IGNoZWNrIG9uIGxvY2FsU3RvcmFnZSBkYXRhXG4gICAgdGhpcy5wZXJmb3JtU3RvcmFnZVNhZmV0eUNoZWNrKCk7XG4gIH1cblxuICAvKipcbiAgICogUGVyZm9ybXMgYSBzYWZldHkgY2hlY2sgb24gbG9jYWxTdG9yYWdlIGRhdGEuXG4gICAqIFRoaXMgaXMgY2FsbGVkIGF0IHNlcnZpY2UgaW5pdGlhbGl6YXRpb24gdG8gZW5zdXJlIGRhdGEgaW50ZWdyaXR5LlxuICAgKi9cbiAgcHJpdmF0ZSBwZXJmb3JtU3RvcmFnZVNhZmV0eUNoZWNrKCk6IHZvaWQge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzYXZlZERhdGEgPSB0aGlzLnN0b3JhZ2UucmV0cmlldmUodGhpcy5rZXkpO1xuXG4gICAgICAvLyBJZiBubyBkYXRhLCBub3RoaW5nIHRvIGNoZWNrXG4gICAgICBpZiAoIXNhdmVkRGF0YSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIENoZWNrIHN0b3JhZ2UgZm9ybWF0IGFuZCBtaWdyYXRlIGlmIG5lZWRlZFxuICAgICAgaWYgKCEoJ3ZlcnNpb24nIGluIHNhdmVkRGF0YSkpIHtcbiAgICAgICAgLy8gSXQncyB2MSBmb3JtYXQsIHNvIHdlJ2xsIG1pZ3JhdGUgaXQgd2hlbiBpdCdzIGFjdHVhbGx5IG5lZWRlZFxuICAgICAgICAvLyBObyBuZWVkIHRvIGRvIGFueXRoaW5nIHJpZ2h0IG5vd1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gSXQncyB2MiBmb3JtYXQsIHNvIHdlIGNhbiBwZXJmb3JtIGNsZWFudXAgcmlnaHQgYXdheVxuICAgICAgICB0aGlzLmF1dG9TYXZlZERhdGEgPSBzYXZlZERhdGEgYXMgQXV0b1NhdmVkRGF0YTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgLy8gSWYgYW55IGVycm9yIG9jY3VycyBkdXJpbmcgc2FmZXR5IGNoZWNrLCByZXNldCBzdG9yYWdlIHRvIGF2b2lkIGlzc3Vlc1xuICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgZHVyaW5nIHN0b3JhZ2Ugc2FmZXR5IGNoZWNrLCByZXNldHRpbmcgc3RvcmFnZTonLCBlcnJvcik7XG4gICAgICB0aGlzLmF1dG9TYXZlZERhdGEgPSB7XG4gICAgICAgIHZlcnNpb246IHRoaXMuQ1VSUkVOVF9TVE9SQUdFX1ZFUlNJT04sXG4gICAgICAgIGNvbmZpZzoge30gYXMgQ29uZmlnLFxuICAgICAgICBpc0Z1bGxzY3JlZW46IGZhbHNlLFxuICAgICAgICBhc3Nlc3NtZW50czoge30sXG4gICAgICAgIGxhc3RNb2RpZmllZDogRGF0ZS5ub3coKSxcbiAgICAgIH07XG4gICAgICB0aGlzLnN0b3JlRGF0YSgpO1xuICAgIH1cbiAgfVxuXG4gIGluaXRpYWxpemVTYXZpbmcoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmNvZGVDaGFuZ2VTdWJzY3JpcHRpb24pIHtcbiAgICAgIHRoaXMuY29kZUNoYW5nZVN1YnNjcmlwdGlvbiA9IHRoaXMubGliQ29kaW5nVGVzdFNlcnZpY2UuY29kZUNoYW5nZSRcbiAgICAgICAgLnBpcGUodGhpcy5pc0NvZGVDb21wb25lbnRBbGl2ZSlcbiAgICAgICAgLnN1YnNjcmliZSgoY29kZTogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgaWYgKHRoaXMuY29kZVNhdmVFbmFibGVkICYmIHRoaXMuYXNzZXNzbWVudElkICYmIHRoaXMucXVlc3Rpb25JZCkge1xuICAgICAgICAgICAgdGhpcy5lbnN1cmVEYXRhU3RydWN0dXJlKCk7XG4gICAgICAgICAgICBjb25zdCBxdWVzdGlvbkRhdGEgPSB0aGlzLmF1dG9TYXZlZERhdGEuYXNzZXNzbWVudHNbdGhpcy5hc3Nlc3NtZW50SWRdW3RoaXMucXVlc3Rpb25JZF07XG4gICAgICAgICAgICBjb25zdCB0YXJnZXRUZXN0RGF0YSA9IHRoaXMuaXNQcmV2aWV3ID8gcXVlc3Rpb25EYXRhLnByZXZpZXcgOiBxdWVzdGlvbkRhdGEuYWN0dWFsO1xuICAgICAgICAgICAgdGFyZ2V0VGVzdERhdGEuY29kZVt0aGlzLmxhbmd1YWdlXSA9IGNvZGUhO1xuICAgICAgICAgICAgdGhpcy51cGRhdGVMYXN0TW9kaWZpZWQodGFyZ2V0VGVzdERhdGEpO1xuICAgICAgICAgICAgdGhpcy5zdG9yZURhdGEoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5jb25maWdTdWJzY3JpcHRpb24pIHtcbiAgICAgIHRoaXMuY29uZmlnU3Vic2NyaXB0aW9uID0gdGhpcy5jb25maWd1cmF0aW9uc1NlcnZpY2UuY29uZmlnJFxuICAgICAgICAucGlwZSh0aGlzLmlzQ29kZUNvbXBvbmVudEFsaXZlKVxuICAgICAgICAuc3Vic2NyaWJlKChjb25maWc6IENvbmZpZykgPT4ge1xuICAgICAgICAgIHRoaXMuYXV0b1NhdmVkRGF0YS5jb25maWcgPSB7IC4uLmNvbmZpZyB9O1xuICAgICAgICAgIHRoaXMudXBkYXRlTGFzdE1vZGlmaWVkKHRoaXMuYXV0b1NhdmVkRGF0YSk7XG4gICAgICAgICAgdGhpcy5zdG9yZURhdGEoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmlzRnVsbHNjcmVlblN1YnNjcmlwdGlvbikge1xuICAgICAgdGhpcy5pc0Z1bGxzY3JlZW5TdWJzY3JpcHRpb24gPSB0aGlzLmxpYkNvZGluZ1Rlc3RTZXJ2aWNlLmlzRnVsbHNjcmVlbiRcbiAgICAgICAgLnBpcGUodGhpcy5pc0NvZGVDb21wb25lbnRBbGl2ZSlcbiAgICAgICAgLnN1YnNjcmliZSgoaXNGdWxsc2NyZWVuOiBib29sZWFuKSA9PiB7XG4gICAgICAgICAgdGhpcy5hdXRvU2F2ZWREYXRhLmlzRnVsbHNjcmVlbiA9IGlzRnVsbHNjcmVlbjtcbiAgICAgICAgICB0aGlzLnVwZGF0ZUxhc3RNb2RpZmllZCh0aGlzLmF1dG9TYXZlZERhdGEpO1xuICAgICAgICAgIHRoaXMuc3RvcmVEYXRhKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5jdXJyZW50TGFuZ3VhZ2VTdWJzY3JpcHRpb24gJiYgdGhpcy5pc0xBVCkge1xuICAgICAgdGhpcy5jdXJyZW50TGFuZ3VhZ2VTdWJzY3JpcHRpb24gPSB0aGlzLmxpYkNvZGluZ1Rlc3RTZXJ2aWNlLmN1cnJlbnRMYW5ndWFnZSRcbiAgICAgICAgLnBpcGUodGhpcy5pc0NvZGVDb21wb25lbnRBbGl2ZSlcbiAgICAgICAgLnN1YnNjcmliZSgobGFuZ3VhZ2U6IENvZGVFZGl0b3JMYW5ndWFnZXMpID0+IHtcbiAgICAgICAgICB0aGlzLmF1dG9TYXZlZERhdGEubGFzdExhbmd1YWdlTEFUID0ge1xuICAgICAgICAgICAgdmFsdWU6IGxhbmd1YWdlLFxuICAgICAgICAgICAgdmVyc2lvbjogdGhpcy5saWJDb2RpbmdUZXN0U2VydmljZS5nZXRWZXJzaW9uKCksXG4gICAgICAgICAgfTtcbiAgICAgICAgICB0aGlzLnVwZGF0ZUxhc3RNb2RpZmllZCh0aGlzLmF1dG9TYXZlZERhdGEpO1xuICAgICAgICAgIHRoaXMuc3RvcmVEYXRhKCk7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHNldHVwQXV0b1NhdmVkRGF0YShcbiAgICBsYW5ndWFnZTogQ29kZUVkaXRvckxhbmd1YWdlcyxcbiAgICBhc3Nlc3NtZW50SWQ6IHN0cmluZyxcbiAgICBxdWVzdGlvbklkOiBzdHJpbmcsXG4gICAgY29kZVNhdmVFbmFibGVkOiBib29sZWFuLFxuICAgIHRlc3RDYXNlc1NhdmVFbmFibGVkOiBib29sZWFuLFxuICAgIGlzTEFUOiBib29sZWFuLFxuICAgIG1vZGU6IE1vZGVzXG4gICkge1xuICAgIHRoaXMubGFuZ3VhZ2UgPSBsYW5ndWFnZTtcbiAgICB0aGlzLmFzc2Vzc21lbnRJZCA9IGFzc2Vzc21lbnRJZDtcbiAgICB0aGlzLnF1ZXN0aW9uSWQgPSBxdWVzdGlvbklkO1xuICAgIHRoaXMuY29kZVNhdmVFbmFibGVkID0gY29kZVNhdmVFbmFibGVkO1xuICAgIHRoaXMudGVzdENhc2VzU2F2ZUVuYWJsZWQgPSB0ZXN0Q2FzZXNTYXZlRW5hYmxlZDtcbiAgICB0aGlzLmlzTEFUID0gaXNMQVQ7XG4gICAgdGhpcy5jdXJyZW50TW9kZSA9IG1vZGU7XG4gICAgdGhpcy5pc1ByZXZpZXcgPSBtb2RlID09PSBNb2Rlcy5QcmV2aWV3IHx8IG1vZGUgPT09IE1vZGVzLk5vbkFzc2Vzc21lbnRQcmV2aWV3O1xuXG4gICAgLy8gR2V0IHNhdmVkIGRhdGFcbiAgICBjb25zdCBzYXZlZERhdGEgPSB0aGlzLnN0b3JhZ2UucmV0cmlldmUodGhpcy5rZXkpO1xuXG4gICAgLy8gSGFuZGxlIG1pZ3JhdGlvbiBpZiBuZWVkZWRcbiAgICBpZiAoc2F2ZWREYXRhKSB7XG4gICAgICAvLyBDaGVjayBpZiBpdCdzIHYxIHNjaGVtYSAobm8gdmVyc2lvbiBmaWVsZClcbiAgICAgIGlmICghKCd2ZXJzaW9uJyBpbiBzYXZlZERhdGEpKSB7XG4gICAgICAgIHRoaXMubWlncmF0ZUZyb21WMVRvVjIoc2F2ZWREYXRhIGFzIEF1dG9TYXZlZERhdGFWMSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmF1dG9TYXZlZERhdGEgPSBzYXZlZERhdGEgYXMgQXV0b1NhdmVkRGF0YTtcbiAgICAgIH1cblxuICAgICAgLy8gQXBwbHkgbG9hZGVkIGNvbmZpZyBhbmQgZnVsbHNjcmVlbiBzZXR0aW5nXG4gICAgICB0aGlzLmNvbmZpZ3VyYXRpb25zU2VydmljZS5zZXRDb25maWcodGhpcy5hdXRvU2F2ZWREYXRhLmNvbmZpZyk7XG4gICAgICB0aGlzLmxpYkNvZGluZ1Rlc3RTZXJ2aWNlLnNldEZ1bGxzY3JlZW4odGhpcy5hdXRvU2F2ZWREYXRhLmlzRnVsbHNjcmVlbik7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBtaWdyYXRlRnJvbVYxVG9WMih2MURhdGE6IEF1dG9TYXZlZERhdGFWMSk6IHZvaWQge1xuICAgIC8vIENyZWF0ZSBhIG5ldyB2MiBkYXRhIHN0cnVjdHVyZVxuICAgIGNvbnN0IHYyRGF0YTogQXV0b1NhdmVkRGF0YVYyID0ge1xuICAgICAgdmVyc2lvbjogdGhpcy5DVVJSRU5UX1NUT1JBR0VfVkVSU0lPTixcbiAgICAgIGNvbmZpZzogdjFEYXRhLmNvbmZpZyxcbiAgICAgIGlzRnVsbHNjcmVlbjogdjFEYXRhLmlzRnVsbHNjcmVlbixcbiAgICAgIGxhc3RMYW5ndWFnZUxBVDogdjFEYXRhLmxhc3RMYW5ndWFnZUxBVCxcbiAgICAgIGFzc2Vzc21lbnRzOiB7fSxcbiAgICAgIGxhc3RNb2RpZmllZDogRGF0ZS5ub3coKSxcbiAgICB9O1xuXG4gICAgLy8gTWlncmF0ZSBhc3Nlc3NtZW50IGRhdGFcbiAgICAvLyBJbiB2MSwgYXNzZXNzbWVudHMgd2VyZSBkaXJlY3RseSBtYXBwZWQgdG8gVGVzdERhdGFcbiAgICAvLyBJbiB2Miwgd2UgbmVlZCB0byBvcmdhbml6ZSBieSBxdWVzdGlvbklkXG4gICAgZm9yIChjb25zdCBbYXNzZXNzbWVudElkLCB0ZXN0RGF0YV0gb2YgT2JqZWN0LmVudHJpZXModjFEYXRhLmFzc2Vzc21lbnRzKSkge1xuICAgICAgaWYgKGFzc2Vzc21lbnRJZCA9PT0gQXNzZXNzbWVudElkUHJldmlldykge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgLy8gV2UgdXNlIGEgY29uc2lzdGVudCBkZWZhdWx0IHF1ZXN0aW9uSWQgZm9yIG1pZ3JhdGlvbiB0byBlbnN1cmUgYmFja3dhcmQgY29tcGF0aWJpbGl0eVxuICAgICAgY29uc3QgZGVmYXVsdFF1ZXN0aW9uSWQgPSB0aGlzLkRFRkFVTFRfTUlHUkFUSU9OX1FVRVNUSU9OX0lEO1xuXG4gICAgICAvLyBJbml0aWFsaXplIHRoZSBhc3Nlc3NtZW50IGVudHJ5IGlmIGl0IGRvZXNuJ3QgZXhpc3RcbiAgICAgIGlmICghdjJEYXRhLmFzc2Vzc21lbnRzW2Fzc2Vzc21lbnRJZF0pIHtcbiAgICAgICAgdjJEYXRhLmFzc2Vzc21lbnRzW2Fzc2Vzc21lbnRJZF0gPSB7fTtcbiAgICAgIH1cblxuICAgICAgLy8gQ3JlYXRlIHF1ZXN0aW9uIGRhdGEgd2l0aCB0aGUgbWlncmF0ZWQgdGVzdCBkYXRhXG4gICAgICBjb25zdCBxdWVzdGlvbkRhdGE6IFF1ZXN0aW9uRGF0YSA9IHt9O1xuXG4gICAgICBxdWVzdGlvbkRhdGEuYWN0dWFsID0ge1xuICAgICAgICAuLi50ZXN0RGF0YSxcbiAgICAgICAgbGFzdE1vZGlmaWVkOiBEYXRlLm5vdygpLFxuICAgICAgfTtcblxuICAgICAgLy8gU2V0IGxhc3QgbW9kaWZpZWQgdGltZSBmb3IgdGhlIHF1ZXN0aW9uIGRhdGFcbiAgICAgIHF1ZXN0aW9uRGF0YS5sYXN0TW9kaWZpZWQgPSBEYXRlLm5vdygpO1xuXG4gICAgICAvLyBBZGQgdG8gdGhlIHYyIHN0cnVjdHVyZVxuICAgICAgdjJEYXRhLmFzc2Vzc21lbnRzW2Fzc2Vzc21lbnRJZF1bZGVmYXVsdFF1ZXN0aW9uSWRdID0gcXVlc3Rpb25EYXRhO1xuICAgIH1cblxuICAgIC8vIFVwZGF0ZSBvdXIgaW5zdGFuY2Ugd2l0aCBtaWdyYXRlZCBkYXRhXG4gICAgdGhpcy5hdXRvU2F2ZWREYXRhID0geyAuLi52MkRhdGEgfTtcblxuICAgIC8vIFNhdmUgdGhlIG1pZ3JhdGVkIGRhdGFcbiAgICB0aGlzLnN0b3JlRGF0YSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBlbnN1cmVEYXRhU3RydWN0dXJlKCk6IHZvaWQge1xuICAgIC8vIE1ha2Ugc3VyZSBhc3Nlc3NtZW50IGV4aXN0c1xuICAgIGlmICghdGhpcy5hdXRvU2F2ZWREYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXSkge1xuICAgICAgdGhpcy5hdXRvU2F2ZWREYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXSA9IHt9O1xuICAgIH1cblxuICAgIC8vIE1ha2Ugc3VyZSBxdWVzdGlvbiBleGlzdHNcbiAgICBpZiAoIXRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50c1t0aGlzLmFzc2Vzc21lbnRJZF1bdGhpcy5xdWVzdGlvbklkXSkge1xuICAgICAgdGhpcy5hdXRvU2F2ZWREYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXVt0aGlzLnF1ZXN0aW9uSWRdID0ge1xuICAgICAgICBsYXN0TW9kaWZpZWQ6IERhdGUubm93KCksXG4gICAgICB9O1xuICAgIH1cblxuICAgIGNvbnN0IHF1ZXN0aW9uRGF0YSA9IHRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50c1t0aGlzLmFzc2Vzc21lbnRJZF1bdGhpcy5xdWVzdGlvbklkXTtcblxuICAgIC8vIEVuc3VyZSBwcmV2aWV3IG9yIGFjdHVhbCBleGlzdHMgYmFzZWQgb24gY3VycmVudCBtb2RlXG4gICAgaWYgKHRoaXMuaXNQcmV2aWV3ICYmICFxdWVzdGlvbkRhdGEucHJldmlldykge1xuICAgICAgcXVlc3Rpb25EYXRhLnByZXZpZXcgPSB7XG4gICAgICAgIGNvZGU6IHt9LFxuICAgICAgICB0ZXN0Q2FzZXNMQVQ6IFtdLFxuICAgICAgICBsYXN0TW9kaWZpZWQ6IERhdGUubm93KCksXG4gICAgICB9O1xuICAgIH0gZWxzZSBpZiAoIXRoaXMuaXNQcmV2aWV3ICYmICFxdWVzdGlvbkRhdGEuYWN0dWFsKSB7XG4gICAgICBxdWVzdGlvbkRhdGEuYWN0dWFsID0ge1xuICAgICAgICBjb2RlOiB7fSxcbiAgICAgICAgdGVzdENhc2VzTEFUOiBbXSxcbiAgICAgICAgbGFzdE1vZGlmaWVkOiBEYXRlLm5vdygpLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHVwZGF0ZUxhc3RNb2RpZmllZChkYXRhOiBUZXN0RGF0YSB8IFF1ZXN0aW9uRGF0YSB8IEF1dG9TYXZlZERhdGEpOiB2b2lkIHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGRhdGEubGFzdE1vZGlmaWVkID0gbm93O1xuXG4gICAgLy8gSWYgdXBkYXRpbmcgYSBUZXN0RGF0YSwgYWxzbyB1cGRhdGUgaXRzIHBhcmVudCBRdWVzdGlvbkRhdGFcbiAgICBpZiAoJ2NvZGUnIGluIGRhdGEgJiYgdGhpcy5hc3Nlc3NtZW50SWQgJiYgdGhpcy5xdWVzdGlvbklkKSB7XG4gICAgICB0aGlzLmF1dG9TYXZlZERhdGEuYXNzZXNzbWVudHNbdGhpcy5hc3Nlc3NtZW50SWRdW3RoaXMucXVlc3Rpb25JZF0ubGFzdE1vZGlmaWVkID0gbm93O1xuICAgIH1cblxuICAgIC8vIEFsd2F5cyB1cGRhdGUgcm9vdCB0aW1lc3RhbXAgcmVnYXJkbGVzcyBvZiB0aGUgb2JqZWN0IGJlaW5nIG1vZGlmaWVkXG4gICAgdGhpcy5hdXRvU2F2ZWREYXRhLmxhc3RNb2RpZmllZCA9IG5vdztcbiAgfVxuXG4gIC8qKlxuICAgKiBDbGVhbnVwIHdpdGggYSB0ZW1wb3JhcnkgYWdlIHRocmVzaG9sZFxuICAgKiBAcGFyYW0gbWF4QWdlRGF5cyBNYXhpbXVtIGFnZSBpbiBkYXlzIGZvciBkYXRhIHRvIGJlIGNvbnNpZGVyZWQgdmFsaWRcbiAgICovXG4gIHByaXZhdGUgY2xlYW51cFdpdGhSZWR1Y2VkVGhyZXNob2xkKG1heEFnZURheXM6IG51bWJlcik6IHZvaWQge1xuICAgIC8vIENhbGwgdGhlIHVuaWZpZWQgY2xlYW51cCBtZXRob2Qgd2l0aCBtb3JlIGFnZ3Jlc3NpdmUgcGFyYW1ldGVyc1xuICAgIHRoaXMuY2xlYW51cFN0b3JhZ2VEYXRhKHtcbiAgICAgIHN0b3JhZ2VBZ2VNdWx0aXBsaWVyOiAyLCAvLyBNb3JlIGFnZ3Jlc3NpdmUgbXVsdGlwbGllclxuICAgICAgY3VzdG9tU3RvcmFnZUFnZURheXM6IG1heEFnZURheXMsIC8vIFVzZSB0aGUgcHJvdmlkZWQgY3VzdG9tIGFnZVxuICAgICAgbWluUXVlc3Rpb25EYXRhQWdlRGF5czogMC41LCAvLyAxMiBob3VycyBtaW5pbXVtXG4gICAgICBhc3Nlc3NtZW50TGltaXRNdWx0aXBsaWVyOiAwLjUsIC8vIEhhbGYgdGhlIG5vcm1hbCBhc3Nlc3NtZW50IGxpbWl0XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVW5pZmllZCBtZXRob2QgdG8gY2xlYW4gdXAgbG9jYWxTdG9yYWdlIGRhdGEgd2l0aCBjb25maWd1cmFibGUgaW50ZW5zaXR5XG4gICAqIEBwYXJhbSBvcHRpb25zIENsZWFudXAgb3B0aW9ucyB0byBjb250cm9sIHRoZSBhZ2dyZXNzaXZlbmVzcyBvZiB0aGUgY2xlYW51cFxuICAgKi9cbiAgcHJpdmF0ZSBjbGVhbnVwU3RvcmFnZURhdGEob3B0aW9uczoge1xuICAgIHN0b3JhZ2VBZ2VNdWx0aXBsaWVyPzogbnVtYmVyOyAvLyBNdWx0aXBsaWVyIGZvciBzdG9yYWdlIGFnZSB0aHJlc2hvbGQgKGRlZmF1bHQ6IDEpXG4gICAgY3VzdG9tU3RvcmFnZUFnZURheXM/OiBudW1iZXI7IC8vIEN1c3RvbSBzdG9yYWdlIGFnZSBpbiBkYXlzIChvdmVycmlkZXMgTUFYX1NUT1JBR0VfQUdFX0RBWVMgaWYgcHJvdmlkZWQpXG4gICAgdXNlU3RhbmRhcmRRdWVzdGlvbkRhdGFBZ2U/OiBib29sZWFuOyAvLyBXaGV0aGVyIHRvIHVzZSBzdGFuZGFyZCBxdWVzdGlvbiBkYXRhIGFnZSAoZGVmYXVsdDogZmFsc2UpXG4gICAgbWluUXVlc3Rpb25EYXRhQWdlRGF5cz86IG51bWJlcjsgLy8gTWluaW11bSBhZ2UgZm9yIHF1ZXN0aW9uIGRhdGEgaW4gZGF5cyAoZGVmYXVsdDogMC41IC0gMTIgaG91cnMpXG4gICAgYXNzZXNzbWVudExpbWl0TXVsdGlwbGllcj86IG51bWJlcjsgLy8gTXVsdGlwbGllciBmb3IgbWF4aW11bSBhc3Nlc3NtZW50cyAoZGVmYXVsdDogMSlcbiAgfSk6IHZvaWQge1xuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG5cbiAgICAvLyBEZXRlcm1pbmUgdGhlIHN0b3JhZ2UgYWdlIHRocmVzaG9sZFxuICAgIGNvbnN0IHN0b3JhZ2VBZ2VEYXlzID0gb3B0aW9ucy5jdXN0b21TdG9yYWdlQWdlRGF5cyA/PyB0aGlzLk1BWF9TVE9SQUdFX0FHRV9EQVlTO1xuICAgIGNvbnN0IHN0b3JhZ2VBZ2VUaHJlc2hvbGQgPSB0aW1lVG9NcyhzdG9yYWdlQWdlRGF5cyk7IC8vIENvbnZlcnQgZGF5cyB0byBtaWxsaXNlY29uZHNcbiAgICBjb25zdCBtdWx0aXBsaWVyID0gb3B0aW9ucy5zdG9yYWdlQWdlTXVsdGlwbGllciA/PyAxO1xuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIGVudGlyZSBzdG9yYWdlIGlzIHRvbyBvbGQgYW5kIG5lZWRzIGNsZWFudXBcbiAgICBpZiAodGhpcy5hdXRvU2F2ZWREYXRhLmxhc3RNb2RpZmllZCAmJiBub3cgLSB0aGlzLmF1dG9TYXZlZERhdGEubGFzdE1vZGlmaWVkID4gc3RvcmFnZUFnZVRocmVzaG9sZCAqIG11bHRpcGxpZXIpIHtcbiAgICAgIC8vIElmIHRoZSBlbnRpcmUgc3RvcmFnZSBpcyB2ZXJ5IG9sZCwganVzdCByZXNldCBldmVyeXRoaW5nXG4gICAgICB0aGlzLmF1dG9TYXZlZERhdGEgPSB7XG4gICAgICAgIHZlcnNpb246IHRoaXMuQ1VSUkVOVF9TVE9SQUdFX1ZFUlNJT04sXG4gICAgICAgIGNvbmZpZzogdGhpcy5hdXRvU2F2ZWREYXRhLmNvbmZpZywgLy8gS2VlcCB0aGUgY29uZmlnIHNldHRpbmdzXG4gICAgICAgIGlzRnVsbHNjcmVlbjogdGhpcy5hdXRvU2F2ZWREYXRhLmlzRnVsbHNjcmVlbiwgLy8gS2VlcCBmdWxsc2NyZWVuIHNldHRpbmdcbiAgICAgICAgYXNzZXNzbWVudHM6IHt9LFxuICAgICAgICBsYXN0TW9kaWZpZWQ6IG5vdyxcbiAgICAgIH07XG4gICAgICB0aGlzLnN0b3JlRGF0YSgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIFN0cnVjdHVyZSBmb3IgY29sbGVjdGluZyBhc3Nlc3NtZW50IGRhdGEgd2l0aCBtZXRhZGF0YVxuICAgIGludGVyZmFjZSBBc3Nlc3NtZW50TWV0YWRhdGEge1xuICAgICAgaWQ6IHN0cmluZztcbiAgICAgIGxhc3RNb2RpZmllZDogbnVtYmVyO1xuICAgIH1cblxuICAgIGNvbnN0IGFzc2Vzc21lbnRNZXRhZGF0YTogQXNzZXNzbWVudE1ldGFkYXRhW10gPSBbXTtcblxuICAgIC8vIERldGVybWluZSB0aGUgcXVlc3Rpb24gZGF0YSBhZ2UgdGhyZXNob2xkXG4gICAgbGV0IHF1ZXN0aW9uRGF0YUFnZVRocmVzaG9sZDogbnVtYmVyO1xuICAgIGlmIChvcHRpb25zLnVzZVN0YW5kYXJkUXVlc3Rpb25EYXRhQWdlKSB7XG4gICAgICAvLyBVc2UgdGhlIHN0YW5kYXJkIHRocmVzaG9sZCBmb3Igbm9ybWFsIGNsZWFudXBcbiAgICAgIHF1ZXN0aW9uRGF0YUFnZVRocmVzaG9sZCA9IHRpbWVUb01zKHRoaXMuTUFYX1FVRVNUSU9OX0RBVEFfQUdFX0RBWVMpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBGb3IgbWFpbnRlbmFuY2UvYWdncmVzc2l2ZSBjbGVhbnVwLCB1c2UgYSBjdXN0b20gdGhyZXNob2xkXG4gICAgICBjb25zdCBtaW5BZ2VIb3VycyA9IChvcHRpb25zLm1pblF1ZXN0aW9uRGF0YUFnZURheXMgPz8gMC41KSAqIDI0OyAvLyBDb252ZXJ0IGRheXMgdG8gaG91cnNcbiAgICAgIHF1ZXN0aW9uRGF0YUFnZVRocmVzaG9sZCA9IE1hdGgubWF4KFxuICAgICAgICB0aW1lVG9Ncyh0aGlzLk1BWF9RVUVTVElPTl9EQVRBX0FHRV9EQVlTKSwgLy8gU3RhbmRhcmQgYWdlIGluIG1pbGxpc2Vjb25kc1xuICAgICAgICB0aW1lVG9NcyhtaW5BZ2VIb3VycywgJ2hvdXJzJykgLy8gTWluaW11bSBhZ2UgaW4gbWlsbGlzZWNvbmRzXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIENvbGxlY3QgYXNzZXNzbWVudHMgd2l0aCB0aGVpciBsYXRlc3QgbW9kaWZpY2F0aW9uIHRpbWVzXG4gICAgZm9yIChjb25zdCBbYXNzZXNzbWVudElkLCBxdWVzdGlvbnNdIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50cykpIHtcbiAgICAgIGxldCBhc3Nlc3NtZW50TGFzdE1vZGlmaWVkID0gMDtcblxuICAgICAgLy8gQ2hlY2sgYWxsIHF1ZXN0aW9ucyBpbiB0aGlzIGFzc2Vzc21lbnRcbiAgICAgIGxldCBoYXNWYWxpZFF1ZXN0aW9ucyA9IGZhbHNlO1xuXG4gICAgICBmb3IgKGNvbnN0IFtxdWVzdGlvbklkLCBxdWVzdGlvbkRhdGFdIG9mIE9iamVjdC5lbnRyaWVzKHF1ZXN0aW9ucykpIHtcbiAgICAgICAgLy8gU2tpcCBpZiB1bmRlZmluZWRcbiAgICAgICAgaWYgKCFxdWVzdGlvbkRhdGEpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEdldCB0aGUgbGF0ZXN0IG1vZGlmaWNhdGlvbiB0aW1lIGZyb20gcHJldmlldyBhbmQgYWN0dWFsXG4gICAgICAgIGNvbnN0IHByZXZpZXdUaW1lID0gcXVlc3Rpb25EYXRhLnByZXZpZXc/Lmxhc3RNb2RpZmllZCB8fCAwO1xuICAgICAgICBjb25zdCBhY3R1YWxUaW1lID0gcXVlc3Rpb25EYXRhLmFjdHVhbD8ubGFzdE1vZGlmaWVkIHx8IDA7XG4gICAgICAgIGNvbnN0IHF1ZXN0aW9uTGFzdE1vZGlmaWVkID0gTWF0aC5tYXgocHJldmlld1RpbWUsIGFjdHVhbFRpbWUsIHF1ZXN0aW9uRGF0YS5sYXN0TW9kaWZpZWQgfHwgMCk7XG5cbiAgICAgICAgLy8gQ2hlY2sgaWYgZGF0YSBpcyB0b28gb2xkIC0gdXNpbmcgY29uZmlndXJlZCB0aHJlc2hvbGRcbiAgICAgICAgY29uc3QgaXNQcmV2aWV3VG9vT2xkID0gcHJldmlld1RpbWUgPiAwICYmIG5vdyAtIHByZXZpZXdUaW1lID4gcXVlc3Rpb25EYXRhQWdlVGhyZXNob2xkO1xuICAgICAgICBjb25zdCBpc0FjdHVhbFRvb09sZCA9IGFjdHVhbFRpbWUgPiAwICYmIG5vdyAtIGFjdHVhbFRpbWUgPiBxdWVzdGlvbkRhdGFBZ2VUaHJlc2hvbGQ7XG5cbiAgICAgICAgLy8gQ2xlYW4gdXAgb2xkIGRhdGEgd2l0aGluIHRoZSBxdWVzdGlvblxuICAgICAgICBpZiAoaXNQcmV2aWV3VG9vT2xkICYmIHF1ZXN0aW9uRGF0YS5wcmV2aWV3KSB7XG4gICAgICAgICAgZGVsZXRlIHF1ZXN0aW9uRGF0YS5wcmV2aWV3O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzQWN0dWFsVG9vT2xkICYmIHF1ZXN0aW9uRGF0YS5hY3R1YWwpIHtcbiAgICAgICAgICBkZWxldGUgcXVlc3Rpb25EYXRhLmFjdHVhbDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIG5laXRoZXIgcHJldmlldyBub3IgYWN0dWFsIGV4aXN0cywgcmVtb3ZlIHRoZSBxdWVzdGlvblxuICAgICAgICBpZiAoIXF1ZXN0aW9uRGF0YS5wcmV2aWV3ICYmICFxdWVzdGlvbkRhdGEuYWN0dWFsKSB7XG4gICAgICAgICAgZGVsZXRlIHF1ZXN0aW9uc1txdWVzdGlvbklkXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBoYXNWYWxpZFF1ZXN0aW9ucyA9IHRydWU7XG4gICAgICAgICAgYXNzZXNzbWVudExhc3RNb2RpZmllZCA9IE1hdGgubWF4KGFzc2Vzc21lbnRMYXN0TW9kaWZpZWQsIHF1ZXN0aW9uTGFzdE1vZGlmaWVkKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBJZiBubyB2YWxpZCBxdWVzdGlvbnMsIHJlbW92ZSB0aGUgYXNzZXNzbWVudFxuICAgICAgaWYgKCFoYXNWYWxpZFF1ZXN0aW9ucykge1xuICAgICAgICBkZWxldGUgdGhpcy5hdXRvU2F2ZWREYXRhLmFzc2Vzc21lbnRzW2Fzc2Vzc21lbnRJZF07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBBZGQgdG8gb3VyIGxpc3QgZm9yIHBvdGVudGlhbCBzaXplLWJhc2VkIGNsZWFudXBcbiAgICAgICAgYXNzZXNzbWVudE1ldGFkYXRhLnB1c2goe1xuICAgICAgICAgIGlkOiBhc3Nlc3NtZW50SWQsXG4gICAgICAgICAgbGFzdE1vZGlmaWVkOiBhc3Nlc3NtZW50TGFzdE1vZGlmaWVkLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBEZXRlcm1pbmUgdGhlIGFzc2Vzc21lbnQgbGltaXQgYmFzZWQgb24gdGhlIG11bHRpcGxpZXJcbiAgICBjb25zdCBsaW1pdE11bHRpcGxpZXIgPSBvcHRpb25zLmFzc2Vzc21lbnRMaW1pdE11bHRpcGxpZXIgPz8gMTtcbiAgICBjb25zdCBhc3Nlc3NtZW50TGltaXQgPSBNYXRoLmNlaWwodGhpcy5NQVhfQVNTRVNTTUVOVFMgKiBsaW1pdE11bHRpcGxpZXIpO1xuXG4gICAgLy8gSWYgd2UgaGF2ZSB0b28gbWFueSBhc3Nlc3NtZW50cywgcmVtb3ZlIHRoZSBvbGRlc3Qgb25lc1xuICAgIGlmIChhc3Nlc3NtZW50TWV0YWRhdGEubGVuZ3RoID4gYXNzZXNzbWVudExpbWl0KSB7XG4gICAgICAvLyBTb3J0IGJ5IGxhc3RNb2RpZmllZCAobW9zdCByZWNlbnQgZmlyc3QpXG4gICAgICBhc3Nlc3NtZW50TWV0YWRhdGEuc29ydCgoYSwgYikgPT4gYi5sYXN0TW9kaWZpZWQgLSBhLmxhc3RNb2RpZmllZCk7XG5cbiAgICAgIC8vIFJlbW92ZSBvbGRlc3QgYXNzZXNzbWVudHMgdGhhdCBleGNlZWQgb3VyIGxpbWl0XG4gICAgICBmb3IgKGxldCBpID0gYXNzZXNzbWVudExpbWl0OyBpIDwgYXNzZXNzbWVudE1ldGFkYXRhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGRlbGV0ZSB0aGlzLmF1dG9TYXZlZERhdGEuYXNzZXNzbWVudHNbYXNzZXNzbWVudE1ldGFkYXRhW2ldLmlkXTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBTYXZlIHRoZSBjbGVhbmVkIGRhdGFcbiAgICB0aGlzLnN0b3JlRGF0YSgpO1xuICB9XG5cbiAgY2hhbmdlTGFuZ3VhZ2UobGFuZ3VhZ2U6IENvZGVFZGl0b3JMYW5ndWFnZXMpIHtcbiAgICB0aGlzLmxhbmd1YWdlID0gbGFuZ3VhZ2U7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBkYXRhIGZyb20gdjEgc2NoZW1hIGZvcm1hdFxuICAgKiBVc2VkIGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5IHdoZW4gcmV0cmlldmluZyBkYXRhXG4gICAqL1xuICBwcml2YXRlIGdldERhdGFGcm9tVjFTY2hlbWEocmV0cmlldmVkRGF0YTogQXV0b1NhdmVkRGF0YVYxKTogc3RyaW5nIHwgKEV4YW1wbGVUZXN0Q2FzZSB8IEN1c3RvbVRlc3RDYXNlKVtdIHwgbnVsbCB8IHVuZGVmaW5lZCB7XG4gICAgLy8gRm9yIHYxLCB3ZSBuZWVkIHRvIGhhbmRsZSB0aGUgY2FzZSB3aGVyZSB3ZSBkb24ndCBoYXZlIHF1ZXN0aW9uSWRcbiAgICAvLyBXZSdyZSBub3cgdXNpbmcgcXVlc3Rpb25JZCBpbiB0aGUgYXBwLCBidXQgc3RvcmVkIGRhdGEgbWlnaHQgc3RpbGwgYmUgaW4gdjEgZm9ybWF0XG5cbiAgICAvLyBGb3IgcHJldmlldyBkYXRhLCB0aGUgYXNzZXNzbWVudCBJRCB3b3VsZCBiZSBBc3Nlc3NtZW50SWRQcmV2aWV3XG4gICAgaWYgKHRoaXMuYXNzZXNzbWVudElkID09PSBBc3Nlc3NtZW50SWRQcmV2aWV3KSB7XG4gICAgICBpZiAodGhpcy5pc1ByZXZpZXcpIHtcbiAgICAgICAgLy8gRm9yIHByZXZpZXcgbW9kZSBvbiBwcmV2aWV3IGFzc2Vzc21lbnQsIGdldCB0aGUgY29kZSBkaXJlY3RseVxuICAgICAgICBjb25zdCBjb2RlID0gcmV0cmlldmVkRGF0YS5hc3Nlc3NtZW50c1t0aGlzLmFzc2Vzc21lbnRJZF0/LmNvZGU7XG4gICAgICAgIGlmIChjb2RlICYmIHRoaXMubGFuZ3VhZ2UgaW4gY29kZSkge1xuICAgICAgICAgIHJldHVybiBjb2RlW3RoaXMubGFuZ3VhZ2VdO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBXZSBkb24ndCBleHBlY3QgYWN0dWFsL25vbi1wcmV2aWV3IGRhdGEgZm9yIEFzc2Vzc21lbnRJZFByZXZpZXdcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBGb3IgcmVndWxhciBhc3Nlc3NtZW50cywgdjEgb25seSBoYWQgY29kZSBpbiB0aGUgXCJhY3R1YWxcIiBzZWN0aW9uXG4gICAgICBpZiAoIXRoaXMuaXNQcmV2aWV3KSB7XG4gICAgICAgIGNvbnN0IGNvZGUgPSByZXRyaWV2ZWREYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXT8uY29kZTtcbiAgICAgICAgaWYgKGNvZGUgJiYgdGhpcy5sYW5ndWFnZSBpbiBjb2RlKSB7XG4gICAgICAgICAgcmV0dXJuIGNvZGVbdGhpcy5sYW5ndWFnZV07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIC8vIFdlIGRvbid0IGhhdmUgcHJldmlldyBkYXRhIGZvciByZWd1bGFyIGFzc2Vzc21lbnRzIGluIHYxXG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cblxuICBnZXRTYXZlZENvZGUoKTogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgcmV0cmlldmVkRGF0YSA9IHRoaXMucmV0cmlldmVEYXRhKCk7XG4gICAgaWYgKCFyZXRyaWV2ZWREYXRhKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBpZiB1c2luZyB2MiBzY2hlbWFcbiAgICBpZiAoJ3ZlcnNpb24nIGluIHJldHJpZXZlZERhdGEpIHtcbiAgICAgIC8vIEhhbmRsZSB2MiBzY2hlbWFcbiAgICAgIGNvbnN0IHYyRGF0YSA9IHJldHJpZXZlZERhdGE7XG4gICAgICBjb25zdCBhc3Nlc3NtZW50RGF0YSA9IHYyRGF0YS5hc3Nlc3NtZW50c1t0aGlzLmFzc2Vzc21lbnRJZF07XG5cbiAgICAgIGlmICghYXNzZXNzbWVudERhdGEpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIC8vIEZpcnN0IHRyeSB3aXRoIHByb3ZpZGVkIHF1ZXN0aW9uSWRcbiAgICAgIGlmICh0aGlzLnF1ZXN0aW9uSWQgJiYgYXNzZXNzbWVudERhdGFbdGhpcy5xdWVzdGlvbklkXSkge1xuICAgICAgICBjb25zdCBxdWVzdGlvbkRhdGEgPSBhc3Nlc3NtZW50RGF0YVt0aGlzLnF1ZXN0aW9uSWRdO1xuICAgICAgICBjb25zdCB0ZXN0RGF0YSA9IHRoaXMuaXNQcmV2aWV3ID8gcXVlc3Rpb25EYXRhLnByZXZpZXcgOiBxdWVzdGlvbkRhdGEuYWN0dWFsO1xuICAgICAgICBpZiAodGVzdERhdGE/LmNvZGUgJiYgdGhpcy5sYW5ndWFnZSBpbiB0ZXN0RGF0YS5jb2RlKSB7XG4gICAgICAgICAgcmV0dXJuIHRlc3REYXRhLmNvZGVbdGhpcy5sYW5ndWFnZV07XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKFxuICAgICAgICB0aGlzLnF1ZXN0aW9uSWQgIT09IHRoaXMuREVGQVVMVF9NSUdSQVRJT05fUVVFU1RJT05fSUQgJiZcbiAgICAgICAgYXNzZXNzbWVudERhdGFbdGhpcy5ERUZBVUxUX01JR1JBVElPTl9RVUVTVElPTl9JRF1cbiAgICAgICkge1xuICAgICAgICBjb25zdCBxdWVzdGlvbkRhdGEgPSBhc3Nlc3NtZW50RGF0YVt0aGlzLkRFRkFVTFRfTUlHUkFUSU9OX1FVRVNUSU9OX0lEXTtcbiAgICAgICAgY29uc3QgdGVzdERhdGEgPSB0aGlzLmlzUHJldmlldyA/IHF1ZXN0aW9uRGF0YS5wcmV2aWV3IDogcXVlc3Rpb25EYXRhLmFjdHVhbDtcbiAgICAgICAgaWYgKHRlc3REYXRhPy5jb2RlICYmIHRoaXMubGFuZ3VhZ2UgaW4gdGVzdERhdGEuY29kZSkge1xuICAgICAgICAgIHJldHVybiB0ZXN0RGF0YS5jb2RlW3RoaXMubGFuZ3VhZ2VdO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBIYW5kbGUgdjEgc2NoZW1hIGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5XG4gICAgICByZXR1cm4gdGhpcy5nZXREYXRhRnJvbVYxU2NoZW1hKHJldHJpZXZlZERhdGEpIGFzIHN0cmluZztcbiAgICB9XG4gIH1cblxuICBnZXRMYXN0TGFuZ3VhZ2VMQVQoKToge1xuICAgIHZhbHVlOiBDb2RlRWRpdG9yTGFuZ3VhZ2VzO1xuICAgIHZlcnNpb246IHN0cmluZztcbiAgfSB8IG51bGwge1xuICAgIGNvbnN0IHJldHJpZXZlZERhdGEgPSB0aGlzLnJldHJpZXZlRGF0YSgpO1xuICAgIGlmICghcmV0cmlldmVkRGF0YSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJldHJpZXZlZERhdGEubGFzdExhbmd1YWdlTEFUIHx8IG51bGw7XG4gIH1cblxuICBnZXRTYXZlZFRlc3RDYXNlcygpOiAoRXhhbXBsZVRlc3RDYXNlIHwgQ3VzdG9tVGVzdENhc2UpW10gfCBudWxsIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCByZXRyaWV2ZWREYXRhID0gdGhpcy5yZXRyaWV2ZURhdGEoKTtcbiAgICBpZiAoIXJldHJpZXZlZERhdGEpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIENoZWNrIGlmIHVzaW5nIHYyIHNjaGVtYVxuICAgIGlmICgndmVyc2lvbicgaW4gcmV0cmlldmVkRGF0YSkge1xuICAgICAgLy8gSGFuZGxlIHYyIHNjaGVtYVxuICAgICAgY29uc3QgdjJEYXRhID0gcmV0cmlldmVkRGF0YTtcbiAgICAgIGNvbnN0IGFzc2Vzc21lbnREYXRhID0gdjJEYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXTtcblxuICAgICAgaWYgKCFhc3Nlc3NtZW50RGF0YSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cblxuICAgICAgLy8gRmlyc3QgdHJ5IHdpdGggcHJvdmlkZWQgcXVlc3Rpb25JZFxuICAgICAgaWYgKHRoaXMucXVlc3Rpb25JZCAmJiBhc3Nlc3NtZW50RGF0YVt0aGlzLnF1ZXN0aW9uSWRdKSB7XG4gICAgICAgIGNvbnN0IHF1ZXN0aW9uRGF0YSA9IGFzc2Vzc21lbnREYXRhW3RoaXMucXVlc3Rpb25JZF07XG4gICAgICAgIGNvbnN0IHRlc3REYXRhID0gdGhpcy5pc1ByZXZpZXcgPyBxdWVzdGlvbkRhdGEucHJldmlldyA6IHF1ZXN0aW9uRGF0YS5hY3R1YWw7XG4gICAgICAgIGlmICh0ZXN0RGF0YT8udGVzdENhc2VzTEFUKSB7XG4gICAgICAgICAgcmV0dXJuIHRlc3REYXRhLnRlc3RDYXNlc0xBVDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBJZiBub3QgZm91bmQgYW5kIHF1ZXN0aW9uSWQgIT0gREVGQVVMVF9NSUdSQVRJT05fUVVFU1RJT05fSUQsXG4gICAgICAvLyBhbHNvIHRyeSB3aXRoIHRoZSBkZWZhdWx0IG1pZ3JhdGlvbiBJRCBhcyBhIGZhbGxiYWNrXG4gICAgICBpZiAoXG4gICAgICAgIHRoaXMucXVlc3Rpb25JZCAhPT0gdGhpcy5ERUZBVUxUX01JR1JBVElPTl9RVUVTVElPTl9JRCAmJlxuICAgICAgICBhc3Nlc3NtZW50RGF0YVt0aGlzLkRFRkFVTFRfTUlHUkFUSU9OX1FVRVNUSU9OX0lEXVxuICAgICAgKSB7XG4gICAgICAgIGNvbnN0IHF1ZXN0aW9uRGF0YSA9IGFzc2Vzc21lbnREYXRhW3RoaXMuREVGQVVMVF9NSUdSQVRJT05fUVVFU1RJT05fSURdO1xuICAgICAgICBjb25zdCB0ZXN0RGF0YSA9IHRoaXMuaXNQcmV2aWV3ID8gcXVlc3Rpb25EYXRhLnByZXZpZXcgOiBxdWVzdGlvbkRhdGEuYWN0dWFsO1xuICAgICAgICBpZiAodGVzdERhdGE/LnRlc3RDYXNlc0xBVCkge1xuICAgICAgICAgIHJldHVybiB0ZXN0RGF0YS50ZXN0Q2FzZXNMQVQ7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIEhhbmRsZSB2MSBzY2hlbWEgdGVzdCBjYXNlcyAodGVzdCBjYXNlcyB3ZXJlIG9ubHkgaW4gdGhlIGFjdHVhbCBtb2RlKVxuICAgICAgY29uc3QgdjFEYXRhID0gcmV0cmlldmVkRGF0YTtcbiAgICAgIGlmICghdGhpcy5pc1ByZXZpZXcgJiYgdjFEYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXT8udGVzdENhc2VzTEFUKSB7XG4gICAgICAgIHJldHVybiB2MURhdGEuYXNzZXNzbWVudHNbdGhpcy5hc3Nlc3NtZW50SWRdLnRlc3RDYXNlc0xBVDtcbiAgICAgIH1cbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIGdldFNhdmVkQ29uZmlnKCk6IENvbmZpZyB8IG51bGwge1xuICAgIGNvbnN0IHJldHJpZXZlZERhdGEgPSB0aGlzLnJldHJpZXZlRGF0YSgpO1xuICAgIHJldHVybiByZXRyaWV2ZWREYXRhPy5jb25maWcgPyB7IC4uLnJldHJpZXZlZERhdGEuY29uZmlnIH0gOiBudWxsO1xuICB9XG5cbiAgZ2V0U2F2ZWRGdWxsU2NyZWVuTW9kZSgpOiBib29sZWFuIHwgbnVsbCB7XG4gICAgY29uc3QgcmV0cmlldmVkRGF0YSA9IHRoaXMucmV0cmlldmVEYXRhKCk7XG4gICAgcmV0dXJuIHJldHJpZXZlZERhdGE/LmlzRnVsbHNjcmVlbiAhPT0gdW5kZWZpbmVkID8gcmV0cmlldmVkRGF0YS5pc0Z1bGxzY3JlZW4gOiBudWxsO1xuICB9XG5cbiAgY2xlYXJTYXZlZENvZGUoKTogdm9pZCB7XG4gICAgdGhpcy5lbnN1cmVEYXRhU3RydWN0dXJlKCk7XG4gICAgY29uc3QgcXVlc3Rpb25EYXRhID0gdGhpcy5hdXRvU2F2ZWREYXRhLmFzc2Vzc21lbnRzW3RoaXMuYXNzZXNzbWVudElkXVt0aGlzLnF1ZXN0aW9uSWRdO1xuICAgIGNvbnN0IHRhcmdldFRlc3REYXRhID0gdGhpcy5pc1ByZXZpZXcgPyBbcXVlc3Rpb25EYXRhLnByZXZpZXddIDogW3F1ZXN0aW9uRGF0YS5wcmV2aWV3LCBxdWVzdGlvbkRhdGEuYWN0dWFsXTtcblxuICAgIGxldCBoYXNDaGFuZ2VkID0gZmFsc2U7XG4gICAgdGFyZ2V0VGVzdERhdGEuZm9yRWFjaCh0ZXN0RGF0YSA9PiB7XG4gICAgICBpZiAodGVzdERhdGEpIHtcbiAgICAgICAgdGVzdERhdGEuY29kZSA9IHt9O1xuICAgICAgICB0aGlzLnVwZGF0ZUxhc3RNb2RpZmllZCh0ZXN0RGF0YSk7XG4gICAgICAgIGhhc0NoYW5nZWQgPSB0cnVlO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGlmIChoYXNDaGFuZ2VkKSB7XG4gICAgICB0aGlzLnN0b3JlRGF0YSgpO1xuICAgIH1cbiAgfVxuXG4gIGNsZWFyTGFzdExhbmcoKTogdm9pZCB7XG4gICAgdGhpcy5hdXRvU2F2ZWREYXRhLmxhc3RMYW5ndWFnZUxBVCA9IG51bGw7XG4gICAgdGhpcy51cGRhdGVMYXN0TW9kaWZpZWQodGhpcy5hdXRvU2F2ZWREYXRhKTtcbiAgICB0aGlzLnN0b3JlRGF0YSgpO1xuICB9XG5cbiAgY2xlYXJTYXZlZFRlc3RDYXNlcygpOiB2b2lkIHtcbiAgICB0aGlzLmVuc3VyZURhdGFTdHJ1Y3R1cmUoKTtcbiAgICBjb25zdCBxdWVzdGlvbkRhdGEgPSB0aGlzLmF1dG9TYXZlZERhdGEuYXNzZXNzbWVudHNbdGhpcy5hc3Nlc3NtZW50SWRdW3RoaXMucXVlc3Rpb25JZF07XG4gICAgY29uc3QgdGFyZ2V0VGVzdERhdGEgPSB0aGlzLmlzUHJldmlldyA/IHF1ZXN0aW9uRGF0YS5wcmV2aWV3IDogcXVlc3Rpb25EYXRhLmFjdHVhbDtcblxuICAgIGlmICh0YXJnZXRUZXN0RGF0YSkge1xuICAgICAgY29uc3QgaGFzTm9Db2RlID0gIU9iamVjdC5rZXlzKHRhcmdldFRlc3REYXRhLmNvZGUgPz8ge30pLmxlbmd0aDtcblxuICAgICAgaWYgKHRoaXMuaXNQcmV2aWV3KSB7XG4gICAgICAgIHRhcmdldFRlc3REYXRhLnRlc3RDYXNlc0xBVCA9IFtdO1xuICAgICAgICB0aGlzLnVwZGF0ZUxhc3RNb2RpZmllZCh0YXJnZXRUZXN0RGF0YSk7XG4gICAgICB9IGVsc2UgaWYgKGhhc05vQ29kZSkge1xuICAgICAgICBjb25zdCBhbGxRdWVzdGlvbnMgPSB0aGlzLmF1dG9TYXZlZERhdGEuYXNzZXNzbWVudHNbdGhpcy5hc3Nlc3NtZW50SWRdO1xuICAgICAgICBkZWxldGUgYWxsUXVlc3Rpb25zW3RoaXMucXVlc3Rpb25JZF07XG4gICAgICAgIHRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50c1t0aGlzLmFzc2Vzc21lbnRJZF0gPSB7IC4uLmFsbFF1ZXN0aW9ucyB9O1xuICAgICAgICB0aGlzLnVwZGF0ZUxhc3RNb2RpZmllZCh0aGlzLmF1dG9TYXZlZERhdGEpO1xuICAgICAgfVxuICAgICAgdGhpcy5zdG9yZURhdGEoKTtcbiAgICB9XG4gIH1cblxuICB1cGRhdGVWZXJzaW9uKHZlcnNpb246IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICh0aGlzLmF1dG9TYXZlZERhdGEubGFzdExhbmd1YWdlTEFUKSB7XG4gICAgICB0aGlzLmF1dG9TYXZlZERhdGEubGFzdExhbmd1YWdlTEFULnZlcnNpb24gPSB2ZXJzaW9uO1xuICAgICAgdGhpcy51cGRhdGVMYXN0TW9kaWZpZWQodGhpcy5hdXRvU2F2ZWREYXRhKTtcbiAgICAgIHRoaXMuc3RvcmVEYXRhKCk7XG4gICAgfVxuICB9XG5cbiAgdXBkYXRlVGVzdENhc2VzKHRlc3RDYXNlczogKEV4YW1wbGVUZXN0Q2FzZSB8IEN1c3RvbVRlc3RDYXNlKVtdKSB7XG4gICAgaWYgKHRoaXMuYXNzZXNzbWVudElkICYmIHRoaXMucXVlc3Rpb25JZCAmJiB0aGlzLnRlc3RDYXNlc1NhdmVFbmFibGVkKSB7XG4gICAgICB0aGlzLmVuc3VyZURhdGFTdHJ1Y3R1cmUoKTtcbiAgICAgIGNvbnN0IHF1ZXN0aW9uRGF0YSA9IHRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50c1t0aGlzLmFzc2Vzc21lbnRJZF1bdGhpcy5xdWVzdGlvbklkXTtcbiAgICAgIGNvbnN0IHRhcmdldFRlc3REYXRhID0gdGhpcy5pc1ByZXZpZXcgPyBxdWVzdGlvbkRhdGEucHJldmlldyA6IHF1ZXN0aW9uRGF0YS5hY3R1YWw7XG5cbiAgICAgIGlmICh0YXJnZXRUZXN0RGF0YSkge1xuICAgICAgICB0YXJnZXRUZXN0RGF0YS50ZXN0Q2FzZXNMQVQgPSB0ZXN0Q2FzZXM7XG4gICAgICAgIHRoaXMudXBkYXRlTGFzdE1vZGlmaWVkKHRhcmdldFRlc3REYXRhKTtcbiAgICAgICAgdGhpcy5zdG9yZURhdGEoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHN0b3JlRGF0YSgpOiB2b2lkIHtcbiAgICB0aGlzLnN0b3JhZ2Uuc3RvcmUodGhpcy5rZXksIHRoaXMuYXV0b1NhdmVkRGF0YSk7XG4gIH1cblxuICBwcml2YXRlIHJldHJpZXZlRGF0YSgpOiBBdXRvU2F2ZWREYXRhIHwgQXV0b1NhdmVkRGF0YVYxIHtcbiAgICByZXR1cm4gdGhpcy5zdG9yYWdlLnJldHJpZXZlKHRoaXMua2V5KSBhcyBBdXRvU2F2ZWREYXRhIHwgQXV0b1NhdmVkRGF0YVYxO1xuICB9XG5cbiAgLyoqXG4gICAqIE1hbnVhbGx5IHRyaWdnZXJzIGRhdGEgY2xlYW51cCBhbmQgbWlncmF0aW9uLlxuICAgKiBVc2VmdWwgZm9yIGhhbmRsaW5nIGxhcmdlIGxvY2FsU3RvcmFnZSBvciBtaWdyYXRpb24gd2hlbiBuZWVkZWQuXG4gICAqIFRoaXMgY2FuIGJlIGNhbGxlZCBmcm9tIGFwcGxpY2F0aW9uIHN0YXJ0dXAgb3IgYWZ0ZXIgbWFqb3IgZXZlbnRzLlxuICAgKi9cbiAgcGVyZm9ybU1haW50ZW5hbmNlQW5kQ2xlYW51cCgpOiB2b2lkIHtcbiAgICAvLyBHZXQgY3VycmVudCBkYXRhXG4gICAgY29uc3Qgc2F2ZWREYXRhID0gdGhpcy5zdG9yYWdlLnJldHJpZXZlKHRoaXMua2V5KTtcblxuICAgIC8vIElmIG5vIGRhdGEsIG5vdGhpbmcgdG8gZG9cbiAgICBpZiAoIXNhdmVkRGF0YSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIENoZWNrIGlmIG1pZ3JhdGlvbiBuZWVkZWRcbiAgICBpZiAoISgndmVyc2lvbicgaW4gc2F2ZWREYXRhKSkge1xuICAgICAgdGhpcy5taWdyYXRlRnJvbVYxVG9WMihzYXZlZERhdGEgYXMgQXV0b1NhdmVkRGF0YVYxKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQWxyZWFkeSBtaWdyYXRlZCwganVzdCBwZXJmb3JtIGNsZWFudXBcbiAgICAgIHRoaXMuYXV0b1NhdmVkRGF0YSA9IHNhdmVkRGF0YSBhcyBBdXRvU2F2ZWREYXRhO1xuXG4gICAgICAvLyBQZXJmb3JtIGEgbW9yZSBhZ2dyZXNzaXZlIGNsZWFudXAgZm9yIG1hbnVhbCBtYWludGVuYW5jZVxuICAgICAgLy8gYnkgdGVtcG9yYXJpbHkgbW9kaWZ5aW5nIHRoZSBjbGVhbnVwIHRocmVzaG9sZHNcbiAgICAgIGNvbnN0IG9yaWdpbmFsTWF4QWdlID0gdGhpcy5NQVhfU1RPUkFHRV9BR0VfREFZUztcbiAgICAgIGNvbnN0IGhhbGZBZ2UgPSBNYXRoLmZsb29yKG9yaWdpbmFsTWF4QWdlIC8gMik7IC8vIEN1dCB0aHJlc2hvbGQgaW4gaGFsZlxuXG4gICAgICAvLyBDcmVhdGUgYSBjdXN0b20gY2xlYW51cCBmdW5jdGlvbiB3aXRoIHJlZHVjZWQgdGhyZXNob2xkXG4gICAgICB0aGlzLmNsZWFudXBXaXRoUmVkdWNlZFRocmVzaG9sZChoYWxmQWdlKTtcbiAgICB9XG5cbiAgICAvLyBWZXJpZnkgbG9jYWxTdG9yYWdlIHNpemUgaXMgbWFuYWdlYWJsZVxuICAgIHRyeSB7XG4gICAgICBjb25zdCBzZXJpYWxpemVkRGF0YSA9IEpTT04uc3RyaW5naWZ5KHRoaXMuYXV0b1NhdmVkRGF0YSk7XG4gICAgICBjb25zdCBzaXplSW5LQiA9IE1hdGgucm91bmQoc2VyaWFsaXplZERhdGEubGVuZ3RoIC8gMTAyNCk7XG5cbiAgICAgIC8vIElmIGRhdGEgaXMgdG9vIGxhcmdlIChvdmVyIDJNQiksIHBlcmZvcm0gbW9yZSBhZ2dyZXNzaXZlIGNsZWFudXBcbiAgICAgIGlmIChzaXplSW5LQiA+IDIwNDgpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGBMb2NhbCBzdG9yYWdlIGRhdGEgaXMgbGFyZ2UgKCR7c2l6ZUluS0J9S0IpLCBwZXJmb3JtaW5nIGRlZXAgY2xlYW51cGApO1xuXG4gICAgICAgIC8vIFVzZSBleHRyZW1lbHkgYWdncmVzc2l2ZSBjbGVhbnVwIHNldHRpbmdzXG4gICAgICAgIHRoaXMuY2xlYW51cFN0b3JhZ2VEYXRhKHtcbiAgICAgICAgICBzdG9yYWdlQWdlTXVsdGlwbGllcjogMC41LCAvLyBFdmVuIG1vcmUgYWdncmVzc2l2ZSAtIGhhbGYgdGhlIG5vcm1hbCBhZ2VcbiAgICAgICAgICBtaW5RdWVzdGlvbkRhdGFBZ2VEYXlzOiAwLjI1LCAvLyA2IGhvdXJzIG1pbmltdW1cbiAgICAgICAgICBhc3Nlc3NtZW50TGltaXRNdWx0aXBsaWVyOiAwLjIsIC8vIEtlZXAgb25seSAyMCUgb2YgYXNzZXNzbWVudHNcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gSWYgc3RpbGwgdG9vIGxhcmdlLCBrZWVwIG9ubHkgYSBmZXcgbW9zdCByZWNlbnQgYXNzZXNzbWVudHNcbiAgICAgICAgY29uc3QgbmV3U2VyaWFsaXplZERhdGEgPSBKU09OLnN0cmluZ2lmeSh0aGlzLmF1dG9TYXZlZERhdGEpO1xuICAgICAgICBjb25zdCBuZXdTaXplSW5LQiA9IE1hdGgucm91bmQobmV3U2VyaWFsaXplZERhdGEubGVuZ3RoIC8gMTAyNCk7XG5cbiAgICAgICAgaWYgKG5ld1NpemVJbktCID4gMTAyNCkge1xuICAgICAgICAgIC8vIEtlZXAgb25seSByZWNlbnQgYXNzZXNzbWVudHNcbiAgICAgICAgICBjb25zdCBhc3Nlc3NtZW50cyA9IHRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50cztcbiAgICAgICAgICAvLyBGaW5kIHRoZSBuZXdlc3QgdGltZXN0YW1wIGluIGVhY2ggYXNzZXNzbWVudFxuICAgICAgICAgIGNvbnN0IGdldE5ld2VzdFRpbWVzdGFtcCA9IChvYmo6IFJlY29yZDxzdHJpbmcsIFF1ZXN0aW9uRGF0YT4pID0+XG4gICAgICAgICAgICBPYmplY3QudmFsdWVzKG9iaikucmVkdWNlKChtYXgsIHF1ZXN0aW9uRGF0YSkgPT4gTWF0aC5tYXgobWF4LCBxdWVzdGlvbkRhdGE/Lmxhc3RNb2RpZmllZCB8fCAwKSwgMCk7XG4gICAgICAgICAgY29uc3QgZW50cmllcyA9IE9iamVjdC5lbnRyaWVzKGFzc2Vzc21lbnRzKS5zb3J0KFxuICAgICAgICAgICAgKFssIGFdLCBbLCBiXSkgPT5cbiAgICAgICAgICAgICAgZ2V0TmV3ZXN0VGltZXN0YW1wKGIgYXMgUmVjb3JkPHN0cmluZywgUXVlc3Rpb25EYXRhPikgLVxuICAgICAgICAgICAgICBnZXROZXdlc3RUaW1lc3RhbXAoYSBhcyBSZWNvcmQ8c3RyaW5nLCBRdWVzdGlvbkRhdGE+KVxuICAgICAgICAgICk7XG5cbiAgICAgICAgICAvLyBLZWVwIG9ubHkgdGhlIDUgbW9zdCByZWNlbnQgYXNzZXNzbWVudHNcbiAgICAgICAgICBjb25zdCBrZWVwQ291bnQgPSBNYXRoLm1pbig1LCBlbnRyaWVzLmxlbmd0aCk7XG4gICAgICAgICAgdGhpcy5hdXRvU2F2ZWREYXRhLmFzc2Vzc21lbnRzID0ge307XG5cbiAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGtlZXBDb3VudDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBbaWQsIGRhdGFdID0gZW50cmllc1tpXTtcbiAgICAgICAgICAgIHRoaXMuYXV0b1NhdmVkRGF0YS5hc3Nlc3NtZW50c1tpZF0gPSBkYXRhIGFzIFJlY29yZDxzdHJpbmcsIFF1ZXN0aW9uRGF0YT47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5zdG9yZURhdGEoKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBjaGVja2luZyBsb2NhbFN0b3JhZ2Ugc2l6ZScsIGVycm9yKTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
|