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