breeze-client 2.1.2 → 2.1.3-mjs
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/LICENSE +1 -1
- package/adapter-ajax-angularjs/{breeze-client-adapter-ajax-angularjs.d.ts → index.d.ts} +1 -0
- package/adapter-ajax-fetch/{breeze-client-adapter-ajax-fetch.d.ts → index.d.ts} +1 -0
- package/adapter-ajax-httpclient/{breeze-client-adapter-ajax-httpclient.d.ts → index.d.ts} +1 -0
- package/adapter-ajax-jquery/{breeze-client-adapter-ajax-jquery.d.ts → index.d.ts} +1 -0
- package/adapter-ajax-post/{breeze-client-adapter-ajax-post.d.ts → index.d.ts} +1 -0
- package/adapter-data-service-odata/{breeze-client-adapter-data-service-odata.d.ts → index.d.ts} +1 -0
- package/adapter-data-service-webapi/{breeze-client-adapter-data-service-webapi.d.ts → index.d.ts} +1 -0
- package/adapter-model-library-backing-store/{breeze-client-adapter-model-library-backing-store.d.ts → index.d.ts} +1 -0
- package/adapter-model-library-ko/{breeze-client-adapter-model-library-ko.d.ts → index.d.ts} +1 -0
- package/adapter-uri-builder-json/{breeze-client-adapter-uri-builder-json.d.ts → index.d.ts} +1 -0
- package/adapter-uri-builder-odata/{breeze-client-adapter-uri-builder-odata.d.ts → index.d.ts} +1 -0
- package/esm2020/adapter-ajax-angularjs/adapter-ajax-angularjs.mjs +130 -0
- package/esm2020/adapter-ajax-angularjs/adapter-core.mjs +49 -0
- package/esm2020/adapter-ajax-angularjs/breeze-client-adapter-ajax-angularjs.mjs +5 -0
- package/esm2020/adapter-ajax-fetch/adapter-ajax-fetch.mjs +132 -0
- package/esm2020/adapter-ajax-fetch/adapter-core.mjs +49 -0
- package/esm2020/adapter-ajax-fetch/breeze-client-adapter-ajax-fetch.mjs +5 -0
- package/esm2020/adapter-ajax-httpclient/adapter-ajax-httpclient.mjs +137 -0
- package/esm2020/adapter-ajax-httpclient/adapter-core.mjs +49 -0
- package/esm2020/adapter-ajax-httpclient/breeze-client-adapter-ajax-httpclient.mjs +5 -0
- package/esm2020/adapter-ajax-jquery/adapter-ajax-jquery.mjs +103 -0
- package/esm2020/adapter-ajax-jquery/breeze-client-adapter-ajax-jquery.mjs +5 -0
- package/esm2020/adapter-ajax-post/adapter-ajax-post.mjs +77 -0
- package/esm2020/adapter-ajax-post/breeze-client-adapter-ajax-post.mjs +5 -0
- package/esm2020/adapter-data-service-odata/adapter-core.mjs +49 -0
- package/esm2020/adapter-data-service-odata/adapter-data-service-odata.mjs +456 -0
- package/esm2020/adapter-data-service-odata/breeze-client-adapter-data-service-odata.mjs +5 -0
- package/esm2020/adapter-data-service-webapi/adapter-data-service-webapi.mjs +93 -0
- package/esm2020/adapter-data-service-webapi/breeze-client-adapter-data-service-webapi.mjs +5 -0
- package/esm2020/adapter-model-library-backing-store/adapter-model-library-backing-store.mjs +268 -0
- package/esm2020/adapter-model-library-backing-store/breeze-client-adapter-model-library-backing-store.mjs +5 -0
- package/esm2020/adapter-model-library-ko/adapter-model-library-ko.mjs +240 -0
- package/esm2020/adapter-model-library-ko/breeze-client-adapter-model-library-ko.mjs +5 -0
- package/esm2020/adapter-uri-builder-json/adapter-core.mjs +49 -0
- package/esm2020/adapter-uri-builder-json/adapter-uri-builder-json.mjs +36 -0
- package/esm2020/adapter-uri-builder-json/breeze-client-adapter-uri-builder-json.mjs +5 -0
- package/esm2020/adapter-uri-builder-odata/adapter-core.mjs +49 -0
- package/esm2020/adapter-uri-builder-odata/adapter-uri-builder-odata.mjs +190 -0
- package/esm2020/adapter-uri-builder-odata/breeze-client-adapter-uri-builder-odata.mjs +5 -0
- package/esm2020/breeze-client.mjs +5 -0
- package/esm2020/index.mjs +2 -0
- package/esm2020/mixin-get-entity-graph/breeze-client-mixin-get-entity-graph.mjs +5 -0
- package/esm2020/mixin-get-entity-graph/mixin-get-entity-graph.mjs +269 -0
- package/esm2020/mixin-save-queuing/breeze-client-mixin-save-queuing.mjs +5 -0
- package/esm2020/mixin-save-queuing/mixin-save-queuing.mjs +400 -0
- package/esm2020/src/abstract-data-service-adapter.mjs +296 -0
- package/esm2020/src/array.mjs +4 -0
- package/esm2020/src/assert-param.mjs +312 -0
- package/esm2020/src/breeze.mjs +85 -0
- package/esm2020/src/complex-array.mjs +117 -0
- package/esm2020/src/config.mjs +223 -0
- package/esm2020/src/core.mjs +707 -0
- package/esm2020/src/csdl-metadata-parser.mjs +385 -0
- package/esm2020/src/data-service.mjs +203 -0
- package/esm2020/src/data-type.mjs +444 -0
- package/esm2020/src/default-property-interceptor.mjs +460 -0
- package/esm2020/src/entity-action.mjs +45 -0
- package/esm2020/src/entity-aspect.mjs +806 -0
- package/esm2020/src/entity-group.mjs +187 -0
- package/esm2020/src/entity-key.mjs +116 -0
- package/esm2020/src/entity-manager.mjs +2094 -0
- package/esm2020/src/entity-metadata.mjs +2109 -0
- package/esm2020/src/entity-query.mjs +996 -0
- package/esm2020/src/entity-state.mjs +99 -0
- package/esm2020/src/enum.mjs +141 -0
- package/esm2020/src/event.mjs +256 -0
- package/esm2020/src/interface-registry.mjs +41 -0
- package/esm2020/src/key-generator.mjs +108 -0
- package/esm2020/src/local-query-comparison-options.mjs +65 -0
- package/esm2020/src/mapping-context.mjs +405 -0
- package/esm2020/src/naming-convention.mjs +88 -0
- package/esm2020/src/observable-array.mjs +183 -0
- package/esm2020/src/predicate.mjs +1232 -0
- package/esm2020/src/primitive-array.mjs +85 -0
- package/esm2020/src/query-options.mjs +152 -0
- package/esm2020/src/relation-array.mjs +173 -0
- package/esm2020/src/save-options.mjs +41 -0
- package/esm2020/src/unattached-children-map.mjs +58 -0
- package/esm2020/src/validate.mjs +988 -0
- package/esm2020/src/validation-options.mjs +64 -0
- package/fesm2015/{breeze-client-adapter-ajax-angularjs.js → breeze-client-adapter-ajax-angularjs.mjs} +1 -1
- package/fesm2015/breeze-client-adapter-ajax-angularjs.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-ajax-fetch.js → breeze-client-adapter-ajax-fetch.mjs} +5 -3
- package/fesm2015/breeze-client-adapter-ajax-fetch.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-ajax-httpclient.js → breeze-client-adapter-ajax-httpclient.mjs} +1 -1
- package/fesm2015/breeze-client-adapter-ajax-httpclient.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-ajax-jquery.js → breeze-client-adapter-ajax-jquery.mjs} +2 -2
- package/fesm2015/breeze-client-adapter-ajax-jquery.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-ajax-post.js → breeze-client-adapter-ajax-post.mjs} +1 -1
- package/fesm2015/breeze-client-adapter-ajax-post.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-data-service-odata.js → breeze-client-adapter-data-service-odata.mjs} +20 -22
- package/fesm2015/breeze-client-adapter-data-service-odata.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-data-service-webapi.js → breeze-client-adapter-data-service-webapi.mjs} +13 -13
- package/fesm2015/breeze-client-adapter-data-service-webapi.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-model-library-backing-store.js → breeze-client-adapter-model-library-backing-store.mjs} +13 -13
- package/fesm2015/breeze-client-adapter-model-library-backing-store.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-model-library-ko.js → breeze-client-adapter-model-library-ko.mjs} +13 -13
- package/fesm2015/breeze-client-adapter-model-library-ko.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-uri-builder-json.js → breeze-client-adapter-uri-builder-json.mjs} +8 -8
- package/fesm2015/breeze-client-adapter-uri-builder-json.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-uri-builder-odata.js → breeze-client-adapter-uri-builder-odata.mjs} +85 -86
- package/fesm2015/breeze-client-adapter-uri-builder-odata.mjs.map +1 -0
- package/fesm2015/{breeze-client-mixin-get-entity-graph.js → breeze-client-mixin-get-entity-graph.mjs} +1 -1
- package/fesm2015/breeze-client-mixin-get-entity-graph.mjs.map +1 -0
- package/fesm2015/{breeze-client-mixin-save-queuing.js → breeze-client-mixin-save-queuing.mjs} +1 -1
- package/fesm2015/breeze-client-mixin-save-queuing.mjs.map +1 -0
- package/fesm2015/{breeze-client.js → breeze-client.mjs} +417 -422
- package/fesm2015/breeze-client.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-ajax-angularjs.js → fesm2020/breeze-client-adapter-ajax-angularjs.mjs} +41 -42
- package/fesm2020/breeze-client-adapter-ajax-angularjs.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-ajax-fetch.js → fesm2020/breeze-client-adapter-ajax-fetch.mjs} +44 -43
- package/fesm2020/breeze-client-adapter-ajax-fetch.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-ajax-httpclient.js → fesm2020/breeze-client-adapter-ajax-httpclient.mjs} +43 -44
- package/fesm2020/breeze-client-adapter-ajax-httpclient.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-ajax-jquery.js → fesm2020/breeze-client-adapter-ajax-jquery.mjs} +18 -19
- package/fesm2020/breeze-client-adapter-ajax-jquery.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-ajax-post.js → fesm2020/breeze-client-adapter-ajax-post.mjs} +8 -11
- package/fesm2020/breeze-client-adapter-ajax-post.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-data-service-odata.js → fesm2020/breeze-client-adapter-data-service-odata.mjs} +126 -134
- package/fesm2020/breeze-client-adapter-data-service-odata.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-data-service-webapi.js → fesm2020/breeze-client-adapter-data-service-webapi.mjs} +38 -42
- package/fesm2020/breeze-client-adapter-data-service-webapi.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-model-library-backing-store.js → fesm2020/breeze-client-adapter-model-library-backing-store.mjs} +63 -64
- package/fesm2020/breeze-client-adapter-model-library-backing-store.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-model-library-ko.js → fesm2020/breeze-client-adapter-model-library-ko.mjs} +57 -58
- package/fesm2020/breeze-client-adapter-model-library-ko.mjs.map +1 -0
- package/fesm2020/breeze-client-adapter-uri-builder-json.mjs +91 -0
- package/fesm2020/breeze-client-adapter-uri-builder-json.mjs.map +1 -0
- package/fesm2020/breeze-client-adapter-uri-builder-odata.mjs +245 -0
- package/fesm2020/breeze-client-adapter-uri-builder-odata.mjs.map +1 -0
- package/{fesm5/breeze-client-mixin-get-entity-graph.js → fesm2020/breeze-client-mixin-get-entity-graph.mjs} +45 -45
- package/fesm2020/breeze-client-mixin-get-entity-graph.mjs.map +1 -0
- package/{fesm5/breeze-client-mixin-save-queuing.js → fesm2020/breeze-client-mixin-save-queuing.mjs} +116 -126
- package/fesm2020/breeze-client-mixin-save-queuing.mjs.map +1 -0
- package/{fesm5/breeze-client.js → fesm2020/breeze-client.mjs} +3403 -3615
- package/fesm2020/breeze-client.mjs.map +1 -0
- package/mixin-get-entity-graph/{breeze-client-mixin-get-entity-graph.d.ts → index.d.ts} +1 -0
- package/mixin-save-queuing/{breeze-client-mixin-save-queuing.d.ts → index.d.ts} +1 -0
- package/package.json +126 -12
- package/src/entity-metadata.d.ts +6 -4
- package/src/entity-query.d.ts +1 -1
- package/adapter-ajax-angularjs/breeze-client-adapter-ajax-angularjs.metadata.json +0 -1
- package/adapter-ajax-angularjs/package.json +0 -13
- package/adapter-ajax-fetch/breeze-client-adapter-ajax-fetch.metadata.json +0 -1
- package/adapter-ajax-fetch/package.json +0 -13
- package/adapter-ajax-httpclient/breeze-client-adapter-ajax-httpclient.metadata.json +0 -1
- package/adapter-ajax-httpclient/package.json +0 -17
- package/adapter-ajax-jquery/breeze-client-adapter-ajax-jquery.metadata.json +0 -1
- package/adapter-ajax-jquery/package.json +0 -13
- package/adapter-ajax-post/breeze-client-adapter-ajax-post.metadata.json +0 -1
- package/adapter-ajax-post/package.json +0 -13
- package/adapter-data-service-odata/breeze-client-adapter-data-service-odata.metadata.json +0 -1
- package/adapter-data-service-odata/package.json +0 -13
- package/adapter-data-service-webapi/breeze-client-adapter-data-service-webapi.metadata.json +0 -1
- package/adapter-data-service-webapi/package.json +0 -13
- package/adapter-model-library-backing-store/breeze-client-adapter-model-library-backing-store.metadata.json +0 -1
- package/adapter-model-library-backing-store/package.json +0 -13
- package/adapter-model-library-ko/breeze-client-adapter-model-library-ko.metadata.json +0 -1
- package/adapter-model-library-ko/package.json +0 -13
- package/adapter-uri-builder-json/breeze-client-adapter-uri-builder-json.metadata.json +0 -1
- package/adapter-uri-builder-json/package.json +0 -13
- package/adapter-uri-builder-odata/breeze-client-adapter-uri-builder-odata.metadata.json +0 -1
- package/adapter-uri-builder-odata/package.json +0 -13
- package/breeze-client.d.ts +0 -8
- package/breeze-client.metadata.json +0 -1
- package/bundles/breeze-client-adapter-ajax-angularjs.umd.js +0 -190
- package/bundles/breeze-client-adapter-ajax-angularjs.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-angularjs.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-ajax-angularjs.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-fetch.umd.js +0 -190
- package/bundles/breeze-client-adapter-ajax-fetch.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-fetch.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-ajax-fetch.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-httpclient.umd.js +0 -195
- package/bundles/breeze-client-adapter-ajax-httpclient.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-httpclient.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-ajax-httpclient.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-jquery.umd.js +0 -115
- package/bundles/breeze-client-adapter-ajax-jquery.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-jquery.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-ajax-jquery.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-post.umd.js +0 -92
- package/bundles/breeze-client-adapter-ajax-post.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-post.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-ajax-post.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-data-service-odata.umd.js +0 -743
- package/bundles/breeze-client-adapter-data-service-odata.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-data-service-odata.umd.min.js +0 -16
- package/bundles/breeze-client-adapter-data-service-odata.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-data-service-webapi.umd.js +0 -326
- package/bundles/breeze-client-adapter-data-service-webapi.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-data-service-webapi.umd.min.js +0 -16
- package/bundles/breeze-client-adapter-data-service-webapi.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-model-library-backing-store.umd.js +0 -280
- package/bundles/breeze-client-adapter-model-library-backing-store.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-model-library-backing-store.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-model-library-backing-store.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-model-library-ko.umd.js +0 -252
- package/bundles/breeze-client-adapter-model-library-ko.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-model-library-ko.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-model-library-ko.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-uri-builder-json.umd.js +0 -96
- package/bundles/breeze-client-adapter-uri-builder-json.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-uri-builder-json.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-uri-builder-json.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-uri-builder-odata.umd.js +0 -262
- package/bundles/breeze-client-adapter-uri-builder-odata.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-uri-builder-odata.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-uri-builder-odata.umd.min.js.map +0 -1
- package/bundles/breeze-client-mixin-get-entity-graph.umd.js +0 -258
- package/bundles/breeze-client-mixin-get-entity-graph.umd.js.map +0 -1
- package/bundles/breeze-client-mixin-get-entity-graph.umd.min.js +0 -2
- package/bundles/breeze-client-mixin-get-entity-graph.umd.min.js.map +0 -1
- package/bundles/breeze-client-mixin-save-queuing.umd.js +0 -579
- package/bundles/breeze-client-mixin-save-queuing.umd.js.map +0 -1
- package/bundles/breeze-client-mixin-save-queuing.umd.min.js +0 -16
- package/bundles/breeze-client-mixin-save-queuing.umd.min.js.map +0 -1
- package/bundles/breeze-client.umd.js +0 -14094
- package/bundles/breeze-client.umd.js.map +0 -1
- package/bundles/breeze-client.umd.min.js +0 -16
- package/bundles/breeze-client.umd.min.js.map +0 -1
- package/esm2015/adapter-ajax-angularjs/adapter-ajax-angularjs.js +0 -130
- package/esm2015/adapter-ajax-angularjs/adapter-core.js +0 -49
- package/esm2015/adapter-ajax-angularjs/breeze-client-adapter-ajax-angularjs.js +0 -5
- package/esm2015/adapter-ajax-fetch/adapter-ajax-fetch.js +0 -130
- package/esm2015/adapter-ajax-fetch/adapter-core.js +0 -49
- package/esm2015/adapter-ajax-fetch/breeze-client-adapter-ajax-fetch.js +0 -5
- package/esm2015/adapter-ajax-httpclient/adapter-ajax-httpclient.js +0 -137
- package/esm2015/adapter-ajax-httpclient/adapter-core.js +0 -49
- package/esm2015/adapter-ajax-httpclient/breeze-client-adapter-ajax-httpclient.js +0 -5
- package/esm2015/adapter-ajax-jquery/adapter-ajax-jquery.js +0 -103
- package/esm2015/adapter-ajax-jquery/breeze-client-adapter-ajax-jquery.js +0 -5
- package/esm2015/adapter-ajax-post/adapter-ajax-post.js +0 -77
- package/esm2015/adapter-ajax-post/breeze-client-adapter-ajax-post.js +0 -5
- package/esm2015/adapter-data-service-odata/adapter-core.js +0 -49
- package/esm2015/adapter-data-service-odata/adapter-data-service-odata.js +0 -459
- package/esm2015/adapter-data-service-odata/breeze-client-adapter-data-service-odata.js +0 -5
- package/esm2015/adapter-data-service-webapi/adapter-data-service-webapi.js +0 -93
- package/esm2015/adapter-data-service-webapi/breeze-client-adapter-data-service-webapi.js +0 -5
- package/esm2015/adapter-model-library-backing-store/adapter-model-library-backing-store.js +0 -268
- package/esm2015/adapter-model-library-backing-store/breeze-client-adapter-model-library-backing-store.js +0 -5
- package/esm2015/adapter-model-library-ko/adapter-model-library-ko.js +0 -240
- package/esm2015/adapter-model-library-ko/breeze-client-adapter-model-library-ko.js +0 -5
- package/esm2015/adapter-uri-builder-json/adapter-core.js +0 -49
- package/esm2015/adapter-uri-builder-json/adapter-uri-builder-json.js +0 -36
- package/esm2015/adapter-uri-builder-json/breeze-client-adapter-uri-builder-json.js +0 -5
- package/esm2015/adapter-uri-builder-odata/adapter-core.js +0 -49
- package/esm2015/adapter-uri-builder-odata/adapter-uri-builder-odata.js +0 -192
- package/esm2015/adapter-uri-builder-odata/breeze-client-adapter-uri-builder-odata.js +0 -5
- package/esm2015/breeze-client.js +0 -9
- package/esm2015/index.js +0 -2
- package/esm2015/mixin-get-entity-graph/breeze-client-mixin-get-entity-graph.js +0 -5
- package/esm2015/mixin-get-entity-graph/mixin-get-entity-graph.js +0 -269
- package/esm2015/mixin-save-queuing/breeze-client-mixin-save-queuing.js +0 -5
- package/esm2015/mixin-save-queuing/mixin-save-queuing.js +0 -400
- package/esm2015/public_api.js +0 -2
- package/esm2015/src/abstract-data-service-adapter.js +0 -296
- package/esm2015/src/array.js +0 -4
- package/esm2015/src/assert-param.js +0 -312
- package/esm2015/src/breeze.js +0 -85
- package/esm2015/src/complex-array.js +0 -119
- package/esm2015/src/config.js +0 -223
- package/esm2015/src/core.js +0 -706
- package/esm2015/src/csdl-metadata-parser.js +0 -385
- package/esm2015/src/data-service.js +0 -203
- package/esm2015/src/data-type.js +0 -444
- package/esm2015/src/default-property-interceptor.js +0 -459
- package/esm2015/src/entity-action.js +0 -45
- package/esm2015/src/entity-aspect.js +0 -806
- package/esm2015/src/entity-group.js +0 -187
- package/esm2015/src/entity-key.js +0 -116
- package/esm2015/src/entity-manager.js +0 -2094
- package/esm2015/src/entity-metadata.js +0 -2109
- package/esm2015/src/entity-query.js +0 -996
- package/esm2015/src/entity-state.js +0 -99
- package/esm2015/src/enum.js +0 -141
- package/esm2015/src/event.js +0 -256
- package/esm2015/src/interface-registry.js +0 -41
- package/esm2015/src/key-generator.js +0 -108
- package/esm2015/src/local-query-comparison-options.js +0 -65
- package/esm2015/src/mapping-context.js +0 -405
- package/esm2015/src/naming-convention.js +0 -88
- package/esm2015/src/observable-array.js +0 -185
- package/esm2015/src/predicate.js +0 -1235
- package/esm2015/src/primitive-array.js +0 -87
- package/esm2015/src/query-options.js +0 -152
- package/esm2015/src/relation-array.js +0 -175
- package/esm2015/src/save-options.js +0 -41
- package/esm2015/src/unattached-children-map.js +0 -58
- package/esm2015/src/validate.js +0 -991
- package/esm2015/src/validation-options.js +0 -64
- package/esm5/adapter-ajax-angularjs/adapter-ajax-angularjs.js +0 -132
- package/esm5/adapter-ajax-angularjs/adapter-core.js +0 -49
- package/esm5/adapter-ajax-angularjs/breeze-client-adapter-ajax-angularjs.js +0 -5
- package/esm5/adapter-ajax-fetch/adapter-ajax-fetch.js +0 -132
- package/esm5/adapter-ajax-fetch/adapter-core.js +0 -49
- package/esm5/adapter-ajax-fetch/breeze-client-adapter-ajax-fetch.js +0 -5
- package/esm5/adapter-ajax-httpclient/adapter-ajax-httpclient.js +0 -139
- package/esm5/adapter-ajax-httpclient/adapter-core.js +0 -49
- package/esm5/adapter-ajax-httpclient/breeze-client-adapter-ajax-httpclient.js +0 -5
- package/esm5/adapter-ajax-jquery/adapter-ajax-jquery.js +0 -105
- package/esm5/adapter-ajax-jquery/breeze-client-adapter-ajax-jquery.js +0 -5
- package/esm5/adapter-ajax-post/adapter-ajax-post.js +0 -81
- package/esm5/adapter-ajax-post/breeze-client-adapter-ajax-post.js +0 -5
- package/esm5/adapter-data-service-odata/adapter-core.js +0 -49
- package/esm5/adapter-data-service-odata/adapter-data-service-odata.js +0 -466
- package/esm5/adapter-data-service-odata/breeze-client-adapter-data-service-odata.js +0 -5
- package/esm5/adapter-data-service-webapi/adapter-data-service-webapi.js +0 -98
- package/esm5/adapter-data-service-webapi/breeze-client-adapter-data-service-webapi.js +0 -5
- package/esm5/adapter-model-library-backing-store/adapter-model-library-backing-store.js +0 -270
- package/esm5/adapter-model-library-backing-store/breeze-client-adapter-model-library-backing-store.js +0 -5
- package/esm5/adapter-model-library-ko/adapter-model-library-ko.js +0 -242
- package/esm5/adapter-model-library-ko/breeze-client-adapter-model-library-ko.js +0 -5
- package/esm5/adapter-uri-builder-json/adapter-core.js +0 -49
- package/esm5/adapter-uri-builder-json/adapter-uri-builder-json.js +0 -38
- package/esm5/adapter-uri-builder-json/breeze-client-adapter-uri-builder-json.js +0 -5
- package/esm5/adapter-uri-builder-odata/adapter-core.js +0 -49
- package/esm5/adapter-uri-builder-odata/adapter-uri-builder-odata.js +0 -197
- package/esm5/adapter-uri-builder-odata/breeze-client-adapter-uri-builder-odata.js +0 -5
- package/esm5/breeze-client.js +0 -9
- package/esm5/index.js +0 -2
- package/esm5/mixin-get-entity-graph/breeze-client-mixin-get-entity-graph.js +0 -5
- package/esm5/mixin-get-entity-graph/mixin-get-entity-graph.js +0 -269
- package/esm5/mixin-save-queuing/breeze-client-mixin-save-queuing.js +0 -5
- package/esm5/mixin-save-queuing/mixin-save-queuing.js +0 -412
- package/esm5/public_api.js +0 -2
- package/esm5/src/abstract-data-service-adapter.js +0 -302
- package/esm5/src/array.js +0 -4
- package/esm5/src/assert-param.js +0 -317
- package/esm5/src/breeze.js +0 -85
- package/esm5/src/complex-array.js +0 -119
- package/esm5/src/config.js +0 -228
- package/esm5/src/core.js +0 -714
- package/esm5/src/csdl-metadata-parser.js +0 -385
- package/esm5/src/data-service.js +0 -207
- package/esm5/src/data-type.js +0 -451
- package/esm5/src/default-property-interceptor.js +0 -459
- package/esm5/src/entity-action.js +0 -52
- package/esm5/src/entity-aspect.js +0 -812
- package/esm5/src/entity-group.js +0 -189
- package/esm5/src/entity-key.js +0 -118
- package/esm5/src/entity-manager.js +0 -2112
- package/esm5/src/entity-metadata.js +0 -2144
- package/esm5/src/entity-query.js +0 -1023
- package/esm5/src/entity-state.js +0 -106
- package/esm5/src/enum.js +0 -144
- package/esm5/src/event.js +0 -259
- package/esm5/src/interface-registry.js +0 -43
- package/esm5/src/key-generator.js +0 -111
- package/esm5/src/local-query-comparison-options.js +0 -67
- package/esm5/src/mapping-context.js +0 -407
- package/esm5/src/naming-convention.js +0 -90
- package/esm5/src/observable-array.js +0 -201
- package/esm5/src/predicate.js +0 -1300
- package/esm5/src/primitive-array.js +0 -87
- package/esm5/src/query-options.js +0 -167
- package/esm5/src/relation-array.js +0 -175
- package/esm5/src/save-options.js +0 -43
- package/esm5/src/unattached-children-map.js +0 -60
- package/esm5/src/validate.js +0 -996
- package/esm5/src/validation-options.js +0 -66
- package/fesm2015/breeze-client-adapter-ajax-angularjs.js.map +0 -1
- package/fesm2015/breeze-client-adapter-ajax-fetch.js.map +0 -1
- package/fesm2015/breeze-client-adapter-ajax-httpclient.js.map +0 -1
- package/fesm2015/breeze-client-adapter-ajax-jquery.js.map +0 -1
- package/fesm2015/breeze-client-adapter-ajax-post.js.map +0 -1
- package/fesm2015/breeze-client-adapter-data-service-odata.js.map +0 -1
- package/fesm2015/breeze-client-adapter-data-service-webapi.js.map +0 -1
- package/fesm2015/breeze-client-adapter-model-library-backing-store.js.map +0 -1
- package/fesm2015/breeze-client-adapter-model-library-ko.js.map +0 -1
- package/fesm2015/breeze-client-adapter-uri-builder-json.js.map +0 -1
- package/fesm2015/breeze-client-adapter-uri-builder-odata.js.map +0 -1
- package/fesm2015/breeze-client-mixin-get-entity-graph.js.map +0 -1
- package/fesm2015/breeze-client-mixin-save-queuing.js.map +0 -1
- package/fesm2015/breeze-client.js.map +0 -1
- package/fesm5/breeze-client-adapter-ajax-angularjs.js.map +0 -1
- package/fesm5/breeze-client-adapter-ajax-fetch.js.map +0 -1
- package/fesm5/breeze-client-adapter-ajax-httpclient.js.map +0 -1
- package/fesm5/breeze-client-adapter-ajax-jquery.js.map +0 -1
- package/fesm5/breeze-client-adapter-ajax-post.js.map +0 -1
- package/fesm5/breeze-client-adapter-data-service-odata.js.map +0 -1
- package/fesm5/breeze-client-adapter-data-service-webapi.js.map +0 -1
- package/fesm5/breeze-client-adapter-model-library-backing-store.js.map +0 -1
- package/fesm5/breeze-client-adapter-model-library-ko.js.map +0 -1
- package/fesm5/breeze-client-adapter-uri-builder-json.js +0 -92
- package/fesm5/breeze-client-adapter-uri-builder-json.js.map +0 -1
- package/fesm5/breeze-client-adapter-uri-builder-odata.js +0 -250
- package/fesm5/breeze-client-adapter-uri-builder-odata.js.map +0 -1
- package/fesm5/breeze-client-mixin-get-entity-graph.js.map +0 -1
- package/fesm5/breeze-client-mixin-save-queuing.js.map +0 -1
- package/fesm5/breeze-client.js.map +0 -1
- package/mixin-get-entity-graph/breeze-client-mixin-get-entity-graph.metadata.json +0 -1
- package/mixin-get-entity-graph/package.json +0 -13
- package/mixin-save-queuing/breeze-client-mixin-save-queuing.metadata.json +0 -1
- package/mixin-save-queuing/package.json +0 -13
- package/public_api.d.ts +0 -1
|
@@ -0,0 +1,996 @@
|
|
|
1
|
+
import { core } from './core';
|
|
2
|
+
import { assertParam } from './assert-param';
|
|
3
|
+
import { DataType } from './data-type';
|
|
4
|
+
import { EntityAspect } from './entity-aspect';
|
|
5
|
+
import { EntityKey } from './entity-key';
|
|
6
|
+
import { BreezeEnum } from './enum';
|
|
7
|
+
import { DataService } from './data-service';
|
|
8
|
+
import { EntityType } from './entity-metadata';
|
|
9
|
+
import { QueryOptions } from './query-options';
|
|
10
|
+
import { Predicate } from './predicate';
|
|
11
|
+
/**
|
|
12
|
+
An EntityQuery instance is used to query entities either from a remote datasource or from a local [[EntityManager]].
|
|
13
|
+
|
|
14
|
+
EntityQueries are immutable - this means that all EntityQuery methods that return an EntityQuery actually create a new EntityQuery. This means that
|
|
15
|
+
EntityQueries can be 'modified' without affecting any current instances.
|
|
16
|
+
@dynamic
|
|
17
|
+
**/
|
|
18
|
+
export class EntityQuery {
|
|
19
|
+
/** Constructor
|
|
20
|
+
> let query = new EntityQuery("Customers")
|
|
21
|
+
|
|
22
|
+
Usually this constructor will be followed by calls to filtering, ordering or selection methods
|
|
23
|
+
> let query = new EntityQuery("Customers")
|
|
24
|
+
> .where("CompanyName", "startsWith", "C")
|
|
25
|
+
> .orderBy("Region");
|
|
26
|
+
@param resourceName - either a resource name or a serialized EntityQuery ( created by [[EntityQuery.toJSON]])
|
|
27
|
+
**/
|
|
28
|
+
constructor(resourceName) {
|
|
29
|
+
if (resourceName != null && (typeof resourceName !== 'string')) {
|
|
30
|
+
return fromJSON(this, resourceName);
|
|
31
|
+
}
|
|
32
|
+
// TODO: cast as string below needed for early versions of TypeDoc - but not for regular compile - check later
|
|
33
|
+
this.resourceName = resourceName;
|
|
34
|
+
this.fromEntityType = undefined;
|
|
35
|
+
this.wherePredicate = undefined;
|
|
36
|
+
this.orderByClause = undefined;
|
|
37
|
+
this.selectClause = undefined;
|
|
38
|
+
this.skipCount = undefined;
|
|
39
|
+
this.takeCount = undefined;
|
|
40
|
+
this.expandClause = undefined;
|
|
41
|
+
this.parameters = {};
|
|
42
|
+
this.inlineCountEnabled = false;
|
|
43
|
+
this.noTrackingEnabled = false;
|
|
44
|
+
// default is to get queryOptions and dataService from the entityManager.
|
|
45
|
+
// this.queryOptions = new QueryOptions();
|
|
46
|
+
// this.dataService = new DataService();
|
|
47
|
+
this.entityManager = undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
Specifies the resource to query for this EntityQuery.
|
|
51
|
+
> let query = new EntityQuery()
|
|
52
|
+
> .from("Customers");
|
|
53
|
+
|
|
54
|
+
is the same as
|
|
55
|
+
> let query = new EntityQuery("Customers");
|
|
56
|
+
@param resourceName - The resource to query.
|
|
57
|
+
**/
|
|
58
|
+
from(resourceName) {
|
|
59
|
+
// TODO: think about allowing entityType as well
|
|
60
|
+
assertParam(resourceName, "resourceName").isString().check();
|
|
61
|
+
return clone(this, "resourceName", resourceName);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
This is a static version of the "from" method and it creates a 'base' entityQuery for the specified resource name.
|
|
65
|
+
> let query = EntityQuery.from("Customers");
|
|
66
|
+
|
|
67
|
+
is the same as
|
|
68
|
+
> let query = new EntityQuery("Customers");
|
|
69
|
+
@param resourceName - The resource to query.
|
|
70
|
+
**/
|
|
71
|
+
static from(resourceName) {
|
|
72
|
+
assertParam(resourceName, "resourceName").isString().check();
|
|
73
|
+
return new EntityQuery(resourceName);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
Specifies the top level EntityType that this query will return. Only needed when a query returns a json result that does not include type information,
|
|
77
|
+
or when using a resource name that is not associated to an EntityType.
|
|
78
|
+
> let query = new EntityQuery()
|
|
79
|
+
> .from("MyCustomMethod")
|
|
80
|
+
> .toType("Customer")
|
|
81
|
+
@param entityType - The top level EntityType that this query will return.
|
|
82
|
+
@summary If the json result consists of more than a simple entity or array of entities, consider using a [[JsonResultsAdapter]] instead.
|
|
83
|
+
**/
|
|
84
|
+
toType(entityType) {
|
|
85
|
+
assertParam(entityType, "entityType").isString().or().isInstanceOf(EntityType).check();
|
|
86
|
+
return clone(this, "resultEntityType", entityType);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
Returns a new query with an added filter criteria; Can be called multiple times which means to 'and' with any existing
|
|
90
|
+
Predicate or can be called with null to clear all predicates.
|
|
91
|
+
> let query = new EntityQuery("Customers")
|
|
92
|
+
> .where("CompanyName", "startsWith", "C");
|
|
93
|
+
|
|
94
|
+
This can also be expressed using an explicit [[FilterQueryOp]] as
|
|
95
|
+
> let query = new EntityQuery("Customers")
|
|
96
|
+
> .where("CompanyName", FilterQueryOp.StartsWith, "C");
|
|
97
|
+
|
|
98
|
+
or a preconstructed [[Predicate]] may be used
|
|
99
|
+
> let pred = new Predicate("CompanyName", FilterQueryOp.StartsWith, "C");
|
|
100
|
+
> let query = new EntityQuery("Customers").where(pred);
|
|
101
|
+
|
|
102
|
+
Predicates are often useful when you want to combine multiple conditions in a single filter, such as
|
|
103
|
+
> let pred = Predicate.create("CompanyName", "startswith", "C").and("Region", FilterQueryOp.Equals, null);
|
|
104
|
+
> let query = new EntityQuery("Customers")
|
|
105
|
+
> .where(pred);
|
|
106
|
+
|
|
107
|
+
More complicated queries can make use of nested property paths
|
|
108
|
+
> let query = new EntityQuery("Products")
|
|
109
|
+
> .where("Category.CategoryName", "startswith", "S");
|
|
110
|
+
|
|
111
|
+
or OData functions - A list of valid OData functions can be found within the [[Predicate]] documentation.
|
|
112
|
+
|
|
113
|
+
> let query = new EntityQuery("Customers")
|
|
114
|
+
> .where("toLower(CompanyName)", "startsWith", "c");
|
|
115
|
+
|
|
116
|
+
or to be even more baroque
|
|
117
|
+
> let query = new EntityQuery("Customers")
|
|
118
|
+
> .where("toUpper(substring(CompanyName, 1, 2))", FilterQueryOp.Equals, "OM");
|
|
119
|
+
@param predicate - Can be either
|
|
120
|
+
- a single [[Predicate]]
|
|
121
|
+
|
|
122
|
+
- the parameters to create a 'simple' Predicate
|
|
123
|
+
- - a property name, a property path with '.' as path seperators or a property expression {String}
|
|
124
|
+
- - an operator - [[FilterQueryOp]] or it's string representation. Case is ignored
|
|
125
|
+
when if a string is provided and any string that matches one of the FilterQueryOp aliases will be accepted.
|
|
126
|
+
- - a value {Object} - This will be treated as either a property expression or a literal depending on context.
|
|
127
|
+
In general, if the value can be interpreted as a property expression it will be, otherwise it will be treated as a literal.
|
|
128
|
+
In most cases this works well, but you can also force the interpretation by making the value argument itself an object
|
|
129
|
+
with a 'value' property and an 'isLiteral' property set to either true or false.
|
|
130
|
+
Breeze also tries to infer the dataType of any literal based on context, if this fails you can force this inference by making the value argument
|
|
131
|
+
an object with a 'value' property and a 'dataType'property set to one of the DataType enumeration instances.
|
|
132
|
+
|
|
133
|
+
- a null or undefined ( this causes any existing where clause to be removed)
|
|
134
|
+
**/
|
|
135
|
+
where(...args) {
|
|
136
|
+
let wherePredicate;
|
|
137
|
+
if (args.length > 0 && args[0] != null) {
|
|
138
|
+
wherePredicate = Predicate.create(...args);
|
|
139
|
+
if (this.fromEntityType)
|
|
140
|
+
wherePredicate._validate(this.fromEntityType);
|
|
141
|
+
if (this.wherePredicate) {
|
|
142
|
+
wherePredicate = this.wherePredicate.and(wherePredicate);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return clone(this, "wherePredicate", wherePredicate);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
Returns a new query that orders the results of the query by property name. By default sorting occurs is ascending order, but sorting in descending order is supported as well.
|
|
149
|
+
OrderBy clauses may be chained.
|
|
150
|
+
> let query = new EntityQuery("Customers")
|
|
151
|
+
> .orderBy("CompanyName");
|
|
152
|
+
|
|
153
|
+
or to sort across multiple properties
|
|
154
|
+
> let query = new EntityQuery("Customers")
|
|
155
|
+
> .orderBy("Region, CompanyName");
|
|
156
|
+
|
|
157
|
+
Nested property paths are also supported
|
|
158
|
+
> let query = new EntityQuery("Products")
|
|
159
|
+
> .orderBy("Category.CategoryName");
|
|
160
|
+
|
|
161
|
+
Sorting in descending order is supported via the addition of ' desc' to the end of any property path.
|
|
162
|
+
> let query = new EntityQuery("Customers")
|
|
163
|
+
> .orderBy("CompanyName desc");
|
|
164
|
+
|
|
165
|
+
or
|
|
166
|
+
> let query = new EntityQuery("Customers")
|
|
167
|
+
> .orderBy("Region desc, CompanyName desc");
|
|
168
|
+
@param propertyPaths - A comma-separated (',') string of property paths or an array of property paths.
|
|
169
|
+
Each property path can optionally end with " desc" to force a descending sort order. If 'propertyPaths' is either null or omitted then all ordering is removed.
|
|
170
|
+
@param isDescending - If specified, overrides all of the embedded 'desc' tags in the previously specified property paths.
|
|
171
|
+
**/
|
|
172
|
+
orderBy(propertyPaths, isDescending) {
|
|
173
|
+
// propertyPaths: can pass in create("A.X,B") or create("A.X desc, B") or create("A.X desc,B", true])
|
|
174
|
+
// isDesc parameter trumps isDesc in propertyName.
|
|
175
|
+
let orderByClause = propertyPaths == null ? null : new OrderByClause(normalizePropertyPaths(propertyPaths), isDescending);
|
|
176
|
+
if (this.orderByClause && orderByClause) {
|
|
177
|
+
orderByClause = new OrderByClause([this.orderByClause, orderByClause]);
|
|
178
|
+
}
|
|
179
|
+
return clone(this, "orderByClause", orderByClause);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
Returns a new query that orders the results of the query by property name in descending order.
|
|
183
|
+
> let query = new EntityQuery("Customers")
|
|
184
|
+
> .orderByDesc("CompanyName");
|
|
185
|
+
|
|
186
|
+
or to sort across multiple properties
|
|
187
|
+
> let query = new EntityQuery("Customers")
|
|
188
|
+
> .orderByDesc("Region, CompanyName");
|
|
189
|
+
|
|
190
|
+
Nested property paths are also supported
|
|
191
|
+
> let query = new EntityQuery("Products")
|
|
192
|
+
> .orderByDesc("Category.CategoryName");
|
|
193
|
+
@param propertyPaths - A comma-separated (',') string of property paths or an array of property paths.
|
|
194
|
+
If 'propertyPaths' is either null or omitted then all ordering is removed.
|
|
195
|
+
**/
|
|
196
|
+
orderByDesc(propertyPaths) {
|
|
197
|
+
return this.orderBy(propertyPaths, true);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
Returns a new query that selects a list of properties from the results of the original query and returns the values of just these properties. This
|
|
201
|
+
will be referred to as a projection.
|
|
202
|
+
If the result of this selection "projection" contains entities, these entities will automatically be added to EntityManager's cache and will
|
|
203
|
+
be made 'observable'.
|
|
204
|
+
Any simple properties, i.e. strings, numbers or dates within a projection will not be cached are will NOT be made 'observable'.
|
|
205
|
+
|
|
206
|
+
Simple data properties can be projected
|
|
207
|
+
> let query = new EntityQuery("Customers")
|
|
208
|
+
> .where("CompanyName", "startsWith", "C")
|
|
209
|
+
> .select("CompanyName");
|
|
210
|
+
|
|
211
|
+
This will return an array of objects each with a single "CompanyName" property of type string.
|
|
212
|
+
A similar query could return a navigation property instead
|
|
213
|
+
> let query = new EntityQuery("Customers")
|
|
214
|
+
> .where("CompanyName", "startsWith", "C")
|
|
215
|
+
> .select("Orders");
|
|
216
|
+
|
|
217
|
+
where the result would be an array of objects each with a single "Orders" property that would itself be an array of "Order" entities.
|
|
218
|
+
Composite projections are also possible:
|
|
219
|
+
> let query = new EntityQuery("Customers")
|
|
220
|
+
> .where("CompanyName", "startsWith", "C")
|
|
221
|
+
> .select("CompanyName, Orders");
|
|
222
|
+
|
|
223
|
+
As well as projections involving nested property paths
|
|
224
|
+
> let query = EntityQuery("Orders")
|
|
225
|
+
> .where("Customer.CompanyName", "startsWith", "C")
|
|
226
|
+
> .select("Customer.CompanyName, Customer, OrderDate");
|
|
227
|
+
@param propertyPaths - A comma-separated (',') string of property paths or an array of property paths.
|
|
228
|
+
If 'propertyPaths' is either null or omitted then any existing projection on the query is removed.
|
|
229
|
+
**/
|
|
230
|
+
select(propertyPaths) {
|
|
231
|
+
let selectClause = propertyPaths == null ? null : new SelectClause(normalizePropertyPaths(propertyPaths));
|
|
232
|
+
return clone(this, "selectClause", selectClause);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
Returns a new query that skips the specified number of entities when returning results.
|
|
236
|
+
Any existing 'skip' can be cleared by calling 'skip' with no arguments.
|
|
237
|
+
> let query = new EntityQuery("Customers")
|
|
238
|
+
> .where("CompanyName", "startsWith", "C")
|
|
239
|
+
> .skip(5);
|
|
240
|
+
@param count - The number of entities to skip over. If omitted or null any existing skip count on the query is removed.
|
|
241
|
+
**/
|
|
242
|
+
skip(count) {
|
|
243
|
+
assertParam(count, "count").isOptional().isNumber().check();
|
|
244
|
+
return clone(this, "skipCount", (count == null) ? null : count);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
Returns a new query that returns only the specified number of entities when returning results. - Same as 'take'.
|
|
248
|
+
Any existing 'top' can be cleared by calling 'top' with no arguments.
|
|
249
|
+
> let query = new EntityQuery("Customers")
|
|
250
|
+
> .top(5);
|
|
251
|
+
@param count - The number of entities to return.
|
|
252
|
+
If 'count' is either null or omitted then any existing 'top' count on the query is removed.
|
|
253
|
+
**/
|
|
254
|
+
top(count) {
|
|
255
|
+
return this.take(count);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
Returns a new query that returns only the specified number of entities when returning results - Same as 'top'.
|
|
259
|
+
Any existing take can be cleared by calling take with no arguments.
|
|
260
|
+
> let query = new EntityQuery("Customers")
|
|
261
|
+
> .take(5);
|
|
262
|
+
@param count - The number of entities to return.
|
|
263
|
+
If 'count' is either null or omitted then any existing 'take' count on the query is removed.
|
|
264
|
+
**/
|
|
265
|
+
take(count) {
|
|
266
|
+
assertParam(count, "count").isOptional().isNumber().check();
|
|
267
|
+
return clone(this, "takeCount", (count == null) ? null : count);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
Returns a new query that will return related entities nested within its results. The expand method allows you to identify related entities, via navigation property
|
|
271
|
+
names such that a graph of entities may be retrieved with a single request. Any filtering occurs before the results are 'expanded'.
|
|
272
|
+
> let query = new EntityQuery("Customers")
|
|
273
|
+
> .where("CompanyName", "startsWith", "C")
|
|
274
|
+
> .expand("Orders");
|
|
275
|
+
|
|
276
|
+
will return the filtered customers each with its "Orders" properties fully resolved.
|
|
277
|
+
Multiple paths may be specified by separating the paths by a ','
|
|
278
|
+
> let query = new EntityQuery("Orders")
|
|
279
|
+
> .expand("Customer, Employee")
|
|
280
|
+
|
|
281
|
+
and nested property paths my be specified as well
|
|
282
|
+
> let query = new EntityQuery("Orders")
|
|
283
|
+
> .expand("Customer, OrderDetails, OrderDetails.Product")
|
|
284
|
+
@param propertyPaths - A comma-separated list of navigation property names or an array of navigation property names. Each Navigation Property name can be followed
|
|
285
|
+
by a '.' and another navigation property name to enable identifying a multi-level relationship.
|
|
286
|
+
If 'propertyPaths' is either null or omitted then any existing 'expand' clause on the query is removed.
|
|
287
|
+
**/
|
|
288
|
+
expand(propertyPaths) {
|
|
289
|
+
let expandClause = propertyPaths == null ? null : new ExpandClause(normalizePropertyPaths(propertyPaths));
|
|
290
|
+
return clone(this, "expandClause", expandClause);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
Returns a new query that includes a collection of parameters to pass to the server.
|
|
294
|
+
> let query = EntityQuery.from("EmployeesFilteredByCountryAndBirthdate")
|
|
295
|
+
> .withParameters({ BirthDate: "1/1/1960", Country: "USA" });
|
|
296
|
+
|
|
297
|
+
will call the 'EmployeesFilteredByCountryAndBirthdate' method on the server and pass in 2 parameters. This
|
|
298
|
+
query will be uri encoded as
|
|
299
|
+
> {serviceApi}/EmployeesFilteredByCountryAndBirthdate?birthDate=1%2F1%2F1960&country=USA
|
|
300
|
+
|
|
301
|
+
Parameters may also be mixed in with other query criteria.
|
|
302
|
+
> let query = EntityQuery.from("EmployeesFilteredByCountryAndBirthdate")
|
|
303
|
+
> .withParameters({ BirthDate: "1/1/1960", Country: "USA" })
|
|
304
|
+
> .where("LastName", "startsWith", "S")
|
|
305
|
+
> .orderBy("BirthDate");
|
|
306
|
+
@param parameters - A parameters object where the keys are the parameter names and the values are the parameter values.
|
|
307
|
+
**/
|
|
308
|
+
withParameters(parameters) {
|
|
309
|
+
assertParam(parameters, "parameters").isObject().check();
|
|
310
|
+
return clone(this, "parameters", parameters);
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
Returns a query with the 'inlineCount' capability either enabled or disabled. With 'inlineCount' enabled, an additional 'inlineCount' property
|
|
314
|
+
will be returned with the query results that will contain the number of entities that would have been returned by this
|
|
315
|
+
query with only the 'where'/'filter' clauses applied, i.e. without any 'skip'/'take' operators applied. For local queries this clause is ignored.
|
|
316
|
+
> let query = new EntityQuery("Customers")
|
|
317
|
+
> .take(20)
|
|
318
|
+
> .orderBy("CompanyName")
|
|
319
|
+
> .inlineCount(true);
|
|
320
|
+
|
|
321
|
+
will return the first 20 customers as well as a count of all of the customers in the remote store.
|
|
322
|
+
@param enabled - (default = true) Whether or not inlineCount capability should be enabled. If this parameter is omitted, true is assumed.
|
|
323
|
+
**/
|
|
324
|
+
inlineCount(enabled) {
|
|
325
|
+
assertParam(enabled, "enabled").isBoolean().isOptional().check();
|
|
326
|
+
enabled = (enabled === undefined) ? true : !!enabled;
|
|
327
|
+
return clone(this, "inlineCountEnabled", enabled);
|
|
328
|
+
}
|
|
329
|
+
useNameOnServer(usesNameOnServer) {
|
|
330
|
+
assertParam(usesNameOnServer, "usesNameOnServer").isBoolean().isOptional().check();
|
|
331
|
+
usesNameOnServer = (usesNameOnServer === undefined) ? true : !!usesNameOnServer;
|
|
332
|
+
return clone(this, "usesNameOnServer", usesNameOnServer);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
Returns a query with the 'noTracking' capability either enabled or disabled. With 'noTracking' enabled, the results of this query
|
|
336
|
+
will not be coerced into entities but will instead look like raw javascript projections. i.e. simple javascript objects.
|
|
337
|
+
> let query = new EntityQuery("Customers")
|
|
338
|
+
> .take(20)
|
|
339
|
+
> .orderBy("CompanyName")
|
|
340
|
+
> .noTracking(true);
|
|
341
|
+
@param enabled - (default = true) Whether or not the noTracking capability should be enabled. If this parameter is omitted, true is assumed.
|
|
342
|
+
**/
|
|
343
|
+
noTracking(enabled) {
|
|
344
|
+
assertParam(enabled, "enabled").isBoolean().isOptional().check();
|
|
345
|
+
enabled = (enabled === undefined) ? true : !!enabled;
|
|
346
|
+
return clone(this, "noTrackingEnabled", enabled);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
Returns a copy of this EntityQuery with the specified [[EntityManager]], [[DataService]],
|
|
350
|
+
[[JsonResultsAdapter]], [[MergeStrategy]] or [[FetchStrategy]] applied.
|
|
351
|
+
> // 'using' can be used to return a new query with a specified EntityManager.
|
|
352
|
+
> let em = new EntityManager(serviceName);
|
|
353
|
+
> let query = new EntityQuery("Orders")
|
|
354
|
+
> .using(em);
|
|
355
|
+
|
|
356
|
+
or with a specified [[MergeStrategy]]
|
|
357
|
+
> let em = new EntityManager(serviceName);
|
|
358
|
+
> let query = new EntityQuery("Orders")
|
|
359
|
+
> .using(MergeStrategy.PreserveChanges);
|
|
360
|
+
|
|
361
|
+
or with a specified [[FetchStrategy]]
|
|
362
|
+
> let em = new EntityManager(serviceName);
|
|
363
|
+
> let query = new EntityQuery("Orders")
|
|
364
|
+
> .using(FetchStrategy.FromLocalCache);
|
|
365
|
+
@param obj - The object to update in creating a new EntityQuery from an existing one.
|
|
366
|
+
**/
|
|
367
|
+
using(obj) {
|
|
368
|
+
if (!obj)
|
|
369
|
+
return this;
|
|
370
|
+
let eq = clone(this);
|
|
371
|
+
processUsing(eq, {
|
|
372
|
+
"entityManager": null,
|
|
373
|
+
"dataService": null,
|
|
374
|
+
"queryOptions": null,
|
|
375
|
+
"fetchStrategy": (eq, val) => {
|
|
376
|
+
eq.queryOptions = (eq.queryOptions || new QueryOptions()).using(val);
|
|
377
|
+
},
|
|
378
|
+
"mergeStrategy": (eq, val) => {
|
|
379
|
+
eq.queryOptions = (eq.queryOptions || new QueryOptions()).using(val);
|
|
380
|
+
},
|
|
381
|
+
"jsonResultsAdapter": (eq, val) => {
|
|
382
|
+
eq.dataService = (eq.dataService || new DataService()).using({ jsonResultsAdapter: val });
|
|
383
|
+
}
|
|
384
|
+
}, obj);
|
|
385
|
+
return eq;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
Executes this query. This method requires that an EntityManager has been previously specified via the "using" method.
|
|
389
|
+
|
|
390
|
+
This method can be called using a 'promises' syntax ( recommended)
|
|
391
|
+
> let em = new EntityManager(serviceName);
|
|
392
|
+
> let query = new EntityQuery("Orders").using(em);
|
|
393
|
+
> query.execute().then( function(data) {
|
|
394
|
+
> ... query results processed here
|
|
395
|
+
> }).catch( function(err) {
|
|
396
|
+
> ... query failure processed here
|
|
397
|
+
> });
|
|
398
|
+
|
|
399
|
+
or with callbacks
|
|
400
|
+
> let em = new EntityManager(serviceName);
|
|
401
|
+
> let query = new EntityQuery("Orders").using(em);
|
|
402
|
+
> query.execute(
|
|
403
|
+
> function(data) {
|
|
404
|
+
> let orders = data.results;
|
|
405
|
+
> ... query results processed here
|
|
406
|
+
> },
|
|
407
|
+
> function(err) {
|
|
408
|
+
> ... query failure processed here
|
|
409
|
+
> });
|
|
410
|
+
|
|
411
|
+
Either way this method is the same as calling the EntityManager 'execute' method.
|
|
412
|
+
> let em = new EntityManager(serviceName);
|
|
413
|
+
> let query = new EntityQuery("Orders");
|
|
414
|
+
> em.executeQuery(query).then( function(data) {
|
|
415
|
+
> let orders = data.results;
|
|
416
|
+
> ... query results processed here
|
|
417
|
+
> }).catch( function(err) {
|
|
418
|
+
> ... query failure processed here
|
|
419
|
+
> });
|
|
420
|
+
|
|
421
|
+
@param callback - Function called on success.
|
|
422
|
+
@param errorCallback - Function called on failure.
|
|
423
|
+
@return Promise
|
|
424
|
+
**/
|
|
425
|
+
execute(callback, errorCallback) {
|
|
426
|
+
if (!this.entityManager) {
|
|
427
|
+
throw new Error("An EntityQuery must have its EntityManager property set before calling 'execute'");
|
|
428
|
+
}
|
|
429
|
+
return this.entityManager.executeQuery(this, callback, errorCallback);
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
Executes this query against the local cache. This method requires that an EntityManager have been previously specified via the "using" method.
|
|
433
|
+
> // assume em is an entityManager already filled with order entities;
|
|
434
|
+
> let query = new EntityQuery("Orders").using(em);
|
|
435
|
+
> let orders = query.executeLocally();
|
|
436
|
+
|
|
437
|
+
Note that calling this method is the same as calling [[EntityManager.executeQueryLocally]].
|
|
438
|
+
**/
|
|
439
|
+
executeLocally() {
|
|
440
|
+
if (!this.entityManager) {
|
|
441
|
+
throw new Error("An EntityQuery must have its EntityManager property set before calling 'executeLocally'");
|
|
442
|
+
}
|
|
443
|
+
return this.entityManager.executeQueryLocally(this);
|
|
444
|
+
}
|
|
445
|
+
toJSON() {
|
|
446
|
+
return this.toJSONExt();
|
|
447
|
+
}
|
|
448
|
+
/** Typically only for use when building UriBuilderAdapters.
|
|
449
|
+
@hidden @internal
|
|
450
|
+
*/
|
|
451
|
+
toJSONExt(context) {
|
|
452
|
+
context = context || {};
|
|
453
|
+
context.entityType = context.entityType || this.fromEntityType;
|
|
454
|
+
context.propertyPathFn = context.toNameOnServer ? context.entityType.clientPropertyPathToServer.bind(context.entityType) : core.identity;
|
|
455
|
+
let toJSONExtFn = function (v) {
|
|
456
|
+
return v ? v.toJSONExt(context) : undefined;
|
|
457
|
+
};
|
|
458
|
+
return core.toJson(this, {
|
|
459
|
+
"from,resourceName": null,
|
|
460
|
+
"toType,resultEntityType": function (v) {
|
|
461
|
+
// resultEntityType can be either a string or an entityType
|
|
462
|
+
return v ? (typeof v === 'string' ? v : v.name) : undefined;
|
|
463
|
+
},
|
|
464
|
+
"where,wherePredicate": toJSONExtFn,
|
|
465
|
+
"orderBy,orderByClause": toJSONExtFn,
|
|
466
|
+
"select,selectClause": toJSONExtFn,
|
|
467
|
+
"expand,expandClause": toJSONExtFn,
|
|
468
|
+
"skip,skipCount": null,
|
|
469
|
+
"take,takeCount": null,
|
|
470
|
+
parameters: function (v) {
|
|
471
|
+
return core.isEmpty(v) ? undefined : v;
|
|
472
|
+
},
|
|
473
|
+
"inlineCount,inlineCountEnabled": false,
|
|
474
|
+
"noTracking,noTrackingEnabled": false,
|
|
475
|
+
queryOptions: null
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
Static method that creates an EntityQuery that will allow 'requerying' an entity or a collection of entities by primary key. This can be useful
|
|
480
|
+
to force a requery of selected entities, or to restrict an existing collection of entities according to some filter.
|
|
481
|
+
|
|
482
|
+
Works for a single entity or an array of entities of the SAME type.
|
|
483
|
+
Does not work for an array of entities of different types.
|
|
484
|
+
> // assuming 'customers' is an array of 'Customer' entities retrieved earlier.
|
|
485
|
+
> let customersQuery = EntityQuery.fromEntities(customers);
|
|
486
|
+
|
|
487
|
+
The resulting query can, of course, be extended
|
|
488
|
+
> // assuming 'customers' is an array of 'Customer' entities retrieved earlier.
|
|
489
|
+
> let customersQuery = EntityQuery.fromEntities(customers)
|
|
490
|
+
> .where("Region", FilterQueryOp.NotEquals, null);
|
|
491
|
+
|
|
492
|
+
Single entities can requeried as well.
|
|
493
|
+
> // assuming 'customer' is a 'Customer' entity retrieved earlier.
|
|
494
|
+
> let customerQuery = EntityQuery.fromEntities(customer);
|
|
495
|
+
|
|
496
|
+
will create a query that will return an array containing a single customer entity.
|
|
497
|
+
@param entities - The entities for which we want to create an EntityQuery.
|
|
498
|
+
**/
|
|
499
|
+
static fromEntities(entities) {
|
|
500
|
+
assertParam(entities, "entities").isEntity().or().isNonEmptyArray().isEntity().check();
|
|
501
|
+
let ents = (Array.isArray(entities)) ? entities : [entities];
|
|
502
|
+
let firstEntity = ents[0];
|
|
503
|
+
let type = firstEntity.entityType;
|
|
504
|
+
if (ents.some(function (e) {
|
|
505
|
+
return e.entityType !== type;
|
|
506
|
+
})) {
|
|
507
|
+
throw new Error("All 'fromEntities' must be the same type; at least one is not of type " +
|
|
508
|
+
type.name);
|
|
509
|
+
}
|
|
510
|
+
let q = new EntityQuery(type.defaultResourceName);
|
|
511
|
+
let preds = ents.map(function (entity) {
|
|
512
|
+
return buildPredicate(entity);
|
|
513
|
+
});
|
|
514
|
+
let pred = Predicate.or(preds);
|
|
515
|
+
q = q.where(pred);
|
|
516
|
+
let em = firstEntity.entityAspect.entityManager;
|
|
517
|
+
if (em) {
|
|
518
|
+
q = q.using(em);
|
|
519
|
+
}
|
|
520
|
+
return q;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
Creates an EntityQuery for the specified [[EntityKey]].
|
|
524
|
+
> let empType = metadataStore.getEntityType("Employee");
|
|
525
|
+
> let entityKey = new EntityKey(empType, 1);
|
|
526
|
+
> let query = EntityQuery.fromEntityKey(entityKey);
|
|
527
|
+
|
|
528
|
+
or
|
|
529
|
+
> // 'employee' is a previously queried employee
|
|
530
|
+
> let entityKey = employee.entityAspect.getKey();
|
|
531
|
+
> let query = EntityQuery.fromEntityKey(entityKey);
|
|
532
|
+
@param entityKey - The [[EntityKey]] for which a query will be created.
|
|
533
|
+
**/
|
|
534
|
+
static fromEntityKey(entityKey) {
|
|
535
|
+
assertParam(entityKey, "entityKey").isInstanceOf(EntityKey).check();
|
|
536
|
+
let q = new EntityQuery(entityKey.entityType.defaultResourceName);
|
|
537
|
+
let pred = buildKeyPredicate(entityKey);
|
|
538
|
+
q = q.where(pred).toType(entityKey.entityType);
|
|
539
|
+
return q;
|
|
540
|
+
}
|
|
541
|
+
// protected methods
|
|
542
|
+
/** @hidden @internal */
|
|
543
|
+
_getFromEntityType(metadataStore, throwErrorIfNotFound) {
|
|
544
|
+
// Uncomment next two lines if we make this method public.
|
|
545
|
+
// assertParam(metadataStore, "metadataStore").isInstanceOf(MetadataStore).check();
|
|
546
|
+
// assertParam(throwErrorIfNotFound, "throwErrorIfNotFound").isBoolean().isOptional().check();
|
|
547
|
+
let entityType = this.fromEntityType;
|
|
548
|
+
if (entityType)
|
|
549
|
+
return entityType;
|
|
550
|
+
let resourceName = this.resourceName;
|
|
551
|
+
if (!resourceName) {
|
|
552
|
+
throw new Error("There is no resourceName for this query");
|
|
553
|
+
}
|
|
554
|
+
if (metadataStore.isEmpty()) {
|
|
555
|
+
if (throwErrorIfNotFound) {
|
|
556
|
+
throw new Error("There is no metadata available for this query. " +
|
|
557
|
+
"Are you querying the local cache before you've fetched metadata?");
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
return undefined;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
let entityTypeName = metadataStore.getEntityTypeNameForResourceName(resourceName);
|
|
564
|
+
if (entityTypeName) {
|
|
565
|
+
entityType = metadataStore._getStructuralType(entityTypeName);
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
entityType = this._getToEntityType(metadataStore, true);
|
|
569
|
+
}
|
|
570
|
+
if (!entityType) {
|
|
571
|
+
if (throwErrorIfNotFound) {
|
|
572
|
+
throw new Error(core.formatString("Cannot find an entityType for resourceName: '%1'. ", resourceName) + core.strings.TO_TYPE);
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
return undefined;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
this.fromEntityType = entityType;
|
|
579
|
+
return entityType;
|
|
580
|
+
}
|
|
581
|
+
/** @hidden @internal */
|
|
582
|
+
_getToEntityType(metadataStore, skipFromCheck) {
|
|
583
|
+
// skipFromCheck is to avoid recursion if called from _getFromEntityType;
|
|
584
|
+
if (this.resultEntityType instanceof EntityType) {
|
|
585
|
+
return this.resultEntityType;
|
|
586
|
+
}
|
|
587
|
+
else if (this.resultEntityType) {
|
|
588
|
+
// resultEntityType is a string
|
|
589
|
+
this.resultEntityType = metadataStore._getStructuralType(this.resultEntityType, false);
|
|
590
|
+
return this.resultEntityType;
|
|
591
|
+
}
|
|
592
|
+
else {
|
|
593
|
+
// resolve it, if possible, via the resourceName
|
|
594
|
+
// do not cache this value in this case
|
|
595
|
+
// cannot determine the resultEntityType if a selectClause is present.
|
|
596
|
+
// return skipFromCheck ? null : (!this.selectClause) && this._getFromEntityType(metadataStore, false);
|
|
597
|
+
if (skipFromCheck || this.selectClause) {
|
|
598
|
+
return undefined;
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
this._getFromEntityType(metadataStore, false);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
/** @hidden @internal */
|
|
606
|
+
// for testing
|
|
607
|
+
_toUri(em) {
|
|
608
|
+
let ds = DataService.resolve([em.dataService]);
|
|
609
|
+
return ds.uriBuilder.buildUri(this, em.metadataStore);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
Creates an EntityQuery for the specified entity and [[NavigationProperty]].
|
|
614
|
+
> // 'employee' is a previously queried employee
|
|
615
|
+
> let ordersNavProp = employee.entityType.getProperty("Orders");
|
|
616
|
+
> let query = EntityQuery.fromEntityNavigation(employee, ordersNavProp);
|
|
617
|
+
|
|
618
|
+
will return a query for the "Orders" of the specified 'employee'.
|
|
619
|
+
@param entity - The Entity whose navigation property will be queried.
|
|
620
|
+
@param navigationProperty - The [[NavigationProperty]] or name of the NavigationProperty to be queried.
|
|
621
|
+
**/
|
|
622
|
+
EntityQuery.fromEntityNavigation = function (entity, navigationProperty) {
|
|
623
|
+
assertParam(entity, "entity").isEntity().check();
|
|
624
|
+
let navProperty = entity.entityType._checkNavProperty(navigationProperty);
|
|
625
|
+
let q = new EntityQuery(navProperty.entityType.defaultResourceName);
|
|
626
|
+
let pred = buildNavigationPredicate(entity, navProperty);
|
|
627
|
+
if (pred == null) {
|
|
628
|
+
throw new Error("Unable to create a NavigationQuery for navigationProperty: " + navProperty.name);
|
|
629
|
+
}
|
|
630
|
+
q = q.where(pred);
|
|
631
|
+
let em = entity.entityAspect.entityManager;
|
|
632
|
+
return em ? q.using(em) : q;
|
|
633
|
+
};
|
|
634
|
+
EntityQuery.prototype._$typeName = "EntityQuery";
|
|
635
|
+
// private functions
|
|
636
|
+
function fromJSON(eq, json) {
|
|
637
|
+
core.toJson(json, {
|
|
638
|
+
"resourceName,from": null,
|
|
639
|
+
// just the name comes back and will be resolved later
|
|
640
|
+
"resultEntityType,toType": null,
|
|
641
|
+
"wherePredicate,where": function (v) {
|
|
642
|
+
return v ? new Predicate(v) : undefined;
|
|
643
|
+
},
|
|
644
|
+
"orderByClause,orderBy": function (v) {
|
|
645
|
+
return v ? new OrderByClause(v) : undefined;
|
|
646
|
+
},
|
|
647
|
+
"selectClause,select": function (v) {
|
|
648
|
+
return v ? new SelectClause(v) : undefined;
|
|
649
|
+
},
|
|
650
|
+
"expandClause,expand": function (v) {
|
|
651
|
+
return v ? new ExpandClause(v) : undefined;
|
|
652
|
+
},
|
|
653
|
+
"skipCount,skip": null,
|
|
654
|
+
"takeCount,take": null,
|
|
655
|
+
parameters: function (v) {
|
|
656
|
+
return core.isEmpty(v) ? undefined : v;
|
|
657
|
+
},
|
|
658
|
+
"inlineCountEnabled,inlineCount": false,
|
|
659
|
+
"noTrackingEnabled,noTracking": false,
|
|
660
|
+
queryOptions: function (v) {
|
|
661
|
+
return v ? QueryOptions.fromJSON(v) : undefined;
|
|
662
|
+
}
|
|
663
|
+
}, eq);
|
|
664
|
+
return eq;
|
|
665
|
+
}
|
|
666
|
+
function clone(eq, propName, value) {
|
|
667
|
+
// immutable queries mean that we don't need to clone if no change in value.
|
|
668
|
+
if (propName) {
|
|
669
|
+
if (eq[propName] === value)
|
|
670
|
+
return eq;
|
|
671
|
+
}
|
|
672
|
+
// copying QueryOptions is safe because they are are immutable;
|
|
673
|
+
let copy = core.extend(new EntityQuery(), eq, [
|
|
674
|
+
"resourceName",
|
|
675
|
+
"fromEntityType",
|
|
676
|
+
"wherePredicate",
|
|
677
|
+
"orderByClause",
|
|
678
|
+
"selectClause",
|
|
679
|
+
"skipCount",
|
|
680
|
+
"takeCount",
|
|
681
|
+
"expandClause",
|
|
682
|
+
"inlineCountEnabled",
|
|
683
|
+
"noTrackingEnabled",
|
|
684
|
+
"usesNameOnServer",
|
|
685
|
+
"queryOptions",
|
|
686
|
+
"entityManager",
|
|
687
|
+
"dataService",
|
|
688
|
+
"resultEntityType"
|
|
689
|
+
]);
|
|
690
|
+
copy.parameters = core.extend({}, eq.parameters);
|
|
691
|
+
if (propName) {
|
|
692
|
+
copy[propName] = value;
|
|
693
|
+
}
|
|
694
|
+
return copy;
|
|
695
|
+
}
|
|
696
|
+
function processUsing(eq, map, value, propertyName) {
|
|
697
|
+
let typeName = value._$typeName || ((value instanceof BreezeEnum) && value.constructor.name);
|
|
698
|
+
let key = typeName && typeName.substr(0, 1).toLowerCase() + typeName.substr(1);
|
|
699
|
+
if (propertyName && key !== propertyName) {
|
|
700
|
+
throw new Error("Invalid value for property: " + propertyName);
|
|
701
|
+
}
|
|
702
|
+
if (key) {
|
|
703
|
+
let fn = map[key];
|
|
704
|
+
if (fn === undefined) {
|
|
705
|
+
throw new Error("Invalid config property: " + key);
|
|
706
|
+
}
|
|
707
|
+
else if (fn === null) {
|
|
708
|
+
eq[key] = value;
|
|
709
|
+
}
|
|
710
|
+
else {
|
|
711
|
+
fn(eq, value);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
core.objectForEach(value, (propName, val) => {
|
|
716
|
+
processUsing(eq, map, val, propName);
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
function normalizePropertyPaths(propertyPaths) {
|
|
721
|
+
assertParam(propertyPaths, "propertyPaths").isOptional().isString().or().isArray().isString().check();
|
|
722
|
+
if (typeof propertyPaths === 'string') {
|
|
723
|
+
propertyPaths = propertyPaths.split(",");
|
|
724
|
+
}
|
|
725
|
+
propertyPaths = propertyPaths.map(function (pp) {
|
|
726
|
+
return pp.trim();
|
|
727
|
+
});
|
|
728
|
+
return propertyPaths;
|
|
729
|
+
}
|
|
730
|
+
function buildPredicate(entity) {
|
|
731
|
+
let entityType = entity.entityType;
|
|
732
|
+
let predParts = entityType.keyProperties.map(function (kp) {
|
|
733
|
+
return Predicate.create(kp.name, FilterQueryOp.Equals, entity.getProperty(kp.name));
|
|
734
|
+
});
|
|
735
|
+
let pred = Predicate.and(predParts);
|
|
736
|
+
return pred;
|
|
737
|
+
}
|
|
738
|
+
function buildKeyPredicate(entityKey) {
|
|
739
|
+
let keyProps = entityKey.entityType.keyProperties;
|
|
740
|
+
let preds = core.arrayZip(keyProps, entityKey.values, function (kp, v) {
|
|
741
|
+
return Predicate.create(kp.name, FilterQueryOp.Equals, v);
|
|
742
|
+
});
|
|
743
|
+
let pred = Predicate.and(preds);
|
|
744
|
+
return pred;
|
|
745
|
+
}
|
|
746
|
+
function buildNavigationPredicate(entity, navigationProperty) {
|
|
747
|
+
if (navigationProperty.isScalar) {
|
|
748
|
+
if (navigationProperty.foreignKeyNames.length === 0)
|
|
749
|
+
return null;
|
|
750
|
+
let relatedKeyValues = navigationProperty.foreignKeyNames.map((fkName) => {
|
|
751
|
+
return entity.getProperty(fkName);
|
|
752
|
+
});
|
|
753
|
+
let entityKey = new EntityKey(navigationProperty.entityType, relatedKeyValues);
|
|
754
|
+
return buildKeyPredicate(entityKey);
|
|
755
|
+
}
|
|
756
|
+
else {
|
|
757
|
+
let inverseNp = navigationProperty.inverse;
|
|
758
|
+
let foreignKeyNames = inverseNp ? inverseNp.foreignKeyNames : navigationProperty.invForeignKeyNames;
|
|
759
|
+
if (foreignKeyNames.length === 0)
|
|
760
|
+
return null;
|
|
761
|
+
let keyValues = entity.entityAspect.getKey().values;
|
|
762
|
+
let predParts = core.arrayZip(foreignKeyNames, keyValues, (fkName, kv) => {
|
|
763
|
+
return Predicate.create(fkName, FilterQueryOp.Equals, kv);
|
|
764
|
+
});
|
|
765
|
+
return Predicate.and(predParts);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
FilterQueryOp is an 'Enum' containing all of the valid [[Predicate]]
|
|
770
|
+
filter operators for an [[EntityQuery]].
|
|
771
|
+
**/
|
|
772
|
+
export class FilterQueryOp extends BreezeEnum {
|
|
773
|
+
}
|
|
774
|
+
/** Aliases: "eq", "==" **/
|
|
775
|
+
FilterQueryOp.Equals = new FilterQueryOp({ operator: "eq" });
|
|
776
|
+
/** Aliases: "ne", "!=" **/
|
|
777
|
+
FilterQueryOp.NotEquals = new FilterQueryOp({ operator: "ne" });
|
|
778
|
+
/** Aliases: "gt", ">" **/
|
|
779
|
+
FilterQueryOp.GreaterThan = new FilterQueryOp({ operator: "gt" });
|
|
780
|
+
/** Aliases: "lt", "<" **/
|
|
781
|
+
FilterQueryOp.LessThan = new FilterQueryOp({ operator: "lt" });
|
|
782
|
+
/** Aliases: "ge", ">=" **/
|
|
783
|
+
FilterQueryOp.GreaterThanOrEqual = new FilterQueryOp({ operator: "ge" });
|
|
784
|
+
/** Aliases: "le", "<=" **/
|
|
785
|
+
FilterQueryOp.LessThanOrEqual = new FilterQueryOp({ operator: "le" });
|
|
786
|
+
/** String operation: Is a string a substring of another string. Aliases: "substringof" **/
|
|
787
|
+
FilterQueryOp.Contains = new FilterQueryOp({ operator: "contains" });
|
|
788
|
+
/** No aliases */
|
|
789
|
+
FilterQueryOp.StartsWith = new FilterQueryOp({ operator: "startswith" });
|
|
790
|
+
/** No aliases */
|
|
791
|
+
FilterQueryOp.EndsWith = new FilterQueryOp({ operator: "endswith" });
|
|
792
|
+
/** Aliases: "some" **/
|
|
793
|
+
FilterQueryOp.Any = new FilterQueryOp({ operator: "any" });
|
|
794
|
+
/** Aliases: "every" **/
|
|
795
|
+
FilterQueryOp.All = new FilterQueryOp({ operator: "all" });
|
|
796
|
+
/** No aliases */
|
|
797
|
+
FilterQueryOp.In = new FilterQueryOp({ operator: "in" });
|
|
798
|
+
/** No aliases */
|
|
799
|
+
FilterQueryOp.IsTypeOf = new FilterQueryOp({ operator: "isof" });
|
|
800
|
+
FilterQueryOp.prototype._$typeName = "FilterQueryOp";
|
|
801
|
+
Error['x'] = FilterQueryOp.resolveSymbols();
|
|
802
|
+
/**
|
|
803
|
+
BooleanQueryOp is an 'Enum' containing all of the valid boolean
|
|
804
|
+
operators for an [[EntityQuery]].
|
|
805
|
+
**/
|
|
806
|
+
export class BooleanQueryOp extends BreezeEnum {
|
|
807
|
+
}
|
|
808
|
+
BooleanQueryOp.And = new BooleanQueryOp({ operator: "and" });
|
|
809
|
+
BooleanQueryOp.Or = new BooleanQueryOp({ operator: "or" });
|
|
810
|
+
BooleanQueryOp.Not = new BooleanQueryOp({ operator: "not" });
|
|
811
|
+
BooleanQueryOp.prototype._$typeName = "BooleanQueryOp";
|
|
812
|
+
Error['x'] = BooleanQueryOp.resolveSymbols();
|
|
813
|
+
/** For use by breeze plugin authors only. The class is used in most [[IUriBuilderAdapter]] implementations
|
|
814
|
+
@adapter (see [[IUriBuilderAdapter]])
|
|
815
|
+
@hidden
|
|
816
|
+
|
|
817
|
+
An OrderByClause is a description of the properties and direction that the result
|
|
818
|
+
of a query should be sorted in. OrderByClauses are immutable, which means that any
|
|
819
|
+
method that would modify an OrderByClause actually returns a new OrderByClause.
|
|
820
|
+
|
|
821
|
+
For example for an Employee object with properties of 'Company' and 'LastName' the following would be valid expressions:
|
|
822
|
+
> let obc = new OrderByClause("Company.CompanyName, LastName")
|
|
823
|
+
|
|
824
|
+
or
|
|
825
|
+
> let obc = new OrderByClause("Company.CompanyName desc, LastName")
|
|
826
|
+
|
|
827
|
+
or
|
|
828
|
+
> let obc = new OrderByClause("Company.CompanyName, LastName", true);
|
|
829
|
+
*/
|
|
830
|
+
export class OrderByClause {
|
|
831
|
+
constructor(propertyPaths, isDesc) {
|
|
832
|
+
if (propertyPaths.length === 0) {
|
|
833
|
+
throw new Error("OrderByClause cannot be empty");
|
|
834
|
+
}
|
|
835
|
+
// you can also pass in an array of orderByClauses
|
|
836
|
+
if (propertyPaths[0] instanceof OrderByClause) {
|
|
837
|
+
let clauses = propertyPaths;
|
|
838
|
+
this.items = core.arrayFlatMap(clauses, c => c.items);
|
|
839
|
+
// this.items = Array.prototype.concat.apply(clauses[0].items, clauses.slice(1).map(core.pluck("items")));
|
|
840
|
+
// this.items = Array.prototype.concat.apply([], clauses.map(core.pluck("items")));
|
|
841
|
+
}
|
|
842
|
+
else {
|
|
843
|
+
this.items = propertyPaths.map(function (pp) {
|
|
844
|
+
return new OrderByItem(pp, isDesc);
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
validate(entityType) {
|
|
849
|
+
if (entityType == null || entityType.isAnonymous)
|
|
850
|
+
return;
|
|
851
|
+
this.items.forEach((item) => {
|
|
852
|
+
item.validate(entityType);
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
getComparer(entityType) {
|
|
856
|
+
let orderByFuncs = this.items.map(function (obc) {
|
|
857
|
+
return obc.getComparer(entityType);
|
|
858
|
+
});
|
|
859
|
+
return function (entity1, entity2) {
|
|
860
|
+
for (let i = 0; i < orderByFuncs.length; i++) {
|
|
861
|
+
let result = orderByFuncs[i](entity1, entity2);
|
|
862
|
+
if (result !== 0) {
|
|
863
|
+
return result;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
return 0;
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
toJSONExt(context) {
|
|
870
|
+
return this.items.map(function (item) {
|
|
871
|
+
return context.propertyPathFn(item.propertyPath) + (item.isDesc ? " desc" : "");
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
/** @hidden @internal */
|
|
876
|
+
export class OrderByItem {
|
|
877
|
+
constructor(propertyPath, isDesc) {
|
|
878
|
+
if (!(typeof propertyPath === 'string')) {
|
|
879
|
+
throw new Error("propertyPath is not a string");
|
|
880
|
+
}
|
|
881
|
+
propertyPath = propertyPath.trim();
|
|
882
|
+
let parts = propertyPath.split(' ');
|
|
883
|
+
// parts[0] is the propertyPath; [1] would be whether descending or not.
|
|
884
|
+
// if (parts.length > 1 && isDesc !== true && isDesc !== false) {
|
|
885
|
+
if (parts.length > 1 && isDesc == null) {
|
|
886
|
+
isDesc = core.stringStartsWith(parts[1].toLowerCase(), "desc");
|
|
887
|
+
if (!isDesc) {
|
|
888
|
+
// isDesc is false but check to make sure its intended.
|
|
889
|
+
let isAsc = core.stringStartsWith(parts[1].toLowerCase(), "asc");
|
|
890
|
+
if (!isAsc) {
|
|
891
|
+
throw new Error("the second word in the propertyPath must begin with 'desc' or 'asc'");
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
this.propertyPath = parts[0];
|
|
896
|
+
this.isDesc = isDesc || false;
|
|
897
|
+
}
|
|
898
|
+
validate(entityType) {
|
|
899
|
+
if (entityType == null || entityType.isAnonymous)
|
|
900
|
+
return;
|
|
901
|
+
// will throw an exception on bad propertyPath
|
|
902
|
+
this.lastProperty = entityType.getProperty(this.propertyPath, true);
|
|
903
|
+
return this.lastProperty;
|
|
904
|
+
}
|
|
905
|
+
getComparer(entityType) {
|
|
906
|
+
let propDataType;
|
|
907
|
+
let isCaseSensitive;
|
|
908
|
+
if (!this.lastProperty)
|
|
909
|
+
this.validate(entityType);
|
|
910
|
+
if (this.lastProperty) {
|
|
911
|
+
propDataType = this.lastProperty.dataType;
|
|
912
|
+
isCaseSensitive = this.lastProperty.parentType.metadataStore.localQueryComparisonOptions.isCaseSensitive;
|
|
913
|
+
}
|
|
914
|
+
let propertyPath = this.propertyPath;
|
|
915
|
+
let isDesc = this.isDesc;
|
|
916
|
+
return function (entity1, entity2) {
|
|
917
|
+
let value1 = EntityAspect.getPropertyPathValue(entity1, propertyPath);
|
|
918
|
+
let value2 = EntityAspect.getPropertyPathValue(entity2, propertyPath);
|
|
919
|
+
let dataType = propDataType || (value1 && DataType.fromValue(value1)) || DataType.fromValue(value2);
|
|
920
|
+
if (dataType === DataType.String) {
|
|
921
|
+
if (isCaseSensitive) {
|
|
922
|
+
value1 = value1 || "";
|
|
923
|
+
value2 = value2 || "";
|
|
924
|
+
}
|
|
925
|
+
else {
|
|
926
|
+
value1 = (value1 || "").toLowerCase();
|
|
927
|
+
value2 = (value2 || "").toLowerCase();
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
else {
|
|
931
|
+
let normalize = DataType.getComparableFn(dataType);
|
|
932
|
+
value1 = normalize(value1);
|
|
933
|
+
value2 = normalize(value2);
|
|
934
|
+
}
|
|
935
|
+
if (value1 === value2) {
|
|
936
|
+
return 0;
|
|
937
|
+
}
|
|
938
|
+
else if (value1 > value2 || value2 === undefined) {
|
|
939
|
+
return isDesc ? -1 : 1;
|
|
940
|
+
}
|
|
941
|
+
else {
|
|
942
|
+
return isDesc ? 1 : -1;
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
/** For use by breeze plugin authors only. The class is used in most [[IUriBuilderAdapter]] implementations
|
|
948
|
+
@adapter (see [[IUriBuilderAdapter]])
|
|
949
|
+
@hidden
|
|
950
|
+
**/
|
|
951
|
+
export class SelectClause {
|
|
952
|
+
constructor(propertyPaths) {
|
|
953
|
+
this.propertyPaths = propertyPaths;
|
|
954
|
+
this._pathNames = propertyPaths.map(function (pp) {
|
|
955
|
+
return pp.replace(".", "_");
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
validate(entityType) {
|
|
959
|
+
if (entityType == null || entityType.isAnonymous)
|
|
960
|
+
return; // can't validate yet
|
|
961
|
+
// will throw an exception on bad propertyPath
|
|
962
|
+
this.propertyPaths.forEach(function (path) {
|
|
963
|
+
entityType.getProperty(path, true);
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
toFunction( /* config */) {
|
|
967
|
+
let that = this;
|
|
968
|
+
return function (entity) {
|
|
969
|
+
let result = {};
|
|
970
|
+
that.propertyPaths.forEach(function (path, i) {
|
|
971
|
+
result[that._pathNames[i]] = EntityAspect.getPropertyPathValue(entity, path);
|
|
972
|
+
});
|
|
973
|
+
return result;
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
toJSONExt(context) {
|
|
977
|
+
return this.propertyPaths.map(function (pp) {
|
|
978
|
+
return context.propertyPathFn(pp);
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
/** For use by breeze plugin authors only. The class is used in most [[IUriBuilderAdapter]] implementations
|
|
983
|
+
@adapter (see [[IUriBuilderAdapter]])
|
|
984
|
+
@hidden
|
|
985
|
+
**/
|
|
986
|
+
export class ExpandClause {
|
|
987
|
+
constructor(propertyPaths) {
|
|
988
|
+
this.propertyPaths = propertyPaths;
|
|
989
|
+
}
|
|
990
|
+
toJSONExt(context) {
|
|
991
|
+
return this.propertyPaths.map(function (pp) {
|
|
992
|
+
return context.propertyPathFn(pp);
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LXF1ZXJ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2VudGl0eS1xdWVyeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsSUFBSSxFQUEyQixNQUFNLFFBQVEsQ0FBQztBQUN2RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN2QyxPQUFPLEVBQUUsWUFBWSxFQUFVLE1BQU0saUJBQWlCLENBQUM7QUFDdkQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxXQUFXLEVBQXNCLE1BQU0sZ0JBQWdCLENBQUM7QUFFakUsT0FBTyxFQUFpQixVQUFVLEVBQXNDLE1BQU0sbUJBQW1CLENBQUM7QUFDbEcsT0FBTyxFQUFFLFlBQVksRUFBZ0MsTUFBTSxpQkFBaUIsQ0FBQztBQUM3RSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBV3hDOzs7Ozs7R0FNRztBQUNILE1BQU0sT0FBTyxXQUFXO0lBd0N0Qjs7Ozs7Ozs7T0FRRztJQUNILFlBQVksWUFBOEI7UUFDeEMsSUFBSSxZQUFZLElBQUksSUFBSSxJQUFJLENBQUMsT0FBTyxZQUFZLEtBQUssUUFBUSxDQUFDLEVBQUU7WUFDOUQsT0FBTyxRQUFRLENBQUMsSUFBSSxFQUFFLFlBQVksQ0FBQyxDQUFDO1NBQ3JDO1FBQ0QsOEdBQThHO1FBQzlHLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBc0IsQ0FBQztRQUMzQyxJQUFJLENBQUMsY0FBYyxHQUFHLFNBQVMsQ0FBQztRQUNoQyxJQUFJLENBQUMsY0FBYyxHQUFHLFNBQVMsQ0FBQztRQUNoQyxJQUFJLENBQUMsYUFBYSxHQUFHLFNBQVMsQ0FBQztRQUMvQixJQUFJ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LENBQUMsQ0FBQztRQUNyQyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQUVEOzs7R0FHRztBQUNILE1BQU0sT0FBTyxZQUFZO0lBR3ZCLFlBQVksYUFBdUI7UUFDakMsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUM7SUFDckMsQ0FBQztJQUVELFNBQVMsQ0FBQyxPQUErQjtRQUN2QyxPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRTtZQUN4QyxPQUFPLE9BQU8sQ0FBQyxjQUFlLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDckMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0NBRUYiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjb3JlLCBDYWxsYmFjaywgRXJyb3JDYWxsYmFjayB9IGZyb20gJy4vY29yZSc7XHJcbmltcG9ydCB7IGFzc2VydFBhcmFtIH0gZnJvbSAnLi9hc3NlcnQtcGFyYW0nO1xyXG5pbXBvcnQgeyBEYXRhVHlwZSB9IGZyb20gJy4vZGF0YS10eXBlJztcclxuaW1wb3J0IHsgRW50aXR5QXNwZWN0LCBFbnRpdHkgfSBmcm9tICcuL2VudGl0eS1hc3BlY3QnO1xyXG5pbXBvcnQgeyBFbnRpdHlLZXkgfSBmcm9tICcuL2VudGl0eS1rZXknO1xyXG5pbXBvcnQgeyBCcmVlemVFbnVtIH0gZnJvbSAnLi9lbnVtJztcclxuaW1wb3J0IHsgRGF0YVNlcnZpY2UsIEpzb25SZXN1bHRzQWRhcHRlciB9IGZyb20gJy4vZGF0YS1zZXJ2aWNlJztcclxuaW1wb3J0IHsgRW50aXR5TWFuYWdlciwgUXVlcnlSZXN1bHQgfSBmcm9tICcuL2VudGl0eS1tYW5hZ2VyJztcclxuaW1wb3J0IHsgTWV0YWRhdGFTdG9yZSwgRW50aXR5VHlwZSwgTmF2aWdhdGlvblByb3BlcnR5LCBFbnRpdHlQcm9wZXJ0eSB9IGZyb20gJy4vZW50aXR5LW1ldGFkYXRhJztcclxuaW1wb3J0IHsgUXVlcnlPcHRpb25zLCBNZXJnZVN0cmF0ZWd5LCBGZXRjaFN0cmF0ZWd5IH0gZnJvbSAnLi9xdWVyeS1vcHRpb25zJztcclxuaW1wb3J0IHsgUHJlZGljYXRlIH0gZnJvbSAnLi9wcmVkaWNhdGUnO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBSZWN1cnNpdmVBcnJheTxUPiB7XHJcbiAgW2k6IG51bWJlcl06IFQgfCBSZWN1cnNpdmVBcnJheTxUPjtcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBFbnRpdHlRdWVyeUpzb25Db250ZXh0IHtcclxuICBlbnRpdHlUeXBlPzogRW50aXR5VHlwZTtcclxuICBwcm9wZXJ0eVBhdGhGbj86IEZ1bmN0aW9uOyAvLyBUT0RPXHJcbiAgdG9OYW1lT25TZXJ2ZXI/OiBib29sZWFuO1xyXG59XHJcbi8qKlxyXG5BbiBFbnRpdHlRdWVyeSBpbnN0YW5jZSBpcyB1c2VkIHRvIHF1ZXJ5IGVudGl0aWVzIGVpdGhlciBmcm9tIGEgcmVtb3RlIGRhdGFzb3VyY2Ugb3IgZnJvbSBhIGxvY2FsIFtbRW50aXR5TWFuYWdlcl1dLlxyXG5cclxuRW50aXR5UXVlcmllcyBhcmUgaW1tdXRhYmxlIC0gdGhpcyBtZWFucyB0aGF0IGFsbCBFbnRpdHlRdWVyeSBtZXRob2RzIHRoYXQgcmV0dXJuIGFuIEVudGl0eVF1ZXJ5IGFjdHVhbGx5IGNyZWF0ZSBhIG5ldyBFbnRpdHlRdWVyeS4gIFRoaXMgbWVhbnMgdGhhdFxyXG5FbnRpdHlRdWVyaWVzIGNhbiBiZSAnbW9kaWZpZWQnIHdpdGhvdXQgYWZmZWN0aW5nIGFueSBjdXJyZW50IGluc3RhbmNlcy5cclxuQGR5bmFtaWNcclxuKiovXHJcbmV4cG9ydCBjbGFzcyBFbnRpdHlRdWVyeSB7XHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgXyR0eXBlTmFtZTogc3RyaW5nOyAvLyBhY3R1YWxseSBwbGFjZWQgb24gcHJvdG90eXBlXHJcbiAgLy8gdG9wID0gdGhpcy50YWtlOyAvLyBUT0RPOiBjb25zaWRlclxyXG4gIC8qKiBUaGUgcmVzb3VyY2UgbmFtZSB1c2VkIGJ5IHRoaXMgcXVlcnkuIF9fUmVhZCBPbmx5X18gKi9cclxuICByZXNvdXJjZU5hbWU/OiBzdHJpbmc7XHJcbiAgLyoqIFRoZSBbW0VudGl0eVR5cGVdXSB0aGF0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGUgJ2Zyb20nIGNsYXVzZSAoIHJlc291cmNlTmFtZSkgb2YgdGhlIHF1ZXJ5LiAgVGhpcyBpcyBvbmx5IGd1YXJhbnRlZWQgdG8gYmUgYmUgc2V0IEFGVEVSIHRoZSBxdWVyeVxyXG4gIGhhcyBiZWVuIGV4ZWN1dGVkIGJlY2F1c2UgaXQgZGVwZW5kcyBvbiB0aGUgW1tNZXRhZGF0YVN0b3JlXV0gYXNzb2NpYXRlZCB3aXRoIHRoZSBbW0VudGl0eU1hbmFnZXJdXSB0aGF0IHRoZSBxdWVyeSB3YXMgZXhlY3V0ZWQgYWdhaW5zdC5cclxuICBUaGlzIHZhbHVlIG1heSBiZSBudWxsIGlmIHRoZSBlbnRpdHlUeXBlIGNhbm5vdCBiZSBhc3NvY2lhdGVkIHdpdGggYSByZXNvdXJjZU5hbWUuIF9fUmVhZCBPbmx5X18gKi9cclxuICBmcm9tRW50aXR5VHlwZT86IEVudGl0eVR5cGU7XHJcbiAgLyoqIFRoZSAnd2hlcmUnIFtbUHJlZGljYXRlXV0gdXNlZCBieSB0aGlzIHF1ZXJ5LiBfX1JlYWQgT25seV9fICovXHJcbiAgd2hlcmVQcmVkaWNhdGU6IFByZWRpY2F0ZTsgLy8gVE9ET1xyXG4gIC8qKiBUaGUgW1tPcmRlckJ5Q2xhdXNlXV0gdXNlZCBieSB0aGlzIHF1ZXJ5LiBfX1JlYWQgT25seV9fICovXHJcbiAgb3JkZXJCeUNsYXVzZT86IE9yZGVyQnlDbGF1c2U7XHJcbiAgLyoqIFRoZSBbW0V4cGFuZENsYXVzZV1dIHVzZWQgYnkgdGhpcyBxdWVyeS4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIGV4cGFuZENsYXVzZT86IEV4cGFuZENsYXVzZTtcclxuICAvKiogVGhlIFtbU2VsZWN0Q2xhdXNlXV0gdXNlZCBieSB0aGlzIHF1ZXJ5LiBfX1JlYWQgT25seV9fICovXHJcbiAgc2VsZWN0Q2xhdXNlPzogU2VsZWN0Q2xhdXNlO1xyXG4gIC8qKiBUaGUgbnVtYmVyIG9mIGVudGl0aWVzIHRvICdza2lwJyBmb3IgdGhpcyBxdWVyeS4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIHNraXBDb3VudD86IG51bWJlcjtcclxuICAvKiogVGhlIG51bWJlciBvZiBlbnRpdGllcyB0byAndGFrZScgZm9yIHRoaXMgcXVlcnkuIF9fUmVhZCBPbmx5X18gKi9cclxuICB0YWtlQ291bnQ/OiBudW1iZXI7XHJcbiAgLyoqIEFueSBhZGRpdGlvbmFsIHBhcmFtZXRlcnMgdGhhdCB3ZXJlIGFkZGVkIHRvIHRoZSBxdWVyeSB2aWEgdGhlICd3aXRoUGFyYW1ldGVycycgbWV0aG9kLiBfX1JlYWQgT25seV9fICovXHJcbiAgcGFyYW1ldGVyczogT2JqZWN0O1xyXG4gIC8qKiBXaGV0aGVyIGFuIGlubGluZSBjb3VudCBpcyByZXR1cm5lZCBmb3IgdGhpcyBxdWVyeS4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIGlubGluZUNvdW50RW5hYmxlZDogYm9vbGVhbjtcclxuICAvKiogV2hldGhlciBlbnRpdHkgdHJhY2tpbmcgaGFzIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgcXVlcnkuIF9fUmVhZCBPbmx5X18gKi9cclxuICBub1RyYWNraW5nRW5hYmxlZDogYm9vbGVhbjtcclxuICAvKiogVGhlIFtbUXVlcnlPcHRpb25zXV0gZm9yIHRoaXMgcXVlcnkuIF9fUmVhZCBPbmx5X18gICoqL1xyXG4gIC8vIGRlZmF1bHQgaXMgdG8gZ2V0IHF1ZXJ5T3B0aW9ucyBhbmQgZGF0YVNlcnZpY2UgZnJvbSB0aGUgZW50aXR5TWFuYWdlci5cclxuICBxdWVyeU9wdGlvbnM/OiBRdWVyeU9wdGlvbnM7XHJcbiAgLyoqIFRoZSBbW0RhdGFTZXJ2aWNlXV0gZm9yIHRoaXMgcXVlcnkuIF9fUmVhZCBPbmx5X18gICoqL1xyXG4gIGRhdGFTZXJ2aWNlPzogRGF0YVNlcnZpY2U7XHJcbiAgLyoqIFRoZSBbW0VudGl0eU1hbmFnZXJdXSBmb3IgdGhpcyBxdWVyeS4gVGhpcyBtYXkgYmUgbnVsbCBhbmQgY2FuIGJlIHNldCB2aWEgdGhlICd1c2luZycgbWV0aG9kLiAgKiovXHJcbiAgZW50aXR5TWFuYWdlcj86IEVudGl0eU1hbmFnZXI7XHJcbiAgLyoqICBUaGUgZW50aXR5VHlwZSB0aGF0IHdpbGwgYmUgcmV0dXJuZWQgYnkgdGhpcyBxdWVyeS4gXHJcbiAgVGhpcyBwcm9wZXJ0eSB3aWxsIG9ubHkgYmUgc2V0IGlmIHRoZSAndG9UeXBlJyBtZXRob2Qgd2FzIGNhbGxlZC4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIHJlc3VsdEVudGl0eVR5cGU6IEVudGl0eVR5cGUgfCBzdHJpbmc7XHJcbiAgdXNlc05hbWVPblNlcnZlcj86IGJvb2xlYW47XHJcblxyXG4gIC8qKiBDb25zdHJ1Y3RvclxyXG4gID4gICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiQ3VzdG9tZXJzXCIpXHJcblxyXG4gIFVzdWFsbHkgdGhpcyBjb25zdHJ1Y3RvciB3aWxsIGJlIGZvbGxvd2VkIGJ5IGNhbGxzIHRvIGZpbHRlcmluZywgb3JkZXJpbmcgb3Igc2VsZWN0aW9uIG1ldGhvZHNcclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiQ3VzdG9tZXJzXCIpXHJcbiAgPiAgICAgICAgLndoZXJlKFwiQ29tcGFueU5hbWVcIiwgXCJzdGFydHNXaXRoXCIsIFwiQ1wiKVxyXG4gID4gICAgICAgIC5vcmRlckJ5KFwiUmVnaW9uXCIpO1xyXG4gIEBwYXJhbSByZXNvdXJjZU5hbWUgLSBlaXRoZXIgYSByZXNvdXJjZSBuYW1lIG9yIGEgc2VyaWFsaXplZCBFbnRpdHlRdWVyeSAoIGNyZWF0ZWQgYnkgW1tFbnRpdHlRdWVyeS50b0pTT05dXSlcclxuICAqKi9cclxuICBjb25zdHJ1Y3RvcihyZXNvdXJjZU5hbWU/OiBzdHJpbmcgfCBPYmplY3QpIHtcclxuICAgIGlmIChyZXNvdXJjZU5hbWUgIT0gbnVsbCAmJiAodHlwZW9mIHJlc291cmNlTmFtZSAhPT0gJ3N0cmluZycpKSB7XHJcbiAgICAgIHJldHVybiBmcm9tSlNPTih0aGlzLCByZXNvdXJjZU5hbWUpO1xyXG4gICAgfVxyXG4gICAgLy8gVE9ETzogY2FzdCBhcyBzdHJpbmcgYmVsb3cgbmVlZGVkIGZvciBlYXJseSB2ZXJzaW9ucyBvZiBUeXBlRG9jIC0gYnV0IG5vdCBmb3IgcmVndWxhciBjb21waWxlIC0gY2hlY2sgbGF0ZXJcclxuICAgIHRoaXMucmVzb3VyY2VOYW1lID0gcmVzb3VyY2VOYW1lIGFzIHN0cmluZztcclxuICAgIHRoaXMuZnJvbUVudGl0eVR5cGUgPSB1bmRlZmluZWQ7XHJcbiAgICB0aGlzLndoZXJlUHJlZGljYXRlID0gdW5kZWZpbmVkO1xyXG4gICAgdGhpcy5vcmRlckJ5Q2xhdXNlID0gdW5kZWZpbmVkO1xyXG4gICAgdGhpcy5zZWxlY3RDbGF1c2UgPSB1bmRlZmluZWQ7XHJcbiAgICB0aGlzLnNraXBDb3VudCA9IHVuZGVmaW5lZDtcclxuICAgIHRoaXMudGFrZUNvdW50ID0gdW5kZWZpbmVkO1xyXG4gICAgdGhpcy5leHBhbmRDbGF1c2UgPSB1bmRlZmluZWQ7XHJcbiAgICB0aGlzLnBhcmFtZXRlcnMgPSB7fTtcclxuICAgIHRoaXMuaW5saW5lQ291bnRFbmFibGVkID0gZmFsc2U7XHJcbiAgICB0aGlzLm5vVHJhY2tpbmdFbmFibGVkID0gZmFsc2U7XHJcbiAgICAvLyBkZWZhdWx0IGlzIHRvIGdldCBxdWVyeU9wdGlvbnMgYW5kIGRhdGFTZXJ2aWNlIGZyb20gdGhlIGVudGl0eU1hbmFnZXIuXHJcbiAgICAvLyB0aGlzLnF1ZXJ5T3B0aW9ucyA9IG5ldyBRdWVyeU9wdGlvbnMoKTtcclxuICAgIC8vIHRoaXMuZGF0YVNlcnZpY2UgPSBuZXcgRGF0YVNlcnZpY2UoKTtcclxuICAgIHRoaXMuZW50aXR5TWFuYWdlciA9IHVuZGVmaW5lZDtcclxuXHJcbiAgfVxyXG5cclxuXHJcbiAgLyoqXHJcbiAgU3BlY2lmaWVzIHRoZSByZXNvdXJjZSB0byBxdWVyeSBmb3IgdGhpcyBFbnRpdHlRdWVyeS5cclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KClcclxuICA+ICAgICAgICAuZnJvbShcIkN1c3RvbWVyc1wiKTtcclxuXHJcbiAgaXMgdGhlIHNhbWUgYXNcclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiQ3VzdG9tZXJzXCIpO1xyXG4gIEBwYXJhbSByZXNvdXJjZU5hbWUgLSBUaGUgcmVzb3VyY2UgdG8gcXVlcnkuXHJcbiAgKiovXHJcbiAgZnJvbShyZXNvdXJjZU5hbWU6IHN0cmluZykge1xyXG4gICAgLy8gVE9ETzogdGhpbmsgYWJvdXQgYWxsb3dpbmcgZW50aXR5VHlwZSBhcyB3ZWxsXHJcbiAgICBhc3NlcnRQYXJhbShyZXNvdXJjZU5hbWUsIFwicmVzb3VyY2VOYW1lXCIpLmlzU3RyaW5nKCkuY2hlY2soKTtcclxuICAgIHJldHVybiBjbG9uZSh0aGlzLCBcInJlc291cmNlTmFtZVwiLCByZXNvdXJjZU5hbWUpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgVGhpcyBpcyBhIHN0YXRpYyB2ZXJzaW9uIG9mIHRoZSBcImZyb21cIiBtZXRob2QgYW5kIGl0IGNyZWF0ZXMgYSAnYmFzZScgZW50aXR5UXVlcnkgZm9yIHRoZSBzcGVjaWZpZWQgcmVzb3VyY2UgbmFtZS5cclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gRW50aXR5UXVlcnkuZnJvbShcIkN1c3RvbWVyc1wiKTtcclxuXHJcbiAgaXMgdGhlIHNhbWUgYXNcclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiQ3VzdG9tZXJzXCIpO1xyXG4gIEBwYXJhbSByZXNvdXJjZU5hbWUgLSBUaGUgcmVzb3VyY2UgdG8gcXVlcnkuXHJcbiAgKiovXHJcbiAgc3RhdGljIGZyb20ocmVzb3VyY2VOYW1lOiBzdHJpbmcpIHtcclxuICAgIGFzc2VydFBhcmFtKHJlc291cmNlTmFtZSwgXCJyZXNvdXJjZU5hbWVcIikuaXNTdHJpbmcoKS5jaGVjaygpO1xyXG4gICAgcmV0dXJuIG5ldyBFbnRpdHlRdWVyeShyZXNvdXJjZU5hbWUpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgU3BlY2lmaWVzIHRoZSB0b3AgbGV2ZWwgRW50aXR5VHlwZSB0aGF0IHRoaXMgcXVlcnkgd2lsbCByZXR1cm4uICBPbmx5IG5lZWRlZCB3aGVuIGEgcXVlcnkgcmV0dXJucyBhIGpzb24gcmVzdWx0IHRoYXQgZG9lcyBub3QgaW5jbHVkZSB0eXBlIGluZm9ybWF0aW9uLFxyXG4gIG9yIHdoZW4gdXNpbmcgYSByZXNvdXJjZSBuYW1lIHRoYXQgaXMgbm90IGFzc29jaWF0ZWQgdG8gYW4gRW50aXR5VHlwZS5cclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KClcclxuICA+ICAgICAgICAuZnJvbShcIk15Q3VzdG9tTWV0aG9kXCIpXHJcbiAgPiAgICAgICAgLnRvVHlwZShcIkN1c3RvbWVyXCIpXHJcbiAgQHBhcmFtIGVudGl0eVR5cGUgLSBUaGUgdG9wIGxldmVsIEVudGl0eVR5cGUgdGhhdCB0aGlzIHF1ZXJ5IHdpbGwgcmV0dXJuLlxyXG4gIEBzdW1tYXJ5IElmIHRoZSBqc29uIHJlc3VsdCBjb25zaXN0cyBvZiBtb3JlIHRoYW4gYSBzaW1wbGUgZW50aXR5IG9yIGFycmF5IG9mIGVudGl0aWVzLCBjb25zaWRlciB1c2luZyBhIFtbSnNvblJlc3VsdHNBZGFwdGVyXV0gaW5zdGVhZC5cclxuICAqKi9cclxuICB0b1R5cGUoZW50aXR5VHlwZTogc3RyaW5nIHwgRW50aXR5VHlwZSkge1xyXG4gICAgYXNzZXJ0UGFyYW0oZW50aXR5VHlwZSwgXCJlbnRpdHlUeXBlXCIpLmlzU3RyaW5nKCkub3IoKS5pc0luc3RhbmNlT2YoRW50aXR5VHlwZSkuY2hlY2soKTtcclxuICAgIHJldHVybiBjbG9uZSh0aGlzLCBcInJlc3VsdEVudGl0eVR5cGVcIiwgZW50aXR5VHlwZSk7XHJcbiAgfVxyXG5cclxuXHJcbiAgd2hlcmUocHJlZGljYXRlPzogUHJlZGljYXRlKTogRW50aXR5UXVlcnk7XHJcbiAgd2hlcmUocHJlZGljYXRlOiBPYmplY3QpOiBFbnRpdHlRdWVyeTtcclxuICB3aGVyZShwcm9wZXJ0eTogc3RyaW5nLCBvcGVyYXRvcjogc3RyaW5nLCB2YWx1ZTogYW55KTogRW50aXR5UXVlcnk7XHJcbiAgd2hlcmUocHJvcGVydHk6IHN0cmluZywgb3BlcmF0b3I6IEZpbHRlclF1ZXJ5T3AsIHZhbHVlOiBhbnkpOiBFbnRpdHlRdWVyeTtcclxuICB3aGVyZShwcm9wZXJ0eTogc3RyaW5nLCBmaWx0ZXJvcDogRmlsdGVyUXVlcnlPcCwgcHJvcGVydHkyOiBzdHJpbmcsIGZpbHRlcm9wMjogRmlsdGVyUXVlcnlPcCwgdmFsdWU6IGFueSk6IEVudGl0eVF1ZXJ5OyAgLy8gZm9yIGFueS9hbGwgY2xhdXNlc1xyXG4gIHdoZXJlKHByb3BlcnR5OiBzdHJpbmcsIGZpbHRlcm9wOiBzdHJpbmcsIHByb3BlcnR5Mjogc3RyaW5nLCBmaWx0ZXJvcDI6IHN0cmluZywgdmFsdWU6IGFueSk6IEVudGl0eVF1ZXJ5OyAgLy8gZm9yIGFueS9hbGwgY2xhdXNlc1xyXG4gIHdoZXJlKHByb3BlcnR5OiBzdHJpbmcsIGZpbHRlcm9wOiBzdHJpbmcsIHByb3BlcnR5Mjogc3RyaW5nLCBmaWx0ZXJvcDI6IHN0cmluZywgcHJvcGVydHkzOiBzdHJpbmcsIGZpbHRlcm9wMzogc3RyaW5nLCB2YWx1ZTogYW55KTogRW50aXR5UXVlcnk7ICAvLyBmb3IgYW55L2FsbCBjbGF1c2VzXHJcbiAgd2hlcmUoYW5BcnJheTogUmVjdXJzaXZlQXJyYXk8c3RyaW5nIHwgbnVtYmVyIHwgRmlsdGVyUXVlcnlPcCB8IFByZWRpY2F0ZT4pOiBFbnRpdHlRdWVyeTtcclxuICAvKipcclxuICBSZXR1cm5zIGEgbmV3IHF1ZXJ5IHdpdGggYW4gYWRkZWQgZmlsdGVyIGNyaXRlcmlhOyBDYW4gYmUgY2FsbGVkIG11bHRpcGxlIHRpbWVzIHdoaWNoIG1lYW5zIHRvICdhbmQnIHdpdGggYW55IGV4aXN0aW5nXHJcbiAgUHJlZGljYXRlIG9yIGNhbiBiZSBjYWxsZWQgd2l0aCBudWxsIHRvIGNsZWFyIGFsbCBwcmVkaWNhdGVzLlxyXG4gID4gICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJDdXN0b21lcnNcIilcclxuICA+ICAgICAgICAgIC53aGVyZShcIkNvbXBhbnlOYW1lXCIsIFwic3RhcnRzV2l0aFwiLCBcIkNcIik7XHJcblxyXG4gIFRoaXMgY2FuIGFsc28gYmUgZXhwcmVzc2VkIHVzaW5nIGFuIGV4cGxpY2l0IFtbRmlsdGVyUXVlcnlPcF1dIGFzXHJcbiAgPiAgICAgIGxldCBxdWVyeSA9IG5ldyBFbnRpdHlRdWVyeShcIkN1c3RvbWVyc1wiKVxyXG4gID4gICAgICAgICAgLndoZXJlKFwiQ29tcGFueU5hbWVcIiwgRmlsdGVyUXVlcnlPcC5TdGFydHNXaXRoLCBcIkNcIik7XHJcblxyXG4gIG9yIGEgcHJlY29uc3RydWN0ZWQgW1tQcmVkaWNhdGVdXSBtYXkgYmUgdXNlZFxyXG4gID4gICAgICBsZXQgcHJlZCA9IG5ldyBQcmVkaWNhdGUoXCJDb21wYW55TmFtZVwiLCBGaWx0ZXJRdWVyeU9wLlN0YXJ0c1dpdGgsIFwiQ1wiKTtcclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiQ3VzdG9tZXJzXCIpLndoZXJlKHByZWQpO1xyXG5cclxuICBQcmVkaWNhdGVzIGFyZSBvZnRlbiB1c2VmdWwgd2hlbiB5b3Ugd2FudCB0byBjb21iaW5lIG11bHRpcGxlIGNvbmRpdGlvbnMgaW4gYSBzaW5nbGUgZmlsdGVyLCBzdWNoIGFzXHJcbiAgPiAgICAgIGxldCBwcmVkID0gUHJlZGljYXRlLmNyZWF0ZShcIkNvbXBhbnlOYW1lXCIsIFwic3RhcnRzd2l0aFwiLCBcIkNcIikuYW5kKFwiUmVnaW9uXCIsIEZpbHRlclF1ZXJ5T3AuRXF1YWxzLCBudWxsKTtcclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiQ3VzdG9tZXJzXCIpXHJcbiAgPiAgICAgICAgICAud2hlcmUocHJlZCk7XHJcblxyXG4gIE1vcmUgY29tcGxpY2F0ZWQgcXVlcmllcyBjYW4gbWFrZSB1c2Ugb2YgbmVzdGVkIHByb3BlcnR5IHBhdGhzXHJcbiAgPiAgICAgIGxldCBxdWVyeSA9IG5ldyBFbnRpdHlRdWVyeShcIlByb2R1Y3RzXCIpXHJcbiAgPiAgICAgICAgICAud2hlcmUoXCJDYXRlZ29yeS5DYXRlZ29yeU5hbWVcIiwgXCJzdGFydHN3aXRoXCIsIFwiU1wiKTtcclxuXHJcbiAgb3IgT0RhdGEgZnVuY3Rpb25zIC0gQSBsaXN0IG9mIHZhbGlkIE9EYXRhIGZ1bmN0aW9ucyBjYW4gYmUgZm91bmQgd2l0aGluIHRoZSBbW1ByZWRpY2F0ZV1dIGRvY3VtZW50YXRpb24uXHJcbiAgXHJcbiAgPiAgICAgIGxldCBxdWVyeSA9IG5ldyBFbnRpdHlRdWVyeShcIkN1c3RvbWVyc1wiKVxyXG4gID4gICAgICAgICAgLndoZXJlKFwidG9Mb3dlcihDb21wYW55TmFtZSlcIiwgXCJzdGFydHNXaXRoXCIsIFwiY1wiKTtcclxuXHJcbiAgb3IgdG8gYmUgZXZlbiBtb3JlIGJhcm9xdWVcclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiQ3VzdG9tZXJzXCIpXHJcbiAgPiAgICAgICAgICAud2hlcmUoXCJ0b1VwcGVyKHN1YnN0cmluZyhDb21wYW55TmFtZSwgMSwgMikpXCIsIEZpbHRlclF1ZXJ5T3AuRXF1YWxzLCBcIk9NXCIpO1xyXG4gIEBwYXJhbSBwcmVkaWNhdGUgLSAgQ2FuIGJlIGVpdGhlclxyXG4gICAgLSBhIHNpbmdsZSBbW1ByZWRpY2F0ZV1dXHJcblxyXG4gICAgLSB0aGUgcGFyYW1ldGVycyB0byBjcmVhdGUgYSAnc2ltcGxlJyBQcmVkaWNhdGVcclxuICAgIC0gLSAgYSBwcm9wZXJ0eSBuYW1lLCBhIHByb3BlcnR5IHBhdGggd2l0aCAnLicgYXMgcGF0aCBzZXBlcmF0b3JzIG9yIGEgcHJvcGVydHkgZXhwcmVzc2lvbiB7U3RyaW5nfVxyXG4gICAgLSAtICBhbiBvcGVyYXRvciAtIFtbRmlsdGVyUXVlcnlPcF1dIG9yIGl0J3Mgc3RyaW5nIHJlcHJlc2VudGF0aW9uLiBDYXNlIGlzIGlnbm9yZWRcclxuICAgIHdoZW4gaWYgYSBzdHJpbmcgaXMgcHJvdmlkZWQgYW5kIGFueSBzdHJpbmcgdGhhdCBtYXRjaGVzIG9uZSBvZiB0aGUgRmlsdGVyUXVlcnlPcCBhbGlhc2VzIHdpbGwgYmUgYWNjZXB0ZWQuXHJcbiAgICAtIC0gIGEgdmFsdWUge09iamVjdH0gLSBUaGlzIHdpbGwgYmUgdHJlYXRlZCBhcyBlaXRoZXIgYSBwcm9wZXJ0eSBleHByZXNzaW9uIG9yIGEgbGl0ZXJhbCBkZXBlbmRpbmcgb24gY29udGV4dC4gIFxyXG4gICAgSW4gZ2VuZXJhbCwgaWYgdGhlIHZhbHVlIGNhbiBiZSBpbnRlcnByZXRlZCBhcyBhIHByb3BlcnR5IGV4cHJlc3Npb24gaXQgd2lsbCBiZSwgb3RoZXJ3aXNlIGl0IHdpbGwgYmUgdHJlYXRlZCBhcyBhIGxpdGVyYWwuXHJcbiAgICBJbiBtb3N0IGNhc2VzIHRoaXMgd29ya3Mgd2VsbCwgYnV0IHlvdSBjYW4gYWxzbyBmb3JjZSB0aGUgaW50ZXJwcmV0YXRpb24gYnkgbWFraW5nIHRoZSB2YWx1ZSBhcmd1bWVudCBpdHNlbGYgYW4gb2JqZWN0IFxyXG4gICAgd2l0aCBhICd2YWx1ZScgcHJvcGVydHkgYW5kIGFuICdpc0xpdGVyYWwnIHByb3BlcnR5IHNldCB0byBlaXRoZXIgdHJ1ZSBvciBmYWxzZS5cclxuICAgIEJyZWV6ZSBhbHNvIHRyaWVzIHRvIGluZmVyIHRoZSBkYXRhVHlwZSBvZiBhbnkgbGl0ZXJhbCBiYXNlZCBvbiBjb250ZXh0LCBpZiB0aGlzIGZhaWxzIHlvdSBjYW4gZm9yY2UgdGhpcyBpbmZlcmVuY2UgYnkgbWFraW5nIHRoZSB2YWx1ZSBhcmd1bWVudCBcclxuICAgIGFuIG9iamVjdCB3aXRoIGEgJ3ZhbHVlJyBwcm9wZXJ0eSBhbmQgYSAnZGF0YVR5cGUncHJvcGVydHkgc2V0IHRvIG9uZSBvZiB0aGUgRGF0YVR5cGUgZW51bWVyYXRpb24gaW5zdGFuY2VzLlxyXG5cclxuICAgIC0gYSBudWxsIG9yIHVuZGVmaW5lZCAoIHRoaXMgY2F1c2VzIGFueSBleGlzdGluZyB3aGVyZSBjbGF1c2UgdG8gYmUgcmVtb3ZlZClcclxuICAqKi9cclxuICB3aGVyZSguLi5hcmdzOiBhbnlbXSkge1xyXG4gICAgbGV0IHdoZXJlUHJlZGljYXRlOiBQcmVkaWNhdGUgfCB1bmRlZmluZWQ7XHJcbiAgICBpZiAoYXJncy5sZW5ndGggPiAwICYmIGFyZ3NbMF0gIT0gbnVsbCkge1xyXG4gICAgICB3aGVyZVByZWRpY2F0ZSA9IFByZWRpY2F0ZS5jcmVhdGUoLi4uPGFueT5hcmdzKTtcclxuICAgICAgaWYgKHRoaXMuZnJvbUVudGl0eVR5cGUpIHdoZXJlUHJlZGljYXRlLl92YWxpZGF0ZSh0aGlzLmZyb21FbnRpdHlUeXBlKTtcclxuICAgICAgaWYgKHRoaXMud2hlcmVQcmVkaWNhdGUpIHtcclxuICAgICAgICB3aGVyZVByZWRpY2F0ZSA9IHRoaXMud2hlcmVQcmVkaWNhdGUuYW5kKHdoZXJlUHJlZGljYXRlKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIGNsb25lKHRoaXMsIFwid2hlcmVQcmVkaWNhdGVcIiwgd2hlcmVQcmVkaWNhdGUpO1xyXG4gIH1cclxuXHJcblxyXG4gIG9yZGVyQnkocHJvcGVydHlQYXRocz86IHN0cmluZywgaXNEZXNjZW5kaW5nPzogYm9vbGVhbik6IEVudGl0eVF1ZXJ5O1xyXG4gIG9yZGVyQnkocHJvcGVydHlQYXRoczogc3RyaW5nW10sIGlzRGVzY2VuZGluZz86IGJvb2xlYW4pOiBFbnRpdHlRdWVyeTtcclxuICAvKipcclxuICBSZXR1cm5zIGEgbmV3IHF1ZXJ5IHRoYXQgb3JkZXJzIHRoZSByZXN1bHRzIG9mIHRoZSBxdWVyeSBieSBwcm9wZXJ0eSBuYW1lLiAgQnkgZGVmYXVsdCBzb3J0aW5nIG9jY3VycyBpcyBhc2NlbmRpbmcgb3JkZXIsIGJ1dCBzb3J0aW5nIGluIGRlc2NlbmRpbmcgb3JkZXIgaXMgc3VwcG9ydGVkIGFzIHdlbGwuXHJcbiAgT3JkZXJCeSBjbGF1c2VzIG1heSBiZSBjaGFpbmVkLlxyXG4gID4gICAgIGxldCBxdWVyeSA9IG5ldyBFbnRpdHlRdWVyeShcIkN1c3RvbWVyc1wiKVxyXG4gID4gICAgICAgIC5vcmRlckJ5KFwiQ29tcGFueU5hbWVcIik7XHJcblxyXG4gIG9yIHRvIHNvcnQgYWNyb3NzIG11bHRpcGxlIHByb3BlcnRpZXNcclxuICA+ICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJDdXN0b21lcnNcIilcclxuICA+ICAgICAgICAub3JkZXJCeShcIlJlZ2lvbiwgQ29tcGFueU5hbWVcIik7XHJcblxyXG4gIE5lc3RlZCBwcm9wZXJ0eSBwYXRocyBhcmUgYWxzbyBzdXBwb3J0ZWRcclxuICA+ICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJQcm9kdWN0c1wiKVxyXG4gID4gICAgICAgIC5vcmRlckJ5KFwiQ2F0ZWdvcnkuQ2F0ZWdvcnlOYW1lXCIpO1xyXG5cclxuICBTb3J0aW5nIGluIGRlc2NlbmRpbmcgb3JkZXIgaXMgc3VwcG9ydGVkIHZpYSB0aGUgYWRkaXRpb24gb2YgJyBkZXNjJyB0byB0aGUgZW5kIG9mIGFueSBwcm9wZXJ0eSBwYXRoLlxyXG4gID4gICAgIGxldCBxdWVyeSA9IG5ldyBFbnRpdHlRdWVyeShcIkN1c3RvbWVyc1wiKVxyXG4gID4gICAgICAgIC5vcmRlckJ5KFwiQ29tcGFueU5hbWUgZGVzY1wiKTtcclxuXHJcbiAgb3JcclxuICA+ICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJDdXN0b21lcnNcIilcclxuICA+ICAgICAgICAub3JkZXJCeShcIlJlZ2lvbiBkZXNjLCBDb21wYW55TmFtZSBkZXNjXCIpO1xyXG4gIEBwYXJhbSBwcm9wZXJ0eVBhdGhzIC0gQSBjb21tYS1zZXBhcmF0ZWQgKCcsJykgc3RyaW5nIG9mIHByb3BlcnR5IHBhdGhzIG9yIGFuIGFycmF5IG9mIHByb3BlcnR5IHBhdGhzLlxyXG4gIEVhY2ggcHJvcGVydHkgcGF0aCBjYW4gb3B0aW9uYWxseSBlbmQgd2l0aCBcIiBkZXNjXCIgdG8gZm9yY2UgYSBkZXNjZW5kaW5nIHNvcnQgb3JkZXIuIElmICdwcm9wZXJ0eVBhdGhzJyBpcyBlaXRoZXIgbnVsbCBvciBvbWl0dGVkIHRoZW4gYWxsIG9yZGVyaW5nIGlzIHJlbW92ZWQuXHJcbiAgQHBhcmFtIGlzRGVzY2VuZGluZyAtIElmIHNwZWNpZmllZCwgb3ZlcnJpZGVzIGFsbCBvZiB0aGUgZW1iZWRkZWQgJ2Rlc2MnIHRhZ3MgaW4gdGhlIHByZXZpb3VzbHkgc3BlY2lmaWVkIHByb3BlcnR5IHBhdGhzLlxyXG4gICoqL1xyXG4gIG9yZGVyQnkocHJvcGVydHlQYXRoczogc3RyaW5nIHwgc3RyaW5nW10sIGlzRGVzY2VuZGluZz86IGJvb2xlYW4pIHtcclxuICAgIC8vIHByb3BlcnR5UGF0aHM6IGNhbiBwYXNzIGluIGNyZWF0ZShcIkEuWCxCXCIpIG9yIGNyZWF0ZShcIkEuWCBkZXNjLCBCXCIpIG9yIGNyZWF0ZShcIkEuWCBkZXNjLEJcIiwgdHJ1ZV0pXHJcbiAgICAvLyBpc0Rlc2MgcGFyYW1ldGVyIHRydW1wcyBpc0Rlc2MgaW4gcHJvcGVydHlOYW1lLlxyXG4gICAgbGV0IG9yZGVyQnlDbGF1c2UgPSBwcm9wZXJ0eVBhdGhzID09IG51bGwgPyBudWxsIDogbmV3IE9yZGVyQnlDbGF1c2Uobm9ybWFsaXplUHJvcGVydHlQYXRocyhwcm9wZXJ0eVBhdGhzKSwgaXNEZXNjZW5kaW5nKTtcclxuICAgIGlmICh0aGlzLm9yZGVyQnlDbGF1c2UgJiYgb3JkZXJCeUNsYXVzZSkge1xyXG4gICAgICBvcmRlckJ5Q2xhdXNlID0gbmV3IE9yZGVyQnlDbGF1c2UoW3RoaXMub3JkZXJCeUNsYXVzZSwgb3JkZXJCeUNsYXVzZV0pO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGNsb25lKHRoaXMsIFwib3JkZXJCeUNsYXVzZVwiLCBvcmRlckJ5Q2xhdXNlKTtcclxuICB9XHJcblxyXG5cclxuICBvcmRlckJ5RGVzYyhwcm9wZXJ0eVBhdGhzOiBzdHJpbmcpOiBFbnRpdHlRdWVyeTtcclxuICBvcmRlckJ5RGVzYyhwcm9wZXJ0eVBhdGhzOiBzdHJpbmdbXSk6IEVudGl0eVF1ZXJ5O1xyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBuZXcgcXVlcnkgdGhhdCBvcmRlcnMgdGhlIHJlc3VsdHMgb2YgdGhlIHF1ZXJ5IGJ5IHByb3BlcnR5IG5hbWUgaW4gZGVzY2VuZGluZyBvcmRlci5cclxuICA+ICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJDdXN0b21lcnNcIilcclxuICA+ICAgICAgICAub3JkZXJCeURlc2MoXCJDb21wYW55TmFtZVwiKTtcclxuXHJcbiAgb3IgdG8gc29ydCBhY3Jvc3MgbXVsdGlwbGUgcHJvcGVydGllc1xyXG4gID4gICAgIGxldCBxdWVyeSA9IG5ldyBFbnRpdHlRdWVyeShcIkN1c3RvbWVyc1wiKVxyXG4gID4gICAgICAgIC5vcmRlckJ5RGVzYyhcIlJlZ2lvbiwgQ29tcGFueU5hbWVcIik7XHJcblxyXG4gIE5lc3RlZCBwcm9wZXJ0eSBwYXRocyBhcmUgYWxzbyBzdXBwb3J0ZWRcclxuICA+ICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJQcm9kdWN0c1wiKVxyXG4gID4gICAgICAgIC5vcmRlckJ5RGVzYyhcIkNhdGVnb3J5LkNhdGVnb3J5TmFtZVwiKTtcclxuICBAcGFyYW0gcHJvcGVydHlQYXRocyAtIEEgY29tbWEtc2VwYXJhdGVkICgnLCcpIHN0cmluZyBvZiBwcm9wZXJ0eSBwYXRocyBvciBhbiBhcnJheSBvZiBwcm9wZXJ0eSBwYXRocy5cclxuICBJZiAncHJvcGVydHlQYXRocycgaXMgZWl0aGVyIG51bGwgb3Igb21pdHRlZCB0aGVuIGFsbCBvcmRlcmluZyBpcyByZW1vdmVkLlxyXG4gICoqL1xyXG4gIG9yZGVyQnlEZXNjKHByb3BlcnR5UGF0aHM6IHN0cmluZyB8IHN0cmluZ1tdKSB7XHJcbiAgICByZXR1cm4gdGhpcy5vcmRlckJ5KHByb3BlcnR5UGF0aHMgYXMgYW55LCB0cnVlKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBuZXcgcXVlcnkgdGhhdCBzZWxlY3RzIGEgbGlzdCBvZiBwcm9wZXJ0aWVzIGZyb20gdGhlIHJlc3VsdHMgb2YgdGhlIG9yaWdpbmFsIHF1ZXJ5IGFuZCByZXR1cm5zIHRoZSB2YWx1ZXMgb2YganVzdCB0aGVzZSBwcm9wZXJ0aWVzLiBUaGlzXHJcbiAgd2lsbCBiZSByZWZlcnJlZCB0byBhcyBhIHByb2plY3Rpb24uXHJcbiAgSWYgdGhlIHJlc3VsdCBvZiB0aGlzIHNlbGVjdGlvbiBcInByb2plY3Rpb25cIiBjb250YWlucyBlbnRpdGllcywgdGhlc2UgZW50aXRpZXMgd2lsbCBhdXRvbWF0aWNhbGx5IGJlIGFkZGVkIHRvIEVudGl0eU1hbmFnZXIncyBjYWNoZSBhbmQgd2lsbFxyXG4gIGJlIG1hZGUgJ29ic2VydmFibGUnLlxyXG4gIEFueSBzaW1wbGUgcHJvcGVydGllcywgaS5lLiBzdHJpbmdzLCBudW1iZXJzIG9yIGRhdGVzIHdpdGhpbiBhIHByb2plY3Rpb24gd2lsbCBub3QgYmUgY2FjaGVkIGFyZSB3aWxsIE5PVCBiZSBtYWRlICdvYnNlcnZhYmxlJy5cclxuICBcclxuICBTaW1wbGUgZGF0YSBwcm9wZXJ0aWVzIGNhbiBiZSBwcm9qZWN0ZWRcclxuICA+ICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJDdXN0b21lcnNcIilcclxuICA+ICAgICAgICAgLndoZXJlKFwiQ29tcGFueU5hbWVcIiwgXCJzdGFydHNXaXRoXCIsIFwiQ1wiKVxyXG4gID4gICAgICAgICAuc2VsZWN0KFwiQ29tcGFueU5hbWVcIik7XHJcblxyXG4gIFRoaXMgd2lsbCByZXR1cm4gYW4gYXJyYXkgb2Ygb2JqZWN0cyBlYWNoIHdpdGggYSBzaW5nbGUgXCJDb21wYW55TmFtZVwiIHByb3BlcnR5IG9mIHR5cGUgc3RyaW5nLlxyXG4gIEEgc2ltaWxhciBxdWVyeSBjb3VsZCByZXR1cm4gYSBuYXZpZ2F0aW9uIHByb3BlcnR5IGluc3RlYWRcclxuICA+ICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJDdXN0b21lcnNcIilcclxuICA+ICAgICAgICAud2hlcmUoXCJDb21wYW55TmFtZVwiLCBcInN0YXJ0c1dpdGhcIiwgXCJDXCIpXHJcbiAgPiAgICAgICAgLnNlbGVjdChcIk9yZGVyc1wiKTtcclxuXHJcbiAgd2hlcmUgdGhlIHJlc3VsdCB3b3VsZCBiZSBhbiBhcnJheSBvZiBvYmplY3RzIGVhY2ggd2l0aCBhIHNpbmdsZSBcIk9yZGVyc1wiIHByb3BlcnR5IHRoYXQgd291bGQgaXRzZWxmIGJlIGFuIGFycmF5IG9mIFwiT3JkZXJcIiBlbnRpdGllcy5cclxuICBDb21wb3NpdGUgcHJvamVjdGlvbnMgYXJlIGFsc28gcG9zc2libGU6XHJcbiAgPiAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiQ3VzdG9tZXJzXCIpXHJcbiAgPiAgICAgICAgLndoZXJlKFwiQ29tcGFueU5hbWVcIiwgXCJzdGFydHNXaXRoXCIsIFwiQ1wiKVxyXG4gID4gICAgICAgIC5zZWxlY3QoXCJDb21wYW55TmFtZSwgT3JkZXJzXCIpO1xyXG5cclxuICBBcyB3ZWxsIGFzIHByb2plY3Rpb25zIGludm9sdmluZyBuZXN0ZWQgcHJvcGVydHkgcGF0aHNcclxuICA+ICAgICBsZXQgcXVlcnkgPSBFbnRpdHlRdWVyeShcIk9yZGVyc1wiKVxyXG4gID4gICAgICAgIC53aGVyZShcIkN1c3RvbWVyLkNvbXBhbnlOYW1lXCIsIFwic3RhcnRzV2l0aFwiLCBcIkNcIilcclxuICA+ICAgICAgICAuc2VsZWN0KFwiQ3VzdG9tZXIuQ29tcGFueU5hbWUsIEN1c3RvbWVyLCBPcmRlckRhdGVcIik7XHJcbiAgQHBhcmFtIHByb3BlcnR5UGF0aHMgLSBBIGNvbW1hLXNlcGFyYXRlZCAoJywnKSBzdHJpbmcgb2YgcHJvcGVydHkgcGF0aHMgb3IgYW4gYXJyYXkgb2YgcHJvcGVydHkgcGF0aHMuXHJcbiAgSWYgJ3Byb3BlcnR5UGF0aHMnIGlzIGVpdGhlciBudWxsIG9yIG9taXR0ZWQgdGhlbiBhbnkgZXhpc3RpbmcgcHJvamVjdGlvbiBvbiB0aGUgcXVlcnkgaXMgcmVtb3ZlZC5cclxuICAqKi9cclxuICBzZWxlY3QocHJvcGVydHlQYXRocz86IHN0cmluZyB8IHN0cmluZ1tdKSB7XHJcbiAgICBsZXQgc2VsZWN0Q2xhdXNlID0gcHJvcGVydHlQYXRocyA9PSBudWxsID8gbnVsbCA6IG5ldyBTZWxlY3RDbGF1c2Uobm9ybWFsaXplUHJvcGVydHlQYXRocyhwcm9wZXJ0eVBhdGhzKSk7XHJcbiAgICByZXR1cm4gY2xvbmUodGhpcywgXCJzZWxlY3RDbGF1c2VcIiwgc2VsZWN0Q2xhdXNlKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBuZXcgcXVlcnkgdGhhdCBza2lwcyB0aGUgc3BlY2lmaWVkIG51bWJlciBvZiBlbnRpdGllcyB3aGVuIHJldHVybmluZyByZXN1bHRzLlxyXG4gIEFueSBleGlzdGluZyAnc2tpcCcgY2FuIGJlIGNsZWFyZWQgYnkgY2FsbGluZyAnc2tpcCcgd2l0aCBubyBhcmd1bWVudHMuXHJcbiAgPiAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiQ3VzdG9tZXJzXCIpXHJcbiAgPiAgICAgICAud2hlcmUoXCJDb21wYW55TmFtZVwiLCBcInN0YXJ0c1dpdGhcIiwgXCJDXCIpXHJcbiAgPiAgICAgICAuc2tpcCg1KTtcclxuICBAcGFyYW0gY291bnQgLSBUaGUgbnVtYmVyIG9mIGVudGl0aWVzIHRvIHNraXAgb3Zlci4gSWYgb21pdHRlZCBvciBudWxsIGFueSBleGlzdGluZyBza2lwIGNvdW50IG9uIHRoZSBxdWVyeSBpcyByZW1vdmVkLlxyXG4gICoqL1xyXG4gIHNraXAoY291bnQ/OiBudW1iZXIpIHtcclxuICAgIGFzc2VydFBhcmFtKGNvdW50LCBcImNvdW50XCIpLmlzT3B0aW9uYWwoKS5pc051bWJlcigpLmNoZWNrKCk7XHJcbiAgICByZXR1cm4gY2xvbmUodGhpcywgXCJza2lwQ291bnRcIiwgKGNvdW50ID09IG51bGwpID8gbnVsbCA6IGNvdW50KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBuZXcgcXVlcnkgdGhhdCByZXR1cm5zIG9ubHkgdGhlIHNwZWNpZmllZCBudW1iZXIgb2YgZW50aXRpZXMgd2hlbiByZXR1cm5pbmcgcmVzdWx0cy4gLSBTYW1lIGFzICd0YWtlJy5cclxuICBBbnkgZXhpc3RpbmcgJ3RvcCcgY2FuIGJlIGNsZWFyZWQgYnkgY2FsbGluZyAndG9wJyB3aXRoIG5vIGFyZ3VtZW50cy5cclxuICA+ICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJDdXN0b21lcnNcIilcclxuICA+ICAgICAgICAudG9wKDUpO1xyXG4gIEBwYXJhbSBjb3VudCAtIFRoZSBudW1iZXIgb2YgZW50aXRpZXMgdG8gcmV0dXJuLlxyXG4gIElmICdjb3VudCcgaXMgZWl0aGVyIG51bGwgb3Igb21pdHRlZCB0aGVuIGFueSBleGlzdGluZyAndG9wJyBjb3VudCBvbiB0aGUgcXVlcnkgaXMgcmVtb3ZlZC5cclxuICAqKi9cclxuICB0b3AoY291bnQ/OiBudW1iZXIpIHtcclxuICAgIHJldHVybiB0aGlzLnRha2UoY291bnQpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgUmV0dXJucyBhIG5ldyBxdWVyeSB0aGF0IHJldHVybnMgb25seSB0aGUgc3BlY2lmaWVkIG51bWJlciBvZiBlbnRpdGllcyB3aGVuIHJldHVybmluZyByZXN1bHRzIC0gU2FtZSBhcyAndG9wJy5cclxuICBBbnkgZXhpc3RpbmcgdGFrZSBjYW4gYmUgY2xlYXJlZCBieSBjYWxsaW5nIHRha2Ugd2l0aCBubyBhcmd1bWVudHMuXHJcbiAgPiAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiQ3VzdG9tZXJzXCIpXHJcbiAgPiAgICAgICAgLnRha2UoNSk7XHJcbiAgQHBhcmFtIGNvdW50IC0gVGhlIG51bWJlciBvZiBlbnRpdGllcyB0byByZXR1cm4uXHJcbiAgSWYgJ2NvdW50JyBpcyBlaXRoZXIgbnVsbCBvciBvbWl0dGVkIHRoZW4gYW55IGV4aXN0aW5nICd0YWtlJyBjb3VudCBvbiB0aGUgcXVlcnkgaXMgcmVtb3ZlZC5cclxuICAqKi9cclxuICB0YWtlKGNvdW50PzogbnVtYmVyKSB7XHJcbiAgICBhc3NlcnRQYXJhbShjb3VudCwgXCJjb3VudFwiKS5pc09wdGlvbmFsKCkuaXNOdW1iZXIoKS5jaGVjaygpO1xyXG4gICAgcmV0dXJuIGNsb25lKHRoaXMsIFwidGFrZUNvdW50XCIsIChjb3VudCA9PSBudWxsKSA/IG51bGwgOiBjb3VudCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBSZXR1cm5zIGEgbmV3IHF1ZXJ5IHRoYXQgd2lsbCByZXR1cm4gcmVsYXRlZCBlbnRpdGllcyBuZXN0ZWQgd2l0aGluIGl0cyByZXN1bHRzLiBUaGUgZXhwYW5kIG1ldGhvZCBhbGxvd3MgeW91IHRvIGlkZW50aWZ5IHJlbGF0ZWQgZW50aXRpZXMsIHZpYSBuYXZpZ2F0aW9uIHByb3BlcnR5XHJcbiAgbmFtZXMgc3VjaCB0aGF0IGEgZ3JhcGggb2YgZW50aXRpZXMgbWF5IGJlIHJldHJpZXZlZCB3aXRoIGEgc2luZ2xlIHJlcXVlc3QuIEFueSBmaWx0ZXJpbmcgb2NjdXJzIGJlZm9yZSB0aGUgcmVzdWx0cyBhcmUgJ2V4cGFuZGVkJy5cclxuICA+ICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJDdXN0b21lcnNcIilcclxuICA+ICAgICAgICAud2hlcmUoXCJDb21wYW55TmFtZVwiLCBcInN0YXJ0c1dpdGhcIiwgXCJDXCIpXHJcbiAgPiAgICAgICAgLmV4cGFuZChcIk9yZGVyc1wiKTtcclxuXHJcbiAgd2lsbCByZXR1cm4gdGhlIGZpbHRlcmVkIGN1c3RvbWVycyBlYWNoIHdpdGggaXRzIFwiT3JkZXJzXCIgcHJvcGVydGllcyBmdWxseSByZXNvbHZlZC5cclxuICBNdWx0aXBsZSBwYXRocyBtYXkgYmUgc3BlY2lmaWVkIGJ5IHNlcGFyYXRpbmcgdGhlIHBhdGhzIGJ5IGEgJywnXHJcbiAgPiAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiT3JkZXJzXCIpXHJcbiAgPiAgICAgICAgLmV4cGFuZChcIkN1c3RvbWVyLCBFbXBsb3llZVwiKVxyXG5cclxuICBhbmQgbmVzdGVkIHByb3BlcnR5IHBhdGhzIG15IGJlIHNwZWNpZmllZCBhcyB3ZWxsXHJcbiAgPiAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiT3JkZXJzXCIpXHJcbiAgPiAgICAgICAgLmV4cGFuZChcIkN1c3RvbWVyLCBPcmRlckRldGFpbHMsIE9yZGVyRGV0YWlscy5Qcm9kdWN0XCIpXHJcbiAgQHBhcmFtIHByb3BlcnR5UGF0aHMgLSBBIGNvbW1hLXNlcGFyYXRlZCBsaXN0IG9mIG5hdmlnYXRpb24gcHJvcGVydHkgbmFtZXMgb3IgYW4gYXJyYXkgb2YgbmF2aWdhdGlvbiBwcm9wZXJ0eSBuYW1lcy4gRWFjaCBOYXZpZ2F0aW9uIFByb3BlcnR5IG5hbWUgY2FuIGJlIGZvbGxvd2VkXHJcbiAgYnkgYSAnLicgYW5kIGFub3RoZXIgbmF2aWdhdGlvbiBwcm9wZXJ0eSBuYW1lIHRvIGVuYWJsZSBpZGVudGlmeWluZyBhIG11bHRpLWxldmVsIHJlbGF0aW9uc2hpcC5cclxuICBJZiAncHJvcGVydHlQYXRocycgaXMgZWl0aGVyIG51bGwgb3Igb21pdHRlZCB0aGVuIGFueSBleGlzdGluZyAnZXhwYW5kJyBjbGF1c2Ugb24gdGhlIHF1ZXJ5IGlzIHJlbW92ZWQuXHJcbiAgKiovXHJcbiAgZXhwYW5kKHByb3BlcnR5UGF0aHM/OiBzdHJpbmcgfCBzdHJpbmdbXSkge1xyXG4gICAgbGV0IGV4cGFuZENsYXVzZSA9IHByb3BlcnR5UGF0aHMgPT0gbnVsbCA/IG51bGwgOiBuZXcgRXhwYW5kQ2xhdXNlKG5vcm1hbGl6ZVByb3BlcnR5UGF0aHMocHJvcGVydHlQYXRocykpO1xyXG4gICAgcmV0dXJuIGNsb25lKHRoaXMsIFwiZXhwYW5kQ2xhdXNlXCIsIGV4cGFuZENsYXVzZSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBSZXR1cm5zIGEgbmV3IHF1ZXJ5IHRoYXQgaW5jbHVkZXMgYSBjb2xsZWN0aW9uIG9mIHBhcmFtZXRlcnMgdG8gcGFzcyB0byB0aGUgc2VydmVyLlxyXG4gID4gICAgIGxldCBxdWVyeSA9IEVudGl0eVF1ZXJ5LmZyb20oXCJFbXBsb3llZXNGaWx0ZXJlZEJ5Q291bnRyeUFuZEJpcnRoZGF0ZVwiKVxyXG4gID4gICAgICAgIC53aXRoUGFyYW1ldGVycyh7IEJpcnRoRGF0ZTogXCIxLzEvMTk2MFwiLCBDb3VudHJ5OiBcIlVTQVwiIH0pO1xyXG4gICBcclxuICB3aWxsIGNhbGwgdGhlICdFbXBsb3llZXNGaWx0ZXJlZEJ5Q291bnRyeUFuZEJpcnRoZGF0ZScgbWV0aG9kIG9uIHRoZSBzZXJ2ZXIgYW5kIHBhc3MgaW4gMiBwYXJhbWV0ZXJzLiBUaGlzXHJcbiAgcXVlcnkgd2lsbCBiZSB1cmkgZW5jb2RlZCBhc1xyXG4gID4gICAgICB7c2VydmljZUFwaX0vRW1wbG95ZWVzRmlsdGVyZWRCeUNvdW50cnlBbmRCaXJ0aGRhdGU/YmlydGhEYXRlPTElMkYxJTJGMTk2MCZjb3VudHJ5PVVTQVxyXG5cclxuICBQYXJhbWV0ZXJzIG1heSBhbHNvIGJlIG1peGVkIGluIHdpdGggb3RoZXIgcXVlcnkgY3JpdGVyaWEuXHJcbiAgPiAgICAgbGV0IHF1ZXJ5ID0gRW50aXR5UXVlcnkuZnJvbShcIkVtcGxveWVlc0ZpbHRlcmVkQnlDb3VudHJ5QW5kQmlydGhkYXRlXCIpXHJcbiAgPiAgICAgICAgLndpdGhQYXJhbWV0ZXJzKHsgQmlydGhEYXRlOiBcIjEvMS8xOTYwXCIsIENvdW50cnk6IFwiVVNBXCIgfSlcclxuICA+ICAgICAgICAud2hlcmUoXCJMYXN0TmFtZVwiLCBcInN0YXJ0c1dpdGhcIiwgXCJTXCIpXHJcbiAgPiAgICAgICAgLm9yZGVyQnkoXCJCaXJ0aERhdGVcIik7XHJcbiAgQHBhcmFtIHBhcmFtZXRlcnMgLSBBIHBhcmFtZXRlcnMgb2JqZWN0IHdoZXJlIHRoZSBrZXlzIGFyZSB0aGUgcGFyYW1ldGVyIG5hbWVzIGFuZCB0aGUgdmFsdWVzIGFyZSB0aGUgcGFyYW1ldGVyIHZhbHVlcy5cclxuICAqKi9cclxuICB3aXRoUGFyYW1ldGVycyhwYXJhbWV0ZXJzOiBPYmplY3QpIHtcclxuICAgIGFzc2VydFBhcmFtKHBhcmFtZXRlcnMsIFwicGFyYW1ldGVyc1wiKS5pc09iamVjdCgpLmNoZWNrKCk7XHJcbiAgICByZXR1cm4gY2xvbmUodGhpcywgXCJwYXJhbWV0ZXJzXCIsIHBhcmFtZXRlcnMpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgUmV0dXJucyBhIHF1ZXJ5IHdpdGggdGhlICdpbmxpbmVDb3VudCcgY2FwYWJpbGl0eSBlaXRoZXIgZW5hYmxlZCBvciBkaXNhYmxlZC4gIFdpdGggJ2lubGluZUNvdW50JyBlbmFibGVkLCBhbiBhZGRpdGlvbmFsICdpbmxpbmVDb3VudCcgcHJvcGVydHlcclxuICB3aWxsIGJlIHJldHVybmVkIHdpdGggdGhlIHF1ZXJ5IHJlc3VsdHMgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIG51bWJlciBvZiBlbnRpdGllcyB0aGF0IHdvdWxkIGhhdmUgYmVlbiByZXR1cm5lZCBieSB0aGlzXHJcbiAgcXVlcnkgd2l0aCBvbmx5IHRoZSAnd2hlcmUnLydmaWx0ZXInIGNsYXVzZXMgYXBwbGllZCwgaS5lLiB3aXRob3V0IGFueSAnc2tpcCcvJ3Rha2UnIG9wZXJhdG9ycyBhcHBsaWVkLiBGb3IgbG9jYWwgcXVlcmllcyB0aGlzIGNsYXVzZSBpcyBpZ25vcmVkLlxyXG4gID4gICAgIGxldCBxdWVyeSA9IG5ldyBFbnRpdHlRdWVyeShcIkN1c3RvbWVyc1wiKVxyXG4gID4gICAgICAgIC50YWtlKDIwKVxyXG4gID4gICAgICAgIC5vcmRlckJ5KFwiQ29tcGFueU5hbWVcIilcclxuICA+ICAgICAgICAuaW5saW5lQ291bnQodHJ1ZSk7XHJcblxyXG4gIHdpbGwgcmV0dXJuIHRoZSBmaXJzdCAyMCBjdXN0b21lcnMgYXMgd2VsbCBhcyBhIGNvdW50IG9mIGFsbCBvZiB0aGUgY3VzdG9tZXJzIGluIHRoZSByZW1vdGUgc3RvcmUuXHJcbiAgQHBhcmFtIGVuYWJsZWQgLSAoZGVmYXVsdCA9IHRydWUpIFdoZXRoZXIgb3Igbm90IGlubGluZUNvdW50IGNhcGFiaWxpdHkgc2hvdWxkIGJlIGVuYWJsZWQuIElmIHRoaXMgcGFyYW1ldGVyIGlzIG9taXR0ZWQsIHRydWUgaXMgYXNzdW1lZC5cclxuICAqKi9cclxuICBpbmxpbmVDb3VudChlbmFibGVkPzogYm9vbGVhbikge1xyXG4gICAgYXNzZXJ0UGFyYW0oZW5hYmxlZCwgXCJlbmFibGVkXCIpLmlzQm9vbGVhbigpLmlzT3B0aW9uYWwoKS5jaGVjaygpO1xyXG4gICAgZW5hYmxlZCA9IChlbmFibGVkID09PSB1bmRlZmluZWQpID8gdHJ1ZSA6ICEhZW5hYmxlZDtcclxuICAgIHJldHVybiBjbG9uZSh0aGlzLCBcImlubGluZUNvdW50RW5hYmxlZFwiLCBlbmFibGVkKTtcclxuICB9XHJcblxyXG4gIHVzZU5hbWVPblNlcnZlcih1c2VzTmFtZU9uU2VydmVyPzogYm9vbGVhbikge1xyXG4gICAgYXNzZXJ0UGFyYW0odXNlc05hbWVPblNlcnZlciwgXCJ1c2VzTmFtZU9uU2VydmVyXCIpLmlzQm9vbGVhbigpLmlzT3B0aW9uYWwoKS5jaGVjaygpO1xyXG4gICAgdXNlc05hbWVPblNlcnZlciA9ICh1c2VzTmFtZU9uU2VydmVyID09PSB1bmRlZmluZWQpID8gdHJ1ZSA6ICEhdXNlc05hbWVPblNlcnZlcjtcclxuICAgIHJldHVybiBjbG9uZSh0aGlzLCBcInVzZXNOYW1lT25TZXJ2ZXJcIiwgdXNlc05hbWVPblNlcnZlcik7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBSZXR1cm5zIGEgcXVlcnkgd2l0aCB0aGUgJ25vVHJhY2tpbmcnIGNhcGFiaWxpdHkgZWl0aGVyIGVuYWJsZWQgb3IgZGlzYWJsZWQuICBXaXRoICdub1RyYWNraW5nJyBlbmFibGVkLCB0aGUgcmVzdWx0cyBvZiB0aGlzIHF1ZXJ5XHJcbiAgd2lsbCBub3QgYmUgY29lcmNlZCBpbnRvIGVudGl0aWVzIGJ1dCB3aWxsIGluc3RlYWQgbG9vayBsaWtlIHJhdyBqYXZhc2NyaXB0IHByb2plY3Rpb25zLiBpLmUuIHNpbXBsZSBqYXZhc2NyaXB0IG9iamVjdHMuXHJcbiAgPiAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiQ3VzdG9tZXJzXCIpXHJcbiAgPiAgICAgICAgIC50YWtlKDIwKVxyXG4gID4gICAgICAgICAub3JkZXJCeShcIkNvbXBhbnlOYW1lXCIpXHJcbiAgPiAgICAgICAgIC5ub1RyYWNraW5nKHRydWUpO1xyXG4gIEBwYXJhbSBlbmFibGVkIC0gKGRlZmF1bHQgPSB0cnVlKSBXaGV0aGVyIG9yIG5vdCB0aGUgbm9UcmFja2luZyBjYXBhYmlsaXR5IHNob3VsZCBiZSBlbmFibGVkLiBJZiB0aGlzIHBhcmFtZXRlciBpcyBvbWl0dGVkLCB0cnVlIGlzIGFzc3VtZWQuXHJcbiAgKiovXHJcbiAgbm9UcmFja2luZyhlbmFibGVkPzogYm9vbGVhbikge1xyXG4gICAgYXNzZXJ0UGFyYW0oZW5hYmxlZCwgXCJlbmFibGVkXCIpLmlzQm9vbGVhbigpLmlzT3B0aW9uYWwoKS5jaGVjaygpO1xyXG4gICAgZW5hYmxlZCA9IChlbmFibGVkID09PSB1bmRlZmluZWQpID8gdHJ1ZSA6ICEhZW5hYmxlZDtcclxuICAgIHJldHVybiBjbG9uZSh0aGlzLCBcIm5vVHJhY2tpbmdFbmFibGVkXCIsIGVuYWJsZWQpO1xyXG4gIH1cclxuXHJcbiAgdXNpbmcob2JqOiBFbnRpdHlNYW5hZ2VyKTogRW50aXR5UXVlcnk7XHJcbiAgdXNpbmcob2JqOiBEYXRhU2VydmljZSk6IEVudGl0eVF1ZXJ5O1xyXG4gIHVzaW5nKG9iajogSnNvblJlc3VsdHNBZGFwdGVyKTogRW50aXR5UXVlcnk7XHJcbiAgdXNpbmcob2JqOiBRdWVyeU9wdGlvbnMpOiBFbnRpdHlRdWVyeTtcclxuICB1c2luZyhvYmo6IE1lcmdlU3RyYXRlZ3kpOiBFbnRpdHlRdWVyeTtcclxuICB1c2luZyhvYmo6IEZldGNoU3RyYXRlZ3kpOiBFbnRpdHlRdWVyeTtcclxuICAvKipcclxuICBSZXR1cm5zIGEgY29weSBvZiB0aGlzIEVudGl0eVF1ZXJ5IHdpdGggdGhlIHNwZWNpZmllZCBbW0VudGl0eU1hbmFnZXJdXSwgW1tEYXRhU2VydmljZV1dLFxyXG4gIFtbSnNvblJlc3VsdHNBZGFwdGVyXV0sIFtbTWVyZ2VTdHJhdGVneV1dIG9yIFtbRmV0Y2hTdHJhdGVneV1dIGFwcGxpZWQuXHJcbiAgPiAgICAgIC8vICd1c2luZycgY2FuIGJlIHVzZWQgdG8gcmV0dXJuIGEgbmV3IHF1ZXJ5IHdpdGggYSBzcGVjaWZpZWQgRW50aXR5TWFuYWdlci5cclxuICA+ICAgICAgbGV0IGVtID0gbmV3IEVudGl0eU1hbmFnZXIoc2VydmljZU5hbWUpO1xyXG4gID4gICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJPcmRlcnNcIilcclxuICA+ICAgICAgICAudXNpbmcoZW0pO1xyXG5cclxuICBvciB3aXRoIGEgc3BlY2lmaWVkIFtbTWVyZ2VTdHJhdGVneV1dXHJcbiAgPiAgICAgIGxldCBlbSA9IG5ldyBFbnRpdHlNYW5hZ2VyKHNlcnZpY2VOYW1lKTtcclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiT3JkZXJzXCIpXHJcbiAgPiAgICAgICAgLnVzaW5nKE1lcmdlU3RyYXRlZ3kuUHJlc2VydmVDaGFuZ2VzKTtcclxuXHJcbiAgb3Igd2l0aCBhIHNwZWNpZmllZCBbW0ZldGNoU3RyYXRlZ3ldXVxyXG4gID4gICAgICBsZXQgZW0gPSBuZXcgRW50aXR5TWFuYWdlcihzZXJ2aWNlTmFtZSk7XHJcbiAgPiAgICAgIGxldCBxdWVyeSA9IG5ldyBFbnRpdHlRdWVyeShcIk9yZGVyc1wiKVxyXG4gID4gICAgICAgIC51c2luZyhGZXRjaFN0cmF0ZWd5LkZyb21Mb2NhbENhY2hlKTtcclxuICBAcGFyYW0gb2JqIC0gVGhlIG9iamVjdCB0byB1cGRhdGUgaW4gY3JlYXRpbmcgYSBuZXcgRW50aXR5UXVlcnkgZnJvbSBhbiBleGlzdGluZyBvbmUuXHJcbiAgKiovXHJcbiAgdXNpbmcob2JqOiBhbnkpIHtcclxuICAgIGlmICghb2JqKSByZXR1cm4gdGhpcztcclxuICAgIGxldCBlcSA9IGNsb25lKHRoaXMpO1xyXG4gICAgcHJvY2Vzc1VzaW5nKGVxLCB7XHJcbiAgICAgIFwiZW50aXR5TWFuYWdlclwiOiBudWxsLFxyXG4gICAgICBcImRhdGFTZXJ2aWNlXCI6IG51bGwsXHJcbiAgICAgIFwicXVlcnlPcHRpb25zXCI6IG51bGwsXHJcbiAgICAgIFwiZmV0Y2hTdHJhdGVneVwiOiAoZXE6IEVudGl0eVF1ZXJ5LCB2YWw6IGFueSkgPT4ge1xyXG4gICAgICAgIGVxLnF1ZXJ5T3B0aW9ucyA9IChlcS5xdWVyeU9wdGlvbnMgfHwgbmV3IFF1ZXJ5T3B0aW9ucygpKS51c2luZyh2YWwpO1xyXG4gICAgICB9LFxyXG4gICAgICBcIm1lcmdlU3RyYXRlZ3lcIjogKGVxOiBFbnRpdHlRdWVyeSwgdmFsOiBhbnkpID0+IHtcclxuICAgICAgICBlcS5xdWVyeU9wdGlvbnMgPSAoZXEucXVlcnlPcHRpb25zIHx8IG5ldyBRdWVyeU9wdGlvbnMoKSkudXNpbmcodmFsKTtcclxuICAgICAgfSxcclxuICAgICAgXCJqc29uUmVzdWx0c0FkYXB0ZXJcIjogKGVxOiBFbnRpdHlRdWVyeSwgdmFsOiBhbnkpID0+IHtcclxuICAgICAgICBlcS5kYXRhU2VydmljZSA9IChlcS5kYXRhU2VydmljZSB8fCBuZXcgRGF0YVNlcnZpY2UoKSkudXNpbmcoeyBqc29uUmVzdWx0c0FkYXB0ZXI6IHZhbCB9KTtcclxuICAgICAgfVxyXG4gICAgfSwgb2JqKTtcclxuICAgIHJldHVybiBlcTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIEV4ZWN1dGVzIHRoaXMgcXVlcnkuICBUaGlzIG1ldGhvZCByZXF1aXJlcyB0aGF0IGFuIEVudGl0eU1hbmFnZXIgaGFzIGJlZW4gcHJldmlvdXNseSBzcGVjaWZpZWQgdmlhIHRoZSBcInVzaW5nXCIgbWV0aG9kLlxyXG4gIFxyXG4gIFRoaXMgbWV0aG9kIGNhbiBiZSBjYWxsZWQgdXNpbmcgYSAncHJvbWlzZXMnIHN5bnRheCAoIHJlY29tbWVuZGVkKVxyXG4gID4gICAgICBsZXQgZW0gPSBuZXcgRW50aXR5TWFuYWdlcihzZXJ2aWNlTmFtZSk7XHJcbiAgPiAgICAgIGxldCBxdWVyeSA9IG5ldyBFbnRpdHlRdWVyeShcIk9yZGVyc1wiKS51c2luZyhlbSk7XHJcbiAgPiAgICAgIHF1ZXJ5LmV4ZWN1dGUoKS50aGVuKCBmdW5jdGlvbihkYXRhKSB7XHJcbiAgPiAgICAgICAgICAuLi4gcXVlcnkgcmVzdWx0cyBwcm9jZXNzZWQgaGVyZVxyXG4gID4gICAgICB9KS5jYXRjaCggZnVuY3Rpb24oZXJyKSB7XHJcbiAgPiAgICAgICAgICAuLi4gcXVlcnkgZmFpbHVyZSBwcm9jZXNzZWQgaGVyZVxyXG4gID4gICAgICB9KTtcclxuXHJcbiAgb3Igd2l0aCBjYWxsYmFja3NcclxuICA+ICAgICAgbGV0IGVtID0gbmV3IEVudGl0eU1hbmFnZXIoc2VydmljZU5hbWUpO1xyXG4gID4gICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJPcmRlcnNcIikudXNpbmcoZW0pO1xyXG4gID4gICAgICBxdWVyeS5leGVjdXRlKFxyXG4gID4gICAgICAgIGZ1bmN0aW9uKGRhdGEpIHtcclxuICA+ICAgICAgICAgICAgICAgICAgICBsZXQgb3JkZXJzID0gZGF0YS5yZXN1bHRzO1xyXG4gID4gICAgICAgICAgICAgICAgICAgIC4uLiBxdWVyeSByZXN1bHRzIHByb2Nlc3NlZCBoZXJlXHJcbiAgPiAgICAgICAgICAgICAgICB9LFxyXG4gID4gICAgICAgIGZ1bmN0aW9uKGVycikge1xyXG4gID4gICAgICAgICAgICAgICAgICAgIC4uLiBxdWVyeSBmYWlsdXJlIHByb2Nlc3NlZCBoZXJlXHJcbiAgPiAgICAgICAgICAgICAgICB9KTtcclxuXHJcbiAgRWl0aGVyIHdheSB0aGlzIG1ldGhvZCBpcyB0aGUgc2FtZSBhcyBjYWxsaW5nIHRoZSBFbnRpdHlNYW5hZ2VyICdleGVjdXRlJyBtZXRob2QuXHJcbiAgPiAgICAgIGxldCBlbSA9IG5ldyBFbnRpdHlNYW5hZ2VyKHNlcnZpY2VOYW1lKTtcclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiT3JkZXJzXCIpO1xyXG4gID4gICAgICBlbS5leGVjdXRlUXVlcnkocXVlcnkpLnRoZW4oIGZ1bmN0aW9uKGRhdGEpIHtcclxuICA+ICAgICAgICAgbGV0IG9yZGVycyA9IGRhdGEucmVzdWx0cztcclxuICA+ICAgICAgICAgIC4uLiBxdWVyeSByZXN1bHRzIHByb2Nlc3NlZCBoZXJlXHJcbiAgPiAgICAgIH0pLmNhdGNoKCBmdW5jdGlvbihlcnIpIHtcclxuICA+ICAgICAgICAgLi4uIHF1ZXJ5IGZhaWx1cmUgcHJvY2Vzc2VkIGhlcmVcclxuICA+ICAgICAgfSk7XHJcblxyXG4gIEBwYXJhbSBjYWxsYmFjayAtICBGdW5jdGlvbiBjYWxsZWQgb24gc3VjY2Vzcy5cclxuICBAcGFyYW0gZXJyb3JDYWxsYmFjayAtIEZ1bmN0aW9uIGNhbGxlZCBvbiBmYWlsdXJlLlxyXG4gIEByZXR1cm4gUHJvbWlzZVxyXG4gICoqL1xyXG4gIGV4ZWN1dGUoY2FsbGJhY2s/OiBDYWxsYmFjaywgZXJyb3JDYWxsYmFjaz86IEVycm9yQ2FsbGJhY2spOiBQcm9taXNlPFF1ZXJ5UmVzdWx0PiB7XHJcbiAgICBpZiAoIXRoaXMuZW50aXR5TWFuYWdlcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJBbiBFbnRpdHlRdWVyeSBtdXN0IGhhdmUgaXRzIEVudGl0eU1hbmFnZXIgcHJvcGVydHkgc2V0IGJlZm9yZSBjYWxsaW5nICdleGVjdXRlJ1wiKTtcclxuICAgIH1cclxuICAgIHJldHVybiB0aGlzLmVudGl0eU1hbmFnZXIuZXhlY3V0ZVF1ZXJ5KHRoaXMsIGNhbGxiYWNrLCBlcnJvckNhbGxiYWNrKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIEV4ZWN1dGVzIHRoaXMgcXVlcnkgYWdhaW5zdCB0aGUgbG9jYWwgY2FjaGUuICBUaGlzIG1ldGhvZCByZXF1aXJlcyB0aGF0IGFuIEVudGl0eU1hbmFnZXIgaGF2ZSBiZWVuIHByZXZpb3VzbHkgc3BlY2lmaWVkIHZpYSB0aGUgXCJ1c2luZ1wiIG1ldGhvZC5cclxuICA+ICAgICAgLy8gYXNzdW1lIGVtIGlzIGFuIGVudGl0eU1hbmFnZXIgYWxyZWFkeSBmaWxsZWQgd2l0aCBvcmRlciBlbnRpdGllcztcclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiT3JkZXJzXCIpLnVzaW5nKGVtKTtcclxuICA+ICAgICAgbGV0IG9yZGVycyA9IHF1ZXJ5LmV4ZWN1dGVMb2NhbGx5KCk7XHJcblxyXG4gIE5vdGUgdGhhdCBjYWxsaW5nIHRoaXMgbWV0aG9kIGlzIHRoZSBzYW1lIGFzIGNhbGxpbmcgW1tFbnRpdHlNYW5hZ2VyLmV4ZWN1dGVRdWVyeUxvY2FsbHldXS5cclxuICAqKi9cclxuICBleGVjdXRlTG9jYWxseSgpIHtcclxuICAgIGlmICghdGhpcy5lbnRpdHlNYW5hZ2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkFuIEVudGl0eVF1ZXJ5IG11c3QgaGF2ZSBpdHMgRW50aXR5TWFuYWdlciBwcm9wZXJ0eSBzZXQgYmVmb3JlIGNhbGxpbmcgJ2V4ZWN1dGVMb2NhbGx5J1wiKTtcclxuICAgIH1cclxuICAgIHJldHVybiB0aGlzLmVudGl0eU1hbmFnZXIuZXhlY3V0ZVF1ZXJ5TG9jYWxseSh0aGlzKTtcclxuICB9XHJcblxyXG4gIHRvSlNPTigpIHtcclxuICAgIHJldHVybiB0aGlzLnRvSlNPTkV4dCgpO1xyXG4gIH1cclxuXHJcbiAgLyoqIFR5cGljYWxseSBvbmx5IGZvciB1c2Ugd2hlbiBidWlsZGluZyBVcmlCdWlsZGVyQWRhcHRlcnMuICBcclxuICBAaGlkZGVuIEBpbnRlcm5hbCAgXHJcbiAgKi9cclxuICB0b0pTT05FeHQoY29udGV4dD86IEVudGl0eVF1ZXJ5SnNvbkNvbnRleHQpIHtcclxuICAgIGNvbnRleHQgPSBjb250ZXh0IHx8IHt9O1xyXG4gICAgY29udGV4dC5lbnRpdHlUeXBlID0gY29udGV4dC5lbnRpdHlUeXBlIHx8IHRoaXMuZnJvbUVudGl0eVR5cGU7XHJcbiAgICBjb250ZXh0LnByb3BlcnR5UGF0aEZuID0gY29udGV4dC50b05hbWVPblNlcnZlciA/IGNvbnRleHQuZW50aXR5VHlwZSEuY2xpZW50UHJvcGVydHlQYXRoVG9TZXJ2ZXIuYmluZChjb250ZXh0LmVudGl0eVR5cGUpIDogY29yZS5pZGVudGl0eTtcclxuXHJcbiAgICBsZXQgdG9KU09ORXh0Rm4gPSBmdW5jdGlvbiAodjogYW55KSB7XHJcbiAgICAgIHJldHVybiB2ID8gdi50b0pTT05FeHQoY29udGV4dCkgOiB1bmRlZmluZWQ7XHJcbiAgICB9O1xyXG4gICAgcmV0dXJuIGNvcmUudG9Kc29uKHRoaXMsIHtcclxuICAgICAgXCJmcm9tLHJlc291cmNlTmFtZVwiOiBudWxsLFxyXG4gICAgICBcInRvVHlwZSxyZXN1bHRFbnRpdHlUeXBlXCI6IGZ1bmN0aW9uICh2OiBhbnkpIHtcclxuICAgICAgICAvLyByZXN1bHRFbnRpdHlUeXBlIGNhbiBiZSBlaXRoZXIgYSBzdHJpbmcgb3IgYW4gZW50aXR5VHlwZVxyXG4gICAgICAgIHJldHVybiB2ID8gKHR5cGVvZiB2ID09PSAnc3RyaW5nJyA/IHYgOiB2Lm5hbWUpIDogdW5kZWZpbmVkO1xyXG4gICAgICB9LFxyXG4gICAgICBcIndoZXJlLHdoZXJlUHJlZGljYXRlXCI6IHRvSlNPTkV4dEZuLFxyXG4gICAgICBcIm9yZGVyQnksb3JkZXJCeUNsYXVzZVwiOiB0b0pTT05FeHRGbixcclxuICAgICAgXCJzZWxlY3Qsc2VsZWN0Q2xhdXNlXCI6IHRvSlNPTkV4dEZuLFxyXG4gICAgICBcImV4cGFuZCxleHBhbmRDbGF1c2VcIjogdG9KU09ORXh0Rm4sXHJcbiAgICAgIFwic2tpcCxza2lwQ291bnRcIjogbnVsbCxcclxuICAgICAgXCJ0YWtlLHRha2VDb3VudFwiOiBudWxsLFxyXG4gICAgICBwYXJhbWV0ZXJzOiBmdW5jdGlvbiAodjogYW55KSB7XHJcbiAgICAgICAgcmV0dXJuIGNvcmUuaXNFbXB0eSh2KSA/IHVuZGVmaW5lZCA6IHY7XHJcbiAgICAgIH0sXHJcbiAgICAgIFwiaW5saW5lQ291bnQsaW5saW5lQ291bnRFbmFibGVkXCI6IGZhbHNlLFxyXG4gICAgICBcIm5vVHJhY2tpbmcsbm9UcmFja2luZ0VuYWJsZWRcIjogZmFsc2UsXHJcbiAgICAgIHF1ZXJ5T3B0aW9uczogbnVsbFxyXG4gICAgfSk7XHJcblxyXG4gIH1cclxuXHJcbiAgc3RhdGljIGZyb21FbnRpdGllcyhlbnRpdHk6IEVudGl0eSk6IEVudGl0eVF1ZXJ5O1xyXG4gIHN0YXRpYyBmcm9tRW50aXRpZXMoZW50aXRpZXM6IEVudGl0eVtdKTogRW50aXR5UXVlcnk7XHJcbiAgLyoqXHJcbiAgU3RhdGljIG1ldGhvZCB0aGF0IGNyZWF0ZXMgYW4gRW50aXR5UXVlcnkgdGhhdCB3aWxsIGFsbG93ICdyZXF1ZXJ5aW5nJyBhbiBlbnRpdHkgb3IgYSBjb2xsZWN0aW9uIG9mIGVudGl0aWVzIGJ5IHByaW1hcnkga2V5LiBUaGlzIGNhbiBiZSB1c2VmdWxcclxuICB0byBmb3JjZSBhIHJlcXVlcnkgb2Ygc2VsZWN0ZWQgZW50aXRpZXMsIG9yIHRvIHJlc3RyaWN0IGFuIGV4aXN0aW5nIGNvbGxlY3Rpb24gb2YgZW50aXRpZXMgYWNjb3JkaW5nIHRvIHNvbWUgZmlsdGVyLlxyXG5cclxuICBXb3JrcyBmb3IgYSBzaW5nbGUgZW50aXR5IG9yIGFuIGFycmF5IG9mIGVudGl0aWVzIG9mIHRoZSBTQU1FIHR5cGUuXHJcbiAgRG9lcyBub3Qgd29yayBmb3IgYW4gYXJyYXkgb2YgZW50aXRpZXMgb2YgZGlmZmVyZW50IHR5cGVzLlxyXG4gID4gICAgICAvLyBhc3N1bWluZyAnY3VzdG9tZXJzJyBpcyBhbiBhcnJheSBvZiAnQ3VzdG9tZXInIGVudGl0aWVzIHJldHJpZXZlZCBlYXJsaWVyLlxyXG4gID4gICAgICBsZXQgY3VzdG9tZXJzUXVlcnkgPSBFbnRpdHlRdWVyeS5mcm9tRW50aXRpZXMoY3VzdG9tZXJzKTtcclxuXHJcbiAgVGhlIHJlc3VsdGluZyBxdWVyeSBjYW4sIG9mIGNvdXJzZSwgYmUgZXh0ZW5kZWRcclxuICA+ICAgICAgLy8gYXNzdW1pbmcgJ2N1c3RvbWVycycgaXMgYW4gYXJyYXkgb2YgJ0N1c3RvbWVyJyBlbnRpdGllcyByZXRyaWV2ZWQgZWFybGllci5cclxuICA+ICAgICAgbGV0IGN1c3RvbWVyc1F1ZXJ5ID0gRW50aXR5UXVlcnkuZnJvbUVudGl0aWVzKGN1c3RvbWVycylcclxuICA+ICAgICAgICAud2hlcmUoXCJSZWdpb25cIiwgRmlsdGVyUXVlcnlPcC5Ob3RFcXVhbHMsIG51bGwpO1xyXG5cclxuICBTaW5nbGUgZW50aXRpZXMgY2FuIHJlcXVlcmllZCBhcyB3ZWxsLlxyXG4gID4gICAgICAvLyBhc3N1bWluZyAnY3VzdG9tZXInIGlzIGEgJ0N1c3RvbWVyJyBlbnRpdHkgcmV0cmlldmVkIGVhcmxpZXIuXHJcbiAgPiAgICAgIGxldCBjdXN0b21lclF1ZXJ5ID0gRW50aXR5UXVlcnkuZnJvbUVudGl0aWVzKGN1c3RvbWVyKTtcclxuXHJcbiAgd2lsbCBjcmVhdGUgYSBxdWVyeSB0aGF0IHdpbGwgcmV0dXJuIGFuIGFycmF5IGNvbnRhaW5pbmcgYSBzaW5nbGUgY3VzdG9tZXIgZW50aXR5LlxyXG4gIEBwYXJhbSBlbnRpdGllcyAtIFRoZSBlbnRpdGllcyBmb3Igd2hpY2ggd2Ugd2FudCB0byBjcmVhdGUgYW4gRW50aXR5UXVlcnkuXHJcbiAgKiovXHJcbiAgc3RhdGljIGZyb21FbnRpdGllcyhlbnRpdGllczogRW50aXR5IHwgRW50aXR5W10pIHtcclxuICAgIGFzc2VydFBhcmFtKGVudGl0aWVzLCBcImVudGl0aWVzXCIpLmlzRW50aXR5KCkub3IoKS5pc05vbkVtcHR5QXJyYXkoKS5pc0VudGl0eSgpLmNoZWNrKCk7XHJcbiAgICBsZXQgZW50cyA9IChBcnJheS5pc0FycmF5KGVudGl0aWVzKSkgPyBlbnRpdGllcyA6IFtlbnRpdGllc107XHJcblxyXG4gICAgbGV0IGZpcnN0RW50aXR5ID0gZW50c1swXTtcclxuICAgIGxldCB0eXBlID0gZmlyc3RFbnRpdHkuZW50aXR5VHlwZTtcclxuICAgIGlmIChlbnRzLnNvbWUoZnVuY3Rpb24gKGUpIHtcclxuICAgICAgcmV0dXJuIGUuZW50aXR5VHlwZSAhPT0gdHlwZTtcclxuICAgIH0pKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkFsbCAnZnJvbUVudGl0aWVzJyBtdXN0IGJlIHRoZSBzYW1lIHR5cGU7IGF0IGxlYXN0IG9uZSBpcyBub3Qgb2YgdHlwZSBcIiArXHJcbiAgICAgICAgdHlwZS5uYW1lKTtcclxuICAgIH1cclxuICAgIGxldCBxID0gbmV3IEVudGl0eVF1ZXJ5KHR5cGUuZGVmYXVsdFJlc291cmNlTmFtZSk7XHJcbiAgICBsZXQgcHJlZHMgPSBlbnRzLm1hcChmdW5jdGlvbiAoZW50aXR5KSB7XHJcbiAgICAgIHJldHVybiBidWlsZFByZWRpY2F0ZShlbnRpdHkpO1xyXG4gICAgfSk7XHJcbiAgICBsZXQgcHJlZCA9IFByZWRpY2F0ZS5vcihwcmVkcyk7XHJcbiAgICBxID0gcS53aGVyZShwcmVkKTtcclxuICAgIGxldCBlbSA9IGZpcnN0RW50aXR5LmVudGl0eUFzcGVjdC5lbnRpdHlNYW5hZ2VyO1xyXG4gICAgaWYgKGVtKSB7XHJcbiAgICAgIHEgPSBxLnVzaW5nKGVtKTtcclxuICAgIH1cclxuICAgIHJldHVybiBxO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgQ3JlYXRlcyBhbiBFbnRpdHlRdWVyeSBmb3IgdGhlIHNwZWNpZmllZCBbW0VudGl0eUtleV1dLlxyXG4gID4gICAgICBsZXQgZW1wVHlwZSA9IG1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZShcIkVtcGxveWVlXCIpO1xyXG4gID4gICAgICBsZXQgZW50aXR5S2V5ID0gbmV3IEVudGl0eUtleShlbXBUeXBlLCAxKTtcclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gRW50aXR5UXVlcnkuZnJvbUVudGl0eUtleShlbnRpdHlLZXkpO1xyXG5cclxuICBvclxyXG4gID4gICAgICAvLyAnZW1wbG95ZWUnIGlzIGEgcHJldmlvdXNseSBxdWVyaWVkIGVtcGxveWVlXHJcbiAgPiAgICAgIGxldCBlbnRpdHlLZXkgPSBlbXBsb3llZS5lbnRpdHlBc3BlY3QuZ2V0S2V5KCk7XHJcbiAgPiAgICAgIGxldCBxdWVyeSA9IEVudGl0eVF1ZXJ5LmZyb21FbnRpdHlLZXkoZW50aXR5S2V5KTtcclxuICBAcGFyYW0gZW50aXR5S2V5IC0gVGhlIFtbRW50aXR5S2V5XV0gZm9yIHdoaWNoIGEgcXVlcnkgd2lsbCBiZSBjcmVhdGVkLlxyXG4gICoqL1xyXG4gIHN0YXRpYyBmcm9tRW50aXR5S2V5KGVudGl0eUtleTogRW50aXR5S2V5KSB7XHJcbiAgICBhc3NlcnRQYXJhbShlbnRpdHlLZXksIFwiZW50aXR5S2V5XCIpLmlzSW5zdGFuY2VPZihFbnRpdHlLZXkpLmNoZWNrKCk7XHJcbiAgICBsZXQgcSA9IG5ldyBFbnRpdHlRdWVyeShlbnRpdHlLZXkuZW50aXR5VHlwZS5kZWZhdWx0UmVzb3VyY2VOYW1lKTtcclxuICAgIGxldCBwcmVkID0gYnVpbGRLZXlQcmVkaWNhdGUoZW50aXR5S2V5KTtcclxuICAgIHEgPSBxLndoZXJlKHByZWQpLnRvVHlwZShlbnRpdHlLZXkuZW50aXR5VHlwZSk7XHJcbiAgICByZXR1cm4gcTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIENyZWF0ZXMgYW4gRW50aXR5UXVlcnkgZm9yIHRoZSBzcGVjaWZpZWQgZW50aXR5IGFuZCBbW05hdmlnYXRpb25Qcm9wZXJ0eV1dLlxyXG4gID4gICAgICAvLyAnZW1wbG95ZWUnIGlzIGEgcHJldmlvdXNseSBxdWVyaWVkIGVtcGxveWVlXHJcbiAgPiAgICAgIGxldCBvcmRlcnNOYXZQcm9wID0gZW1wbG95ZWUuZW50aXR5VHlwZS5nZXRQcm9wZXJ0eShcIk9yZGVyc1wiKTtcclxuICA+ICAgICAgbGV0IHF1ZXJ5ID0gRW50aXR5UXVlcnkuZnJvbUVudGl0eU5hdmlnYXRpb24oZW1wbG95ZWUsIG9yZGVyc05hdlByb3ApO1xyXG5cclxuICB3aWxsIHJldHVybiBhIHF1ZXJ5IGZvciB0aGUgXCJPcmRlcnNcIiBvZiB0aGUgc3BlY2lmaWVkICdlbXBsb3llZScuXHJcbiAgQHBhcmFtIGVudGl0eSAtIFRoZSBFbnRpdHkgd2hvc2UgbmF2aWdhdGlvbiBwcm9wZXJ0eSB3aWxsIGJlIHF1ZXJpZWQuXHJcbiAgQHBhcmFtIG5hdmlnYXRpb25Qcm9wZXJ0eSAtIFRoZSBbW05hdmlnYXRpb25Qcm9wZXJ0eV1dIG9yIG5hbWUgb2YgdGhlIE5hdmlnYXRpb25Qcm9wZXJ0eSB0byBiZSBxdWVyaWVkLlxyXG4gICoqL1xyXG4gIHN0YXRpYyBmcm9tRW50aXR5TmF2aWdhdGlvbiA9IGZ1bmN0aW9uIChlbnRpdHk6IEVudGl0eSwgbmF2aWdhdGlvblByb3BlcnR5OiBOYXZpZ2F0aW9uUHJvcGVydHkgfCBzdHJpbmcpIHtcclxuICAgIGFzc2VydFBhcmFtKGVudGl0eSwgXCJlbnRpdHlcIikuaXNFbnRpdHkoKS5jaGVjaygpO1xyXG4gICAgbGV0IG5hdlByb3BlcnR5ID0gZW50aXR5LmVudGl0eVR5cGUuX2NoZWNrTmF2UHJvcGVydHkobmF2aWdhdGlvblByb3BlcnR5KTtcclxuICAgIGxldCBxID0gbmV3IEVudGl0eVF1ZXJ5KG5hdlByb3BlcnR5LmVudGl0eVR5cGUuZGVmYXVsdFJlc291cmNlTmFtZSk7XHJcbiAgICBsZXQgcHJlZCA9IGJ1aWxkTmF2aWdhdGlvblByZWRpY2F0ZShlbnRpdHksIG5hdlByb3BlcnR5KTtcclxuICAgIGlmIChwcmVkID09IG51bGwpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVW5hYmxlIHRvIGNyZWF0ZSBhIE5hdmlnYXRpb25RdWVyeSBmb3IgbmF2aWdhdGlvblByb3BlcnR5OiBcIiArIG5hdlByb3BlcnR5Lm5hbWUgKTtcclxuICAgIH1cclxuICAgIHEgPSBxLndoZXJlKHByZWQpO1xyXG4gICAgbGV0IGVtID0gZW50aXR5LmVudGl0eUFzcGVjdC5lbnRpdHlNYW5hZ2VyO1xyXG4gICAgcmV0dXJuIGVtID8gcS51c2luZyhlbSkgOiBxO1xyXG4gIH07XHJcblxyXG4gIC8vIHByb3RlY3RlZCBtZXRob2RzXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2dldEZyb21FbnRpdHlUeXBlKG1ldGFkYXRhU3RvcmU6IE1ldGFkYXRhU3RvcmUsIHRocm93RXJyb3JJZk5vdEZvdW5kPzogYm9vbGVhbikge1xyXG4gICAgLy8gVW5jb21tZW50IG5leHQgdHdvIGxpbmVzIGlmIHdlIG1ha2UgdGhpcyBtZXRob2QgcHVibGljLlxyXG4gICAgLy8gYXNzZXJ0UGFyYW0obWV0YWRhdGFTdG9yZSwgXCJtZXRhZGF0YVN0b3JlXCIpLmlzSW5zdGFuY2VPZihNZXRhZGF0YVN0b3JlKS5jaGVjaygpO1xyXG4gICAgLy8gYXNzZXJ0UGFyYW0odGhyb3dFcnJvcklmTm90Rm91bmQsIFwidGhyb3dFcnJvcklmTm90Rm91bmRcIikuaXNCb29sZWFuKCkuaXNPcHRpb25hbCgpLmNoZWNrKCk7XHJcbiAgICBsZXQgZW50aXR5VHlwZSA9IHRoaXMuZnJvbUVudGl0eVR5cGU7XHJcbiAgICBpZiAoZW50aXR5VHlwZSkgcmV0dXJuIGVudGl0eVR5cGU7XHJcblxyXG4gICAgbGV0IHJlc291cmNlTmFtZSA9IHRoaXMucmVzb3VyY2VOYW1lO1xyXG4gICAgaWYgKCFyZXNvdXJjZU5hbWUpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGhlcmUgaXMgbm8gcmVzb3VyY2VOYW1lIGZvciB0aGlzIHF1ZXJ5XCIpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChtZXRhZGF0YVN0b3JlLmlzRW1wdHkoKSkge1xyXG4gICAgICBpZiAodGhyb3dFcnJvcklmTm90Rm91bmQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUaGVyZSBpcyBubyBtZXRhZGF0YSBhdmFpbGFibGUgZm9yIHRoaXMgcXVlcnkuIFwiICtcclxuICAgICAgICAgIFwiQXJlIHlvdSBxdWVyeWluZyB0aGUgbG9jYWwgY2FjaGUgYmVmb3JlIHlvdSd2ZSBmZXRjaGVkIG1ldGFkYXRhP1wiKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IGVudGl0eVR5cGVOYW1lID0gbWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlTmFtZUZvclJlc291cmNlTmFtZShyZXNvdXJjZU5hbWUpO1xyXG4gICAgaWYgKGVudGl0eVR5cGVOYW1lKSB7XHJcbiAgICAgIGVudGl0eVR5cGUgPSBtZXRhZGF0YVN0b3JlLl9nZXRTdHJ1Y3R1cmFsVHlwZShlbnRpdHlUeXBlTmFtZSkgYXMgRW50aXR5VHlwZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGVudGl0eVR5cGUgPSB0aGlzLl9nZXRUb0VudGl0eVR5cGUobWV0YWRhdGFTdG9yZSwgdHJ1ZSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFlbnRpdHlUeXBlKSB7XHJcbiAgICAgIGlmICh0aHJvd0Vycm9ySWZOb3RGb3VuZCkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihjb3JlLmZvcm1hdFN0cmluZyhcIkNhbm5vdCBmaW5kIGFuIGVudGl0eVR5cGUgZm9yIHJlc291cmNlTmFtZTogJyUxJy4gXCIsIHJlc291cmNlTmFtZSkgKyBjb3JlLnN0cmluZ3MuVE9fVFlQRSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuZnJvbUVudGl0eVR5cGUgPSBlbnRpdHlUeXBlO1xyXG4gICAgcmV0dXJuIGVudGl0eVR5cGU7XHJcblxyXG4gIH1cclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2dldFRvRW50aXR5VHlwZShtZXRhZGF0YVN0b3JlOiBNZXRhZGF0YVN0b3JlLCBza2lwRnJvbUNoZWNrPzogYm9vbGVhbik6IEVudGl0eVR5cGUgfCB1bmRlZmluZWQge1xyXG4gICAgLy8gc2tpcEZyb21DaGVjayBpcyB0byBhdm9pZCByZWN1cnNpb24gaWYgY2FsbGVkIGZyb20gX2dldEZyb21FbnRpdHlUeXBlO1xyXG4gICAgaWYgKHRoaXMucmVzdWx0RW50aXR5VHlwZSBpbnN0YW5jZW9mIEVudGl0eVR5cGUpIHtcclxuICAgICAgcmV0dXJuIHRoaXMucmVzdWx0RW50aXR5VHlwZTtcclxuICAgIH0gZWxzZSBpZiAodGhpcy5yZXN1bHRFbnRpdHlUeXBlKSB7XHJcbiAgICAgIC8vIHJlc3VsdEVudGl0eVR5cGUgaXMgYSBzdHJpbmdcclxuICAgICAgdGhpcy5yZXN1bHRFbnRpdHlUeXBlID0gbWV0YWRhdGFTdG9yZS5fZ2V0U3RydWN0dXJhbFR5cGUodGhpcy5yZXN1bHRFbnRpdHlUeXBlLCBmYWxzZSkgYXMgRW50aXR5VHlwZTtcclxuICAgICAgcmV0dXJuIHRoaXMucmVzdWx0RW50aXR5VHlwZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIHJlc29sdmUgaXQsIGlmIHBvc3NpYmxlLCB2aWEgdGhlIHJlc291cmNlTmFtZVxyXG4gICAgICAvLyBkbyBub3QgY2FjaGUgdGhpcyB2YWx1ZSBpbiB0aGlzIGNhc2VcclxuICAgICAgLy8gY2Fubm90IGRldGVybWluZSB0aGUgcmVzdWx0RW50aXR5VHlwZSBpZiBhIHNlbGVjdENsYXVzZSBpcyBwcmVzZW50LlxyXG4gICAgICAvLyByZXR1cm4gc2tpcEZyb21DaGVjayA/IG51bGwgOiAoIXRoaXMuc2VsZWN0Q2xhdXNlKSAmJiB0aGlzLl9nZXRGcm9tRW50aXR5VHlwZShtZXRhZGF0YVN0b3JlLCBmYWxzZSk7XHJcbiAgICAgIGlmIChza2lwRnJvbUNoZWNrIHx8IHRoaXMuc2VsZWN0Q2xhdXNlKSB7XHJcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLl9nZXRGcm9tRW50aXR5VHlwZShtZXRhZGF0YVN0b3JlLCBmYWxzZSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICAvLyBmb3IgdGVzdGluZ1xyXG4gIF90b1VyaShlbTogRW50aXR5TWFuYWdlcikge1xyXG4gICAgbGV0IGRzID0gRGF0YVNlcnZpY2UucmVzb2x2ZShbZW0uZGF0YVNlcnZpY2VdKTtcclxuICAgIHJldHVybiBkcyEudXJpQnVpbGRlciEuYnVpbGRVcmkodGhpcywgZW0ubWV0YWRhdGFTdG9yZSk7XHJcbiAgfVxyXG5cclxufVxyXG5FbnRpdHlRdWVyeS5wcm90b3R5cGUuXyR0eXBlTmFtZSA9IFwiRW50aXR5UXVlcnlcIjtcclxuXHJcbi8vIHByaXZhdGUgZnVuY3Rpb25zXHJcblxyXG5mdW5jdGlvbiBmcm9tSlNPTihlcTogRW50aXR5UXVlcnksIGpzb246IE9iamVjdCkge1xyXG4gIGNvcmUudG9Kc29uKGpzb24sIHtcclxuICAgIFwicmVzb3VyY2VOYW1lLGZyb21cIjogbnVsbCxcclxuICAgIC8vIGp1c3QgdGhlIG5hbWUgY29tZXMgYmFjayBhbmQgd2lsbCBiZSByZXNvbHZlZCBsYXRlclxyXG4gICAgXCJyZXN1bHRFbnRpdHlUeXBlLHRvVHlwZVwiOiBudWxsLFxyXG4gICAgXCJ3aGVyZVByZWRpY2F0ZSx3aGVyZVwiOiBmdW5jdGlvbiAodjogYW55KSB7XHJcbiAgICAgIHJldHVybiB2ID8gbmV3IFByZWRpY2F0ZSh2KSA6IHVuZGVmaW5lZDtcclxuICAgIH0sXHJcbiAgICBcIm9yZGVyQnlDbGF1c2Usb3JkZXJCeVwiOiBmdW5jdGlvbiAodjogYW55KSB7XHJcbiAgICAgIHJldHVybiB2ID8gbmV3IE9yZGVyQnlDbGF1c2UodikgOiB1bmRlZmluZWQ7XHJcbiAgICB9LFxyXG4gICAgXCJzZWxlY3RDbGF1c2Usc2VsZWN0XCI6IGZ1bmN0aW9uICh2OiBhbnkpIHtcclxuICAgICAgcmV0dXJuIHYgPyBuZXcgU2VsZWN0Q2xhdXNlKHYpIDogdW5kZWZpbmVkO1xyXG4gICAgfSxcclxuICAgIFwiZXhwYW5kQ2xhdXNlLGV4cGFuZFwiOiBmdW5jdGlvbiAodjogYW55KSB7XHJcbiAgICAgIHJldHVybiB2ID8gbmV3IEV4cGFuZENsYXVzZSh2KSA6IHVuZGVmaW5lZDtcclxuICAgIH0sXHJcbiAgICBcInNraXBDb3VudCxza2lwXCI6IG51bGwsXHJcbiAgICBcInRha2VDb3VudCx0YWtlXCI6IG51bGwsXHJcbiAgICBwYXJhbWV0ZXJzOiBmdW5jdGlvbiAodjogYW55KSB7XHJcbiAgICAgIHJldHVybiBjb3JlLmlzRW1wdHkodikgPyB1bmRlZmluZWQgOiB2O1xyXG4gICAgfSxcclxuICAgIFwiaW5saW5lQ291bnRFbmFibGVkLGlubGluZUNvdW50XCI6IGZhbHNlLFxyXG4gICAgXCJub1RyYWNraW5nRW5hYmxlZCxub1RyYWNraW5nXCI6IGZhbHNlLFxyXG4gICAgcXVlcnlPcHRpb25zOiBmdW5jdGlvbiAodjogYW55KSB7XHJcbiAgICAgIHJldHVybiB2ID8gUXVlcnlPcHRpb25zLmZyb21KU09OKHYpIDogdW5kZWZpbmVkO1xyXG4gICAgfVxyXG4gIH0sIGVxKTtcclxuICByZXR1cm4gZXE7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNsb25lKGVxOiBFbnRpdHlRdWVyeSwgcHJvcE5hbWU/OiBzdHJpbmcsIHZhbHVlPzogYW55KSB7XHJcbiAgLy8gaW1tdXRhYmxlIHF1ZXJpZXMgbWVhbiB0aGF0IHdlIGRvbid0IG5lZWQgdG8gY2xvbmUgaWYgbm8gY2hhbmdlIGluIHZhbHVlLlxyXG4gIGlmIChwcm9wTmFtZSkge1xyXG4gICAgaWYgKGVxW3Byb3BOYW1lXSA9PT0gdmFsdWUpIHJldHVybiBlcTtcclxuICB9XHJcbiAgLy8gY29weWluZyBRdWVyeU9wdGlvbnMgaXMgc2FmZSBiZWNhdXNlIHRoZXkgYXJlIGFyZSBpbW11dGFibGU7XHJcbiAgbGV0IGNvcHkgPSBjb3JlLmV4dGVuZChuZXcgRW50aXR5UXVlcnkoKSwgZXEsIFtcclxuICAgIFwicmVzb3VyY2VOYW1lXCIsXHJcbiAgICBcImZyb21FbnRpdHlUeXBlXCIsXHJcbiAgICBcIndoZXJlUHJlZGljYXRlXCIsXHJcbiAgICBcIm9yZGVyQnlDbGF1c2VcIixcclxuICAgIFwic2VsZWN0Q2xhdXNlXCIsXHJcbiAgICBcInNraXBDb3VudFwiLFxyXG4gICAgXCJ0YWtlQ291bnRcIixcclxuICAgIFwiZXhwYW5kQ2xhdXNlXCIsXHJcbiAgICBcImlubGluZUNvdW50RW5hYmxlZFwiLFxyXG4gICAgXCJub1RyYWNraW5nRW5hYmxlZFwiLFxyXG4gICAgXCJ1c2VzTmFtZU9uU2VydmVyXCIsXHJcbiAgICBcInF1ZXJ5T3B0aW9uc1wiLFxyXG4gICAgXCJlbnRpdHlNYW5hZ2VyXCIsXHJcbiAgICBcImRhdGFTZXJ2aWNlXCIsXHJcbiAgICBcInJlc3VsdEVudGl0eVR5cGVcIlxyXG4gIF0pIGFzIEVudGl0eVF1ZXJ5O1xyXG4gIGNvcHkucGFyYW1ldGVycyA9IGNvcmUuZXh0ZW5kKHt9LCBlcS5wYXJhbWV0ZXJzKTtcclxuICBpZiAocHJvcE5hbWUpIHtcclxuICAgIGNvcHlbcHJvcE5hbWVdID0gdmFsdWU7XHJcbiAgfVxyXG4gIHJldHVybiBjb3B5O1xyXG59XHJcblxyXG5mdW5jdGlvbiBwcm9jZXNzVXNpbmcoZXE6IEVudGl0eVF1ZXJ5LCBtYXA6IE9iamVjdCwgdmFsdWU6IGFueSwgcHJvcGVydHlOYW1lPzogc3RyaW5nKSB7XHJcbiAgbGV0IHR5cGVOYW1lID0gdmFsdWUuXyR0eXBlTmFtZSB8fCAoKHZhbHVlIGluc3RhbmNlb2YgQnJlZXplRW51bSkgJiYgKHZhbHVlLmNvbnN0cnVjdG9yIGFzIGFueSkubmFtZSk7XHJcbiAgbGV0IGtleSA9IHR5cGVOYW1lICYmIHR5cGVOYW1lLnN1YnN0cigwLCAxKS50b0xvd2VyQ2FzZSgpICsgdHlwZU5hbWUuc3Vic3RyKDEpO1xyXG4gIGlmIChwcm9wZXJ0eU5hbWUgJiYga2V5ICE9PSBwcm9wZXJ0eU5hbWUpIHtcclxuICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgdmFsdWUgZm9yIHByb3BlcnR5OiBcIiArIHByb3BlcnR5TmFtZSk7XHJcbiAgfVxyXG4gIGlmIChrZXkpIHtcclxuICAgIGxldCBmbiA9IG1hcFtrZXldO1xyXG4gICAgaWYgKGZuID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBjb25maWcgcHJvcGVydHk6IFwiICsga2V5KTtcclxuICAgIH0gZWxzZSBpZiAoZm4gPT09IG51bGwpIHtcclxuICAgICAgZXFba2V5XSA9IHZhbHVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgZm4oZXEsIHZhbHVlKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgY29yZS5vYmplY3RGb3JFYWNoKHZhbHVlLCAocHJvcE5hbWUsIHZhbCkgPT4ge1xyXG4gICAgICBwcm9jZXNzVXNpbmcoZXEsIG1hcCwgdmFsLCBwcm9wTmFtZSk7XHJcbiAgICB9KTtcclxuICB9XHJcbn1cclxuXHJcbmZ1bmN0aW9uIG5vcm1hbGl6ZVByb3BlcnR5UGF0aHMocHJvcGVydHlQYXRoczogc3RyaW5nIHwgc3RyaW5nW10pIHtcclxuICBhc3NlcnRQYXJhbShwcm9wZXJ0eVBhdGhzLCBcInByb3BlcnR5UGF0aHNcIikuaXNPcHRpb25hbCgpLmlzU3RyaW5nKCkub3IoKS5pc0FycmF5KCkuaXNTdHJpbmcoKS5jaGVjaygpO1xyXG4gIGlmICh0eXBlb2YgcHJvcGVydHlQYXRocyA9PT0gJ3N0cmluZycpIHtcclxuICAgIHByb3BlcnR5UGF0aHMgPSBwcm9wZXJ0eVBhdGhzLnNwbGl0KFwiLFwiKTtcclxuICB9XHJcblxyXG4gIHByb3BlcnR5UGF0aHMgPSBwcm9wZXJ0eVBhdGhzLm1hcChmdW5jdGlvbiAocHApIHtcclxuICAgIHJldHVybiBwcC50cmltKCk7XHJcbiAgfSk7XHJcbiAgcmV0dXJuIHByb3BlcnR5UGF0aHM7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGJ1aWxkUHJlZGljYXRlKGVudGl0eTogRW50aXR5KSB7XHJcbiAgbGV0IGVudGl0eVR5cGUgPSBlbnRpdHkuZW50aXR5VHlwZTtcclxuICBsZXQgcHJlZFBhcnRzID0gZW50aXR5VHlwZS5rZXlQcm9wZXJ0aWVzLm1hcChmdW5jdGlvbiAoa3ApIHtcclxuICAgIHJldHVybiBQcmVkaWNhdGUuY3JlYXRlKGtwLm5hbWUsIEZpbHRlclF1ZXJ5T3AuRXF1YWxzLCBlbnRpdHkuZ2V0UHJvcGVydHkoa3AubmFtZSkpO1xyXG4gIH0pO1xyXG4gIGxldCBwcmVkID0gUHJlZGljYXRlLmFuZChwcmVkUGFydHMpO1xyXG4gIHJldHVybiBwcmVkO1xyXG59XHJcblxyXG5mdW5jdGlvbiBidWlsZEtleVByZWRpY2F0ZShlbnRpdHlLZXk6IEVudGl0eUtleSkge1xyXG4gIGxldCBrZXlQcm9wcyA9IGVudGl0eUtleS5lbnRpdHlUeXBlLmtleVByb3BlcnRpZXM7XHJcbiAgbGV0IHByZWRzID0gY29yZS5hcnJheVppcChrZXlQcm9wcywgZW50aXR5S2V5LnZhbHVlcywgZnVuY3Rpb24gKGtwLCB2KSB7XHJcbiAgICByZXR1cm4gUHJlZGljYXRlLmNyZWF0ZShrcC5uYW1lLCBGaWx0ZXJRdWVyeU9wLkVxdWFscywgdik7XHJcbiAgfSk7XHJcbiAgbGV0IHByZWQgPSBQcmVkaWNhdGUuYW5kKHByZWRzKTtcclxuICByZXR1cm4gcHJlZDtcclxufVxyXG5cclxuZnVuY3Rpb24gYnVpbGROYXZpZ2F0aW9uUHJlZGljYXRlKGVudGl0eTogRW50aXR5LCBuYXZpZ2F0aW9uUHJvcGVydHk6IE5hdmlnYXRpb25Qcm9wZXJ0eSkge1xyXG4gIGlmIChuYXZpZ2F0aW9uUHJvcGVydHkuaXNTY2FsYXIpIHtcclxuICAgIGlmIChuYXZpZ2F0aW9uUHJvcGVydHkuZm9yZWlnbktleU5hbWVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIG51bGw7XHJcbiAgICBsZXQgcmVsYXRlZEtleVZhbHVlcyA9IG5hdmlnYXRpb25Qcm9wZXJ0eS5mb3JlaWduS2V5TmFtZXMubWFwKChma05hbWUpID0+IHtcclxuICAgICAgcmV0dXJuIGVudGl0eS5nZXRQcm9wZXJ0eShma05hbWUpO1xyXG4gICAgfSk7XHJcbiAgICBsZXQgZW50aXR5S2V5ID0gbmV3IEVudGl0eUtleShuYXZpZ2F0aW9uUHJvcGVydHkuZW50aXR5VHlwZSwgcmVsYXRlZEtleVZhbHVlcyk7XHJcbiAgICByZXR1cm4gYnVpbGRLZXlQcmVkaWNhdGUoZW50aXR5S2V5KTtcclxuICB9IGVsc2Uge1xyXG4gICAgbGV0IGludmVyc2VOcCA9IG5hdmlnYXRpb25Qcm9wZXJ0eS5pbnZlcnNlO1xyXG4gICAgbGV0IGZvcmVpZ25LZXlOYW1lcyA9IGludmVyc2VOcCA/IGludmVyc2VOcC5mb3JlaWduS2V5TmFtZXMgOiBuYXZpZ2F0aW9uUHJvcGVydHkuaW52Rm9yZWlnbktleU5hbWVzO1xyXG4gICAgaWYgKGZvcmVpZ25LZXlOYW1lcy5sZW5ndGggPT09IDApIHJldHVybiBudWxsO1xyXG4gICAgbGV0IGtleVZhbHVlcyA9IGVudGl0eS5lbnRpdHlBc3BlY3QuZ2V0S2V5KCkudmFsdWVzO1xyXG4gICAgbGV0IHByZWRQYXJ0cyA9IGNvcmUuYXJyYXlaaXAoZm9yZWlnbktleU5hbWVzLCBrZXlWYWx1ZXMsIChma05hbWUsIGt2KSA9PiB7XHJcbiAgICAgIHJldHVybiBQcmVkaWNhdGUuY3JlYXRlKGZrTmFtZSwgRmlsdGVyUXVlcnlPcC5FcXVhbHMsIGt2KTtcclxuICAgIH0pO1xyXG4gICAgcmV0dXJuIFByZWRpY2F0ZS5hbmQocHJlZFBhcnRzKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKiBCYXNlIGNsYXNzIGZvciBCb29sZWFuUXVlcnlPcCBhbmQgRmlsdGVyUXVlcnlPcCAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIFF1ZXJ5T3Age1xyXG4gIC8qKiBUaGUgb3BlcmF0b3IgZm9yIHRoaXMgZW51bS4gKi9cclxuICBvcGVyYXRvcjogc3RyaW5nO1xyXG59XHJcblxyXG5cclxuXHJcbi8qKlxyXG5GaWx0ZXJRdWVyeU9wIGlzIGFuICdFbnVtJyBjb250YWluaW5nIGFsbCBvZiB0aGUgdmFsaWQgIFtbUHJlZGljYXRlXV1cclxuZmlsdGVyIG9wZXJhdG9ycyBmb3IgYW4gW1tFbnRpdHlRdWVyeV1dLlxyXG4qKi9cclxuZXhwb3J0IGNsYXNzIEZpbHRlclF1ZXJ5T3AgZXh0ZW5kcyBCcmVlemVFbnVtIGltcGxlbWVudHMgUXVlcnlPcCB7XHJcbiAgLyoqIFRoZSBvcGVyYXRvciBmb3IgdGhpcyBlbnVtLiAqL1xyXG4gIG9wZXJhdG9yOiBzdHJpbmc7XHJcblxyXG4gIC8qKiBBbGlhc2VzOiBcImVxXCIsIFwiPT1cIiAqKi9cclxuICBzdGF0aWMgRXF1YWxzID0gbmV3IEZpbHRlclF1ZXJ5T3AoeyBvcGVyYXRvcjogXCJlcVwiIH0pO1xyXG4gIC8qKiAgQWxpYXNlczogXCJuZVwiLCBcIiE9XCIgICoqL1xyXG4gIHN0YXRpYyBOb3RFcXVhbHMgPSBuZXcgRmlsdGVyUXVlcnlPcCh7IG9wZXJhdG9yOiBcIm5lXCIgfSk7XHJcbiAgLyoqIEFsaWFzZXM6IFwiZ3RcIiwgXCI+XCIgICAqKi9cclxuICBzdGF0aWMgR3JlYXRlclRoYW4gPSBuZXcgRmlsdGVyUXVlcnlPcCh7IG9wZXJhdG9yOiBcImd0XCIgfSk7XHJcbiAgLyoqIEFsaWFzZXM6IFwibHRcIiwgXCI8XCIgICoqL1xyXG4gIHN0YXRpYyBMZXNzVGhhbiA9IG5ldyBGaWx0ZXJRdWVyeU9wKHsgb3BlcmF0b3I6IFwibHRcIiB9KTtcclxuICAvKiogIEFsaWFzZXM6IFwiZ2VcIiwgXCI+PVwiICAqKi9cclxuICBzdGF0aWMgR3JlYXRlclRoYW5PckVxdWFsID0gbmV3IEZpbHRlclF1ZXJ5T3AoeyBvcGVyYXRvcjogXCJnZVwiIH0pO1xyXG4gIC8qKiAgQWxpYXNlczogXCJsZVwiLCBcIjw9XCIgICoqL1xyXG4gIHN0YXRpYyBMZXNzVGhhbk9yRXF1YWwgPSBuZXcgRmlsdGVyUXVlcnlPcCh7IG9wZXJhdG9yOiBcImxlXCIgfSk7XHJcbiAgLyoqICBTdHJpbmcgb3BlcmF0aW9uOiBJcyBhIHN0cmluZyBhIHN1YnN0cmluZyBvZiBhbm90aGVyIHN0cmluZy4gIEFsaWFzZXM6IFwic3Vic3RyaW5nb2ZcIiAgICoqL1xyXG4gIHN0YXRpYyBDb250YWlucyA9IG5ldyBGaWx0ZXJRdWVyeU9wKHsgb3BlcmF0b3I6IFwiY29udGFpbnNcIiB9KTtcclxuICAvKiogTm8gYWxpYXNlcyAqL1xyXG4gIHN0YXRpYyBTdGFydHNXaXRoID0gbmV3IEZpbHRlclF1ZXJ5T3AoeyBvcGVyYXRvcjogXCJzdGFydHN3aXRoXCIgfSk7XHJcbiAgLyoqIE5vIGFsaWFzZXMgKi9cclxuICBzdGF0aWMgRW5kc1dpdGggPSBuZXcgRmlsdGVyUXVlcnlPcCh7IG9wZXJhdG9yOiBcImVuZHN3aXRoXCIgfSk7XHJcbiAgLyoqICBBbGlhc2VzOiBcInNvbWVcIiAgKiovXHJcbiAgc3RhdGljIEFueSA9IG5ldyBGaWx0ZXJRdWVyeU9wKHsgb3BlcmF0b3I6IFwiYW55XCIgfSk7XHJcbiAgLyoqICBBbGlhc2VzOiBcImV2ZXJ5XCIgICoqL1xyXG4gIHN0YXRpYyBBbGwgPSBuZXcgRmlsdGVyUXVlcnlPcCh7IG9wZXJhdG9yOiBcImFsbFwiIH0pO1xyXG4gIC8qKiBObyBhbGlhc2VzICovXHJcbiAgc3RhdGljIEluID0gbmV3IEZpbHRlclF1ZXJ5T3AoeyBvcGVyYXRvcjogXCJpblwiIH0pO1xyXG4gIC8qKiBObyBhbGlhc2VzICovXHJcbiAgc3RhdGljIElzVHlwZU9mID0gbmV3IEZpbHRlclF1ZXJ5T3AoeyBvcGVyYXRvcjogXCJpc29mXCIgfSk7XHJcbn1cclxuRmlsdGVyUXVlcnlPcC5wcm90b3R5cGUuXyR0eXBlTmFtZSA9IFwiRmlsdGVyUXVlcnlPcFwiO1xyXG5FcnJvclsneCddID0gRmlsdGVyUXVlcnlPcC5yZXNvbHZlU3ltYm9scygpO1xyXG5cclxuXHJcbi8qKlxyXG4gQm9vbGVhblF1ZXJ5T3AgaXMgYW4gJ0VudW0nIGNvbnRhaW5pbmcgYWxsIG9mIHRoZSB2YWxpZCAgYm9vbGVhblxyXG5vcGVyYXRvcnMgZm9yIGFuIFtbRW50aXR5UXVlcnldXS5cclxuKiovXHJcbmV4cG9ydCBjbGFzcyBCb29sZWFuUXVlcnlPcCBleHRlbmRzIEJyZWV6ZUVudW0gaW1wbGVtZW50cyBRdWVyeU9wIHtcclxuICAvKiogVGhlIG9wZXJhdG9yIGZvciB0aGlzIGVudW0uICovXHJcbiAgb3BlcmF0b3I6IHN0cmluZztcclxuXHJcbiAgc3RhdGljIEFuZCA9IG5ldyBCb29sZWFuUXVlcnlPcCh7IG9wZXJhdG9yOiBcImFuZFwiIH0pO1xyXG4gIHN0YXRpYyBPciA9IG5ldyBCb29sZWFuUXVlcnlPcCh7IG9wZXJhdG9yOiBcIm9yXCIgfSk7XHJcbiAgc3RhdGljIE5vdCA9IG5ldyBCb29sZWFuUXVlcnlPcCh7IG9wZXJhdG9yOiBcIm5vdFwiIH0pO1xyXG5cclxufVxyXG5Cb29sZWFuUXVlcnlPcC5wcm90b3R5cGUuXyR0eXBlTmFtZSA9IFwiQm9vbGVhblF1ZXJ5T3BcIjtcclxuRXJyb3JbJ3gnXSA9IEJvb2xlYW5RdWVyeU9wLnJlc29sdmVTeW1ib2xzKCk7XHJcblxyXG5cclxuLyoqIEZvciB1c2UgYnkgYnJlZXplIHBsdWdpbiBhdXRob3JzIG9ubHkuICBUaGUgY2xhc3MgaXMgdXNlZCBpbiBtb3N0IFtbSVVyaUJ1aWxkZXJBZGFwdGVyXV0gaW1wbGVtZW50YXRpb25zXHJcbkBhZGFwdGVyIChzZWUgW1tJVXJpQnVpbGRlckFkYXB0ZXJdXSkgICAgXHJcbkBoaWRkZW5cclxuXHJcbkFuIE9yZGVyQnlDbGF1c2UgaXMgYSBkZXNjcmlwdGlvbiBvZiB0aGUgcHJvcGVydGllcyBhbmQgZGlyZWN0aW9uIHRoYXQgdGhlIHJlc3VsdFxyXG5vZiBhIHF1ZXJ5IHNob3VsZCBiZSBzb3J0ZWQgaW4uICBPcmRlckJ5Q2xhdXNlcyBhcmUgaW1tdXRhYmxlLCB3aGljaCBtZWFucyB0aGF0IGFueVxyXG5tZXRob2QgdGhhdCB3b3VsZCBtb2RpZnkgYW4gT3JkZXJCeUNsYXVzZSBhY3R1YWxseSByZXR1cm5zIGEgbmV3IE9yZGVyQnlDbGF1c2UuXHJcblxyXG5Gb3IgZXhhbXBsZSBmb3IgYW4gRW1wbG95ZWUgb2JqZWN0IHdpdGggcHJvcGVydGllcyBvZiAnQ29tcGFueScgYW5kICdMYXN0TmFtZScgdGhlIGZvbGxvd2luZyB3b3VsZCBiZSB2YWxpZCBleHByZXNzaW9uczpcclxuPiAgICAgbGV0IG9iYyA9IG5ldyBPcmRlckJ5Q2xhdXNlKFwiQ29tcGFueS5Db21wYW55TmFtZSwgTGFzdE5hbWVcIilcclxuXHJcbm9yXHJcbj4gICAgIGxldCBvYmMgPSBuZXcgT3JkZXJCeUNsYXVzZShcIkNvbXBhbnkuQ29tcGFueU5hbWUgZGVzYywgTGFzdE5hbWVcIilcclxuXHJcbm9yXHJcbj4gICAgIGxldCBvYmMgPSBuZXcgT3JkZXJCeUNsYXVzZShcIkNvbXBhbnkuQ29tcGFueU5hbWUsIExhc3ROYW1lXCIsIHRydWUpO1xyXG4qL1xyXG5leHBvcnQgY2xhc3MgT3JkZXJCeUNsYXVzZSB7XHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgaXRlbXM6IE9yZGVyQnlJdGVtW107XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByb3BlcnR5UGF0aHM6IHN0cmluZ1tdIHwgT3JkZXJCeUNsYXVzZVtdLCBpc0Rlc2M/OiBib29sZWFuKSB7XHJcbiAgICBpZiAocHJvcGVydHlQYXRocy5sZW5ndGggPT09IDApIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiT3JkZXJCeUNsYXVzZSBjYW5ub3QgYmUgZW1wdHlcIik7XHJcbiAgICB9XHJcblxyXG4gICAgLy8geW91IGNhbiBhbHNvIHBhc3MgaW4gYW4gYXJyYXkgb2Ygb3JkZXJCeUNsYXVzZXNcclxuICAgIGlmIChwcm9wZXJ0eVBhdGhzWzBdIGluc3RhbmNlb2YgT3JkZXJCeUNsYXVzZSkge1xyXG4gICAgICBsZXQgY2xhdXNlcyA9IHByb3BlcnR5UGF0aHMgYXMgT3JkZXJCeUNsYXVzZVtdO1xyXG4gICAgICB0aGlzLml0ZW1zID0gY29yZS5hcnJheUZsYXRNYXAoY2xhdXNlcywgYyA9PiBjLml0ZW1zKTtcclxuICAgICAgLy8gdGhpcy5pdGVtcyA9IEFycmF5LnByb3RvdHlwZS5jb25jYXQuYXBwbHkoY2xhdXNlc1swXS5pdGVtcywgY2xhdXNlcy5zbGljZSgxKS5tYXAoY29yZS5wbHVjayhcIml0ZW1zXCIpKSk7XHJcbiAgICAgIC8vIHRoaXMuaXRlbXMgPSBBcnJheS5wcm90b3R5cGUuY29uY2F0LmFwcGx5KFtdLCBjbGF1c2VzLm1hcChjb3JlLnBsdWNrKFwiaXRlbXNcIikpKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuaXRlbXMgPSAocHJvcGVydHlQYXRocyBhcyBzdHJpbmdbXSkubWFwKGZ1bmN0aW9uIChwcCkge1xyXG4gICAgICAgIHJldHVybiBuZXcgT3JkZXJCeUl0ZW0ocHAsIGlzRGVzYyk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICB9XHJcblxyXG4gIHZhbGlkYXRlKGVudGl0eVR5cGU6IEVudGl0eVR5cGUpIHtcclxuICAgIGlmIChlbnRpdHlUeXBlID09IG51bGwgfHwgZW50aXR5VHlwZS5pc0Fub255bW91cykgcmV0dXJuO1xyXG4gICAgdGhpcy5pdGVtcy5mb3JFYWNoKChpdGVtKSA9PiB7XHJcbiAgICAgIGl0ZW0udmFsaWRhdGUoZW50aXR5VHlwZSk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIGdldENvbXBhcmVyKGVudGl0eVR5cGU6IEVudGl0eVR5cGUpIHtcclxuICAgIGxldCBvcmRlckJ5RnVuY3MgPSB0aGlzLml0ZW1zLm1hcChmdW5jdGlvbiAob2JjKSB7XHJcbiAgICAgIHJldHVybiBvYmMuZ2V0Q29tcGFyZXIoZW50aXR5VHlwZSk7XHJcbiAgICB9KTtcclxuICAgIHJldHVybiBmdW5jdGlvbiAoZW50aXR5MTogYW55LCBlbnRpdHkyOiBhbnkpIHtcclxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBvcmRlckJ5RnVuY3MubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICBsZXQgcmVzdWx0ID0gb3JkZXJCeUZ1bmNzW2ldKGVudGl0eTEsIGVudGl0eTIpO1xyXG4gICAgICAgIGlmIChyZXN1bHQgIT09IDApIHtcclxuICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiAwO1xyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIHRvSlNPTkV4dChjb250ZXh0OiBFbnRpdHlRdWVyeUpzb25Db250ZXh0KSB7XHJcbiAgICByZXR1cm4gdGhpcy5pdGVtcy5tYXAoZnVuY3Rpb24gKGl0ZW0pIHtcclxuICAgICAgcmV0dXJuIGNvbnRleHQucHJvcGVydHlQYXRoRm4hKGl0ZW0ucHJvcGVydHlQYXRoKSArIChpdGVtLmlzRGVzYyA/IFwiIGRlc2NcIiA6IFwiXCIpO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxufVxyXG5cclxuLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbmV4cG9ydCBjbGFzcyBPcmRlckJ5SXRlbSB7XHJcbiAgcHJvcGVydHlQYXRoOiBzdHJpbmc7XHJcbiAgaXNEZXNjOiBib29sZWFuO1xyXG4gIGxhc3RQcm9wZXJ0eTogRW50aXR5UHJvcGVydHk7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByb3BlcnR5UGF0aDogc3RyaW5nLCBpc0Rlc2M/OiBib29sZWFuKSB7XHJcbiAgICBpZiAoISh0eXBlb2YgcHJvcGVydHlQYXRoID09PSAnc3RyaW5nJykpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwicHJvcGVydHlQYXRoIGlzIG5vdCBhIHN0cmluZ1wiKTtcclxuICAgIH1cclxuICAgIHByb3BlcnR5UGF0aCA9IHByb3BlcnR5UGF0aC50cmltKCk7XHJcblxyXG4gICAgbGV0IHBhcnRzID0gcHJvcGVydHlQYXRoLnNwbGl0KCcgJyk7XHJcbiAgICAvLyBwYXJ0c1swXSBpcyB0aGUgcHJvcGVydHlQYXRoOyBbMV0gd291bGQgYmUgd2hldGhlciBkZXNjZW5kaW5nIG9yIG5vdC5cclxuICAgIC8vIGlmIChwYXJ0cy5sZW5ndGggPiAxICYmIGlzRGVzYyAhPT0gdHJ1ZSAmJiBpc0Rlc2MgIT09IGZhbHNlKSB7XHJcbiAgICBpZiAocGFydHMubGVuZ3RoID4gMSAmJiBpc0Rlc2MgPT0gbnVsbCkge1xyXG4gICAgICBpc0Rlc2MgPSBjb3JlLnN0cmluZ1N0YXJ0c1dpdGgocGFydHNbMV0udG9Mb3dlckNhc2UoKSwgXCJkZXNjXCIpO1xyXG4gICAgICBpZiAoIWlzRGVzYykge1xyXG4gICAgICAgIC8vIGlzRGVzYyBpcyBmYWxzZSBidXQgY2hlY2sgdG8gbWFrZSBzdXJlIGl0cyBpbnRlbmRlZC5cclxuICAgICAgICBsZXQgaXNBc2MgPSBjb3JlLnN0cmluZ1N0YXJ0c1dpdGgocGFydHNbMV0udG9Mb3dlckNhc2UoKSwgXCJhc2NcIik7XHJcbiAgICAgICAgaWYgKCFpc0FzYykge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwidGhlIHNlY29uZCB3b3JkIGluIHRoZSBwcm9wZXJ0eVBhdGggbXVzdCBiZWdpbiB3aXRoICdkZXNjJyBvciAnYXNjJ1wiKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICB0aGlzLnByb3BlcnR5UGF0aCA9IHBhcnRzWzBdO1xyXG4gICAgdGhpcy5pc0Rlc2MgPSBpc0Rlc2MgfHwgZmFsc2U7XHJcbiAgfVxyXG5cclxuICB2YWxpZGF0ZShlbnRpdHlUeXBlOiBFbnRpdHlUeXBlKTogRW50aXR5UHJvcGVydHkgfCB1bmRlZmluZWQge1xyXG4gICAgaWYgKGVudGl0eVR5cGUgPT0gbnVsbCB8fCBlbnRpdHlUeXBlLmlzQW5vbnltb3VzKSByZXR1cm47XHJcbiAgICAvLyB3aWxsIHRocm93IGFuIGV4Y2VwdGlvbiBvbiBiYWQgcHJvcGVydHlQYXRoXHJcbiAgICB0aGlzLmxhc3RQcm9wZXJ0eSA9IGVudGl0eVR5cGUuZ2V0UHJvcGVydHkodGhpcy5wcm9wZXJ0eVBhdGgsIHRydWUpIGFzIEVudGl0eVByb3BlcnR5O1xyXG4gICAgcmV0dXJuIHRoaXMubGFzdFByb3BlcnR5O1xyXG4gIH1cclxuXHJcbiAgZ2V0Q29tcGFyZXIoZW50aXR5VHlwZTogRW50aXR5VHlwZSkge1xyXG4gICAgbGV0IHByb3BEYXRhVHlwZTogRGF0YVR5cGU7XHJcbiAgICBsZXQgaXNDYXNlU2Vuc2l0aXZlOiBib29sZWFuO1xyXG4gICAgaWYgKCF0aGlzLmxhc3RQcm9wZXJ0eSkgdGhpcy52YWxpZGF0ZShlbnRpdHlUeXBlKTtcclxuICAgIGlmICh0aGlzLmxhc3RQcm9wZXJ0eSkge1xyXG4gICAgICBwcm9wRGF0YVR5cGUgPSAodGhpcy5sYXN0UHJvcGVydHkgYXMgYW55KS5kYXRhVHlwZTtcclxuICAgICAgaXNDYXNlU2Vuc2l0aXZlID0gdGhpcy5sYXN0UHJvcGVydHkucGFyZW50VHlwZS5tZXRhZGF0YVN0b3JlLmxvY2FsUXVlcnlDb21wYXJpc29uT3B0aW9ucy5pc0Nhc2VTZW5zaXRpdmU7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IHByb3BlcnR5UGF0aCA9IHRoaXMucHJvcGVydHlQYXRoO1xyXG4gICAgbGV0IGlzRGVzYyA9IHRoaXMuaXNEZXNjO1xyXG5cclxuICAgIHJldHVybiBmdW5jdGlvbiAoZW50aXR5MTogYW55LCBlbnRpdHkyOiBhbnkpIHtcclxuICAgICAgbGV0IHZhbHVlMSA9IEVudGl0eUFzcGVjdC5nZXRQcm9wZXJ0eVBhdGhWYWx1ZShlbnRpdHkxLCBwcm9wZXJ0eVBhdGgpO1xyXG4gICAgICBsZXQgdmFsdWUyID0gRW50aXR5QXNwZWN0LmdldFByb3BlcnR5UGF0aFZhbHVlKGVudGl0eTIsIHByb3BlcnR5UGF0aCk7XHJcbiAgICAgIGxldCBkYXRhVHlwZSA9IHByb3BEYXRhVHlwZSB8fCAodmFsdWUxICYmIERhdGFUeXBlLmZyb21WYWx1ZSh2YWx1ZTEpKSB8fCBEYXRhVHlwZS5mcm9tVmFsdWUodmFsdWUyKTtcclxuICAgICAgaWYgKGRhdGFUeXBlID09PSBEYXRhVHlwZS5TdHJpbmcpIHtcclxuICAgICAgICBpZiAoaXNDYXNlU2Vuc2l0aXZlKSB7XHJcbiAgICAgICAgICB2YWx1ZTEgPSB2YWx1ZTEgfHwgXCJcIjtcclxuICAgICAgICAgIHZhbHVlMiA9IHZhbHVlMiB8fCBcIlwiO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB2YWx1ZTEgPSAodmFsdWUxIHx8IFwiXCIpLnRvTG93ZXJDYXNlKCk7XHJcbiAgICAgICAgICB2YWx1ZTIgPSAodmFsdWUyIHx8IFwiXCIpLnRvTG93ZXJDYXNlKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxldCBub3JtYWxpemUgPSBEYXRhVHlwZS5nZXRDb21wYXJhYmxlRm4oZGF0YVR5cGUpO1xyXG4gICAgICAgIHZhbHVlMSA9IG5vcm1hbGl6ZSh2YWx1ZTEpO1xyXG4gICAgICAgIHZhbHVlMiA9IG5vcm1hbGl6ZSh2YWx1ZTIpO1xyXG4gICAgICB9XHJcbiAgICAgIGlmICh2YWx1ZTEgPT09IHZhbHVlMikge1xyXG4gICAgICAgIHJldHVybiAwO1xyXG4gICAgICB9IGVsc2UgaWYgKHZhbHVlMSA+IHZhbHVlMiB8fCB2YWx1ZTIgPT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIHJldHVybiBpc0Rlc2MgPyAtMSA6IDE7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgcmV0dXJuIGlzRGVzYyA/IDEgOiAtMTtcclxuICAgICAgfVxyXG4gICAgfTtcclxuICB9XHJcbn1cclxuXHJcbi8qKiBGb3IgdXNlIGJ5IGJyZWV6ZSBwbHVnaW4gYXV0aG9ycyBvbmx5LiAgVGhlIGNsYXNzIGlzIHVzZWQgaW4gbW9zdCBbW0lVcmlCdWlsZGVyQWRhcHRlcl1dIGltcGxlbWVudGF0aW9uc1xyXG5AYWRhcHRlciAoc2VlIFtbSVVyaUJ1aWxkZXJBZGFwdGVyXV0pICAgIFxyXG5AaGlkZGVuIFxyXG4qKi9cclxuZXhwb3J0IGNsYXNzIFNlbGVjdENsYXVzZSB7XHJcbiAgcHJvcGVydHlQYXRoczogc3RyaW5nW107XHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX3BhdGhOYW1lczogc3RyaW5nW107XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByb3BlcnR5UGF0aHM6IHN0cmluZ1tdKSB7XHJcbiAgICB0aGlzLnByb3BlcnR5UGF0aHMgPSBwcm9wZXJ0eVBhdGhzO1xyXG4gICAgdGhpcy5fcGF0aE5hbWVzID0gcHJvcGVydHlQYXRocy5tYXAoZnVuY3Rpb24gKHBwKSB7XHJcbiAgICAgIHJldHVybiBwcC5yZXBsYWNlKFwiLlwiLCBcIl9cIik7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHZhbGlkYXRlKGVudGl0eVR5cGU6IEVudGl0eVR5cGUpIHtcclxuICAgIGlmIChlbnRpdHlUeXBlID09IG51bGwgfHwgZW50aXR5VHlwZS5pc0Fub255bW91cykgcmV0dXJuOyAvLyBjYW4ndCB2YWxpZGF0ZSB5ZXRcclxuICAgIC8vIHdpbGwgdGhyb3cgYW4gZXhjZXB0aW9uIG9uIGJhZCBwcm9wZXJ0eVBhdGhcclxuICAgIHRoaXMucHJvcGVydHlQYXRocy5mb3JFYWNoKGZ1bmN0aW9uIChwYXRoKSB7XHJcbiAgICAgIGVudGl0eVR5cGUuZ2V0UHJvcGVydHkocGF0aCwgdHJ1ZSk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHRvRnVuY3Rpb24oLyogY29uZmlnICovKSB7XHJcbiAgICBsZXQgdGhhdCA9IHRoaXM7XHJcbiAgICByZXR1cm4gZnVuY3Rpb24gKGVudGl0eTogRW50aXR5KSB7XHJcbiAgICAgIGxldCByZXN1bHQgPSB7fTtcclxuICAgICAgdGhhdC5wcm9wZXJ0eVBhdGhzLmZvckVhY2goZnVuY3Rpb24gKHBhdGgsIGkpIHtcclxuICAgICAgICByZXN1bHRbdGhhdC5fcGF0aE5hbWVzW2ldXSA9IEVudGl0eUFzcGVjdC5nZXRQcm9wZXJ0eVBhdGhWYWx1ZShlbnRpdHksIHBhdGgpO1xyXG4gICAgICB9KTtcclxuICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICB0b0pTT05FeHQoY29udGV4dDogRW50aXR5UXVlcnlKc29uQ29udGV4dCkge1xyXG4gICAgcmV0dXJuIHRoaXMucHJvcGVydHlQYXRocy5tYXAoZnVuY3Rpb24gKHBwKSB7XHJcbiAgICAgIHJldHVybiBjb250ZXh0LnByb3BlcnR5UGF0aEZuIShwcCk7XHJcbiAgICB9KTtcclxuICB9XHJcbn1cclxuXHJcbi8qKiBGb3IgdXNlIGJ5IGJyZWV6ZSBwbHVnaW4gYXV0aG9ycyBvbmx5LiAgVGhlIGNsYXNzIGlzIHVzZWQgaW4gbW9zdCBbW0lVcmlCdWlsZGVyQWRhcHRlcl1dIGltcGxlbWVudGF0aW9uc1xyXG5AYWRhcHRlciAoc2VlIFtbSVVyaUJ1aWxkZXJBZGFwdGVyXV0pICAgIFxyXG5AaGlkZGVuIFxyXG4qKi9cclxuZXhwb3J0IGNsYXNzIEV4cGFuZENsYXVzZSB7XHJcbiAgcHJvcGVydHlQYXRoczogc3RyaW5nW107XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByb3BlcnR5UGF0aHM6IHN0cmluZ1tdKSB7XHJcbiAgICB0aGlzLnByb3BlcnR5UGF0aHMgPSBwcm9wZXJ0eVBhdGhzO1xyXG4gIH1cclxuXHJcbiAgdG9KU09ORXh0KGNvbnRleHQ6IEVudGl0eVF1ZXJ5SnNvbkNvbnRleHQpIHtcclxuICAgIHJldHVybiB0aGlzLnByb3BlcnR5UGF0aHMubWFwKGZ1bmN0aW9uIChwcCkge1xyXG4gICAgICByZXR1cm4gY29udGV4dC5wcm9wZXJ0eVBhdGhGbiEocHApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxufVxyXG5cclxuXHJcbiJdfQ==
|