@colijnit/corecomponents_v12 12.2.26 → 12.2.27
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/bundles/colijnit-corecomponents_v12.umd.js +13684 -13680
- package/bundles/colijnit-corecomponents_v12.umd.js.map +1 -1
- package/colijnit-corecomponents_v12.d.ts +43 -43
- package/colijnit-corecomponents_v12.metadata.json +1 -1
- package/esm2015/colijnit-corecomponents_v12.js +43 -43
- package/esm2015/lib/components/article-tile/article-tile.component.js +49 -49
- package/esm2015/lib/components/article-tile/article-tile.module.js +34 -34
- package/esm2015/lib/components/base/base-input.component.js +833 -833
- package/esm2015/lib/components/base/base.module.js +21 -21
- package/esm2015/lib/components/base/commit-buttons/commit-buttons.component.js +85 -85
- package/esm2015/lib/components/base/commit-buttons/commit-buttons.module.js +20 -20
- package/esm2015/lib/components/base/dialog-base.component.js +5 -5
- package/esm2015/lib/components/base-input-date-picker/base-input-date-picker.directive.js +24 -24
- package/esm2015/lib/components/button/button.component.js +73 -73
- package/esm2015/lib/components/button/button.module.js +18 -18
- package/esm2015/lib/components/calendar/calendar-template.component.js +281 -281
- package/esm2015/lib/components/calendar/calendar.component.js +32 -32
- package/esm2015/lib/components/calendar/calendar.module.js +27 -27
- package/esm2015/lib/components/card/card.component.js +50 -50
- package/esm2015/lib/components/card/card.module.js +34 -34
- package/esm2015/lib/components/carousel/carousel.component.js +109 -109
- package/esm2015/lib/components/carousel/carousel.module.js +31 -31
- package/esm2015/lib/components/carousel-3d/carousel-3d.component.js +293 -293
- package/esm2015/lib/components/carousel-3d/carousel-3d.module.js +18 -18
- package/esm2015/lib/components/carousel-3d/carouselItem.js +53 -53
- package/esm2015/lib/components/checkmark-overlay/checkmark-overlay.component.js +72 -72
- package/esm2015/lib/components/checkmark-overlay/checkmark-overlay.module.js +18 -18
- package/esm2015/lib/components/co-dialog/co-dialog.component.js +91 -91
- package/esm2015/lib/components/co-dialog/co-dialog.module.js +18 -18
- package/esm2015/lib/components/co-dialog-wizard/co-dialog-wizard.component.js +35 -35
- package/esm2015/lib/components/co-dialog-wizard/co-dialog-wizard.module.js +16 -16
- package/esm2015/lib/components/collapsible/collapsible.component.js +67 -67
- package/esm2015/lib/components/collapsible/collapsible.module.js +18 -18
- package/esm2015/lib/components/color-picker/color-picker.component.js +33 -33
- package/esm2015/lib/components/color-picker/color-picker.module.js +20 -20
- package/esm2015/lib/components/core-dialog/confirmation-dialog/confirmation-dialog.component.js +46 -46
- package/esm2015/lib/components/core-dialog/core-dialog.module.js +38 -38
- package/esm2015/lib/components/core-dialog/core-dialog.service.js +66 -66
- package/esm2015/lib/components/core-dialog/core-dynamic-component.service.js +92 -92
- package/esm2015/lib/components/double-calendar/double-calendar.component.js +62 -62
- package/esm2015/lib/components/double-calendar/double-calendar.module.js +24 -24
- package/esm2015/lib/components/filter-item/filter-item-viewmodel.js +12 -12
- package/esm2015/lib/components/filter-item/filter-item.component.js +496 -496
- package/esm2015/lib/components/filter-item/filter-item.module.js +42 -42
- package/esm2015/lib/components/filter-item/filter-viewmodel.js +10 -10
- package/esm2015/lib/components/form/form.component.js +181 -181
- package/esm2015/lib/components/form/form.module.js +22 -22
- package/esm2015/lib/components/grid-toolbar/grid-toolbar.component.js +48 -48
- package/esm2015/lib/components/grid-toolbar/grid-toolbar.module.js +22 -22
- package/esm2015/lib/components/grid-toolbar-button/grid-toolbar-button.component.js +23 -23
- package/esm2015/lib/components/grid-toolbar-button/grid-toolbar-button.module.js +18 -18
- package/esm2015/lib/components/icon/icon-cache.service.js +51 -51
- package/esm2015/lib/components/icon/icon.component.js +47 -47
- package/esm2015/lib/components/icon/icon.module.js +24 -24
- package/esm2015/lib/components/icon-collapse-handle/icon-collapse-handle.component.js +56 -56
- package/esm2015/lib/components/icon-collapse-handle/icon-collapse-handle.module.js +22 -22
- package/esm2015/lib/components/image/image.component.js +31 -31
- package/esm2015/lib/components/image/image.module.js +13 -13
- package/esm2015/lib/components/input-checkbox/input-checkbox.component.js +71 -71
- package/esm2015/lib/components/input-checkbox/input-checkbox.module.js +18 -18
- package/esm2015/lib/components/input-date-picker/input-date-picker.component.js +74 -74
- package/esm2015/lib/components/input-date-picker/input-date-picker.module.js +25 -25
- package/esm2015/lib/components/input-date-range-picker/input-date-range-picker.component.js +107 -107
- package/esm2015/lib/components/input-date-range-picker/input-date-range-picker.module.js +26 -26
- package/esm2015/lib/components/input-number-picker/input-number-picker.component.js +285 -285
- package/esm2015/lib/components/input-number-picker/input-number-picker.module.js +22 -22
- package/esm2015/lib/components/input-radio-button/input-radio-button.component.js +77 -77
- package/esm2015/lib/components/input-radio-button/input-radio-button.module.js +18 -18
- package/esm2015/lib/components/input-scanner/bar-code-scanner.js +22 -22
- package/esm2015/lib/components/input-scanner/input-scanner.component.js +56 -56
- package/esm2015/lib/components/input-scanner/input-scanner.module.js +20 -20
- package/esm2015/lib/components/input-scanner/scanner.service.js +27 -27
- package/esm2015/lib/components/input-search/input-search.component.js +67 -63
- package/esm2015/lib/components/input-search/input-search.module.js +20 -20
- package/esm2015/lib/components/input-text/input-text.component.js +192 -192
- package/esm2015/lib/components/input-text/input-text.module.js +32 -32
- package/esm2015/lib/components/input-textarea/input-textarea.component.js +55 -55
- package/esm2015/lib/components/input-textarea/input-textarea.module.js +26 -26
- package/esm2015/lib/components/level-indicator/level-indicator-level.enum.js +6 -6
- package/esm2015/lib/components/level-indicator/level-indicator.component.js +29 -29
- package/esm2015/lib/components/level-indicator/level-indicator.module.js +14 -14
- package/esm2015/lib/components/list-of-values/list-of-values-multiselect-popup.component.js +87 -87
- package/esm2015/lib/components/list-of-values/list-of-values-popup.component.js +218 -218
- package/esm2015/lib/components/list-of-values/list-of-values.component.js +199 -199
- package/esm2015/lib/components/list-of-values/list-of-values.module.js +37 -37
- package/esm2015/lib/components/loader/loader.component.js +16 -16
- package/esm2015/lib/components/loader/loader.module.js +18 -18
- package/esm2015/lib/components/pagination/paginate.pipe.js +98 -98
- package/esm2015/lib/components/pagination/pagination-instance.js +1 -1
- package/esm2015/lib/components/pagination/pagination.component.js +107 -107
- package/esm2015/lib/components/pagination/pagination.module.js +27 -27
- package/esm2015/lib/components/pagination/pagination.service.js +87 -87
- package/esm2015/lib/components/pagination-bar/pagination-bar.component.js +136 -136
- package/esm2015/lib/components/pagination-bar/pagination-bar.module.js +18 -18
- package/esm2015/lib/components/popup/const/popup-window-token.js +2 -2
- package/esm2015/lib/components/popup/interface/popup-button.js +7 -7
- package/esm2015/lib/components/popup/interface/popup-close-event.js +1 -1
- package/esm2015/lib/components/popup/interface/popup-settings.js +41 -41
- package/esm2015/lib/components/popup/interface/popup.js +1 -1
- package/esm2015/lib/components/popup/model/popup-button-globals.js +10 -10
- package/esm2015/lib/components/popup/model/popup-window.js +37 -37
- package/esm2015/lib/components/popup/popup-buttons.component.js +42 -42
- package/esm2015/lib/components/popup/popup-message-display.component.js +37 -37
- package/esm2015/lib/components/popup/popup-window-shell.component.js +141 -141
- package/esm2015/lib/components/popup/popup.module.js +48 -48
- package/esm2015/lib/components/popup/service/popup-shower.service.js +89 -89
- package/esm2015/lib/components/popup/service/prompt.service.js +126 -126
- package/esm2015/lib/components/popup/text-input-popup.component.js +33 -33
- package/esm2015/lib/components/responsive-text/responsive-text.component.js +17 -17
- package/esm2015/lib/components/responsive-text/responsive-text.module.js +18 -18
- package/esm2015/lib/components/simple-grid/base-simple-grid.component.js +163 -163
- package/esm2015/lib/components/simple-grid/simple-grid-cell.component.js +141 -141
- package/esm2015/lib/components/simple-grid/simple-grid-column.directive.js +110 -110
- package/esm2015/lib/components/simple-grid/simple-grid.component.js +378 -378
- package/esm2015/lib/components/simple-grid/simple-grid.module.js +40 -40
- package/esm2015/lib/components/tile/tile.component.js +44 -44
- package/esm2015/lib/components/tile/tile.module.js +22 -22
- package/esm2015/lib/components/tile-select/tile-select.component.js +26 -26
- package/esm2015/lib/components/tile-select/tile-select.module.js +20 -20
- package/esm2015/lib/components/tooltip/tooltip.component.js +74 -74
- package/esm2015/lib/components/tooltip/tooltip.module.js +18 -18
- package/esm2015/lib/components/validation-error/validation-error.component.js +30 -30
- package/esm2015/lib/components/validation-error/validation-error.module.js +24 -24
- package/esm2015/lib/components/view-mode-buttons/content-view-mode.enum.js +10 -10
- package/esm2015/lib/components/view-mode-buttons/view-mode-buttons.component.js +41 -41
- package/esm2015/lib/components/view-mode-buttons/view-mode-buttons.module.js +20 -20
- package/esm2015/lib/core/constant/default-upper-bound-for-range-components.js +3 -3
- package/esm2015/lib/core/constant/java-max-int.js +1 -1
- package/esm2015/lib/core/constant/number-inputs-key-down-white-list.js +44 -44
- package/esm2015/lib/core/decorator/input-boolean.decorator.js +33 -33
- package/esm2015/lib/core/enum/co-direction.js +8 -8
- package/esm2015/lib/core/enum/co-document-image-display-kind.enum.js +6 -6
- package/esm2015/lib/core/enum/co-document-type.enum.js +10 -10
- package/esm2015/lib/core/enum/co-orientation.js +16 -16
- package/esm2015/lib/core/enum/core-components-icon.enum.js +299 -299
- package/esm2015/lib/core/enum/file-type-internal.enum.js +16 -16
- package/esm2015/lib/core/enum/file-type.enum.js +10 -10
- package/esm2015/lib/core/enum/filterItem-mode.enum.js +42 -42
- package/esm2015/lib/core/enum/input-number-picker-show-mode.enum.js +7 -7
- package/esm2015/lib/core/enum/keyboard-code.enum.js +73 -73
- package/esm2015/lib/core/enum/keyboard-key.enum.js +75 -75
- package/esm2015/lib/core/enum/object-right-type.enum.js +6 -6
- package/esm2015/lib/core/enum/popup-button-type.enum.js +11 -11
- package/esm2015/lib/core/enum/popup-type.enum.js +10 -10
- package/esm2015/lib/core/enum/table-name.enum.js +80 -80
- package/esm2015/lib/core/function/any-nill.function.js +5 -5
- package/esm2015/lib/core/function/is-nill.function.js +4 -4
- package/esm2015/lib/core/function/none-nill.function.js +16 -16
- package/esm2015/lib/core/function/not-nill.function.js +4 -4
- package/esm2015/lib/core/model/bounds-constrained-number-value.js +170 -170
- package/esm2015/lib/core/model/check-precision-and-scale-result.js +1 -1
- package/esm2015/lib/core/model/check-within-stepped-bounds-result.js +1 -1
- package/esm2015/lib/core/model/co-document-right.bo.js +2 -2
- package/esm2015/lib/core/model/co-document.bo.js +120 -120
- package/esm2015/lib/core/model/core-components-icon-svg.js +298 -298
- package/esm2015/lib/core/model/element-position.js +9 -9
- package/esm2015/lib/core/model/event/string-prompt-result-event.js +7 -7
- package/esm2015/lib/core/service/form-input-user-change-listener.service.js +24 -24
- package/esm2015/lib/core/service/form-master.service.js +101 -101
- package/esm2015/lib/core/service/ng-zone-wrapper.service.js +19 -19
- package/esm2015/lib/core/utils/array-utils.js +263 -263
- package/esm2015/lib/core/utils/browser-utils.js +99 -99
- package/esm2015/lib/core/utils/direction-enum-utils.js +13 -13
- package/esm2015/lib/core/utils/event-utils.js +52 -52
- package/esm2015/lib/core/utils/file-utils.js +266 -266
- package/esm2015/lib/core/utils/number-utils.js +308 -308
- package/esm2015/lib/core/utils/object-utils.js +185 -185
- package/esm2015/lib/core/utils/string-utils.js +93 -93
- package/esm2015/lib/core/validator/email.validator.js +5 -5
- package/esm2015/lib/core/validator/equal.validator.js +10 -10
- package/esm2015/lib/core/validator/max-string-length.validator.js +9 -9
- package/esm2015/lib/core/validator/password.validator.js +30 -30
- package/esm2015/lib/core/validator/precision-scale.validator.js +10 -10
- package/esm2015/lib/core/validator/required.validator.js +4 -4
- package/esm2015/lib/directives/clickoutside/click-outside-master.service.js +56 -56
- package/esm2015/lib/directives/clickoutside/click-outside.directive.js +70 -70
- package/esm2015/lib/directives/clickoutside/clickoutside.module.js +18 -18
- package/esm2015/lib/directives/observe-visibility/observe-visibility.directive.js +52 -52
- package/esm2015/lib/directives/observe-visibility/observe-visibility.module.js +14 -14
- package/esm2015/lib/directives/overlay/overlay-parent.directive.js +18 -18
- package/esm2015/lib/directives/overlay/overlay.directive.js +160 -160
- package/esm2015/lib/directives/overlay/overlay.module.js +17 -17
- package/esm2015/lib/directives/ripple/ripple-ref.js +25 -25
- package/esm2015/lib/directives/ripple/ripple-renderer.js +159 -159
- package/esm2015/lib/directives/ripple/ripple.directive.js +79 -79
- package/esm2015/lib/directives/ripple/ripple.module.js +23 -23
- package/esm2015/lib/directives/ripple/scroll-dispatcher.service.js +107 -107
- package/esm2015/lib/directives/ripple/scrollable.directive.js +39 -39
- package/esm2015/lib/directives/ripple/viewport-ruler.service.js +72 -72
- package/esm2015/lib/directives/screen-configuration/screen-configuration.directive.js +157 -157
- package/esm2015/lib/directives/screen-configuration/screen-configuration.module.js +18 -18
- package/esm2015/lib/directives/stopclick/stop-click.directive.js +37 -37
- package/esm2015/lib/directives/stopclick/stop-click.module.js +14 -14
- package/esm2015/lib/directives/template-wrapper/template-wrapper.directive.js +67 -67
- package/esm2015/lib/directives/template-wrapper/template-wrapper.module.js +14 -14
- package/esm2015/lib/directives/tooltip/tooltip-directive.module.js +18 -18
- package/esm2015/lib/directives/tooltip/tooltip.directive.js +77 -77
- package/esm2015/lib/interfaces/dialog-response.interface.js +1 -1
- package/esm2015/lib/interfaces/scanner-input.interface.js +1 -1
- package/esm2015/lib/interfaces/screen-config-adapter-component-interface-name.js +3 -3
- package/esm2015/lib/interfaces/screen-config-adapter.component.interface.js +1 -1
- package/esm2015/lib/model/enum/app-button-type.enum.js +10 -10
- package/esm2015/lib/model/enum/app-popup-type.enum.js +7 -7
- package/esm2015/lib/pipes/append.pipe.js +16 -16
- package/esm2015/lib/pipes/append.pipe.module.js +14 -14
- package/esm2015/lib/pipes/filter.pipe.js +15 -15
- package/esm2015/lib/pipes/filter.pipe.module.js +14 -14
- package/esm2015/lib/pipes/prepend.pipe.js +16 -16
- package/esm2015/lib/pipes/prepend.pipe.module.js +14 -14
- package/esm2015/lib/pipes/price-display-pipe.module.js +14 -14
- package/esm2015/lib/pipes/price-display.pipe.js +19 -19
- package/esm2015/lib/service/base-module-screen-config.service.js +204 -204
- package/esm2015/lib/service/base-module.service.js +41 -41
- package/esm2015/lib/service/color-sequence.service.js +22 -22
- package/esm2015/lib/service/overlay.service.js +72 -72
- package/esm2015/lib/translation/core-components-translation.module.js +28 -28
- package/esm2015/lib/translation/core-components-translation.service.js +16 -16
- package/esm2015/lib/translation/core-dictionary.service.js +28 -28
- package/esm2015/lib/translation/core-localize.pipe.js +25 -25
- package/esm2015/public-api.js +129 -129
- package/fesm2015/colijnit-corecomponents_v12.js +12090 -12086
- package/fesm2015/colijnit-corecomponents_v12.js.map +1 -1
- package/lib/components/article-tile/article-tile.component.d.ts +22 -22
- package/lib/components/article-tile/article-tile.module.d.ts +2 -2
- package/lib/components/base/base-input.component.d.ts +182 -182
- package/lib/components/base/base.module.d.ts +2 -2
- package/lib/components/base/commit-buttons/commit-buttons.component.d.ts +21 -21
- package/lib/components/base/commit-buttons/commit-buttons.module.d.ts +2 -2
- package/lib/components/base/dialog-base.component.d.ts +4 -4
- package/lib/components/base-input-date-picker/base-input-date-picker.directive.d.ts +15 -15
- package/lib/components/button/button.component.d.ts +29 -29
- package/lib/components/button/button.module.d.ts +2 -2
- package/lib/components/calendar/calendar-template.component.d.ts +60 -60
- package/lib/components/calendar/calendar.component.d.ts +13 -13
- package/lib/components/calendar/calendar.module.d.ts +2 -2
- package/lib/components/card/card.component.d.ts +23 -23
- package/lib/components/card/card.module.d.ts +2 -2
- package/lib/components/carousel/carousel.component.d.ts +23 -23
- package/lib/components/carousel/carousel.module.d.ts +6 -6
- package/lib/components/carousel-3d/carousel-3d.component.d.ts +55 -55
- package/lib/components/carousel-3d/carousel-3d.module.d.ts +2 -2
- package/lib/components/carousel-3d/carouselItem.d.ts +13 -13
- package/lib/components/checkmark-overlay/checkmark-overlay.component.d.ts +17 -17
- package/lib/components/checkmark-overlay/checkmark-overlay.module.d.ts +2 -2
- package/lib/components/co-dialog/co-dialog.component.d.ts +23 -23
- package/lib/components/co-dialog/co-dialog.module.d.ts +2 -2
- package/lib/components/co-dialog-wizard/co-dialog-wizard.component.d.ts +9 -9
- package/lib/components/co-dialog-wizard/co-dialog-wizard.module.d.ts +2 -2
- package/lib/components/collapsible/collapsible.component.d.ts +22 -22
- package/lib/components/collapsible/collapsible.module.d.ts +2 -2
- package/lib/components/color-picker/color-picker.component.d.ts +6 -6
- package/lib/components/color-picker/color-picker.module.d.ts +2 -2
- package/lib/components/core-dialog/confirmation-dialog/confirmation-dialog.component.d.ts +20 -20
- package/lib/components/core-dialog/core-dialog.module.d.ts +4 -4
- package/lib/components/core-dialog/core-dialog.service.d.ts +15 -15
- package/lib/components/core-dialog/core-dynamic-component.service.d.ts +12 -12
- package/lib/components/double-calendar/double-calendar.component.d.ts +18 -18
- package/lib/components/double-calendar/double-calendar.module.d.ts +2 -2
- package/lib/components/filter-item/filter-item-viewmodel.d.ts +9 -9
- package/lib/components/filter-item/filter-item.component.d.ts +80 -80
- package/lib/components/filter-item/filter-item.module.d.ts +2 -2
- package/lib/components/filter-item/filter-viewmodel.d.ts +8 -8
- package/lib/components/form/form.component.d.ts +39 -39
- package/lib/components/form/form.module.d.ts +2 -2
- package/lib/components/grid-toolbar/grid-toolbar.component.d.ts +19 -19
- package/lib/components/grid-toolbar/grid-toolbar.module.d.ts +2 -2
- package/lib/components/grid-toolbar-button/grid-toolbar-button.component.d.ts +8 -8
- package/lib/components/grid-toolbar-button/grid-toolbar-button.module.d.ts +2 -2
- package/lib/components/icon/icon-cache.service.d.ts +20 -20
- package/lib/components/icon/icon.component.d.ts +17 -17
- package/lib/components/icon/icon.module.d.ts +2 -2
- package/lib/components/icon-collapse-handle/icon-collapse-handle.component.d.ts +21 -21
- package/lib/components/icon-collapse-handle/icon-collapse-handle.module.d.ts +2 -2
- package/lib/components/image/image.component.d.ts +20 -20
- package/lib/components/image/image.module.d.ts +2 -2
- package/lib/components/input-checkbox/input-checkbox.component.d.ts +24 -24
- package/lib/components/input-checkbox/input-checkbox.module.d.ts +2 -2
- package/lib/components/input-date-picker/input-date-picker.component.d.ts +12 -12
- package/lib/components/input-date-picker/input-date-picker.module.d.ts +2 -2
- package/lib/components/input-date-range-picker/input-date-range-picker.component.d.ts +20 -20
- package/lib/components/input-date-range-picker/input-date-range-picker.module.d.ts +2 -2
- package/lib/components/input-number-picker/input-number-picker.component.d.ts +73 -73
- package/lib/components/input-number-picker/input-number-picker.module.d.ts +2 -2
- package/lib/components/input-radio-button/input-radio-button.component.d.ts +19 -19
- package/lib/components/input-radio-button/input-radio-button.module.d.ts +2 -2
- package/lib/components/input-scanner/bar-code-scanner.d.ts +7 -7
- package/lib/components/input-scanner/input-scanner.component.d.ts +24 -24
- package/lib/components/input-scanner/input-scanner.module.d.ts +2 -2
- package/lib/components/input-scanner/scanner.service.d.ts +11 -11
- package/lib/components/input-search/input-search.component.d.ts +20 -19
- package/lib/components/input-search/input-search.module.d.ts +2 -2
- package/lib/components/input-text/input-text.component.d.ts +65 -65
- package/lib/components/input-text/input-text.module.d.ts +2 -2
- package/lib/components/input-textarea/input-textarea.component.d.ts +19 -19
- package/lib/components/input-textarea/input-textarea.module.d.ts +2 -2
- package/lib/components/level-indicator/level-indicator-level.enum.d.ts +5 -5
- package/lib/components/level-indicator/level-indicator.component.d.ts +10 -10
- package/lib/components/level-indicator/level-indicator.module.d.ts +2 -2
- package/lib/components/list-of-values/list-of-values-multiselect-popup.component.d.ts +25 -25
- package/lib/components/list-of-values/list-of-values-popup.component.d.ts +47 -47
- package/lib/components/list-of-values/list-of-values.component.d.ts +37 -37
- package/lib/components/list-of-values/list-of-values.module.d.ts +2 -2
- package/lib/components/loader/loader.component.d.ts +3 -3
- package/lib/components/loader/loader.module.d.ts +2 -2
- package/lib/components/pagination/paginate.pipe.d.ts +15 -15
- package/lib/components/pagination/pagination-instance.d.ts +14 -14
- package/lib/components/pagination/pagination.component.d.ts +38 -38
- package/lib/components/pagination/pagination.module.d.ts +2 -2
- package/lib/components/pagination/pagination.service.d.ts +24 -24
- package/lib/components/pagination-bar/pagination-bar.component.d.ts +33 -33
- package/lib/components/pagination-bar/pagination-bar.module.d.ts +2 -2
- package/lib/components/popup/const/popup-window-token.d.ts +3 -3
- package/lib/components/popup/interface/popup-button.d.ts +8 -8
- package/lib/components/popup/interface/popup-close-event.d.ts +5 -5
- package/lib/components/popup/interface/popup-settings.d.ts +21 -21
- package/lib/components/popup/interface/popup.d.ts +9 -9
- package/lib/components/popup/model/popup-button-globals.d.ts +9 -9
- package/lib/components/popup/model/popup-window.d.ts +21 -21
- package/lib/components/popup/popup-buttons.component.d.ts +13 -13
- package/lib/components/popup/popup-message-display.component.d.ts +12 -12
- package/lib/components/popup/popup-window-shell.component.d.ts +42 -42
- package/lib/components/popup/popup.module.d.ts +4 -4
- package/lib/components/popup/service/popup-shower.service.d.ts +17 -17
- package/lib/components/popup/service/prompt.service.d.ts +17 -17
- package/lib/components/popup/text-input-popup.component.d.ts +12 -12
- package/lib/components/responsive-text/responsive-text.component.d.ts +4 -4
- package/lib/components/responsive-text/responsive-text.module.d.ts +2 -2
- package/lib/components/simple-grid/base-simple-grid.component.d.ts +52 -52
- package/lib/components/simple-grid/simple-grid-cell.component.d.ts +30 -30
- package/lib/components/simple-grid/simple-grid-column.directive.d.ts +42 -42
- package/lib/components/simple-grid/simple-grid.component.d.ts +64 -64
- package/lib/components/simple-grid/simple-grid.module.d.ts +2 -2
- package/lib/components/tile/tile.component.d.ts +16 -16
- package/lib/components/tile/tile.module.d.ts +2 -2
- package/lib/components/tile-select/tile-select.component.d.ts +8 -8
- package/lib/components/tile-select/tile-select.module.d.ts +2 -2
- package/lib/components/tooltip/tooltip.component.d.ts +18 -18
- package/lib/components/tooltip/tooltip.module.d.ts +2 -2
- package/lib/components/validation-error/validation-error.component.d.ts +12 -12
- package/lib/components/validation-error/validation-error.module.d.ts +2 -2
- package/lib/components/view-mode-buttons/content-view-mode.enum.d.ts +8 -8
- package/lib/components/view-mode-buttons/view-mode-buttons.component.d.ts +17 -17
- package/lib/components/view-mode-buttons/view-mode-buttons.module.d.ts +2 -2
- package/lib/core/constant/default-upper-bound-for-range-components.d.ts +2 -2
- package/lib/core/constant/java-max-int.d.ts +1 -1
- package/lib/core/constant/number-inputs-key-down-white-list.d.ts +2 -2
- package/lib/core/decorator/input-boolean.decorator.d.ts +8 -8
- package/lib/core/enum/co-direction.d.ts +6 -6
- package/lib/core/enum/co-document-image-display-kind.enum.d.ts +5 -5
- package/lib/core/enum/co-document-type.enum.d.ts +5 -5
- package/lib/core/enum/co-orientation.d.ts +6 -6
- package/lib/core/enum/core-components-icon.enum.d.ts +298 -298
- package/lib/core/enum/file-type-internal.enum.d.ts +15 -15
- package/lib/core/enum/file-type.enum.d.ts +5 -5
- package/lib/core/enum/filterItem-mode.enum.d.ts +15 -15
- package/lib/core/enum/input-number-picker-show-mode.enum.d.ts +5 -5
- package/lib/core/enum/keyboard-code.enum.d.ts +71 -71
- package/lib/core/enum/keyboard-key.enum.d.ts +70 -70
- package/lib/core/enum/object-right-type.enum.d.ts +5 -5
- package/lib/core/enum/popup-button-type.enum.d.ts +9 -9
- package/lib/core/enum/popup-type.enum.d.ts +9 -9
- package/lib/core/enum/table-name.enum.d.ts +79 -79
- package/lib/core/function/any-nill.function.d.ts +1 -1
- package/lib/core/function/is-nill.function.d.ts +1 -1
- package/lib/core/function/none-nill.function.d.ts +1 -1
- package/lib/core/function/not-nill.function.d.ts +1 -1
- package/lib/core/model/bounds-constrained-number-value.d.ts +46 -46
- package/lib/core/model/check-precision-and-scale-result.d.ts +4 -4
- package/lib/core/model/check-within-stepped-bounds-result.d.ts +8 -8
- package/lib/core/model/co-document-right.bo.d.ts +6 -6
- package/lib/core/model/co-document.bo.d.ts +61 -61
- package/lib/core/model/core-components-icon-svg.d.ts +4 -4
- package/lib/core/model/element-position.d.ts +7 -7
- package/lib/core/model/event/string-prompt-result-event.d.ts +6 -6
- package/lib/core/service/form-input-user-change-listener.service.d.ts +10 -10
- package/lib/core/service/form-master.service.d.ts +26 -26
- package/lib/core/service/ng-zone-wrapper.service.d.ts +6 -6
- package/lib/core/utils/array-utils.d.ts +85 -85
- package/lib/core/utils/browser-utils.d.ts +15 -15
- package/lib/core/utils/direction-enum-utils.d.ts +5 -5
- package/lib/core/utils/event-utils.d.ts +12 -12
- package/lib/core/utils/file-utils.d.ts +29 -29
- package/lib/core/utils/number-utils.d.ts +89 -89
- package/lib/core/utils/object-utils.d.ts +31 -31
- package/lib/core/utils/string-utils.d.ts +25 -25
- package/lib/core/validator/email.validator.d.ts +2 -2
- package/lib/core/validator/equal.validator.d.ts +2 -2
- package/lib/core/validator/max-string-length.validator.d.ts +2 -2
- package/lib/core/validator/password.validator.d.ts +3 -3
- package/lib/core/validator/precision-scale.validator.d.ts +2 -2
- package/lib/core/validator/required.validator.d.ts +2 -2
- package/lib/directives/clickoutside/click-outside-master.service.d.ts +15 -15
- package/lib/directives/clickoutside/click-outside.directive.d.ts +18 -18
- package/lib/directives/clickoutside/clickoutside.module.d.ts +2 -2
- package/lib/directives/observe-visibility/observe-visibility.directive.d.ts +14 -14
- package/lib/directives/observe-visibility/observe-visibility.module.d.ts +2 -2
- package/lib/directives/overlay/overlay-parent.directive.d.ts +6 -6
- package/lib/directives/overlay/overlay.directive.d.ts +25 -25
- package/lib/directives/overlay/overlay.module.d.ts +2 -2
- package/lib/directives/ripple/ripple-ref.d.ts +21 -21
- package/lib/directives/ripple/ripple-renderer.d.ts +56 -56
- package/lib/directives/ripple/ripple.directive.d.ts +56 -56
- package/lib/directives/ripple/ripple.module.d.ts +2 -2
- package/lib/directives/ripple/scroll-dispatcher.service.d.ts +51 -51
- package/lib/directives/ripple/scrollable.directive.d.ts +20 -20
- package/lib/directives/ripple/viewport-ruler.service.d.ts +29 -29
- package/lib/directives/screen-configuration/screen-configuration.directive.d.ts +32 -32
- package/lib/directives/screen-configuration/screen-configuration.module.d.ts +2 -2
- package/lib/directives/stopclick/stop-click.directive.d.ts +10 -10
- package/lib/directives/stopclick/stop-click.module.d.ts +2 -2
- package/lib/directives/template-wrapper/template-wrapper.directive.d.ts +13 -13
- package/lib/directives/template-wrapper/template-wrapper.module.d.ts +2 -2
- package/lib/directives/tooltip/tooltip-directive.module.d.ts +2 -2
- package/lib/directives/tooltip/tooltip.directive.d.ts +20 -20
- package/lib/interfaces/dialog-response.interface.d.ts +6 -6
- package/lib/interfaces/scanner-input.interface.d.ts +3 -3
- package/lib/interfaces/screen-config-adapter-component-interface-name.d.ts +3 -3
- package/lib/interfaces/screen-config-adapter.component.interface.d.ts +10 -10
- package/lib/model/enum/app-button-type.enum.d.ts +9 -9
- package/lib/model/enum/app-popup-type.enum.d.ts +6 -6
- package/lib/pipes/append.pipe.d.ts +4 -4
- package/lib/pipes/append.pipe.module.d.ts +2 -2
- package/lib/pipes/filter.pipe.d.ts +4 -4
- package/lib/pipes/filter.pipe.module.d.ts +2 -2
- package/lib/pipes/prepend.pipe.d.ts +4 -4
- package/lib/pipes/prepend.pipe.module.d.ts +2 -2
- package/lib/pipes/price-display-pipe.module.d.ts +2 -2
- package/lib/pipes/price-display.pipe.d.ts +4 -4
- package/lib/service/base-module-screen-config.service.d.ts +47 -47
- package/lib/service/base-module.service.d.ts +22 -22
- package/lib/service/color-sequence.service.d.ts +4 -4
- package/lib/service/overlay.service.d.ts +13 -13
- package/lib/translation/core-components-translation.module.d.ts +4 -4
- package/lib/translation/core-components-translation.service.d.ts +6 -6
- package/lib/translation/core-dictionary.service.d.ts +12 -12
- package/lib/translation/core-localize.pipe.d.ts +7 -7
- package/package.json +1 -1
- package/public-api.d.ts +126 -126
|
@@ -1,309 +1,309 @@
|
|
|
1
|
-
import { anyNill } from "../function/any-nill.function";
|
|
2
|
-
import { ArrayUtils } from "./array-utils";
|
|
3
|
-
import { isNill } from "../function/is-nill.function";
|
|
4
|
-
import { ObjectUtils } from './object-utils';
|
|
5
|
-
// @dynamic
|
|
6
|
-
export class NumberUtils {
|
|
7
|
-
// @returns The inclusive max value
|
|
8
|
-
static PrecisionScaleToMaxValue(precision, scale) {
|
|
9
|
-
const oneStep = this.DecimalsToStepIncrement(scale);
|
|
10
|
-
const maxExclusive = Math.pow(10, precision - scale);
|
|
11
|
-
return maxExclusive - oneStep;
|
|
12
|
-
}
|
|
13
|
-
// Parses given argument to an integer, using a native parseInt() function with a radix of 10. Returns NaN if parsing was not possible.
|
|
14
|
-
static ParseInt(arg) {
|
|
15
|
-
if (isNill(arg) || Array.isArray(arg)) {
|
|
16
|
-
return undefined;
|
|
17
|
-
}
|
|
18
|
-
return parseInt(arg, 10);
|
|
19
|
-
}
|
|
20
|
-
static DecimalsToStepIncrement(numberOfDecimals) {
|
|
21
|
-
return Math.pow(10, -1 * numberOfDecimals);
|
|
22
|
-
}
|
|
23
|
-
// Returns the given argument as a number. Returns given defaultValue if conversion of argument was impossible.
|
|
24
|
-
static ParseNumberOrDefault(arg, defaultValue = 0) {
|
|
25
|
-
if (Array.isArray(arg)) {
|
|
26
|
-
return defaultValue;
|
|
27
|
-
}
|
|
28
|
-
if (!NumberUtils.IsNumber(arg)) {
|
|
29
|
-
arg = parseFloat(arg);
|
|
30
|
-
arg = isNaN(arg) ? defaultValue : arg;
|
|
31
|
-
}
|
|
32
|
-
return arg;
|
|
33
|
-
}
|
|
34
|
-
// Parses given numberInput to a number, or returns given defaultValue if parse not possible. Allows ',' char as decimal delimiter.
|
|
35
|
-
static ParseNumberInputOrDefault(numberInput, defaultValue = 0) {
|
|
36
|
-
return NumberUtils.ParseNumberOrDefault(NumberUtils._NumberInputToNumberStr(numberInput), defaultValue);
|
|
37
|
-
}
|
|
38
|
-
static IsParsableNumberInput(numberInput) {
|
|
39
|
-
return NumberUtils.IsParsableNumber(NumberUtils._NumberInputToNumberStr(numberInput));
|
|
40
|
-
}
|
|
41
|
-
// Returns whether the type of given argument is 'number'.
|
|
42
|
-
static IsNumber(arg) {
|
|
43
|
-
return typeof arg === 'number';
|
|
44
|
-
}
|
|
45
|
-
// Returns whether the value is parasable as a number.
|
|
46
|
-
static IsParsableNumber(arg) {
|
|
47
|
-
if (Array.isArray(arg)) {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
return !isNaN(parseFloat(arg));
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Returns given arg as a float number with given decimal precision, if possible. Returns NaN if parse conversion failed.
|
|
54
|
-
*
|
|
55
|
-
* @param The argument to parse to a float
|
|
56
|
-
* @param The number of decimals, or the precision, the parsed return float should have
|
|
57
|
-
* @returns NaN if not possible, else the parsed float value
|
|
58
|
-
*/
|
|
59
|
-
static ParseFloat(arg, decimalPrecision = 2) {
|
|
60
|
-
if (anyNill(arg, decimalPrecision) || Array.isArray(arg)) {
|
|
61
|
-
return NaN;
|
|
62
|
-
}
|
|
63
|
-
if (!NumberUtils.IsInteger(decimalPrecision) || decimalPrecision < 0) {
|
|
64
|
-
decimalPrecision = 2;
|
|
65
|
-
// toFixed() can only handle up until 20
|
|
66
|
-
}
|
|
67
|
-
else if (decimalPrecision > 20) {
|
|
68
|
-
decimalPrecision = 20;
|
|
69
|
-
}
|
|
70
|
-
return parseFloat(parseFloat(arg).toFixed(decimalPrecision));
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Returns given arg as a float number with given decimal precision, if possible. Returns NaN if parse conversion failed.
|
|
74
|
-
*
|
|
75
|
-
* @param The argument to parse to a float
|
|
76
|
-
* @returns The argument as a float with its original decimal precision intact
|
|
77
|
-
*/
|
|
78
|
-
static ParseFloatKeepPrecision(arg) {
|
|
79
|
-
let decimalPrecision = this.GetDecimalPlaces(arg);
|
|
80
|
-
return this.ParseFloat(arg, decimalPrecision);
|
|
81
|
-
}
|
|
82
|
-
static ParseFloatNumberInputKeepPrecision(arg) {
|
|
83
|
-
let correctedInputStr = NumberUtils._NumberInputToNumberStr(arg);
|
|
84
|
-
let decimalPrecision = this.GetDecimalPlaces(correctedInputStr);
|
|
85
|
-
return NumberUtils.ParseFloat(correctedInputStr, decimalPrecision);
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Finds the number closest to the originalNumber, that adheres to the given bounds. That is, for which it holds that
|
|
89
|
-
* nr = min + N * step with N integer or 0.
|
|
90
|
-
* @param originalNr Find closest answer to this number
|
|
91
|
-
* @param min Inclusive
|
|
92
|
-
* @param max Inclusive
|
|
93
|
-
* @param stepSize
|
|
94
|
-
* @returns The closest OK number for bounds.
|
|
95
|
-
*/
|
|
96
|
-
static GetNearestNumberWithinSteppedBounds(originalNr, min, max, stepSize = 1) {
|
|
97
|
-
if (originalNr < min) {
|
|
98
|
-
return min;
|
|
99
|
-
}
|
|
100
|
-
else if (originalNr > max) {
|
|
101
|
-
return NumberUtils.GetTrueSteppedBoundsMax(min, max, stepSize);
|
|
102
|
-
}
|
|
103
|
-
let boundsCheck = NumberUtils.CheckWithinSteppedBounds(originalNr, min, max, stepSize);
|
|
104
|
-
if (boundsCheck.isOk) {
|
|
105
|
-
return originalNr;
|
|
106
|
-
}
|
|
107
|
-
let answer = undefined;
|
|
108
|
-
let remainder = boundsCheck.remainder;
|
|
109
|
-
if (remainder) {
|
|
110
|
-
// round up or down?
|
|
111
|
-
if ((remainder / stepSize) < 0.5) {
|
|
112
|
-
// round down, but not below min
|
|
113
|
-
answer = (originalNr - remainder >= min ? originalNr - remainder : min);
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
// round up, but not above max
|
|
117
|
-
answer = (originalNr + stepSize - remainder <= max ? originalNr + stepSize - remainder :
|
|
118
|
-
NumberUtils.GetTrueSteppedBoundsMax(min, max, stepSize));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
// is this real life, why wasn't our stepped bounds check OK?
|
|
123
|
-
answer = originalNr;
|
|
124
|
-
}
|
|
125
|
-
// 'correct' float errors
|
|
126
|
-
answer = NumberUtils.ParseFloat(answer, NumberUtils._GetLargestDecimalPrecisionOf(originalNr, min, max, stepSize));
|
|
127
|
-
return answer;
|
|
128
|
-
}
|
|
129
|
-
// Returns the number of decimal places of the given number. Returns 0 if no decimals whatsoever could be found on given arg.
|
|
130
|
-
static GetDecimalPlaces(arg, maxAnswer = 1000) {
|
|
131
|
-
let match = ('' + arg).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
|
|
132
|
-
if (!match) {
|
|
133
|
-
return 0;
|
|
134
|
-
}
|
|
135
|
-
let answer = Math.max(0,
|
|
136
|
-
// number of digits right of decimal point.
|
|
137
|
-
(match[1] ? match[1].length : 0)
|
|
138
|
-
// adjust for scientific notation
|
|
139
|
-
- (match[2] ? +match[2] : 0));
|
|
140
|
-
if (answer > maxAnswer) {
|
|
141
|
-
answer = maxAnswer;
|
|
142
|
-
}
|
|
143
|
-
return answer;
|
|
144
|
-
}
|
|
145
|
-
// Returns true iff given argument is an integer number. Returns false on non-numbers or numbers with significant decimals.
|
|
146
|
-
static IsInteger(arg) {
|
|
147
|
-
if (isNaN(arg) || Array.isArray(arg)) {
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
let argAsFloat = parseFloat(arg);
|
|
151
|
-
return ((argAsFloat | 0) === argAsFloat); // returns whether 'arg converted to an integer equals arg'
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Returns whether given arg is parseable as a number, and whether the lengts of its number parse result is equal to its original length.
|
|
155
|
-
* I.e. this function returns FALSE with given number-parsable strings, but that have non-numeric appendices, eg '2233ff'. That arg
|
|
156
|
-
* IS number-parseable, but not a strict 'string number', the latter being what this method actually checks for.
|
|
157
|
-
*/
|
|
158
|
-
static IsStringNumber(arg) {
|
|
159
|
-
if (!NumberUtils.IsParsableNumber(arg)) {
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
return arg.toString().length === parseFloat(arg).toString().length;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Returns a random integer in range [lowerBound .. upperBound], an inclusive range. Returns NaN if not possible.
|
|
168
|
-
* Given bounds are truncated first, before serving as the true lower- and upper bounds for the random int.
|
|
169
|
-
*/
|
|
170
|
-
static RandomInt(lowerBoundInt, upperBoundInt) {
|
|
171
|
-
if (!NumberUtils.IsNumber(lowerBoundInt) || !NumberUtils.IsNumber(upperBoundInt) || lowerBoundInt > upperBoundInt) {
|
|
172
|
-
return NaN;
|
|
173
|
-
}
|
|
174
|
-
lowerBoundInt = Math.trunc(lowerBoundInt);
|
|
175
|
-
upperBoundInt = Math.trunc(upperBoundInt);
|
|
176
|
-
if (lowerBoundInt === upperBoundInt) {
|
|
177
|
-
return lowerBoundInt;
|
|
178
|
-
}
|
|
179
|
-
const delta = upperBoundInt - lowerBoundInt;
|
|
180
|
-
return (Math.round(Math.random() * delta) + lowerBoundInt);
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Returns the true maximum allowed value for the given "stepped bounds": min, stepSize and max, for which it holds that each allowed
|
|
184
|
-
* value Y = min + stepSize * N, for any INTEGER or 0 N where it also holds, of course, that Y <= max.
|
|
185
|
-
* @param min
|
|
186
|
-
* @param max
|
|
187
|
-
* @param stepSize
|
|
188
|
-
*/
|
|
189
|
-
static GetTrueSteppedBoundsMax(min, max, stepSize = 1) {
|
|
190
|
-
// solve max integer X in formula min + X * step <= max, and return min + X * stepSize for that X
|
|
191
|
-
let maxSteps = Math.floor((max - min) / stepSize);
|
|
192
|
-
// 'correct' float errors
|
|
193
|
-
return NumberUtils.ParseFloat(min + maxSteps * stepSize, NumberUtils._GetLargestDecimalPrecisionOf(min, min, max));
|
|
194
|
-
}
|
|
195
|
-
// Returns the string representation of given number. If it's not a number, returns the empty string.
|
|
196
|
-
static ToString(nr) {
|
|
197
|
-
if (!NumberUtils.IsNaN(nr)) {
|
|
198
|
-
return "" + nr;
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
return "";
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
// Returns whether given arg is indeed not a number (it's NaN or it has another type than 'number').
|
|
205
|
-
static IsNaN(arg) {
|
|
206
|
-
return isNaN(arg) || !NumberUtils.IsNumber(arg);
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Returns whether given x is OK within the given min, max and step boundaries, where it should hold that nrToCheck = min + N * step,
|
|
210
|
-
* with N integer or 0.
|
|
211
|
-
* @param nrToCheck Number to check whether it's within the given bounds
|
|
212
|
-
* @param min Inclusive
|
|
213
|
-
* @param max Inclusive
|
|
214
|
-
* @param stepSize
|
|
215
|
-
* @returns Returns remainder of undefined when nrToCheck was OUTSIDE [min, max], else full result object.
|
|
216
|
-
*/
|
|
217
|
-
static CheckWithinSteppedBounds(nrToCheck, min, max, stepSize = 1) {
|
|
218
|
-
if (nrToCheck < min || nrToCheck > max) {
|
|
219
|
-
return { isOk: false, remainder: undefined };
|
|
220
|
-
}
|
|
221
|
-
// we're in [min, max], but still check if nrToCheck = min + N * step holds (for N integer or 0)
|
|
222
|
-
let remainder = (nrToCheck - min) % stepSize;
|
|
223
|
-
// correct float for largest precision amongst input numbers
|
|
224
|
-
remainder = NumberUtils.ParseFloat(remainder, NumberUtils._GetLargestDecimalPrecisionOf(nrToCheck, min, stepSize));
|
|
225
|
-
return { isOk: (remainder === 0), remainder: remainder };
|
|
226
|
-
}
|
|
227
|
-
// Adds thousands comma's to given value, E.g. '1000' to '1,000'. Returns empty string if value was undefined.
|
|
228
|
-
static AddThousandsCommasTo(value) {
|
|
229
|
-
if (isNill(value)) {
|
|
230
|
-
return "";
|
|
231
|
-
}
|
|
232
|
-
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
233
|
-
}
|
|
234
|
-
// Returns the nearest number, relative to the given originalNr, that is within the given [min, max] inclusive bounds.
|
|
235
|
-
static GetNearestNumberWithinBounds(originalNr, min, max) {
|
|
236
|
-
let answer = originalNr;
|
|
237
|
-
if (originalNr < min) {
|
|
238
|
-
answer = min;
|
|
239
|
-
}
|
|
240
|
-
else if (originalNr > max) {
|
|
241
|
-
answer = max;
|
|
242
|
-
}
|
|
243
|
-
return answer;
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Returns whether given nrToCheck is within the given precision and scale limits. Precision and scale, here, are Oracle DB terms.
|
|
247
|
-
* This function can thus be used to check whether the given number is safe to send to the 'database' beforehand, if we know the
|
|
248
|
-
* precision and scale of the number in the db declaration.
|
|
249
|
-
*
|
|
250
|
-
* I.e. A number declared in the Oracle DB as number(5, 2) has a precision of 5 and a scale of 2.
|
|
251
|
-
*
|
|
252
|
-
* @param nrToCheck
|
|
253
|
-
* @param precision The number of significant digits, including possibly negative scale. E.g. 3 in '123' and 5 in '51.123'
|
|
254
|
-
* @param [scale = 0] The number of significant digits AFTER the decimal point. E.g. 1 in 5432.1 and 3 in 54000.003
|
|
255
|
-
* @returns Whether given nrToCheck is ok for given precision and scale, and if not, the
|
|
256
|
-
* nearest number that IS ok for those constraints.
|
|
257
|
-
*/
|
|
258
|
-
static CheckPrecisionAndScale(nrToCheck, precision, scale = 0) {
|
|
259
|
-
// let's say any undefined number is checked OK, and all numbers are checked OK for an undefined precision
|
|
260
|
-
if (!ObjectUtils.AllExist(nrToCheck, precision, scale)) {
|
|
261
|
-
return { isOk: true, nearestOkNr: NaN };
|
|
262
|
-
}
|
|
263
|
-
// no number can have 0 or less than 0 significant digits, in our universe
|
|
264
|
-
if (precision < 1 || precision - scale < 1) {
|
|
265
|
-
return { isOk: false, nearestOkNr: NaN };
|
|
266
|
-
}
|
|
267
|
-
// begin check
|
|
268
|
-
const isNegative = (nrToCheck < 0);
|
|
269
|
-
const nrParts = nrToCheck.toString().split(".");
|
|
270
|
-
// remove minus sign if negative
|
|
271
|
-
if (isNegative) {
|
|
272
|
-
nrParts[0] = nrParts[0].slice(1);
|
|
273
|
-
}
|
|
274
|
-
const numCountBeforeDot = nrParts[0].length;
|
|
275
|
-
const allowedNumCountBeforeDot = precision - scale;
|
|
276
|
-
if (numCountBeforeDot <= allowedNumCountBeforeDot) {
|
|
277
|
-
return { isOk: true, nearestOkNr: nrToCheck };
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
// cut a part from the "before decimal number" so that the number is not too big anymore
|
|
281
|
-
const numCountToRemove = numCountBeforeDot - allowedNumCountBeforeDot;
|
|
282
|
-
// remove the right-most numbers before the decimal dot
|
|
283
|
-
nrParts[0] = nrParts[0].slice(0, -1 * numCountToRemove);
|
|
284
|
-
// add minus sign again if it was negative
|
|
285
|
-
if (isNegative) {
|
|
286
|
-
nrParts[0] = "-" + nrParts[0];
|
|
287
|
-
}
|
|
288
|
-
// build and return composite number again
|
|
289
|
-
let nearestOkNr;
|
|
290
|
-
if (nrParts[1]) {
|
|
291
|
-
nearestOkNr = Number(nrParts[0] + "." + nrParts[1]);
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
nearestOkNr = Number(nrParts[0]);
|
|
295
|
-
}
|
|
296
|
-
return { isOk: false, nearestOkNr: nearestOkNr };
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
static _GetLargestDecimalPrecisionOf(...args) {
|
|
300
|
-
return ArrayUtils.GetMaxCalculatedValue(args, (arg) => {
|
|
301
|
-
return NumberUtils.GetDecimalPlaces(arg);
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
// Returns given number input as a number that's useable by Javascript. Allows for incoming ',' decimal delimiter.
|
|
305
|
-
static _NumberInputToNumberStr(numberInput) {
|
|
306
|
-
return (numberInput + '').replace(',', '.');
|
|
307
|
-
}
|
|
308
|
-
}
|
|
1
|
+
import { anyNill } from "../function/any-nill.function";
|
|
2
|
+
import { ArrayUtils } from "./array-utils";
|
|
3
|
+
import { isNill } from "../function/is-nill.function";
|
|
4
|
+
import { ObjectUtils } from './object-utils';
|
|
5
|
+
// @dynamic
|
|
6
|
+
export class NumberUtils {
|
|
7
|
+
// @returns The inclusive max value
|
|
8
|
+
static PrecisionScaleToMaxValue(precision, scale) {
|
|
9
|
+
const oneStep = this.DecimalsToStepIncrement(scale);
|
|
10
|
+
const maxExclusive = Math.pow(10, precision - scale);
|
|
11
|
+
return maxExclusive - oneStep;
|
|
12
|
+
}
|
|
13
|
+
// Parses given argument to an integer, using a native parseInt() function with a radix of 10. Returns NaN if parsing was not possible.
|
|
14
|
+
static ParseInt(arg) {
|
|
15
|
+
if (isNill(arg) || Array.isArray(arg)) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
return parseInt(arg, 10);
|
|
19
|
+
}
|
|
20
|
+
static DecimalsToStepIncrement(numberOfDecimals) {
|
|
21
|
+
return Math.pow(10, -1 * numberOfDecimals);
|
|
22
|
+
}
|
|
23
|
+
// Returns the given argument as a number. Returns given defaultValue if conversion of argument was impossible.
|
|
24
|
+
static ParseNumberOrDefault(arg, defaultValue = 0) {
|
|
25
|
+
if (Array.isArray(arg)) {
|
|
26
|
+
return defaultValue;
|
|
27
|
+
}
|
|
28
|
+
if (!NumberUtils.IsNumber(arg)) {
|
|
29
|
+
arg = parseFloat(arg);
|
|
30
|
+
arg = isNaN(arg) ? defaultValue : arg;
|
|
31
|
+
}
|
|
32
|
+
return arg;
|
|
33
|
+
}
|
|
34
|
+
// Parses given numberInput to a number, or returns given defaultValue if parse not possible. Allows ',' char as decimal delimiter.
|
|
35
|
+
static ParseNumberInputOrDefault(numberInput, defaultValue = 0) {
|
|
36
|
+
return NumberUtils.ParseNumberOrDefault(NumberUtils._NumberInputToNumberStr(numberInput), defaultValue);
|
|
37
|
+
}
|
|
38
|
+
static IsParsableNumberInput(numberInput) {
|
|
39
|
+
return NumberUtils.IsParsableNumber(NumberUtils._NumberInputToNumberStr(numberInput));
|
|
40
|
+
}
|
|
41
|
+
// Returns whether the type of given argument is 'number'.
|
|
42
|
+
static IsNumber(arg) {
|
|
43
|
+
return typeof arg === 'number';
|
|
44
|
+
}
|
|
45
|
+
// Returns whether the value is parasable as a number.
|
|
46
|
+
static IsParsableNumber(arg) {
|
|
47
|
+
if (Array.isArray(arg)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return !isNaN(parseFloat(arg));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns given arg as a float number with given decimal precision, if possible. Returns NaN if parse conversion failed.
|
|
54
|
+
*
|
|
55
|
+
* @param The argument to parse to a float
|
|
56
|
+
* @param The number of decimals, or the precision, the parsed return float should have
|
|
57
|
+
* @returns NaN if not possible, else the parsed float value
|
|
58
|
+
*/
|
|
59
|
+
static ParseFloat(arg, decimalPrecision = 2) {
|
|
60
|
+
if (anyNill(arg, decimalPrecision) || Array.isArray(arg)) {
|
|
61
|
+
return NaN;
|
|
62
|
+
}
|
|
63
|
+
if (!NumberUtils.IsInteger(decimalPrecision) || decimalPrecision < 0) {
|
|
64
|
+
decimalPrecision = 2;
|
|
65
|
+
// toFixed() can only handle up until 20
|
|
66
|
+
}
|
|
67
|
+
else if (decimalPrecision > 20) {
|
|
68
|
+
decimalPrecision = 20;
|
|
69
|
+
}
|
|
70
|
+
return parseFloat(parseFloat(arg).toFixed(decimalPrecision));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Returns given arg as a float number with given decimal precision, if possible. Returns NaN if parse conversion failed.
|
|
74
|
+
*
|
|
75
|
+
* @param The argument to parse to a float
|
|
76
|
+
* @returns The argument as a float with its original decimal precision intact
|
|
77
|
+
*/
|
|
78
|
+
static ParseFloatKeepPrecision(arg) {
|
|
79
|
+
let decimalPrecision = this.GetDecimalPlaces(arg);
|
|
80
|
+
return this.ParseFloat(arg, decimalPrecision);
|
|
81
|
+
}
|
|
82
|
+
static ParseFloatNumberInputKeepPrecision(arg) {
|
|
83
|
+
let correctedInputStr = NumberUtils._NumberInputToNumberStr(arg);
|
|
84
|
+
let decimalPrecision = this.GetDecimalPlaces(correctedInputStr);
|
|
85
|
+
return NumberUtils.ParseFloat(correctedInputStr, decimalPrecision);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Finds the number closest to the originalNumber, that adheres to the given bounds. That is, for which it holds that
|
|
89
|
+
* nr = min + N * step with N integer or 0.
|
|
90
|
+
* @param originalNr Find closest answer to this number
|
|
91
|
+
* @param min Inclusive
|
|
92
|
+
* @param max Inclusive
|
|
93
|
+
* @param stepSize
|
|
94
|
+
* @returns The closest OK number for bounds.
|
|
95
|
+
*/
|
|
96
|
+
static GetNearestNumberWithinSteppedBounds(originalNr, min, max, stepSize = 1) {
|
|
97
|
+
if (originalNr < min) {
|
|
98
|
+
return min;
|
|
99
|
+
}
|
|
100
|
+
else if (originalNr > max) {
|
|
101
|
+
return NumberUtils.GetTrueSteppedBoundsMax(min, max, stepSize);
|
|
102
|
+
}
|
|
103
|
+
let boundsCheck = NumberUtils.CheckWithinSteppedBounds(originalNr, min, max, stepSize);
|
|
104
|
+
if (boundsCheck.isOk) {
|
|
105
|
+
return originalNr;
|
|
106
|
+
}
|
|
107
|
+
let answer = undefined;
|
|
108
|
+
let remainder = boundsCheck.remainder;
|
|
109
|
+
if (remainder) {
|
|
110
|
+
// round up or down?
|
|
111
|
+
if ((remainder / stepSize) < 0.5) {
|
|
112
|
+
// round down, but not below min
|
|
113
|
+
answer = (originalNr - remainder >= min ? originalNr - remainder : min);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// round up, but not above max
|
|
117
|
+
answer = (originalNr + stepSize - remainder <= max ? originalNr + stepSize - remainder :
|
|
118
|
+
NumberUtils.GetTrueSteppedBoundsMax(min, max, stepSize));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
// is this real life, why wasn't our stepped bounds check OK?
|
|
123
|
+
answer = originalNr;
|
|
124
|
+
}
|
|
125
|
+
// 'correct' float errors
|
|
126
|
+
answer = NumberUtils.ParseFloat(answer, NumberUtils._GetLargestDecimalPrecisionOf(originalNr, min, max, stepSize));
|
|
127
|
+
return answer;
|
|
128
|
+
}
|
|
129
|
+
// Returns the number of decimal places of the given number. Returns 0 if no decimals whatsoever could be found on given arg.
|
|
130
|
+
static GetDecimalPlaces(arg, maxAnswer = 1000) {
|
|
131
|
+
let match = ('' + arg).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
|
|
132
|
+
if (!match) {
|
|
133
|
+
return 0;
|
|
134
|
+
}
|
|
135
|
+
let answer = Math.max(0,
|
|
136
|
+
// number of digits right of decimal point.
|
|
137
|
+
(match[1] ? match[1].length : 0)
|
|
138
|
+
// adjust for scientific notation
|
|
139
|
+
- (match[2] ? +match[2] : 0));
|
|
140
|
+
if (answer > maxAnswer) {
|
|
141
|
+
answer = maxAnswer;
|
|
142
|
+
}
|
|
143
|
+
return answer;
|
|
144
|
+
}
|
|
145
|
+
// Returns true iff given argument is an integer number. Returns false on non-numbers or numbers with significant decimals.
|
|
146
|
+
static IsInteger(arg) {
|
|
147
|
+
if (isNaN(arg) || Array.isArray(arg)) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
let argAsFloat = parseFloat(arg);
|
|
151
|
+
return ((argAsFloat | 0) === argAsFloat); // returns whether 'arg converted to an integer equals arg'
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Returns whether given arg is parseable as a number, and whether the lengts of its number parse result is equal to its original length.
|
|
155
|
+
* I.e. this function returns FALSE with given number-parsable strings, but that have non-numeric appendices, eg '2233ff'. That arg
|
|
156
|
+
* IS number-parseable, but not a strict 'string number', the latter being what this method actually checks for.
|
|
157
|
+
*/
|
|
158
|
+
static IsStringNumber(arg) {
|
|
159
|
+
if (!NumberUtils.IsParsableNumber(arg)) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
return arg.toString().length === parseFloat(arg).toString().length;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Returns a random integer in range [lowerBound .. upperBound], an inclusive range. Returns NaN if not possible.
|
|
168
|
+
* Given bounds are truncated first, before serving as the true lower- and upper bounds for the random int.
|
|
169
|
+
*/
|
|
170
|
+
static RandomInt(lowerBoundInt, upperBoundInt) {
|
|
171
|
+
if (!NumberUtils.IsNumber(lowerBoundInt) || !NumberUtils.IsNumber(upperBoundInt) || lowerBoundInt > upperBoundInt) {
|
|
172
|
+
return NaN;
|
|
173
|
+
}
|
|
174
|
+
lowerBoundInt = Math.trunc(lowerBoundInt);
|
|
175
|
+
upperBoundInt = Math.trunc(upperBoundInt);
|
|
176
|
+
if (lowerBoundInt === upperBoundInt) {
|
|
177
|
+
return lowerBoundInt;
|
|
178
|
+
}
|
|
179
|
+
const delta = upperBoundInt - lowerBoundInt;
|
|
180
|
+
return (Math.round(Math.random() * delta) + lowerBoundInt);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Returns the true maximum allowed value for the given "stepped bounds": min, stepSize and max, for which it holds that each allowed
|
|
184
|
+
* value Y = min + stepSize * N, for any INTEGER or 0 N where it also holds, of course, that Y <= max.
|
|
185
|
+
* @param min
|
|
186
|
+
* @param max
|
|
187
|
+
* @param stepSize
|
|
188
|
+
*/
|
|
189
|
+
static GetTrueSteppedBoundsMax(min, max, stepSize = 1) {
|
|
190
|
+
// solve max integer X in formula min + X * step <= max, and return min + X * stepSize for that X
|
|
191
|
+
let maxSteps = Math.floor((max - min) / stepSize);
|
|
192
|
+
// 'correct' float errors
|
|
193
|
+
return NumberUtils.ParseFloat(min + maxSteps * stepSize, NumberUtils._GetLargestDecimalPrecisionOf(min, min, max));
|
|
194
|
+
}
|
|
195
|
+
// Returns the string representation of given number. If it's not a number, returns the empty string.
|
|
196
|
+
static ToString(nr) {
|
|
197
|
+
if (!NumberUtils.IsNaN(nr)) {
|
|
198
|
+
return "" + nr;
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
return "";
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Returns whether given arg is indeed not a number (it's NaN or it has another type than 'number').
|
|
205
|
+
static IsNaN(arg) {
|
|
206
|
+
return isNaN(arg) || !NumberUtils.IsNumber(arg);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Returns whether given x is OK within the given min, max and step boundaries, where it should hold that nrToCheck = min + N * step,
|
|
210
|
+
* with N integer or 0.
|
|
211
|
+
* @param nrToCheck Number to check whether it's within the given bounds
|
|
212
|
+
* @param min Inclusive
|
|
213
|
+
* @param max Inclusive
|
|
214
|
+
* @param stepSize
|
|
215
|
+
* @returns Returns remainder of undefined when nrToCheck was OUTSIDE [min, max], else full result object.
|
|
216
|
+
*/
|
|
217
|
+
static CheckWithinSteppedBounds(nrToCheck, min, max, stepSize = 1) {
|
|
218
|
+
if (nrToCheck < min || nrToCheck > max) {
|
|
219
|
+
return { isOk: false, remainder: undefined };
|
|
220
|
+
}
|
|
221
|
+
// we're in [min, max], but still check if nrToCheck = min + N * step holds (for N integer or 0)
|
|
222
|
+
let remainder = (nrToCheck - min) % stepSize;
|
|
223
|
+
// correct float for largest precision amongst input numbers
|
|
224
|
+
remainder = NumberUtils.ParseFloat(remainder, NumberUtils._GetLargestDecimalPrecisionOf(nrToCheck, min, stepSize));
|
|
225
|
+
return { isOk: (remainder === 0), remainder: remainder };
|
|
226
|
+
}
|
|
227
|
+
// Adds thousands comma's to given value, E.g. '1000' to '1,000'. Returns empty string if value was undefined.
|
|
228
|
+
static AddThousandsCommasTo(value) {
|
|
229
|
+
if (isNill(value)) {
|
|
230
|
+
return "";
|
|
231
|
+
}
|
|
232
|
+
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
233
|
+
}
|
|
234
|
+
// Returns the nearest number, relative to the given originalNr, that is within the given [min, max] inclusive bounds.
|
|
235
|
+
static GetNearestNumberWithinBounds(originalNr, min, max) {
|
|
236
|
+
let answer = originalNr;
|
|
237
|
+
if (originalNr < min) {
|
|
238
|
+
answer = min;
|
|
239
|
+
}
|
|
240
|
+
else if (originalNr > max) {
|
|
241
|
+
answer = max;
|
|
242
|
+
}
|
|
243
|
+
return answer;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Returns whether given nrToCheck is within the given precision and scale limits. Precision and scale, here, are Oracle DB terms.
|
|
247
|
+
* This function can thus be used to check whether the given number is safe to send to the 'database' beforehand, if we know the
|
|
248
|
+
* precision and scale of the number in the db declaration.
|
|
249
|
+
*
|
|
250
|
+
* I.e. A number declared in the Oracle DB as number(5, 2) has a precision of 5 and a scale of 2.
|
|
251
|
+
*
|
|
252
|
+
* @param nrToCheck
|
|
253
|
+
* @param precision The number of significant digits, including possibly negative scale. E.g. 3 in '123' and 5 in '51.123'
|
|
254
|
+
* @param [scale = 0] The number of significant digits AFTER the decimal point. E.g. 1 in 5432.1 and 3 in 54000.003
|
|
255
|
+
* @returns Whether given nrToCheck is ok for given precision and scale, and if not, the
|
|
256
|
+
* nearest number that IS ok for those constraints.
|
|
257
|
+
*/
|
|
258
|
+
static CheckPrecisionAndScale(nrToCheck, precision, scale = 0) {
|
|
259
|
+
// let's say any undefined number is checked OK, and all numbers are checked OK for an undefined precision
|
|
260
|
+
if (!ObjectUtils.AllExist(nrToCheck, precision, scale)) {
|
|
261
|
+
return { isOk: true, nearestOkNr: NaN };
|
|
262
|
+
}
|
|
263
|
+
// no number can have 0 or less than 0 significant digits, in our universe
|
|
264
|
+
if (precision < 1 || precision - scale < 1) {
|
|
265
|
+
return { isOk: false, nearestOkNr: NaN };
|
|
266
|
+
}
|
|
267
|
+
// begin check
|
|
268
|
+
const isNegative = (nrToCheck < 0);
|
|
269
|
+
const nrParts = nrToCheck.toString().split(".");
|
|
270
|
+
// remove minus sign if negative
|
|
271
|
+
if (isNegative) {
|
|
272
|
+
nrParts[0] = nrParts[0].slice(1);
|
|
273
|
+
}
|
|
274
|
+
const numCountBeforeDot = nrParts[0].length;
|
|
275
|
+
const allowedNumCountBeforeDot = precision - scale;
|
|
276
|
+
if (numCountBeforeDot <= allowedNumCountBeforeDot) {
|
|
277
|
+
return { isOk: true, nearestOkNr: nrToCheck };
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
// cut a part from the "before decimal number" so that the number is not too big anymore
|
|
281
|
+
const numCountToRemove = numCountBeforeDot - allowedNumCountBeforeDot;
|
|
282
|
+
// remove the right-most numbers before the decimal dot
|
|
283
|
+
nrParts[0] = nrParts[0].slice(0, -1 * numCountToRemove);
|
|
284
|
+
// add minus sign again if it was negative
|
|
285
|
+
if (isNegative) {
|
|
286
|
+
nrParts[0] = "-" + nrParts[0];
|
|
287
|
+
}
|
|
288
|
+
// build and return composite number again
|
|
289
|
+
let nearestOkNr;
|
|
290
|
+
if (nrParts[1]) {
|
|
291
|
+
nearestOkNr = Number(nrParts[0] + "." + nrParts[1]);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
nearestOkNr = Number(nrParts[0]);
|
|
295
|
+
}
|
|
296
|
+
return { isOk: false, nearestOkNr: nearestOkNr };
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
static _GetLargestDecimalPrecisionOf(...args) {
|
|
300
|
+
return ArrayUtils.GetMaxCalculatedValue(args, (arg) => {
|
|
301
|
+
return NumberUtils.GetDecimalPlaces(arg);
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
// Returns given number input as a number that's useable by Javascript. Allows for incoming ',' decimal delimiter.
|
|
305
|
+
static _NumberInputToNumberStr(numberInput) {
|
|
306
|
+
return (numberInput + '').replace(',', '.');
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
309
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVtYmVyLXV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY29yZWNvbXBvbmVudHMvc3JjL2xpYi9jb3JlL3V0aWxzL251bWJlci11dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsT0FBTyxFQUFDLE1BQU0sK0JBQStCLENBQUM7QUFDdEQsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUV6QyxPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sOEJBQThCLENBQUM7QUFDcEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRzdDLFdBQVc7QUFDWCxNQUFNLE9BQU8sV0FBVztJQUNwQixtQ0FBbUM7SUFDNUIsTUFBTSxDQUFDLHdCQUF3QixDQUFDLFNBQWlCLEVBQUUsS0FBYTtRQUNuRSxNQUFNLE9BQU8sR0FBVyxJQUFJLENBQUMsdUJBQXVCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDNUQsTUFBTSxZQUFZLEdBQVcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsU0FBUyxHQUFHLEtBQUssQ0FBQyxDQUFDO1FBQzdELE9BQU8sWUFBWSxHQUFHLE9BQU8sQ0FBQztJQUNsQyxDQUFDO0lBRUQsdUlBQXVJO0lBQ2hJLE1BQU0sQ0FBQyxRQUFRLENBQUMsR0FBUTtRQUMzQixJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQ25DLE9BQU8sU0FBUyxDQUFDO1NBQ3BCO1FBRUQsT0FBTyxRQUFRLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzdCLENBQUM7SUFFTSxNQUFNLENBQUMsdUJBQXVCLENBQUMsZ0JBQXdCO1FBQzFELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsZ0JBQWdCLENBQUMs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RyxHQUFHLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7YUFDdkQ7aUJBQU07Z0JBQ0gsV0FBVyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUNwQztZQUNELE9BQU8sRUFBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUMsQ0FBQztTQUNsRDtJQUNMLENBQUM7SUFFTyxNQUFNLENBQUMsNkJBQTZCLENBQUMsR0FBRyxJQUFjO1FBQzFELE9BQU8sVUFBVSxDQUFDLHFCQUFxQixDQUFDLElBQUksRUFBRSxDQUFDLEdBQVcsRUFBRSxFQUFFO1lBQzFELE9BQU8sV0FBVyxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzdDLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVELGtIQUFrSDtJQUMxRyxNQUFNLENBQUMsdUJBQXVCLENBQUMsV0FBbUI7UUFDdEQsT0FBTyxDQUFDLFdBQVcsR0FBRyxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ2hELENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7YW55TmlsbH0gZnJvbSBcIi4uL2Z1bmN0aW9uL2FueS1uaWxsLmZ1bmN0aW9uXCI7XHJcbmltcG9ydCB7QXJyYXlVdGlsc30gZnJvbSBcIi4vYXJyYXktdXRpbHNcIjtcclxuaW1wb3J0IHtDaGVja1dpdGhpblN0ZXBwZWRCb3VuZHNSZXN1bHR9IGZyb20gXCIuLi9tb2RlbC9jaGVjay13aXRoaW4tc3RlcHBlZC1ib3VuZHMtcmVzdWx0XCI7XHJcbmltcG9ydCB7aXNOaWxsfSBmcm9tIFwiLi4vZnVuY3Rpb24vaXMtbmlsbC5mdW5jdGlvblwiO1xyXG5pbXBvcnQgeyBPYmplY3RVdGlscyB9IGZyb20gJy4vb2JqZWN0LXV0aWxzJztcclxuaW1wb3J0IHsgQ2hlY2tQcmVjaXNpb25BbmRTY2FsZVJlc3VsdCB9IGZyb20gJy4uL21vZGVsL2NoZWNrLXByZWNpc2lvbi1hbmQtc2NhbGUtcmVzdWx0JztcclxuXHJcbi8vIEBkeW5hbWljXHJcbmV4cG9ydCBjbGFzcyBOdW1iZXJVdGlscyB7XHJcbiAgICAvLyBAcmV0dXJucyBUaGUgaW5jbHVzaXZlIG1heCB2YWx1ZVxyXG4gICAgcHVibGljIHN0YXRpYyBQcmVjaXNpb25TY2FsZVRvTWF4VmFsdWUocHJlY2lzaW9uOiBudW1iZXIsIHNjYWxlOiBudW1iZXIpOiBudW1iZXIge1xyXG4gICAgICAgIGNvbnN0IG9uZVN0ZXA6IG51bWJlciA9IHRoaXMuRGVjaW1hbHNUb1N0ZXBJbmNyZW1lbnQoc2NhbGUpO1xyXG4gICAgICAgIGNvbnN0IG1heEV4Y2x1c2l2ZTogbnVtYmVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiAtIHNjYWxlKTtcclxuICAgICAgICByZXR1cm4gbWF4RXhjbHVzaXZlIC0gb25lU3RlcDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBQYXJzZXMgZ2l2ZW4gYXJndW1lbnQgdG8gYW4gaW50ZWdlciwgdXNpbmcgYSBuYXRpdmUgcGFyc2VJbnQoKSBmdW5jdGlvbiB3aXRoIGEgcmFkaXggb2YgMTAuIFJldHVybnMgTmFOIGlmIHBhcnNpbmcgd2FzIG5vdCBwb3NzaWJsZS5cclxuICAgIHB1YmxpYyBzdGF0aWMgUGFyc2VJbnQoYXJnOiBhbnkpOiBudW1iZXIge1xyXG4gICAgICAgIGlmIChpc05pbGwoYXJnKSB8fCBBcnJheS5pc0FycmF5KGFyZykpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiBwYXJzZUludChhcmcsIDEwKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgc3RhdGljIERlY2ltYWxzVG9TdGVwSW5jcmVtZW50KG51bWJlck9mRGVjaW1hbHM6IG51bWJlcik6IG51bWJlciB7XHJcbiAgICAgICAgcmV0dXJuIE1hdGgucG93KDEwLCAtMSAqIG51bWJlck9mRGVjaW1hbHMpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybnMgdGhlIGdpdmVuIGFyZ3VtZW50IGFzIGEgbnVtYmVyLiBSZXR1cm5zIGdpdmVuIGRlZmF1bHRWYWx1ZSBpZiBjb252ZXJzaW9uIG9mIGFyZ3VtZW50IHdhcyBpbXBvc3NpYmxlLlxyXG4gICAgcHVibGljIHN0YXRpYyBQYXJzZU51bWJlck9yRGVmYXVsdChhcmc6IGFueSwgZGVmYXVsdFZhbHVlOiBudW1iZXIgPSAwKTogbnVtYmVyIHtcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShhcmcpKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBkZWZhdWx0VmFsdWU7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoIU51bWJlclV0aWxzLklzTnVtYmVyKGFyZykpIHtcclxuICAgICAgICAgICAgYXJnID0gcGFyc2VGbG9hdChhcmcpO1xyXG4gICAgICAgICAgICBhcmcgPSBpc05hTihhcmcpID8gZGVmYXVsdFZhbHVlIDogYXJnO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gYXJnO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFBhcnNlcyBnaXZlbiBudW1iZXJJbnB1dCB0byBhIG51bWJlciwgb3IgcmV0dXJucyBnaXZlbiBkZWZhdWx0VmFsdWUgaWYgcGFyc2Ugbm90IHBvc3NpYmxlLiBBbGxvd3MgJywnIGNoYXIgYXMgZGVjaW1hbCBkZWxpbWl0ZXIuXHJcbiAgICBwdWJsaWMgc3RhdGljIFBhcnNlTnVtYmVySW5wdXRPckRlZmF1bHQobnVtYmVySW5wdXQ6IGFueSwgZGVmYXVsdFZhbHVlOiBudW1iZXIgPSAwKTogbnVtYmVyIHtcclxuICAgICAgICByZXR1cm4gTnVtYmVyVXRpbHMuUGFyc2VOdW1iZXJPckRlZmF1bHQoTnVtYmVyVXRpbHMuX051bWJlcklucHV0VG9OdW1iZXJTdHIobnVtYmVySW5wdXQpLCBkZWZhdWx0VmFsdWUpO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBzdGF0aWMgSXNQYXJzYWJsZU51bWJlcklucHV0KG51bWJlcklucHV0OiBhbnkpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gTnVtYmVyVXRpbHMuSXNQYXJzYWJsZU51bWJlcihOdW1iZXJVdGlscy5fTnVtYmVySW5wdXRUb051bWJlclN0cihudW1iZXJJbnB1dCkpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybnMgd2hldGhlciB0aGUgdHlwZSBvZiBnaXZlbiBhcmd1bWVudCBpcyAnbnVtYmVyJy5cclxuICAgIHB1YmxpYyBzdGF0aWMgSXNOdW1iZXIoYXJnOiBhbnkpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ251bWJlcic7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJucyB3aGV0aGVyIHRoZSB2YWx1ZSBpcyBwYXJhc2FibGUgYXMgYSBudW1iZXIuXHJcbiAgICBwdWJsaWMgc3RhdGljIElzUGFyc2FibGVOdW1iZXIoYXJnOiBhbnkpOiBib29sZWFuIHtcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShhcmcpKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiAhaXNOYU4ocGFyc2VGbG9hdChhcmcpKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFJldHVybnMgZ2l2ZW4gYXJnIGFzIGEgZmxvYXQgbnVtYmVyIHdpdGggZ2l2ZW4gZGVjaW1hbCBwcmVjaXNpb24sIGlmIHBvc3NpYmxlLiBSZXR1cm5zIE5hTiBpZiBwYXJzZSBjb252ZXJzaW9uIGZhaWxlZC5cclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gVGhlIGFyZ3VtZW50IHRvIHBhcnNlIHRvIGEgZmxvYXRcclxuICAgICAqIEBwYXJhbSBUaGUgbnVtYmVyIG9mIGRlY2ltYWxzLCBvciB0aGUgcHJlY2lzaW9uLCB0aGUgcGFyc2VkIHJldHVybiBmbG9hdCBzaG91bGQgaGF2ZVxyXG4gICAgICogQHJldHVybnMgTmFOIGlmIG5vdCBwb3NzaWJsZSwgZWxzZSB0aGUgcGFyc2VkIGZsb2F0IHZhbHVlXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzdGF0aWMgUGFyc2VGbG9hdChhcmc6IGFueSwgZGVjaW1hbFByZWNpc2lvbjogbnVtYmVyID0gMik6IG51bWJlciB7XHJcbiAgICAgICAgaWYgKGFueU5pbGwoYXJnLCBkZWNpbWFsUHJlY2lzaW9uKSB8fCBBcnJheS5pc0FycmF5KGFyZykpIHtcclxuICAgICAgICAgICAgcmV0dXJuIE5hTjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICghTnVtYmVyVXRpbHMuSXNJbnRlZ2VyKGRlY2ltYWxQcmVjaXNpb24pIHx8IGRlY2ltYWxQcmVjaXNpb24gPCAwKSB7XHJcbiAgICAgICAgICAgIGRlY2ltYWxQcmVjaXNpb24gPSAyO1xyXG4gICAgICAgICAgICAvLyB0b0ZpeGVkKCkgY2FuIG9ubHkgaGFuZGxlIHVwIHVudGlsIDIwXHJcbiAgICAgICAgfSBlbHNlIGlmIChkZWNpbWFsUHJlY2lzaW9uID4gMjApIHtcclxuICAgICAgICAgICAgZGVjaW1hbFByZWNpc2lvbiA9IDIwO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIHBhcnNlRmxvYXQocGFyc2VGbG9hdChhcmcpLnRvRml4ZWQoZGVjaW1hbFByZWNpc2lvbikpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmV0dXJucyBnaXZlbiBhcmcgYXMgYSBmbG9hdCBudW1iZXIgd2l0aCBnaXZlbiBkZWNpbWFsIHByZWNpc2lvbiwgaWYgcG9zc2libGUuIFJldHVybnMgTmFOIGlmIHBhcnNlIGNvbnZlcnNpb24gZmFpbGVkLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBUaGUgYXJndW1lbnQgdG8gcGFyc2UgdG8gYSBmbG9hdFxyXG4gICAgICogQHJldHVybnMgVGhlIGFyZ3VtZW50IGFzIGEgZmxvYXQgd2l0aCBpdHMgb3JpZ2luYWwgZGVjaW1hbCBwcmVjaXNpb24gaW50YWN0XHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzdGF0aWMgUGFyc2VGbG9hdEtlZXBQcmVjaXNpb24oYXJnOiBhbnkpOiBudW1iZXIge1xyXG4gICAgICAgIGxldCBkZWNpbWFsUHJlY2lzaW9uOiBudW1iZXIgPSB0aGlzLkdldERlY2ltYWxQbGFjZXMoYXJnKTtcclxuICAgICAgICByZXR1cm4gdGhpcy5QYXJzZUZsb2F0KGFyZywgZGVjaW1hbFByZWNpc2lvbik7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIHN0YXRpYyBQYXJzZUZsb2F0TnVtYmVySW5wdXRLZWVwUHJlY2lzaW9uKGFyZzogYW55KTogbnVtYmVyIHtcclxuICAgICAgICBsZXQgY29ycmVjdGVkSW5wdXRTdHI6IHN0cmluZyA9IE51bWJlclV0aWxzLl9OdW1iZXJJbnB1dFRvTnVtYmVyU3RyKGFyZyk7XHJcbiAgICAgICAgbGV0IGRlY2ltYWxQcmVjaXNpb246IG51bWJlciA9IHRoaXMuR2V0RGVjaW1hbFBsYWNlcyhjb3JyZWN0ZWRJbnB1dFN0cik7XHJcbiAgICAgICAgcmV0dXJuIE51bWJlclV0aWxzLlBhcnNlRmxvYXQoY29ycmVjdGVkSW5wdXRTdHIsIGRlY2ltYWxQcmVjaXNpb24pO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRmluZHMgdGhlIG51bWJlciBjbG9zZXN0IHRvIHRoZSBvcmlnaW5hbE51bWJlciwgdGhhdCBhZGhlcmVzIHRvIHRoZSBnaXZlbiBib3VuZHMuIFRoYXQgaXMsIGZvciB3aGljaCBpdCBob2xkcyB0aGF0XHJcbiAgICAgKiBuciA9IG1pbiArIE4gKiBzdGVwIHdpdGggTiBpbnRlZ2VyIG9yIDAuXHJcbiAgICAgKiBAcGFyYW0gb3JpZ2luYWxOciBGaW5kIGNsb3Nlc3QgYW5zd2VyIHRvIHRoaXMgbnVtYmVyXHJcbiAgICAgKiBAcGFyYW0gbWluIEluY2x1c2l2ZVxyXG4gICAgICogQHBhcmFtIG1heCBJbmNsdXNpdmVcclxuICAgICAqIEBwYXJhbSBzdGVwU2l6ZVxyXG4gICAgICogQHJldHVybnMgVGhlIGNsb3Nlc3QgT0sgbnVtYmVyIGZvciBib3VuZHMuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzdGF0aWMgR2V0TmVhcmVzdE51bWJlcldpdGhpblN0ZXBwZWRCb3VuZHMob3JpZ2luYWxOcjogbnVtYmVyLCBtaW46IG51bWJlciwgbWF4OiBudW1iZXIsIHN0ZXBTaXplOiBudW1iZXIgPSAxKTogbnVtYmVyIHtcclxuICAgICAgICBpZiAob3JpZ2luYWxOciA8IG1pbikge1xyXG4gICAgICAgICAgICByZXR1cm4gbWluO1xyXG4gICAgICAgIH0gZWxzZSBpZiAob3JpZ2luYWxOciA+IG1heCkge1xyXG4gICAgICAgICAgICByZXR1cm4gTnVtYmVyVXRpbHMuR2V0VHJ1ZVN0ZXBwZWRCb3VuZHNNYXgobWluLCBtYXgsIHN0ZXBTaXplKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGxldCBib3VuZHNDaGVjazogQ2hlY2tXaXRoaW5TdGVwcGVkQm91bmRzUmVzdWx0ID0gTnVtYmVyVXRpbHMuQ2hlY2tXaXRoaW5TdGVwcGVkQm91bmRzKG9yaWdpbmFsTnIsIG1pbiwgbWF4LCBzdGVwU2l6ZSk7XHJcbiAgICAgICAgaWYgKGJvdW5kc0NoZWNrLmlzT2spIHtcclxuICAgICAgICAgICAgcmV0dXJuIG9yaWdpbmFsTnI7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBsZXQgYW5zd2VyOiBudW1iZXIgPSB1bmRlZmluZWQ7XHJcblxyXG4gICAgICAgIGxldCByZW1haW5kZXI6IG51bWJlciA9IGJvdW5kc0NoZWNrLnJlbWFpbmRlcjtcclxuICAgICAgICBpZiAocmVtYWluZGVyKSB7XHJcbiAgICAgICAgICAgIC8vIHJvdW5kIHVwIG9yIGRvd24/XHJcbiAgICAgICAgICAgIGlmICgocmVtYWluZGVyIC8gc3RlcFNpemUpIDwgMC41KSB7XHJcbiAgICAgICAgICAgICAgICAvLyAgcm91bmQgZG93biwgYnV0IG5vdCBiZWxvdyBtaW5cclxuICAgICAgICAgICAgICAgIGFuc3dlciA9IChvcmlnaW5hbE5yIC0gcmVtYWluZGVyID49IG1pbiA/IG9yaWdpbmFsTnIgLSByZW1haW5kZXIgOiBtaW4pO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgLy8gcm91bmQgdXAsIGJ1dCBub3QgYWJvdmUgbWF4XHJcbiAgICAgICAgICAgICAgICBhbnN3ZXIgPSAob3JpZ2luYWxOciArIHN0ZXBTaXplIC0gcmVtYWluZGVyIDw9IG1heCA/IG9yaWdpbmFsTnIgKyBzdGVwU2l6ZSAtIHJlbWFpbmRlciA6XHJcbiAgICAgICAgICAgICAgICAgICAgTnVtYmVyVXRpbHMuR2V0VHJ1ZVN0ZXBwZWRCb3VuZHNNYXgobWluLCBtYXgsIHN0ZXBTaXplKSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBpcyB0aGlzIHJlYWwgbGlmZSwgd2h5IHdhc24ndCBvdXIgc3RlcHBlZCBib3VuZHMgY2hlY2sgT0s/XHJcbiAgICAgICAgICAgIGFuc3dlciA9IG9yaWdpbmFsTnI7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyAnY29ycmVjdCcgZmxvYXQgZXJyb3JzXHJcbiAgICAgICAgYW5zd2VyID0gTnVtYmVyVXRpbHMuUGFyc2VGbG9hdChhbnN3ZXIsIE51bWJlclV0aWxzLl9HZXRMYXJnZXN0RGVjaW1hbFByZWNpc2lvbk9mKG9yaWdpbmFsTnIsIG1pbiwgbWF4LCBzdGVwU2l6ZSkpO1xyXG4gICAgICAgIHJldHVybiBhbnN3ZXI7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJucyB0aGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIG9mIHRoZSBnaXZlbiBudW1iZXIuIFJldHVybnMgMCBpZiBubyBkZWNpbWFscyB3aGF0c29ldmVyIGNvdWxkIGJlIGZvdW5kIG9uIGdpdmVuIGFyZy5cclxuICAgIHB1YmxpYyBzdGF0aWMgR2V0RGVjaW1hbFBsYWNlcyhhcmc6IGFueSwgbWF4QW5zd2VyOiBudW1iZXIgPSAxMDAwKTogbnVtYmVyIHtcclxuICAgICAgICBsZXQgbWF0Y2g6IFJlZ0V4cE1hdGNoQXJyYXkgPSAoJycgKyBhcmcpLm1hdGNoKC8oPzpcXC4oXFxkKykpPyg/OltlRV0oWystXT9cXGQrKSk/JC8pO1xyXG4gICAgICAgIGlmICghbWF0Y2gpIHtcclxuICAgICAgICAgICAgcmV0dXJuIDA7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBsZXQgYW5zd2VyOiBudW1iZXIgPSBNYXRoLm1heCgwLFxyXG4gICAgICAgICAgICAvLyBudW1iZXIgb2YgZGlnaXRzIHJpZ2h0IG9mIGRlY2ltYWwgcG9pbnQuXHJcbiAgICAgICAgICAgIChtYXRjaFsxXSA/IG1hdGNoWzFdLmxlbmd0aCA6IDApXHJcbiAgICAgICAgICAgIC8vIGFkanVzdCBmb3Igc2NpZW50aWZpYyBub3RhdGlvblxyXG4gICAgICAgICAgICAtIChtYXRjaFsyXSA/ICttYXRjaFsyXSA6IDApKTtcclxuXHJcbiAgICAgICAgaWYgKGFuc3dlciA+IG1heEFuc3dlcikge1xyXG4gICAgICAgICAgICBhbnN3ZXIgPSBtYXhBbnN3ZXI7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICByZXR1cm4gYW5zd2VyO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybnMgdHJ1ZSBpZmYgZ2l2ZW4gYXJndW1lbnQgaXMgYW4gaW50ZWdlciBudW1iZXIuIFJldHVybnMgZmFsc2Ugb24gbm9uLW51bWJlcnMgb3IgbnVtYmVycyB3aXRoIHNpZ25pZmljYW50IGRlY2ltYWxzLlxyXG4gICAgcHVibGljIHN0YXRpYyBJc0ludGVnZXIoYXJnOiBhbnkpOiBib29sZWFuIHtcclxuICAgICAgICBpZiAoaXNOYU4oYXJnKSB8fCBBcnJheS5pc0FycmF5KGFyZykpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZXQgYXJnQXNGbG9hdDogbnVtYmVyID0gcGFyc2VGbG9hdChhcmcpO1xyXG4gICAgICAgIHJldHVybiAoKGFyZ0FzRmxvYXQgfCAwKSA9PT0gYXJnQXNGbG9hdCk7IC8vIHJldHVybnMgd2hldGhlciAnYXJnIGNvbnZlcnRlZCB0byBhbiBpbnRlZ2VyIGVxdWFscyBhcmcnXHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIHdoZXRoZXIgZ2l2ZW4gYXJnIGlzIHBhcnNlYWJsZSBhcyBhIG51bWJlciwgYW5kIHdoZXRoZXIgdGhlIGxlbmd0cyBvZiBpdHMgbnVtYmVyIHBhcnNlIHJlc3VsdCBpcyBlcXVhbCB0byBpdHMgb3JpZ2luYWwgbGVuZ3RoLlxyXG4gICAgICogSS5lLiB0aGlzIGZ1bmN0aW9uIHJldHVybnMgRkFMU0Ugd2l0aCBnaXZlbiBudW1iZXItcGFyc2FibGUgc3RyaW5ncywgYnV0IHRoYXQgaGF2ZSBub24tbnVtZXJpYyBhcHBlbmRpY2VzLCBlZyAnMjIzM2ZmJy4gVGhhdCBhcmdcclxuICAgICAqIElTIG51bWJlci1wYXJzZWFibGUsIGJ1dCBub3QgYSBzdHJpY3QgJ3N0cmluZyBudW1iZXInLCB0aGUgbGF0dGVyIGJlaW5nIHdoYXQgdGhpcyBtZXRob2QgYWN0dWFsbHkgY2hlY2tzIGZvci5cclxuICAgICAqL1xyXG4gICAgcHVibGljIHN0YXRpYyBJc1N0cmluZ051bWJlcihhcmc6IHN0cmluZyk6IGJvb2xlYW4ge1xyXG4gICAgICAgIGlmICghTnVtYmVyVXRpbHMuSXNQYXJzYWJsZU51bWJlcihhcmcpKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICByZXR1cm4gYXJnLnRvU3RyaW5nKCkubGVuZ3RoID09PSBwYXJzZUZsb2F0KGFyZykudG9TdHJpbmcoKS5sZW5ndGg7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmV0dXJucyBhIHJhbmRvbSBpbnRlZ2VyIGluIHJhbmdlIFtsb3dlckJvdW5kIC4uIHVwcGVyQm91bmRdLCBhbiBpbmNsdXNpdmUgcmFuZ2UuIFJldHVybnMgTmFOIGlmIG5vdCBwb3NzaWJsZS5cclxuICAgICAqIEdpdmVuIGJvdW5kcyBhcmUgdHJ1bmNhdGVkIGZpcnN0LCBiZWZvcmUgc2VydmluZyBhcyB0aGUgdHJ1ZSBsb3dlci0gYW5kIHVwcGVyIGJvdW5kcyBmb3IgdGhlIHJhbmRvbSBpbnQuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzdGF0aWMgUmFuZG9tSW50KGxvd2VyQm91bmRJbnQ6IG51bWJlciwgdXBwZXJCb3VuZEludDogbnVtYmVyKTogbnVtYmVyIHtcclxuICAgICAgICBpZiAoIU51bWJlclV0aWxzLklzTnVtYmVyKGxvd2VyQm91bmRJbnQpIHx8ICFOdW1iZXJVdGlscy5Jc051bWJlcih1cHBlckJvdW5kSW50KSB8fCBsb3dlckJvdW5kSW50ID4gdXBwZXJCb3VuZEludCkge1xyXG4gICAgICAgICAgICByZXR1cm4gTmFOO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgbG93ZXJCb3VuZEludCA9IE1hdGgudHJ1bmMobG93ZXJCb3VuZEludCk7XHJcbiAgICAgICAgdXBwZXJCb3VuZEludCA9IE1hdGgudHJ1bmModXBwZXJCb3VuZEludCk7XHJcblxyXG4gICAgICAgIGlmIChsb3dlckJvdW5kSW50ID09PSB1cHBlckJvdW5kSW50KSB7XHJcbiAgICAgICAgICAgIHJldHVybiBsb3dlckJvdW5kSW50O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uc3QgZGVsdGE6IG51bWJlciA9IHVwcGVyQm91bmRJbnQgLSBsb3dlckJvdW5kSW50O1xyXG4gICAgICAgIHJldHVybiAoTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogZGVsdGEpICsgbG93ZXJCb3VuZEludCk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIHRoZSB0cnVlIG1heGltdW0gYWxsb3dlZCB2YWx1ZSBmb3IgdGhlIGdpdmVuIFwic3RlcHBlZCBib3VuZHNcIjogbWluLCBzdGVwU2l6ZSBhbmQgbWF4LCBmb3Igd2hpY2ggaXQgaG9sZHMgdGhhdCBlYWNoIGFsbG93ZWRcclxuICAgICAqIHZhbHVlIFkgPSBtaW4gKyBzdGVwU2l6ZSAqIE4sIGZvciBhbnkgSU5URUdFUiBvciAwIE4gd2hlcmUgaXQgYWxzbyBob2xkcywgb2YgY291cnNlLCB0aGF0IFkgPD0gbWF4LlxyXG4gICAgICogQHBhcmFtIG1pblxyXG4gICAgICogQHBhcmFtIG1heFxyXG4gICAgICogQHBhcmFtIHN0ZXBTaXplXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzdGF0aWMgR2V0VHJ1ZVN0ZXBwZWRCb3VuZHNNYXgobWluOiBudW1iZXIsIG1heDogbnVtYmVyLCBzdGVwU2l6ZTogbnVtYmVyID0gMSk6IG51bWJlciB7XHJcbiAgICAgICAgLy8gc29sdmUgbWF4IGludGVnZXIgWCBpbiBmb3JtdWxhIG1pbiArIFggKiBzdGVwIDw9IG1heCwgYW5kIHJldHVybiBtaW4gKyBYICogc3RlcFNpemUgZm9yIHRoYXQgWFxyXG4gICAgICAgIGxldCBtYXhTdGVwczogbnVtYmVyID0gTWF0aC5mbG9vcigobWF4IC0gbWluKSAvIHN0ZXBTaXplKTtcclxuICAgICAgICAvLyAnY29ycmVjdCcgZmxvYXQgZXJyb3JzXHJcbiAgICAgICAgcmV0dXJuIE51bWJlclV0aWxzLlBhcnNlRmxvYXQobWluICsgbWF4U3RlcHMgKiBzdGVwU2l6ZSwgTnVtYmVyVXRpbHMuX0dldExhcmdlc3REZWNpbWFsUHJlY2lzaW9uT2YobWluLCBtaW4sIG1heCkpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybnMgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBnaXZlbiBudW1iZXIuIElmIGl0J3Mgbm90IGEgbnVtYmVyLCByZXR1cm5zIHRoZSBlbXB0eSBzdHJpbmcuXHJcbiAgICBwdWJsaWMgc3RhdGljIFRvU3RyaW5nKG5yOiBudW1iZXIpOiBzdHJpbmcge1xyXG4gICAgICAgIGlmICghTnVtYmVyVXRpbHMuSXNOYU4obnIpKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBcIlwiICsgbnI7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgcmV0dXJuIFwiXCI7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybnMgd2hldGhlciBnaXZlbiBhcmcgaXMgaW5kZWVkIG5vdCBhIG51bWJlciAoaXQncyBOYU4gb3IgaXQgaGFzIGFub3RoZXIgdHlwZSB0aGFuICdudW1iZXInKS5cclxuICAgIHB1YmxpYyBzdGF0aWMgSXNOYU4oYXJnOiBhbnkpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gaXNOYU4oYXJnKSB8fCAhTnVtYmVyVXRpbHMuSXNOdW1iZXIoYXJnKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFJldHVybnMgd2hldGhlciBnaXZlbiB4IGlzIE9LIHdpdGhpbiB0aGUgZ2l2ZW4gbWluLCBtYXggYW5kIHN0ZXAgYm91bmRhcmllcywgd2hlcmUgaXQgc2hvdWxkIGhvbGQgdGhhdCBuclRvQ2hlY2sgPSBtaW4gKyBOICogc3RlcCxcclxuICAgICAqIHdpdGggTiBpbnRlZ2VyIG9yIDAuXHJcbiAgICAgKiBAcGFyYW0gbnJUb0NoZWNrIE51bWJlciB0byBjaGVjayB3aGV0aGVyIGl0J3Mgd2l0aGluIHRoZSBnaXZlbiBib3VuZHNcclxuICAgICAqIEBwYXJhbSBtaW4gSW5jbHVzaXZlXHJcbiAgICAgKiBAcGFyYW0gbWF4IEluY2x1c2l2ZVxyXG4gICAgICogQHBhcmFtIHN0ZXBTaXplXHJcbiAgICAgKiBAcmV0dXJucyBSZXR1cm5zIHJlbWFpbmRlciBvZiB1bmRlZmluZWQgd2hlbiBuclRvQ2hlY2sgd2FzIE9VVFNJREUgW21pbiwgbWF4XSwgZWxzZSBmdWxsIHJlc3VsdCBvYmplY3QuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzdGF0aWMgQ2hlY2tXaXRoaW5TdGVwcGVkQm91bmRzKFxyXG4gICAgICAgIG5yVG9DaGVjazogbnVtYmVyLFxyXG4gICAgICAgIG1pbjogbnVtYmVyLFxyXG4gICAgICAgIG1heDogbnVtYmVyLFxyXG4gICAgICAgIHN0ZXBTaXplOiBudW1iZXIgPSAxXHJcbiAgICApOiBDaGVja1dpdGhpblN0ZXBwZWRCb3VuZHNSZXN1bHQge1xyXG4gICAgICAgIGlmIChuclRvQ2hlY2sgPCBtaW4gfHwgbnJUb0NoZWNrID4gbWF4KSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7aXNPazogZmFsc2UsIHJlbWFpbmRlcjogdW5kZWZpbmVkfTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIHdlJ3JlIGluIFttaW4sIG1heF0sIGJ1dCBzdGlsbCBjaGVjayBpZiBuclRvQ2hlY2sgPSBtaW4gKyBOICogc3RlcCBob2xkcyAoZm9yIE4gaW50ZWdlciBvciAwKVxyXG4gICAgICAgIGxldCByZW1haW5kZXI6IG51bWJlciA9IChuclRvQ2hlY2sgLSBtaW4pICUgc3RlcFNpemU7XHJcbiAgICAgICAgLy8gY29ycmVjdCBmbG9hdCBmb3IgbGFyZ2VzdCBwcmVjaXNpb24gYW1vbmdzdCBpbnB1dCBudW1iZXJzXHJcbiAgICAgICAgcmVtYWluZGVyID0gTnVtYmVyVXRpbHMuUGFyc2VGbG9hdChyZW1haW5kZXIsIE51bWJlclV0aWxzLl9HZXRMYXJnZXN0RGVjaW1hbFByZWNpc2lvbk9mKG5yVG9DaGVjaywgbWluLCBzdGVwU2l6ZSkpO1xyXG4gICAgICAgIHJldHVybiB7aXNPazogKHJlbWFpbmRlciA9PT0gMCksIHJlbWFpbmRlcjogcmVtYWluZGVyfTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBZGRzIHRob3VzYW5kcyBjb21tYSdzIHRvIGdpdmVuIHZhbHVlLCBFLmcuICcxMDAwJyB0byAnMSwwMDAnLiBSZXR1cm5zIGVtcHR5IHN0cmluZyBpZiB2YWx1ZSB3YXMgdW5kZWZpbmVkLlxyXG4gICAgcHVibGljIHN0YXRpYyBBZGRUaG91c2FuZHNDb21tYXNUbyh2YWx1ZTogYW55KTogc3RyaW5nIHtcclxuICAgICAgICBpZiAoaXNOaWxsKHZhbHVlKSkge1xyXG4gICAgICAgICAgICByZXR1cm4gXCJcIjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiB2YWx1ZS50b1N0cmluZygpLnJlcGxhY2UoL1xcQig/PShcXGR7M30pKyg/IVxcZCkpL2csIFwiLFwiKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm5zIHRoZSBuZWFyZXN0IG51bWJlciwgcmVsYXRpdmUgdG8gdGhlIGdpdmVuIG9yaWdpbmFsTnIsIHRoYXQgaXMgd2l0aGluIHRoZSBnaXZlbiBbbWluLCBtYXhdIGluY2x1c2l2ZSBib3VuZHMuXHJcbiAgICBwdWJsaWMgc3RhdGljIEdldE5lYXJlc3ROdW1iZXJXaXRoaW5Cb3VuZHMob3JpZ2luYWxOcjogbnVtYmVyLCBtaW46IG51bWJlciwgbWF4OiBudW1iZXIpOiBudW1iZXIge1xyXG4gICAgICAgIGxldCBhbnN3ZXI6IG51bWJlciA9IG9yaWdpbmFsTnI7XHJcblxyXG4gICAgICAgIGlmIChvcmlnaW5hbE5yIDwgbWluKSB7XHJcbiAgICAgICAgICAgIGFuc3dlciA9IG1pbjtcclxuICAgICAgICB9IGVsc2UgaWYgKG9yaWdpbmFsTnIgPiBtYXgpIHtcclxuICAgICAgICAgICAgYW5zd2VyID0gbWF4O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIGFuc3dlcjtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFJldHVybnMgd2hldGhlciBnaXZlbiBuclRvQ2hlY2sgaXMgd2l0aGluIHRoZSBnaXZlbiBwcmVjaXNpb24gYW5kIHNjYWxlIGxpbWl0cy4gUHJlY2lzaW9uIGFuZCBzY2FsZSwgaGVyZSwgYXJlIE9yYWNsZSBEQiB0ZXJtcy5cclxuICAgICAqIFRoaXMgZnVuY3Rpb24gY2FuIHRodXMgYmUgdXNlZCB0byBjaGVjayB3aGV0aGVyIHRoZSBnaXZlbiBudW1iZXIgaXMgc2FmZSB0byBzZW5kIHRvIHRoZSAnZGF0YWJhc2UnIGJlZm9yZWhhbmQsIGlmIHdlIGtub3cgdGhlXHJcbiAgICAgKiBwcmVjaXNpb24gYW5kIHNjYWxlIG9mIHRoZSBudW1iZXIgaW4gdGhlIGRiIGRlY2xhcmF0aW9uLlxyXG4gICAgICpcclxuICAgICAqIEkuZS4gQSBudW1iZXIgZGVjbGFyZWQgaW4gdGhlIE9yYWNsZSBEQiBhcyBudW1iZXIoNSwgMikgaGFzIGEgcHJlY2lzaW9uIG9mIDUgYW5kIGEgc2NhbGUgb2YgMi5cclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gbnJUb0NoZWNrXHJcbiAgICAgKiBAcGFyYW0gcHJlY2lzaW9uIFRoZSBudW1iZXIgb2Ygc2lnbmlmaWNhbnQgZGlnaXRzLCBpbmNsdWRpbmcgcG9zc2libHkgbmVnYXRpdmUgc2NhbGUuIEUuZy4gMyBpbiAnMTIzJyBhbmQgNSBpbiAnNTEuMTIzJ1xyXG4gICAgICogQHBhcmFtIFtzY2FsZSA9IDBdIFRoZSBudW1iZXIgb2Ygc2lnbmlmaWNhbnQgZGlnaXRzIEFGVEVSIHRoZSBkZWNpbWFsIHBvaW50LiBFLmcuIDEgaW4gNTQzMi4xIGFuZCAzIGluIDU0MDAwLjAwM1xyXG4gICAgICogQHJldHVybnMgV2hldGhlciBnaXZlbiBuclRvQ2hlY2sgaXMgb2sgZm9yIGdpdmVuIHByZWNpc2lvbiBhbmQgc2NhbGUsIGFuZCBpZiBub3QsIHRoZVxyXG4gICAgICogbmVhcmVzdCBudW1iZXIgdGhhdCBJUyBvayBmb3IgdGhvc2UgY29uc3RyYWludHMuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzdGF0aWMgQ2hlY2tQcmVjaXNpb25BbmRTY2FsZShuclRvQ2hlY2s6IG51bWJlciwgcHJlY2lzaW9uOiBudW1iZXIsIHNjYWxlOiBudW1iZXIgPSAwKTogQ2hlY2tQcmVjaXNpb25BbmRTY2FsZVJlc3VsdCB7XHJcbiAgICAgICAgLy8gbGV0J3Mgc2F5IGFueSB1bmRlZmluZWQgbnVtYmVyIGlzIGNoZWNrZWQgT0ssIGFuZCBhbGwgbnVtYmVycyBhcmUgY2hlY2tlZCBPSyBmb3IgYW4gdW5kZWZpbmVkIHByZWNpc2lvblxyXG4gICAgICAgIGlmICghT2JqZWN0VXRpbHMuQWxsRXhpc3QobnJUb0NoZWNrLCBwcmVjaXNpb24sIHNjYWxlKSkge1xyXG4gICAgICAgICAgICByZXR1cm4ge2lzT2s6IHRydWUsIG5lYXJlc3RPa05yOiBOYU59O1xyXG4gICAgICAgIH1cclxuICAgICAgICAvLyBubyBudW1iZXIgY2FuIGhhdmUgMCBvciBsZXNzIHRoYW4gMCBzaWduaWZpY2FudCBkaWdpdHMsIGluIG91ciB1bml2ZXJzZVxyXG4gICAgICAgIGlmIChwcmVjaXNpb24gPCAxIHx8IHByZWNpc2lvbiAtIHNjYWxlIDwgMSkge1xyXG4gICAgICAgICAgICByZXR1cm4ge2lzT2s6IGZhbHNlLCBuZWFyZXN0T2tOcjogTmFOfTtcclxuICAgICAgICB9XHJcbiAgICAgICAgLy8gYmVnaW4gY2hlY2tcclxuICAgICAgICBjb25zdCBpc05lZ2F0aXZlOiBib29sZWFuID0gKG5yVG9DaGVjayA8IDApO1xyXG4gICAgICAgIGNvbnN0IG5yUGFydHM6IHN0cmluZ1tdID0gbnJUb0NoZWNrLnRvU3RyaW5nKCkuc3BsaXQoXCIuXCIpO1xyXG4gICAgICAgIC8vIHJlbW92ZSBtaW51cyBzaWduIGlmIG5lZ2F0aXZlXHJcbiAgICAgICAgaWYgKGlzTmVnYXRpdmUpIHtcclxuICAgICAgICAgICAgbnJQYXJ0c1swXSA9IG5yUGFydHNbMF0uc2xpY2UoMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IG51bUNvdW50QmVmb3JlRG90OiBudW1iZXIgPSBuclBhcnRzWzBdLmxlbmd0aDtcclxuICAgICAgICBjb25zdCBhbGxvd2VkTnVtQ291bnRCZWZvcmVEb3Q6IG51bWJlciA9IHByZWNpc2lvbiAtIHNjYWxlO1xyXG4gICAgICAgIGlmIChudW1Db3VudEJlZm9yZURvdCA8PSBhbGxvd2VkTnVtQ291bnRCZWZvcmVEb3QpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHtpc09rOiB0cnVlLCBuZWFyZXN0T2tOcjogbnJUb0NoZWNrfTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBjdXQgYSBwYXJ0IGZyb20gdGhlIFwiYmVmb3JlIGRlY2ltYWwgbnVtYmVyXCIgc28gdGhhdCB0aGUgbnVtYmVyIGlzIG5vdCB0b28gYmlnIGFueW1vcmVcclxuICAgICAgICAgICAgY29uc3QgbnVtQ291bnRUb1JlbW92ZTogbnVtYmVyID0gbnVtQ291bnRCZWZvcmVEb3QgLSBhbGxvd2VkTnVtQ291bnRCZWZvcmVEb3Q7XHJcbiAgICAgICAgICAgIC8vIHJlbW92ZSB0aGUgcmlnaHQtbW9zdCBudW1iZXJzIGJlZm9yZSB0aGUgZGVjaW1hbCBkb3RcclxuICAgICAgICAgICAgbnJQYXJ0c1swXSA9IG5yUGFydHNbMF0uc2xpY2UoMCwgLTEgKiBudW1Db3VudFRvUmVtb3ZlKTtcclxuICAgICAgICAgICAgLy8gYWRkIG1pbnVzIHNpZ24gYWdhaW4gaWYgaXQgd2FzIG5lZ2F0aXZlXHJcbiAgICAgICAgICAgIGlmIChpc05lZ2F0aXZlKSB7XHJcbiAgICAgICAgICAgICAgICBuclBhcnRzWzBdID0gXCItXCIgKyBuclBhcnRzWzBdO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIC8vIGJ1aWxkIGFuZCByZXR1cm4gY29tcG9zaXRlIG51bWJlciBhZ2FpblxyXG4gICAgICAgICAgICBsZXQgbmVhcmVzdE9rTnI6IG51bWJlcjtcclxuICAgICAgICAgICAgaWYgKG5yUGFydHNbMV0pIHtcclxuICAgICAgICAgICAgICAgIG5lYXJlc3RPa05yID0gTnVtYmVyKG5yUGFydHNbMF0gKyBcIi5cIiArIG5yUGFydHNbMV0pO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgbmVhcmVzdE9rTnIgPSBOdW1iZXIobnJQYXJ0c1swXSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgcmV0dXJuIHtpc09rOiBmYWxzZSwgbmVhcmVzdE9rTnI6IG5lYXJlc3RPa05yfTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBzdGF0aWMgX0dldExhcmdlc3REZWNpbWFsUHJlY2lzaW9uT2YoLi4uYXJnczogbnVtYmVyW10pOiBudW1iZXIge1xyXG4gICAgICAgIHJldHVybiBBcnJheVV0aWxzLkdldE1heENhbGN1bGF0ZWRWYWx1ZShhcmdzLCAoYXJnOiBudW1iZXIpID0+IHtcclxuICAgICAgICAgICAgcmV0dXJuIE51bWJlclV0aWxzLkdldERlY2ltYWxQbGFjZXMoYXJnKTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm5zIGdpdmVuIG51bWJlciBpbnB1dCBhcyBhIG51bWJlciB0aGF0J3MgdXNlYWJsZSBieSBKYXZhc2NyaXB0LiBBbGxvd3MgZm9yIGluY29taW5nICcsJyBkZWNpbWFsIGRlbGltaXRlci5cclxuICAgIHByaXZhdGUgc3RhdGljIF9OdW1iZXJJbnB1dFRvTnVtYmVyU3RyKG51bWJlcklucHV0OiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiAobnVtYmVySW5wdXQgKyAnJykucmVwbGFjZSgnLCcsICcuJyk7XHJcbiAgICB9XHJcbn1cclxuIl19
|