breeze-client 2.2.0 → 2.2.1-cjs
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/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 +14234 -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 +506 -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 +513 -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/esm5/src/naming-convention.js +90 -0
- 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} +1543 -2042
- 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 +13956 -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 +12 -94
- 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 +1 -1
- 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 -325
- 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 -510
- 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 -1024
- 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/naming-convention.mjs +0 -96
- 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,2094 @@
|
|
|
1
|
+
import { core } from './core';
|
|
2
|
+
import { assertParam, assertConfig } from './assert-param';
|
|
3
|
+
import { config } from './config';
|
|
4
|
+
import { BreezeEvent } from './event';
|
|
5
|
+
import { EntityAspect } from './entity-aspect';
|
|
6
|
+
import { MetadataStore, EntityType, DataProperty, AutoGeneratedKeyType } from './entity-metadata';
|
|
7
|
+
import { EntityKey } from './entity-key';
|
|
8
|
+
import { EntityAction } from './entity-action';
|
|
9
|
+
import { EntityState } from './entity-state';
|
|
10
|
+
import { DataService } from './data-service';
|
|
11
|
+
import { DataType } from './data-type';
|
|
12
|
+
import { ValidationError } from './validate';
|
|
13
|
+
import { ValidationOptions } from './validation-options';
|
|
14
|
+
import { QueryOptions, MergeStrategy, FetchStrategy } from './query-options';
|
|
15
|
+
import { SaveOptions } from './save-options';
|
|
16
|
+
import { KeyGenerator } from './key-generator';
|
|
17
|
+
import { EntityGroup } from './entity-group';
|
|
18
|
+
import { MappingContext } from './mapping-context';
|
|
19
|
+
import { EntityQuery } from './entity-query';
|
|
20
|
+
import { UnattachedChildrenMap } from './unattached-children-map';
|
|
21
|
+
/**
|
|
22
|
+
Instances of the EntityManager contain and manage collections of entities, either retrieved from a backend datastore or created on the client.
|
|
23
|
+
**/
|
|
24
|
+
export class EntityManager {
|
|
25
|
+
/**
|
|
26
|
+
EntityManager constructor.
|
|
27
|
+
|
|
28
|
+
At its most basic an EntityManager can be constructed with just a service name
|
|
29
|
+
> let entityManager = new EntityManager( "breeze/NorthwindIBModel");
|
|
30
|
+
|
|
31
|
+
This is the same as calling it with the following configuration object
|
|
32
|
+
> let entityManager = new EntityManager( {serviceName: "breeze/NorthwindIBModel" });
|
|
33
|
+
|
|
34
|
+
Usually however, configuration objects will contain more than just the 'serviceName';
|
|
35
|
+
> let metadataStore = new MetadataStore();
|
|
36
|
+
> let entityManager = new EntityManager( {
|
|
37
|
+
> serviceName: "breeze/NorthwindIBModel",
|
|
38
|
+
> metadataStore: metadataStore
|
|
39
|
+
> });
|
|
40
|
+
|
|
41
|
+
or
|
|
42
|
+
> return new QueryOptions({
|
|
43
|
+
> mergeStrategy: obj,
|
|
44
|
+
> fetchStrategy: this.fetchStrategy
|
|
45
|
+
> });
|
|
46
|
+
> let queryOptions = new QueryOptions({
|
|
47
|
+
> mergeStrategy: MergeStrategy.OverwriteChanges,
|
|
48
|
+
> fetchStrategy: FetchStrategy.FromServer
|
|
49
|
+
> });
|
|
50
|
+
> let validationOptions = new ValidationOptions({
|
|
51
|
+
> validateOnAttach: true,
|
|
52
|
+
> validateOnSave: true,
|
|
53
|
+
> validateOnQuery: false
|
|
54
|
+
> });
|
|
55
|
+
> let entityManager = new EntityManager({
|
|
56
|
+
> serviceName: "breeze/NorthwindIBModel",
|
|
57
|
+
> queryOptions: queryOptions,
|
|
58
|
+
> validationOptions: validationOptions
|
|
59
|
+
> });
|
|
60
|
+
@param emConfig - Configuration settings or a service name.
|
|
61
|
+
**/
|
|
62
|
+
constructor(emConfig) {
|
|
63
|
+
this.helper = {
|
|
64
|
+
unwrapInstance: unwrapInstance,
|
|
65
|
+
unwrapOriginalValues: unwrapOriginalValues,
|
|
66
|
+
unwrapChangedValues: unwrapChangedValues
|
|
67
|
+
};
|
|
68
|
+
if (arguments.length > 1) {
|
|
69
|
+
throw new Error("The EntityManager ctor has a single optional argument that is either a 'serviceName' or a configuration object.");
|
|
70
|
+
}
|
|
71
|
+
let config;
|
|
72
|
+
if (arguments.length === 0) {
|
|
73
|
+
config = { serviceName: "" };
|
|
74
|
+
}
|
|
75
|
+
else if (typeof emConfig === 'string') {
|
|
76
|
+
config = { serviceName: emConfig };
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
config = emConfig || {};
|
|
80
|
+
}
|
|
81
|
+
EntityManager._updateWithConfig(this, config, true);
|
|
82
|
+
this.entityChanged = new BreezeEvent("entityChanged", this);
|
|
83
|
+
this.validationErrorsChanged = new BreezeEvent("validationErrorsChanged", this);
|
|
84
|
+
this.hasChangesChanged = new BreezeEvent("hasChangesChanged", this);
|
|
85
|
+
this.clear();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
General purpose property set method. Any of the properties in the [[EntityManagerConfig]]
|
|
89
|
+
may be set.
|
|
90
|
+
> // assume em1 is a previously created EntityManager
|
|
91
|
+
> // where we want to change some of its settings.
|
|
92
|
+
> em1.setProperties( {
|
|
93
|
+
> serviceName: "breeze/foo"
|
|
94
|
+
> });
|
|
95
|
+
@param config - An object containing the selected properties and values to set.
|
|
96
|
+
**/
|
|
97
|
+
setProperties(config) {
|
|
98
|
+
EntityManager._updateWithConfig(this, config, false);
|
|
99
|
+
}
|
|
100
|
+
/** @hidden @internal */
|
|
101
|
+
static _updateWithConfig(em, config, isCtor) {
|
|
102
|
+
let defaultQueryOptions = isCtor ? QueryOptions.defaultInstance : em.queryOptions;
|
|
103
|
+
let defaultSaveOptions = isCtor ? SaveOptions.defaultInstance : em.saveOptions;
|
|
104
|
+
let defaultValidationOptions = isCtor ? ValidationOptions.defaultInstance : em.validationOptions;
|
|
105
|
+
let configParam = assertConfig(config)
|
|
106
|
+
.whereParam("serviceName").isOptional().isString()
|
|
107
|
+
.whereParam("dataService").isOptional().isInstanceOf(DataService)
|
|
108
|
+
.whereParam("queryOptions").isInstanceOf(QueryOptions).isOptional().withDefault(defaultQueryOptions)
|
|
109
|
+
.whereParam("saveOptions").isInstanceOf(SaveOptions).isOptional().withDefault(defaultSaveOptions)
|
|
110
|
+
.whereParam("validationOptions").isInstanceOf(ValidationOptions).isOptional().withDefault(defaultValidationOptions)
|
|
111
|
+
.whereParam("keyGeneratorCtor").isFunction().isOptional();
|
|
112
|
+
if (isCtor) {
|
|
113
|
+
configParam = configParam
|
|
114
|
+
.whereParam("metadataStore").isInstanceOf(MetadataStore).isOptional().withDefault(new MetadataStore());
|
|
115
|
+
}
|
|
116
|
+
configParam.applyAll(em);
|
|
117
|
+
// insure that entityManager's options versions are completely populated
|
|
118
|
+
core.updateWithDefaults(em.queryOptions, defaultQueryOptions);
|
|
119
|
+
core.updateWithDefaults(em.saveOptions, defaultSaveOptions);
|
|
120
|
+
core.updateWithDefaults(em.validationOptions, defaultValidationOptions);
|
|
121
|
+
if (config.serviceName) {
|
|
122
|
+
em.dataService = new DataService({
|
|
123
|
+
serviceName: em.serviceName
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
em.serviceName = em.dataService && em.dataService.serviceName;
|
|
127
|
+
em.keyGeneratorCtor = em.keyGeneratorCtor || KeyGenerator;
|
|
128
|
+
if (isCtor || config.keyGeneratorCtor) {
|
|
129
|
+
em.keyGenerator = new em.keyGeneratorCtor();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
Creates a new entity of a specified type and optionally initializes it. By default the new entity is created with an EntityState of Added
|
|
134
|
+
but you can also optionally specify an EntityState. An EntityState of 'Detached' will insure that the entity is created but not yet added
|
|
135
|
+
to the EntityManager.
|
|
136
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
137
|
+
> // create and add an entity;
|
|
138
|
+
> let emp1 = em1.createEntity("Employee");
|
|
139
|
+
> // create and add an initialized entity;
|
|
140
|
+
> let emp2 = em1.createEntity("Employee", { lastName: "Smith", firstName: "John" });
|
|
141
|
+
> // create and attach (not add) an initialized entity
|
|
142
|
+
> let emp3 = em1.createEntity("Employee", { id: 435, lastName: "Smith", firstName: "John" }, EntityState.Unchanged);
|
|
143
|
+
> // create but don't attach an entity;
|
|
144
|
+
> let emp4 = em1.createEntity("Employee", { id: 435, lastName: "Smith", firstName: "John" }, EntityState.Detached);
|
|
145
|
+
@param typeName - The name of the EntityType for which an instance should be created.
|
|
146
|
+
@param entityType - The EntityType of the type for which an instance should be created.
|
|
147
|
+
@param initialValues - (default=null) Configuration object of the properties to set immediately after creation.
|
|
148
|
+
@param entityState - (default = [[EntityState.Added]]) The EntityState of the entity after being created and added to this EntityManager.
|
|
149
|
+
@param mergeStrategy - (default = [[MergeStrategy.Disallowed]]) - How to handle conflicts if an entity with the same key already exists within this EntityManager.
|
|
150
|
+
@return {Entity} A new Entity of the specified type.
|
|
151
|
+
*/
|
|
152
|
+
createEntity(entityType, initialValues, entityState, mergeStrategy) {
|
|
153
|
+
assertParam(entityType, "entityType").isString().or().isInstanceOf(EntityType).check();
|
|
154
|
+
assertParam(entityState, "entityState").isEnumOf(EntityState).isOptional().check();
|
|
155
|
+
assertParam(mergeStrategy, "mergeStrategy").isEnumOf(MergeStrategy).isOptional().check();
|
|
156
|
+
let et = (typeof entityType === "string") ? this.metadataStore._getStructuralType(entityType) : entityType;
|
|
157
|
+
entityState = entityState || EntityState.Added;
|
|
158
|
+
let entity = {};
|
|
159
|
+
core.using(this, "isLoading", true, function () {
|
|
160
|
+
entity = et.createEntity(initialValues);
|
|
161
|
+
});
|
|
162
|
+
if (entityState !== EntityState.Detached) {
|
|
163
|
+
entity = this.attachEntity(entity, entityState, mergeStrategy);
|
|
164
|
+
}
|
|
165
|
+
return entity;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
Creates a new EntityManager and imports a previously exported result into it.
|
|
169
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
170
|
+
> let bundle = em1.exportEntities();
|
|
171
|
+
> // can be stored via the web storage api
|
|
172
|
+
> window.localStorage.setItem("myEntityManager", bundle);
|
|
173
|
+
> // assume the code below occurs in a different session.
|
|
174
|
+
> let bundleFromStorage = window.localStorage.getItem("myEntityManager");
|
|
175
|
+
> // and imported
|
|
176
|
+
> let em2 = EntityManager.importEntities(bundleFromStorage);
|
|
177
|
+
> // em2 will now have a complete copy of what was in em1
|
|
178
|
+
@param exportedString - The result of a previous 'exportEntities' call as a string
|
|
179
|
+
@param exportedData - The result of a previous 'exportEntities' call as an Object.
|
|
180
|
+
@param config - A configuration object.
|
|
181
|
+
@param config.mergeStrategy - A [[MergeStrategy]] to use when
|
|
182
|
+
merging into an existing EntityManager.
|
|
183
|
+
@param config.metadataVersionFn - A function that takes two arguments (the current metadataVersion and the imported store's 'name')
|
|
184
|
+
and may be used to perform version checking.
|
|
185
|
+
@return A new EntityManager. Note that the return value of this method call is different from that
|
|
186
|
+
provided by the same named method on an EntityManager instance. Use that method if you need additional information
|
|
187
|
+
regarding the imported entities.
|
|
188
|
+
**/
|
|
189
|
+
static importEntities(exported, config) {
|
|
190
|
+
let em = new EntityManager();
|
|
191
|
+
em.importEntities(exported, config);
|
|
192
|
+
return em;
|
|
193
|
+
}
|
|
194
|
+
// instance methods
|
|
195
|
+
/**
|
|
196
|
+
Calls [[EntityAspect.acceptChanges]] on every changed entity in this EntityManager.
|
|
197
|
+
**/
|
|
198
|
+
acceptChanges() {
|
|
199
|
+
this.getChanges().map(function (entity) {
|
|
200
|
+
return entity.entityAspect._checkOperation("acceptChanges");
|
|
201
|
+
}).forEach(function (aspect) {
|
|
202
|
+
aspect.acceptChanges();
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
Exports selected entities, all entities of selected types, or an entire EntityManager cache.
|
|
207
|
+
|
|
208
|
+
This method takes a snapshot of an EntityManager that can be stored offline or held in memory.
|
|
209
|
+
Use the [[EntityManager.importEntities]] method to restore or merge the snapshot
|
|
210
|
+
into another EntityManager at some later time.
|
|
211
|
+
> // let em1 be an EntityManager containing a number of existing entities.
|
|
212
|
+
> // export every entity in em1.
|
|
213
|
+
> let bundle = em1.exportEntities();
|
|
214
|
+
> // save to the browser's local storage
|
|
215
|
+
> window.localStorage.setItem("myEntityManager", bundle);
|
|
216
|
+
> // later retrieve the export
|
|
217
|
+
> let bundleFromStorage = window.localStorage.getItem("myEntityManager");
|
|
218
|
+
> // import the retrieved export bundle into another manager
|
|
219
|
+
> let em2 = em1.createEmptyCopy();
|
|
220
|
+
> em2.importEntities(bundleFromStorage);
|
|
221
|
+
> // em2 now has a complete, faithful copy of the entities that were in em1
|
|
222
|
+
|
|
223
|
+
You can also control exactly which entities are exported.
|
|
224
|
+
> // get em1's unsaved changes (an array) and export them.
|
|
225
|
+
> let changes = em1.getChanges();
|
|
226
|
+
> let bundle = em1.exportEntities(changes);
|
|
227
|
+
> // merge these entities into em2 which may contains some of the same entities.
|
|
228
|
+
> // do NOT overwrite the entities in em2 if they themselves have unsaved changes.
|
|
229
|
+
> em2.importEntities(bundle, { mergeStrategy: MergeStrategy.PreserveChanges} );
|
|
230
|
+
|
|
231
|
+
Metadata are included in an export by default. You may want to exclude the metadata
|
|
232
|
+
especially if you're exporting just a few entities for local storage.
|
|
233
|
+
> let bundle = em1.exportEntities(arrayOfSelectedEntities, {includeMetadata: false});
|
|
234
|
+
> window.localStorage.setItem("goodStuff", bundle);
|
|
235
|
+
|
|
236
|
+
You may still express this option as a boolean value although this older syntax is deprecated.
|
|
237
|
+
> // Exclude the metadata (deprecated syntax)
|
|
238
|
+
> let bundle = em1.exportEntities(arrayOfSelectedEntities, false);
|
|
239
|
+
|
|
240
|
+
You can export all entities of one or more specified EntityTypes.
|
|
241
|
+
> // Export all Customer and Employee entities (and also exclude metadata)
|
|
242
|
+
> let bundle = em1.exportEntities(['Customer', 'Employee'], {includeMetadata: false});
|
|
243
|
+
|
|
244
|
+
All of the above examples return an export bundle as a string which is the default format.
|
|
245
|
+
You can export the bundle as JSON if you prefer by setting the `asString` option to false.
|
|
246
|
+
> // Export all Customer and Employee entities as JSON and exclude the metadata
|
|
247
|
+
> let bundle = em1.exportEntities(['Customer', 'Employee'],
|
|
248
|
+
> {asString: false, includeMetadata: false});
|
|
249
|
+
> // store JSON bundle somewhere ... perhaps indexDb ... and later import as we do here.
|
|
250
|
+
> em2.importEntities(bundle);
|
|
251
|
+
@param entities - The entities to export or the EntityType(s) of the entities to export;
|
|
252
|
+
all entities are exported if this parameter is omitted or null.
|
|
253
|
+
@param exportConfig - Export configuration options or a boolean
|
|
254
|
+
- asString - (boolean) - If true (default), return export bundle as a string.
|
|
255
|
+
- includeMetadata - (boolean) - If true (default), include metadata in the export bundle.
|
|
256
|
+
@return The export bundle either serialized as a string (default) or as a JSON object.
|
|
257
|
+
The bundle contains the metadata (unless excluded) and the entity data grouped by type.
|
|
258
|
+
The entity data include property values, change-state, and temporary key mappings (if any).
|
|
259
|
+
|
|
260
|
+
The export bundle internals are deliberately undocumented. This Breeze-internal representation of entity data is
|
|
261
|
+
suitable for export, storage, and import. The schema and contents of the bundle may change in future versions of Breeze.
|
|
262
|
+
Manipulate it at your own risk with appropriate caution.
|
|
263
|
+
**/
|
|
264
|
+
exportEntities(entities, exportConfig) {
|
|
265
|
+
assertParam(entities, "entities").isArray().isEntity()
|
|
266
|
+
.or().isNonEmptyArray().isInstanceOf(EntityType)
|
|
267
|
+
.or().isNonEmptyArray().isString()
|
|
268
|
+
.or().isOptional().check();
|
|
269
|
+
// assertParam(exportConfig, "exportConfig").isObject()
|
|
270
|
+
// .or().isBoolean()
|
|
271
|
+
// .or().isOptional().check();
|
|
272
|
+
if (exportConfig == null) {
|
|
273
|
+
exportConfig = { includeMetadata: true, asString: true };
|
|
274
|
+
}
|
|
275
|
+
else if (typeof exportConfig === 'boolean') { // deprecated
|
|
276
|
+
exportConfig = { includeMetadata: exportConfig, asString: true };
|
|
277
|
+
}
|
|
278
|
+
assertConfig(exportConfig)
|
|
279
|
+
.whereParam("asString").isBoolean().isOptional().withDefault(true)
|
|
280
|
+
.whereParam("includeMetadata").isBoolean().isOptional().withDefault(true)
|
|
281
|
+
.applyAll(exportConfig);
|
|
282
|
+
let exportBundle = exportEntityGroups(this, entities);
|
|
283
|
+
let json = core.extend({}, exportBundle, ["tempKeys", "entityGroupMap"]);
|
|
284
|
+
if (exportConfig.includeMetadata) {
|
|
285
|
+
json = core.extend(json, this, ["dataService", "saveOptions", "queryOptions", "validationOptions"]);
|
|
286
|
+
json.metadataStore = this.metadataStore.exportMetadata();
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
json.metadataVersion = MetadataStore.metadataVersion;
|
|
290
|
+
json.metadataStoreName = this.metadataStore.name;
|
|
291
|
+
}
|
|
292
|
+
let result = exportConfig.asString ? JSON.stringify(json, null, config.stringifyPad) : json;
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
Imports a previously exported result into this EntityManager.
|
|
297
|
+
|
|
298
|
+
This method can be used to make a complete copy of any previously created entityManager, even if created
|
|
299
|
+
in a previous session and stored in localStorage. The static version of this method performs a
|
|
300
|
+
very similar process.
|
|
301
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
302
|
+
> let bundle = em1.exportEntities();
|
|
303
|
+
> // bundle can be stored in window.localStorage or just held in memory.
|
|
304
|
+
> let em2 = new EntityManager({
|
|
305
|
+
> serviceName: em1.serviceName,
|
|
306
|
+
> metadataStore: em1.metadataStore
|
|
307
|
+
> });
|
|
308
|
+
> em2.importEntities(bundle);
|
|
309
|
+
> // em2 will now have a complete copy of what was in em1
|
|
310
|
+
|
|
311
|
+
It can also be used to merge the contents of a previously created EntityManager with an
|
|
312
|
+
existing EntityManager with control over how the two are merged.
|
|
313
|
+
> let bundle = em1.exportEntities();
|
|
314
|
+
> // assume em2 is another entityManager containing some of the same entities possibly with modifications.
|
|
315
|
+
> em2.importEntities(bundle, { mergeStrategy: MergeStrategy.PreserveChanges} );
|
|
316
|
+
> // em2 will now contain all of the entities from both em1 and em2. Any em2 entities with previously
|
|
317
|
+
> // made modifications will not have been touched, but all other entities from em1 will have been imported.
|
|
318
|
+
@param exportedString - The result of a previous 'export' call.
|
|
319
|
+
@param importConfig - A configuration object.
|
|
320
|
+
@param importConfig.mergeStrategy - A [[MergeStrategy]] to use when
|
|
321
|
+
merging into an existing EntityManager.
|
|
322
|
+
@param importConfig.metadataVersionFn - A function that takes two arguments (the current metadataVersion and the imported store's 'name')
|
|
323
|
+
and may be used to perform version checking.
|
|
324
|
+
@return result
|
|
325
|
+
- result.entities {Array of Entities} The entities that were imported.
|
|
326
|
+
- result.tempKeyMap {Object} Mapping from original EntityKey in the import bundle to its corresponding EntityKey in this EntityManager.
|
|
327
|
+
**/
|
|
328
|
+
importEntities(exported, importConfig) {
|
|
329
|
+
importConfig = importConfig || {};
|
|
330
|
+
assertConfig(importConfig)
|
|
331
|
+
.whereParam("mergeStrategy").isEnumOf(MergeStrategy).isOptional().withDefault(this.queryOptions.mergeStrategy)
|
|
332
|
+
.whereParam("metadataVersionFn").isFunction().isOptional()
|
|
333
|
+
.whereParam("mergeAdds").isBoolean().isOptional()
|
|
334
|
+
.applyAll(importConfig);
|
|
335
|
+
let json = (typeof exported === "string") ? JSON.parse(exported) : exported;
|
|
336
|
+
if (json.metadataStore) {
|
|
337
|
+
this.metadataStore.importMetadata(json.metadataStore);
|
|
338
|
+
// the || clause is for backwards compat with an earlier serialization format.
|
|
339
|
+
this.dataService = (json.dataService && DataService.fromJSON(json.dataService)) || new DataService({ serviceName: json.serviceName });
|
|
340
|
+
this.saveOptions = new SaveOptions(json.saveOptions);
|
|
341
|
+
this.queryOptions = QueryOptions.fromJSON(json.queryOptions);
|
|
342
|
+
this.validationOptions = new ValidationOptions(json.validationOptions);
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
importConfig.metadataVersionFn && importConfig.metadataVersionFn({
|
|
346
|
+
metadataVersion: json.metadataVersion,
|
|
347
|
+
metadataStoreName: json.metadataStoreName
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
let tempKeyMap = {};
|
|
351
|
+
json.tempKeys.forEach((k) => {
|
|
352
|
+
let oldKey = EntityKey.fromJSON(k, this.metadataStore);
|
|
353
|
+
// try to use oldKey if not already used in this keyGenerator.
|
|
354
|
+
tempKeyMap[oldKey.toString()] = new EntityKey(oldKey.entityType, this.keyGenerator.generateTempKeyValue(oldKey.entityType, oldKey.values[0]));
|
|
355
|
+
});
|
|
356
|
+
let entitiesToLink = [];
|
|
357
|
+
let impConfig = importConfig;
|
|
358
|
+
impConfig.tempKeyMap = tempKeyMap;
|
|
359
|
+
core.wrapExecution(() => {
|
|
360
|
+
this._pendingPubs = [];
|
|
361
|
+
}, (state) => {
|
|
362
|
+
this._pendingPubs.forEach((fn) => fn());
|
|
363
|
+
this._pendingPubs = undefined;
|
|
364
|
+
this._hasChangesAction && this._hasChangesAction();
|
|
365
|
+
}, () => {
|
|
366
|
+
core.objectForEach(json.entityGroupMap, (entityTypeName, jsonGroup) => {
|
|
367
|
+
let entityType = this.metadataStore._getStructuralType(entityTypeName, false);
|
|
368
|
+
let targetEntityGroup = findOrCreateEntityGroup(this, entityType);
|
|
369
|
+
let entities = importEntityGroup(targetEntityGroup, jsonGroup, impConfig);
|
|
370
|
+
if (entities && entities.length) {
|
|
371
|
+
entitiesToLink = entitiesToLink.concat(entities);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
entitiesToLink.forEach((entity) => {
|
|
375
|
+
if (!entity.entityAspect.entityState.isDeleted()) {
|
|
376
|
+
this._linkRelatedEntities(entity);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
return {
|
|
381
|
+
entities: entitiesToLink,
|
|
382
|
+
tempKeyMapping: tempKeyMap
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
Clears this EntityManager's cache but keeps all other settings. Note that this
|
|
387
|
+
method is not as fast as creating a new EntityManager via 'new EntityManager'.
|
|
388
|
+
This is because clear actually detaches all of the entities from the EntityManager.
|
|
389
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
390
|
+
> em1.clear();
|
|
391
|
+
> // em1 is will now contain no entities, but all other setting will be maintained.
|
|
392
|
+
**/
|
|
393
|
+
clear() {
|
|
394
|
+
core.objectMap(this._entityGroupMap, function (key, entityGroup) {
|
|
395
|
+
return entityGroup._checkOperation('clear');
|
|
396
|
+
}).forEach((entityGroup) => {
|
|
397
|
+
entityGroup._clear();
|
|
398
|
+
});
|
|
399
|
+
this._entityGroupMap = {};
|
|
400
|
+
this._unattachedChildrenMap = new UnattachedChildrenMap();
|
|
401
|
+
this.keyGenerator = new this.keyGeneratorCtor();
|
|
402
|
+
this.entityChanged.publish({ entityAction: EntityAction.Clear });
|
|
403
|
+
this._setHasChanges(false);
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
Creates an empty copy of this EntityManager but with the same DataService, MetadataStore, QueryOptions, SaveOptions, ValidationOptions, etc.
|
|
407
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
408
|
+
> let em2 = em1.createEmptyCopy();
|
|
409
|
+
> // em2 is a new EntityManager with all of em1's settings
|
|
410
|
+
> // but no entities.
|
|
411
|
+
@return A new EntityManager.
|
|
412
|
+
**/
|
|
413
|
+
createEmptyCopy() {
|
|
414
|
+
let copy = new EntityManager(core.extend({}, this, ["dataService", "metadataStore", "queryOptions", "saveOptions", "validationOptions", "keyGeneratorCtor"]));
|
|
415
|
+
return copy;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
Attaches an entity to this EntityManager with an [[EntityState]] of 'Added'.
|
|
419
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
420
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
421
|
+
> let cust1 = custType.createEntity();
|
|
422
|
+
> em1.addEntity(cust1);
|
|
423
|
+
|
|
424
|
+
Note that this is the same as using 'attachEntity' with an [[EntityState]] of 'Added'.
|
|
425
|
+
|
|
426
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
427
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
428
|
+
> let cust1 = custType.createEntity();
|
|
429
|
+
> em1.attachEntity(cust1, EntityState.Added);
|
|
430
|
+
@param entity - The entity to add.
|
|
431
|
+
@return The added entity.
|
|
432
|
+
**/
|
|
433
|
+
addEntity(entity) {
|
|
434
|
+
return this.attachEntity(entity, EntityState.Added);
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
Attaches an entity to this EntityManager with a specified [[EntityState]].
|
|
438
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
439
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
440
|
+
> let cust1 = custType.createEntity();
|
|
441
|
+
> em1.attachEntity(cust1, EntityState.Added);
|
|
442
|
+
@param entity - The entity to add.
|
|
443
|
+
@param entityState - (default=EntityState.Unchanged) The EntityState of the newly attached entity. If omitted this defaults to EntityState.Unchanged.
|
|
444
|
+
@param mergeStrategy - (default = MergeStrategy.Disallowed) How the specified entity should be merged into the EntityManager if this EntityManager already contains an entity with the same key.
|
|
445
|
+
@return The attached entity.
|
|
446
|
+
**/
|
|
447
|
+
attachEntity(entity, entityState, mergeStrategy) {
|
|
448
|
+
assertParam(entity, "entity").isRequired().check();
|
|
449
|
+
this.metadataStore._checkEntityType(entity);
|
|
450
|
+
let esSymbol = assertParam(entityState, "entityState").isEnumOf(EntityState).isOptional().check(EntityState.Unchanged);
|
|
451
|
+
let msSymbol = assertParam(mergeStrategy, "mergeStrategy").isEnumOf(MergeStrategy).isOptional().check(MergeStrategy.Disallowed);
|
|
452
|
+
if (entity.entityType.metadataStore !== this.metadataStore) {
|
|
453
|
+
throw new Error("Cannot attach this entity because the EntityType (" + entity.entityType.name +
|
|
454
|
+
") and MetadataStore associated with this entity does not match this EntityManager's MetadataStore.");
|
|
455
|
+
}
|
|
456
|
+
let aspect = entity.entityAspect;
|
|
457
|
+
if (aspect) {
|
|
458
|
+
// to avoid reattaching an entity in progress
|
|
459
|
+
if (aspect._inProcessEntity)
|
|
460
|
+
return aspect._inProcessEntity;
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
// this occur's when attaching an entity created via new instead of via createEntity.
|
|
464
|
+
aspect = new EntityAspect(entity);
|
|
465
|
+
}
|
|
466
|
+
let manager = aspect.entityManager;
|
|
467
|
+
if (manager) {
|
|
468
|
+
if (manager === this) {
|
|
469
|
+
return entity;
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
throw new Error("This entity already belongs to another EntityManager");
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
let attachedEntity = {};
|
|
476
|
+
core.using(this, "isLoading", true, () => {
|
|
477
|
+
if (esSymbol.isAdded()) {
|
|
478
|
+
checkEntityKey(this, entity);
|
|
479
|
+
}
|
|
480
|
+
// attachedEntity === entity EXCEPT in the case of a merge.
|
|
481
|
+
attachedEntity = this._attachEntityCore(entity, esSymbol, msSymbol);
|
|
482
|
+
aspect._inProcessEntity = attachedEntity;
|
|
483
|
+
try {
|
|
484
|
+
// entity ( not attachedEntity) is deliberate here.
|
|
485
|
+
attachRelatedEntities(this, entity, esSymbol, msSymbol);
|
|
486
|
+
}
|
|
487
|
+
finally {
|
|
488
|
+
// insure that _inProcessEntity is cleared.
|
|
489
|
+
aspect._inProcessEntity = undefined;
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
if (this.validationOptions.validateOnAttach) {
|
|
493
|
+
attachedEntity.entityAspect.validateEntity();
|
|
494
|
+
}
|
|
495
|
+
if (!esSymbol.isUnchanged()) {
|
|
496
|
+
this._notifyStateChange(attachedEntity, true);
|
|
497
|
+
}
|
|
498
|
+
this.entityChanged.publish({ entityAction: EntityAction.Attach, entity: attachedEntity });
|
|
499
|
+
return attachedEntity;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
Detaches an entity from this EntityManager.
|
|
503
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
504
|
+
> // assume cust1 is a customer Entity previously attached to em1
|
|
505
|
+
> em1.detachEntity(cust1);
|
|
506
|
+
> // em1 will now no longer contain cust1 and cust1 will have an
|
|
507
|
+
> // entityAspect.entityState of EntityState.Detached
|
|
508
|
+
@param entity - The entity to detach.
|
|
509
|
+
@return Whether the entity could be detached. This will return false if the entity is already detached or was never attached.
|
|
510
|
+
**/
|
|
511
|
+
detachEntity(entity) {
|
|
512
|
+
assertParam(entity, "entity").isEntity().check();
|
|
513
|
+
let aspect = entity.entityAspect;
|
|
514
|
+
if (!aspect) {
|
|
515
|
+
// no aspect means in couldn't appear in any group
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
if (aspect.entityManager !== this) {
|
|
519
|
+
throw new Error("This entity does not belong to this EntityManager.");
|
|
520
|
+
}
|
|
521
|
+
return aspect.setDetached();
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
Fetches the metadata associated with the EntityManager's current 'serviceName'. This call
|
|
525
|
+
occurs internally before the first query to any service if the metadata hasn't already been
|
|
526
|
+
loaded. __Async__
|
|
527
|
+
|
|
528
|
+
Usually you will not actually process the results of a fetchMetadata call directly, but will instead
|
|
529
|
+
ask for the metadata from the EntityManager after the fetchMetadata call returns.
|
|
530
|
+
> let em1 = new EntityManager( "breeze/NorthwindIBModel");
|
|
531
|
+
> em1.fetchMetadata()
|
|
532
|
+
> .then(function() {
|
|
533
|
+
> let metadataStore = em1.metadataStore;
|
|
534
|
+
> // do something with the metadata
|
|
535
|
+
> }).catch(function(exception) {
|
|
536
|
+
> // handle exception here
|
|
537
|
+
> });
|
|
538
|
+
|
|
539
|
+
@param callback - Function called on success.
|
|
540
|
+
@param errorCallback - Function called on failure.
|
|
541
|
+
@return {Promise}
|
|
542
|
+
- schema {Object} The raw Schema object from metadata provider - Because this schema will differ depending on the metadata provider
|
|
543
|
+
it is usually better to access metadata via the 'metadataStore' property of the EntityManager instead of using this 'raw' data.
|
|
544
|
+
**/
|
|
545
|
+
fetchMetadata(dataService, callback, errorCallback) {
|
|
546
|
+
if (typeof (dataService) === "function") {
|
|
547
|
+
// legacy support for when dataService was not an arg. i.e. first arg was callback
|
|
548
|
+
errorCallback = callback;
|
|
549
|
+
callback = dataService;
|
|
550
|
+
dataService = undefined;
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
assertParam(dataService, "dataService").isInstanceOf(DataService).isOptional().check();
|
|
554
|
+
assertParam(callback, "callback").isFunction().isOptional().check();
|
|
555
|
+
assertParam(errorCallback, "errorCallback").isFunction().isOptional().check();
|
|
556
|
+
}
|
|
557
|
+
let promise = this.metadataStore.fetchMetadata(dataService || this.dataService);
|
|
558
|
+
return promiseWithCallbacks(promise, callback, errorCallback);
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
Executes the specified query. __Async__
|
|
562
|
+
|
|
563
|
+
> let em = new EntityManager(serviceName);
|
|
564
|
+
> let query = new EntityQuery("Orders");
|
|
565
|
+
> em.executeQuery(query).then( function(data) {
|
|
566
|
+
> let orders = data.results;
|
|
567
|
+
> ... query results processed here
|
|
568
|
+
> }).catch( function(err) {
|
|
569
|
+
> ... query failure processed here
|
|
570
|
+
> });
|
|
571
|
+
|
|
572
|
+
or with callbacks
|
|
573
|
+
> let em = new EntityManager(serviceName);
|
|
574
|
+
> let query = new EntityQuery("Orders");
|
|
575
|
+
> em.executeQuery(query,
|
|
576
|
+
> function(data) {
|
|
577
|
+
> let orders = data.results;
|
|
578
|
+
> ... query results processed here
|
|
579
|
+
> },
|
|
580
|
+
> function(err) {
|
|
581
|
+
> ... query failure processed here
|
|
582
|
+
> });
|
|
583
|
+
|
|
584
|
+
Either way this method is the same as calling the The [[EntityQuery]] 'execute' method.
|
|
585
|
+
> let em = new EntityManager(serviceName);
|
|
586
|
+
> let query = new EntityQuery("Orders").using(em);
|
|
587
|
+
> query.execute().then( function(data) {
|
|
588
|
+
> let orders = data.results;
|
|
589
|
+
> ... query results processed here
|
|
590
|
+
> }).catch( function(err) {
|
|
591
|
+
> ... query failure processed here
|
|
592
|
+
> });
|
|
593
|
+
@param query - The [[EntityQuery]] or OData query string to execute.
|
|
594
|
+
@param callback - Function called on success.
|
|
595
|
+
@param errorCallback - {Function} Function called on failure.
|
|
596
|
+
@return Promise of
|
|
597
|
+
- results - An array of entities
|
|
598
|
+
- retrievedEntities - A array of all of the entities returned by the query. Differs from results (above) when .expand() is used.
|
|
599
|
+
- query - The original [[EntityQuery]] or query string
|
|
600
|
+
- entityManager - The EntityManager.
|
|
601
|
+
- httpResponse - The [[IHttpResponse]] returned from the server.
|
|
602
|
+
- inlineCount - Only available if 'inlineCount(true)' was applied to the query. Returns the count of
|
|
603
|
+
items that would have been returned by the query before applying any skip or take operators, but after any filter/where predicates
|
|
604
|
+
would have been applied.
|
|
605
|
+
**/
|
|
606
|
+
executeQuery(query, callback, errorCallback) {
|
|
607
|
+
assertParam(query, "query").isInstanceOf(EntityQuery).or().isString().check();
|
|
608
|
+
assertParam(callback, "callback").isFunction().isOptional().check();
|
|
609
|
+
assertParam(errorCallback, "errorCallback").isFunction().isOptional().check();
|
|
610
|
+
let promise;
|
|
611
|
+
// 'resolve' methods create a new typed object with all of its properties fully resolved against a list of sources.
|
|
612
|
+
// Thought about creating a 'normalized' query with these 'resolved' objects
|
|
613
|
+
// but decided not to because the 'query' may not be an EntityQuery (it can be a string) and hence might not have a queryOptions or dataServices property on it.
|
|
614
|
+
let queryOptions = QueryOptions.resolve([query.queryOptions, this.queryOptions, QueryOptions.defaultInstance]);
|
|
615
|
+
let dataService = DataService.resolve([query.dataService, this.dataService]);
|
|
616
|
+
if ((!dataService.hasServerMetadata) || this.metadataStore.hasMetadataFor(dataService.serviceName)) {
|
|
617
|
+
promise = executeQueryCore(this, query, queryOptions, dataService);
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
promise = this.fetchMetadata(dataService).then(() => {
|
|
621
|
+
return executeQueryCore(this, query, queryOptions, dataService);
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
return promiseWithCallbacks(promise, callback, errorCallback);
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
Executes the specified query against this EntityManager's local cache.
|
|
628
|
+
|
|
629
|
+
Because this method is executed immediately there is no need for a promise or a callback
|
|
630
|
+
> let em = new EntityManager(serviceName);
|
|
631
|
+
> let query = new EntityQuery("Orders");
|
|
632
|
+
> let orders = em.executeQueryLocally(query);
|
|
633
|
+
|
|
634
|
+
Note that this can also be accomplished using the 'executeQuery' method with
|
|
635
|
+
a FetchStrategy of FromLocalCache and making use of the Promise or callback
|
|
636
|
+
> let em = new EntityManager(serviceName);
|
|
637
|
+
> let query = new EntityQuery("Orders").using(FetchStrategy.FromLocalCache);
|
|
638
|
+
> em.executeQuery(query).then( function(data) {
|
|
639
|
+
> let orders = data.results;
|
|
640
|
+
> ... query results processed here
|
|
641
|
+
> }).catch( function(err) {
|
|
642
|
+
> ... query failure processed here
|
|
643
|
+
> });
|
|
644
|
+
@param query - The [[EntityQuery]] to execute.
|
|
645
|
+
@return {Array of Entity} Array of entities from cache that satisfy the query
|
|
646
|
+
**/
|
|
647
|
+
executeQueryLocally(query) {
|
|
648
|
+
return executeQueryLocallyCore(this, query).results;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
Saves either a list of specified entities or all changed entities within this EntityManager. If there are no changes to any of the entities
|
|
652
|
+
specified then there will be no server side call made but a valid 'empty' saveResult will still be returned. __Async__
|
|
653
|
+
|
|
654
|
+
Often we will be saving all of the entities within an EntityManager that are either added, modified or deleted
|
|
655
|
+
and we will let the 'saveChanges' call determine which entities these are.
|
|
656
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
657
|
+
> // This could include added, modified and deleted entities.
|
|
658
|
+
> em.saveChanges().then(function(saveResult) {
|
|
659
|
+
> let savedEntities = saveResult.entities;
|
|
660
|
+
> let keyMappings = saveResult.keyMappings;
|
|
661
|
+
> }).catch(function (e) {
|
|
662
|
+
> // e is any exception that was thrown.
|
|
663
|
+
> });
|
|
664
|
+
|
|
665
|
+
But we can also control exactly which entities to save and can specify specific SaveOptions
|
|
666
|
+
|
|
667
|
+
> // assume entitiesToSave is an array of entities to save.
|
|
668
|
+
> let saveOptions = new SaveOptions({ allowConcurrentSaves: true });
|
|
669
|
+
> em.saveChanges(entitiesToSave, saveOptions).then(function(saveResult) {
|
|
670
|
+
> let savedEntities = saveResult.entities;
|
|
671
|
+
> let keyMappings = saveResult.keyMappings;
|
|
672
|
+
> }).catch(function (e) {
|
|
673
|
+
> // e is any exception that was thrown.
|
|
674
|
+
> });
|
|
675
|
+
|
|
676
|
+
Callback methods can also be used
|
|
677
|
+
> em.saveChanges(entitiesToSave, null,
|
|
678
|
+
> function(saveResult) {
|
|
679
|
+
> let savedEntities = saveResult.entities;
|
|
680
|
+
> let keyMappings = saveResult.keyMappings;
|
|
681
|
+
> }, function (e) {
|
|
682
|
+
> // e is any exception that was thrown.
|
|
683
|
+
> }
|
|
684
|
+
> );
|
|
685
|
+
|
|
686
|
+
@param entities - The list of entities to save.
|
|
687
|
+
Every entity in that list will be sent to the server, whether changed or unchanged,
|
|
688
|
+
as long as it is attached to this EntityManager.
|
|
689
|
+
If this parameter is omitted, null or empty (the usual case),
|
|
690
|
+
every entity with pending changes in this EntityManager will be saved.
|
|
691
|
+
@param saveOptions - [[SaveOptions]] for the save - will default to
|
|
692
|
+
[[EntityManager.saveOptions]] if null.
|
|
693
|
+
@param callback - Function called on success.
|
|
694
|
+
@param errorCallback - Function called on failure.
|
|
695
|
+
@return {Promise} Promise
|
|
696
|
+
**/
|
|
697
|
+
saveChanges(entities, saveOptions, callback, errorCallback) {
|
|
698
|
+
assertParam(entities, "entities").isOptional().isArray().isEntity().check();
|
|
699
|
+
assertParam(saveOptions, "saveOptions").isInstanceOf(SaveOptions).isOptional().check();
|
|
700
|
+
assertParam(callback, "callback").isFunction().isOptional().check();
|
|
701
|
+
assertParam(errorCallback, "errorCallback").isFunction().isOptional().check();
|
|
702
|
+
saveOptions = saveOptions || this.saveOptions || SaveOptions.defaultInstance;
|
|
703
|
+
let entitiesToSave = getEntitiesToSave(this, entities ? entities : undefined);
|
|
704
|
+
if (entitiesToSave.length === 0) {
|
|
705
|
+
let result = { entities: [], keyMappings: [] };
|
|
706
|
+
if (callback)
|
|
707
|
+
callback(result);
|
|
708
|
+
return Promise.resolve(result);
|
|
709
|
+
}
|
|
710
|
+
if (!saveOptions.allowConcurrentSaves) {
|
|
711
|
+
let anyPendingSaves = entitiesToSave.some(function (entity) {
|
|
712
|
+
return entity.entityAspect.isBeingSaved;
|
|
713
|
+
});
|
|
714
|
+
if (anyPendingSaves) {
|
|
715
|
+
let err = new Error("Concurrent saves not allowed - SaveOptions.allowConcurrentSaves is false");
|
|
716
|
+
if (errorCallback)
|
|
717
|
+
errorCallback(err);
|
|
718
|
+
return Promise.reject(err);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
clearServerErrors(entitiesToSave);
|
|
722
|
+
let valError = this.saveChangesValidateOnClient(entitiesToSave);
|
|
723
|
+
if (valError) {
|
|
724
|
+
if (errorCallback)
|
|
725
|
+
errorCallback(valError);
|
|
726
|
+
return Promise.reject(valError);
|
|
727
|
+
}
|
|
728
|
+
let dataService = DataService.resolve([saveOptions.dataService, this.dataService]);
|
|
729
|
+
let saveContext = {
|
|
730
|
+
entityManager: this,
|
|
731
|
+
dataService: dataService,
|
|
732
|
+
processSavedEntities: processSavedEntities,
|
|
733
|
+
resourceName: saveOptions.resourceName || this.saveOptions.resourceName || "SaveChanges"
|
|
734
|
+
};
|
|
735
|
+
// TODO: need to check that if we are doing a partial save that all entities whose temp keys
|
|
736
|
+
// are referenced are also in the partial save group
|
|
737
|
+
let saveBundle = { entities: entitiesToSave, saveOptions: saveOptions };
|
|
738
|
+
try { // Guard against exception thrown in dataservice adapter before it goes async
|
|
739
|
+
updateConcurrencyProperties(entitiesToSave);
|
|
740
|
+
return dataService.adapterInstance.saveChanges(saveContext, saveBundle)
|
|
741
|
+
.then(saveSuccess).then((r) => r, saveFail);
|
|
742
|
+
}
|
|
743
|
+
catch (err) {
|
|
744
|
+
// undo the marking by updateConcurrencyProperties
|
|
745
|
+
markIsBeingSaved(entitiesToSave, false);
|
|
746
|
+
if (errorCallback)
|
|
747
|
+
errorCallback(err);
|
|
748
|
+
return Promise.reject(err);
|
|
749
|
+
}
|
|
750
|
+
function saveSuccess(saveResult) {
|
|
751
|
+
let em = saveContext.entityManager;
|
|
752
|
+
markIsBeingSaved(entitiesToSave, false);
|
|
753
|
+
let savedEntities = saveContext.processSavedEntities(saveResult);
|
|
754
|
+
saveResult.entities = savedEntities;
|
|
755
|
+
// update _hasChanges after save.
|
|
756
|
+
em._setHasChanges();
|
|
757
|
+
// can't do this anymore because other changes might have been made while saved entities in flight.
|
|
758
|
+
// let hasChanges = (isFullSave && haveSameContents(entitiesToSave, savedEntities)) ? false : null;
|
|
759
|
+
// em._setHasChanges(hasChanges);
|
|
760
|
+
if (callback)
|
|
761
|
+
callback(saveResult);
|
|
762
|
+
return Promise.resolve(saveResult);
|
|
763
|
+
}
|
|
764
|
+
function processSavedEntities(saveResult) {
|
|
765
|
+
let savedEntities = saveResult.entities;
|
|
766
|
+
let deletedKeys = saveResult.deletedKeys || [];
|
|
767
|
+
if (savedEntities.length === 0 && deletedKeys.length === 0) {
|
|
768
|
+
return [];
|
|
769
|
+
}
|
|
770
|
+
let keyMappings = saveResult.keyMappings;
|
|
771
|
+
let em = saveContext.entityManager;
|
|
772
|
+
// must occur outside of isLoading block
|
|
773
|
+
fixupKeys(em, keyMappings);
|
|
774
|
+
core.using(em, "isLoading", true, () => {
|
|
775
|
+
let mappingContext = new MappingContext({
|
|
776
|
+
query: undefined,
|
|
777
|
+
entityManager: em,
|
|
778
|
+
mergeOptions: { mergeStrategy: MergeStrategy.OverwriteChanges },
|
|
779
|
+
dataService: dataService
|
|
780
|
+
});
|
|
781
|
+
// The visitAndMerge operation has been optimized so that we do not actually perform a merge if the
|
|
782
|
+
// the save operation did not actually return the entity - i.e. during OData and Mongo updates and deletes.
|
|
783
|
+
savedEntities = mappingContext.visitAndMerge(savedEntities, { nodeType: "root" });
|
|
784
|
+
});
|
|
785
|
+
// detach any entities found in the em that appear in the deletedKeys list.
|
|
786
|
+
deletedKeys.forEach(key => {
|
|
787
|
+
let entityType = em.metadataStore._getStructuralType(key.entityTypeName);
|
|
788
|
+
let ekey = new EntityKey(entityType, key.keyValues);
|
|
789
|
+
let entity = em.getEntityByKey(ekey);
|
|
790
|
+
if (entity) {
|
|
791
|
+
entity.entityAspect.setDetached();
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
return savedEntities;
|
|
795
|
+
}
|
|
796
|
+
function saveFail(serverError) {
|
|
797
|
+
markIsBeingSaved(entitiesToSave, false);
|
|
798
|
+
let clientError = processServerErrors(saveContext, serverError);
|
|
799
|
+
if (errorCallback)
|
|
800
|
+
errorCallback(clientError);
|
|
801
|
+
return Promise.reject(clientError);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
Run the "saveChanges" pre-save client validation logic.
|
|
806
|
+
|
|
807
|
+
This is NOT a general purpose validation method.
|
|
808
|
+
It is intended for utilities that must know if saveChanges
|
|
809
|
+
would reject the save due to client validation errors.
|
|
810
|
+
|
|
811
|
+
It only validates entities if the EntityManager's
|
|
812
|
+
[[ValidationOptions]].validateOnSave is true.
|
|
813
|
+
|
|
814
|
+
@param entitiesToSave {Array of Entity} The list of entities to save (to validate).
|
|
815
|
+
@return {Error} Validation error or null if no error
|
|
816
|
+
**/
|
|
817
|
+
saveChangesValidateOnClient(entitiesToSave) {
|
|
818
|
+
if (this.validationOptions.validateOnSave) {
|
|
819
|
+
let failedEntities = entitiesToSave.filter(function (entity) {
|
|
820
|
+
let aspect = entity.entityAspect;
|
|
821
|
+
let isValid = aspect.entityState.isDeleted() || aspect.validateEntity();
|
|
822
|
+
return !isValid;
|
|
823
|
+
});
|
|
824
|
+
if (failedEntities.length > 0) {
|
|
825
|
+
let valError = new Error("Client side validation errors encountered - see the entityErrors collection on this object for more detail");
|
|
826
|
+
valError.entityErrors = createEntityErrors(failedEntities);
|
|
827
|
+
return valError; // TODO: type this.
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
return null;
|
|
831
|
+
}
|
|
832
|
+
/** @hidden @internal */
|
|
833
|
+
_findEntityGroup(entityType) {
|
|
834
|
+
return this._entityGroupMap[entityType.name];
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
Attempts to locate an entity within this EntityManager by its [EntityKey].
|
|
838
|
+
@param entityKey - The [[EntityKey]] of the Entity to be located.
|
|
839
|
+
@param type - The [[EntityType]] for this key.
|
|
840
|
+
@param typeName - The EntityType name for this key.
|
|
841
|
+
@param keyValues - The values for this key - will usually just be a single value; an array is only needed for multipart keys.
|
|
842
|
+
@return An Entity or null;
|
|
843
|
+
**/
|
|
844
|
+
getEntityByKey(...args) {
|
|
845
|
+
let entityKey = createEntityKey(this, args).entityKey;
|
|
846
|
+
let entityTypes = entityKey._subtypes || [entityKey.entityType];
|
|
847
|
+
let e;
|
|
848
|
+
// hack use of some to simulate mapFirst logic.
|
|
849
|
+
entityTypes.some((et) => {
|
|
850
|
+
let group = this._findEntityGroup(et);
|
|
851
|
+
// group version of findEntityByKey doesn't care about entityType
|
|
852
|
+
e = group && group.findEntityByKey(entityKey);
|
|
853
|
+
return e != null;
|
|
854
|
+
});
|
|
855
|
+
return e || null;
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
Attempts to fetch an entity from the server by its [[EntityKey]] with
|
|
859
|
+
an option to check the local cache first. Note the this EntityManager's queryOptions.mergeStrategy
|
|
860
|
+
will be used to merge any server side entity returned by this method.
|
|
861
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
862
|
+
> let employeeType = em1.metadataStore.getEntityType("Employee");
|
|
863
|
+
> let employeeKey = new EntityKey(employeeType, 1);
|
|
864
|
+
> em1.fetchEntityByKey(employeeKey).then(function(result) {
|
|
865
|
+
> let employee = result.entity;
|
|
866
|
+
> let entityKey = result.entityKey;
|
|
867
|
+
> let fromCache = result.fromCache;
|
|
868
|
+
> });
|
|
869
|
+
@param typeName - The EntityType name for this key.
|
|
870
|
+
@param entityType - The EntityType for this key.
|
|
871
|
+
@param keyValues - The values for this key - will usually just be a single value; an array is only needed for multipart keys.
|
|
872
|
+
@param entityKey - The [[EntityKey]] of the Entity to be located.
|
|
873
|
+
@param checkLocalCacheFirst - (default = false) - Whether to check this EntityManager first before going to the server. By default, the query will NOT do this.
|
|
874
|
+
@return {Promise}
|
|
875
|
+
- Properties on the promise success result
|
|
876
|
+
- entity {Object} The entity returned or null
|
|
877
|
+
- entityKey {EntityKey} The entityKey of the entity to fetch.
|
|
878
|
+
- fromCache {Boolean} Whether this entity was fetched from the server or was found in the local cache.
|
|
879
|
+
**/
|
|
880
|
+
fetchEntityByKey(...args) {
|
|
881
|
+
let dataService = DataService.resolve([this.dataService]);
|
|
882
|
+
if ((!dataService.hasServerMetadata) || this.metadataStore.hasMetadataFor(dataService.serviceName)) {
|
|
883
|
+
return fetchEntityByKeyCore(this, args);
|
|
884
|
+
}
|
|
885
|
+
else {
|
|
886
|
+
return this.fetchMetadata(dataService).then(() => {
|
|
887
|
+
return fetchEntityByKeyCore(this, args);
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
[Deprecated] - Attempts to locate an entity within this EntityManager by its [[EntityKey]].
|
|
893
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
894
|
+
> let employeeType = em1.metadataStore.getEntityType("Employee");
|
|
895
|
+
> let employeeKey = new EntityKey(employeeType, 1);
|
|
896
|
+
> let employee = em1.findEntityByKey(employeeKey);
|
|
897
|
+
> // employee will either be an entity or null.
|
|
898
|
+
@deprecated Use getEntityByKey instead
|
|
899
|
+
@param entityKey - The [[EntityKey]] of the Entity to be located.
|
|
900
|
+
@return An Entity or null;
|
|
901
|
+
**/
|
|
902
|
+
findEntityByKey(entityKey) {
|
|
903
|
+
return this.getEntityByKey(entityKey);
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
Generates a temporary key for the specified entity. This is used to insure that newly
|
|
907
|
+
created entities have unique keys and to register that these keys are temporary and
|
|
908
|
+
need to be automatically replaced with 'real' key values once these entities are saved.
|
|
909
|
+
|
|
910
|
+
The [[EntityManager.keyGeneratorCtor]] property is used internally by this method to actually generate
|
|
911
|
+
the keys - See the KeyGenerator interface interface description to see
|
|
912
|
+
how a custom key generator can be plugged in.
|
|
913
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
914
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
915
|
+
> let customer = custType.createEntity();
|
|
916
|
+
> let customerId = em.generateTempKeyValue(customer);
|
|
917
|
+
> // The 'customer' entity 'CustomerID' property is now set to a newly generated unique id value
|
|
918
|
+
> // This property will change again after a successful save of the 'customer' entity.
|
|
919
|
+
>
|
|
920
|
+
> em1.saveChanges().then( function( data) {
|
|
921
|
+
> let sameCust1 = data.results[0];
|
|
922
|
+
> // cust1 === sameCust1;
|
|
923
|
+
> // but cust1.getProperty("CustomerId") != customerId
|
|
924
|
+
> // because the server will have generated a new id
|
|
925
|
+
> // and the client will have been updated with this
|
|
926
|
+
> // new id.
|
|
927
|
+
> })
|
|
928
|
+
@param entity - The Entity to generate a key for.
|
|
929
|
+
@return The new key value
|
|
930
|
+
**/
|
|
931
|
+
generateTempKeyValue(entity) {
|
|
932
|
+
// TODO - check if this entity is attached to this EntityManager.
|
|
933
|
+
assertParam(entity, "entity").isEntity().check();
|
|
934
|
+
let entityType = entity.entityType;
|
|
935
|
+
let nextKeyValue = this.keyGenerator.generateTempKeyValue(entityType);
|
|
936
|
+
let keyProp = entityType.keyProperties[0];
|
|
937
|
+
entity.setProperty(keyProp.name, nextKeyValue);
|
|
938
|
+
entity.entityAspect.hasTempKey = true;
|
|
939
|
+
return nextKeyValue;
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
Returns whether there are any changed entities of the specified [[EntityType]]s. A 'changed' Entity has
|
|
943
|
+
has an [[EntityState]] of either Added, Modified or Deleted.
|
|
944
|
+
|
|
945
|
+
This method can be used to determine if an EntityManager has any changes
|
|
946
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
947
|
+
> if ( em1.hasChanges() {
|
|
948
|
+
> // do something interesting
|
|
949
|
+
> }
|
|
950
|
+
|
|
951
|
+
or if it has any changes on to a specific [[EntityType]].
|
|
952
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
953
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
954
|
+
> if ( em1.hasChanges(custType) {
|
|
955
|
+
> // do something interesting
|
|
956
|
+
> }
|
|
957
|
+
|
|
958
|
+
or to a collection of [[EntityType]]s
|
|
959
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
960
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
961
|
+
> let orderType = em1.metadataStore.getEntityType("Order");
|
|
962
|
+
> if ( em1.hasChanges( [custType, orderType]) {
|
|
963
|
+
> // do something interesting
|
|
964
|
+
> }
|
|
965
|
+
@param entityTypes - The [[EntityType]] or EntityTypes for which 'changed' entities will be found.
|
|
966
|
+
@param entityTypeNames - The [[EntityType]] name or names for which 'changed' entities will be found.
|
|
967
|
+
@return Whether there are any changed entities that match the types specified..
|
|
968
|
+
**/
|
|
969
|
+
hasChanges(entityTypes) {
|
|
970
|
+
if (!this._hasChanges)
|
|
971
|
+
return false;
|
|
972
|
+
if (entityTypes === undefined)
|
|
973
|
+
return this._hasChanges;
|
|
974
|
+
return this._hasChangesCore(entityTypes);
|
|
975
|
+
}
|
|
976
|
+
/** @hidden @internal */
|
|
977
|
+
// backdoor to "really" check for changes.
|
|
978
|
+
_hasChangesCore(entityTypes) {
|
|
979
|
+
let ets = checkEntityTypes(this, entityTypes);
|
|
980
|
+
let entityGroups = getEntityGroups(this, ets);
|
|
981
|
+
return entityGroups.some(function (eg) {
|
|
982
|
+
return eg && eg.hasChanges();
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
Returns a array of all changed entities of the specified [[EntityType]]s. A 'changed' Entity has
|
|
987
|
+
has an [[EntityState]] of either Added, Modified or Deleted.
|
|
988
|
+
|
|
989
|
+
This method can be used to get all of the changed entities within an EntityManager
|
|
990
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
991
|
+
> let changedEntities = em1.getChanges();
|
|
992
|
+
|
|
993
|
+
or you can specify that you only want the changes on a specific [[EntityType]]
|
|
994
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
995
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
996
|
+
> let changedCustomers = em1.getChanges(custType);
|
|
997
|
+
|
|
998
|
+
or to a collection of [[EntityType]]s
|
|
999
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
1000
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
1001
|
+
> let orderType = em1.metadataStore.getEntityType("Order");
|
|
1002
|
+
> let changedCustomersAndOrders = em1.getChanges([custType, orderType]);
|
|
1003
|
+
@param entityTypes - The [[EntityType]] or EntityTypes for which 'changed' entities will be found.
|
|
1004
|
+
@param entityTypeNames - The [[EntityType]] name or names for which 'changed' entities will be found.
|
|
1005
|
+
@return An array of Entities
|
|
1006
|
+
**/
|
|
1007
|
+
getChanges(entityTypes) {
|
|
1008
|
+
let ets = checkEntityTypes(this, entityTypes);
|
|
1009
|
+
return getChangesCore(this, ets);
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
Rejects (reverses the effects) all of the additions, modifications and deletes from this EntityManager.
|
|
1013
|
+
Calls [[EntityAspect.rejectChanges]] on every changed entity in this EntityManager.
|
|
1014
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
1015
|
+
> let entities = em1.rejectChanges();
|
|
1016
|
+
@return The entities whose changes were rejected. These entities will all have EntityStates of
|
|
1017
|
+
either 'Unchanged' or 'Detached'
|
|
1018
|
+
**/
|
|
1019
|
+
rejectChanges() {
|
|
1020
|
+
if (!this._hasChanges)
|
|
1021
|
+
return [];
|
|
1022
|
+
let changes = getChangesCore(this);
|
|
1023
|
+
// next line stops individual reject changes from each calling _hasChangesCore
|
|
1024
|
+
let aspects = changes.map(function (e) {
|
|
1025
|
+
return e.entityAspect._checkOperation("rejectChanges");
|
|
1026
|
+
});
|
|
1027
|
+
this._hasChanges = false;
|
|
1028
|
+
aspects.forEach(function (aspect) {
|
|
1029
|
+
aspect.rejectChanges();
|
|
1030
|
+
});
|
|
1031
|
+
this.hasChangesChanged.publish({ entityManager: this, hasChanges: false });
|
|
1032
|
+
return changes;
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
Returns a array of all entities of the specified [[EntityType]]s with the specified [[EntityState]]s.
|
|
1036
|
+
|
|
1037
|
+
This method can be used to get all of the entities within an EntityManager
|
|
1038
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
1039
|
+
> let entities = em1.getEntities();
|
|
1040
|
+
|
|
1041
|
+
or you can specify that you only want the changes on a specific [[EntityType]]
|
|
1042
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
1043
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
1044
|
+
> let customers = em1.getEntities(custType);
|
|
1045
|
+
|
|
1046
|
+
or to a collection of [[EntityType]]s
|
|
1047
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
1048
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
1049
|
+
> let orderType = em1.metadataStore.getEntityType("Order");
|
|
1050
|
+
> let customersAndOrders = em1.getChanges([custType, orderType]);
|
|
1051
|
+
|
|
1052
|
+
You can also ask for entities with a particular [[EntityState]] or EntityStates.
|
|
1053
|
+
> // assume em1 is an EntityManager containing a number of preexisting entities.
|
|
1054
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
1055
|
+
> let orderType = em1.metadataStore.getEntityType("Order");
|
|
1056
|
+
> let addedCustomersAndOrders = em1.getEntities([custType, orderType], EntityState.Added);
|
|
1057
|
+
|
|
1058
|
+
@param entityTypeName - The [[EntityType]] name or names for which entities will be found.
|
|
1059
|
+
If this parameter is omitted, all EntityTypes are searched.
|
|
1060
|
+
@param entityTypes - The [[EntityType]] or EntityTypes for which entities will be found.
|
|
1061
|
+
If this parameter is omitted, all EntityTypes are searched.
|
|
1062
|
+
@param entityStates - The [[EntityState]]s for which entities will be found.
|
|
1063
|
+
If this parameter is omitted, entities of all EntityStates are returned.
|
|
1064
|
+
@return An array of Entities
|
|
1065
|
+
**/
|
|
1066
|
+
getEntities(entityTypes, entityStates) {
|
|
1067
|
+
let entTypes = checkEntityTypes(this, entityTypes);
|
|
1068
|
+
assertParam(entityStates, "entityStates").isOptional().isEnumOf(EntityState).or().isNonEmptyArray().isEnumOf(EntityState).check();
|
|
1069
|
+
let states = validateEntityStates(this, entityStates);
|
|
1070
|
+
return getEntitiesCore(this, entTypes, states);
|
|
1071
|
+
}
|
|
1072
|
+
// protected methods
|
|
1073
|
+
/** @hidden @internal */
|
|
1074
|
+
_notifyStateChange(entity, needsSave) {
|
|
1075
|
+
let ecArgs = { entityAction: EntityAction.EntityStateChange, entity: entity };
|
|
1076
|
+
if (needsSave) {
|
|
1077
|
+
if (!this._hasChanges)
|
|
1078
|
+
this._setHasChanges(true);
|
|
1079
|
+
}
|
|
1080
|
+
else {
|
|
1081
|
+
// called when rejecting a change or merging an unchanged record.
|
|
1082
|
+
// NOTE: this can be slow with lots of entities in the cache.
|
|
1083
|
+
// so defer it during a query/import or save and call it once when complete ( if needed).
|
|
1084
|
+
if (this._hasChanges) {
|
|
1085
|
+
if (this.isLoading) {
|
|
1086
|
+
this._hasChangesAction = this._hasChangesAction || function () {
|
|
1087
|
+
this._setHasChanges(null);
|
|
1088
|
+
this.entityChanged.publish(ecArgs);
|
|
1089
|
+
}.bind(this);
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
else {
|
|
1093
|
+
this._setHasChanges();
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
this.entityChanged.publish(ecArgs);
|
|
1098
|
+
}
|
|
1099
|
+
/** @hidden @internal */
|
|
1100
|
+
_setHasChanges(hasChanges) {
|
|
1101
|
+
if (hasChanges == null)
|
|
1102
|
+
hasChanges = this._hasChangesCore();
|
|
1103
|
+
let hadChanges = this._hasChanges;
|
|
1104
|
+
this._hasChanges = hasChanges;
|
|
1105
|
+
if (hasChanges !== hadChanges) {
|
|
1106
|
+
this.hasChangesChanged.publish({ entityManager: this, hasChanges: hasChanges });
|
|
1107
|
+
}
|
|
1108
|
+
this._hasChangesAction = undefined;
|
|
1109
|
+
}
|
|
1110
|
+
/** @hidden @internal */
|
|
1111
|
+
_linkRelatedEntities(entity) {
|
|
1112
|
+
let em = this;
|
|
1113
|
+
let entityAspect = entity.entityAspect;
|
|
1114
|
+
// we do not want entityState to change as a result of linkage.
|
|
1115
|
+
core.using(em, "isLoading", true, function () {
|
|
1116
|
+
let unattachedMap = em._unattachedChildrenMap;
|
|
1117
|
+
let entityKey = entityAspect.getKey();
|
|
1118
|
+
let entityType = entityKey.entityType;
|
|
1119
|
+
while (entityType) {
|
|
1120
|
+
let keystring = entityKey.toString(entityType);
|
|
1121
|
+
// attach any unattachedChildren
|
|
1122
|
+
let tuples = unattachedMap.getTuplesByString(keystring);
|
|
1123
|
+
if (tuples) {
|
|
1124
|
+
tuples.slice(0).forEach(function (tpl) {
|
|
1125
|
+
let unattachedChildren = tpl.children.filter(function (e) {
|
|
1126
|
+
return e.entityAspect.entityState !== EntityState.Detached;
|
|
1127
|
+
});
|
|
1128
|
+
let childToParentNp;
|
|
1129
|
+
let parentToChildNp;
|
|
1130
|
+
// np is usually childToParentNp
|
|
1131
|
+
// except with unidirectional 1-n where it is parentToChildNp;
|
|
1132
|
+
let np = tpl.navigationProperty;
|
|
1133
|
+
let inverseNp = np.inverse;
|
|
1134
|
+
if (inverseNp) {
|
|
1135
|
+
// bidirectional
|
|
1136
|
+
childToParentNp = np;
|
|
1137
|
+
parentToChildNp = inverseNp;
|
|
1138
|
+
if (parentToChildNp.isScalar) {
|
|
1139
|
+
let onlyChild = unattachedChildren[0];
|
|
1140
|
+
entity.setProperty(parentToChildNp.name, onlyChild);
|
|
1141
|
+
onlyChild.setProperty(childToParentNp.name, entity);
|
|
1142
|
+
}
|
|
1143
|
+
else {
|
|
1144
|
+
let currentChildren = entity.getProperty(parentToChildNp.name);
|
|
1145
|
+
unattachedChildren.forEach(function (child) {
|
|
1146
|
+
currentChildren.push(child);
|
|
1147
|
+
child.setProperty(childToParentNp.name, entity);
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
unattachedMap.removeChildren(keystring, childToParentNp);
|
|
1151
|
+
}
|
|
1152
|
+
else {
|
|
1153
|
+
// unidirectional
|
|
1154
|
+
// if (np.isScalar || np.parentType !== entity.entityType) {
|
|
1155
|
+
if (np.isScalar) {
|
|
1156
|
+
// n -> 1 eg: child: OrderDetail parent: Product
|
|
1157
|
+
// 1 -> 1 eg child: Employee parent: Employee ( only Manager, no DirectReports property)
|
|
1158
|
+
childToParentNp = np;
|
|
1159
|
+
unattachedChildren.forEach(function (child) {
|
|
1160
|
+
child.setProperty(childToParentNp.name, entity);
|
|
1161
|
+
});
|
|
1162
|
+
unattachedMap.removeChildren(keystring, childToParentNp);
|
|
1163
|
+
}
|
|
1164
|
+
else {
|
|
1165
|
+
// 1 -> n eg: parent: Region child: Terr
|
|
1166
|
+
// TODO: need to remove unattached children from the map after this; only a perf issue.
|
|
1167
|
+
parentToChildNp = np;
|
|
1168
|
+
let currentChildren = entity.getProperty(parentToChildNp.name);
|
|
1169
|
+
unattachedChildren.forEach(function (child) {
|
|
1170
|
+
// we know if can't already be there.
|
|
1171
|
+
currentChildren._push(child);
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
entityType = entityType.baseEntityType; // look for relationships up the hierarchy
|
|
1178
|
+
}
|
|
1179
|
+
// now add to unattachedMap if needed.
|
|
1180
|
+
entity.entityType.navigationProperties.forEach(function (np) {
|
|
1181
|
+
if (np.isScalar) {
|
|
1182
|
+
let value = entity.getProperty(np.name);
|
|
1183
|
+
// property is already linked up
|
|
1184
|
+
if (value)
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
// first determine if np contains a parent or child
|
|
1188
|
+
// having a parentKey means that this is a child
|
|
1189
|
+
// if a parent then no need for more work because children will attach to it.
|
|
1190
|
+
let parentKey = entityAspect.getParentKey(np);
|
|
1191
|
+
if (parentKey) {
|
|
1192
|
+
// check for empty keys - meaning that parent id's are not yet set.
|
|
1193
|
+
if (parentKey._isEmpty())
|
|
1194
|
+
return;
|
|
1195
|
+
// if a child - look for parent in the em cache
|
|
1196
|
+
if (np.invForeignKeyNames.length) {
|
|
1197
|
+
// np relates to non-PK property of parent entity
|
|
1198
|
+
const query = new EntityQuery(parentKey.entityType.defaultResourceName).where(np.invForeignKeyNames[0], 'eq', parentKey.values[0]);
|
|
1199
|
+
const qresult = em.executeQueryLocally(query);
|
|
1200
|
+
if (qresult.length === 1) {
|
|
1201
|
+
let parent = qresult[0];
|
|
1202
|
+
entity.setProperty(np.name, parent);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
else {
|
|
1206
|
+
// np relates to PK of parent entity
|
|
1207
|
+
let parent = em.getEntityByKey(parentKey);
|
|
1208
|
+
if (parent) {
|
|
1209
|
+
// if found hook it up
|
|
1210
|
+
entity.setProperty(np.name, parent);
|
|
1211
|
+
}
|
|
1212
|
+
else {
|
|
1213
|
+
// else add parent to unresolvedParentMap;
|
|
1214
|
+
unattachedMap.addChild(parentKey, np, entity);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
else if (np.inverse && np.inverse.invForeignKeyNames.length) {
|
|
1219
|
+
// np relates to non-PK property of parent entity; query entities by FK
|
|
1220
|
+
const akValue = entity.getProperty(np.inverse.invForeignKeyNames[0]);
|
|
1221
|
+
const query = new EntityQuery(np.entityType.defaultResourceName).where(np.invForeignKeyNames[0], 'eq', akValue);
|
|
1222
|
+
const qresult = em.executeQueryLocally(query);
|
|
1223
|
+
qresult.forEach((child) => {
|
|
1224
|
+
child.setProperty(np.inverse.name, entity);
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
});
|
|
1228
|
+
// handle unidirectional 1-x where we set x.fk
|
|
1229
|
+
entity.entityType.foreignKeyProperties.forEach(function (fkProp) {
|
|
1230
|
+
let invNp = fkProp.inverseNavigationProperty;
|
|
1231
|
+
if (!invNp)
|
|
1232
|
+
return;
|
|
1233
|
+
// unidirectional fk props only
|
|
1234
|
+
let fkValue = entity.getProperty(fkProp.name);
|
|
1235
|
+
let parentKey = new EntityKey(invNp.parentType, [fkValue]);
|
|
1236
|
+
let parent = em.getEntityByKey(parentKey);
|
|
1237
|
+
if (parent) {
|
|
1238
|
+
if (invNp.isScalar) {
|
|
1239
|
+
parent.setProperty(invNp.name, entity);
|
|
1240
|
+
}
|
|
1241
|
+
else {
|
|
1242
|
+
if (em.isLoading) {
|
|
1243
|
+
parent.getProperty(invNp.name)._push(entity);
|
|
1244
|
+
}
|
|
1245
|
+
else {
|
|
1246
|
+
parent.getProperty(invNp.name).push(entity);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
else {
|
|
1251
|
+
// else add parent to unresolvedParentMap;
|
|
1252
|
+
unattachedMap.addChild(parentKey, invNp, entity);
|
|
1253
|
+
}
|
|
1254
|
+
});
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
/** @hidden @internal */
|
|
1258
|
+
_attachEntityCore(entity, entityState, mergeStrategy) {
|
|
1259
|
+
let group = findOrCreateEntityGroup(this, entity.entityType);
|
|
1260
|
+
let attachedEntity = group.attachEntity(entity, entityState, mergeStrategy);
|
|
1261
|
+
this._linkRelatedEntities(attachedEntity);
|
|
1262
|
+
return attachedEntity;
|
|
1263
|
+
}
|
|
1264
|
+
/** @hidden @internal */
|
|
1265
|
+
_updateFkVal(fkProp, oldValue, newValue) {
|
|
1266
|
+
let group = this._entityGroupMap[fkProp.parentType.name];
|
|
1267
|
+
if (!group)
|
|
1268
|
+
return;
|
|
1269
|
+
group._updateFkVal(fkProp, oldValue, newValue);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
EntityManager.prototype._$typeName = "EntityManager";
|
|
1273
|
+
BreezeEvent.bubbleEvent(EntityManager.prototype);
|
|
1274
|
+
function clearServerErrors(entities) {
|
|
1275
|
+
entities.forEach(function (entity) {
|
|
1276
|
+
let serverKeys = [];
|
|
1277
|
+
let aspect = entity.entityAspect;
|
|
1278
|
+
core.objectForEach(aspect._validationErrors, function (key, ve) {
|
|
1279
|
+
if (ve.isServerError)
|
|
1280
|
+
serverKeys.push(key);
|
|
1281
|
+
});
|
|
1282
|
+
if (serverKeys.length === 0)
|
|
1283
|
+
return;
|
|
1284
|
+
aspect._processValidationOpAndPublish(function () {
|
|
1285
|
+
serverKeys.forEach(function (key) {
|
|
1286
|
+
aspect._removeValidationError(key);
|
|
1287
|
+
});
|
|
1288
|
+
});
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
function createEntityErrors(entities) {
|
|
1292
|
+
let entityErrors = [];
|
|
1293
|
+
entities.forEach((entity) => {
|
|
1294
|
+
core.objectForEach(entity.entityAspect._validationErrors, function (key, ve) {
|
|
1295
|
+
let cfg = core.extend({
|
|
1296
|
+
entity: entity,
|
|
1297
|
+
errorName: ve.validator.name
|
|
1298
|
+
}, ve, ["errorMessage", "propertyName", "isServerError", "custom"]);
|
|
1299
|
+
entityErrors.push(cfg);
|
|
1300
|
+
});
|
|
1301
|
+
});
|
|
1302
|
+
return entityErrors;
|
|
1303
|
+
}
|
|
1304
|
+
function processServerErrors(saveContext, saveError) {
|
|
1305
|
+
// converting ISaveErrorFromServer -> ISaveError
|
|
1306
|
+
let serverErrors = saveError.entityErrors;
|
|
1307
|
+
if (!serverErrors)
|
|
1308
|
+
return saveError;
|
|
1309
|
+
let entityManager = saveContext.entityManager;
|
|
1310
|
+
let metadataStore = entityManager.metadataStore;
|
|
1311
|
+
let entityErrors = serverErrors.map((serr) => {
|
|
1312
|
+
let entity = null;
|
|
1313
|
+
let entityType;
|
|
1314
|
+
if (serr.keyValues) {
|
|
1315
|
+
entityType = metadataStore._getStructuralType(serr.entityTypeName);
|
|
1316
|
+
let ekey = new EntityKey(entityType, serr.keyValues);
|
|
1317
|
+
entity = entityManager.getEntityByKey(ekey);
|
|
1318
|
+
}
|
|
1319
|
+
if (entityType && entity) {
|
|
1320
|
+
let context = serr.propertyName ?
|
|
1321
|
+
{
|
|
1322
|
+
propertyName: serr.propertyName,
|
|
1323
|
+
property: entityType.getProperty(serr.propertyName)
|
|
1324
|
+
} : {};
|
|
1325
|
+
let key = ValidationError.getKey(serr.errorName || serr.errorMessage, serr.propertyName);
|
|
1326
|
+
let ve = new ValidationError(null, context, serr.errorMessage, key);
|
|
1327
|
+
ve.isServerError = true;
|
|
1328
|
+
entity.entityAspect.addValidationError(ve);
|
|
1329
|
+
}
|
|
1330
|
+
let entityError = core.extend({
|
|
1331
|
+
entity: entity,
|
|
1332
|
+
isServerError: true
|
|
1333
|
+
}, serr, ["errorName", "errorMessage", "propertyName", "custom"]);
|
|
1334
|
+
return entityError;
|
|
1335
|
+
});
|
|
1336
|
+
// converting ISaveErrorFromServer -> ISaveError
|
|
1337
|
+
saveError.entityErrors = entityErrors;
|
|
1338
|
+
return saveError;
|
|
1339
|
+
}
|
|
1340
|
+
function fetchEntityByKeyCore(em, args) {
|
|
1341
|
+
let tpl = createEntityKey(em, args);
|
|
1342
|
+
let entityKey = tpl.entityKey;
|
|
1343
|
+
let checkLocalCacheFirst = tpl.remainingArgs.length === 0 ? false : !!tpl.remainingArgs[0];
|
|
1344
|
+
let entity = null;
|
|
1345
|
+
let foundIt = false;
|
|
1346
|
+
if (checkLocalCacheFirst) {
|
|
1347
|
+
entity = em.getEntityByKey(entityKey);
|
|
1348
|
+
foundIt = entity != null;
|
|
1349
|
+
if (entity != null &&
|
|
1350
|
+
// null the entity if it is deleted and we should exclude deleted entities
|
|
1351
|
+
!em.queryOptions.includeDeleted && entity.entityAspect.entityState.isDeleted()) {
|
|
1352
|
+
entity = null;
|
|
1353
|
+
// but resume looking if we'd overwrite deleted entity with a remote entity
|
|
1354
|
+
// note: em.queryOptions is always fully resolved by now
|
|
1355
|
+
foundIt = em.queryOptions.mergeStrategy !== MergeStrategy.OverwriteChanges;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
if (foundIt) {
|
|
1359
|
+
return Promise.resolve({ entity: entity || undefined, entityKey: entityKey, fromCache: true });
|
|
1360
|
+
}
|
|
1361
|
+
else {
|
|
1362
|
+
return EntityQuery.fromEntityKey(entityKey).using(em).execute().then(function (data) {
|
|
1363
|
+
entity = (data.results.length === 0) ? null : data.results[0];
|
|
1364
|
+
return Promise.resolve({ entity: entity || undefined, entityKey: entityKey, fromCache: false });
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
// private fns
|
|
1369
|
+
// takes in entityTypes as either strings or entityTypes or arrays of either
|
|
1370
|
+
// and returns either an entityType or an array of entityTypes or throws an error
|
|
1371
|
+
function checkEntityTypes(em, entityTypes) {
|
|
1372
|
+
assertParam(entityTypes, "entityTypes").isString().isOptional().or().isNonEmptyArray().isString()
|
|
1373
|
+
.or().isInstanceOf(EntityType).or().isNonEmptyArray().isInstanceOf(EntityType).check();
|
|
1374
|
+
let resultTypes;
|
|
1375
|
+
if (typeof entityTypes === "string") {
|
|
1376
|
+
resultTypes = em.metadataStore._getStructuralType(entityTypes, false);
|
|
1377
|
+
}
|
|
1378
|
+
else if (Array.isArray(entityTypes) && typeof entityTypes[0] === "string") {
|
|
1379
|
+
resultTypes = entityTypes.map(function (etName) {
|
|
1380
|
+
return em.metadataStore._getStructuralType(etName, false);
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
else {
|
|
1384
|
+
resultTypes = entityTypes;
|
|
1385
|
+
}
|
|
1386
|
+
return resultTypes;
|
|
1387
|
+
}
|
|
1388
|
+
function getChangesCore(em, entityTypes) {
|
|
1389
|
+
let entityGroups = getEntityGroups(em, entityTypes);
|
|
1390
|
+
// TODO: think about writing a core.mapMany method if we see more of these.
|
|
1391
|
+
let selected = [];
|
|
1392
|
+
entityGroups.forEach(function (eg) {
|
|
1393
|
+
// eg may be undefined or null
|
|
1394
|
+
if (!eg)
|
|
1395
|
+
return;
|
|
1396
|
+
let entities = eg.getChanges();
|
|
1397
|
+
if (selected && selected.length) {
|
|
1398
|
+
selected = selected.concat(entities);
|
|
1399
|
+
}
|
|
1400
|
+
else {
|
|
1401
|
+
selected = entities;
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1404
|
+
return selected;
|
|
1405
|
+
}
|
|
1406
|
+
function getEntitiesCore(em, entityTypes, entityStates) {
|
|
1407
|
+
let entityGroups = getEntityGroups(em, entityTypes);
|
|
1408
|
+
// TODO: think about writing a core.mapMany method if we see more of these.
|
|
1409
|
+
let selected = [];
|
|
1410
|
+
entityGroups.forEach(function (eg) {
|
|
1411
|
+
// eg may be undefined or null
|
|
1412
|
+
if (!eg)
|
|
1413
|
+
return;
|
|
1414
|
+
let entities = eg.getEntities(entityStates);
|
|
1415
|
+
if (selected && selected.length) {
|
|
1416
|
+
selected = selected.concat(entities);
|
|
1417
|
+
}
|
|
1418
|
+
else {
|
|
1419
|
+
selected = entities;
|
|
1420
|
+
}
|
|
1421
|
+
});
|
|
1422
|
+
return selected;
|
|
1423
|
+
}
|
|
1424
|
+
function createEntityKey(em, args) {
|
|
1425
|
+
try {
|
|
1426
|
+
if (args[0] instanceof EntityKey) {
|
|
1427
|
+
return { entityKey: args[0], remainingArgs: core.arraySlice(args, 1) };
|
|
1428
|
+
}
|
|
1429
|
+
else if (args.length >= 2) {
|
|
1430
|
+
let entityType = (typeof args[0] === 'string') ? em.metadataStore._getStructuralType(args[0], false) : args[0];
|
|
1431
|
+
return { entityKey: new EntityKey(entityType, args[1]), remainingArgs: core.arraySlice(args, 2) };
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
catch (e) { /* throw below */
|
|
1435
|
+
// throw new Error("Must supply an EntityKey OR an EntityType name or EntityType followed by a key value or an array of key values.");
|
|
1436
|
+
}
|
|
1437
|
+
throw new Error("Must supply an EntityKey OR an EntityType name or EntityType followed by a key value or an array of key values.");
|
|
1438
|
+
}
|
|
1439
|
+
function markIsBeingSaved(entities, flag) {
|
|
1440
|
+
entities.forEach(function (entity) {
|
|
1441
|
+
entity.entityAspect.isBeingSaved = flag;
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
function exportEntityGroups(em, entitiesOrEntityTypes) {
|
|
1445
|
+
let entityGroupMap;
|
|
1446
|
+
let first = entitiesOrEntityTypes && entitiesOrEntityTypes[0];
|
|
1447
|
+
// check if array
|
|
1448
|
+
if (first) {
|
|
1449
|
+
// group entities by entityType and
|
|
1450
|
+
// create 'groups' that look like entityGroups.
|
|
1451
|
+
entityGroupMap = {};
|
|
1452
|
+
if (first.entityType) {
|
|
1453
|
+
let entities = entitiesOrEntityTypes;
|
|
1454
|
+
// assume "entities" is an array of entities;
|
|
1455
|
+
entities.forEach(function (e) {
|
|
1456
|
+
if (e.entityAspect.entityState === EntityState.Detached) {
|
|
1457
|
+
throw new Error("Unable to export an entity with an EntityState of 'Detached'");
|
|
1458
|
+
}
|
|
1459
|
+
let group = entityGroupMap[e.entityType.name];
|
|
1460
|
+
if (!group) {
|
|
1461
|
+
group = {};
|
|
1462
|
+
group.entityType = e.entityType;
|
|
1463
|
+
group._entities = [];
|
|
1464
|
+
entityGroupMap[e.entityType.name] = group;
|
|
1465
|
+
}
|
|
1466
|
+
group._entities.push(e);
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
else {
|
|
1470
|
+
// assume "entities" is an array of EntityTypes (or names)
|
|
1471
|
+
let entityTypes = checkEntityTypes(em, entitiesOrEntityTypes);
|
|
1472
|
+
if (entityTypes != null) {
|
|
1473
|
+
entityTypes.forEach((et) => {
|
|
1474
|
+
let group = em._entityGroupMap[et.name];
|
|
1475
|
+
if (group && group._entities.length) {
|
|
1476
|
+
entityGroupMap[et.name] = group;
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
else if (entitiesOrEntityTypes && entitiesOrEntityTypes.length === 0) {
|
|
1483
|
+
// empty array = export nothing
|
|
1484
|
+
entityGroupMap = {};
|
|
1485
|
+
}
|
|
1486
|
+
else {
|
|
1487
|
+
entityGroupMap = em._entityGroupMap;
|
|
1488
|
+
}
|
|
1489
|
+
let tempKeys = [];
|
|
1490
|
+
let newGroupMap = {};
|
|
1491
|
+
core.objectForEach(entityGroupMap, (entityTypeName, entityGroup) => {
|
|
1492
|
+
newGroupMap[entityTypeName] = exportEntityGroup(entityGroup, tempKeys);
|
|
1493
|
+
});
|
|
1494
|
+
return { entityGroupMap: newGroupMap, tempKeys: tempKeys };
|
|
1495
|
+
}
|
|
1496
|
+
function exportEntityGroup(entityGroup, tempKeys) {
|
|
1497
|
+
let resultGroup = {};
|
|
1498
|
+
let entityType = entityGroup.entityType;
|
|
1499
|
+
let dps = entityType.dataProperties;
|
|
1500
|
+
let serializerFn = getSerializerFn(entityType);
|
|
1501
|
+
let rawEntities = [];
|
|
1502
|
+
entityGroup._entities.forEach((entity) => {
|
|
1503
|
+
if (entity) {
|
|
1504
|
+
let rawEntity = structuralObjectToJson(entity, dps, serializerFn, tempKeys);
|
|
1505
|
+
rawEntities.push(rawEntity);
|
|
1506
|
+
}
|
|
1507
|
+
});
|
|
1508
|
+
resultGroup.entities = rawEntities;
|
|
1509
|
+
return resultGroup;
|
|
1510
|
+
}
|
|
1511
|
+
function structuralObjectToJson(so, dps, serializerFn, tempKeys) {
|
|
1512
|
+
let result = {};
|
|
1513
|
+
dps.forEach(function (dp) {
|
|
1514
|
+
let dpName = dp.name;
|
|
1515
|
+
let value = so.getProperty(dpName);
|
|
1516
|
+
if (value == null && dp.defaultValue == null)
|
|
1517
|
+
return;
|
|
1518
|
+
if (value && dp.isComplexProperty) {
|
|
1519
|
+
let coDps = dp.dataType.dataProperties;
|
|
1520
|
+
value = core.map(value, function (v) {
|
|
1521
|
+
return structuralObjectToJson(v, coDps, serializerFn);
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
else {
|
|
1525
|
+
value = serializerFn ? serializerFn(dp, value) : value;
|
|
1526
|
+
if (dp.isUnmapped) {
|
|
1527
|
+
value = core.toJSONSafe(value, core.toJSONSafeReplacer);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
if (value === undefined)
|
|
1531
|
+
return;
|
|
1532
|
+
result[dpName] = value;
|
|
1533
|
+
});
|
|
1534
|
+
// if (so.entityAspect) {
|
|
1535
|
+
if (EntityAspect.isEntity(so)) {
|
|
1536
|
+
let aspect = so.entityAspect;
|
|
1537
|
+
let entityState = aspect.entityState;
|
|
1538
|
+
let newAspect = {
|
|
1539
|
+
tempNavPropNames: exportTempKeyInfo(aspect, tempKeys || []),
|
|
1540
|
+
entityState: entityState.name
|
|
1541
|
+
};
|
|
1542
|
+
if (aspect.extraMetadata) {
|
|
1543
|
+
newAspect.extraMetadata = aspect.extraMetadata;
|
|
1544
|
+
}
|
|
1545
|
+
if (entityState.isModified() || entityState.isDeleted()) {
|
|
1546
|
+
newAspect.originalValuesMap = aspect.originalValues;
|
|
1547
|
+
}
|
|
1548
|
+
result.entityAspect = newAspect;
|
|
1549
|
+
}
|
|
1550
|
+
else {
|
|
1551
|
+
let aspect = so.complexAspect;
|
|
1552
|
+
let newAspect = {};
|
|
1553
|
+
if (aspect.originalValues && !core.isEmpty(aspect.originalValues)) {
|
|
1554
|
+
newAspect.originalValuesMap = aspect.originalValues;
|
|
1555
|
+
}
|
|
1556
|
+
result.complexAspect = newAspect;
|
|
1557
|
+
}
|
|
1558
|
+
return result;
|
|
1559
|
+
}
|
|
1560
|
+
function exportTempKeyInfo(entityAspect, tempKeys) {
|
|
1561
|
+
let entity = entityAspect.entity;
|
|
1562
|
+
if (entityAspect.hasTempKey) {
|
|
1563
|
+
tempKeys.push(entityAspect.getKey().toJSON());
|
|
1564
|
+
}
|
|
1565
|
+
// create map for this entity with foreignKeys that are 'temporary'
|
|
1566
|
+
// map -> key: tempKey, value: fkPropName
|
|
1567
|
+
let tempNavPropNames = [];
|
|
1568
|
+
entity.entityType.navigationProperties.forEach(function (np) {
|
|
1569
|
+
if (np.relatedDataProperties) {
|
|
1570
|
+
let relatedValue = entity.getProperty(np.name);
|
|
1571
|
+
if (relatedValue && relatedValue.entityAspect.hasTempKey) {
|
|
1572
|
+
tempNavPropNames.push(np.name);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
});
|
|
1576
|
+
return tempNavPropNames;
|
|
1577
|
+
}
|
|
1578
|
+
function importEntityGroup(entityGroup, jsonGroup, importConfig) {
|
|
1579
|
+
let tempKeyMap = importConfig.tempKeyMap;
|
|
1580
|
+
let mergeAdds = !!importConfig.mergeAdds;
|
|
1581
|
+
let entityType = entityGroup.entityType;
|
|
1582
|
+
let mergeStrategy = importConfig.mergeStrategy;
|
|
1583
|
+
let targetEntity;
|
|
1584
|
+
let em = entityGroup.entityManager;
|
|
1585
|
+
let entityChanged = em.entityChanged;
|
|
1586
|
+
let entitiesToLink = [];
|
|
1587
|
+
let rawValueFn = DataProperty.getRawValueFromClient;
|
|
1588
|
+
jsonGroup.entities.forEach(function (rawEntity) {
|
|
1589
|
+
let newAspect = rawEntity.entityAspect;
|
|
1590
|
+
let entityKey = entityType.getEntityKeyFromRawEntity(rawEntity, rawValueFn);
|
|
1591
|
+
let entityState = EntityState.fromName(newAspect.entityState);
|
|
1592
|
+
if (!entityState || entityState === EntityState.Detached) {
|
|
1593
|
+
throw new Error("Only entities with a non detached entity state may be imported.");
|
|
1594
|
+
}
|
|
1595
|
+
// Merge if raw entity is in cache UNLESS this is a new entity w/ a temp key
|
|
1596
|
+
// Cannot safely merge such entities even if could match temp key to an entity in cache.
|
|
1597
|
+
// Can enable merge of entities w/temp key using "mergeAdds" - use at your own risk!
|
|
1598
|
+
let newTempKey = !mergeAdds && entityState.isAdded() && getMappedKey(tempKeyMap, entityKey);
|
|
1599
|
+
targetEntity = newTempKey ? undefined : entityGroup.findEntityByKey(entityKey);
|
|
1600
|
+
if (targetEntity) {
|
|
1601
|
+
if (mergeStrategy === MergeStrategy.SkipMerge) {
|
|
1602
|
+
// deliberate fall thru
|
|
1603
|
+
}
|
|
1604
|
+
else if (mergeStrategy === MergeStrategy.Disallowed) {
|
|
1605
|
+
throw new Error("A MergeStrategy of 'Disallowed' prevents " + entityKey.toString() + " from being merged");
|
|
1606
|
+
}
|
|
1607
|
+
else {
|
|
1608
|
+
let targetEntityState = targetEntity.entityAspect.entityState;
|
|
1609
|
+
let wasUnchanged = targetEntityState.isUnchanged();
|
|
1610
|
+
if (mergeStrategy === MergeStrategy.OverwriteChanges || wasUnchanged) {
|
|
1611
|
+
entityType._updateTargetFromRaw(targetEntity, rawEntity, rawValueFn);
|
|
1612
|
+
targetEntity.entityAspect.setEntityState(entityState);
|
|
1613
|
+
entityChanged.publish({ entityAction: EntityAction.MergeOnImport, entity: targetEntity });
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
else {
|
|
1618
|
+
targetEntity = entityType._createInstanceCore();
|
|
1619
|
+
entityType._updateTargetFromRaw(targetEntity, rawEntity, rawValueFn);
|
|
1620
|
+
if (newTempKey) {
|
|
1621
|
+
targetEntity.entityAspect.hasTempKey = true;
|
|
1622
|
+
// fixup pk
|
|
1623
|
+
targetEntity.setProperty(entityType.keyProperties[0].name, newTempKey.values[0]);
|
|
1624
|
+
// fixup foreign keys
|
|
1625
|
+
// This is safe because the entity is detached here and therefore originalValues will not be updated.
|
|
1626
|
+
if (newAspect.tempNavPropNames) {
|
|
1627
|
+
newAspect.tempNavPropNames.forEach(function (npName) {
|
|
1628
|
+
let np = entityType.getNavigationProperty(npName);
|
|
1629
|
+
let fkPropName = np.relatedDataProperties[0].name;
|
|
1630
|
+
let oldFkValue = targetEntity.getProperty(fkPropName);
|
|
1631
|
+
let fk = new EntityKey(np.entityType, [oldFkValue]);
|
|
1632
|
+
let newFk = getMappedKey(tempKeyMap, fk);
|
|
1633
|
+
targetEntity.setProperty(fkPropName, newFk.values[0]);
|
|
1634
|
+
});
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
// Now performed in attachEntity
|
|
1638
|
+
targetEntity = entityGroup.attachEntity(targetEntity, entityState);
|
|
1639
|
+
entityChanged.publish({ entityAction: EntityAction.AttachOnImport, entity: targetEntity });
|
|
1640
|
+
if (!entityState.isUnchanged()) {
|
|
1641
|
+
em._notifyStateChange(targetEntity, true);
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
entitiesToLink.push(targetEntity);
|
|
1645
|
+
});
|
|
1646
|
+
return entitiesToLink;
|
|
1647
|
+
}
|
|
1648
|
+
function getMappedKey(tempKeyMap, entityKey) {
|
|
1649
|
+
let newKey = tempKeyMap[entityKey.toString()];
|
|
1650
|
+
if (newKey)
|
|
1651
|
+
return newKey;
|
|
1652
|
+
let subtypes = entityKey._subtypes;
|
|
1653
|
+
if (!subtypes)
|
|
1654
|
+
return null;
|
|
1655
|
+
for (let i = 0, j = subtypes.length; i < j; i++) {
|
|
1656
|
+
newKey = tempKeyMap[entityKey.toString(subtypes[i])];
|
|
1657
|
+
if (newKey)
|
|
1658
|
+
return newKey;
|
|
1659
|
+
}
|
|
1660
|
+
return null;
|
|
1661
|
+
}
|
|
1662
|
+
function promiseWithCallbacks(promise, callback, errorCallback) {
|
|
1663
|
+
promise = promise.then(function (data) {
|
|
1664
|
+
if (callback)
|
|
1665
|
+
callback(data);
|
|
1666
|
+
return Promise.resolve(data);
|
|
1667
|
+
}, function (error) {
|
|
1668
|
+
if (errorCallback)
|
|
1669
|
+
errorCallback(error);
|
|
1670
|
+
return Promise.reject(error);
|
|
1671
|
+
});
|
|
1672
|
+
return promise;
|
|
1673
|
+
}
|
|
1674
|
+
function getEntitiesToSave(em, entities) {
|
|
1675
|
+
let entitiesToSave;
|
|
1676
|
+
if (entities) {
|
|
1677
|
+
entitiesToSave = entities.filter(function (e) {
|
|
1678
|
+
if (e.entityAspect.entityManager !== em) {
|
|
1679
|
+
throw new Error("Only entities in this entityManager may be saved");
|
|
1680
|
+
}
|
|
1681
|
+
return !e.entityAspect.entityState.isDetached();
|
|
1682
|
+
});
|
|
1683
|
+
}
|
|
1684
|
+
else {
|
|
1685
|
+
entitiesToSave = em.getChanges();
|
|
1686
|
+
}
|
|
1687
|
+
return entitiesToSave;
|
|
1688
|
+
}
|
|
1689
|
+
function fixupKeys(em, keyMappings) {
|
|
1690
|
+
em._inKeyFixup = true;
|
|
1691
|
+
keyMappings.forEach(function (km) {
|
|
1692
|
+
let group = em._entityGroupMap[km.entityTypeName];
|
|
1693
|
+
if (!group) {
|
|
1694
|
+
throw new Error("Unable to locate the following fully qualified EntityType name: " + km.entityTypeName);
|
|
1695
|
+
}
|
|
1696
|
+
group._fixupKey(km.tempValue, km.realValue);
|
|
1697
|
+
});
|
|
1698
|
+
em._inKeyFixup = false;
|
|
1699
|
+
}
|
|
1700
|
+
function getEntityGroups(em, entityTypes) {
|
|
1701
|
+
let groupMap = em._entityGroupMap;
|
|
1702
|
+
if (entityTypes) {
|
|
1703
|
+
return core.toArray(entityTypes).map(function (et) {
|
|
1704
|
+
if (et instanceof EntityType) {
|
|
1705
|
+
return groupMap[et.name];
|
|
1706
|
+
}
|
|
1707
|
+
else {
|
|
1708
|
+
throw new Error("The EntityManager.getChanges() 'entityTypes' parameter must be either an entityType or an array of entityTypes or null");
|
|
1709
|
+
}
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1712
|
+
else {
|
|
1713
|
+
return core.getOwnPropertyValues(groupMap);
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
function checkEntityKey(em, entity) {
|
|
1717
|
+
let ek = entity.entityAspect.getKey();
|
|
1718
|
+
// return properties that are = to defaultValues
|
|
1719
|
+
let keyPropsWithDefaultValues = core.arrayZip(entity.entityType.keyProperties, ek.values, function (kp, kv) {
|
|
1720
|
+
return (kp.defaultValue === kv) ? kp : null;
|
|
1721
|
+
}).filter(function (kp) {
|
|
1722
|
+
return kp !== null;
|
|
1723
|
+
});
|
|
1724
|
+
if (keyPropsWithDefaultValues.length) {
|
|
1725
|
+
if (entity.entityType.autoGeneratedKeyType !== AutoGeneratedKeyType.None) {
|
|
1726
|
+
em.generateTempKeyValue(entity);
|
|
1727
|
+
}
|
|
1728
|
+
else {
|
|
1729
|
+
// we will allow attaches of entities where only part of the key is set.
|
|
1730
|
+
if (keyPropsWithDefaultValues.length === ek.values.length) {
|
|
1731
|
+
throw new Error("Cannot attach an object of type (" + entity.entityType.name + ") to an EntityManager without first setting its key or setting its entityType 'AutoGeneratedKeyType' property to something other than 'None'");
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
function validateEntityStates(em, entityStates) {
|
|
1737
|
+
if (!entityStates)
|
|
1738
|
+
return [];
|
|
1739
|
+
let entStates = core.toArray(entityStates);
|
|
1740
|
+
entStates.forEach((es) => {
|
|
1741
|
+
if (!(es instanceof EntityState)) {
|
|
1742
|
+
throw new Error("The EntityManager.getChanges() 'entityStates' parameter must either be null, an entityState or an array of entityStates");
|
|
1743
|
+
}
|
|
1744
|
+
});
|
|
1745
|
+
return entStates;
|
|
1746
|
+
}
|
|
1747
|
+
function attachRelatedEntities(em, entity, entityState, mergeStrategy) {
|
|
1748
|
+
let navProps = entity.entityType.navigationProperties;
|
|
1749
|
+
navProps.forEach(function (np) {
|
|
1750
|
+
let related = entity.getProperty(np.name);
|
|
1751
|
+
if (np.isScalar) {
|
|
1752
|
+
if (!related)
|
|
1753
|
+
return;
|
|
1754
|
+
em.attachEntity(related, entityState, mergeStrategy);
|
|
1755
|
+
}
|
|
1756
|
+
else {
|
|
1757
|
+
related.forEach(function (e) {
|
|
1758
|
+
em.attachEntity(e, entityState, mergeStrategy);
|
|
1759
|
+
});
|
|
1760
|
+
}
|
|
1761
|
+
});
|
|
1762
|
+
}
|
|
1763
|
+
// returns a promise
|
|
1764
|
+
function executeQueryCore(em, query, queryOptions, dataService) {
|
|
1765
|
+
try {
|
|
1766
|
+
let results;
|
|
1767
|
+
let metadataStore = em.metadataStore;
|
|
1768
|
+
if (metadataStore.isEmpty() && dataService.hasServerMetadata) {
|
|
1769
|
+
throw new Error("cannot execute _executeQueryCore until metadataStore is populated.");
|
|
1770
|
+
}
|
|
1771
|
+
if (queryOptions.fetchStrategy === FetchStrategy.FromLocalCache) {
|
|
1772
|
+
try {
|
|
1773
|
+
if (typeof query === 'string') {
|
|
1774
|
+
throw new Error("cannot execute 'string' EntityQuery locally.");
|
|
1775
|
+
}
|
|
1776
|
+
let qr = executeQueryLocallyCore(em, query);
|
|
1777
|
+
return Promise.resolve({ results: qr.results, entityManager: em, inlineCount: qr.inlineCount, query: query });
|
|
1778
|
+
}
|
|
1779
|
+
catch (e) {
|
|
1780
|
+
return Promise.reject(e);
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
let mappingContext = new MappingContext({
|
|
1784
|
+
query: query,
|
|
1785
|
+
entityManager: em,
|
|
1786
|
+
dataService: dataService,
|
|
1787
|
+
mergeOptions: {
|
|
1788
|
+
mergeStrategy: queryOptions.mergeStrategy,
|
|
1789
|
+
noTracking: !!query.noTrackingEnabled,
|
|
1790
|
+
includeDeleted: queryOptions.includeDeleted
|
|
1791
|
+
}
|
|
1792
|
+
});
|
|
1793
|
+
let validateOnQuery = em.validationOptions.validateOnQuery;
|
|
1794
|
+
return dataService.adapterInstance.executeQuery(mappingContext).then(function (data) {
|
|
1795
|
+
let result = core.wrapExecution(function () {
|
|
1796
|
+
let state = { isLoading: em.isLoading };
|
|
1797
|
+
em.isLoading = true;
|
|
1798
|
+
em._pendingPubs = [];
|
|
1799
|
+
return state;
|
|
1800
|
+
}, function (state) {
|
|
1801
|
+
// cleanup
|
|
1802
|
+
em.isLoading = state.isLoading;
|
|
1803
|
+
em._pendingPubs.forEach(function (fn) {
|
|
1804
|
+
fn();
|
|
1805
|
+
});
|
|
1806
|
+
em._pendingPubs = undefined;
|
|
1807
|
+
em._hasChangesAction && em._hasChangesAction();
|
|
1808
|
+
// TODO: removed - not sure why needed in first place...
|
|
1809
|
+
// // HACK for GC
|
|
1810
|
+
// query = undefined;
|
|
1811
|
+
mappingContext = undefined;
|
|
1812
|
+
// HACK: some errors thrown in next function do not propogate properly - this catches them.
|
|
1813
|
+
if (state.error) {
|
|
1814
|
+
return Promise.reject(state.error);
|
|
1815
|
+
}
|
|
1816
|
+
}, function () {
|
|
1817
|
+
let nodes = dataService.jsonResultsAdapter.extractResults(data);
|
|
1818
|
+
nodes = core.toArray(nodes);
|
|
1819
|
+
results = mappingContext.visitAndMerge(nodes, { nodeType: "root" });
|
|
1820
|
+
if (validateOnQuery) {
|
|
1821
|
+
results.forEach(function (r) {
|
|
1822
|
+
// anon types and simple types will not have an entityAspect.
|
|
1823
|
+
r.entityAspect && r.entityAspect.validateEntity();
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
mappingContext.processDeferred();
|
|
1827
|
+
// if query has expand clauses walk each of the 'results' and mark the expanded props as loaded.
|
|
1828
|
+
if (query instanceof EntityQuery) {
|
|
1829
|
+
markLoadedNavProps(results, query);
|
|
1830
|
+
}
|
|
1831
|
+
let retrievedEntities = core.objectMap(mappingContext.refMap);
|
|
1832
|
+
return { results: results, query: query, entityManager: em, httpResponse: data.httpResponse, inlineCount: data.inlineCount, retrievedEntities: retrievedEntities };
|
|
1833
|
+
});
|
|
1834
|
+
return Promise.resolve(result);
|
|
1835
|
+
}, function (e) {
|
|
1836
|
+
if (e) {
|
|
1837
|
+
e.query = query;
|
|
1838
|
+
e.entityManager = em;
|
|
1839
|
+
}
|
|
1840
|
+
return Promise.reject(e);
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
catch (e) {
|
|
1844
|
+
if (e) {
|
|
1845
|
+
e.query = query;
|
|
1846
|
+
}
|
|
1847
|
+
return Promise.reject(e);
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
function markLoadedNavProps(entities, query) {
|
|
1851
|
+
if (query.noTrackingEnabled)
|
|
1852
|
+
return;
|
|
1853
|
+
let expandClause = query.expandClause;
|
|
1854
|
+
if (expandClause == null)
|
|
1855
|
+
return;
|
|
1856
|
+
expandClause.propertyPaths.forEach(function (propertyPath) {
|
|
1857
|
+
let propNames = propertyPath.split('.');
|
|
1858
|
+
markLoadedNavPath(entities, propNames);
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
function markLoadedNavPath(entities, propNames) {
|
|
1862
|
+
let propName = propNames[0];
|
|
1863
|
+
entities.forEach((entity) => {
|
|
1864
|
+
let ea = entity.entityAspect;
|
|
1865
|
+
if (!ea)
|
|
1866
|
+
return; // entity may not be a 'real' entity in the case of a projection.
|
|
1867
|
+
ea._markAsLoaded(propName);
|
|
1868
|
+
if (propNames.length === 1)
|
|
1869
|
+
return;
|
|
1870
|
+
let next = entity.getProperty(propName);
|
|
1871
|
+
if (!next)
|
|
1872
|
+
return; // no children to process.
|
|
1873
|
+
// strange logic because nonscalar nav values are NOT really arrays
|
|
1874
|
+
// otherwise we could use Array.isArray
|
|
1875
|
+
if (!next.arrayChanged)
|
|
1876
|
+
next = [next];
|
|
1877
|
+
markLoadedNavPath(next, propNames.slice(1));
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1880
|
+
function updateConcurrencyProperties(entities) {
|
|
1881
|
+
let candidates = entities.filter((e) => {
|
|
1882
|
+
e.entityAspect.isBeingSaved = true;
|
|
1883
|
+
return e.entityAspect.entityState.isModified()
|
|
1884
|
+
&& e.entityType.concurrencyProperties.length > 0;
|
|
1885
|
+
});
|
|
1886
|
+
if (candidates.length === 0)
|
|
1887
|
+
return;
|
|
1888
|
+
candidates.forEach(function (c) {
|
|
1889
|
+
c.entityType.concurrencyProperties.forEach(function (cp) {
|
|
1890
|
+
updateConcurrencyProperty(c, cp);
|
|
1891
|
+
});
|
|
1892
|
+
});
|
|
1893
|
+
}
|
|
1894
|
+
function updateConcurrencyProperty(entity, property) {
|
|
1895
|
+
// check if property has already been updated
|
|
1896
|
+
if (entity.entityAspect.originalValues[property.name])
|
|
1897
|
+
return;
|
|
1898
|
+
let value = entity.getProperty(property.name);
|
|
1899
|
+
let dataType = property.dataType;
|
|
1900
|
+
if (!value)
|
|
1901
|
+
value = dataType.defaultValue;
|
|
1902
|
+
if (dataType.isNumeric) {
|
|
1903
|
+
entity.setProperty(property.name, value + 1);
|
|
1904
|
+
}
|
|
1905
|
+
else if (dataType.getConcurrencyValue) {
|
|
1906
|
+
// DataType has its own implementation
|
|
1907
|
+
let nextValue = dataType.getConcurrencyValue(value);
|
|
1908
|
+
entity.setProperty(property.name, nextValue);
|
|
1909
|
+
}
|
|
1910
|
+
else if (dataType === DataType.Binary) {
|
|
1911
|
+
// best guess - that this is a timestamp column and is computed on the server during save
|
|
1912
|
+
// - so no need to set it here.
|
|
1913
|
+
return;
|
|
1914
|
+
}
|
|
1915
|
+
else {
|
|
1916
|
+
// this just leaves DataTypes of Boolean, String and Byte - none of which should be the
|
|
1917
|
+
// type for a concurrency column.
|
|
1918
|
+
// NOTE: thought about just returning here but would rather be safe for now.
|
|
1919
|
+
throw new Error("Unable to update the value of concurrency property before saving: " + property.name);
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
function findOrCreateEntityGroup(em, entityType) {
|
|
1923
|
+
let group = em._entityGroupMap[entityType.name];
|
|
1924
|
+
if (!group) {
|
|
1925
|
+
group = new EntityGroup(em, entityType);
|
|
1926
|
+
em._entityGroupMap[entityType.name] = group;
|
|
1927
|
+
}
|
|
1928
|
+
return group;
|
|
1929
|
+
}
|
|
1930
|
+
function findOrCreateEntityGroups(em, entityType) {
|
|
1931
|
+
let entityTypes = entityType.getSelfAndSubtypes();
|
|
1932
|
+
return entityTypes.map((et) => {
|
|
1933
|
+
return findOrCreateEntityGroup(em, et);
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
function unwrapInstance(structObj, transformFn) {
|
|
1937
|
+
let rawObject = {};
|
|
1938
|
+
let stype = EntityAspect.isEntity(structObj) ? structObj.entityType : structObj.complexType;
|
|
1939
|
+
let serializerFn = getSerializerFn(stype);
|
|
1940
|
+
let unmapped = {};
|
|
1941
|
+
stype.dataProperties.forEach(function (dp) {
|
|
1942
|
+
if (dp.isComplexProperty) {
|
|
1943
|
+
rawObject[dp.nameOnServer] = core.map(structObj.getProperty(dp.name), function (co) {
|
|
1944
|
+
return unwrapInstance(co, transformFn);
|
|
1945
|
+
});
|
|
1946
|
+
}
|
|
1947
|
+
else {
|
|
1948
|
+
let val = structObj.getProperty(dp.name);
|
|
1949
|
+
val = transformFn ? transformFn(dp, val) : val;
|
|
1950
|
+
if (val === undefined)
|
|
1951
|
+
return;
|
|
1952
|
+
val = serializerFn ? serializerFn(dp, val) : val;
|
|
1953
|
+
if (val !== undefined) {
|
|
1954
|
+
if (dp.isUnmapped) {
|
|
1955
|
+
unmapped[dp.nameOnServer] = core.toJSONSafe(val, core.toJSONSafeReplacer);
|
|
1956
|
+
}
|
|
1957
|
+
else {
|
|
1958
|
+
rawObject[dp.nameOnServer] = val;
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
});
|
|
1963
|
+
if (!core.isEmpty(unmapped)) {
|
|
1964
|
+
// TODO: review this.
|
|
1965
|
+
rawObject.__unmapped = unmapped;
|
|
1966
|
+
}
|
|
1967
|
+
return rawObject;
|
|
1968
|
+
}
|
|
1969
|
+
function unwrapOriginalValues(target, metadataStore, transformFn) {
|
|
1970
|
+
let stype = EntityAspect.isEntity(target) ? target.entityType : target.complexType;
|
|
1971
|
+
let aspect = EntityAspect.isEntity(target) ? target.entityAspect : target.complexAspect;
|
|
1972
|
+
let fn = metadataStore.namingConvention.clientPropertyNameToServer;
|
|
1973
|
+
let result = {};
|
|
1974
|
+
core.objectForEach(aspect.originalValues, function (propName, val) {
|
|
1975
|
+
let prop = stype.getProperty(propName);
|
|
1976
|
+
val = transformFn ? transformFn(prop, val) : val;
|
|
1977
|
+
if (val !== undefined) {
|
|
1978
|
+
result[fn(propName, prop)] = val;
|
|
1979
|
+
}
|
|
1980
|
+
});
|
|
1981
|
+
stype.complexProperties.forEach(function (cp) {
|
|
1982
|
+
let nextTarget = target.getProperty(cp.name);
|
|
1983
|
+
if (cp.isScalar) {
|
|
1984
|
+
let unwrappedCo = unwrapOriginalValues(nextTarget, metadataStore, transformFn);
|
|
1985
|
+
if (!core.isEmpty(unwrappedCo)) {
|
|
1986
|
+
result[fn(cp.name, cp)] = unwrappedCo;
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
else {
|
|
1990
|
+
let unwrappedCos = nextTarget.map((item) => {
|
|
1991
|
+
return unwrapOriginalValues(item, metadataStore, transformFn);
|
|
1992
|
+
});
|
|
1993
|
+
result[fn(cp.name, cp)] = unwrappedCos;
|
|
1994
|
+
}
|
|
1995
|
+
});
|
|
1996
|
+
return result;
|
|
1997
|
+
}
|
|
1998
|
+
function unwrapChangedValues(entity, metadataStore, transformFn) {
|
|
1999
|
+
let stype = entity.entityType;
|
|
2000
|
+
let serializerFn = getSerializerFn(stype);
|
|
2001
|
+
let fn = metadataStore.namingConvention.clientPropertyNameToServer;
|
|
2002
|
+
let result = {};
|
|
2003
|
+
core.objectForEach(entity.entityAspect.originalValues, function (propName, value) {
|
|
2004
|
+
let prop = stype.getProperty(propName);
|
|
2005
|
+
let val = entity.getProperty(propName);
|
|
2006
|
+
val = transformFn ? transformFn(prop, val) : val;
|
|
2007
|
+
if (val === undefined)
|
|
2008
|
+
return;
|
|
2009
|
+
val = serializerFn ? serializerFn(prop, val) : val;
|
|
2010
|
+
if (val !== undefined) {
|
|
2011
|
+
result[fn(propName, prop)] = val;
|
|
2012
|
+
}
|
|
2013
|
+
});
|
|
2014
|
+
// any change to any complex object or array of complex objects returns the ENTIRE
|
|
2015
|
+
// current complex object or complex object array. This is by design. Complex Objects
|
|
2016
|
+
// are atomic.
|
|
2017
|
+
stype.complexProperties.forEach((cp) => {
|
|
2018
|
+
if (cpHasOriginalValues(entity, cp)) {
|
|
2019
|
+
let coOrCos = entity.getProperty(cp.name);
|
|
2020
|
+
result[fn(cp.name, cp)] = core.map(coOrCos, function (co) {
|
|
2021
|
+
return unwrapInstance(co, transformFn);
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
2024
|
+
});
|
|
2025
|
+
return result;
|
|
2026
|
+
}
|
|
2027
|
+
function cpHasOriginalValues(structuralObject, cp) {
|
|
2028
|
+
let coOrCos = structuralObject.getProperty(cp.name);
|
|
2029
|
+
if (cp.isScalar) {
|
|
2030
|
+
return coHasOriginalValues(coOrCos);
|
|
2031
|
+
}
|
|
2032
|
+
else {
|
|
2033
|
+
// this occurs when a nonscalar co array has had cos added or removed.
|
|
2034
|
+
if (coOrCos._origValues)
|
|
2035
|
+
return true;
|
|
2036
|
+
return coOrCos.some(function (co) {
|
|
2037
|
+
return coHasOriginalValues(co);
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
function executeQueryLocallyCore(em, query) {
|
|
2042
|
+
assertParam(query, "query").isInstanceOf(EntityQuery).check();
|
|
2043
|
+
let metadataStore = em.metadataStore;
|
|
2044
|
+
let entityType = query._getFromEntityType(metadataStore, true);
|
|
2045
|
+
// there may be multiple groups is this is a base entity type.
|
|
2046
|
+
let groups = findOrCreateEntityGroups(em, entityType);
|
|
2047
|
+
// filter then order then skip then take
|
|
2048
|
+
let filterFunc = query.wherePredicate && query.wherePredicate.toFunction({ entityType: entityType });
|
|
2049
|
+
let queryOptions = QueryOptions.resolve([query.queryOptions, em.queryOptions, QueryOptions.defaultInstance]);
|
|
2050
|
+
let includeDeleted = queryOptions.includeDeleted === true;
|
|
2051
|
+
let newFilterFunc = function (entity) {
|
|
2052
|
+
return entity && (includeDeleted || !entity.entityAspect.entityState.isDeleted()) && (filterFunc ? filterFunc(entity) : true);
|
|
2053
|
+
};
|
|
2054
|
+
let result = [];
|
|
2055
|
+
// TODO: mapMany
|
|
2056
|
+
groups.forEach((group) => {
|
|
2057
|
+
let entities = group._entities.filter(newFilterFunc);
|
|
2058
|
+
if (entities.length) {
|
|
2059
|
+
result = result.length ? result.concat(entities) : entities;
|
|
2060
|
+
}
|
|
2061
|
+
});
|
|
2062
|
+
let orderByComparer = query.orderByClause && query.orderByClause.getComparer(entityType);
|
|
2063
|
+
if (orderByComparer) {
|
|
2064
|
+
result.sort(orderByComparer);
|
|
2065
|
+
}
|
|
2066
|
+
let inlineCount = query.inlineCountEnabled ? result.length : undefined;
|
|
2067
|
+
let skipCount = query.skipCount;
|
|
2068
|
+
if (skipCount) {
|
|
2069
|
+
result = result.slice(skipCount);
|
|
2070
|
+
}
|
|
2071
|
+
let takeCount = query.takeCount;
|
|
2072
|
+
if (takeCount) {
|
|
2073
|
+
result = result.slice(0, takeCount);
|
|
2074
|
+
}
|
|
2075
|
+
let selectClause = query.selectClause;
|
|
2076
|
+
if (selectClause) {
|
|
2077
|
+
let selectFn = selectClause.toFunction();
|
|
2078
|
+
result = result.map(selectFn);
|
|
2079
|
+
}
|
|
2080
|
+
return { results: result, inlineCount: inlineCount };
|
|
2081
|
+
}
|
|
2082
|
+
function coHasOriginalValues(co) {
|
|
2083
|
+
// next line checks all non complex properties of the co.
|
|
2084
|
+
if (!core.isEmpty(co.complexAspect.originalValues))
|
|
2085
|
+
return true;
|
|
2086
|
+
// now need to recursively check each of the cps
|
|
2087
|
+
return co.complexType.complexProperties.some(function (cp) {
|
|
2088
|
+
return cpHasOriginalValues(co, cp);
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
function getSerializerFn(stype) {
|
|
2092
|
+
return stype.serializerFn || (stype.metadataStore && stype.metadataStore.serializerFn);
|
|
2093
|
+
}
|
|
2094
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LW1hbmFnZXIuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9icmVlemUtY2xpZW50LyIsInNvdXJjZXMiOlsic3JjL2VudGl0eS1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxJQUFJLEVBQTJCLE1BQU0sUUFBUSxDQUFDO0FBQ3ZELE9BQU8sRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDM0QsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNsQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3RDLE9BQU8sRUFBRSxZQUFZLEVBQXFFLE1BQU0saUJBQWlCLENBQUM7QUFDbEgsT0FBTyxFQUFFLGFBQWEsRUFBRSxVQUFVLEVBQWUsWUFBWSxFQUFzQixvQkFBb0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ25JLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDekMsT0FBTyxFQUFFLFlBQVksRUFBRyxNQUFNLGlCQUFpQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN2QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3pELE9BQU8sRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLGFBQWEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzdFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFB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QUFPLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUUsQ0FBQztBQUN2RCxDQUFDO0FBRUQsU0FBUyxtQkFBbUIsQ0FBQyxFQUFpQjtJQUM1Qyx5REFBeUQ7SUFDekQsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxjQUFjLENBQUM7UUFBRSxPQUFPLElBQUksQ0FBQztJQUNoRSxnREFBZ0Q7SUFDaEQsT0FBTyxFQUFFLENBQUMsV0FBVyxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUU7UUFDdkQsT0FBTyxtQkFBbUIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDckMsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUyxlQUFlLENBQUMsS0FBK0I7SUFDdEQsT0FBTyxLQUFLLENBQUMsWUFBWSxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsSUFBSSxLQUFLLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxDQUFDO0FBQ3pGLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEYXRhU2VydmljZUFkYXB0ZXIgfSBmcm9tICcuL2ludGVyZmFjZS1yZWdpc3RyeSc7XHJcbmltcG9ydCB7IGNvcmUsIENhbGxiYWNrLCBFcnJvckNhbGxiYWNrIH0gZnJvbSAnLi9jb3JlJztcclxuaW1wb3J0IHsgYXNzZXJ0UGFyYW0sIGFzc2VydENvbmZpZyB9IGZyb20gJy4vYXNzZXJ0LXBhcmFtJztcclxuaW1wb3J0IHsgY29uZmlnIH0gZnJvbSAnLi9jb25maWcnO1xyXG5pbXBvcnQgeyBCcmVlemVFdmVudCB9IGZyb20gJy4vZXZlbnQnO1xyXG5pbXBvcnQgeyBFbnRpdHlBc3BlY3QsIEVudGl0eSwgQ29tcGxleE9iamVjdCwgU3RydWN0dXJhbE9iamVjdCwgUHJvcGVydHlDaGFuZ2VkRXZlbnRBcmdzIH0gZnJvbSAnLi9lbnRpdHktYXNwZWN0JztcclxuaW1wb3J0IHsgTWV0YWRhdGFTdG9yZSwgRW50aXR5VHlwZSwgQ29tcGxleFR5cGUsIERhdGFQcm9wZXJ0eSwgTmF2aWdhdGlvblByb3BlcnR5LCBBdXRvR2VuZXJhdGVkS2V5VHlwZSB9IGZyb20gJy4vZW50aXR5LW1ldGFkYXRhJztcclxuaW1wb3J0IHsgRW50aXR5S2V5IH0gZnJvbSAnLi9lbnRpdHkta2V5JztcclxuaW1wb3J0IHsgRW50aXR5QWN0aW9uICB9IGZyb20gJy4vZW50aXR5LWFjdGlvbic7XHJcbmltcG9ydCB7IEVudGl0eVN0YXRlIH0gZnJvbSAnLi9lbnRpdHktc3RhdGUnO1xyXG5pbXBvcnQgeyBEYXRhU2VydmljZSB9IGZyb20gJy4vZGF0YS1zZXJ2aWNlJztcclxuaW1wb3J0IHsgRGF0YVR5cGUgfSBmcm9tICcuL2RhdGEtdHlwZSc7XHJcbmltcG9ydCB7IFZhbGlkYXRpb25FcnJvciB9IGZyb20gJy4vdmFsaWRhdGUnO1xyXG5pbXBvcnQgeyBWYWxpZGF0aW9uT3B0aW9ucyB9IGZyb20gJy4vdmFsaWRhdGlvbi1vcHRpb25zJztcclxuaW1wb3J0IHsgUXVlcnlPcHRpb25zLCBNZXJnZVN0cmF0ZWd5LCBGZXRjaFN0cmF0ZWd5IH0gZnJvbSAnLi9xdWVyeS1vcHRpb25zJztcclxuaW1wb3J0IHsgU2F2ZU9wdGlvbnMgfSBmcm9tICcuL3NhdmUtb3B0aW9ucyc7XHJcbmltcG9ydCB7IEtleUdlbmVyYXRvciB9IGZyb20gJy4va2V5LWdlbmVyYXRvcic7XHJcbmltcG9ydCB7IEVudGl0eUdyb3VwIH0gZnJvbSAnLi9lbnRpdHktZ3JvdXAnO1xyXG5pbXBvcnQgeyBNYXBwaW5nQ29udGV4dCB9IGZyb20gJy4vbWFwcGluZy1jb250ZXh0JztcclxuaW1wb3J0IHsgRW50aXR5UXVlcnkgfSBmcm9tICcuL2VudGl0eS1xdWVyeSc7XHJcbmltcG9ydCB7IFVuYXR0YWNoZWRDaGlsZHJlbk1hcCB9IGZyb20gJy4vdW5hdHRhY2hlZC1jaGlsZHJlbi1tYXAnO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBIdHRwUmVzcG9uc2Uge1xyXG4gIGNvbmZpZzogYW55O1xyXG4gIGRhdGE6IGFueTtcclxuICBlcnJvcj86IGFueTtcclxuICBzYXZlQ29udGV4dD86IGFueTtcclxuICBzdGF0dXM6IG51bWJlcjtcclxuICBnZXRIZWFkZXJzKGhlYWRlck5hbWU6IHN0cmluZyk6IHN0cmluZztcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBJbXBvcnRSZXN1bHQge1xyXG4gIGVudGl0aWVzOiBFbnRpdHlbXTtcclxuICB0ZW1wS2V5TWFwcGluZzogSVRlbXBLZXlNYXA7XHJcbn1cclxuXHJcbi8vIHN1YmNsYXNzZXMgb2YgRXJyb3JcclxuXHJcbi8qKiBCYXNlIHNoYXBlIG9mIGFueSBlcnJvcnMgcmV0dXJuZWQgZnJvbSB0aGUgc2VydmVyLiAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIFNlcnZlckVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIGh0dHBSZXNwb25zZTogSHR0cFJlc3BvbnNlO1xyXG4gIHN0YXR1czogbnVtYmVyO1xyXG4gIG1lc3NhZ2U6IHN0cmluZztcclxuICBzdGF0dXNUZXh0Pzogc3RyaW5nO1xyXG4gIGJvZHk/OiBhbnk7XHJcbiAgdXJsPzogc3RyaW5nO1xyXG59XHJcblxyXG4vKiogU2hhcGUgb2YgYSBzYXZlIGVycm9yIHJldHVybmVkIGZyb20gdGhlIHNlcnZlci4gXHJcbkZvciB1c2UgYnkgYnJlZXplIHBsdWdpbiBhdXRob3JzIG9ubHkuIFRoZSBjbGFzcyBpcyBmb3IgdXNlIGluIGJ1aWxkaW5nIGEgW1tJRGF0YVNlcnZpY2VBZGFwdGVyXV0gaW1wbGVtZW50YXRpb24uIFxyXG5AYWRhcHRlciAoc2VlIFtbSURhdGFTZXJ2aWNlQWRhcHRlcl1dKSAgICBcclxuQGhpZGRlbiBAaW50ZXJuYWwgXHJcbiovXHJcbmV4cG9ydCBpbnRlcmZhY2UgU2F2ZUVycm9yRnJvbVNlcnZlciBleHRlbmRzIFNlcnZlckVycm9yIHtcclxuICBlbnRpdHlFcnJvcnM6IEVudGl0eUVycm9yRnJvbVNlcnZlcltdO1xyXG59XHJcblxyXG4vKiogU2hhcGUgb2YgYSBzYXZlIGVycm9yIHdoZW4gcmV0dXJuZWQgdG8gdGhlIGNsaWVudC4gKi9cclxuZXhwb3J0IGludGVyZmFjZSBTYXZlRXJyb3IgZXh0ZW5kcyBTZXJ2ZXJFcnJvciB7XHJcbiAgZW50aXR5RXJyb3JzOiBFbnRpdHlFcnJvcltdO1xyXG59XHJcblxyXG4vLyBub3Qgc3ViY2xhc3NlcyBvZiBFcnJvclxyXG4vKiogXHJcbkZvciB1c2UgYnkgYnJlZXplIHBsdWdpbiBhdXRob3JzIG9ubHkuIFRoZSBjbGFzcyBpcyBmb3IgdXNlIGluIGJ1aWxkaW5nIGEgW1tJRGF0YVNlcnZpY2VBZGFwdGVyXV0gaW1wbGVtZW50YXRpb24uIFxyXG5AYWRhcHRlciAoc2VlIFtbSURhdGFTZXJ2aWNlQWRhcHRlcl1dKSAgICBcclxuQGhpZGRlbiBAaW50ZXJuYWwgXHJcbiovXHJcbmV4cG9ydCBpbnRlcmZhY2UgRW50aXR5RXJyb3JGcm9tU2VydmVyIHtcclxuICBlbnRpdHlUeXBlTmFtZTogc3RyaW5nO1xyXG4gIGtleVZhbHVlczogYW55W107XHJcblxyXG4gIGVycm9yTmFtZTogc3RyaW5nO1xyXG4gIGVycm9yTWVzc2FnZTogc3RyaW5nO1xyXG4gIHByb3BlcnR5TmFtZTogc3RyaW5nO1xyXG4gIGN1c3RvbT86IGFueTtcclxufVxyXG5cclxuLyoqIFNoYXBlIG9mIGFuIGVycm9yIG9uIGEgc3BlY2lmaWMgZW50aXR5LiAgUGFydCBvZiBhIFtbSVNhdmVFcnJvcl1dICovXHJcbmV4cG9ydCBpbnRlcmZhY2UgRW50aXR5RXJyb3Ige1xyXG4gIGVudGl0eTogRW50aXR5O1xyXG4gIGVycm9yTmFtZTogc3RyaW5nO1xyXG4gIGVycm9yTWVzc2FnZTogc3RyaW5nO1xyXG4gIHByb3BlcnR5TmFtZTogc3RyaW5nO1xyXG4gIGlzU2VydmVyRXJyb3I6IGJvb2xlYW47XHJcbiAgY3VzdG9tPzogYW55O1xyXG59XHJcblxyXG4vKiogVGhlIHNoYXBlIG9mIHRoZSBQcm9taXNlIHJldHVybmVkIGJ5IGFuIFtbRW50aXR5TWFuYWdlci5leGVjdXRlUXVlcnldXSBjYWxsLiAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIFF1ZXJ5UmVzdWx0IHtcclxuICAvKiogVG9wIGxldmVsIGVudGl0aWVzIHJldHVybmVkLiAgRXhjbHVkZXMgZW50aXRpZXMgdGhhdCBhcmUgRGVsZXRlZC4gKi9cclxuICByZXN1bHRzOiBhbnlbXTtcclxuICAvKiogUXVlcnkgdGhhdCB3YXMgZXhlY3V0ZWQgKi9cclxuICBxdWVyeTogRW50aXR5UXVlcnkgfCBzdHJpbmc7XHJcbiAgLyoqIEVudGl0eU1hbmFnZXIgdGhhdCBleGVjdXRlZCB0aGUgcXVlcnkgKi9cclxuICBlbnRpdHlNYW5hZ2VyPzogRW50aXR5TWFuYWdlcjtcclxuICAvKiogVG90YWwgbnVtYmVyIG9mIHJlc3VsdHMgYXZhaWxhYmxlIG9uIHRoZSBzZXJ2ZXIgKi9cclxuICBpbmxpbmVDb3VudD86IG51bWJlcjtcclxuICAvKiogQWxsIGVudGl0aWVzIHJldHVybmVkIGJ5IHRoZSBxdWVyeS4gIERpZmZlcnMgZnJvbSBgcmVzdWx0c2Agd2hlbiBhbiBleHBhbmQgaXMgdXNlZC4gIEluY2x1ZGVzIGVudGl0aWVzIHRoYXQgYXJlIERlbGV0ZWQuICovXHJcbiAgcmV0cmlldmVkRW50aXRpZXM/OiBFbnRpdHlbXTtcclxuICAgIC8qKiBSYXcgcmVzcG9uc2UgZnJvbSB0aGUgc2VydmVyICovXHJcbiAgaHR0cFJlc3BvbnNlPzogSHR0cFJlc3BvbnNlO1xyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFF1ZXJ5U3VjY2Vzc0NhbGxiYWNrIHtcclxuICAoZGF0YTogUXVlcnlSZXN1bHQpOiB2b2lkO1xyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFF1ZXJ5RXJyb3JDYWxsYmFjayB7XHJcbiAgKGVycm9yOiB7IHF1ZXJ5OiBFbnRpdHlRdWVyeTsgaHR0cFJlc3BvbnNlOiBIdHRwUmVzcG9uc2U7IGVudGl0eU1hbmFnZXI6IEVudGl0eU1hbmFnZXI7IG1lc3NhZ2U/OiBzdHJpbmc7IHN0YWNrPzogc3RyaW5nIH0pOiB2b2lkO1xyXG59XHJcblxyXG4vKiogS2V5IG1hcHBpbmcgaW5mb3JtYXRpb24gcmV0dXJuZWQgYXMgcGFydCBvZiBhbiBbW0lTYXZlUmVzdWx0XV0uICovXHJcbmV4cG9ydCBpbnRlcmZhY2UgS2V5TWFwcGluZyB7XHJcbiAgZW50aXR5VHlwZU5hbWU6IHN0cmluZztcclxuICB0ZW1wVmFsdWU6IGFueTtcclxuICByZWFsVmFsdWU6IGFueTtcclxufVxyXG5cclxuaW50ZXJmYWNlIElUZW1wS2V5TWFwIHtcclxuICBbaW5kZXg6IHN0cmluZ106IEVudGl0eUtleTtcclxufVxyXG5cclxuLyoqIENvbmZpZ3VyYXRpb24gaW5mbyB0byBiZSBwYXNzZWQgdG8gdGhlIFtbRW50aXR5TWFuYWdlci5pbXBvcnRFbnRpdGllc11dIG1ldGhvZCAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIEltcG9ydENvbmZpZyB7XHJcbiAgLyoqIElmIHRydWUsIG1lcmdlIEFkZGVkIGVudGl0aWVzICh3aXRoIHRlbXAga2V5cykgYXMgd2VsbC4gIFRoaXMgY2FuIGJlIGRhbmdlcm91cy4gKi9cclxuICBtZXJnZUFkZHM/OiBib29sZWFuO1xyXG4gIG1lcmdlU3RyYXRlZ3k/OiBNZXJnZVN0cmF0ZWd5OyAgXHJcbiAgbWV0YWRhdGFWZXJzaW9uRm4/OiAoYXJnOiB7IG1ldGFkYXRhVmVyc2lvbjogYW55LCBtZXRhZGF0YVN0b3JlTmFtZTogYW55IH0pID0+IHZvaWQ7XHJcbn1cclxuXHJcbmludGVyZmFjZSBJbXBvcnRDb25maWdFeHQgZXh0ZW5kcyBJbXBvcnRDb25maWcge1xyXG4gIHRlbXBLZXlNYXA/OiBJVGVtcEtleU1hcDtcclxufVxyXG5cclxuLyoqIFRoZSBzaGFwZSBvZiB0aGUgUHJvbWlzZSByZXR1cm5lZCBieSBhbiBbW0VudGl0eU1hbmFnZXIuc2F2ZUNoYW5nZXNdXSBjYWxsLiAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIFNhdmVSZXN1bHQge1xyXG4gIGVudGl0aWVzOiBFbnRpdHlbXTtcclxuICBrZXlNYXBwaW5nczogS2V5TWFwcGluZ1tdO1xyXG4gIGRlbGV0ZWRLZXlzPzogeyBlbnRpdHlUeXBlTmFtZTogc3RyaW5nLCBrZXlWYWx1ZXM6IGFueVtdfVtdO1xyXG4gIGh0dHBSZXNwb25zZT86IEh0dHBSZXNwb25zZTtcclxufVxyXG5cclxuLyoqIEZvciB1c2UgYnkgYnJlZXplIHBsdWdpbiBhdXRob3JzIG9ubHkuIFRoZSBjbGFzcyBpcyBmb3IgdXNlIGluIGJ1aWxkaW5nIGEgW1tJRGF0YVNlcnZpY2VBZGFwdGVyXV0gaW1wbGVtZW50YXRpb24uIFxyXG5AYWRhcHRlciAoc2VlIFtbSURhdGFTZXJ2aWNlQWRhcHRlcl1dKSAgICBcclxuQGhpZGRlbiBcclxuKi9cclxuZXhwb3J0IGludGVyZmFjZSBTYXZlQ29udGV4dCB7XHJcbiAgZW50aXR5TWFuYWdlcjogRW50aXR5TWFuYWdlcjtcclxuICBkYXRhU2VydmljZTogRGF0YVNlcnZpY2U7XHJcbiAgcHJvY2Vzc1NhdmVkRW50aXRpZXM6IChzYXZlUmVzdWx0OiBTYXZlUmVzdWx0KSA9PiBFbnRpdHlbXTtcclxuICByZXNvdXJjZU5hbWU6IHN0cmluZztcclxuICBhZGFwdGVyPzogRGF0YVNlcnZpY2VBZGFwdGVyO1xyXG4gIHJvdXRlUHJlZml4Pzogc3RyaW5nO1xyXG59XHJcblxyXG4vKiogRm9yIHVzZSBieSBicmVlemUgcGx1Z2luIGF1dGhvcnMgb25seS4gVGhlIGNsYXNzIGlzIGZvciB1c2UgaW4gYnVpbGRpbmcgYSBbW0lEYXRhU2VydmljZUFkYXB0ZXJdXSBpbXBsZW1lbnRhdGlvbi4gXHJcbkBhZGFwdGVyIChzZWUgW1tJRGF0YVNlcnZpY2VBZGFwdGVyXV0pICAgIFxyXG5AaGlkZGVuIFxyXG4qL1xyXG5leHBvcnQgaW50ZXJmYWNlIFNhdmVCdW5kbGUge1xyXG4gIGVudGl0aWVzOiBFbnRpdHlbXTtcclxuICBzYXZlT3B0aW9uczogU2F2ZU9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKiBDb25maWd1cmF0aW9uIGluZm8gdG8gYmUgcGFzc2VkIHRvIHRoZSBbW0VudGl0eU1hbmFnZXJdXSBjb25zdHJ1Y3RvciAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIEVudGl0eU1hbmFnZXJDb25maWcge1xyXG4gIC8qKiBUaGUgc2VydmljZSBuYW1lIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEVudGl0eU1hbmFnZXIuICAqKi9cclxuICBzZXJ2aWNlTmFtZT86IHN0cmluZztcclxuICAvKiogVGhlIERhdGFTZXJ2aWNlIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEVudGl0eU1hbmFnZXIuICoqL1xyXG4gIGRhdGFTZXJ2aWNlPzogRGF0YVNlcnZpY2U7XHJcbiAgLyoqIFRoZSBbW1F1ZXJ5T3B0aW9uc11dIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEVudGl0eU1hbmFnZXIuICAqKi9cclxuICBxdWVyeU9wdGlvbnM/OiBRdWVyeU9wdGlvbnM7XHJcbiAgLyoqIFRoZSBbW1NhdmVPcHRpb25zXV0gYXNzb2NpYXRlZCB3aXRoIHRoaXMgRW50aXR5TWFuYWdlci4gKiovXHJcbiAgc2F2ZU9wdGlvbnM/OiBTYXZlT3B0aW9ucztcclxuICAvKiogVGhlIFtbVmFsaWRhdGlvbk9wdGlvbnNdXSBhc3NvY2lhdGVkIHdpdGggdGhpcyBFbnRpdHlNYW5hZ2VyLiAgKiovXHJcbiAgdmFsaWRhdGlvbk9wdGlvbnM/OiBWYWxpZGF0aW9uT3B0aW9ucztcclxuICAvKiogVGhlIFtbS2V5R2VuZXJhdG9yXV0gYXNzb2NpYXRlZCB3aXRoIHRoaXMgRW50aXR5TWFuYWdlci4gKiovXHJcbiAga2V5R2VuZXJhdG9yPzogS2V5R2VuZXJhdG9yO1xyXG4gIC8qKiBUaGUgW1tLZXlHZW5lcmF0b3JdXSBjb25zdHJ1Y3RvciBhc3NvY2lhdGVkIHdpdGggdGhpcyBFbnRpdHlNYW5hZ2VyLiAqKi9cclxuICBrZXlHZW5lcmF0b3JDdG9yPzogeyBuZXcgKCk6IEtleUdlbmVyYXRvciB9OyAvLyBUT0RPOiByZXZpZXcgdGhpc1xyXG4gIC8qKiBUaGUgW1tNZXRhZGF0YVN0b3JlXV0gYXNzb2NpYXRlZCB3aXRoIHRoaXMgRW50aXR5TWFuYWdlci4gKiovXHJcbiAgbWV0YWRhdGFTdG9yZT86IE1ldGFkYXRhU3RvcmU7XHJcbn1cclxuXHJcbi8qKiBUaGUgc2hhcGUgcmV0dXJuZWQgYnkgY2FsbGJhY2tzIHJlZ2lzdGVyZWQgd2l0aCBbW0VudGl0eU1hbmFnZXIuZW50aXR5Q2hhbmdlZF1dIGV2ZW50ICovXHJcbmV4cG9ydCBpbnRlcmZhY2UgRW50aXR5Q2hhbmdlZEV2ZW50QXJncyB7XHJcbiAgZW50aXR5QWN0aW9uOiBFbnRpdHlBY3Rpb247XHJcbiAgZW50aXR5PzogRW50aXR5O1xyXG4gIGFyZ3M/OiBQcm9wZXJ0eUNoYW5nZWRFdmVudEFyZ3M7XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgVmFsaWRhdGlvbkVycm9yc0NoYW5nZWRFdmVudEFyZ3Mge1xyXG4gIGVudGl0eTogRW50aXR5OyBcclxuICBhZGRlZDogVmFsaWRhdGlvbkVycm9yW107IFxyXG4gIHJlbW92ZWQ6IFZhbGlkYXRpb25FcnJvcltdO1xyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIEhhc0NoYW5nZXNDaGFuZ2VkRXZlbnRBcmdzIHtcclxuICBlbnRpdHlNYW5hZ2VyOiBFbnRpdHlNYW5hZ2VyOyBcclxuICBoYXNDaGFuZ2VzOiBib29sZWFuO1xyXG59XHJcblxyXG4vKipcclxuSW5zdGFuY2VzIG9mIHRoZSBFbnRpdHlNYW5hZ2VyIGNvbnRhaW4gYW5kIG1hbmFnZSBjb2xsZWN0aW9ucyBvZiBlbnRpdGllcywgZWl0aGVyIHJldHJpZXZlZCBmcm9tIGEgYmFja2VuZCBkYXRhc3RvcmUgb3IgY3JlYXRlZCBvbiB0aGUgY2xpZW50LlxyXG4qKi9cclxuZXhwb3J0IGNsYXNzIEVudGl0eU1hbmFnZXIge1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIGRlY2xhcmUgXyR0eXBlTmFtZTogc3RyaW5nOyAvLyBhY3R1YWxseSBkZWZpbmVkIG9uIHByb3RvdHlwZVxyXG5cclxuICAvKiogVGhlIHNlcnZpY2UgbmFtZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBFbnRpdHlNYW5hZ2VyLiBfX1JlYWQgT25seV9fICoqL1xyXG4gIGRlY2xhcmUgc2VydmljZU5hbWU6IHN0cmluZztcclxuICAvKiogVGhlIERhdGFTZXJ2aWNlIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEVudGl0eU1hbmFnZXIuIF9fUmVhZCBPbmx5X18gKiovXHJcbiAgZGVjbGFyZSBkYXRhU2VydmljZTogRGF0YVNlcnZpY2U7XHJcbiAgLyoqIFRoZSBbW1F1ZXJ5T3B0aW9uc11dIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEVudGl0eU1hbmFnZXIuIF9fUmVhZCBPbmx5X18gKiovXHJcbiAgZGVjbGFyZSBxdWVyeU9wdGlvbnM6IFF1ZXJ5T3B0aW9ucztcclxuICAvKiogVGhlIFtbU2F2ZU9wdGlvbnNdXSBhc3NvY2lhdGVkIHdpdGggdGhpcyBFbnRpdHlNYW5hZ2VyLiBfX1JlYWQgT25seV9fICoqL1xyXG4gIGRlY2xhcmUgc2F2ZU9wdGlvbnM6IFNhdmVPcHRpb25zO1xyXG4gIC8qKiBUaGUgW1tWYWxpZGF0aW9uT3B0aW9uc11dIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEVudGl0eU1hbmFnZXIuIF9fUmVhZCBPbmx5X18gKiovXHJcbiAgZGVjbGFyZSB2YWxpZGF0aW9uT3B0aW9uczogVmFsaWRhdGlvbk9wdGlvbnM7XHJcbiAgLyoqIFRoZSBbW0tleUdlbmVyYXRvcl1dIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEVudGl0eU1hbmFnZXIuIF9fUmVhZCBPbmx5X18gKiovXHJcbiAgZGVjbGFyZSBrZXlHZW5lcmF0b3I6IEtleUdlbmVyYXRvcjtcclxuICAvKiogVGhlIFtbS2V5R2VuZXJhdG9yXV0gY29uc3RydWN0b3IgYXNzb2NpYXRlZCB3aXRoIHRoaXMgRW50aXR5TWFuYWdlci4gX19SZWFkIE9ubHlfXyAqKi9cclxuICBkZWNsYXJlIGtleUdlbmVyYXRvckN0b3I6IHsgbmV3ICgpOiBLZXlHZW5lcmF0b3IgfTsgLy8gVE9ETzogcmV2aWV3IHRoaXNcclxuICAvKiogVGhlIFtbTWV0YWRhdGFTdG9yZV1dIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEVudGl0eU1hbmFnZXIuIF9fUmVhZCBPbmx5X18gKiovXHJcbiAgZGVjbGFyZSBtZXRhZGF0YVN0b3JlOiBNZXRhZGF0YVN0b3JlO1xyXG4gIGRlY2xhcmUgaXNMb2FkaW5nOiBib29sZWFuO1xyXG4gIGRlY2xhcmUgaXNSZWplY3RpbmdDaGFuZ2VzOiBib29sZWFuO1xyXG5cclxuICAvLyBldmVudHNcclxuICAvKipcclxuICBBIFtbQnJlZXplRXZlbnRdXSB0aGF0IGZpcmVzIHdoZW5ldmVyIGEgY2hhbmdlIHRvIGFueSBlbnRpdHkgaW4gdGhpcyBFbnRpdHlNYW5hZ2VyIG9jY3Vycy4gX19SZWFkIE9ubHlfX1xyXG5cclxuICBAZXZlbnRBcmdzIC0gXHJcbiAgLSBlbnRpdHlBY3Rpb24gLSBUaGUgW1tFbnRpdHlBY3Rpb25dXSB0aGF0IG9jY3VyZWQuXHJcbiAgLSBlbnRpdHkgLSBUaGUgZW50aXR5IHRoYXQgY2hhbmdlZC4gIElmIHRoaXMgaXMgbnVsbCwgdGhlbiBhbGwgZW50aXRpZXMgaW4gdGhlIGVudGl0eU1hbmFnZXIgd2VyZSBhZmZlY3RlZC5cclxuICAtIGFyZ3MgLSBBZGRpdGlvbmFsIGluZm9ybWF0aW9uIGFib3V0IHRoaXMgZXZlbnQuIFRoaXMgd2lsbCBkaWZmZXIgYmFzZWQgb24gdGhlIGVudGl0eUFjdGlvbi5cclxuXHJcbiAgPiAgICAgIGxldCBlbSA9IG5ldyBFbnRpdHlNYW5hZ2VyKCB7c2VydmljZU5hbWU6IFwiYnJlZXplL05vcnRod2luZElCTW9kZWxcIiB9KTtcclxuICA+ICAgICAgZW0uZW50aXR5Q2hhbmdlZC5zdWJzY3JpYmUoZnVuY3Rpb24oY2hhbmdlQXJncykge1xyXG4gID4gICAgICAgICAgLy8gVGhpcyBjb2RlIHdpbGwgYmUgZXhlY3V0ZWQgYW55IHRpbWUgYW55IGVudGl0eSB3aXRoaW4gdGhlIGVudGl0eU1hbmFnZXIgXHJcbiAgPiAgICAgICAgICAvLyBpcyBhZGRlZCwgbW9kaWZpZWQsIGRlbGV0ZWQgb3IgZGV0YWNoZWQgZm9yIGFueSByZWFzb24uXHJcbiAgPiAgICAgICAgICBsZXQgYWN0aW9uID0gY2hhbmdlQXJncy5lbnRpdHlBY3Rpb247XHJcbiAgPiAgICAgICAgICBsZXQgZW50aXR5ID0gY2hhbmdlQXJncy5lbnRpdHk7XHJcbiAgPiAgICAgICAgICAvLyAuLiBkbyBzb21ldGhpbmcgdG8gdGhpcyBlbnRpdHkgd2hlbiBpdCBpcyBjaGFuZ2VkLlxyXG4gID4gICAgICB9KTtcclxuICA+ICB9KTtcclxuICBAZXZlbnRcclxuICAqKi9cclxuICBlbnRpdHlDaGFuZ2VkOiBCcmVlemVFdmVudDxFbnRpdHlDaGFuZ2VkRXZlbnRBcmdzPjtcclxuXHJcbiAgLyoqXHJcbiAgQW4gW1tCcmVlemVFdmVudF1dIHRoYXQgZmlyZXMgd2hlbmV2ZXIgdmFsaWRhdGlvbkVycm9ycyBjaGFuZ2UgZm9yIGFueSBlbnRpdHkgaW4gdGhpcyBFbnRpdHlNYW5hZ2VyLiBfX1JlYWQgT25seV9fXHJcbiAgQGV2ZW50QXJncyAtXHJcbiAgICAtIGVudGl0eSAtIFRoZSBlbnRpdHkgb24gd2hpY2ggdGhlIHZhbGlkYXRpb24gZXJyb3JzIGhhdmUgYmVlbiBhZGRlZCBvciByZW1vdmVkLlxyXG4gICAgLSBhZGRlZCAtIEFuIGFycmF5IGNvbnRhaW5pbmcgYW55IG5ld2x5IGFkZGVkIFtbVmFsaWRhdGlvbkVycm9yXV1zXHJcbiAgICAtIHJlbW92ZWQgLSBBbiBhcnJheSBjb250YWluaW5nIGFueSBuZXdseSByZW1vdmVkIFtbVmFsaWRhdGlvbkVycm9yXV1zLiBUaGlzIGlzIHRob3NlIGVycm9ycyB0aGF0IGhhdmUgYmVlbiAnZml4ZWQnICBcclxuXHJcbiAgPiAgICAgIGxldCBlbSA9IG5ldyBFbnRpdHlNYW5hZ2VyKCB7c2VydmljZU5hbWU6IFwiYnJlZXplL05vcnRod2luZElCTW9kZWxcIiB9KTtcclxuICA+ICAgICAgZW0udmFsaWRhdGlvbkVycm9yc0NoYW5nZWQuc3Vic2NyaWJlKGZ1bmN0aW9uKGNoYW5nZUFyZ3MpIHtcclxuICA+ICAgICAgICAgICAgICAvLyBUaGlzIGNvZGUgd2lsbCBiZSBleGVjdXRlZCBhbnkgdGltZSBhbnkgZW50aXR5IHdpdGhpbiB0aGUgZW50aXR5TWFuYWdlciBleHBlcmllbmNlcyBhIGNoYW5nZSB0byBpdHMgdmFsaWRhdGlvbkVycm9ycyBjb2xsZWN0aW9uLlxyXG4gID4gICAgICAgICAgICAgIGZ1bmN0aW9uICh2YWxpZGF0aW9uQ2hhbmdlQXJncykge1xyXG4gID4gICAgICAgICAgICAgICAgICBsZXQgZW50aXR5ID09IHZhbGlkYXRpb25DaGFuZ2VBcmdzLmVudGl0eTtcclxuICA+ICAgICAgICAgICAgICAgICAgbGV0IGVycm9yc0FkZGVkID0gdmFsaWRhdGlvbkNoYW5nZUFyZ3MuYWRkZWQ7XHJcbiAgPiAgICAgICAgICAgICAgICAgIGxldCBlcnJvcnNDbGVhcmVkID0gdmFsaWRhdGlvbkNoYW5nZUFyZ3MucmVtb3ZlZDtcclxuICA+ICAgICAgICAgICAgICAgICAgLy8gLi4uIGRvIHNvbWV0aGluZyBpbnRlcmVzdGluZyB3aXRoIHRoZSBvcmRlci5cclxuICA+ICAgICAgICAgICAgICB9KTtcclxuICA+ICAgICAgICAgIH0pO1xyXG4gID4gICAgICB9KTtcclxuICBAZXZlbnRcclxuICAqKi9cclxuICB2YWxpZGF0aW9uRXJyb3JzQ2hhbmdlZDogQnJlZXplRXZlbnQ8VmFsaWRhdGlvbkVycm9yc0NoYW5nZWRFdmVudEFyZ3M+O1xyXG5cclxuICAvKipcclxuICBBIFtbQnJlZXplRXZlbnRdXSB0aGF0IGZpcmVzIHdoZW5ldmVyIGFuIEVudGl0eU1hbmFnZXIgdHJhbnNpdGlvbnMgdG8gb3IgZnJvbSBoYXZpbmcgY2hhbmdlcy4gX19SZWFkIE9ubHlfX1xyXG4gIEBldmVudEFyZ3MgLVxyXG4gICAgLSBlbnRpdHlNYW5hZ2VyIC0gVGhlIEVudGl0eU1hbmFnZXIgd2hvc2UgJ2hhc0NoYW5nZXMnIHN0YXR1cyBoYXMgY2hhbmdlZC5cclxuICAgIC0gaGFzQ2hhbmdlcyAtIFdoZXRoZXIgb3Igbm90IHRoaXMgRW50aXR5TWFuYWdlciBoYXMgY2hhbmdlcy5cclxuXHJcbiAgPiAgICAgIGxldCBlbSA9IG5ldyBFbnRpdHlNYW5hZ2VyKCB7c2VydmljZU5hbWU6IFwiYnJlZXplL05vcnRod2luZElCTW9kZWxcIiB9KTtcclxuICA+ICAgICAgZW0uaGFzQ2hhbmdlc0NoYW5nZWQuc3Vic2NyaWJlKGZ1bmN0aW9uKGFyZ3MpIHtcclxuICA+ICAgICAgICAgICAgICBsZXQgaGFzQ2hhbmdlc0NoYW5nZWQgPSBhcmdzLmhhc0NoYW5nZXM7XHJcbiAgPiAgICAgICAgICAgICAgbGV0IGVudGl0eU1hbmFnZXIgPSBhcmdzLmVudGl0eU1hbmFnZXI7XHJcbiAgPiAgICAgICAgICB9KTtcclxuICA+ICAgICAgfSk7XHJcbiAgQGV2ZW50IFxyXG4gICoqL1xyXG4gIGhhc0NoYW5nZXNDaGFuZ2VkOiBCcmVlemVFdmVudDxIYXNDaGFuZ2VzQ2hhbmdlZEV2ZW50QXJncz47XHJcblxyXG5cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfcGVuZGluZ1B1YnM/OiBhbnlbXTsgLy8gVE9ETzogcmVmaW5lIGxhdGVyXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2hhc0NoYW5nZXNBY3Rpb24/OiAoKCkgPT4gYm9vbGVhbik7IC8vIFRPRE8gcmVmaW5lIGxhdGVyXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2hhc0NoYW5nZXM6IGJvb2xlYW47XHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2VudGl0eUdyb3VwTWFwOiB7IFtpbmRleDogc3RyaW5nXTogRW50aXR5R3JvdXAgfTtcclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfdW5hdHRhY2hlZENoaWxkcmVuTWFwOiBVbmF0dGFjaGVkQ2hpbGRyZW5NYXA7XHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2luS2V5Rml4dXA6IGJvb2xlYW47XHJcblxyXG4gIGhlbHBlciA9IHtcclxuICAgIHVud3JhcEluc3RhbmNlOiB1bndyYXBJbnN0YW5jZSxcclxuICAgIHVud3JhcE9yaWdpbmFsVmFsdWVzOiB1bndyYXBPcmlnaW5hbFZhbHVlcyxcclxuICAgIHVud3JhcENoYW5nZWRWYWx1ZXM6IHVud3JhcENoYW5nZWRWYWx1ZXNcclxuICB9O1xyXG5cclxuICAvKipcclxuICBFbnRpdHlNYW5hZ2VyIGNvbnN0cnVjdG9yLlxyXG5cclxuICBBdCBpdHMgbW9zdCBiYXNpYyBhbiBFbnRpdHlNYW5hZ2VyIGNhbiBiZSBjb25zdHJ1Y3RlZCB3aXRoIGp1c3QgYSBzZXJ2aWNlIG5hbWVcclxuICA+ICAgICBsZXQgZW50aXR5TWFuYWdlciA9IG5ldyBFbnRpdHlNYW5hZ2VyKCBcImJyZWV6ZS9Ob3J0aHdpbmRJQk1vZGVsXCIpO1xyXG5cclxuICBUaGlzIGlzIHRoZSBzYW1lIGFzIGNhbGxpbmcgaXQgd2l0aCB0aGUgZm9sbG93aW5nIGNvbmZpZ3VyYXRpb24gb2JqZWN0XHJcbiAgPiAgICAgbGV0IGVudGl0eU1hbmFnZXIgPSBuZXcgRW50aXR5TWFuYWdlcigge3NlcnZpY2VOYW1lOiBcImJyZWV6ZS9Ob3J0aHdpbmRJQk1vZGVsXCIgfSk7XHJcblxyXG4gIFVzdWFsbHkgaG93ZXZlciwgY29uZmlndXJhdGlvbiBvYmplY3RzIHdpbGwgY29udGFpbiBtb3JlIHRoYW4ganVzdCB0aGUgJ3NlcnZpY2VOYW1lJztcclxuICA+ICAgICBsZXQgbWV0YWRhdGFTdG9yZSA9IG5ldyBNZXRhZGF0YVN0b3JlKCk7XHJcbiAgPiAgICAgbGV0IGVudGl0eU1hbmFnZXIgPSBuZXcgRW50aXR5TWFuYWdlcigge1xyXG4gID4gICAgICAgc2VydmljZU5hbWU6IFwiYnJlZXplL05vcnRod2luZElCTW9kZWxcIixcclxuICA+ICAgICAgIG1ldGFkYXRhU3RvcmU6IG1ldGFkYXRhU3RvcmVcclxuICA+ICAgICB9KTtcclxuXHJcbiAgb3JcclxuICA+ICAgICByZXR1cm4gbmV3IFF1ZXJ5T3B0aW9ucyh7XHJcbiAgPiAgICAgICAgIG1lcmdlU3RyYXRlZ3k6IG9iaixcclxuICA+ICAgICAgICAgZmV0Y2hTdHJhdGVneTogdGhpcy5mZXRjaFN0cmF0ZWd5XHJcbiAgPiAgICAgfSk7XHJcbiAgPiAgICAgbGV0IHF1ZXJ5T3B0aW9ucyA9IG5ldyBRdWVyeU9wdGlvbnMoe1xyXG4gID4gICAgICAgICBtZXJnZVN0cmF0ZWd5OiBNZXJnZVN0cmF0ZWd5Lk92ZXJ3cml0ZUNoYW5nZXMsXHJcbiAgPiAgICAgICAgIGZldGNoU3RyYXRlZ3k6IEZldGNoU3RyYXRlZ3kuRnJvbVNlcnZlclxyXG4gID4gICAgIH0pO1xyXG4gID4gICAgIGxldCB2YWxpZGF0aW9uT3B0aW9ucyA9IG5ldyBWYWxpZGF0aW9uT3B0aW9ucyh7XHJcbiAgPiAgICAgICAgIHZhbGlkYXRlT25BdHRhY2g6IHRydWUsXHJcbiAgPiAgICAgICAgIHZhbGlkYXRlT25TYXZlOiB0cnVlLFxyXG4gID4gICAgICAgICB2YWxpZGF0ZU9uUXVlcnk6IGZhbHNlXHJcbiAgPiAgICAgfSk7XHJcbiAgPiAgICAgbGV0IGVudGl0eU1hbmFnZXIgPSBuZXcgRW50aXR5TWFuYWdlcih7XHJcbiAgPiAgICAgICAgIHNlcnZpY2VOYW1lOiBcImJyZWV6ZS9Ob3J0aHdpbmRJQk1vZGVsXCIsXHJcbiAgPiAgICAgICAgIHF1ZXJ5T3B0aW9uczogcXVlcnlPcHRpb25zLFxyXG4gID4gICAgICAgICB2YWxpZGF0aW9uT3B0aW9uczogdmFsaWRhdGlvbk9wdGlvbnNcclxuICA+ICAgICB9KTtcclxuICBAcGFyYW0gZW1Db25maWcgLSBDb25maWd1cmF0aW9uIHNldHRpbmdzIG9yIGEgc2VydmljZSBuYW1lLiAgXHJcbiAgKiovXHJcbiAgY29uc3RydWN0b3IoZW1Db25maWc/OiBFbnRpdHlNYW5hZ2VyQ29uZmlnIHwgc3RyaW5nKSB7XHJcblxyXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIlRoZSBFbnRpdHlNYW5hZ2VyIGN0b3IgaGFzIGEgc2luZ2xlIG9wdGlvbmFsIGFyZ3VtZW50IHRoYXQgaXMgZWl0aGVyIGEgJ3NlcnZpY2VOYW1lJyBvciBhIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlwiKTtcclxuICAgIH1cclxuICAgIGxldCBjb25maWc6IEVudGl0eU1hbmFnZXJDb25maWc7XHJcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICBjb25maWcgPSB7IHNlcnZpY2VOYW1lOiBcIlwiIH07XHJcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBlbUNvbmZpZyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgY29uZmlnID0geyBzZXJ2aWNlTmFtZTogZW1Db25maWcgfTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGNvbmZpZyA9IGVtQ29uZmlnIHx8IHt9O1xyXG4gICAgfVxyXG5cclxuICAgIEVudGl0eU1hbmFnZXIuX3VwZGF0ZVdpdGhDb25maWcodGhpcywgY29uZmlnLCB0cnVlKTtcclxuXHJcbiAgICB0aGlzLmVudGl0eUNoYW5nZWQgPSBuZXcgQnJlZXplRXZlbnQoXCJlbnRpdHlDaGFuZ2VkXCIsIHRoaXMpO1xyXG4gICAgdGhpcy52YWxpZGF0aW9uRXJyb3JzQ2hhbmdlZCA9IG5ldyBCcmVlemVFdmVudChcInZhbGlkYXRpb25FcnJvcnNDaGFuZ2VkXCIsIHRoaXMpO1xyXG4gICAgdGhpcy5oYXNDaGFuZ2VzQ2hhbmdlZCA9IG5ldyBCcmVlemVFdmVudChcImhhc0NoYW5nZXNDaGFuZ2VkXCIsIHRoaXMpO1xyXG5cclxuICAgIHRoaXMuY2xlYXIoKTtcclxuXHJcbiAgfVxyXG5cclxuICAvKipcclxuICBHZW5lcmFsIHB1cnBvc2UgcHJvcGVydHkgc2V0IG1ldGhvZC4gIEFueSBvZiB0aGUgcHJvcGVydGllcyBpbiB0aGUgW1tFbnRpdHlNYW5hZ2VyQ29uZmlnXV1cclxuICBtYXkgYmUgc2V0LlxyXG4gID4gICAgICAvLyBhc3N1bWUgZW0xIGlzIGEgcHJldmlvdXNseSBjcmVhdGVkIEVudGl0eU1hbmFnZXJcclxuICA+ICAgICAgLy8gd2hlcmUgd2Ugd2FudCB0byBjaGFuZ2Ugc29tZSBvZiBpdHMgc2V0dGluZ3MuXHJcbiAgPiAgICAgIGVtMS5zZXRQcm9wZXJ0aWVzKCB7XHJcbiAgPiAgICAgICAgICBzZXJ2aWNlTmFtZTogXCJicmVlemUvZm9vXCJcclxuICA+ICAgICAgfSk7XHJcbiAgQHBhcmFtIGNvbmZpZyAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBzZWxlY3RlZCBwcm9wZXJ0aWVzIGFuZCB2YWx1ZXMgdG8gc2V0LlxyXG4gICoqL1xyXG4gIHNldFByb3BlcnRpZXMoY29uZmlnOiBFbnRpdHlNYW5hZ2VyQ29uZmlnKSB7XHJcbiAgICBFbnRpdHlNYW5hZ2VyLl91cGRhdGVXaXRoQ29uZmlnKHRoaXMsIGNvbmZpZywgZmFsc2UpO1xyXG4gIH1cclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgc3RhdGljIF91cGRhdGVXaXRoQ29uZmlnKGVtOiBFbnRpdHlNYW5hZ2VyLCBjb25maWc6IEVudGl0eU1hbmFnZXJDb25maWcsIGlzQ3RvcjogYm9vbGVhbikge1xyXG4gICAgbGV0IGRlZmF1bHRRdWVyeU9wdGlvbnMgPSBpc0N0b3IgPyBRdWVyeU9wdGlvbnMuZGVmYXVsdEluc3RhbmNlIDogZW0ucXVlcnlPcHRpb25zO1xyXG4gICAgbGV0IGRlZmF1bHRTYXZlT3B0aW9ucyA9IGlzQ3RvciA/IFNhdmVPcHRpb25zLmRlZmF1bHRJbnN0YW5jZSA6IGVtLnNhdmVPcHRpb25zO1xyXG4gICAgbGV0IGRlZmF1bHRWYWxpZGF0aW9uT3B0aW9ucyA9IGlzQ3RvciA/IFZhbGlkYXRpb25PcHRpb25zLmRlZmF1bHRJbnN0YW5jZSA6IGVtLnZhbGlkYXRpb25PcHRpb25zO1xyXG5cclxuICAgIGxldCBjb25maWdQYXJhbSA9IGFzc2VydENvbmZpZyhjb25maWcpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwic2VydmljZU5hbWVcIikuaXNPcHRpb25hbCgpLmlzU3RyaW5nKClcclxuICAgICAgLndoZXJlUGFyYW0oXCJkYXRhU2VydmljZVwiKS5pc09wdGlvbmFsKCkuaXNJbnN0YW5jZU9mKERhdGFTZXJ2aWNlKVxyXG4gICAgICAud2hlcmVQYXJhbShcInF1ZXJ5T3B0aW9uc1wiKS5pc0luc3RhbmNlT2YoUXVlcnlPcHRpb25zKS5pc09wdGlvbmFsKCkud2l0aERlZmF1bHQoZGVmYXVsdFF1ZXJ5T3B0aW9ucylcclxuICAgICAgLndoZXJlUGFyYW0oXCJzYXZlT3B0aW9uc1wiKS5pc0luc3RhbmNlT2YoU2F2ZU9wdGlvbnMpLmlzT3B0aW9uYWwoKS53aXRoRGVmYXVsdChkZWZhdWx0U2F2ZU9wdGlvbnMpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwidmFsaWRhdGlvbk9wdGlvbnNcIikuaXNJbnN0YW5jZU9mKFZhbGlkYXRpb25PcHRpb25zKS5pc09wdGlvbmFsKCkud2l0aERlZmF1bHQoZGVmYXVsdFZhbGlkYXRpb25PcHRpb25zKVxyXG4gICAgICAud2hlcmVQYXJhbShcImtleUdlbmVyYXRvckN0b3JcIikuaXNGdW5jdGlvbigpLmlzT3B0aW9uYWwoKTtcclxuICAgIGlmIChpc0N0b3IpIHtcclxuICAgICAgY29uZmlnUGFyYW0gPSBjb25maWdQYXJhbVxyXG4gICAgICAgIC53aGVyZVBhcmFtKFwibWV0YWRhdGFTdG9yZVwiKS5pc0luc3RhbmNlT2YoTWV0YWRhdGFTdG9yZSkuaXNPcHRpb25hbCgpLndpdGhEZWZhdWx0KG5ldyBNZXRhZGF0YVN0b3JlKCkpO1xyXG4gICAgfVxyXG4gICAgY29uZmlnUGFyYW0uYXBwbHlBbGwoZW0pO1xyXG5cclxuICAgIC8vIGluc3VyZSB0aGF0IGVudGl0eU1hbmFnZXIncyBvcHRpb25zIHZlcnNpb25zIGFyZSBjb21wbGV0ZWx5IHBvcHVsYXRlZFxyXG4gICAgY29yZS51cGRhdGVXaXRoRGVmYXVsdHMoZW0ucXVlcnlPcHRpb25zLCBkZWZhdWx0UXVlcnlPcHRpb25zKTtcclxuICAgIGNvcmUudXBkYXRlV2l0aERlZmF1bHRzKGVtLnNhdmVPcHRpb25zLCBkZWZhdWx0U2F2ZU9wdGlvbnMpO1xyXG4gICAgY29yZS51cGRhdGVXaXRoRGVmYXVsdHMoZW0udmFsaWRhdGlvbk9wdGlvbnMsIGRlZmF1bHRWYWxpZGF0aW9uT3B0aW9ucyk7XHJcblxyXG4gICAgaWYgKGNvbmZpZy5zZXJ2aWNlTmFtZSkge1xyXG4gICAgICBlbS5kYXRhU2VydmljZSA9IG5ldyBEYXRhU2VydmljZSh7XHJcbiAgICAgICAgc2VydmljZU5hbWU6IGVtLnNlcnZpY2VOYW1lXHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgZW0uc2VydmljZU5hbWUgPSBlbS5kYXRhU2VydmljZSAmJiBlbS5kYXRhU2VydmljZS5zZXJ2aWNlTmFtZTtcclxuXHJcbiAgICBlbS5rZXlHZW5lcmF0b3JDdG9yID0gZW0ua2V5R2VuZXJhdG9yQ3RvciB8fCBLZXlHZW5lcmF0b3I7XHJcbiAgICBpZiAoaXNDdG9yIHx8IGNvbmZpZy5rZXlHZW5lcmF0b3JDdG9yKSB7XHJcbiAgICAgIGVtLmtleUdlbmVyYXRvciA9IG5ldyBlbS5rZXlHZW5lcmF0b3JDdG9yKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBjcmVhdGVFbnRpdHkodHlwZU5hbWU6IHN0cmluZywgaW5pdGlhbFZhbHVlcz86IE9iamVjdCwgZW50aXR5U3RhdGU/OiBFbnRpdHlTdGF0ZSwgbWVyZ2VTdHJhdGVneT86IE1lcmdlU3RyYXRlZ3kpOiBFbnRpdHk7XHJcbiAgY3JlYXRlRW50aXR5KGVudGl0eVR5cGU6IEVudGl0eVR5cGUsIGluaXRpYWxWYWx1ZXM/OiBPYmplY3QsIGVudGl0eVN0YXRlPzogRW50aXR5U3RhdGUsIG1lcmdlU3RyYXRlZ3k/OiBNZXJnZVN0cmF0ZWd5KTogRW50aXR5O1xyXG4gIC8qKlxyXG4gIENyZWF0ZXMgYSBuZXcgZW50aXR5IG9mIGEgc3BlY2lmaWVkIHR5cGUgYW5kIG9wdGlvbmFsbHkgaW5pdGlhbGl6ZXMgaXQuIEJ5IGRlZmF1bHQgdGhlIG5ldyBlbnRpdHkgaXMgY3JlYXRlZCB3aXRoIGFuIEVudGl0eVN0YXRlIG9mIEFkZGVkXHJcbiAgYnV0IHlvdSBjYW4gYWxzbyBvcHRpb25hbGx5IHNwZWNpZnkgYW4gRW50aXR5U3RhdGUuICBBbiBFbnRpdHlTdGF0ZSBvZiAnRGV0YWNoZWQnIHdpbGwgaW5zdXJlIHRoYXQgdGhlIGVudGl0eSBpcyBjcmVhdGVkIGJ1dCBub3QgeWV0IGFkZGVkXHJcbiAgdG8gdGhlIEVudGl0eU1hbmFnZXIuIFxyXG4gID4gICAgICAvLyBhc3N1bWUgZW0xIGlzIGFuIEVudGl0eU1hbmFnZXIgY29udGFpbmluZyBhIG51bWJlciBvZiBwcmVleGlzdGluZyBlbnRpdGllcy5cclxuICA+ICAgICAgLy8gY3JlYXRlIGFuZCBhZGQgYW4gZW50aXR5O1xyXG4gID4gICAgICBsZXQgZW1wMSA9IGVtMS5jcmVhdGVFbnRpdHkoXCJFbXBsb3llZVwiKTtcclxuICA+ICAgICAgLy8gY3JlYXRlIGFuZCBhZGQgYW4gaW5pdGlhbGl6ZWQgZW50aXR5O1xyXG4gID4gICAgICBsZXQgZW1wMiA9IGVtMS5jcmVhdGVFbnRpdHkoXCJFbXBsb3llZVwiLCB7IGxhc3ROYW1lOiBcIlNtaXRoXCIsIGZpcnN0TmFtZTogXCJKb2huXCIgfSk7XHJcbiAgPiAgICAgIC8vIGNyZWF0ZSBhbmQgYXR0YWNoIChub3QgYWRkKSBhbiBpbml0aWFsaXplZCBlbnRpdHlcclxuICA+ICAgICAgbGV0IGVtcDMgPSBlbTEuY3JlYXRlRW50aXR5KFwiRW1wbG95ZWVcIiwgeyBpZDogNDM1LCBsYXN0TmFtZTogXCJTbWl0aFwiLCBmaXJzdE5hbWU6IFwiSm9oblwiIH0sIEVudGl0eVN0YXRlLlVuY2hhbmdlZCk7XHJcbiAgPiAgICAgIC8vIGNyZWF0ZSBidXQgZG9uJ3QgYXR0YWNoIGFuIGVudGl0eTtcclxuICA+ICAgICAgbGV0IGVtcDQgPSBlbTEuY3JlYXRlRW50aXR5KFwiRW1wbG95ZWVcIiwgeyBpZDogNDM1LCBsYXN0TmFtZTogXCJTbWl0aFwiLCBmaXJzdE5hbWU6IFwiSm9oblwiIH0sIEVudGl0eVN0YXRlLkRldGFjaGVkKTtcclxuICBAcGFyYW0gdHlwZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgRW50aXR5VHlwZSBmb3Igd2hpY2ggYW4gaW5zdGFuY2Ugc2hvdWxkIGJlIGNyZWF0ZWQuXHJcbiAgQHBhcmFtIGVudGl0eVR5cGUgLSBUaGUgRW50aXR5VHlwZSBvZiB0aGUgdHlwZSBmb3Igd2hpY2ggYW4gaW5zdGFuY2Ugc2hvdWxkIGJlIGNyZWF0ZWQuXHJcbiAgQHBhcmFtIGluaXRpYWxWYWx1ZXMgLSAoZGVmYXVsdD1udWxsKSBDb25maWd1cmF0aW9uIG9iamVjdCBvZiB0aGUgcHJvcGVydGllcyB0byBzZXQgaW1tZWRpYXRlbHkgYWZ0ZXIgY3JlYXRpb24uXHJcbiAgQHBhcmFtIGVudGl0eVN0YXRlIC0gKGRlZmF1bHQgPSBbW0VudGl0eVN0YXRlLkFkZGVkXV0pIFRoZSBFbnRpdHlTdGF0ZSBvZiB0aGUgZW50aXR5IGFmdGVyIGJlaW5nIGNyZWF0ZWQgYW5kIGFkZGVkIHRvIHRoaXMgRW50aXR5TWFuYWdlci5cclxuICBAcGFyYW0gbWVyZ2VTdHJhdGVneSAtIChkZWZhdWx0ID0gW1tNZXJnZVN0cmF0ZWd5LkRpc2FsbG93ZWRdXSkgLSBIb3cgdG8gaGFuZGxlIGNvbmZsaWN0cyBpZiBhbiBlbnRpdHkgd2l0aCB0aGUgc2FtZSBrZXkgYWxyZWFkeSBleGlzdHMgd2l0aGluIHRoaXMgRW50aXR5TWFuYWdlci5cclxuICBAcmV0dXJuIHtFbnRpdHl9IEEgbmV3IEVudGl0eSBvZiB0aGUgc3BlY2lmaWVkIHR5cGUuIFxyXG4gICovXHJcbiAgY3JlYXRlRW50aXR5KGVudGl0eVR5cGU6IEVudGl0eVR5cGUgfCBzdHJpbmcsIGluaXRpYWxWYWx1ZXM6IE9iamVjdCwgZW50aXR5U3RhdGU6IEVudGl0eVN0YXRlLCBtZXJnZVN0cmF0ZWd5OiBNZXJnZVN0cmF0ZWd5KSB7XHJcbiAgICBhc3NlcnRQYXJhbShlbnRpdHlUeXBlLCBcImVudGl0eVR5cGVcIikuaXNTdHJpbmcoKS5vcigpLmlzSW5zdGFuY2VPZihFbnRpdHlUeXBlKS5jaGVjaygpO1xyXG4gICAgYXNzZXJ0UGFyYW0oZW50aXR5U3RhdGUsIFwiZW50aXR5U3RhdGVcIikuaXNFbnVtT2YoRW50aXR5U3RhdGUpLmlzT3B0aW9uYWwoKS5jaGVjaygpO1xyXG4gICAgYXNzZXJ0UGFyYW0obWVyZ2VTdHJhdGVneSwgXCJtZXJnZVN0cmF0ZWd5XCIpLmlzRW51bU9mKE1lcmdlU3RyYXRlZ3kpLmlzT3B0aW9uYWwoKS5jaGVjaygpO1xyXG5cclxuICAgIGxldCBldCA9ICh0eXBlb2YgZW50aXR5VHlwZSA9PT0gXCJzdHJpbmdcIikgPyB0aGlzLm1ldGFkYXRhU3RvcmUuX2dldFN0cnVjdHVyYWxUeXBlKGVudGl0eVR5cGUpIGFzIEVudGl0eVR5cGUgOiBlbnRpdHlUeXBlO1xyXG4gICAgZW50aXR5U3RhdGUgPSBlbnRpdHlTdGF0ZSB8fCBFbnRpdHlTdGF0ZS5BZGRlZDtcclxuICAgIGxldCBlbnRpdHkgPSB7fSBhcyBFbnRpdHk7XHJcbiAgICBjb3JlLnVzaW5nKHRoaXMsIFwiaXNMb2FkaW5nXCIsIHRydWUsIGZ1bmN0aW9uICgpIHtcclxuICAgICAgZW50aXR5ID0gZXQuY3JlYXRlRW50aXR5KGluaXRpYWxWYWx1ZXMpO1xyXG4gICAgfSk7XHJcbiAgICBpZiAoZW50aXR5U3RhdGUgIT09IEVudGl0eVN0YXRlLkRldGFjaGVkKSB7XHJcbiAgICAgIGVudGl0eSA9IHRoaXMuYXR0YWNoRW50aXR5KGVudGl0eSwgZW50aXR5U3RhdGUsIG1lcmdlU3RyYXRlZ3kpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGVudGl0eTtcclxuICB9XHJcblxyXG4gIHN0YXRpYyBpbXBvcnRFbnRpdGllcyhleHBvcnRlZFN0cmluZzogc3RyaW5nLCBjb25maWc/OiBJbXBvcnRDb25maWcpOiBFbnRpdHlNYW5hZ2VyO1xyXG4gIHN0YXRpYyBpbXBvcnRFbnRpdGllcyhleHBvcnRlZERhdGE6IE9iamVjdCwgY29uZmlnPzogSW1wb3J0Q29uZmlnKTogRW50aXR5TWFuYWdlcjtcclxuICAvKipcclxuICBDcmVhdGVzIGEgbmV3IEVudGl0eU1hbmFnZXIgYW5kIGltcG9ydHMgYSBwcmV2aW91c2x5IGV4cG9ydGVkIHJlc3VsdCBpbnRvIGl0LlxyXG4gID4gICAgICAvLyBhc3N1bWUgZW0xIGlzIGFuIEVudGl0eU1hbmFnZXIgY29udGFpbmluZyBhIG51bWJlciBvZiBwcmVleGlzdGluZyBlbnRpdGllcy5cclxuICA+ICAgICAgbGV0IGJ1bmRsZSA9IGVtMS5leHBvcnRFbnRpdGllcygpO1xyXG4gID4gICAgICAvLyBjYW4gYmUgc3RvcmVkIHZpYSB0aGUgd2ViIHN0b3JhZ2UgYXBpXHJcbiAgPiAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbShcIm15RW50aXR5TWFuYWdlclwiLCBidW5kbGUpO1xyXG4gID4gICAgICAvLyBhc3N1bWUgdGhlIGNvZGUgYmVsb3cgb2NjdXJzIGluIGEgZGlmZmVyZW50IHNlc3Npb24uXHJcbiAgPiAgICAgIGxldCBidW5kbGVGcm9tU3RvcmFnZSA9IHdpbmRvdy5sb2NhbFN0b3JhZ2UuZ2V0SXRlbShcIm15RW50aXR5TWFuYWdlclwiKTtcclxuICA+ICAgICAgLy8gYW5kIGltcG9ydGVkXHJcbiAgPiAgICAgIGxldCBlbTIgPSBFbnRpdHlNYW5hZ2VyLmltcG9ydEVudGl0aWVzKGJ1bmRsZUZyb21TdG9yYWdlKTtcclxuICA+ICAgICAgLy8gZW0yIHdpbGwgbm93IGhhdmUgYSBjb21wbGV0ZSBjb3B5IG9mIHdoYXQgd2FzIGluIGVtMVxyXG4gIEBwYXJhbSBleHBvcnRlZFN0cmluZyAtIFRoZSByZXN1bHQgb2YgYSBwcmV2aW91cyAnZXhwb3J0RW50aXRpZXMnIGNhbGwgYXMgYSBzdHJpbmdcclxuICBAcGFyYW0gZXhwb3J0ZWREYXRhIC0gVGhlIHJlc3VsdCBvZiBhIHByZXZpb3VzICdleHBvcnRFbnRpdGllcycgY2FsbCBhcyBhbiBPYmplY3QuXHJcbiAgQHBhcmFtIGNvbmZpZyAtIEEgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAgQHBhcmFtIGNvbmZpZy5tZXJnZVN0cmF0ZWd5IC0gQSAgW1tNZXJnZVN0cmF0ZWd5XV0gdG8gdXNlIHdoZW4gXHJcbiAgbWVyZ2luZyBpbnRvIGFuIGV4aXN0aW5nIEVudGl0eU1hbmFnZXIuXHJcbiAgQHBhcmFtIGNvbmZpZy5tZXRhZGF0YVZlcnNpb25GbiAtIEEgZnVuY3Rpb24gdGhhdCB0YWtlcyB0d28gYXJndW1lbnRzICh0aGUgY3VycmVudCBtZXRhZGF0YVZlcnNpb24gYW5kIHRoZSBpbXBvcnRlZCBzdG9yZSdzICduYW1lJylcclxuICBhbmQgbWF5IGJlIHVzZWQgdG8gcGVyZm9ybSB2ZXJzaW9uIGNoZWNraW5nLlxyXG4gIEByZXR1cm4gQSBuZXcgRW50aXR5TWFuYWdlci4gIE5vdGUgdGhhdCB0aGUgcmV0dXJuIHZhbHVlIG9mIHRoaXMgbWV0aG9kIGNhbGwgaXMgZGlmZmVyZW50IGZyb20gdGhhdFxyXG4gIHByb3ZpZGVkIGJ5IHRoZSBzYW1lIG5hbWVkIG1ldGhvZCBvbiBhbiBFbnRpdHlNYW5hZ2VyIGluc3RhbmNlLiBVc2UgdGhhdCBtZXRob2QgaWYgeW91IG5lZWQgYWRkaXRpb25hbCBpbmZvcm1hdGlvblxyXG4gIHJlZ2FyZGluZyB0aGUgaW1wb3J0ZWQgZW50aXRpZXMuXHJcbiAgKiovXHJcbiAgc3RhdGljIGltcG9ydEVudGl0aWVzKGV4cG9ydGVkOiBzdHJpbmcgfCBPYmplY3QsIGNvbmZpZz86IEltcG9ydENvbmZpZykge1xyXG4gICAgbGV0IGVtID0gbmV3IEVudGl0eU1hbmFnZXIoKTtcclxuICAgIGVtLmltcG9ydEVudGl0aWVzKGV4cG9ydGVkLCBjb25maWcpO1xyXG4gICAgcmV0dXJuIGVtO1xyXG4gIH1cclxuXHJcbiAgLy8gaW5zdGFuY2UgbWV0aG9kc1xyXG5cclxuICAvKipcclxuICBDYWxscyBbW0VudGl0eUFzcGVjdC5hY2NlcHRDaGFuZ2VzXV0gb24gZXZlcnkgY2hhbmdlZCBlbnRpdHkgaW4gdGhpcyBFbnRpdHlNYW5hZ2VyLlxyXG4gICoqL1xyXG4gIGFjY2VwdENoYW5nZXMoKSB7XHJcbiAgICB0aGlzLmdldENoYW5nZXMoKS5tYXAoZnVuY3Rpb24gKGVudGl0eSkge1xyXG4gICAgICByZXR1cm4gZW50aXR5LmVudGl0eUFzcGVjdC5fY2hlY2tPcGVyYXRpb24oXCJhY2NlcHRDaGFuZ2VzXCIpO1xyXG4gICAgfSkuZm9yRWFjaChmdW5jdGlvbiAoYXNwZWN0KSB7XHJcbiAgICAgIGFzcGVjdC5hY2NlcHRDaGFuZ2VzKCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIEV4cG9ydHMgc2VsZWN0ZWQgZW50aXRpZXMsIGFsbCBlbnRpdGllcyBvZiBzZWxlY3RlZCB0eXBlcywgb3IgYW4gZW50aXJlIEVudGl0eU1hbmFnZXIgY2FjaGUuXHJcblxyXG4gIFRoaXMgbWV0aG9kIHRha2VzIGEgc25hcHNob3Qgb2YgYW4gRW50aXR5TWFuYWdlciB0aGF0IGNhbiBiZSBzdG9yZWQgb2ZmbGluZSBvciBoZWxkIGluIG1lbW9yeS5cclxuICBVc2UgdGhlIFtbRW50aXR5TWFuYWdlci5pbXBvcnRFbnRpdGllc11dIG1ldGhvZCB0byByZXN0b3JlIG9yIG1lcmdlIHRoZSBzbmFwc2hvdFxyXG4gIGludG8gYW5vdGhlciBFbnRpdHlNYW5hZ2VyIGF0IHNvbWUgbGF0ZXIgdGltZS5cclxuICA+ICAgICAgLy8gbGV0IGVtMSBiZSBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgLy8gZXhwb3J0IGV2ZXJ5IGVudGl0eSBpbiBlbTEuXHJcbiAgPiAgICAgbGV0IGJ1bmRsZSA9IGVtMS5leHBvcnRFbnRpdGllcygpO1xyXG4gID4gICAgIC8vIHNhdmUgdG8gdGhlIGJyb3dzZXIncyBsb2NhbCBzdG9yYWdlXHJcbiAgPiAgICAgd2luZG93LmxvY2FsU3RvcmFnZS5zZXRJdGVtKFwibXlFbnRpdHlNYW5hZ2VyXCIsIGJ1bmRsZSk7XHJcbiAgPiAgICAgLy8gbGF0ZXIgcmV0cmlldmUgdGhlIGV4cG9ydFxyXG4gID4gICAgIGxldCBidW5kbGVGcm9tU3RvcmFnZSA9IHdpbmRvdy5sb2NhbFN0b3JhZ2UuZ2V0SXRlbShcIm15RW50aXR5TWFuYWdlclwiKTtcclxuICA+ICAgICAvLyBpbXBvcnQgdGhlIHJldHJpZXZlZCBleHBvcnQgYnVuZGxlIGludG8gYW5vdGhlciBtYW5hZ2VyXHJcbiAgPiAgICAgbGV0IGVtMiA9IGVtMS5jcmVhdGVFbXB0eUNvcHkoKTtcclxuICA+ICAgICBlbTIuaW1wb3J0RW50aXRpZXMoYnVuZGxlRnJvbVN0b3JhZ2UpO1xyXG4gID4gICAgIC8vIGVtMiBub3cgaGFzIGEgY29tcGxldGUsIGZhaXRoZnVsIGNvcHkgb2YgdGhlIGVudGl0aWVzIHRoYXQgd2VyZSBpbiBlbTFcclxuXHJcbiAgWW91IGNhbiBhbHNvIGNvbnRyb2wgZXhhY3RseSB3aGljaCBlbnRpdGllcyBhcmUgZXhwb3J0ZWQuXHJcbiAgPiAgICAgLy8gZ2V0IGVtMSdzIHVuc2F2ZWQgY2hhbmdlcyAoYW4gYXJyYXkpIGFuZCBleHBvcnQgdGhlbS5cclxuICA+ICAgICBsZXQgY2hhbmdlcyA9IGVtMS5nZXRDaGFuZ2VzKCk7XHJcbiAgPiAgICAgbGV0IGJ1bmRsZSA9IGVtMS5leHBvcnRFbnRpdGllcyhjaGFuZ2VzKTtcclxuICA+ICAgICAvLyBtZXJnZSB0aGVzZSBlbnRpdGllcyBpbnRvIGVtMiB3aGljaCBtYXkgY29udGFpbnMgc29tZSBvZiB0aGUgc2FtZSBlbnRpdGllcy5cclxuICA+ICAgICAvLyBkbyBOT1Qgb3ZlcndyaXRlIHRoZSBlbnRpdGllcyBpbiBlbTIgaWYgdGhleSB0aGVtc2VsdmVzIGhhdmUgdW5zYXZlZCBjaGFuZ2VzLlxyXG4gID4gICAgIGVtMi5pbXBvcnRFbnRpdGllcyhidW5kbGUsIHsgbWVyZ2VTdHJhdGVneTogTWVyZ2VTdHJhdGVneS5QcmVzZXJ2ZUNoYW5nZXN9ICk7XHJcblxyXG4gIE1ldGFkYXRhIGFyZSBpbmNsdWRlZCBpbiBhbiBleHBvcnQgYnkgZGVmYXVsdC4gWW91IG1heSB3YW50IHRvIGV4Y2x1ZGUgdGhlIG1ldGFkYXRhXHJcbiAgZXNwZWNpYWxseSBpZiB5b3UncmUgZXhwb3J0aW5nIGp1c3QgYSBmZXcgZW50aXRpZXMgZm9yIGxvY2FsIHN0b3JhZ2UuXHJcbiAgPiAgICAgbGV0IGJ1bmRsZSA9IGVtMS5leHBvcnRFbnRpdGllcyhhcnJheU9mU2VsZWN0ZWRFbnRpdGllcywge2luY2x1ZGVNZXRhZGF0YTogZmFsc2V9KTtcclxuICA+ICAgICB3aW5kb3cubG9jYWxTdG9yYWdlLnNldEl0ZW0oXCJnb29kU3R1ZmZcIiwgYnVuZGxlKTtcclxuXHJcbiAgWW91IG1heSBzdGlsbCBleHByZXNzIHRoaXMgb3B0aW9uIGFzIGEgYm9vbGVhbiB2YWx1ZSBhbHRob3VnaCB0aGlzIG9sZGVyIHN5bnRheCBpcyBkZXByZWNhdGVkLlxyXG4gID4gICAgIC8vIEV4Y2x1ZGUgdGhlIG1ldGFkYXRhIChkZXByZWNhdGVkIHN5bnRheClcclxuICA+ICAgICBsZXQgYnVuZGxlID0gZW0xLmV4cG9ydEVudGl0aWVzKGFycmF5T2ZTZWxlY3RlZEVudGl0aWVzLCBmYWxzZSk7XHJcblxyXG4gIFlvdSBjYW4gZXhwb3J0IGFsbCBlbnRpdGllcyBvZiBvbmUgb3IgbW9yZSBzcGVjaWZpZWQgRW50aXR5VHlwZXMuXHJcbiAgPiAgICAgLy8gRXhwb3J0IGFsbCBDdXN0b21lciBhbmQgRW1wbG95ZWUgZW50aXRpZXMgKGFuZCBhbHNvIGV4Y2x1ZGUgbWV0YWRhdGEpXHJcbiAgPiAgICAgbGV0IGJ1bmRsZSA9IGVtMS5leHBvcnRFbnRpdGllcyhbJ0N1c3RvbWVyJywgJ0VtcGxveWVlJ10sIHtpbmNsdWRlTWV0YWRhdGE6IGZhbHNlfSk7XHJcblxyXG4gIEFsbCBvZiB0aGUgYWJvdmUgZXhhbXBsZXMgcmV0dXJuIGFuIGV4cG9ydCBidW5kbGUgYXMgYSBzdHJpbmcgd2hpY2ggaXMgdGhlIGRlZmF1bHQgZm9ybWF0LlxyXG4gIFlvdSBjYW4gZXhwb3J0IHRoZSBidW5kbGUgYXMgSlNPTiBpZiB5b3UgcHJlZmVyIGJ5IHNldHRpbmcgdGhlIGBhc1N0cmluZ2Agb3B0aW9uIHRvIGZhbHNlLlxyXG4gID4gICAgIC8vIEV4cG9ydCBhbGwgQ3VzdG9tZXIgYW5kIEVtcGxveWVlIGVudGl0aWVzIGFzIEpTT04gYW5kIGV4Y2x1ZGUgdGhlIG1ldGFkYXRhXHJcbiAgPiAgICAgbGV0IGJ1bmRsZSA9IGVtMS5leHBvcnRFbnRpdGllcyhbJ0N1c3RvbWVyJywgJ0VtcGxveWVlJ10sXHJcbiAgPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7YXNTdHJpbmc6IGZhbHNlLCBpbmNsdWRlTWV0YWRhdGE6IGZhbHNlfSk7XHJcbiAgPiAgICAgLy8gc3RvcmUgSlNPTiBidW5kbGUgc29tZXdoZXJlIC4uLiBwZXJoYXBzIGluZGV4RGIgLi4uIGFuZCBsYXRlciBpbXBvcnQgYXMgd2UgZG8gaGVyZS5cclxuICA+ICAgICBlbTIuaW1wb3J0RW50aXRpZXMoYnVuZGxlKTtcclxuICBAcGFyYW0gZW50aXRpZXMgLSBUaGUgZW50aXRpZXMgdG8gZXhwb3J0IG9yIHRoZSBFbnRpdHlUeXBlKHMpIG9mIHRoZSBlbnRpdGllcyB0byBleHBvcnQ7XHJcbiAgICBhbGwgZW50aXRpZXMgYXJlIGV4cG9ydGVkIGlmIHRoaXMgcGFyYW1ldGVyIGlzIG9taXR0ZWQgb3IgbnVsbC5cclxuICBAcGFyYW0gZXhwb3J0Q29uZmlnIC0gRXhwb3J0IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvciBhIGJvb2xlYW5cclxuICAgIC0gYXNTdHJpbmcgLSAoYm9vbGVhbikgLSBJZiB0cnVlIChkZWZhdWx0KSwgcmV0dXJuIGV4cG9ydCBidW5kbGUgYXMgYSBzdHJpbmcuXHJcbiAgICAtIGluY2x1ZGVNZXRhZGF0YSAtIChib29sZWFuKSAtIElmIHRydWUgKGRlZmF1bHQpLCBpbmNsdWRlIG1ldGFkYXRhIGluIHRoZSBleHBvcnQgYnVuZGxlLlxyXG4gIEByZXR1cm4gVGhlIGV4cG9ydCBidW5kbGUgZWl0aGVyIHNlcmlhbGl6ZWQgYXMgYSBzdHJpbmcgKGRlZmF1bHQpIG9yIGFzIGEgSlNPTiBvYmplY3QuXHJcbiAgVGhlIGJ1bmRsZSBjb250YWlucyB0aGUgbWV0YWRhdGEgKHVubGVzcyBleGNsdWRlZCkgYW5kIHRoZSBlbnRpdHkgZGF0YSBncm91cGVkIGJ5IHR5cGUuXHJcbiAgVGhlIGVudGl0eSBkYXRhIGluY2x1ZGUgcHJvcGVydHkgdmFsdWVzLCBjaGFuZ2Utc3RhdGUsIGFuZCB0ZW1wb3Jhcnkga2V5IG1hcHBpbmdzIChpZiBhbnkpLlxyXG5cclxuICBUaGUgZXhwb3J0IGJ1bmRsZSBpbnRlcm5hbHMgYXJlIGRlbGliZXJhdGVseSB1bmRvY3VtZW50ZWQuICBUaGlzIEJyZWV6ZS1pbnRlcm5hbCByZXByZXNlbnRhdGlvbiBvZiBlbnRpdHkgZGF0YSBpc1xyXG4gIHN1aXRhYmxlIGZvciBleHBvcnQsIHN0b3JhZ2UsIGFuZCBpbXBvcnQuIFRoZSBzY2hlbWEgYW5kIGNvbnRlbnRzIG9mIHRoZSBidW5kbGUgbWF5IGNoYW5nZSBpbiBmdXR1cmUgdmVyc2lvbnMgb2YgQnJlZXplLlxyXG4gIE1hbmlwdWxhdGUgaXQgYXQgeW91ciBvd24gcmlzayB3aXRoIGFwcHJvcHJpYXRlIGNhdXRpb24uXHJcbiAgKiovXHJcbiAgZXhwb3J0RW50aXRpZXMoZW50aXRpZXM/OiBFbnRpdHlbXSB8IEVudGl0eVR5cGVbXSB8IHN0cmluZ1tdLCBleHBvcnRDb25maWc/OiB7IGFzU3RyaW5nPzogYm9vbGVhbiwgaW5jbHVkZU1ldGFkYXRhPzogYm9vbGVhbiB9IHwgYm9vbGVhbik6IHN0cmluZyB8IE9iamVjdCB7XHJcbiAgICBhc3NlcnRQYXJhbShlbnRpdGllcywgXCJlbnRpdGllc1wiKS5pc0FycmF5KCkuaXNFbnRpdHkoKVxyXG4gICAgICAub3IoKS5pc05vbkVtcHR5QXJyYXkoKS5pc0luc3RhbmNlT2YoRW50aXR5VHlwZSlcclxuICAgICAgLm9yKCkuaXNOb25FbXB0eUFycmF5KCkuaXNTdHJpbmcoKVxyXG4gICAgICAub3IoKS5pc09wdGlvbmFsKCkuY2hlY2soKTtcclxuXHJcbiAgICAvLyBhc3NlcnRQYXJhbShleHBvcnRDb25maWcsIFwiZXhwb3J0Q29uZmlnXCIpLmlzT2JqZWN0KClcclxuICAgIC8vICAgLm9yKCkuaXNCb29sZWFuKClcclxuICAgIC8vICAgLm9yKCkuaXNPcHRpb25hbCgpLmNoZWNrKCk7XHJcblxyXG4gICAgaWYgKGV4cG9ydENvbmZpZyA9PSBudWxsKSB7XHJcbiAgICAgIGV4cG9ydENvbmZpZyA9IHsgaW5jbHVkZU1ldGFkYXRhOiB0cnVlLCBhc1N0cmluZzogdHJ1ZSB9O1xyXG4gICAgfSBlbHNlIGlmICh0eXBlb2YgZXhwb3J0Q29uZmlnID09PSAnYm9vbGVhbicpIHsgLy8gZGVwcmVjYXRlZFxyXG4gICAgICBleHBvcnRDb25maWcgPSB7IGluY2x1ZGVNZXRhZGF0YTogZXhwb3J0Q29uZmlnLCBhc1N0cmluZzogdHJ1ZSB9O1xyXG4gICAgfVxyXG5cclxuICAgIGFzc2VydENvbmZpZyhleHBvcnRDb25maWcpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwiYXNTdHJpbmdcIikuaXNCb29sZWFuKCkuaXNPcHRpb25hbCgpLndpdGhEZWZhdWx0KHRydWUpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwiaW5jbHVkZU1ldGFkYXRhXCIpLmlzQm9vbGVhbigpLmlzT3B0aW9uYWwoKS53aXRoRGVmYXVsdCh0cnVlKVxyXG4gICAgICAuYXBwbHlBbGwoZXhwb3J0Q29uZmlnKTtcclxuXHJcbiAgICBsZXQgZXhwb3J0QnVuZGxlID0gZXhwb3J0RW50aXR5R3JvdXBzKHRoaXMsIGVudGl0aWVzKTtcclxuICAgIGxldCBqc29uID0gY29yZS5leHRlbmQoe30sIGV4cG9ydEJ1bmRsZSwgW1widGVtcEtleXNcIiwgXCJlbnRpdHlHcm91cE1hcFwiXSk7XHJcblxyXG4gICAgaWYgKGV4cG9ydENvbmZpZy5pbmNsdWRlTWV0YWRhdGEpIHtcclxuICAgICAganNvbiA9IGNvcmUuZXh0ZW5kKGpzb24sIHRoaXMsIFtcImRhdGFTZXJ2aWNlXCIsIFwic2F2ZU9wdGlvbnNcIiwgXCJxdWVyeU9wdGlvbnNcIiwgXCJ2YWxpZGF0aW9uT3B0aW9uc1wiXSk7XHJcbiAgICAgIChqc29uIGFzIGFueSkubWV0YWRhdGFTdG9yZSA9IHRoaXMubWV0YWRhdGFTdG9yZS5leHBvcnRNZXRhZGF0YSgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgKGpzb24gYXMgYW55KS5tZXRhZGF0YVZlcnNpb24gPSBNZXRhZGF0YVN0b3JlLm1ldGFkYXRhVmVyc2lvbjtcclxuICAgICAgKGpzb24gYXMgYW55KS5tZXRhZGF0YVN0b3JlTmFtZSA9IHRoaXMubWV0YWRhdGFTdG9yZS5uYW1lO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCByZXN1bHQgPSBleHBvcnRDb25maWcuYXNTdHJpbmcgPyBKU09OLnN0cmluZ2lmeShqc29uLCBudWxsLCBjb25maWcuc3RyaW5naWZ5UGFkKSA6IGpzb247XHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG4gIH1cclxuXHJcbiAgLy8gVE9ETzogdHlwZSB0aGUgcmV0dXJuIHZhbHVlIHsgZW50aXRpZXM6IGVudGl0aWVzVG9MaW5rLCB0ZW1wS2V5TWFwcGluZzogdGVtcEtleU1hcCB9XHJcbiAgaW1wb3J0RW50aXRpZXMoZXhwb3J0ZWRTdHJpbmc6IHN0cmluZywgY29uZmlnPzogSW1wb3J0Q29uZmlnKTogSW1wb3J0UmVzdWx0O1xyXG4gIGltcG9ydEVudGl0aWVzKGV4cG9ydGVkRGF0YTogT2JqZWN0LCBjb25maWc/OiBJbXBvcnRDb25maWcpOiBJbXBvcnRSZXN1bHQ7XHJcbiAgLyoqXHJcbiAgSW1wb3J0cyBhIHByZXZpb3VzbHkgZXhwb3J0ZWQgcmVzdWx0IGludG8gdGhpcyBFbnRpdHlNYW5hZ2VyLlxyXG5cclxuICBUaGlzIG1ldGhvZCBjYW4gYmUgdXNlZCB0byBtYWtlIGEgY29tcGxldGUgY29weSBvZiBhbnkgcHJldmlvdXNseSBjcmVhdGVkIGVudGl0eU1hbmFnZXIsIGV2ZW4gaWYgY3JlYXRlZFxyXG4gIGluIGEgcHJldmlvdXMgc2Vzc2lvbiBhbmQgc3RvcmVkIGluIGxvY2FsU3RvcmFnZS4gVGhlIHN0YXRpYyB2ZXJzaW9uIG9mIHRoaXMgbWV0aG9kIHBlcmZvcm1zIGFcclxuICB2ZXJ5IHNpbWlsYXIgcHJvY2Vzcy5cclxuICA+ICAgICAvLyBhc3N1bWUgZW0xIGlzIGFuIEVudGl0eU1hbmFnZXIgY29udGFpbmluZyBhIG51bWJlciBvZiBleGlzdGluZyBlbnRpdGllcy5cclxuICA+ICAgICBsZXQgYnVuZGxlID0gZW0xLmV4cG9ydEVudGl0aWVzKCk7XHJcbiAgPiAgICAgLy8gYnVuZGxlIGNhbiBiZSBzdG9yZWQgaW4gd2luZG93LmxvY2FsU3RvcmFnZSBvciBqdXN0IGhlbGQgaW4gbWVtb3J5LlxyXG4gID4gICAgIGxldCBlbTIgPSBuZXcgRW50aXR5TWFuYWdlcih7XHJcbiAgPiAgICAgICAgIHNlcnZpY2VOYW1lOiBlbTEuc2VydmljZU5hbWUsXHJcbiAgPiAgICAgICAgIG1ldGFkYXRhU3RvcmU6IGVtMS5tZXRhZGF0YVN0b3JlXHJcbiAgPiAgICAgfSk7XHJcbiAgPiAgICAgZW0yLmltcG9ydEVudGl0aWVzKGJ1bmRsZSk7XHJcbiAgPiAgICAgLy8gZW0yIHdpbGwgbm93IGhhdmUgYSBjb21wbGV0ZSBjb3B5IG9mIHdoYXQgd2FzIGluIGVtMVxyXG5cclxuICBJdCBjYW4gYWxzbyBiZSB1c2VkIHRvIG1lcmdlIHRoZSBjb250ZW50cyBvZiBhIHByZXZpb3VzbHkgY3JlYXRlZCBFbnRpdHlNYW5hZ2VyIHdpdGggYW5cclxuICBleGlzdGluZyBFbnRpdHlNYW5hZ2VyIHdpdGggY29udHJvbCBvdmVyIGhvdyB0aGUgdHdvIGFyZSBtZXJnZWQuXHJcbiAgPiAgICAgbGV0IGJ1bmRsZSA9IGVtMS5leHBvcnRFbnRpdGllcygpO1xyXG4gID4gICAgIC8vIGFzc3VtZSBlbTIgaXMgYW5vdGhlciBlbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgc29tZSBvZiB0aGUgc2FtZSBlbnRpdGllcyBwb3NzaWJseSB3aXRoIG1vZGlmaWNhdGlvbnMuXHJcbiAgPiAgICAgZW0yLmltcG9ydEVudGl0aWVzKGJ1bmRsZSwgeyBtZXJnZVN0cmF0ZWd5OiBNZXJnZVN0cmF0ZWd5LlByZXNlcnZlQ2hhbmdlc30gKTtcclxuICA+ICAgICAvLyBlbTIgd2lsbCBub3cgY29udGFpbiBhbGwgb2YgdGhlIGVudGl0aWVzIGZyb20gYm90aCBlbTEgYW5kIGVtMi4gIEFueSBlbTIgZW50aXRpZXMgd2l0aCBwcmV2aW91c2x5XHJcbiAgPiAgICAgLy8gbWFkZSBtb2RpZmljYXRpb25zIHdpbGwgbm90IGhhdmUgYmVlbiB0b3VjaGVkLCBidXQgYWxsIG90aGVyIGVudGl0aWVzIGZyb20gZW0xIHdpbGwgaGF2ZSBiZWVuIGltcG9ydGVkLlxyXG4gIEBwYXJhbSBleHBvcnRlZFN0cmluZyAtIFRoZSByZXN1bHQgb2YgYSBwcmV2aW91cyAnZXhwb3J0JyBjYWxsLlxyXG4gIEBwYXJhbSBpbXBvcnRDb25maWcgLSBBIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gIEBwYXJhbSBpbXBvcnRDb25maWcubWVyZ2VTdHJhdGVneSAtICBBIFtbTWVyZ2VTdHJhdGVneV1dIHRvIHVzZSB3aGVuXHJcbiAgbWVyZ2luZyBpbnRvIGFuIGV4aXN0aW5nIEVudGl0eU1hbmFnZXIuXHJcbiAgQHBhcmFtIGltcG9ydENvbmZpZy5tZXRhZGF0YVZlcnNpb25GbiAtIEEgZnVuY3Rpb24gdGhhdCB0YWtlcyB0d28gYXJndW1lbnRzICh0aGUgY3VycmVudCBtZXRhZGF0YVZlcnNpb24gYW5kIHRoZSBpbXBvcnRlZCBzdG9yZSdzICduYW1lJylcclxuICBhbmQgbWF5IGJlIHVzZWQgdG8gcGVyZm9ybSB2ZXJzaW9uIGNoZWNraW5nLlxyXG4gIEByZXR1cm4gcmVzdWx0IFxyXG4gICAgLSByZXN1bHQuZW50aXRpZXMge0FycmF5IG9mIEVudGl0aWVzfSBUaGUgZW50aXRpZXMgdGhhdCB3ZXJlIGltcG9ydGVkLlxyXG4gICAgLSByZXN1bHQudGVtcEtleU1hcCB7T2JqZWN0fSBNYXBwaW5nIGZyb20gb3JpZ2luYWwgRW50aXR5S2V5IGluIHRoZSBpbXBvcnQgYnVuZGxlIHRvIGl0cyBjb3JyZXNwb25kaW5nIEVudGl0eUtleSBpbiB0aGlzIEVudGl0eU1hbmFnZXIuXHJcbiAgKiovXHJcbiAgaW1wb3J0RW50aXRpZXMoZXhwb3J0ZWQ6IHN0cmluZyB8IE9iamVjdCwgaW1wb3J0Q29uZmlnPzogSW1wb3J0Q29uZmlnKSB7XHJcbiAgICBpbXBvcnRDb25maWcgPSBpbXBvcnRDb25maWcgfHwge307XHJcbiAgICBhc3NlcnRDb25maWcoaW1wb3J0Q29uZmlnKVxyXG4gICAgICAud2hlcmVQYXJhbShcIm1lcmdlU3RyYXRlZ3lcIikuaXNFbnVtT2YoTWVyZ2VTdHJhdGVneSkuaXNPcHRpb25hbCgpLndpdGhEZWZhdWx0KHRoaXMucXVlcnlPcHRpb25zLm1lcmdlU3RyYXRlZ3kpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwibWV0YWRhdGFWZXJzaW9uRm5cIikuaXNGdW5jdGlvbigpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAud2hlcmVQYXJhbShcIm1lcmdlQWRkc1wiKS5pc0Jvb2xlYW4oKS5pc09wdGlvbmFsKClcclxuICAgICAgLmFwcGx5QWxsKGltcG9ydENvbmZpZyk7XHJcblxyXG4gICAgbGV0IGpzb24gPSAodHlwZW9mIGV4cG9ydGVkID09PSBcInN0cmluZ1wiKSA/IEpTT04ucGFyc2UoZXhwb3J0ZWQpIDogZXhwb3J0ZWQ7XHJcbiAgICBpZiAoanNvbi5tZXRhZGF0YVN0b3JlKSB7XHJcbiAgICAgIHRoaXMubWV0YWRhdGFTdG9yZS5pbXBvcnRNZXRhZGF0YShqc29uLm1ldGFkYXRhU3RvcmUpO1xyXG4gICAgICAvLyB0aGUgfHwgY2xhdXNlIGlzIGZvciBiYWNrd2FyZHMgY29tcGF0IHdpdGggYW4gZWFybGllciBzZXJpYWxpemF0aW9uIGZvcm1hdC5cclxuICAgICAgdGhpcy5kYXRhU2VydmljZSA9IChqc29uLmRhdGFTZXJ2aWNlICYmIERhdGFTZXJ2aWNlLmZyb21KU09OKGpzb24uZGF0YVNlcnZpY2UpKSB8fCBuZXcgRGF0YVNlcnZpY2UoeyBzZXJ2aWNlTmFtZToganNvbi5zZXJ2aWNlTmFtZSB9KTtcclxuXHJcbiAgICAgIHRoaXMuc2F2ZU9wdGlvbnMgPSBuZXcgU2F2ZU9wdGlvbnMoanNvbi5zYXZlT3B0aW9ucyk7XHJcbiAgICAgIHRoaXMucXVlcnlPcHRpb25zID0gUXVlcnlPcHRpb25zLmZyb21KU09OKGpzb24ucXVlcnlPcHRpb25zKTtcclxuICAgICAgdGhpcy52YWxpZGF0aW9uT3B0aW9ucyA9IG5ldyBWYWxpZGF0aW9uT3B0aW9ucyhqc29uLnZhbGlkYXRpb25PcHRpb25zKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGltcG9ydENvbmZpZy5tZXRhZGF0YVZlcnNpb25GbiAmJiBpbXBvcnRDb25maWcubWV0YWRhdGFWZXJzaW9uRm4oe1xyXG4gICAgICAgIG1ldGFkYXRhVmVyc2lvbjoganNvbi5tZXRhZGF0YVZlcnNpb24sXHJcbiAgICAgICAgbWV0YWRhdGFTdG9yZU5hbWU6IGpzb24ubWV0YWRhdGFTdG9yZU5hbWVcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IHRlbXBLZXlNYXA6IElUZW1wS2V5TWFwID0ge307XHJcbiAgICBqc29uLnRlbXBLZXlzLmZvckVhY2goKGs6IGFueSkgPT4ge1xyXG4gICAgICBsZXQgb2xkS2V5ID0gRW50aXR5S2V5LmZyb21KU09OKGssIHRoaXMubWV0YWRhdGFTdG9yZSk7XHJcbiAgICAgIC8vIHRyeSB0byB1c2Ugb2xkS2V5IGlmIG5vdCBhbHJlYWR5IHVzZWQgaW4gdGhpcyBrZXlHZW5lcmF0b3IuXHJcbiAgICAgIHRlbXBLZXlNYXBbb2xkS2V5LnRvU3RyaW5nKCldID0gbmV3IEVudGl0eUtleShvbGRLZXkuZW50aXR5VHlwZSwgdGhpcy5rZXlHZW5lcmF0b3IuZ2VuZXJhdGVUZW1wS2V5VmFsdWUob2xkS2V5LmVudGl0eVR5cGUsIG9sZEtleS52YWx1ZXNbMF0pKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCBlbnRpdGllc1RvTGluazogRW50aXR5W10gPSBbXTtcclxuICAgIGxldCBpbXBDb25maWcgPSBpbXBvcnRDb25maWcgYXMgSW1wb3J0Q29uZmlnRXh0O1xyXG5cclxuICAgIGltcENvbmZpZy50ZW1wS2V5TWFwID0gdGVtcEtleU1hcDtcclxuICAgIGNvcmUud3JhcEV4ZWN1dGlvbigoKSA9PiB7XHJcbiAgICAgIHRoaXMuX3BlbmRpbmdQdWJzID0gW107XHJcbiAgICB9LCAoc3RhdGUpID0+IHtcclxuICAgICAgdGhpcy5fcGVuZGluZ1B1YnMhLmZvckVhY2goKGZuKSA9PiBmbigpKTtcclxuICAgICAgdGhpcy5fcGVuZGluZ1B1YnMgPSB1bmRlZmluZWQ7XHJcbiAgICAgIHRoaXMuX2hhc0NoYW5nZXNBY3Rpb24gJiYgdGhpcy5faGFzQ2hhbmdlc0FjdGlvbigpO1xyXG4gICAgfSwgKCkgPT4ge1xyXG4gICAgICBjb3JlLm9iamVjdEZvckVhY2goanNvbi5lbnRpdHlHcm91cE1hcCwgKGVudGl0eVR5cGVOYW1lLCBqc29uR3JvdXApID0+IHtcclxuICAgICAgICBsZXQgZW50aXR5VHlwZSA9IHRoaXMubWV0YWRhdGFTdG9yZS5fZ2V0U3RydWN0dXJhbFR5cGUoZW50aXR5VHlwZU5hbWUsIGZhbHNlKSBhcyBFbnRpdHlUeXBlO1xyXG4gICAgICAgIGxldCB0YXJnZXRFbnRpdHlHcm91cCA9IGZpbmRPckNyZWF0ZUVudGl0eUdyb3VwKHRoaXMsIGVudGl0eVR5cGUpO1xyXG4gICAgICAgIGxldCBlbnRpdGllcyA9IGltcG9ydEVudGl0eUdyb3VwKHRhcmdldEVudGl0eUdyb3VwLCBqc29uR3JvdXAsIGltcENvbmZpZyk7XHJcbiAgICAgICAgaWYgKGVudGl0aWVzICYmIGVudGl0aWVzLmxlbmd0aCkge1xyXG4gICAgICAgICAgZW50aXRpZXNUb0xpbmsgPSBlbnRpdGllc1RvTGluay5jb25jYXQoZW50aXRpZXMpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICAgIGVudGl0aWVzVG9MaW5rLmZvckVhY2goKGVudGl0eSkgPT4ge1xyXG4gICAgICAgIGlmICghZW50aXR5LmVudGl0eUFzcGVjdC5lbnRpdHlTdGF0ZS5pc0RlbGV0ZWQoKSkge1xyXG4gICAgICAgICAgdGhpcy5fbGlua1JlbGF0ZWRFbnRpdGllcyhlbnRpdHkpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9KTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIGVudGl0aWVzOiBlbnRpdGllc1RvTGluayxcclxuICAgICAgdGVtcEtleU1hcHBpbmc6IHRlbXBLZXlNYXBcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBDbGVhcnMgdGhpcyBFbnRpdHlNYW5hZ2VyJ3MgY2FjaGUgYnV0IGtlZXBzIGFsbCBvdGhlciBzZXR0aW5ncy4gTm90ZSB0aGF0IHRoaXNcclxuICBtZXRob2QgaXMgbm90IGFzIGZhc3QgYXMgY3JlYXRpbmcgYSBuZXcgRW50aXR5TWFuYWdlciB2aWEgJ25ldyBFbnRpdHlNYW5hZ2VyJy5cclxuICBUaGlzIGlzIGJlY2F1c2UgY2xlYXIgYWN0dWFsbHkgZGV0YWNoZXMgYWxsIG9mIHRoZSBlbnRpdGllcyBmcm9tIHRoZSBFbnRpdHlNYW5hZ2VyLlxyXG4gID4gICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIGV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgIGVtMS5jbGVhcigpO1xyXG4gID4gICAgIC8vIGVtMSBpcyB3aWxsIG5vdyBjb250YWluIG5vIGVudGl0aWVzLCBidXQgYWxsIG90aGVyIHNldHRpbmcgd2lsbCBiZSBtYWludGFpbmVkLlxyXG4gICoqL1xyXG4gIGNsZWFyKCkge1xyXG4gICAgY29yZS5vYmplY3RNYXAodGhpcy5fZW50aXR5R3JvdXBNYXAsIGZ1bmN0aW9uIChrZXk6IHN0cmluZywgZW50aXR5R3JvdXA6IEVudGl0eUdyb3VwKSB7XHJcbiAgICAgIHJldHVybiBlbnRpdHlHcm91cC5fY2hlY2tPcGVyYXRpb24oJ2NsZWFyJyk7XHJcbiAgICB9KS5mb3JFYWNoKChlbnRpdHlHcm91cDogRW50aXR5R3JvdXApID0+IHtcclxuICAgICAgZW50aXR5R3JvdXAuX2NsZWFyKCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICB0aGlzLl9lbnRpdHlHcm91cE1hcCA9IHt9O1xyXG4gICAgdGhpcy5fdW5hdHRhY2hlZENoaWxkcmVuTWFwID0gbmV3IFVuYXR0YWNoZWRDaGlsZHJlbk1hcCgpO1xyXG4gICAgdGhpcy5rZXlHZW5lcmF0b3IgPSBuZXcgdGhpcy5rZXlHZW5lcmF0b3JDdG9yKCk7XHJcbiAgICB0aGlzLmVudGl0eUNoYW5nZWQucHVibGlzaCh7IGVudGl0eUFjdGlvbjogRW50aXR5QWN0aW9uLkNsZWFyIH0pO1xyXG4gICAgdGhpcy5fc2V0SGFzQ2hhbmdlcyhmYWxzZSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBDcmVhdGVzIGFuIGVtcHR5IGNvcHkgb2YgdGhpcyBFbnRpdHlNYW5hZ2VyIGJ1dCB3aXRoIHRoZSBzYW1lIERhdGFTZXJ2aWNlLCBNZXRhZGF0YVN0b3JlLCBRdWVyeU9wdGlvbnMsIFNhdmVPcHRpb25zLCBWYWxpZGF0aW9uT3B0aW9ucywgZXRjLiBcclxuICA+ICAgICAvLyBhc3N1bWUgZW0xIGlzIGFuIEVudGl0eU1hbmFnZXIgY29udGFpbmluZyBhIG51bWJlciBvZiBleGlzdGluZyBlbnRpdGllcy5cclxuICA+ICAgICBsZXQgZW0yID0gZW0xLmNyZWF0ZUVtcHR5Q29weSgpO1xyXG4gID4gICAgIC8vIGVtMiBpcyBhIG5ldyBFbnRpdHlNYW5hZ2VyIHdpdGggYWxsIG9mIGVtMSdzIHNldHRpbmdzXHJcbiAgPiAgICAgLy8gYnV0IG5vIGVudGl0aWVzLlxyXG4gIEByZXR1cm4gQSBuZXcgRW50aXR5TWFuYWdlci5cclxuICAqKi9cclxuICBjcmVhdGVFbXB0eUNvcHkoKSB7XHJcbiAgICBsZXQgY29weSA9IG5ldyBFbnRpdHlNYW5hZ2VyKGNvcmUuZXh0ZW5kKHt9LCB0aGlzLFxyXG4gICAgICBbXCJkYXRhU2VydmljZVwiLCBcIm1ldGFkYXRhU3RvcmVcIiwgXCJxdWVyeU9wdGlvbnNcIiwgXCJzYXZlT3B0aW9uc1wiLCBcInZhbGlkYXRpb25PcHRpb25zXCIsIFwia2V5R2VuZXJhdG9yQ3RvclwiXSkpO1xyXG4gICAgcmV0dXJuIGNvcHk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBBdHRhY2hlcyBhbiBlbnRpdHkgdG8gdGhpcyBFbnRpdHlNYW5hZ2VyIHdpdGggYW4gIFtbRW50aXR5U3RhdGVdXSBvZiAnQWRkZWQnLlxyXG4gID4gICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIGV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgIGxldCBjdXN0VHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJDdXN0b21lclwiKTtcclxuICA+ICAgICBsZXQgY3VzdDEgPSBjdXN0VHlwZS5jcmVhdGVFbnRpdHkoKTtcclxuICA+ICAgICBlbTEuYWRkRW50aXR5KGN1c3QxKTtcclxuXHJcbiAgTm90ZSB0aGF0IHRoaXMgaXMgdGhlIHNhbWUgYXMgdXNpbmcgJ2F0dGFjaEVudGl0eScgd2l0aCBhbiBbW0VudGl0eVN0YXRlXV0gb2YgJ0FkZGVkJy5cclxuXHJcbiAgPiAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgbGV0IGN1c3RUeXBlID0gZW0xLm1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZShcIkN1c3RvbWVyXCIpO1xyXG4gID4gICAgIGxldCBjdXN0MSA9IGN1c3RUeXBlLmNyZWF0ZUVudGl0eSgpO1xyXG4gID4gICAgIGVtMS5hdHRhY2hFbnRpdHkoY3VzdDEsIEVudGl0eVN0YXRlLkFkZGVkKTtcclxuICBAcGFyYW0gZW50aXR5IC0gVGhlIGVudGl0eSB0byBhZGQuXHJcbiAgQHJldHVybiBUaGUgYWRkZWQgZW50aXR5LlxyXG4gICoqL1xyXG4gIGFkZEVudGl0eShlbnRpdHk6IEVudGl0eSkge1xyXG4gICAgcmV0dXJuIHRoaXMuYXR0YWNoRW50aXR5KGVudGl0eSwgRW50aXR5U3RhdGUuQWRkZWQpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgQXR0YWNoZXMgYW4gZW50aXR5IHRvIHRoaXMgRW50aXR5TWFuYWdlciB3aXRoIGEgc3BlY2lmaWVkIFtbRW50aXR5U3RhdGVdXS5cclxuICA+ICAgICAvLyBhc3N1bWUgZW0xIGlzIGFuIEVudGl0eU1hbmFnZXIgY29udGFpbmluZyBhIG51bWJlciBvZiBleGlzdGluZyBlbnRpdGllcy5cclxuICA+ICAgICBsZXQgY3VzdFR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQ3VzdG9tZXJcIik7XHJcbiAgPiAgICAgbGV0IGN1c3QxID0gY3VzdFR5cGUuY3JlYXRlRW50aXR5KCk7XHJcbiAgPiAgICAgZW0xLmF0dGFjaEVudGl0eShjdXN0MSwgRW50aXR5U3RhdGUuQWRkZWQpO1xyXG4gIEBwYXJhbSBlbnRpdHkgLSBUaGUgZW50aXR5IHRvIGFkZC5cclxuICBAcGFyYW0gZW50aXR5U3RhdGUgLSAoZGVmYXVsdD1FbnRpdHlTdGF0ZS5VbmNoYW5nZWQpIFRoZSBFbnRpdHlTdGF0ZSBvZiB0aGUgbmV3bHkgYXR0YWNoZWQgZW50aXR5LiBJZiBvbWl0dGVkIHRoaXMgZGVmYXVsdHMgdG8gRW50aXR5U3RhdGUuVW5jaGFuZ2VkLlxyXG4gIEBwYXJhbSBtZXJnZVN0cmF0ZWd5IC0gKGRlZmF1bHQgPSBNZXJnZVN0cmF0ZWd5LkRpc2FsbG93ZWQpIEhvdyB0aGUgc3BlY2lmaWVkIGVudGl0eSBzaG91bGQgYmUgbWVyZ2VkIGludG8gdGhlIEVudGl0eU1hbmFnZXIgaWYgdGhpcyBFbnRpdHlNYW5hZ2VyIGFscmVhZHkgY29udGFpbnMgYW4gZW50aXR5IHdpdGggdGhlIHNhbWUga2V5LlxyXG4gIEByZXR1cm4gVGhlIGF0dGFjaGVkIGVudGl0eS5cclxuICAqKi9cclxuICBhdHRhY2hFbnRpdHkoZW50aXR5OiBFbnRpdHksIGVudGl0eVN0YXRlPzogRW50aXR5U3RhdGUsIG1lcmdlU3RyYXRlZ3k/OiBNZXJnZVN0cmF0ZWd5KSB7XHJcbiAgICBhc3NlcnRQYXJhbShlbnRpdHksIFwiZW50aXR5XCIpLmlzUmVxdWlyZWQoKS5jaGVjaygpO1xyXG4gICAgdGhpcy5tZXRhZGF0YVN0b3JlLl9jaGVja0VudGl0eVR5cGUoZW50aXR5KTtcclxuICAgIGxldCBlc1N5bWJvbCA9IGFzc2VydFBhcmFtKGVudGl0eVN0YXRlLCBcImVudGl0eVN0YXRlXCIpLmlzRW51bU9mKEVudGl0eVN0YXRlKS5pc09wdGlvbmFsKCkuY2hlY2soRW50aXR5U3RhdGUuVW5jaGFuZ2VkKSBhcyBFbnRpdHlTdGF0ZTtcclxuICAgIGxldCBtc1N5bWJvbCA9IGFzc2VydFBhcmFtKG1lcmdlU3RyYXRlZ3ksIFwibWVyZ2VTdHJhdGVneVwiKS5pc0VudW1PZihNZXJnZVN0cmF0ZWd5KS5pc09wdGlvbmFsKCkuY2hlY2soTWVyZ2VTdHJhdGVneS5EaXNhbGxvd2VkKSBhcyBNZXJnZVN0cmF0ZWd5O1xyXG5cclxuICAgIGlmIChlbnRpdHkuZW50aXR5VHlwZS5tZXRhZGF0YVN0b3JlICE9PSB0aGlzLm1ldGFkYXRhU3RvcmUpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2Fubm90IGF0dGFjaCB0aGlzIGVudGl0eSBiZWNhdXNlIHRoZSBFbnRpdHlUeXBlIChcIiArIGVudGl0eS5lbnRpdHlUeXBlLm5hbWUgK1xyXG4gICAgICAgIFwiKSBhbmQgTWV0YWRhdGFTdG9yZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBlbnRpdHkgZG9lcyBub3QgbWF0Y2ggdGhpcyBFbnRpdHlNYW5hZ2VyJ3MgTWV0YWRhdGFTdG9yZS5cIik7XHJcbiAgICB9XHJcbiAgICBsZXQgYXNwZWN0ID0gZW50aXR5LmVudGl0eUFzcGVjdDtcclxuICAgIGlmIChhc3BlY3QpIHtcclxuICAgICAgLy8gdG8gYXZvaWQgcmVhdHRhY2hpbmcgYW4gZW50aXR5IGluIHByb2dyZXNzXHJcbiAgICAgIGlmIChhc3BlY3QuX2luUHJvY2Vzc0VudGl0eSkgcmV0dXJuIGFzcGVjdC5faW5Qcm9jZXNzRW50aXR5O1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gdGhpcyBvY2N1cidzIHdoZW4gYXR0YWNoaW5nIGFuIGVudGl0eSBjcmVhdGVkIHZpYSBuZXcgaW5zdGVhZCBvZiB2aWEgY3JlYXRlRW50aXR5LlxyXG4gICAgICBhc3BlY3QgPSBuZXcgRW50aXR5QXNwZWN0KGVudGl0eSk7XHJcbiAgICB9XHJcbiAgICBsZXQgbWFuYWdlciA9IGFzcGVjdC5lbnRpdHlNYW5hZ2VyO1xyXG4gICAgaWYgKG1hbmFnZXIpIHtcclxuICAgICAgaWYgKG1hbmFnZXIgPT09IHRoaXMpIHtcclxuICAgICAgICByZXR1cm4gZW50aXR5O1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlRoaXMgZW50aXR5IGFscmVhZHkgYmVsb25ncyB0byBhbm90aGVyIEVudGl0eU1hbmFnZXJcIik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBsZXQgYXR0YWNoZWRFbnRpdHkgPSB7fSBhcyBFbnRpdHk7XHJcbiAgICBjb3JlLnVzaW5nKHRoaXMsIFwiaXNMb2FkaW5nXCIsIHRydWUsICgpID0+IHtcclxuICAgICAgaWYgKGVzU3ltYm9sLmlzQWRkZWQoKSkge1xyXG4gICAgICAgIGNoZWNrRW50aXR5S2V5KHRoaXMsIGVudGl0eSk7XHJcbiAgICAgIH1cclxuICAgICAgLy8gYXR0YWNoZWRFbnRpdHkgPT09IGVudGl0eSBFWENFUFQgaW4gdGhlIGNhc2Ugb2YgYSBtZXJnZS5cclxuICAgICAgYXR0YWNoZWRFbnRpdHkgPSB0aGlzLl9hdHRhY2hFbnRpdHlDb3JlKGVudGl0eSwgZXNTeW1ib2wsIG1zU3ltYm9sKTtcclxuICAgICAgYXNwZWN0Ll9pblByb2Nlc3NFbnRpdHkgPSBhdHRhY2hlZEVudGl0eTtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBlbnRpdHkgKCBub3QgYXR0YWNoZWRFbnRpdHkpIGlzIGRlbGliZXJhdGUgaGVyZS5cclxuICAgICAgICBhdHRhY2hSZWxhdGVkRW50aXRpZXModGhpcywgZW50aXR5LCBlc1N5bWJvbCwgbXNTeW1ib2wpO1xyXG4gICAgICB9IGZpbmFsbHkge1xyXG4gICAgICAgIC8vIGluc3VyZSB0aGF0IF9pblByb2Nlc3NFbnRpdHkgaXMgY2xlYXJlZC5cclxuICAgICAgICBhc3BlY3QuX2luUHJvY2Vzc0VudGl0eSA9IHVuZGVmaW5lZDtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgICBpZiAodGhpcy52YWxpZGF0aW9uT3B0aW9ucy52YWxpZGF0ZU9uQXR0YWNoKSB7XHJcbiAgICAgIGF0dGFjaGVkRW50aXR5LmVudGl0eUFzcGVjdC52YWxpZGF0ZUVudGl0eSgpO1xyXG4gICAgfVxyXG4gICAgaWYgKCFlc1N5bWJvbC5pc1VuY2hhbmdlZCgpKSB7XHJcbiAgICAgIHRoaXMuX25vdGlmeVN0YXRlQ2hhbmdlKGF0dGFjaGVkRW50aXR5LCB0cnVlKTtcclxuICAgIH1cclxuICAgIHRoaXMuZW50aXR5Q2hhbmdlZC5wdWJsaXNoKHsgZW50aXR5QWN0aW9uOiBFbnRpdHlBY3Rpb24uQXR0YWNoLCBlbnRpdHk6IGF0dGFjaGVkRW50aXR5IH0pO1xyXG5cclxuICAgIHJldHVybiBhdHRhY2hlZEVudGl0eTtcclxuICB9XHJcblxyXG5cclxuICAvKipcclxuICBEZXRhY2hlcyBhbiBlbnRpdHkgZnJvbSB0aGlzIEVudGl0eU1hbmFnZXIuXHJcbiAgPiAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgLy8gYXNzdW1lIGN1c3QxIGlzIGEgY3VzdG9tZXIgRW50aXR5IHByZXZpb3VzbHkgYXR0YWNoZWQgdG8gZW0xXHJcbiAgPiAgICAgZW0xLmRldGFjaEVudGl0eShjdXN0MSk7XHJcbiAgPiAgICAgLy8gZW0xIHdpbGwgbm93IG5vIGxvbmdlciBjb250YWluIGN1c3QxIGFuZCBjdXN0MSB3aWxsIGhhdmUgYW5cclxuICA+ICAgICAvLyBlbnRpdHlBc3BlY3QuZW50aXR5U3RhdGUgb2YgRW50aXR5U3RhdGUuRGV0YWNoZWRcclxuICBAcGFyYW0gZW50aXR5IC0gVGhlIGVudGl0eSB0byBkZXRhY2guXHJcbiAgQHJldHVybiBXaGV0aGVyIHRoZSBlbnRpdHkgY291bGQgYmUgZGV0YWNoZWQuIFRoaXMgd2lsbCByZXR1cm4gZmFsc2UgaWYgdGhlIGVudGl0eSBpcyBhbHJlYWR5IGRldGFjaGVkIG9yIHdhcyBuZXZlciBhdHRhY2hlZC5cclxuICAqKi9cclxuICBkZXRhY2hFbnRpdHkoZW50aXR5OiBFbnRpdHkpIHtcclxuICAgIGFzc2VydFBhcmFtKGVudGl0eSwgXCJlbnRpdHlcIikuaXNFbnRpdHkoKS5jaGVjaygpO1xyXG4gICAgbGV0IGFzcGVjdCA9IGVudGl0eS5lbnRpdHlBc3BlY3Q7XHJcbiAgICBpZiAoIWFzcGVjdCkge1xyXG4gICAgICAvLyBubyBhc3BlY3QgbWVhbnMgaW4gY291bGRuJ3QgYXBwZWFyIGluIGFueSBncm91cFxyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGFzcGVjdC5lbnRpdHlNYW5hZ2VyICE9PSB0aGlzKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIlRoaXMgZW50aXR5IGRvZXMgbm90IGJlbG9uZyB0byB0aGlzIEVudGl0eU1hbmFnZXIuXCIpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGFzcGVjdC5zZXREZXRhY2hlZCgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgRmV0Y2hlcyB0aGUgbWV0YWRhdGEgYXNzb2NpYXRlZCB3aXRoIHRoZSBFbnRpdHlNYW5hZ2VyJ3MgY3VycmVudCAnc2VydmljZU5hbWUnLiAgVGhpcyBjYWxsXHJcbiAgb2NjdXJzIGludGVybmFsbHkgYmVmb3JlIHRoZSBmaXJzdCBxdWVyeSB0byBhbnkgc2VydmljZSBpZiB0aGUgbWV0YWRhdGEgaGFzbid0IGFscmVhZHkgYmVlblxyXG4gIGxvYWRlZC4gX19Bc3luY19fXHJcblxyXG4gIFVzdWFsbHkgeW91IHdpbGwgbm90IGFjdHVhbGx5IHByb2Nlc3MgdGhlIHJlc3VsdHMgb2YgYSBmZXRjaE1ldGFkYXRhIGNhbGwgZGlyZWN0bHksIGJ1dCB3aWxsIGluc3RlYWRcclxuICBhc2sgZm9yIHRoZSBtZXRhZGF0YSBmcm9tIHRoZSBFbnRpdHlNYW5hZ2VyIGFmdGVyIHRoZSBmZXRjaE1ldGFkYXRhIGNhbGwgcmV0dXJucy5cclxuICA+ICAgICBsZXQgZW0xID0gbmV3IEVudGl0eU1hbmFnZXIoIFwiYnJlZXplL05vcnRod2luZElCTW9kZWxcIik7XHJcbiAgPiAgICAgZW0xLmZldGNoTWV0YWRhdGEoKVxyXG4gID4gICAgICAgLnRoZW4oZnVuY3Rpb24oKSB7XHJcbiAgPiAgICAgICAgICAgbGV0IG1ldGFkYXRhU3RvcmUgPSBlbTEubWV0YWRhdGFTdG9yZTtcclxuICA+ICAgICAgICAgICAvLyBkbyBzb21ldGhpbmcgd2l0aCB0aGUgbWV0YWRhdGFcclxuICA+ICAgICAgIH0pLmNhdGNoKGZ1bmN0aW9uKGV4Y2VwdGlvbikge1xyXG4gID4gICAgICAgICAgIC8vIGhhbmRsZSBleGNlcHRpb24gaGVyZVxyXG4gID4gICAgICAgfSk7XHJcbiAgXHJcbiAgQHBhcmFtIGNhbGxiYWNrIC0gRnVuY3Rpb24gY2FsbGVkIG9uIHN1Y2Nlc3MuXHJcbiAgQHBhcmFtIGVycm9yQ2FsbGJhY2sgLSBGdW5jdGlvbiBjYWxsZWQgb24gZmFpbHVyZS5cclxuICBAcmV0dXJuIHtQcm9taXNlfVxyXG4gICAgLSBzY2hlbWEge09iamVjdH0gVGhlIHJhdyBTY2hlbWEgb2JqZWN0IGZyb20gbWV0YWRhdGEgcHJvdmlkZXIgLSBCZWNhdXNlIHRoaXMgc2NoZW1hIHdpbGwgZGlmZmVyIGRlcGVuZGluZyBvbiB0aGUgbWV0YWRhdGEgcHJvdmlkZXJcclxuICAgICAgICBpdCBpcyB1c3VhbGx5IGJldHRlciB0byBhY2Nlc3MgbWV0YWRhdGEgdmlhIHRoZSAnbWV0YWRhdGFTdG9yZScgcHJvcGVydHkgb2YgdGhlIEVudGl0eU1hbmFnZXIgaW5zdGVhZCBvZiB1c2luZyB0aGlzICdyYXcnIGRhdGEuXHJcbiAgKiovXHJcbiAgZmV0Y2hNZXRhZGF0YShkYXRhU2VydmljZT86IERhdGFTZXJ2aWNlLCBjYWxsYmFjaz86IENhbGxiYWNrLCBlcnJvckNhbGxiYWNrPzogRXJyb3JDYWxsYmFjaykge1xyXG4gICAgaWYgKHR5cGVvZiAoZGF0YVNlcnZpY2UpID09PSBcImZ1bmN0aW9uXCIpIHtcclxuICAgICAgLy8gbGVnYWN5IHN1cHBvcnQgZm9yIHdoZW4gZGF0YVNlcnZpY2Ugd2FzIG5vdCBhbiBhcmcuIGkuZS4gZmlyc3QgYXJnIHdhcyBjYWxsYmFja1xyXG4gICAgICBlcnJvckNhbGxiYWNrID0gY2FsbGJhY2s7XHJcbiAgICAgIGNhbGxiYWNrID0gZGF0YVNlcnZpY2U7XHJcbiAgICAgIGRhdGFTZXJ2aWNlID0gdW5kZWZpbmVkO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgYXNzZXJ0UGFyYW0oZGF0YVNlcnZpY2UsIFwiZGF0YVNlcnZpY2VcIikuaXNJbnN0YW5jZU9mKERhdGFTZXJ2aWNlKS5pc09wdGlvbmFsKCkuY2hlY2soKTtcclxuICAgICAgYXNzZXJ0UGFyYW0oY2FsbGJhY2ssIFwiY2FsbGJhY2tcIikuaXNGdW5jdGlvbigpLmlzT3B0aW9uYWwoKS5jaGVjaygpO1xyXG4gICAgICBhc3NlcnRQYXJhbShlcnJvckNhbGxiYWNrLCBcImVycm9yQ2FsbGJhY2tcIikuaXNGdW5jdGlvbigpLmlzT3B0aW9uYWwoKS5jaGVjaygpO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBwcm9taXNlID0gdGhpcy5tZXRhZGF0YVN0b3JlLmZldGNoTWV0YWRhdGEoZGF0YVNlcnZpY2UgfHwgdGhpcy5kYXRhU2VydmljZSk7XHJcbiAgICByZXR1cm4gcHJvbWlzZVdpdGhDYWxsYmFja3MocHJvbWlzZSwgY2FsbGJhY2ssIGVycm9yQ2FsbGJhY2spO1xyXG4gIH1cclxuXHJcblxyXG4gIGV4ZWN1dGVRdWVyeShxdWVyeTogc3RyaW5nLCBjYWxsYmFjaz86IFF1ZXJ5U3VjY2Vzc0NhbGxiYWNrLCBlcnJvckNhbGxiYWNrPzogUXVlcnlFcnJvckNhbGxiYWNrKTogUHJvbWlzZTxRdWVyeVJlc3VsdD47XHJcbiAgZXhlY3V0ZVF1ZXJ5KHF1ZXJ5OiBFbnRpdHlRdWVyeSwgY2FsbGJhY2s/OiBRdWVyeVN1Y2Nlc3NDYWxsYmFjaywgZXJyb3JDYWxsYmFjaz86IFF1ZXJ5RXJyb3JDYWxsYmFjayk6IFByb21pc2U8UXVlcnlSZXN1bHQ+O1xyXG4gIC8qKlxyXG4gIEV4ZWN1dGVzIHRoZSBzcGVjaWZpZWQgcXVlcnkuIF9fQXN5bmNfXyBcclxuICBcclxuICA+ICAgICBsZXQgZW0gPSBuZXcgRW50aXR5TWFuYWdlcihzZXJ2aWNlTmFtZSk7XHJcbiAgPiAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiT3JkZXJzXCIpO1xyXG4gID4gICAgIGVtLmV4ZWN1dGVRdWVyeShxdWVyeSkudGhlbiggZnVuY3Rpb24oZGF0YSkge1xyXG4gID4gICAgICAgICBsZXQgb3JkZXJzID0gZGF0YS5yZXN1bHRzO1xyXG4gID4gICAgICAgICAuLi4gcXVlcnkgcmVzdWx0cyBwcm9jZXNzZWQgaGVyZVxyXG4gID4gICAgIH0pLmNhdGNoKCBmdW5jdGlvbihlcnIpIHtcclxuICA+ICAgICAgICAgLi4uIHF1ZXJ5IGZhaWx1cmUgcHJvY2Vzc2VkIGhlcmVcclxuICA+ICAgICB9KTtcclxuXHJcbiAgb3Igd2l0aCBjYWxsYmFja3NcclxuICA+ICAgICBsZXQgZW0gPSBuZXcgRW50aXR5TWFuYWdlcihzZXJ2aWNlTmFtZSk7XHJcbiAgPiAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiT3JkZXJzXCIpO1xyXG4gID4gICAgIGVtLmV4ZWN1dGVRdWVyeShxdWVyeSxcclxuICA+ICAgICAgICAgZnVuY3Rpb24oZGF0YSkge1xyXG4gID4gICAgICAgICAgICAgbGV0IG9yZGVycyA9IGRhdGEucmVzdWx0cztcclxuICA+ICAgICAgICAgICAgIC4uLiBxdWVyeSByZXN1bHRzIHByb2Nlc3NlZCBoZXJlXHJcbiAgPiAgICAgICAgIH0sXHJcbiAgPiAgICAgICAgIGZ1bmN0aW9uKGVycikge1xyXG4gID4gICAgICAgICAgICAgLi4uIHF1ZXJ5IGZhaWx1cmUgcHJvY2Vzc2VkIGhlcmVcclxuICA+ICAgICAgICAgfSk7XHJcblxyXG4gIEVpdGhlciB3YXkgdGhpcyBtZXRob2QgaXMgdGhlIHNhbWUgYXMgY2FsbGluZyB0aGUgVGhlIFtbRW50aXR5UXVlcnldXSAnZXhlY3V0ZScgbWV0aG9kLlxyXG4gID4gICAgIGxldCBlbSA9IG5ldyBFbnRpdHlNYW5hZ2VyKHNlcnZpY2VOYW1lKTtcclxuICA+ICAgICBsZXQgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkoXCJPcmRlcnNcIikudXNpbmcoZW0pO1xyXG4gID4gICAgIHF1ZXJ5LmV4ZWN1dGUoKS50aGVuKCBmdW5jdGlvbihkYXRhKSB7XHJcbiAgPiAgICAgICAgIGxldCBvcmRlcnMgPSBkYXRhLnJlc3VsdHM7XHJcbiAgPiAgICAgICAgIC4uLiBxdWVyeSByZXN1bHRzIHByb2Nlc3NlZCBoZXJlXHJcbiAgPiAgICAgfSkuY2F0Y2goIGZ1bmN0aW9uKGVycikge1xyXG4gID4gICAgICAgICAuLi4gcXVlcnkgZmFpbHVyZSBwcm9jZXNzZWQgaGVyZVxyXG4gID4gICAgIH0pO1xyXG4gIEBwYXJhbSBxdWVyeSAtIFRoZSBbW0VudGl0eVF1ZXJ5XV0gb3IgT0RhdGEgcXVlcnkgc3RyaW5nIHRvIGV4ZWN1dGUuXHJcbiAgQHBhcmFtIGNhbGxiYWNrIC0gRnVuY3Rpb24gY2FsbGVkIG9uIHN1Y2Nlc3MuXHJcbiAgQHBhcmFtIGVycm9yQ2FsbGJhY2sgLSB7RnVuY3Rpb259IEZ1bmN0aW9uIGNhbGxlZCBvbiBmYWlsdXJlLlxyXG4gIEByZXR1cm4gUHJvbWlzZSBvZiBcclxuICAgIC0gcmVzdWx0cyAtIEFuIGFycmF5IG9mIGVudGl0aWVzXHJcbiAgICAtIHJldHJpZXZlZEVudGl0aWVzIC0gQSBhcnJheSBvZiBhbGwgb2YgdGhlIGVudGl0aWVzIHJldHVybmVkIGJ5IHRoZSBxdWVyeS4gIERpZmZlcnMgZnJvbSByZXN1bHRzIChhYm92ZSkgd2hlbiAuZXhwYW5kKCkgaXMgdXNlZC5cclxuICAgIC0gcXVlcnkgLSBUaGUgb3JpZ2luYWwgW1tFbnRpdHlRdWVyeV1dIG9yIHF1ZXJ5IHN0cmluZ1xyXG4gICAgLSBlbnRpdHlNYW5hZ2VyIC0gIFRoZSBFbnRpdHlNYW5hZ2VyLlxyXG4gICAgLSBodHRwUmVzcG9uc2UgLSBUaGUgW1tJSHR0cFJlc3BvbnNlXV0gcmV0dXJuZWQgZnJvbSB0aGUgc2VydmVyLlxyXG4gICAgLSBpbmxpbmVDb3VudCAtICBPbmx5IGF2YWlsYWJsZSBpZiAnaW5saW5lQ291bnQodHJ1ZSknIHdhcyBhcHBsaWVkIHRvIHRoZSBxdWVyeS4gIFJldHVybnMgdGhlIGNvdW50IG9mXHJcbiAgICBpdGVtcyB0aGF0IHdvdWxkIGhhdmUgYmVlbiByZXR1cm5lZCBieSB0aGUgcXVlcnkgYmVmb3JlIGFwcGx5aW5nIGFueSBza2lwIG9yIHRha2Ugb3BlcmF0b3JzLCBidXQgYWZ0ZXIgYW55IGZpbHRlci93aGVyZSBwcmVkaWNhdGVzXHJcbiAgICB3b3VsZCBoYXZlIGJlZW4gYXBwbGllZC5cclxuICAqKi9cclxuICBleGVjdXRlUXVlcnkocXVlcnk6IEVudGl0eVF1ZXJ5IHwgc3RyaW5nLCBjYWxsYmFjaz86IFF1ZXJ5U3VjY2Vzc0NhbGxiYWNrLCBlcnJvckNhbGxiYWNrPzogUXVlcnlFcnJvckNhbGxiYWNrKSB7XHJcbiAgICBhc3NlcnRQYXJhbShxdWVyeSwgXCJxdWVyeVwiKS5pc0luc3RhbmNlT2YoRW50aXR5UXVlcnkpLm9yKCkuaXNTdHJpbmcoKS5jaGVjaygpO1xyXG4gICAgYXNzZXJ0UGFyYW0oY2FsbGJhY2ssIFwiY2FsbGJhY2tcIikuaXNGdW5jdGlvbigpLmlzT3B0aW9uYWwoKS5jaGVjaygpO1xyXG4gICAgYXNzZXJ0UGFyYW0oZXJyb3JDYWxsYmFjaywgXCJlcnJvckNhbGxiYWNrXCIpLmlzRnVuY3Rpb24oKS5pc09wdGlvbmFsKCkuY2hlY2soKTtcclxuICAgIGxldCBwcm9taXNlOiBQcm9taXNlPGFueT47XHJcbiAgICAvLyAncmVzb2x2ZScgbWV0aG9kcyBjcmVhdGUgYSBuZXcgdHlwZWQgb2JqZWN0IHdpdGggYWxsIG9mIGl0cyBwcm9wZXJ0aWVzIGZ1bGx5IHJlc29sdmVkIGFnYWluc3QgYSBsaXN0IG9mIHNvdXJjZXMuXHJcbiAgICAvLyBUaG91Z2h0IGFib3V0IGNyZWF0aW5nIGEgJ25vcm1hbGl6ZWQnIHF1ZXJ5IHdpdGggdGhlc2UgJ3Jlc29sdmVkJyBvYmplY3RzXHJcbiAgICAvLyBidXQgZGVjaWRlZCBub3QgdG8gYmVjYXVzZSB0aGUgJ3F1ZXJ5JyBtYXkgbm90IGJlIGFuIEVudGl0eVF1ZXJ5IChpdCBjYW4gYmUgYSBzdHJpbmcpIGFuZCBoZW5jZSBtaWdodCBub3QgaGF2ZSBhIHF1ZXJ5T3B0aW9ucyBvciBkYXRhU2VydmljZXMgcHJvcGVydHkgb24gaXQuXHJcbiAgICBsZXQgcXVlcnlPcHRpb25zID0gUXVlcnlPcHRpb25zLnJlc29sdmUoWyhxdWVyeSBhcyBhbnkpLnF1ZXJ5T3B0aW9ucywgdGhpcy5xdWVyeU9wdGlvbnMsIFF1ZXJ5T3B0aW9ucy5kZWZhdWx0SW5zdGFuY2VdKTtcclxuICAgIGxldCBkYXRhU2VydmljZSA9IERhdGFTZXJ2aWNlLnJlc29sdmUoWyhxdWVyeSBhcyBhbnkpLmRhdGFTZXJ2aWNlISwgdGhpcy5kYXRhU2VydmljZV0pO1xyXG5cclxuICAgIGlmICgoIWRhdGFTZXJ2aWNlLmhhc1NlcnZlck1ldGFkYXRhKSB8fCB0aGlzLm1ldGFkYXRhU3RvcmUuaGFzTWV0YWRhdGFGb3IoZGF0YVNlcnZpY2Uuc2VydmljZU5hbWUpKSB7XHJcbiAgICAgIHByb21pc2UgPSBleGVjdXRlUXVlcnlDb3JlKHRoaXMsIHF1ZXJ5LCBxdWVyeU9wdGlvbnMsIGRhdGFTZXJ2aWNlKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHByb21pc2UgPSB0aGlzLmZldGNoTWV0YWRhdGEoZGF0YVNlcnZpY2UpLnRoZW4oKCkgPT4ge1xyXG4gICAgICAgIHJldHVybiBleGVjdXRlUXVlcnlDb3JlKHRoaXMsIHF1ZXJ5LCBxdWVyeU9wdGlvbnMsIGRhdGFTZXJ2aWNlKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHByb21pc2VXaXRoQ2FsbGJhY2tzKHByb21pc2UsIGNhbGxiYWNrLCBlcnJvckNhbGxiYWNrIGFzIEVycm9yQ2FsbGJhY2spO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgRXhlY3V0ZXMgdGhlIHNwZWNpZmllZCBxdWVyeSBhZ2FpbnN0IHRoaXMgRW50aXR5TWFuYWdlcidzIGxvY2FsIGNhY2hlLlxyXG5cclxuICBCZWNhdXNlIHRoaXMgbWV0aG9kIGlzIGV4ZWN1dGVkIGltbWVkaWF0ZWx5IHRoZXJlIGlzIG5vIG5lZWQgZm9yIGEgcHJvbWlzZSBvciBhIGNhbGxiYWNrXHJcbiAgPiAgICAgbGV0IGVtID0gbmV3IEVudGl0eU1hbmFnZXIoc2VydmljZU5hbWUpO1xyXG4gID4gICAgIGxldCBxdWVyeSA9IG5ldyBFbnRpdHlRdWVyeShcIk9yZGVyc1wiKTtcclxuICA+ICAgICBsZXQgb3JkZXJzID0gZW0uZXhlY3V0ZVF1ZXJ5TG9jYWxseShxdWVyeSk7XHJcblxyXG4gIE5vdGUgdGhhdCB0aGlzIGNhbiBhbHNvIGJlIGFjY29tcGxpc2hlZCB1c2luZyB0aGUgJ2V4ZWN1dGVRdWVyeScgbWV0aG9kIHdpdGhcclxuICBhIEZldGNoU3RyYXRlZ3kgb2YgRnJvbUxvY2FsQ2FjaGUgYW5kIG1ha2luZyB1c2Ugb2YgdGhlIFByb21pc2Ugb3IgY2FsbGJhY2tcclxuICA+ICAgICBsZXQgZW0gPSBuZXcgRW50aXR5TWFuYWdlcihzZXJ2aWNlTmFtZSk7XHJcbiAgPiAgICAgbGV0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KFwiT3JkZXJzXCIpLnVzaW5nKEZldGNoU3RyYXRlZ3kuRnJvbUxvY2FsQ2FjaGUpO1xyXG4gID4gICAgIGVtLmV4ZWN1dGVRdWVyeShxdWVyeSkudGhlbiggZnVuY3Rpb24oZGF0YSkge1xyXG4gID4gICAgICAgICBsZXQgb3JkZXJzID0gZGF0YS5yZXN1bHRzO1xyXG4gID4gICAgICAgICAuLi4gcXVlcnkgcmVzdWx0cyBwcm9jZXNzZWQgaGVyZVxyXG4gID4gICAgIH0pLmNhdGNoKCBmdW5jdGlvbihlcnIpIHtcclxuICA+ICAgICAgICAgLi4uIHF1ZXJ5IGZhaWx1cmUgcHJvY2Vzc2VkIGhlcmVcclxuICA+ICAgICB9KTtcclxuICBAcGFyYW0gcXVlcnkgLSBUaGUgW1tFbnRpdHlRdWVyeV1dIHRvIGV4ZWN1dGUuXHJcbiAgQHJldHVybiAge0FycmF5IG9mIEVudGl0eX0gIEFycmF5IG9mIGVudGl0aWVzIGZyb20gY2FjaGUgdGhhdCBzYXRpc2Z5IHRoZSBxdWVyeVxyXG4gICoqL1xyXG4gIGV4ZWN1dGVRdWVyeUxvY2FsbHkocXVlcnk6IEVudGl0eVF1ZXJ5KSB7XHJcbiAgICByZXR1cm4gZXhlY3V0ZVF1ZXJ5TG9jYWxseUNvcmUodGhpcywgcXVlcnkpLnJlc3VsdHM7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBTYXZlcyBlaXRoZXIgYSBsaXN0IG9mIHNwZWNpZmllZCBlbnRpdGllcyBvciBhbGwgY2hhbmdlZCBlbnRpdGllcyB3aXRoaW4gdGhpcyBFbnRpdHlNYW5hZ2VyLiBJZiB0aGVyZSBhcmUgbm8gY2hhbmdlcyB0byBhbnkgb2YgdGhlIGVudGl0aWVzXHJcbiAgc3BlY2lmaWVkIHRoZW4gdGhlcmUgd2lsbCBiZSBubyBzZXJ2ZXIgc2lkZSBjYWxsIG1hZGUgYnV0IGEgdmFsaWQgJ2VtcHR5JyBzYXZlUmVzdWx0IHdpbGwgc3RpbGwgYmUgcmV0dXJuZWQuIF9fQXN5bmNfX1xyXG5cclxuICBPZnRlbiB3ZSB3aWxsIGJlIHNhdmluZyBhbGwgb2YgdGhlIGVudGl0aWVzIHdpdGhpbiBhbiBFbnRpdHlNYW5hZ2VyIHRoYXQgYXJlIGVpdGhlciBhZGRlZCwgbW9kaWZpZWQgb3IgZGVsZXRlZFxyXG4gIGFuZCB3ZSB3aWxsIGxldCB0aGUgJ3NhdmVDaGFuZ2VzJyBjYWxsIGRldGVybWluZSB3aGljaCBlbnRpdGllcyB0aGVzZSBhcmUuXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIHByZWV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgICAvLyBUaGlzIGNvdWxkIGluY2x1ZGUgYWRkZWQsIG1vZGlmaWVkIGFuZCBkZWxldGVkIGVudGl0aWVzLlxyXG4gID4gICAgICBlbS5zYXZlQ2hhbmdlcygpLnRoZW4oZnVuY3Rpb24oc2F2ZVJlc3VsdCkge1xyXG4gID4gICAgICAgICAgbGV0IHNhdmVkRW50aXRpZXMgPSBzYXZlUmVzdWx0LmVudGl0aWVzO1xyXG4gID4gICAgICAgICAgbGV0IGtleU1hcHBpbmdzID0gc2F2ZVJlc3VsdC5rZXlNYXBwaW5ncztcclxuICA+ICAgICAgfSkuY2F0Y2goZnVuY3Rpb24gKGUpIHtcclxuICA+ICAgICAgICAgIC8vIGUgaXMgYW55IGV4Y2VwdGlvbiB0aGF0IHdhcyB0aHJvd24uXHJcbiAgPiAgICAgIH0pO1xyXG5cclxuICBCdXQgd2UgY2FuIGFsc28gY29udHJvbCBleGFjdGx5IHdoaWNoIGVudGl0aWVzIHRvIHNhdmUgYW5kIGNhbiBzcGVjaWZ5IHNwZWNpZmljIFNhdmVPcHRpb25zXHJcblxyXG4gID4gICAgICAvLyBhc3N1bWUgZW50aXRpZXNUb1NhdmUgaXMgYW4gYXJyYXkgb2YgZW50aXRpZXMgdG8gc2F2ZS5cclxuICA+ICAgICAgbGV0IHNhdmVPcHRpb25zID0gbmV3IFNhdmVPcHRpb25zKHsgYWxsb3dDb25jdXJyZW50U2F2ZXM6IHRydWUgfSk7XHJcbiAgPiAgICAgIGVtLnNhdmVDaGFuZ2VzKGVudGl0aWVzVG9TYXZlLCBzYXZlT3B0aW9ucykudGhlbihmdW5jdGlvbihzYXZlUmVzdWx0KSB7XHJcbiAgPiAgICAgICAgICBsZXQgc2F2ZWRFbnRpdGllcyA9IHNhdmVSZXN1bHQuZW50aXRpZXM7XHJcbiAgPiAgICAgICAgICBsZXQga2V5TWFwcGluZ3MgPSBzYXZlUmVzdWx0LmtleU1hcHBpbmdzO1xyXG4gID4gICAgICB9KS5jYXRjaChmdW5jdGlvbiAoZSkge1xyXG4gID4gICAgICAgICAgLy8gZSBpcyBhbnkgZXhjZXB0aW9uIHRoYXQgd2FzIHRocm93bi5cclxuICA+ICAgICAgfSk7XHJcblxyXG4gIENhbGxiYWNrIG1ldGhvZHMgY2FuIGFsc28gYmUgdXNlZFxyXG4gID4gICAgICBlbS5zYXZlQ2hhbmdlcyhlbnRpdGllc1RvU2F2ZSwgbnVsbCxcclxuICA+ICAgICAgICAgIGZ1bmN0aW9uKHNhdmVSZXN1bHQpIHtcclxuICA+ICAgICAgICAgICAgICBsZXQgc2F2ZWRFbnRpdGllcyA9IHNhdmVSZXN1bHQuZW50aXRpZXM7XHJcbiAgPiAgICAgICAgICAgICAgbGV0IGtleU1hcHBpbmdzID0gc2F2ZVJlc3VsdC5rZXlNYXBwaW5ncztcclxuICA+ICAgICAgICAgIH0sIGZ1bmN0aW9uIChlKSB7XHJcbiAgPiAgICAgICAgICAgICAgLy8gZSBpcyBhbnkgZXhjZXB0aW9uIHRoYXQgd2FzIHRocm93bi5cclxuICA+ICAgICAgICAgIH1cclxuICA+ICAgICAgKTtcclxuXHJcbiAgQHBhcmFtIGVudGl0aWVzIC0gVGhlIGxpc3Qgb2YgZW50aXRpZXMgdG8gc2F2ZS5cclxuICBFdmVyeSBlbnRpdHkgaW4gdGhhdCBsaXN0IHdpbGwgYmUgc2VudCB0byB0aGUgc2VydmVyLCB3aGV0aGVyIGNoYW5nZWQgb3IgdW5jaGFuZ2VkLFxyXG4gIGFzIGxvbmcgYXMgaXQgaXMgYXR0YWNoZWQgdG8gdGhpcyBFbnRpdHlNYW5hZ2VyLlxyXG4gIElmIHRoaXMgcGFyYW1ldGVyIGlzIG9taXR0ZWQsIG51bGwgb3IgZW1wdHkgKHRoZSB1c3VhbCBjYXNlKSxcclxuICBldmVyeSBlbnRpdHkgd2l0aCBwZW5kaW5nIGNoYW5nZXMgaW4gdGhpcyBFbnRpdHlNYW5hZ2VyIHdpbGwgYmUgc2F2ZWQuXHJcbiAgQHBhcmFtIHNhdmVPcHRpb25zIC0gW1tTYXZlT3B0aW9uc11dIGZvciB0aGUgc2F2ZSAtIHdpbGwgZGVmYXVsdCB0b1xyXG4gIFtbRW50aXR5TWFuYWdlci5zYXZlT3B0aW9uc11dIGlmIG51bGwuXHJcbiAgQHBhcmFtIGNhbGxiYWNrIC0gIEZ1bmN0aW9uIGNhbGxlZCBvbiBzdWNjZXNzLlxyXG4gIEBwYXJhbSBlcnJvckNhbGxiYWNrIC0gRnVuY3Rpb24gY2FsbGVkIG9uIGZhaWx1cmUuXHJcbiAgQHJldHVybiB7UHJvbWlzZX0gUHJvbWlzZVxyXG4gICoqL1xyXG4gIHNhdmVDaGFuZ2VzKGVudGl0aWVzPzogRW50aXR5W10gfCBudWxsLCBzYXZlT3B0aW9ucz86IFNhdmVPcHRpb25zLCBjYWxsYmFjaz86IEZ1bmN0aW9uLCBlcnJvckNhbGxiYWNrPzogRnVuY3Rpb24pIHtcclxuICAgIGFzc2VydFBhcmFtKGVudGl0aWVzLCBcImVudGl0aWVzXCIpLmlzT3B0aW9uYWwoKS5pc0FycmF5KCkuaXNFbnRpdHkoKS5jaGVjaygpO1xyXG4gICAgYXNzZXJ0UGFyYW0oc2F2ZU9wdGlvbnMsIFwic2F2ZU9wdGlvbnNcIikuaXNJbnN0YW5jZU9mKFNhdmVPcHRpb25zKS5pc09wdGlvbmFsKCkuY2hlY2soKTtcclxuICAgIGFzc2VydFBhcmFtKGNhbGxiYWNrLCBcImNhbGxiYWNrXCIpLmlzRnVuY3Rpb24oKS5pc09wdGlvbmFsKCkuY2hlY2soKTtcclxuICAgIGFzc2VydFBhcmFtKGVycm9yQ2FsbGJhY2ssIFwiZXJyb3JDYWxsYmFja1wiKS5pc0Z1bmN0aW9uKCkuaXNPcHRpb25hbCgpLmNoZWNrKCk7XHJcblxyXG4gICAgc2F2ZU9wdGlvbnMgPSBzYXZlT3B0aW9ucyB8fCB0aGlzLnNhdmVPcHRpb25zIHx8IFNhdmVPcHRpb25zLmRlZmF1bHRJbnN0YW5jZTtcclxuXHJcbiAgICBsZXQgZW50aXRpZXNUb1NhdmUgPSBnZXRFbnRpdGllc1RvU2F2ZSh0aGlzLCBlbnRpdGllcyA/IGVudGl0aWVzIDogdW5kZWZpbmVkKTtcclxuXHJcbiAgICBpZiAoZW50aXRpZXNUb1NhdmUubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgIGxldCByZXN1bHQgPSB7IGVudGl0aWVzOiBbXSwga2V5TWFwcGluZ3M6IFtdIH0gYXMgU2F2ZVJlc3VsdDtcclxuICAgICAgaWYgKGNhbGxiYWNrKSBjYWxsYmFjayhyZXN1bHQpO1xyXG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFzYXZlT3B0aW9ucy5hbGxvd0NvbmN1cnJlbnRTYXZlcykge1xyXG4gICAgICBsZXQgYW55UGVuZGluZ1NhdmVzID0gZW50aXRpZXNUb1NhdmUuc29tZShmdW5jdGlvbiAoZW50aXR5KSB7XHJcbiAgICAgICAgcmV0dXJuIGVudGl0eS5lbnRpdHlBc3BlY3QuaXNCZWluZ1NhdmVkO1xyXG4gICAgICB9KTtcclxuICAgICAgaWYgKGFueVBlbmRpbmdTYXZlcykge1xyXG4gICAgICAgIGxldCBlcnIgPSBuZXcgRXJyb3IoXCJDb25jdXJyZW50IHNhdmVzIG5vdCBhbGxvd2VkIC0gU2F2ZU9wdGlvbnMuYWxsb3dDb25jdXJyZW50U2F2ZXMgaXMgZmFsc2VcIik7XHJcbiAgICAgICAgaWYgKGVycm9yQ2FsbGJhY2spIGVycm9yQ2FsbGJhY2soZXJyKTtcclxuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZXJyKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGNsZWFyU2VydmVyRXJyb3JzKGVudGl0aWVzVG9TYXZlKTtcclxuXHJcbiAgICBsZXQgdmFsRXJyb3IgPSB0aGlzLnNhdmVDaGFuZ2VzVmFsaWRhdGVPbkNsaWVudChlbnRpdGllc1RvU2F2ZSk7XHJcbiAgICBpZiAodmFsRXJyb3IpIHtcclxuICAgICAgaWYgKGVycm9yQ2FsbGJhY2spIGVycm9yQ2FsbGJhY2sodmFsRXJyb3IpO1xyXG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QodmFsRXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBkYXRhU2VydmljZSA9IERhdGFTZXJ2aWNlLnJlc29sdmUoW3NhdmVPcHRpb25zLmRhdGFTZXJ2aWNlLCB0aGlzLmRhdGFTZXJ2aWNlXSk7XHJcbiAgICBsZXQgc2F2ZUNvbnRleHQ6IFNhdmVDb250ZXh0ID0ge1xyXG4gICAgICBlbnRpdHlNYW5hZ2VyOiB0aGlzLFxyXG4gICAgICBkYXRhU2VydmljZTogZGF0YVNlcnZpY2UsXHJcbiAgICAgIHByb2Nlc3NTYXZlZEVudGl0aWVzOiBwcm9jZXNzU2F2ZWRFbnRpdGllcyxcclxuICAgICAgcmVzb3VyY2VOYW1lOiBzYXZlT3B0aW9ucy5yZXNvdXJjZU5hbWUgfHwgdGhpcy5zYXZlT3B0aW9ucy5yZXNvdXJjZU5hbWUgfHwgXCJTYXZlQ2hhbmdlc1wiXHJcbiAgICB9O1xyXG5cclxuICAgIC8vIFRPRE86IG5lZWQgdG8gY2hlY2sgdGhhdCBpZiB3ZSBhcmUgZG9pbmcgYSBwYXJ0aWFsIHNhdmUgdGhhdCBhbGwgZW50aXRpZXMgd2hvc2UgdGVtcCBrZXlzXHJcbiAgICAvLyBhcmUgcmVmZXJlbmNlZCBhcmUgYWxzbyBpbiB0aGUgcGFydGlhbCBzYXZlIGdyb3VwXHJcblxyXG4gICAgbGV0IHNhdmVCdW5kbGUgPSB7IGVudGl0aWVzOiBlbnRpdGllc1RvU2F2ZSwgc2F2ZU9wdGlvbnM6IHNhdmVPcHRpb25zIH07XHJcblxyXG5cclxuICAgIHRyeSB7IC8vIEd1YXJkIGFnYWluc3QgZXhjZXB0aW9uIHRocm93biBpbiBkYXRhc2VydmljZSBhZGFwdGVyIGJlZm9yZSBpdCBnb2VzIGFzeW5jXHJcbiAgICAgIHVwZGF0ZUNvbmN1cnJlbmN5UHJvcGVydGllcyhlbnRpdGllc1RvU2F2ZSk7XHJcbiAgICAgIHJldHVybiBkYXRhU2VydmljZS5hZGFwdGVySW5zdGFuY2UhLnNhdmVDaGFuZ2VzKHNhdmVDb250ZXh0LCBzYXZlQnVuZGxlKVxyXG4gICAgICAgIC50aGVuKHNhdmVTdWNjZXNzKS50aGVuKChyKSA9PiByLCBzYXZlRmFpbCk7XHJcbiAgICB9IGNhdGNoIChlcnIpIHtcclxuICAgICAgLy8gdW5kbyB0aGUgbWFya2luZyBieSB1cGRhdGVDb25jdXJyZW5jeVByb3BlcnRpZXNcclxuICAgICAgbWFya0lzQmVpbmdTYXZlZChlbnRpdGllc1RvU2F2ZSwgZmFsc2UpO1xyXG4gICAgICBpZiAoZXJyb3JDYWxsYmFjaykgZXJyb3JDYWxsYmFjayhlcnIpO1xyXG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZXJyKTtcclxuICAgIH1cclxuXHJcbiAgICBmdW5jdGlvbiBzYXZlU3VjY2VzcyhzYXZlUmVzdWx0OiBTYXZlUmVzdWx0KSB7XHJcbiAgICAgIGxldCBlbSA9IHNhdmVDb250ZXh0LmVudGl0eU1hbmFnZXI7XHJcbiAgICAgIG1hcmtJc0JlaW5nU2F2ZWQoZW50aXRpZXNUb1NhdmUsIGZhbHNlKTtcclxuICAgICAgbGV0IHNhdmVkRW50aXRpZXMgPSBzYXZlQ29udGV4dC5wcm9jZXNzU2F2ZWRFbnRpdGllcyhzYXZlUmVzdWx0KTtcclxuICAgICAgc2F2ZVJlc3VsdC5lbnRpdGllcyA9IHNhdmVkRW50aXRpZXM7XHJcblxyXG4gICAgICAvLyB1cGRhdGUgX2hhc0NoYW5nZXMgYWZ0ZXIgc2F2ZS5cclxuICAgICAgZW0uX3NldEhhc0NoYW5nZXMoKTtcclxuXHJcbiAgICAgIC8vIGNhbid0IGRvIHRoaXMgYW55bW9yZSBiZWNhdXNlIG90aGVyIGNoYW5nZXMgbWlnaHQgaGF2ZSBiZWVuIG1hZGUgd2hpbGUgc2F2ZWQgZW50aXRpZXMgaW4gZmxpZ2h0LlxyXG4gICAgICAvLyAgICAgIGxldCBoYXNDaGFuZ2VzID0gKGlzRnVsbFNhdmUgJiYgaGF2ZVNhbWVDb250ZW50cyhlbnRpdGllc1RvU2F2ZSwgc2F2ZWRFbnRpdGllcykpID8gZmFsc2UgOiBudWxsO1xyXG4gICAgICAvLyAgICAgIGVtLl9zZXRIYXNDaGFuZ2VzKGhhc0NoYW5nZXMpO1xyXG5cclxuICAgICAgaWYgKGNhbGxiYWNrKSBjYWxsYmFjayhzYXZlUmVzdWx0KTtcclxuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShzYXZlUmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICBmdW5jdGlvbiBwcm9jZXNzU2F2ZWRFbnRpdGllcyhzYXZlUmVzdWx0OiBTYXZlUmVzdWx0KSB7XHJcbiAgICAgIGxldCBzYXZlZEVudGl0aWVzID0gc2F2ZVJlc3VsdC5lbnRpdGllcztcclxuICAgICAgbGV0IGRlbGV0ZWRLZXlzID0gc2F2ZVJlc3VsdC5kZWxldGVkS2V5cyB8fCBbXTtcclxuICAgICAgaWYgKHNhdmVkRW50aXRpZXMubGVuZ3RoID09PSAwICYmIGRlbGV0ZWRLZXlzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgIHJldHVybiBbXTtcclxuICAgICAgfVxyXG4gICAgICBsZXQga2V5TWFwcGluZ3MgPSBzYXZlUmVzdWx0LmtleU1hcHBpbmdzO1xyXG4gICAgICBsZXQgZW0gPSBzYXZlQ29udGV4dC5lbnRpdHlNYW5hZ2VyO1xyXG5cclxuICAgICAgLy8gbXVzdCBvY2N1ciBvdXRzaWRlIG9mIGlzTG9hZGluZyBibG9ja1xyXG4gICAgICBmaXh1cEtleXMoZW0sIGtleU1hcHBpbmdzKTtcclxuXHJcbiAgICAgIGNvcmUudXNpbmcoZW0sIFwiaXNMb2FkaW5nXCIsIHRydWUsICgpID0+IHtcclxuXHJcbiAgICAgICAgbGV0IG1hcHBpbmdDb250ZXh0ID0gbmV3IE1hcHBpbmdDb250ZXh0KHtcclxuICAgICAgICAgIHF1ZXJ5OiB1bmRlZmluZWQsIC8vIHRlbGxzIHZpc2l0QW5kTWVyZ2UgdGhpcyBpcyBhIHNhdmUgaW5zdGVhZCBvZiBhIHF1ZXJ5XHJcbiAgICAgICAgICBlbnRpdHlNYW5hZ2VyOiBlbSxcclxuICAgICAgICAgIG1lcmdlT3B0aW9uczogeyBtZXJnZVN0cmF0ZWd5OiBNZXJnZVN0cmF0ZWd5Lk92ZXJ3cml0ZUNoYW5nZXMgfSxcclxuICAgICAgICAgIGRhdGFTZXJ2aWNlOiBkYXRhU2VydmljZVxyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBUaGUgdmlzaXRBbmRNZXJnZSBvcGVyYXRpb24gaGFzIGJlZW4gb3B0aW1pemVkIHNvIHRoYXQgd2UgZG8gbm90IGFjdHVhbGx5IHBlcmZvcm0gYSBtZXJnZSBpZiB0aGVcclxuICAgICAgICAvLyB0aGUgc2F2ZSBvcGVyYXRpb24gZGlkIG5vdCBhY3R1YWxseSByZXR1cm4gdGhlIGVudGl0eSAtIGkuZS4gZHVyaW5nIE9EYXRhIGFuZCBNb25nbyB1cGRhdGVzIGFuZCBkZWxldGVzLlxyXG4gICAgICAgIHNhdmVkRW50aXRpZXMgPSBtYXBwaW5nQ29udGV4dC52aXNpdEFuZE1lcmdlKHNhdmVkRW50aXRpZXMsIHsgbm9kZVR5cGU6IFwicm9vdFwiIH0pO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIGRldGFjaCBhbnkgZW50aXRpZXMgZm91bmQgaW4gdGhlIGVtIHRoYXQgYXBwZWFyIGluIHRoZSBkZWxldGVkS2V5cyBsaXN0LiBcclxuICAgICAgZGVsZXRlZEtleXMuZm9yRWFjaChrZXkgPT4ge1xyXG4gICAgICAgIGxldCBlbnRpdHlUeXBlID0gZW0ubWV0YWRhdGFTdG9yZS5fZ2V0U3RydWN0dXJhbFR5cGUoa2V5LmVudGl0eVR5cGVOYW1lKSBhcyBFbnRpdHlUeXBlO1xyXG4gICAgICAgIGxldCBla2V5ID0gbmV3IEVudGl0eUtleShlbnRpdHlUeXBlLCBrZXkua2V5VmFsdWVzKTtcclxuICAgICAgICBsZXQgZW50aXR5ID0gZW0uZ2V0RW50aXR5QnlLZXkoZWtleSk7XHJcbiAgICAgICAgaWYgKGVudGl0eSkge1xyXG4gICAgICAgICAgZW50aXR5LmVudGl0eUFzcGVjdC5zZXREZXRhY2hlZCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICByZXR1cm4gc2F2ZWRFbnRpdGllcztcclxuICAgIH1cclxuXHJcbiAgICBmdW5jdGlvbiBzYXZlRmFpbChzZXJ2ZXJFcnJvcjogU2F2ZUVycm9yRnJvbVNlcnZlcikge1xyXG4gICAgICBtYXJrSXNCZWluZ1NhdmVkKGVudGl0aWVzVG9TYXZlLCBmYWxzZSk7XHJcbiAgICAgIGxldCBjbGllbnRFcnJvciA9IHByb2Nlc3NTZXJ2ZXJFcnJvcnMoc2F2ZUNvbnRleHQsIHNlcnZlckVycm9yKTtcclxuICAgICAgaWYgKGVycm9yQ2FsbGJhY2spIGVycm9yQ2FsbGJhY2soY2xpZW50RXJyb3IpO1xyXG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoY2xpZW50RXJyb3IpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgUnVuIHRoZSBcInNhdmVDaGFuZ2VzXCIgcHJlLXNhdmUgY2xpZW50IHZhbGlkYXRpb24gbG9naWMuXHJcbiAgXHJcbiAgVGhpcyBpcyBOT1QgYSBnZW5lcmFsIHB1cnBvc2UgdmFsaWRhdGlvbiBtZXRob2QuXHJcbiAgSXQgaXMgaW50ZW5kZWQgZm9yIHV0aWxpdGllcyB0aGF0IG11c3Qga25vdyBpZiBzYXZlQ2hhbmdlc1xyXG4gIHdvdWxkIHJlamVjdCB0aGUgc2F2ZSBkdWUgdG8gY2xpZW50IHZhbGlkYXRpb24gZXJyb3JzLlxyXG4gIFxyXG4gIEl0IG9ubHkgdmFsaWRhdGVzIGVudGl0aWVzIGlmIHRoZSBFbnRpdHlNYW5hZ2VyJ3NcclxuICBbW1ZhbGlkYXRpb25PcHRpb25zXV0udmFsaWRhdGVPblNhdmUgaXMgdHJ1ZS5cclxuICBcclxuICBAcGFyYW0gZW50aXRpZXNUb1NhdmUge0FycmF5IG9mIEVudGl0eX0gVGhlIGxpc3Qgb2YgZW50aXRpZXMgdG8gc2F2ZSAodG8gdmFsaWRhdGUpLlxyXG4gIEByZXR1cm4ge0Vycm9yfSBWYWxpZGF0aW9uIGVycm9yIG9yIG51bGwgaWYgbm8gZXJyb3JcclxuICAqKi9cclxuICBzYXZlQ2hhbmdlc1ZhbGlkYXRlT25DbGllbnQoZW50aXRpZXNUb1NhdmU6IEVudGl0eVtdKSB7XHJcblxyXG4gICAgaWYgKHRoaXMudmFsaWRhdGlvbk9wdGlvbnMudmFsaWRhdGVPblNhdmUpIHtcclxuICAgICAgbGV0IGZhaWxlZEVudGl0aWVzID0gZW50aXRpZXNUb1NhdmUuZmlsdGVyKGZ1bmN0aW9uIChlbnRpdHkpIHtcclxuICAgICAgICBsZXQgYXNwZWN0ID0gZW50aXR5LmVudGl0eUFzcGVjdDtcclxuICAgICAgICBsZXQgaXNWYWxpZCA9IGFzcGVjdC5lbnRpdHlTdGF0ZS5pc0RlbGV0ZWQoKSB8fCBhc3BlY3QudmFsaWRhdGVFbnRpdHkoKTtcclxuICAgICAgICByZXR1cm4gIWlzVmFsaWQ7XHJcbiAgICAgIH0pO1xyXG4gICAgICBpZiAoZmFpbGVkRW50aXRpZXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgIGxldCB2YWxFcnJvciA9IG5ldyBFcnJvcihcIkNsaWVudCBzaWRlIHZhbGlkYXRpb24gZXJyb3JzIGVuY291bnRlcmVkIC0gc2VlIHRoZSBlbnRpdHlFcnJvcnMgY29sbGVjdGlvbiBvbiB0aGlzIG9iamVjdCBmb3IgbW9yZSBkZXRhaWxcIik7XHJcbiAgICAgICAgKHZhbEVycm9yIGFzIGFueSkuZW50aXR5RXJyb3JzID0gY3JlYXRlRW50aXR5RXJyb3JzKGZhaWxlZEVudGl0aWVzKTtcclxuICAgICAgICByZXR1cm4gdmFsRXJyb3I7IC8vIFRPRE86IHR5cGUgdGhpcy5cclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG5cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfZmluZEVudGl0eUdyb3VwKGVudGl0eVR5cGU6IEVudGl0eVR5cGUpIHtcclxuICAgIHJldHVybiB0aGlzLl9lbnRpdHlHcm91cE1hcFtlbnRpdHlUeXBlLm5hbWVdO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIHByZWV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgICBsZXQgZW1wbG95ZWVUeXBlID0gZW0xLm1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZShcIkVtcGxveWVlXCIpO1xyXG4gID4gICAgICBsZXQgZW1wbG95ZWVLZXkgPSBuZXcgRW50aXR5S2V5KGVtcGxveWVlVHlwZSwgMSk7XHJcbiAgPiAgICAgIGxldCBlbXBsb3llZSA9IGVtMS5nZXRFbnRpdHlCeUtleShlbXBsb3llZUtleSk7XHJcbiAgPiAgICAgIC8vIGVtcGxveWVlIHdpbGwgZWl0aGVyIGJlIGFuIGVudGl0eSBvciBudWxsLlxyXG4gICoqL1xyXG4gIGdldEVudGl0eUJ5S2V5KGVudGl0eUtleTogRW50aXR5S2V5KTogRW50aXR5IHwgbnVsbDtcclxuXHJcbiAgLyoqICBcclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgcHJlZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgIGxldCBlbXBsb3llZSA9IGVtMS5nZXRFbnRpdHlCeUtleShcIkVtcGxveWVlXCIsIDEpO1xyXG4gID4gICAgICAvLyBlbXBsb3llZSB3aWxsIGVpdGhlciBiZSBhbiBlbnRpdHkgb3IgbnVsbC5cclxuICAqKi9cclxuICBnZXRFbnRpdHlCeUtleSh0eXBlTmFtZTogc3RyaW5nLCBrZXlWYWx1ZXM6IGFueSB8IGFueVtdKTogRW50aXR5IHwgbnVsbDtcclxuXHJcbiAgLyoqICBcclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgcHJlZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgIGxldCBlbXBsb3llZVR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiRW1wbG95ZWVcIik7XHJcbiAgPiAgICAgIGxldCBlbXBsb3llZSA9IGVtMS5nZXRFbnRpdHlCeUtleShlbXBsb3llZVR5cGUsIDEpO1xyXG4gID4gICAgICAvLyBlbXBsb3llZSB3aWxsIGVpdGhlciBiZSBhbiBlbnRpdHkgb3IgbnVsbC5cclxuICAqKi9cclxuICBnZXRFbnRpdHlCeUtleSh0eXBlOiBFbnRpdHlUeXBlLCBrZXlWYWx1ZXM6IGFueSB8IGFueVtdKTogRW50aXR5IHwgbnVsbDtcclxuXHJcbiAgLyoqICBcclxuICBBdHRlbXB0cyB0byBsb2NhdGUgYW4gZW50aXR5IHdpdGhpbiB0aGlzIEVudGl0eU1hbmFnZXIgYnkgaXRzIFtFbnRpdHlLZXldLlxyXG4gIEBwYXJhbSBlbnRpdHlLZXkgLSBUaGUgW1tFbnRpdHlLZXldXSBvZiB0aGUgRW50aXR5IHRvIGJlIGxvY2F0ZWQuXHJcbiAgQHBhcmFtIHR5cGUgLSBUaGUgW1tFbnRpdHlUeXBlXV0gZm9yIHRoaXMga2V5LlxyXG4gIEBwYXJhbSB0eXBlTmFtZSAtIFRoZSBFbnRpdHlUeXBlIG5hbWUgZm9yIHRoaXMga2V5LlxyXG4gIEBwYXJhbSBrZXlWYWx1ZXMgLSBUaGUgdmFsdWVzIGZvciB0aGlzIGtleSAtIHdpbGwgdXN1YWxseSBqdXN0IGJlIGEgc2luZ2xlIHZhbHVlOyBhbiBhcnJheSBpcyBvbmx5IG5lZWRlZCBmb3IgbXVsdGlwYXJ0IGtleXMuICBcclxuICBAcmV0dXJuIEFuIEVudGl0eSBvciBudWxsO1xyXG4gICoqL1xyXG4gIGdldEVudGl0eUJ5S2V5KC4uLmFyZ3M6IGFueVtdKSB7XHJcbiAgICBsZXQgZW50aXR5S2V5ID0gY3JlYXRlRW50aXR5S2V5KHRoaXMsIGFyZ3MpLmVudGl0eUtleTtcclxuICAgIGxldCBlbnRpdHlUeXBlcyA9IGVudGl0eUtleS5fc3VidHlwZXMgfHwgW2VudGl0eUtleS5lbnRpdHlUeXBlXTtcclxuICAgIGxldCBlOiBFbnRpdHkgfCB1bmRlZmluZWQ7XHJcbiAgICAvLyBoYWNrIHVzZSBvZiBzb21lIHRvIHNpbXVsYXRlIG1hcEZpcnN0IGxvZ2ljLlxyXG4gICAgZW50aXR5VHlwZXMuc29tZSgoZXQpID0+IHtcclxuICAgICAgbGV0IGdyb3VwID0gdGhpcy5fZmluZEVudGl0eUdyb3VwKGV0KTtcclxuICAgICAgLy8gZ3JvdXAgdmVyc2lvbiBvZiBmaW5kRW50aXR5QnlLZXkgZG9lc24ndCBjYXJlIGFib3V0IGVudGl0eVR5cGVcclxuICAgICAgZSA9IGdyb3VwICYmIGdyb3VwLmZpbmRFbnRpdHlCeUtleShlbnRpdHlLZXkpO1xyXG4gICAgICByZXR1cm4gZSAhPSBudWxsO1xyXG4gICAgfSk7XHJcbiAgICByZXR1cm4gZSB8fCBudWxsO1xyXG4gIH1cclxuXHJcbiAgZmV0Y2hFbnRpdHlCeUtleSh0eXBlTmFtZTogc3RyaW5nLCBrZXlWYWx1ZXM6IGFueSB8IGFueVtdLCBjaGVja0xvY2FsQ2FjaGVGaXJzdD86IGJvb2xlYW4pOiBQcm9taXNlPElFbnRpdHlCeUtleVJlc3VsdD47XHJcbiAgZmV0Y2hFbnRpdHlCeUtleShlbnRpdHlUeXBlOiBFbnRpdHlUeXBlLCBrZXlWYWx1ZXM6IGFueSB8IGFueVtdLCBjaGVja0xvY2FsQ2FjaGVGaXJzdD86IGJvb2xlYW4pOiBQcm9taXNlPElFbnRpdHlCeUtleVJlc3VsdD47XHJcbiAgZmV0Y2hFbnRpdHlCeUtleShlbnRpdHlLZXk6IEVudGl0eUtleSwgY2hlY2tMb2NhbENhY2hlRmlyc3Q/OiBib29sZWFuKTogUHJvbWlzZTxJRW50aXR5QnlLZXlSZXN1bHQ+O1xyXG4gIC8qKlxyXG4gIEF0dGVtcHRzIHRvIGZldGNoIGFuIGVudGl0eSBmcm9tIHRoZSBzZXJ2ZXIgYnkgaXRzIFtbRW50aXR5S2V5XV0gd2l0aFxyXG4gIGFuIG9wdGlvbiB0byBjaGVjayB0aGUgbG9jYWwgY2FjaGUgZmlyc3QuIE5vdGUgdGhlIHRoaXMgRW50aXR5TWFuYWdlcidzIHF1ZXJ5T3B0aW9ucy5tZXJnZVN0cmF0ZWd5XHJcbiAgd2lsbCBiZSB1c2VkIHRvIG1lcmdlIGFueSBzZXJ2ZXIgc2lkZSBlbnRpdHkgcmV0dXJuZWQgYnkgdGhpcyBtZXRob2QuXHJcbiAgPiAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgcHJlZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgbGV0IGVtcGxveWVlVHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJFbXBsb3llZVwiKTtcclxuICA+ICAgICBsZXQgZW1wbG95ZWVLZXkgPSBuZXcgRW50aXR5S2V5KGVtcGxveWVlVHlwZSwgMSk7XHJcbiAgPiAgICAgZW0xLmZldGNoRW50aXR5QnlLZXkoZW1wbG95ZWVLZXkpLnRoZW4oZnVuY3Rpb24ocmVzdWx0KSB7XHJcbiAgPiAgICAgICBsZXQgZW1wbG95ZWUgPSByZXN1bHQuZW50aXR5O1xyXG4gID4gICAgICAgbGV0IGVudGl0eUtleSA9IHJlc3VsdC5lbnRpdHlLZXk7XHJcbiAgPiAgICAgICBsZXQgZnJvbUNhY2hlID0gcmVzdWx0LmZyb21DYWNoZTtcclxuICA+ICAgICB9KTtcclxuICBAcGFyYW0gdHlwZU5hbWUgIC0gVGhlIEVudGl0eVR5cGUgbmFtZSBmb3IgdGhpcyBrZXkuXHJcbiAgQHBhcmFtIGVudGl0eVR5cGUgIC0gVGhlIEVudGl0eVR5cGUgZm9yIHRoaXMga2V5LlxyXG4gIEBwYXJhbSBrZXlWYWx1ZXMgLSBUaGUgdmFsdWVzIGZvciB0aGlzIGtleSAtIHdpbGwgdXN1YWxseSBqdXN0IGJlIGEgc2luZ2xlIHZhbHVlOyBhbiBhcnJheSBpcyBvbmx5IG5lZWRlZCBmb3IgbXVsdGlwYXJ0IGtleXMuXHJcbiAgQHBhcmFtIGVudGl0eUtleSAtIFRoZSBbW0VudGl0eUtleV1dIG9mIHRoZSBFbnRpdHkgdG8gYmUgbG9jYXRlZC5cclxuICBAcGFyYW0gY2hlY2tMb2NhbENhY2hlRmlyc3QgLSAoZGVmYXVsdCA9IGZhbHNlKSAtIFdoZXRoZXIgdG8gY2hlY2sgdGhpcyBFbnRpdHlNYW5hZ2VyIGZpcnN0IGJlZm9yZSBnb2luZyB0byB0aGUgc2VydmVyLiBCeSBkZWZhdWx0LCB0aGUgcXVlcnkgd2lsbCBOT1QgZG8gdGhpcy5cclxuICBAcmV0dXJuIHtQcm9taXNlfVxyXG4gICAgLSBQcm9wZXJ0aWVzIG9uIHRoZSBwcm9taXNlIHN1Y2Nlc3MgcmVzdWx0XHJcbiAgICAgIC0gZW50aXR5IHtPYmplY3R9IFRoZSBlbnRpdHkgcmV0dXJuZWQgb3IgbnVsbFxyXG4gICAgICAtIGVudGl0eUtleSB7RW50aXR5S2V5fSBUaGUgZW50aXR5S2V5IG9mIHRoZSBlbnRpdHkgdG8gZmV0Y2guXHJcbiAgICAgIC0gZnJvbUNhY2hlIHtCb29sZWFufSBXaGV0aGVyIHRoaXMgZW50aXR5IHdhcyBmZXRjaGVkIGZyb20gdGhlIHNlcnZlciBvciB3YXMgZm91bmQgaW4gdGhlIGxvY2FsIGNhY2hlLlxyXG4gICoqL1xyXG4gIGZldGNoRW50aXR5QnlLZXkoLi4uYXJnczogYW55W10pIHtcclxuICAgIGxldCBkYXRhU2VydmljZSA9IERhdGFTZXJ2aWNlLnJlc29sdmUoW3RoaXMuZGF0YVNlcnZpY2VdKTtcclxuICAgIGlmICgoIWRhdGFTZXJ2aWNlLmhhc1NlcnZlck1ldGFkYXRhKSB8fCB0aGlzLm1ldGFkYXRhU3RvcmUuaGFzTWV0YWRhdGFGb3IoZGF0YVNlcnZpY2Uuc2VydmljZU5hbWUpKSB7XHJcbiAgICAgIHJldHVybiBmZXRjaEVudGl0eUJ5S2V5Q29yZSh0aGlzLCBhcmdzKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHJldHVybiB0aGlzLmZldGNoTWV0YWRhdGEoZGF0YVNlcnZpY2UpLnRoZW4oKCkgPT4ge1xyXG4gICAgICAgIHJldHVybiBmZXRjaEVudGl0eUJ5S2V5Q29yZSh0aGlzLCBhcmdzKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBbRGVwcmVjYXRlZF0gLSBBdHRlbXB0cyB0byBsb2NhdGUgYW4gZW50aXR5IHdpdGhpbiB0aGlzIEVudGl0eU1hbmFnZXIgYnkgaXRzICBbW0VudGl0eUtleV1dLlxyXG4gID4gICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIHByZWV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgIGxldCBlbXBsb3llZVR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiRW1wbG95ZWVcIik7XHJcbiAgPiAgICAgbGV0IGVtcGxveWVlS2V5ID0gbmV3IEVudGl0eUtleShlbXBsb3llZVR5cGUsIDEpO1xyXG4gID4gICAgIGxldCBlbXBsb3llZSA9IGVtMS5maW5kRW50aXR5QnlLZXkoZW1wbG95ZWVLZXkpO1xyXG4gID4gICAgIC8vIGVtcGxveWVlIHdpbGwgZWl0aGVyIGJlIGFuIGVudGl0eSBvciBudWxsLlxyXG4gIEBkZXByZWNhdGVkICAgIFVzZSBnZXRFbnRpdHlCeUtleSBpbnN0ZWFkXHJcbiAgQHBhcmFtIGVudGl0eUtleSAtIFRoZSAgW1tFbnRpdHlLZXldXSBvZiB0aGUgRW50aXR5IHRvIGJlIGxvY2F0ZWQuXHJcbiAgQHJldHVybiBBbiBFbnRpdHkgb3IgbnVsbDtcclxuICAqKi9cclxuICBmaW5kRW50aXR5QnlLZXkoZW50aXR5S2V5OiBFbnRpdHlLZXkpIHtcclxuICAgIHJldHVybiB0aGlzLmdldEVudGl0eUJ5S2V5KGVudGl0eUtleSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBHZW5lcmF0ZXMgYSB0ZW1wb3Jhcnkga2V5IGZvciB0aGUgc3BlY2lmaWVkIGVudGl0eS4gIFRoaXMgaXMgdXNlZCB0byBpbnN1cmUgdGhhdCBuZXdseVxyXG4gIGNyZWF0ZWQgZW50aXRpZXMgaGF2ZSB1bmlxdWUga2V5cyBhbmQgdG8gcmVnaXN0ZXIgdGhhdCB0aGVzZSBrZXlzIGFyZSB0ZW1wb3JhcnkgYW5kXHJcbiAgbmVlZCB0byBiZSBhdXRvbWF0aWNhbGx5IHJlcGxhY2VkIHdpdGggJ3JlYWwnIGtleSB2YWx1ZXMgb25jZSB0aGVzZSBlbnRpdGllcyBhcmUgc2F2ZWQuXHJcbiAgXHJcbiAgVGhlIFtbRW50aXR5TWFuYWdlci5rZXlHZW5lcmF0b3JDdG9yXV0gcHJvcGVydHkgaXMgdXNlZCBpbnRlcm5hbGx5IGJ5IHRoaXMgbWV0aG9kIHRvIGFjdHVhbGx5IGdlbmVyYXRlXHJcbiAgdGhlIGtleXMgLSBTZWUgdGhlICBLZXlHZW5lcmF0b3IgaW50ZXJmYWNlIGludGVyZmFjZSBkZXNjcmlwdGlvbiB0byBzZWVcclxuICBob3cgYSBjdXN0b20ga2V5IGdlbmVyYXRvciBjYW4gYmUgcGx1Z2dlZCBpbi5cclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgcHJlZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgIGxldCBjdXN0VHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJDdXN0b21lclwiKTtcclxuICA+ICAgICAgbGV0IGN1c3RvbWVyID0gY3VzdFR5cGUuY3JlYXRlRW50aXR5KCk7XHJcbiAgPiAgICAgIGxldCBjdXN0b21lcklkID0gZW0uZ2VuZXJhdGVUZW1wS2V5VmFsdWUoY3VzdG9tZXIpO1xyXG4gID4gICAgICAvLyBUaGUgJ2N1c3RvbWVyJyBlbnRpdHkgJ0N1c3RvbWVySUQnIHByb3BlcnR5IGlzIG5vdyBzZXQgdG8gYSBuZXdseSBnZW5lcmF0ZWQgdW5pcXVlIGlkIHZhbHVlXHJcbiAgPiAgICAgIC8vIFRoaXMgcHJvcGVydHkgd2lsbCBjaGFuZ2UgYWdhaW4gYWZ0ZXIgYSBzdWNjZXNzZnVsIHNhdmUgb2YgdGhlICdjdXN0b21lcicgZW50aXR5LlxyXG4gID4gIFxyXG4gID4gICAgICBlbTEuc2F2ZUNoYW5nZXMoKS50aGVuKCBmdW5jdGlvbiggZGF0YSkge1xyXG4gID4gICAgICAgICAgbGV0IHNhbWVDdXN0MSA9IGRhdGEucmVzdWx0c1swXTtcclxuICA+ICAgICAgICAgIC8vIGN1c3QxID09PSBzYW1lQ3VzdDE7XHJcbiAgPiAgICAgICAgICAvLyBidXQgY3VzdDEuZ2V0UHJvcGVydHkoXCJDdXN0b21lcklkXCIpICE9IGN1c3RvbWVySWRcclxuICA+ICAgICAgICAgIC8vIGJlY2F1c2UgdGhlIHNlcnZlciB3aWxsIGhhdmUgZ2VuZXJhdGVkIGEgbmV3IGlkXHJcbiAgPiAgICAgICAgICAvLyBhbmQgdGhlIGNsaWVudCB3aWxsIGhhdmUgYmVlbiB1cGRhdGVkIHdpdGggdGhpc1xyXG4gID4gICAgICAgICAgLy8gbmV3IGlkLlxyXG4gID4gICAgICB9KVxyXG4gIEBwYXJhbSBlbnRpdHkgLSBUaGUgRW50aXR5IHRvIGdlbmVyYXRlIGEga2V5IGZvci5cclxuICBAcmV0dXJuIFRoZSBuZXcga2V5IHZhbHVlXHJcbiAgKiovXHJcbiAgZ2VuZXJhdGVUZW1wS2V5VmFsdWUoZW50aXR5OiBFbnRpdHkpIHtcclxuICAgIC8vIFRPRE8gLSBjaGVjayBpZiB0aGlzIGVudGl0eSBpcyBhdHRhY2hlZCB0byB0aGlzIEVudGl0eU1hbmFnZXIuXHJcbiAgICBhc3NlcnRQYXJhbShlbnRpdHksIFwiZW50aXR5XCIpLmlzRW50aXR5KCkuY2hlY2soKTtcclxuICAgIGxldCBlbnRpdHlUeXBlID0gZW50aXR5LmVudGl0eVR5cGU7XHJcbiAgICBsZXQgbmV4dEtleVZhbHVlID0gdGhpcy5rZXlHZW5lcmF0b3IuZ2VuZXJhdGVUZW1wS2V5VmFsdWUoZW50aXR5VHlwZSk7XHJcbiAgICBsZXQga2V5UHJvcCA9IGVudGl0eVR5cGUua2V5UHJvcGVydGllc1swXTtcclxuICAgIGVudGl0eS5zZXRQcm9wZXJ0eShrZXlQcm9wLm5hbWUsIG5leHRLZXlWYWx1ZSk7XHJcbiAgICBlbnRpdHkuZW50aXR5QXNwZWN0Lmhhc1RlbXBLZXkgPSB0cnVlO1xyXG4gICAgcmV0dXJuIG5leHRLZXlWYWx1ZTtcclxuICB9XHJcblxyXG4gIGhhc0NoYW5nZXMoKTogYm9vbGVhbjtcclxuICBoYXNDaGFuZ2VzKGVudGl0eVR5cGVOYW1lczogc3RyaW5nIHwgc3RyaW5nW10pOiBib29sZWFuO1xyXG4gIGhhc0NoYW5nZXMoZW50aXR5VHlwZXM6IEVudGl0eVR5cGUgfCBFbnRpdHlUeXBlW10pOiBib29sZWFuO1xyXG4gIC8qKlxyXG4gIFJldHVybnMgd2hldGhlciB0aGVyZSBhcmUgYW55IGNoYW5nZWQgZW50aXRpZXMgb2YgdGhlIHNwZWNpZmllZCBbW0VudGl0eVR5cGVdXXMuIEEgJ2NoYW5nZWQnIEVudGl0eSBoYXNcclxuICBoYXMgYW4gW1tFbnRpdHlTdGF0ZV1dIG9mIGVpdGhlciBBZGRlZCwgTW9kaWZpZWQgb3IgRGVsZXRlZC5cclxuXHJcbiAgVGhpcyBtZXRob2QgY2FuIGJlIHVzZWQgdG8gZGV0ZXJtaW5lIGlmIGFuIEVudGl0eU1hbmFnZXIgaGFzIGFueSBjaGFuZ2VzXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIHByZWV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgICBpZiAoIGVtMS5oYXNDaGFuZ2VzKCkge1xyXG4gID4gICAgICAgICAgLy8gZG8gc29tZXRoaW5nIGludGVyZXN0aW5nXHJcbiAgPiAgICAgIH1cclxuXHJcbiAgb3IgaWYgaXQgaGFzIGFueSBjaGFuZ2VzIG9uIHRvIGEgc3BlY2lmaWMgW1tFbnRpdHlUeXBlXV0uXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIHByZWV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgICBsZXQgY3VzdFR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQ3VzdG9tZXJcIik7XHJcbiAgPiAgICAgIGlmICggZW0xLmhhc0NoYW5nZXMoY3VzdFR5cGUpIHtcclxuICA+ICAgICAgICAgIC8vIGRvIHNvbWV0aGluZyBpbnRlcmVzdGluZ1xyXG4gID4gICAgICB9XHJcblxyXG4gIG9yIHRvIGEgY29sbGVjdGlvbiBvZiBbW0VudGl0eVR5cGVdXXNcclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgcHJlZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgIGxldCBjdXN0VHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJDdXN0b21lclwiKTtcclxuICA+ICAgICAgbGV0IG9yZGVyVHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJPcmRlclwiKTtcclxuICA+ICAgICAgaWYgKCBlbTEuaGFzQ2hhbmdlcyggW2N1c3RUeXBlLCBvcmRlclR5cGVdKSB7XHJcbiAgPiAgICAgICAgICAvLyBkbyBzb21ldGhpbmcgaW50ZXJlc3RpbmdcclxuICA+ICAgICAgfVxyXG4gIEBwYXJhbSBlbnRpdHlUeXBlcyAtIFRoZSBbW0VudGl0eVR5cGVdXSBvciBFbnRpdHlUeXBlcyBmb3Igd2hpY2ggJ2NoYW5nZWQnIGVudGl0aWVzIHdpbGwgYmUgZm91bmQuXHJcbiAgQHBhcmFtIGVudGl0eVR5cGVOYW1lcyAtIFRoZSBbW0VudGl0eVR5cGVdXSBuYW1lIG9yIG5hbWVzIGZvciB3aGljaCAnY2hhbmdlZCcgZW50aXRpZXMgd2lsbCBiZSBmb3VuZC5cclxuICBAcmV0dXJuIFdoZXRoZXIgdGhlcmUgYXJlIGFueSBjaGFuZ2VkIGVudGl0aWVzIHRoYXQgbWF0Y2ggdGhlIHR5cGVzIHNwZWNpZmllZC4uXHJcbiAgKiovXHJcbiAgaGFzQ2hhbmdlcyhlbnRpdHlUeXBlcz86IEVudGl0eVR5cGUgfCBFbnRpdHlUeXBlW10gfCBzdHJpbmcgfCBzdHJpbmdbXSkge1xyXG4gICAgaWYgKCF0aGlzLl9oYXNDaGFuZ2VzKSByZXR1cm4gZmFsc2U7XHJcbiAgICBpZiAoZW50aXR5VHlwZXMgPT09IHVuZGVmaW5lZCkgcmV0dXJuIHRoaXMuX2hhc0NoYW5nZXM7XHJcbiAgICByZXR1cm4gdGhpcy5faGFzQ2hhbmdlc0NvcmUoZW50aXR5VHlwZXMpO1xyXG4gIH1cclxuXHJcblxyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIC8vIGJhY2tkb29yIHRvIFwicmVhbGx5XCIgY2hlY2sgZm9yIGNoYW5nZXMuXHJcbiAgX2hhc0NoYW5nZXNDb3JlKGVudGl0eVR5cGVzPzogRW50aXR5VHlwZSB8IEVudGl0eVR5cGVbXSB8IHN0cmluZyB8IHN0cmluZ1tdKSB7XHJcbiAgICBsZXQgZXRzID0gY2hlY2tFbnRpdHlUeXBlcyh0aGlzLCBlbnRpdHlUeXBlcyk7XHJcbiAgICBsZXQgZW50aXR5R3JvdXBzID0gZ2V0RW50aXR5R3JvdXBzKHRoaXMsIGV0cyk7XHJcbiAgICByZXR1cm4gZW50aXR5R3JvdXBzLnNvbWUoZnVuY3Rpb24gKGVnKSB7XHJcbiAgICAgIHJldHVybiBlZyAmJiBlZy5oYXNDaGFuZ2VzKCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIGdldENoYW5nZXMoKTogRW50aXR5W107XHJcbiAgZ2V0Q2hhbmdlcyhlbnRpdHlUeXBlTmFtZXM6IHN0cmluZyB8IHN0cmluZ1tdKTogRW50aXR5W107XHJcbiAgZ2V0Q2hhbmdlcyhlbnRpdHlUeXBlczogRW50aXR5VHlwZSB8IEVudGl0eVR5cGVbXSk6IEVudGl0eVtdO1xyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBhcnJheSBvZiBhbGwgY2hhbmdlZCBlbnRpdGllcyBvZiB0aGUgc3BlY2lmaWVkIFtbRW50aXR5VHlwZV1dcy4gQSAnY2hhbmdlZCcgRW50aXR5IGhhc1xyXG4gIGhhcyBhbiBbW0VudGl0eVN0YXRlXV0gb2YgZWl0aGVyIEFkZGVkLCBNb2RpZmllZCBvciBEZWxldGVkLlxyXG4gIFxyXG4gIFRoaXMgbWV0aG9kIGNhbiBiZSB1c2VkIHRvIGdldCBhbGwgb2YgdGhlIGNoYW5nZWQgZW50aXRpZXMgd2l0aGluIGFuIEVudGl0eU1hbmFnZXJcclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgcHJlZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgIGxldCBjaGFuZ2VkRW50aXRpZXMgPSBlbTEuZ2V0Q2hhbmdlcygpO1xyXG5cclxuICBvciB5b3UgY2FuIHNwZWNpZnkgdGhhdCB5b3Ugb25seSB3YW50IHRoZSBjaGFuZ2VzIG9uIGEgc3BlY2lmaWMgW1tFbnRpdHlUeXBlXV1cclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgcHJlZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgIGxldCBjdXN0VHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJDdXN0b21lclwiKTtcclxuICA+ICAgICAgbGV0IGNoYW5nZWRDdXN0b21lcnMgPSBlbTEuZ2V0Q2hhbmdlcyhjdXN0VHlwZSk7XHJcblxyXG4gIG9yIHRvIGEgY29sbGVjdGlvbiBvZiBbW0VudGl0eVR5cGVdXXNcclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgcHJlZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgIGxldCBjdXN0VHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJDdXN0b21lclwiKTtcclxuICA+ICAgICAgbGV0IG9yZGVyVHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJPcmRlclwiKTtcclxuICA+ICAgICAgbGV0IGNoYW5nZWRDdXN0b21lcnNBbmRPcmRlcnMgPSBlbTEuZ2V0Q2hhbmdlcyhbY3VzdFR5cGUsIG9yZGVyVHlwZV0pO1xyXG4gIEBwYXJhbSBlbnRpdHlUeXBlcyAtIFRoZSBbW0VudGl0eVR5cGVdXSBvciBFbnRpdHlUeXBlcyBmb3Igd2hpY2ggJ2NoYW5nZWQnIGVudGl0aWVzIHdpbGwgYmUgZm91bmQuXHJcbiAgQHBhcmFtIGVudGl0eVR5cGVOYW1lcyAtIFRoZSBbW0VudGl0eVR5cGVdXSBuYW1lIG9yIG5hbWVzIGZvciB3aGljaCAnY2hhbmdlZCcgZW50aXRpZXMgd2lsbCBiZSBmb3VuZC5cclxuICBAcmV0dXJuIEFuIGFycmF5IG9mIEVudGl0aWVzXHJcbiAgKiovXHJcbiAgZ2V0Q2hhbmdlcyhlbnRpdHlUeXBlcz86IEVudGl0eVR5cGUgfCBFbnRpdHlUeXBlW10gfCBzdHJpbmcgfCBzdHJpbmdbXSkge1xyXG4gICAgbGV0IGV0cyA9IGNoZWNrRW50aXR5VHlwZXModGhpcywgZW50aXR5VHlwZXMpO1xyXG4gICAgcmV0dXJuIGdldENoYW5nZXNDb3JlKHRoaXMsIGV0cyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBSZWplY3RzIChyZXZlcnNlcyB0aGUgZWZmZWN0cykgYWxsIG9mIHRoZSBhZGRpdGlvbnMsIG1vZGlmaWNhdGlvbnMgYW5kIGRlbGV0ZXMgZnJvbSB0aGlzIEVudGl0eU1hbmFnZXIuXHJcbiAgQ2FsbHMgW1tFbnRpdHlBc3BlY3QucmVqZWN0Q2hhbmdlc11dIG9uIGV2ZXJ5IGNoYW5nZWQgZW50aXR5IGluIHRoaXMgRW50aXR5TWFuYWdlci5cclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgcHJlZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgIGxldCBlbnRpdGllcyA9IGVtMS5yZWplY3RDaGFuZ2VzKCk7XHJcbiAgQHJldHVybiBUaGUgZW50aXRpZXMgd2hvc2UgY2hhbmdlcyB3ZXJlIHJlamVjdGVkLiBUaGVzZSBlbnRpdGllcyB3aWxsIGFsbCBoYXZlIEVudGl0eVN0YXRlcyBvZlxyXG4gIGVpdGhlciAnVW5jaGFuZ2VkJyBvciAnRGV0YWNoZWQnXHJcbiAgKiovXHJcbiAgcmVqZWN0Q2hhbmdlcygpIHtcclxuICAgIGlmICghdGhpcy5faGFzQ2hhbmdlcykgcmV0dXJuIFtdO1xyXG4gICAgbGV0IGNoYW5nZXMgPSBnZXRDaGFuZ2VzQ29yZSh0aGlzKTtcclxuICAgIC8vIG5leHQgbGluZSBzdG9wcyBpbmRpdmlkdWFsIHJlamVjdCBjaGFuZ2VzIGZyb20gZWFjaCBjYWxsaW5nIF9oYXNDaGFuZ2VzQ29yZVxyXG4gICAgbGV0IGFzcGVjdHMgPSBjaGFuZ2VzLm1hcChmdW5jdGlvbiAoZSkge1xyXG4gICAgICByZXR1cm4gZS5lbnRpdHlBc3BlY3QuX2NoZWNrT3BlcmF0aW9uKFwicmVqZWN0Q2hhbmdlc1wiKTtcclxuICAgIH0pO1xyXG4gICAgdGhpcy5faGFzQ2hhbmdlcyA9IGZhbHNlO1xyXG4gICAgYXNwZWN0cy5mb3JFYWNoKGZ1bmN0aW9uIChhc3BlY3QpIHtcclxuICAgICAgYXNwZWN0LnJlamVjdENoYW5nZXMoKTtcclxuICAgIH0pO1xyXG4gICAgdGhpcy5oYXNDaGFuZ2VzQ2hhbmdlZC5wdWJsaXNoKHsgZW50aXR5TWFuYWdlcjogdGhpcywgaGFzQ2hhbmdlczogZmFsc2UgfSk7XHJcbiAgICByZXR1cm4gY2hhbmdlcztcclxuICB9XHJcblxyXG4gIGdldEVudGl0aWVzKGVudGl0eVR5cGVOYW1lcz86IHN0cmluZyB8IHN0cmluZ1tdLCBlbnRpdHlTdGF0ZXM/OiBFbnRpdHlTdGF0ZSB8IEVudGl0eVN0YXRlW10pOiBFbnRpdHlbXTtcclxuICBnZXRFbnRpdGllcyhlbnRpdHlUeXBlcz86IEVudGl0eVR5cGUgfCBFbnRpdHlUeXBlW10sIGVudGl0eVN0YXRlcz86IEVudGl0eVN0YXRlIHwgRW50aXR5U3RhdGVbXSk6IEVudGl0eVtdO1xyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBhcnJheSBvZiBhbGwgZW50aXRpZXMgb2YgdGhlIHNwZWNpZmllZCBbW0VudGl0eVR5cGVdXXMgd2l0aCB0aGUgc3BlY2lmaWVkIFtbRW50aXR5U3RhdGVdXXMuXHJcblxyXG4gIFRoaXMgbWV0aG9kIGNhbiBiZSB1c2VkIHRvIGdldCBhbGwgb2YgdGhlIGVudGl0aWVzIHdpdGhpbiBhbiBFbnRpdHlNYW5hZ2VyXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIHByZWV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgICBsZXQgZW50aXRpZXMgPSBlbTEuZ2V0RW50aXRpZXMoKTtcclxuXHJcbiAgb3IgeW91IGNhbiBzcGVjaWZ5IHRoYXQgeW91IG9ubHkgd2FudCB0aGUgY2hhbmdlcyBvbiBhIHNwZWNpZmljIFtbRW50aXR5VHlwZV1dXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIHByZWV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgICBsZXQgY3VzdFR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQ3VzdG9tZXJcIik7XHJcbiAgPiAgICAgIGxldCBjdXN0b21lcnMgPSBlbTEuZ2V0RW50aXRpZXMoY3VzdFR5cGUpO1xyXG5cclxuICBvciB0byBhIGNvbGxlY3Rpb24gb2YgW1tFbnRpdHlUeXBlXV1zXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIHByZWV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgICBsZXQgY3VzdFR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQ3VzdG9tZXJcIik7XHJcbiAgPiAgICAgIGxldCBvcmRlclR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiT3JkZXJcIik7XHJcbiAgPiAgICAgIGxldCBjdXN0b21lcnNBbmRPcmRlcnMgPSBlbTEuZ2V0Q2hhbmdlcyhbY3VzdFR5cGUsIG9yZGVyVHlwZV0pO1xyXG5cclxuICBZb3UgY2FuIGFsc28gYXNrIGZvciBlbnRpdGllcyB3aXRoIGEgcGFydGljdWxhciBbW0VudGl0eVN0YXRlXV0gb3IgRW50aXR5U3RhdGVzLlxyXG4gID4gICAgICAvLyBhc3N1bWUgZW0xIGlzIGFuIEVudGl0eU1hbmFnZXIgY29udGFpbmluZyBhIG51bWJlciBvZiBwcmVleGlzdGluZyBlbnRpdGllcy5cclxuICA+ICAgICAgbGV0IGN1c3RUeXBlID0gZW0xLm1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZShcIkN1c3RvbWVyXCIpO1xyXG4gID4gICAgICBsZXQgb3JkZXJUeXBlID0gZW0xLm1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZShcIk9yZGVyXCIpO1xyXG4gID4gICAgICBsZXQgYWRkZWRDdXN0b21lcnNBbmRPcmRlcnMgPSBlbTEuZ2V0RW50aXRpZXMoW2N1c3RUeXBlLCBvcmRlclR5cGVdLCBFbnRpdHlTdGF0ZS5BZGRlZCk7XHJcbiBcclxuICBAcGFyYW0gZW50aXR5VHlwZU5hbWUgLSBUaGUgW1tFbnRpdHlUeXBlXV0gbmFtZSBvciBuYW1lcyBmb3Igd2hpY2ggZW50aXRpZXMgd2lsbCBiZSBmb3VuZC5cclxuICBJZiB0aGlzIHBhcmFtZXRlciBpcyBvbWl0dGVkLCBhbGwgRW50aXR5VHlwZXMgYXJlIHNlYXJjaGVkLiAgXHJcbiAgQHBhcmFtIGVudGl0eVR5cGVzIC0gVGhlIFtbRW50aXR5VHlwZV1dIG9yIEVudGl0eVR5cGVzIGZvciB3aGljaCBlbnRpdGllcyB3aWxsIGJlIGZvdW5kLlxyXG4gIElmIHRoaXMgcGFyYW1ldGVyIGlzIG9taXR0ZWQsIGFsbCBFbnRpdHlUeXBlcyBhcmUgc2VhcmNoZWQuIFxyXG4gIEBwYXJhbSBlbnRpdHlTdGF0ZXMgLSBUaGUgW1tFbnRpdHlTdGF0ZV1dcyBmb3Igd2hpY2ggZW50aXRpZXMgd2lsbCBiZSBmb3VuZC5cclxuICBJZiB0aGlzIHBhcmFtZXRlciBpcyBvbWl0dGVkLCBlbnRpdGllcyBvZiBhbGwgRW50aXR5U3RhdGVzIGFyZSByZXR1cm5lZC5cclxuICBAcmV0dXJuIEFuIGFycmF5IG9mIEVudGl0aWVzXHJcbiAgKiovXHJcbiAgZ2V0RW50aXRpZXMoZW50aXR5VHlwZXM/OiBFbnRpdHlUeXBlIHwgRW50aXR5VHlwZVtdIHwgc3RyaW5nIHwgc3RyaW5nW10sIGVudGl0eVN0YXRlcz86IEVudGl0eVN0YXRlIHwgRW50aXR5U3RhdGVbXSkge1xyXG4gICAgbGV0IGVudFR5cGVzID0gY2hlY2tFbnRpdHlUeXBlcyh0aGlzLCBlbnRpdHlUeXBlcyk7XHJcbiAgICBhc3NlcnRQYXJhbShlbnRpdHlTdGF0ZXMsIFwiZW50aXR5U3RhdGVzXCIpLmlzT3B0aW9uYWwoKS5pc0VudW1PZihFbnRpdHlTdGF0ZSkub3IoKS5pc05vbkVtcHR5QXJyYXkoKS5pc0VudW1PZihFbnRpdHlTdGF0ZSkuY2hlY2soKTtcclxuXHJcbiAgICBsZXQgc3RhdGVzID0gdmFsaWRhdGVFbnRpdHlTdGF0ZXModGhpcywgZW50aXR5U3RhdGVzKTtcclxuICAgIHJldHVybiBnZXRFbnRpdGllc0NvcmUodGhpcywgZW50VHlwZXMsIHN0YXRlcyk7XHJcbiAgfVxyXG5cclxuXHJcbiAgLy8gcHJvdGVjdGVkIG1ldGhvZHNcclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfbm90aWZ5U3RhdGVDaGFuZ2UoZW50aXR5OiBFbnRpdHksIG5lZWRzU2F2ZTogYm9vbGVhbikge1xyXG4gICAgbGV0IGVjQXJncyA9IHsgZW50aXR5QWN0aW9uOiBFbnRpdHlBY3Rpb24uRW50aXR5U3RhdGVDaGFuZ2UsIGVudGl0eTogZW50aXR5IH07XHJcblxyXG4gICAgaWYgKG5lZWRzU2F2ZSkge1xyXG4gICAgICBpZiAoIXRoaXMuX2hhc0NoYW5nZXMpIHRoaXMuX3NldEhhc0NoYW5nZXModHJ1ZSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBjYWxsZWQgd2hlbiByZWplY3RpbmcgYSBjaGFuZ2Ugb3IgbWVyZ2luZyBhbiB1bmNoYW5nZWQgcmVjb3JkLlxyXG4gICAgICAvLyBOT1RFOiB0aGlzIGNhbiBiZSBzbG93IHdpdGggbG90cyBvZiBlbnRpdGllcyBpbiB0aGUgY2FjaGUuXHJcbiAgICAgIC8vIHNvIGRlZmVyIGl0IGR1cmluZyBhIHF1ZXJ5L2ltcG9ydCBvciBzYXZlIGFuZCBjYWxsIGl0IG9uY2Ugd2hlbiBjb21wbGV0ZSAoIGlmIG5lZWRlZCkuXHJcbiAgICAgIGlmICh0aGlzLl9oYXNDaGFuZ2VzKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuaXNMb2FkaW5nKSB7XHJcbiAgICAgICAgICB0aGlzLl9oYXNDaGFuZ2VzQWN0aW9uID0gdGhpcy5faGFzQ2hhbmdlc0FjdGlvbiB8fCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIHRoaXMuX3NldEhhc0NoYW5nZXMobnVsbCk7XHJcbiAgICAgICAgICAgIHRoaXMuZW50aXR5Q2hhbmdlZC5wdWJsaXNoKGVjQXJncyk7XHJcbiAgICAgICAgICB9LmJpbmQodGhpcyk7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRoaXMuX3NldEhhc0NoYW5nZXMoKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHRoaXMuZW50aXR5Q2hhbmdlZC5wdWJsaXNoKGVjQXJncyk7XHJcbiAgfVxyXG5cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfc2V0SGFzQ2hhbmdlcyhoYXNDaGFuZ2VzPzogYm9vbGVhbikge1xyXG4gICAgaWYgKGhhc0NoYW5nZXMgPT0gbnVsbCkgaGFzQ2hhbmdlcyA9IHRoaXMuX2hhc0NoYW5nZXNDb3JlKCk7XHJcbiAgICBsZXQgaGFkQ2hhbmdlcyA9IHRoaXMuX2hhc0NoYW5nZXM7XHJcbiAgICB0aGlzLl9oYXNDaGFuZ2VzID0gaGFzQ2hhbmdlcztcclxuICAgIGlmIChoYXNDaGFuZ2VzICE9PSBoYWRDaGFuZ2VzKSB7XHJcbiAgICAgIHRoaXMuaGFzQ2hhbmdlc0NoYW5nZWQucHVibGlzaCh7IGVudGl0eU1hbmFnZXI6IHRoaXMsIGhhc0NoYW5nZXM6IGhhc0NoYW5nZXMgfSk7XHJcbiAgICB9XHJcbiAgICB0aGlzLl9oYXNDaGFuZ2VzQWN0aW9uID0gdW5kZWZpbmVkO1xyXG4gIH1cclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2xpbmtSZWxhdGVkRW50aXRpZXMoZW50aXR5OiBFbnRpdHkpIHtcclxuICAgIGxldCBlbSA9IHRoaXM7XHJcbiAgICBsZXQgZW50aXR5QXNwZWN0ID0gZW50aXR5LmVudGl0eUFzcGVjdDtcclxuICAgIC8vIHdlIGRvIG5vdCB3YW50IGVudGl0eVN0YXRlIHRvIGNoYW5nZSBhcyBhIHJlc3VsdCBvZiBsaW5rYWdlLlxyXG4gICAgY29yZS51c2luZyhlbSwgXCJpc0xvYWRpbmdcIiwgdHJ1ZSwgZnVuY3Rpb24gKCkge1xyXG5cclxuICAgICAgbGV0IHVuYXR0YWNoZWRNYXAgPSBlbS5fdW5hdHRhY2hlZENoaWxkcmVuTWFwO1xyXG4gICAgICBsZXQgZW50aXR5S2V5ID0gZW50aXR5QXNwZWN0LmdldEtleSgpO1xyXG4gICAgICBsZXQgZW50aXR5VHlwZSA9IGVudGl0eUtleS5lbnRpdHlUeXBlO1xyXG5cclxuICAgICAgd2hpbGUgKGVudGl0eVR5cGUpIHtcclxuICAgICAgICBsZXQga2V5c3RyaW5nID0gZW50aXR5S2V5LnRvU3RyaW5nKGVudGl0eVR5cGUpO1xyXG5cclxuICAgICAgICAvLyBhdHRhY2ggYW55IHVuYXR0YWNoZWRDaGlsZHJlblxyXG4gICAgICAgIGxldCB0dXBsZXMgPSB1bmF0dGFjaGVkTWFwLmdldFR1cGxlc0J5U3RyaW5nKGtleXN0cmluZyk7XHJcbiAgICAgICAgaWYgKHR1cGxlcykge1xyXG4gICAgICAgICAgdHVwbGVzLnNsaWNlKDApLmZvckVhY2goZnVuY3Rpb24gKHRwbCkge1xyXG5cclxuICAgICAgICAgICAgbGV0IHVuYXR0YWNoZWRDaGlsZHJlbiA9IHRwbC5jaGlsZHJlbi5maWx0ZXIoZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgICAgICByZXR1cm4gZS5lbnRpdHlBc3BlY3QuZW50aXR5U3RhdGUgIT09IEVudGl0eVN0YXRlLkRldGFjaGVkO1xyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICAgIGxldCBjaGlsZFRvUGFyZW50TnA6IE5hdmlnYXRpb25Qcm9wZXJ0eTtcclxuICAgICAgICAgICAgbGV0IHBhcmVudFRvQ2hpbGROcDogTmF2aWdhdGlvblByb3BlcnR5O1xyXG5cclxuICAgICAgICAgICAgLy8gbnAgaXMgdXN1YWxseSBjaGlsZFRvUGFyZW50TnBcclxuICAgICAgICAgICAgLy8gZXhjZXB0IHdpdGggdW5pZGlyZWN0aW9uYWwgMS1uIHdoZXJlIGl0IGlzIHBhcmVudFRvQ2hpbGROcDtcclxuICAgICAgICAgICAgbGV0IG5wID0gdHBsLm5hdmlnYXRpb25Qcm9wZXJ0eTtcclxuXHJcbiAgICAgICAgICAgIGxldCBpbnZlcnNlTnAgPSBucC5pbnZlcnNlO1xyXG4gICAgICAgICAgICBpZiAoaW52ZXJzZU5wKSB7XHJcbiAgICAgICAgICAgICAgLy8gYmlkaXJlY3Rpb25hbFxyXG4gICAgICAgICAgICAgIGNoaWxkVG9QYXJlbnROcCA9IG5wO1xyXG4gICAgICAgICAgICAgIHBhcmVudFRvQ2hpbGROcCA9IGludmVyc2VOcDtcclxuXHJcbiAgICAgICAgICAgICAgaWYgKHBhcmVudFRvQ2hpbGROcC5pc1NjYWxhcikge1xyXG4gICAgICAgICAgICAgICAgbGV0IG9ubHlDaGlsZCA9IHVuYXR0YWNoZWRDaGlsZHJlblswXTtcclxuICAgICAgICAgICAgICAgIGVudGl0eS5zZXRQcm9wZXJ0eShwYXJlbnRUb0NoaWxkTnAubmFtZSwgb25seUNoaWxkKTtcclxuICAgICAgICAgICAgICAgIG9ubHlDaGlsZC5zZXRQcm9wZXJ0eShjaGlsZFRvUGFyZW50TnAubmFtZSwgZW50aXR5KTtcclxuICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgbGV0IGN1cnJlbnRDaGlsZHJlbiA9IGVudGl0eS5nZXRQcm9wZXJ0eShwYXJlbnRUb0NoaWxkTnAubmFtZSk7XHJcbiAgICAgICAgICAgICAgICB1bmF0dGFjaGVkQ2hpbGRyZW4uZm9yRWFjaChmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgICAgICAgY3VycmVudENoaWxkcmVuLnB1c2goY2hpbGQpO1xyXG4gICAgICAgICAgICAgICAgICBjaGlsZC5zZXRQcm9wZXJ0eShjaGlsZFRvUGFyZW50TnAubmFtZSwgZW50aXR5KTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB1bmF0dGFjaGVkTWFwLnJlbW92ZUNoaWxkcmVuKGtleXN0cmluZywgY2hpbGRUb1BhcmVudE5wKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAvLyB1bmlkaXJlY3Rpb25hbFxyXG4gICAgICAgICAgICAgIC8vIGlmIChucC5pc1NjYWxhciB8fCBucC5wYXJlbnRUeXBlICE9PSBlbnRpdHkuZW50aXR5VHlwZSkge1xyXG4gICAgICAgICAgICAgIGlmIChucC5pc1NjYWxhcikge1xyXG4gICAgICAgICAgICAgICAgLy8gbiAtPiAxICBlZzogY2hpbGQ6IE9yZGVyRGV0YWlsIHBhcmVudDogUHJvZHVjdFxyXG4gICAgICAgICAgICAgICAgLy8gMSAtPiAxIGVnIGNoaWxkOiBFbXBsb3llZSBwYXJlbnQ6IEVtcGxveWVlICggb25seSBNYW5hZ2VyLCBubyBEaXJlY3RSZXBvcnRzIHByb3BlcnR5KVxyXG4gICAgICAgICAgICAgICAgY2hpbGRUb1BhcmVudE5wID0gbnA7XHJcbiAgICAgICAgICAgICAgICB1bmF0dGFjaGVkQ2hpbGRyZW4uZm9yRWFjaChmdW5jdGlvbiAoY2hpbGQpIHtcclxuICAgICAgICAgICAgICAgICAgY2hpbGQuc2V0UHJvcGVydHkoY2hpbGRUb1BhcmVudE5wLm5hbWUsIGVudGl0eSk7XHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgIHVuYXR0YWNoZWRNYXAucmVtb3ZlQ2hpbGRyZW4oa2V5c3RyaW5nLCBjaGlsZFRvUGFyZW50TnApO1xyXG4gICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyAxIC0+IG4gIGVnOiBwYXJlbnQ6IFJlZ2lvbiBjaGlsZDogVGVyclxyXG4gICAgICAgICAgICAgICAgLy8gVE9ETzogbmVlZCB0byByZW1vdmUgdW5hdHRhY2hlZCBjaGlsZHJlbiBmcm9tIHRoZSBtYXAgYWZ0ZXIgdGhpczsgb25seSBhIHBlcmYgaXNzdWUuXHJcbiAgICAgICAgICAgICAgICBwYXJlbnRUb0NoaWxkTnAgPSBucDtcclxuICAgICAgICAgICAgICAgIGxldCBjdXJyZW50Q2hpbGRyZW4gPSBlbnRpdHkuZ2V0UHJvcGVydHkocGFyZW50VG9DaGlsZE5wLm5hbWUpO1xyXG4gICAgICAgICAgICAgICAgdW5hdHRhY2hlZENoaWxkcmVuLmZvckVhY2goZnVuY3Rpb24gKGNoaWxkKSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIHdlIGtub3cgaWYgY2FuJ3QgYWxyZWFkeSBiZSB0aGVyZS5cclxuICAgICAgICAgICAgICAgICAgY3VycmVudENoaWxkcmVuLl9wdXNoKGNoaWxkKTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVudGl0eVR5cGUgPSBlbnRpdHlUeXBlLmJhc2VFbnRpdHlUeXBlOyAvLyBsb29rIGZvciByZWxhdGlvbnNoaXBzIHVwIHRoZSBoaWVyYXJjaHlcclxuICAgICAgfVxyXG5cclxuXHJcbiAgICAgIC8vIG5vdyBhZGQgdG8gdW5hdHRhY2hlZE1hcCBpZiBuZWVkZWQuXHJcbiAgICAgIGVudGl0eS5lbnRpdHlUeXBlLm5hdmlnYXRpb25Qcm9wZXJ0aWVzLmZvckVhY2goZnVuY3Rpb24gKG5wKSB7XHJcbiAgICAgICAgaWYgKG5wLmlzU2NhbGFyKSB7XHJcbiAgICAgICAgICBsZXQgdmFsdWUgPSBlbnRpdHkuZ2V0UHJvcGVydHkobnAubmFtZSk7XHJcbiAgICAgICAgICAvLyBwcm9wZXJ0eSBpcyBhbHJlYWR5IGxpbmtlZCB1cFxyXG4gICAgICAgICAgaWYgKHZhbHVlKSByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBmaXJzdCBkZXRlcm1pbmUgaWYgbnAgY29udGFpbnMgYSBwYXJlbnQgb3IgY2hpbGRcclxuICAgICAgICAvLyBoYXZpbmcgYSBwYXJlbnRLZXkgbWVhbnMgdGhhdCB0aGlzIGlzIGEgY2hpbGRcclxuICAgICAgICAvLyBpZiBhIHBhcmVudCB0aGVuIG5vIG5lZWQgZm9yIG1vcmUgd29yayBiZWNhdXNlIGNoaWxkcmVuIHdpbGwgYXR0YWNoIHRvIGl0LlxyXG4gICAgICAgIGxldCBwYXJlbnRLZXkgPSBlbnRpdHlBc3BlY3QuZ2V0UGFyZW50S2V5KG5wKTtcclxuICAgICAgICBpZiAocGFyZW50S2V5KSB7XHJcbiAgICAgICAgICAvLyBjaGVjayBmb3IgZW1wdHkga2V5cyAtIG1lYW5pbmcgdGhhdCBwYXJlbnQgaWQncyBhcmUgbm90IHlldCBzZXQuXHJcbiAgICAgICAgICBpZiAocGFyZW50S2V5Ll9pc0VtcHR5KCkpIHJldHVybjtcclxuICAgICAgICAgIC8vIGlmIGEgY2hpbGQgLSBsb29rIGZvciBwYXJlbnQgaW4gdGhlIGVtIGNhY2hlXHJcbiAgICAgICAgICBpZiAobnAuaW52Rm9yZWlnbktleU5hbWVzLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAvLyBucCByZWxhdGVzIHRvIG5vbi1QSyBwcm9wZXJ0eSBvZiBwYXJlbnQgZW50aXR5XHJcbiAgICAgICAgICAgIGNvbnN0IHF1ZXJ5ID0gbmV3IEVudGl0eVF1ZXJ5KHBhcmVudEtleS5lbnRpdHlUeXBlLmRlZmF1bHRSZXNvdXJjZU5hbWUpLndoZXJlKG5wLmludkZvcmVpZ25LZXlOYW1lc1swXSwgJ2VxJywgcGFyZW50S2V5LnZhbHVlc1swXSk7XHJcbiAgICAgICAgICAgIGNvbnN0IHFyZXN1bHQgPSBlbS5leGVjdXRlUXVlcnlMb2NhbGx5KHF1ZXJ5KTtcclxuICAgICAgICAgICAgaWYgKHFyZXN1bHQubGVuZ3RoID09PSAxKSB7XHJcbiAgICAgICAgICAgICAgbGV0IHBhcmVudCA9IHFyZXN1bHRbMF07XHJcbiAgICAgICAgICAgICAgZW50aXR5LnNldFByb3BlcnR5KG5wLm5hbWUsIHBhcmVudCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIG5wIHJlbGF0ZXMgdG8gUEsgb2YgcGFyZW50IGVudGl0eVxyXG4gICAgICAgICAgICBsZXQgcGFyZW50ID0gZW0uZ2V0RW50aXR5QnlLZXkocGFyZW50S2V5KTtcclxuICAgICAgICAgICAgaWYgKHBhcmVudCkge1xyXG4gICAgICAgICAgICAgIC8vIGlmIGZvdW5kIGhvb2sgaXQgdXBcclxuICAgICAgICAgICAgICBlbnRpdHkuc2V0UHJvcGVydHkobnAubmFtZSwgcGFyZW50KTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAvLyBlbHNlIGFkZCBwYXJlbnQgdG8gdW5yZXNvbHZlZFBhcmVudE1hcDtcclxuICAgICAgICAgICAgICB1bmF0dGFjaGVkTWFwLmFkZENoaWxkKHBhcmVudEtleSwgbnAsIGVudGl0eSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2UgaWYgKG5wLmludmVyc2UgJiYgbnAuaW52ZXJzZS5pbnZGb3JlaWduS2V5TmFtZXMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBucCByZWxhdGVzIHRvIG5vbi1QSyBwcm9wZXJ0eSBvZiBwYXJlbnQgZW50aXR5OyBxdWVyeSBlbnRpdGllcyBieSBGS1xyXG4gICAgICAgICAgY29uc3QgYWtWYWx1ZSA9IGVudGl0eS5nZXRQcm9wZXJ0eShucC5pbnZlcnNlLmludkZvcmVpZ25LZXlOYW1lc1swXSk7XHJcbiAgICAgICAgICBjb25zdCBxdWVyeSA9IG5ldyBFbnRpdHlRdWVyeShucC5lbnRpdHlUeXBlLmRlZmF1bHRSZXNvdXJjZU5hbWUpLndoZXJlKG5wLmludkZvcmVpZ25LZXlOYW1lc1swXSwgJ2VxJywgYWtWYWx1ZSk7XHJcbiAgICAgICAgICBjb25zdCBxcmVzdWx0ID0gZW0uZXhlY3V0ZVF1ZXJ5TG9jYWxseShxdWVyeSk7XHJcbiAgICAgICAgICBxcmVzdWx0LmZvckVhY2goKGNoaWxkOiBFbnRpdHkpID0+IHtcclxuICAgICAgICAgICAgY2hpbGQuc2V0UHJvcGVydHkobnAuaW52ZXJzZS5uYW1lLCBlbnRpdHkpO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIGhhbmRsZSB1bmlkaXJlY3Rpb25hbCAxLXggd2hlcmUgd2Ugc2V0IHguZmtcclxuICAgICAgZW50aXR5LmVudGl0eVR5cGUuZm9yZWlnbktleVByb3BlcnRpZXMuZm9yRWFjaChmdW5jdGlvbiAoZmtQcm9wKSB7XHJcbiAgICAgICAgbGV0IGludk5wID0gZmtQcm9wLmludmVyc2VOYXZpZ2F0aW9uUHJvcGVydHk7XHJcbiAgICAgICAgaWYgKCFpbnZOcCkgcmV0dXJuO1xyXG4gICAgICAgIC8vIHVuaWRpcmVjdGlvbmFsIGZrIHByb3BzIG9ubHlcclxuICAgICAgICBsZXQgZmtWYWx1ZSA9IGVudGl0eS5nZXRQcm9wZXJ0eShma1Byb3AubmFtZSk7XHJcbiAgICAgICAgbGV0IHBhcmVudEtleSA9IG5ldyBFbnRpdHlLZXkoaW52TnAucGFyZW50VHlwZSwgW2ZrVmFsdWVdKTtcclxuICAgICAgICBsZXQgcGFyZW50ID0gZW0uZ2V0RW50aXR5QnlLZXkocGFyZW50S2V5KTtcclxuXHJcbiAgICAgICAgaWYgKHBhcmVudCkge1xyXG4gICAgICAgICAgaWYgKGludk5wLmlzU2NhbGFyKSB7XHJcbiAgICAgICAgICAgIHBhcmVudC5zZXRQcm9wZXJ0eShpbnZOcC5uYW1lLCBlbnRpdHkpO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgaWYgKGVtLmlzTG9hZGluZykge1xyXG4gICAgICAgICAgICAgIHBhcmVudC5nZXRQcm9wZXJ0eShpbnZOcC5uYW1lKS5fcHVzaChlbnRpdHkpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIHBhcmVudC5nZXRQcm9wZXJ0eShpbnZOcC5uYW1lKS5wdXNoKGVudGl0eSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gZWxzZSBhZGQgcGFyZW50IHRvIHVucmVzb2x2ZWRQYXJlbnRNYXA7XHJcbiAgICAgICAgICB1bmF0dGFjaGVkTWFwLmFkZENoaWxkKHBhcmVudEtleSwgaW52TnAsIGVudGl0eSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH0pO1xyXG5cclxuICB9XHJcblxyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF9hdHRhY2hFbnRpdHlDb3JlKGVudGl0eTogRW50aXR5LCBlbnRpdHlTdGF0ZTogRW50aXR5U3RhdGUsIG1lcmdlU3RyYXRlZ3k6IE1lcmdlU3RyYXRlZ3kpIHtcclxuICAgIGxldCBncm91cCA9IGZpbmRPckNyZWF0ZUVudGl0eUdyb3VwKHRoaXMsIGVudGl0eS5lbnRpdHlUeXBlKTtcclxuICAgIGxldCBhdHRhY2hlZEVudGl0eSA9IGdyb3VwLmF0dGFjaEVudGl0eShlbnRpdHksIGVudGl0eVN0YXRlLCBtZXJnZVN0cmF0ZWd5KTtcclxuICAgIHRoaXMuX2xpbmtSZWxhdGVkRW50aXRpZXMoYXR0YWNoZWRFbnRpdHkpO1xyXG4gICAgcmV0dXJuIGF0dGFjaGVkRW50aXR5O1xyXG4gIH1cclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX3VwZGF0ZUZrVmFsKGZrUHJvcDogRGF0YVByb3BlcnR5LCBvbGRWYWx1ZTogYW55LCBuZXdWYWx1ZTogYW55KSB7XHJcbiAgICBsZXQgZ3JvdXAgPSB0aGlzLl9lbnRpdHlHcm91cE1hcFtma1Byb3AucGFyZW50VHlwZS5uYW1lXTtcclxuICAgIGlmICghZ3JvdXApIHJldHVybjtcclxuICAgIGdyb3VwLl91cGRhdGVGa1ZhbChma1Byb3AsIG9sZFZhbHVlLCBuZXdWYWx1ZSk7XHJcbiAgfVxyXG59XHJcblxyXG5FbnRpdHlNYW5hZ2VyLnByb3RvdHlwZS5fJHR5cGVOYW1lID0gXCJFbnRpdHlNYW5hZ2VyXCI7XHJcblxyXG5CcmVlemVFdmVudC5idWJibGVFdmVudChFbnRpdHlNYW5hZ2VyLnByb3RvdHlwZSk7XHJcblxyXG5mdW5jdGlvbiBjbGVhclNlcnZlckVycm9ycyhlbnRpdGllczogRW50aXR5W10pIHtcclxuICBlbnRpdGllcy5mb3JFYWNoKGZ1bmN0aW9uIChlbnRpdHkpIHtcclxuICAgIGxldCBzZXJ2ZXJLZXlzOiBzdHJpbmdbXSA9IFtdO1xyXG4gICAgbGV0IGFzcGVjdCA9IGVudGl0eS5lbnRpdHlBc3BlY3Q7XHJcbiAgICBjb3JlLm9iamVjdEZvckVhY2goYXNwZWN0Ll92YWxpZGF0aW9uRXJyb3JzLCBmdW5jdGlvbiAoa2V5LCB2ZSkge1xyXG4gICAgICBpZiAodmUuaXNTZXJ2ZXJFcnJvcikgc2VydmVyS2V5cy5wdXNoKGtleSk7XHJcbiAgICB9KTtcclxuICAgIGlmIChzZXJ2ZXJLZXlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xyXG4gICAgYXNwZWN0Ll9wcm9jZXNzVmFsaWRhdGlvbk9wQW5kUHVibGlzaChmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHNlcnZlcktleXMuZm9yRWFjaChmdW5jdGlvbiAoa2V5KSB7XHJcbiAgICAgICAgYXNwZWN0Ll9yZW1vdmVWYWxpZGF0aW9uRXJyb3Ioa2V5KTtcclxuICAgICAgfSk7XHJcbiAgICB9KTtcclxuICB9KTtcclxufVxyXG5cclxuZnVuY3Rpb24gY3JlYXRlRW50aXR5RXJyb3JzKGVudGl0aWVzOiBFbnRpdHlbXSkge1xyXG4gIGxldCBlbnRpdHlFcnJvcnM6IEVudGl0eUVycm9yW10gPSBbXTtcclxuICBlbnRpdGllcy5mb3JFYWNoKChlbnRpdHkpID0+IHtcclxuICAgIGNvcmUub2JqZWN0Rm9yRWFjaChlbnRpdHkuZW50aXR5QXNwZWN0Ll92YWxpZGF0aW9uRXJyb3JzLCBmdW5jdGlvbiAoa2V5LCB2ZSkge1xyXG4gICAgICBsZXQgY2ZnID0gY29yZS5leHRlbmQoe1xyXG4gICAgICAgIGVudGl0eTogZW50aXR5LFxyXG4gICAgICAgIGVycm9yTmFtZTogdmUudmFsaWRhdG9yLm5hbWVcclxuICAgICAgfSwgdmUsIFtcImVycm9yTWVzc2FnZVwiLCBcInByb3BlcnR5TmFtZVwiLCBcImlzU2VydmVyRXJyb3JcIiwgXCJjdXN0b21cIl0pIGFzIEVudGl0eUVycm9yO1xyXG4gICAgICBlbnRpdHlFcnJvcnMucHVzaChjZmcpO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbiAgcmV0dXJuIGVudGl0eUVycm9ycztcclxufVxyXG5cclxuXHJcbmZ1bmN0aW9uIHByb2Nlc3NTZXJ2ZXJFcnJvcnMoc2F2ZUNvbnRleHQ6IFNhdmVDb250ZXh0LCBzYXZlRXJyb3I6IFNhdmVFcnJvckZyb21TZXJ2ZXIpIHtcclxuICAvLyBjb252ZXJ0aW5nIElTYXZlRXJyb3JGcm9tU2VydmVyIC0+IElTYXZlRXJyb3JcclxuICBsZXQgc2VydmVyRXJyb3JzID0gc2F2ZUVycm9yLmVudGl0eUVycm9ycztcclxuICBpZiAoIXNlcnZlckVycm9ycykgcmV0dXJuIDxTYXZlRXJyb3I+IDxhbnk+IHNhdmVFcnJvcjtcclxuICBsZXQgZW50aXR5TWFuYWdlciA9IHNhdmVDb250ZXh0LmVudGl0eU1hbmFnZXI7XHJcbiAgbGV0IG1ldGFkYXRhU3RvcmUgPSBlbnRpdHlNYW5hZ2VyLm1ldGFkYXRhU3RvcmU7XHJcbiAgbGV0IGVudGl0eUVycm9ycyA9IHNlcnZlckVycm9ycy5tYXAoKHNlcnIpID0+IHtcclxuICAgIGxldCBlbnRpdHk6IEVudGl0eSB8IG51bGwgPSBudWxsO1xyXG4gICAgbGV0IGVudGl0eVR5cGU6IEVudGl0eVR5cGUgfCB1bmRlZmluZWQ7XHJcbiAgICBpZiAoc2Vyci5rZXlWYWx1ZXMpIHtcclxuICAgICAgZW50aXR5VHlwZSA9IG1ldGFkYXRhU3RvcmUuX2dldFN0cnVjdHVyYWxUeXBlKHNlcnIuZW50aXR5VHlwZU5hbWUpIGFzIEVudGl0eVR5cGU7XHJcbiAgICAgIGxldCBla2V5ID0gbmV3IEVudGl0eUtleShlbnRpdHlUeXBlLCBzZXJyLmtleVZhbHVlcyk7XHJcbiAgICAgIGVudGl0eSA9IGVudGl0eU1hbmFnZXIuZ2V0RW50aXR5QnlLZXkoZWtleSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGVudGl0eVR5cGUgJiYgZW50aXR5KSB7XHJcbiAgICAgIGxldCBjb250ZXh0ID0gc2Vyci5wcm9wZXJ0eU5hbWUgP1xyXG4gICAgICAgIHtcclxuICAgICAgICAgIHByb3BlcnR5TmFtZTogc2Vyci5wcm9wZXJ0eU5hbWUsXHJcbiAgICAgICAgICBwcm9wZXJ0eTogZW50aXR5VHlwZS5nZXRQcm9wZXJ0eShzZXJyLnByb3BlcnR5TmFtZSlcclxuICAgICAgICB9IDoge1xyXG4gICAgICAgIH07XHJcbiAgICAgIGxldCBrZXkgPSBWYWxpZGF0aW9uRXJyb3IuZ2V0S2V5KHNlcnIuZXJyb3JOYW1lIHx8IHNlcnIuZXJyb3JNZXNzYWdlLCBzZXJyLnByb3BlcnR5TmFtZSk7XHJcblxyXG4gICAgICBsZXQgdmUgPSBuZXcgVmFsaWRhdGlvbkVycm9yKG51bGwsIGNvbnRleHQsIHNlcnIuZXJyb3JNZXNzYWdlLCBrZXkpO1xyXG4gICAgICB2ZS5pc1NlcnZlckVycm9yID0gdHJ1ZTtcclxuICAgICAgZW50aXR5LmVudGl0eUFzcGVjdC5hZGRWYWxpZGF0aW9uRXJyb3IodmUpO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBlbnRpdHlFcnJvciA9IGNvcmUuZXh0ZW5kKHtcclxuICAgICAgZW50aXR5OiBlbnRpdHksXHJcbiAgICAgIGlzU2VydmVyRXJyb3I6IHRydWVcclxuICAgIH0sIHNlcnIsIFtcImVycm9yTmFtZVwiLCBcImVycm9yTWVzc2FnZVwiLCBcInByb3BlcnR5TmFtZVwiLCBcImN1c3RvbVwiXSkgYXMgRW50aXR5RXJyb3I7XHJcbiAgICByZXR1cm4gZW50aXR5RXJyb3I7XHJcbiAgfSk7XHJcbiAgLy8gY29udmVydGluZyBJU2F2ZUVycm9yRnJvbVNlcnZlciAtPiBJU2F2ZUVycm9yIFxyXG4gIHNhdmVFcnJvci5lbnRpdHlFcnJvcnMgPSBlbnRpdHlFcnJvcnMgYXMgYW55O1xyXG4gIHJldHVybiA8U2F2ZUVycm9yPiA8YW55PiBzYXZlRXJyb3I7XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgSUVudGl0eUJ5S2V5UmVzdWx0IHtcclxuICBlbnRpdHk/OiBFbnRpdHk7XHJcbiAgZW50aXR5S2V5OiBFbnRpdHlLZXk7XHJcbiAgZnJvbUNhY2hlOiBib29sZWFuO1xyXG59XHJcblxyXG5mdW5jdGlvbiBmZXRjaEVudGl0eUJ5S2V5Q29yZShlbTogRW50aXR5TWFuYWdlciwgYXJnczogYW55W10pOiBQcm9taXNlPElFbnRpdHlCeUtleVJlc3VsdD4ge1xyXG4gIGxldCB0cGwgPSBjcmVhdGVFbnRpdHlLZXkoZW0sIGFyZ3MpO1xyXG4gIGxldCBlbnRpdHlLZXkgPSB0cGwuZW50aXR5S2V5O1xyXG5cclxuICBsZXQgY2hlY2tMb2NhbENhY2hlRmlyc3QgPSB0cGwucmVtYWluaW5nQXJncy5sZW5ndGggPT09IDAgPyBmYWxzZSA6ICEhdHBsLnJlbWFpbmluZ0FyZ3NbMF07XHJcbiAgbGV0IGVudGl0eTogRW50aXR5IHwgbnVsbCA9IG51bGw7XHJcbiAgbGV0IGZvdW5kSXQgPSBmYWxzZTtcclxuICBpZiAoY2hlY2tMb2NhbENhY2hlRmlyc3QpIHtcclxuICAgIGVudGl0eSA9IGVtLmdldEVudGl0eUJ5S2V5KGVudGl0eUtleSk7XHJcbiAgICBmb3VuZEl0ID0gZW50aXR5ICE9IG51bGw7XHJcbiAgICBpZiAoZW50aXR5ICE9IG51bGwgJiZcclxuICAgICAgLy8gbnVsbCB0aGUgZW50aXR5IGlmIGl0IGlzIGRlbGV0ZWQgYW5kIHdlIHNob3VsZCBleGNsdWRlIGRlbGV0ZWQgZW50aXRpZXNcclxuICAgICAgIWVtLnF1ZXJ5T3B0aW9ucy5pbmNsdWRlRGVsZXRlZCAmJiBlbnRpdHkuZW50aXR5QXNwZWN0LmVudGl0eVN0YXRlLmlzRGVsZXRlZCgpKSB7XHJcbiAgICAgIGVudGl0eSA9IG51bGw7XHJcbiAgICAgIC8vIGJ1dCByZXN1bWUgbG9va2luZyBpZiB3ZSdkIG92ZXJ3cml0ZSBkZWxldGVkIGVudGl0eSB3aXRoIGEgcmVtb3RlIGVudGl0eVxyXG4gICAgICAvLyBub3RlOiBlbS5xdWVyeU9wdGlvbnMgaXMgYWx3YXlzIGZ1bGx5IHJlc29sdmVkIGJ5IG5vd1xyXG4gICAgICBmb3VuZEl0ID0gZW0ucXVlcnlPcHRpb25zLm1lcmdlU3RyYXRlZ3kgIT09IE1lcmdlU3RyYXRlZ3kuT3ZlcndyaXRlQ2hhbmdlcztcclxuICAgIH1cclxuICB9XHJcbiAgaWYgKGZvdW5kSXQpIHtcclxuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoeyBlbnRpdHk6IGVudGl0eSB8fCB1bmRlZmluZWQsIGVudGl0eUtleTogZW50aXR5S2V5LCBmcm9tQ2FjaGU6IHRydWUgfSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHJldHVybiBFbnRpdHlRdWVyeS5mcm9tRW50aXR5S2V5KGVudGl0eUtleSkudXNpbmcoZW0pLmV4ZWN1dGUoKS50aGVuKGZ1bmN0aW9uIChkYXRhOiBhbnkpIHtcclxuICAgICAgZW50aXR5ID0gKGRhdGEucmVzdWx0cy5sZW5ndGggPT09IDApID8gbnVsbCA6IGRhdGEucmVzdWx0c1swXTtcclxuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7IGVudGl0eTogZW50aXR5IHx8IHVuZGVmaW5lZCwgZW50aXR5S2V5OiBlbnRpdHlLZXksIGZyb21DYWNoZTogZmFsc2UgfSk7XHJcbiAgICB9KTtcclxuICB9XHJcbn1cclxuXHJcblxyXG4vLyBwcml2YXRlIGZuc1xyXG5cclxuLy8gdGFrZXMgaW4gZW50aXR5VHlwZXMgYXMgZWl0aGVyIHN0cmluZ3Mgb3IgZW50aXR5VHlwZXMgb3IgYXJyYXlzIG9mIGVpdGhlclxyXG4vLyBhbmQgcmV0dXJucyBlaXRoZXIgYW4gZW50aXR5VHlwZSBvciBhbiBhcnJheSBvZiBlbnRpdHlUeXBlcyBvciB0aHJvd3MgYW4gZXJyb3JcclxuZnVuY3Rpb24gY2hlY2tFbnRpdHlUeXBlcyhlbTogRW50aXR5TWFuYWdlciwgZW50aXR5VHlwZXM/OiBFbnRpdHlUeXBlIHwgRW50aXR5VHlwZVtdIHwgc3RyaW5nIHwgc3RyaW5nW10pIHtcclxuICBhc3NlcnRQYXJhbShlbnRpdHlUeXBlcywgXCJlbnRpdHlUeXBlc1wiKS5pc1N0cmluZygpLmlzT3B0aW9uYWwoKS5vcigpLmlzTm9uRW1wdHlBcnJheSgpLmlzU3RyaW5nKClcclxuICAgIC5vcigpLmlzSW5zdGFuY2VPZihFbnRpdHlUeXBlKS5vcigpLmlzTm9uRW1wdHlBcnJheSgpLmlzSW5zdGFuY2VPZihFbnRpdHlUeXBlKS5jaGVjaygpO1xyXG4gIGxldCByZXN1bHRUeXBlczogRW50aXR5VHlwZSB8IEVudGl0eVR5cGVbXSB8IHVuZGVmaW5lZDtcclxuICBpZiAodHlwZW9mIGVudGl0eVR5cGVzID09PSBcInN0cmluZ1wiKSB7XHJcbiAgICByZXN1bHRUeXBlcyA9IGVtLm1ldGFkYXRhU3RvcmUuX2dldFN0cnVjdHVyYWxUeXBlKGVudGl0eVR5cGVzLCBmYWxzZSkgYXMgKEVudGl0eVR5cGUgfCBFbnRpdHlUeXBlW10pO1xyXG4gIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShlbnRpdHlUeXBlcykgJiYgdHlwZW9mIGVudGl0eVR5cGVzWzBdID09PSBcInN0cmluZ1wiKSB7XHJcbiAgICByZXN1bHRUeXBlcyA9IChlbnRpdHlUeXBlcyBhcyBzdHJpbmdbXSkubWFwKGZ1bmN0aW9uIChldE5hbWUpIHtcclxuICAgICAgcmV0dXJuIGVtLm1ldGFkYXRhU3RvcmUuX2dldFN0cnVjdHVyYWxUeXBlKGV0TmFtZSwgZmFsc2UpIGFzIEVudGl0eVR5cGU7XHJcbiAgICB9KTtcclxuICB9IGVsc2Uge1xyXG4gICAgcmVzdWx0VHlwZXMgPSBlbnRpdHlUeXBlcyBhcyAoRW50aXR5VHlwZSB8IEVudGl0eVR5cGVbXSB8IHVuZGVmaW5lZCk7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gcmVzdWx0VHlwZXM7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGdldENoYW5nZXNDb3JlKGVtOiBFbnRpdHlNYW5hZ2VyLCBlbnRpdHlUeXBlcz86IEVudGl0eVR5cGUgfCBFbnRpdHlUeXBlW10pIHtcclxuICBsZXQgZW50aXR5R3JvdXBzID0gZ2V0RW50aXR5R3JvdXBzKGVtLCBlbnRpdHlUeXBlcyk7XHJcblxyXG4gIC8vIFRPRE86IHRoaW5rIGFib3V0IHdyaXRpbmcgYSBjb3JlLm1hcE1hbnkgbWV0aG9kIGlmIHdlIHNlZSBtb3JlIG9mIHRoZXNlLlxyXG4gIGxldCBzZWxlY3RlZDogRW50aXR5W10gPSBbXTtcclxuICBlbnRpdHlHcm91cHMuZm9yRWFjaChmdW5jdGlvbiAoZWcpIHtcclxuICAgIC8vIGVnIG1heSBiZSB1bmRlZmluZWQgb3IgbnVsbFxyXG4gICAgaWYgKCFlZykgcmV0dXJuO1xyXG4gICAgbGV0IGVudGl0aWVzID0gZWcuZ2V0Q2hhbmdlcygpO1xyXG4gICAgaWYgKHNlbGVjdGVkICYmIHNlbGVjdGVkLmxlbmd0aCkge1xyXG4gICAgICBzZWxlY3RlZCA9IHNlbGVjdGVkLmNvbmNhdChlbnRpdGllcyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBzZWxlY3RlZCA9IGVudGl0aWVzO1xyXG4gICAgfVxyXG4gIH0pO1xyXG4gIHJldHVybiBzZWxlY3RlZDtcclxufVxyXG5cclxuZnVuY3Rpb24gZ2V0RW50aXRpZXNDb3JlKGVtOiBFbnRpdHlNYW5hZ2VyLCBlbnRpdHlUeXBlczogRW50aXR5VHlwZSB8IEVudGl0eVR5cGVbXSB8IHVuZGVmaW5lZCwgZW50aXR5U3RhdGVzOiBFbnRpdHlTdGF0ZVtdKSB7XHJcbiAgbGV0IGVudGl0eUdyb3VwcyA9IGdldEVudGl0eUdyb3VwcyhlbSwgZW50aXR5VHlwZXMpO1xyXG5cclxuICAvLyBUT0RPOiB0aGluayBhYm91dCB3cml0aW5nIGEgY29yZS5tYXBNYW55IG1ldGhvZCBpZiB3ZSBzZWUgbW9yZSBvZiB0aGVzZS5cclxuICBsZXQgc2VsZWN0ZWQ6IEVudGl0eVtdID0gW107XHJcbiAgZW50aXR5R3JvdXBzLmZvckVhY2goZnVuY3Rpb24gKGVnKSB7XHJcbiAgICAvLyBlZyBtYXkgYmUgdW5kZWZpbmVkIG9yIG51bGxcclxuICAgIGlmICghZWcpIHJldHVybjtcclxuICAgIGxldCBlbnRpdGllcyA9IGVnLmdldEVudGl0aWVzKGVudGl0eVN0YXRlcyk7XHJcbiAgICBpZiAoc2VsZWN0ZWQgJiYgc2VsZWN0ZWQubGVuZ3RoKSB7XHJcbiAgICAgIHNlbGVjdGVkID0gc2VsZWN0ZWQuY29uY2F0KGVudGl0aWVzKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHNlbGVjdGVkID0gZW50aXRpZXM7XHJcbiAgICB9XHJcbiAgfSk7XHJcbiAgcmV0dXJuIHNlbGVjdGVkO1xyXG59XHJcblxyXG5cclxuZnVuY3Rpb24gY3JlYXRlRW50aXR5S2V5KGVtOiBFbnRpdHlNYW5hZ2VyLCBhcmdzOiBhbnlbXSkge1xyXG4gIHRyeSB7XHJcbiAgICBpZiAoYXJnc1swXSBpbnN0YW5jZW9mIEVudGl0eUtleSkge1xyXG4gICAgICByZXR1cm4geyBlbnRpdHlLZXk6IGFyZ3NbMF0gYXMgRW50aXR5S2V5LCByZW1haW5pbmdBcmdzOiBjb3JlLmFycmF5U2xpY2UoYXJncywgMSkgfTtcclxuICAgIH0gZWxzZSBpZiAoYXJncy5sZW5ndGggPj0gMikge1xyXG4gICAgICBsZXQgZW50aXR5VHlwZSA9ICh0eXBlb2YgYXJnc1swXSA9PT0gJ3N0cmluZycpID8gZW0ubWV0YWRhdGFTdG9yZS5fZ2V0U3RydWN0dXJhbFR5cGUoYXJnc1swXSwgZmFsc2UpIDogYXJnc1swXTtcclxuICAgICAgcmV0dXJuIHsgZW50aXR5S2V5OiBuZXcgRW50aXR5S2V5KGVudGl0eVR5cGUsIGFyZ3NbMV0pLCByZW1haW5pbmdBcmdzOiBjb3JlLmFycmF5U2xpY2UoYXJncywgMikgfTtcclxuICAgIH1cclxuICB9IGNhdGNoIChlKSB7LyogdGhyb3cgYmVsb3cgKi9cclxuICAgIC8vIHRocm93IG5ldyBFcnJvcihcIk11c3Qgc3VwcGx5IGFuIEVudGl0eUtleSBPUiBhbiBFbnRpdHlUeXBlIG5hbWUgb3IgRW50aXR5VHlwZSBmb2xsb3dlZCBieSBhIGtleSB2YWx1ZSBvciBhbiBhcnJheSBvZiBrZXkgdmFsdWVzLlwiKTtcclxuICB9XHJcbiAgdGhyb3cgbmV3IEVycm9yKFwiTXVzdCBzdXBwbHkgYW4gRW50aXR5S2V5IE9SIGFuIEVudGl0eVR5cGUgbmFtZSBvciBFbnRpdHlUeXBlIGZvbGxvd2VkIGJ5IGEga2V5IHZhbHVlIG9yIGFuIGFycmF5IG9mIGtleSB2YWx1ZXMuXCIpO1xyXG59XHJcblxyXG5mdW5jdGlvbiBtYXJrSXNCZWluZ1NhdmVkKGVudGl0aWVzOiBFbnRpdHlbXSwgZmxhZzogYm9vbGVhbikge1xyXG4gIGVudGl0aWVzLmZvckVhY2goZnVuY3Rpb24gKGVudGl0eSkge1xyXG4gICAgZW50aXR5LmVudGl0eUFzcGVjdC5pc0JlaW5nU2F2ZWQgPSBmbGFnO1xyXG4gIH0pO1xyXG59XHJcblxyXG5mdW5jdGlvbiBleHBvcnRFbnRpdHlHcm91cHMoZW06IEVudGl0eU1hbmFnZXIsIGVudGl0aWVzT3JFbnRpdHlUeXBlczogRW50aXR5W10gfCBFbnRpdHlUeXBlW10gfCBzdHJpbmdbXSkge1xyXG4gIGxldCBlbnRpdHlHcm91cE1hcDogeyBbaW5kZXg6IHN0cmluZ106IEVudGl0eUdyb3VwIH07XHJcbiAgbGV0IGZpcnN0ID0gZW50aXRpZXNPckVudGl0eVR5cGVzICYmIGVudGl0aWVzT3JFbnRpdHlUeXBlc1swXTtcclxuICAvLyBjaGVjayBpZiBhcnJheVxyXG4gIGlmIChmaXJzdCkge1xyXG4gICAgLy8gZ3JvdXAgZW50aXRpZXMgYnkgZW50aXR5VHlwZSBhbmRcclxuICAgIC8vIGNyZWF0ZSAnZ3JvdXBzJyB0aGF0IGxvb2sgbGlrZSBlbnRpdHlHcm91cHMuXHJcbiAgICBlbnRpdHlHcm91cE1hcCA9IHt9O1xyXG4gICAgaWYgKChmaXJzdCBhcyBhbnkpLmVudGl0eVR5cGUpIHtcclxuICAgICAgbGV0IGVudGl0aWVzID0gZW50aXRpZXNPckVudGl0eVR5cGVzIGFzIEVudGl0eVtdO1xyXG4gICAgICAvLyBhc3N1bWUgXCJlbnRpdGllc1wiIGlzIGFuIGFycmF5IG9mIGVudGl0aWVzO1xyXG4gICAgICBlbnRpdGllcy5mb3JFYWNoKGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgaWYgKGUuZW50aXR5QXNwZWN0LmVudGl0eVN0YXRlID09PSBFbnRpdHlTdGF0ZS5EZXRhY2hlZCkge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVW5hYmxlIHRvIGV4cG9ydCBhbiBlbnRpdHkgd2l0aCBhbiBFbnRpdHlTdGF0ZSBvZiAnRGV0YWNoZWQnXCIpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZXQgZ3JvdXAgPSBlbnRpdHlHcm91cE1hcFtlLmVudGl0eVR5cGUubmFtZV07XHJcbiAgICAgICAgaWYgKCFncm91cCkge1xyXG4gICAgICAgICAgZ3JvdXAgPSB7fSBhcyBFbnRpdHlHcm91cDtcclxuICAgICAgICAgIGdyb3VwLmVudGl0eVR5cGUgPSBlLmVudGl0eVR5cGU7XHJcbiAgICAgICAgICBncm91cC5fZW50aXRpZXMgPSBbXTtcclxuICAgICAgICAgIGVudGl0eUdyb3VwTWFwW2UuZW50aXR5VHlwZS5uYW1lXSA9IGdyb3VwO1xyXG4gICAgICAgIH1cclxuICAgICAgICBncm91cC5fZW50aXRpZXMucHVzaChlKTtcclxuICAgICAgfSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBhc3N1bWUgXCJlbnRpdGllc1wiIGlzIGFuIGFycmF5IG9mIEVudGl0eVR5cGVzIChvciBuYW1lcylcclxuICAgICAgbGV0IGVudGl0eVR5cGVzID0gY2hlY2tFbnRpdHlUeXBlcyhlbSwgZW50aXRpZXNPckVudGl0eVR5cGVzIGFzIEVudGl0eVR5cGVbXSB8IHN0cmluZ1tdKSBhcyBFbnRpdHlUeXBlW107XHJcbiAgICAgIGlmIChlbnRpdHlUeXBlcyAhPSBudWxsKSB7XHJcbiAgICAgICAgZW50aXR5VHlwZXMuZm9yRWFjaCgoZXQpID0+IHtcclxuICAgICAgICAgIGxldCBncm91cCA9IGVtLl9lbnRpdHlHcm91cE1hcFtldC5uYW1lXTtcclxuICAgICAgICAgIGlmIChncm91cCAmJiBncm91cC5fZW50aXRpZXMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgIGVudGl0eUdyb3VwTWFwW2V0Lm5hbWVdID0gZ3JvdXA7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9IGVsc2UgaWYgKGVudGl0aWVzT3JFbnRpdHlUeXBlcyAmJiBlbnRpdGllc09yRW50aXR5VHlwZXMubGVuZ3RoID09PSAwKSB7XHJcbiAgICAvLyBlbXB0eSBhcnJheSA9IGV4cG9ydCBub3RoaW5nXHJcbiAgICBlbnRpdHlHcm91cE1hcCA9IHt9O1xyXG4gIH0gZWxzZSB7XHJcbiAgICBlbnRpdHlHcm91cE1hcCA9IGVtLl9lbnRpdHlHcm91cE1hcDtcclxuICB9XHJcblxyXG4gIGxldCB0ZW1wS2V5czogSVRlbXBLZXlbXSA9IFtdO1xyXG4gIGxldCBuZXdHcm91cE1hcCA9IHt9O1xyXG4gIGNvcmUub2JqZWN0Rm9yRWFjaChlbnRpdHlHcm91cE1hcCwgKGVudGl0eVR5cGVOYW1lLCBlbnRpdHlHcm91cCkgPT4ge1xyXG4gICAgbmV3R3JvdXBNYXBbZW50aXR5VHlwZU5hbWVdID0gZXhwb3J0RW50aXR5R3JvdXAoZW50aXR5R3JvdXAsIHRlbXBLZXlzKTtcclxuICB9KTtcclxuXHJcbiAgcmV0dXJuIHsgZW50aXR5R3JvdXBNYXA6IG5ld0dyb3VwTWFwLCB0ZW1wS2V5czogdGVtcEtleXMgfTtcclxufVxyXG5cclxuZnVuY3Rpb24gZXhwb3J0RW50aXR5R3JvdXAoZW50aXR5R3JvdXA6IEVudGl0eUdyb3VwLCB0ZW1wS2V5czogSVRlbXBLZXlbXSkge1xyXG4gIGxldCByZXN1bHRHcm91cCA9IHt9IGFzIHsgZW50aXRpZXM6IGFueVtdIH07XHJcbiAgbGV0IGVudGl0eVR5cGUgPSBlbnRpdHlHcm91cC5lbnRpdHlUeXBlO1xyXG4gIGxldCBkcHMgPSBlbnRpdHlUeXBlLmRhdGFQcm9wZXJ0aWVzO1xyXG4gIGxldCBzZXJpYWxpemVyRm4gPSBnZXRTZXJpYWxpemVyRm4oZW50aXR5VHlwZSk7XHJcbiAgbGV0IHJhd0VudGl0aWVzOiBhbnlbXSA9IFtdO1xyXG4gIGVudGl0eUdyb3VwLl9lbnRpdGllcy5mb3JFYWNoKChlbnRpdHkpID0+IHtcclxuICAgIGlmIChlbnRpdHkpIHtcclxuICAgICAgbGV0IHJhd0VudGl0eSA9IHN0cnVjdHVyYWxPYmplY3RUb0pzb24oZW50aXR5LCBkcHMsIHNlcmlhbGl6ZXJGbiwgdGVtcEtleXMpO1xyXG4gICAgICByYXdFbnRpdGllcy5wdXNoKHJhd0VudGl0eSk7XHJcbiAgICB9XHJcbiAgfSk7XHJcbiAgcmVzdWx0R3JvdXAuZW50aXRpZXMgPSByYXdFbnRpdGllcztcclxuICByZXR1cm4gcmVzdWx0R3JvdXA7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIHN0cnVjdHVyYWxPYmplY3RUb0pzb24oc286IFN0cnVjdHVyYWxPYmplY3QsIGRwczogRGF0YVByb3BlcnR5W10sIHNlcmlhbGl6ZXJGbj86IChkcDogRGF0YVByb3BlcnR5LCB2YWx1ZTogYW55KSA9PiBhbnksIHRlbXBLZXlzPzogSVRlbXBLZXlbXSkge1xyXG5cclxuICBsZXQgcmVzdWx0ID0ge307XHJcbiAgZHBzLmZvckVhY2goZnVuY3Rpb24gKGRwKSB7XHJcbiAgICBsZXQgZHBOYW1lID0gZHAubmFtZTtcclxuICAgIGxldCB2YWx1ZSA9IHNvLmdldFByb3BlcnR5KGRwTmFtZSk7XHJcbiAgICBpZiAodmFsdWUgPT0gbnVsbCAmJiBkcC5kZWZhdWx0VmFsdWUgPT0gbnVsbCkgcmV0dXJuO1xyXG5cclxuICAgIGlmICh2YWx1ZSAmJiBkcC5pc0NvbXBsZXhQcm9wZXJ0eSkge1xyXG4gICAgICBsZXQgY29EcHMgPSAoZHAuZGF0YVR5cGUgYXMgQ29tcGxleFR5cGUpLmRhdGFQcm9wZXJ0aWVzO1xyXG4gICAgICB2YWx1ZSA9IGNvcmUubWFwKHZhbHVlLCBmdW5jdGlvbiAodjogQ29tcGxleE9iamVjdCkge1xyXG4gICAgICAgIHJldHVybiBzdHJ1Y3R1cmFsT2JqZWN0VG9Kc29uKHYsIGNvRHBzLCBzZXJpYWxpemVyRm4pO1xyXG4gICAgICB9KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHZhbHVlID0gc2VyaWFsaXplckZuID8gc2VyaWFsaXplckZuKGRwLCB2YWx1ZSkgOiB2YWx1ZTtcclxuICAgICAgaWYgKGRwLmlzVW5tYXBwZWQpIHtcclxuICAgICAgICB2YWx1ZSA9IGNvcmUudG9KU09OU2FmZSh2YWx1ZSwgY29yZS50b0pTT05TYWZlUmVwbGFjZXIpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xyXG4gICAgcmVzdWx0W2RwTmFtZV0gPSB2YWx1ZTtcclxuICB9KTtcclxuXHJcbiAgLy8gaWYgKHNvLmVudGl0eUFzcGVjdCkge1xyXG4gIGlmIChFbnRpdHlBc3BlY3QuaXNFbnRpdHkoc28pKSB7XHJcbiAgICBsZXQgYXNwZWN0ID0gc28uZW50aXR5QXNwZWN0O1xyXG4gICAgbGV0IGVudGl0eVN0YXRlID0gYXNwZWN0LmVudGl0eVN0YXRlO1xyXG4gICAgbGV0IG5ld0FzcGVjdCA9IHtcclxuICAgICAgdGVtcE5hdlByb3BOYW1lczogZXhwb3J0VGVtcEtleUluZm8oYXNwZWN0LCB0ZW1wS2V5cyB8fCBbXSksXHJcbiAgICAgIGVudGl0eVN0YXRlOiBlbnRpdHlTdGF0ZS5uYW1lXHJcbiAgICB9IGFzIGFueTtcclxuICAgIGlmIChhc3BlY3QuZXh0cmFNZXRhZGF0YSkge1xyXG4gICAgICBuZXdBc3BlY3QuZXh0cmFNZXRhZGF0YSA9IGFzcGVjdC5leHRyYU1ldGFkYXRhO1xyXG4gICAgfVxyXG4gICAgaWYgKGVudGl0eVN0YXRlLmlzTW9kaWZpZWQoKSB8fCBlbnRpdHlTdGF0ZS5pc0RlbGV0ZWQoKSkge1xyXG4gICAgICBuZXdBc3BlY3Qub3JpZ2luYWxWYWx1ZXNNYXAgPSBhc3BlY3Qub3JpZ2luYWxWYWx1ZXM7XHJcbiAgICB9XHJcbiAgICAocmVzdWx0IGFzIGFueSkuZW50aXR5QXNwZWN0ID0gbmV3QXNwZWN0O1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsZXQgYXNwZWN0ID0gc28uY29tcGxleEFzcGVjdDtcclxuICAgIGxldCBuZXdBc3BlY3QgPSB7fSBhcyBhbnk7XHJcbiAgICBpZiAoYXNwZWN0Lm9yaWdpbmFsVmFsdWVzICYmICFjb3JlLmlzRW1wdHkoYXNwZWN0Lm9yaWdpbmFsVmFsdWVzKSkge1xyXG4gICAgICBuZXdBc3BlY3Qub3JpZ2luYWxWYWx1ZXNNYXAgPSBhc3BlY3Qub3JpZ2luYWxWYWx1ZXM7XHJcbiAgICB9XHJcblxyXG4gICAgKHJlc3VsdCBhcyBhbnkpLmNvbXBsZXhBc3BlY3QgPSBuZXdBc3BlY3Q7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gcmVzdWx0O1xyXG59XHJcblxyXG5pbnRlcmZhY2UgSVRlbXBLZXkge1xyXG4gIGVudGl0eVR5cGU6IHN0cmluZztcclxuICB2YWx1ZXM6IGFueVtdO1xyXG59XHJcblxyXG5mdW5jdGlvbiBleHBvcnRUZW1wS2V5SW5mbyhlbnRpdHlBc3BlY3Q6IEVudGl0eUFzcGVjdCwgdGVtcEtleXM6IElUZW1wS2V5W10pIHtcclxuICBsZXQgZW50aXR5ID0gZW50aXR5QXNwZWN0LmVudGl0eSBhcyBFbnRpdHk7XHJcbiAgaWYgKGVudGl0eUFzcGVjdC5oYXNUZW1wS2V5KSB7XHJcbiAgICB0ZW1wS2V5cy5wdXNoKGVudGl0eUFzcGVjdC5nZXRLZXkoKS50b0pTT04oKSk7XHJcbiAgfVxyXG4gIC8vIGNyZWF0ZSBtYXAgZm9yIHRoaXMgZW50aXR5IHdpdGggZm9yZWlnbktleXMgdGhhdCBhcmUgJ3RlbXBvcmFyeSdcclxuICAvLyBtYXAgLT4ga2V5OiB0ZW1wS2V5LCB2YWx1ZTogZmtQcm9wTmFtZVxyXG4gIGxldCB0ZW1wTmF2UHJvcE5hbWVzOiBzdHJpbmdbXSA9IFtdO1xyXG4gIGVudGl0eS5lbnRpdHlUeXBlLm5hdmlnYXRpb25Qcm9wZXJ0aWVzLmZvckVhY2goZnVuY3Rpb24gKG5wKSB7XHJcbiAgICBpZiAobnAucmVsYXRlZERhdGFQcm9wZXJ0aWVzKSB7XHJcbiAgICAgIGxldCByZWxhdGVkVmFsdWUgPSBlbnRpdHkuZ2V0UHJvcGVydHkobnAubmFtZSk7XHJcbiAgICAgIGlmIChyZWxhdGVkVmFsdWUgJiYgcmVsYXRlZFZhbHVlLmVudGl0eUFzcGVjdC5oYXNUZW1wS2V5KSB7XHJcbiAgICAgICAgdGVtcE5hdlByb3BOYW1lcy5wdXNoKG5wLm5hbWUpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbiAgcmV0dXJuIHRlbXBOYXZQcm9wTmFtZXM7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGltcG9ydEVudGl0eUdyb3VwKGVudGl0eUdyb3VwOiBFbnRpdHlHcm91cCwganNvbkdyb3VwOiB7IGVudGl0aWVzOiBhbnlbXSB9LCBpbXBvcnRDb25maWc6IEltcG9ydENvbmZpZ0V4dCkge1xyXG5cclxuICBsZXQgdGVtcEtleU1hcCA9IGltcG9ydENvbmZpZy50ZW1wS2V5TWFwO1xyXG4gIGxldCBtZXJnZUFkZHMgPSAhIWltcG9ydENvbmZpZy5tZXJnZUFkZHM7XHJcblxyXG4gIGxldCBlbnRpdHlUeXBlID0gZW50aXR5R3JvdXAuZW50aXR5VHlwZTtcclxuICBsZXQgbWVyZ2VTdHJhdGVneSA9IGltcG9ydENvbmZpZy5tZXJnZVN0cmF0ZWd5O1xyXG5cclxuICBsZXQgdGFyZ2V0RW50aXR5OiBFbnRpdHkgfCB1bmRlZmluZWQ7XHJcblxyXG4gIGxldCBlbSA9IGVudGl0eUdyb3VwLmVudGl0eU1hbmFnZXI7XHJcbiAgbGV0IGVudGl0eUNoYW5nZWQgPSBlbS5lbnRpdHlDaGFuZ2VkO1xyXG4gIGxldCBlbnRpdGllc1RvTGluazogRW50aXR5W10gPSBbXTtcclxuICBsZXQgcmF3VmFsdWVGbiA9IERhdGFQcm9wZXJ0eS5nZXRSYXdWYWx1ZUZyb21DbGllbnQ7XHJcbiAganNvbkdyb3VwLmVudGl0aWVzLmZvckVhY2goZnVuY3Rpb24gKHJhd0VudGl0eTogYW55KSB7XHJcbiAgICBsZXQgbmV3QXNwZWN0ID0gcmF3RW50aXR5LmVudGl0eUFzcGVjdDtcclxuXHJcbiAgICBsZXQgZW50aXR5S2V5ID0gZW50aXR5VHlwZS5nZXRFbnRpdHlLZXlGcm9tUmF3RW50aXR5KHJhd0VudGl0eSwgcmF3VmFsdWVGbik7XHJcbiAgICBsZXQgZW50aXR5U3RhdGUgPSBFbnRpdHlTdGF0ZS5mcm9tTmFtZShuZXdBc3BlY3QuZW50aXR5U3RhdGUpIGFzIEVudGl0eVN0YXRlO1xyXG4gICAgaWYgKCFlbnRpdHlTdGF0ZSB8fCBlbnRpdHlTdGF0ZSA9PT0gRW50aXR5U3RhdGUuRGV0YWNoZWQpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiT25seSBlbnRpdGllcyB3aXRoIGEgbm9uIGRldGFjaGVkIGVudGl0eSBzdGF0ZSBtYXkgYmUgaW1wb3J0ZWQuXCIpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIGlmIHJhdyBlbnRpdHkgaXMgaW4gY2FjaGUgVU5MRVNTIHRoaXMgaXMgYSBuZXcgZW50aXR5IHcvIGEgdGVtcCBrZXlcclxuICAgIC8vIENhbm5vdCBzYWZlbHkgbWVyZ2Ugc3VjaCBlbnRpdGllcyBldmVuIGlmIGNvdWxkIG1hdGNoIHRlbXAga2V5IHRvIGFuIGVudGl0eSBpbiBjYWNoZS5cclxuICAgIC8vIENhbiBlbmFibGUgbWVyZ2Ugb2YgZW50aXRpZXMgdy90ZW1wIGtleSB1c2luZyBcIm1lcmdlQWRkc1wiIC0gdXNlIGF0IHlvdXIgb3duIHJpc2shXHJcbiAgICBsZXQgbmV3VGVtcEtleSA9ICFtZXJnZUFkZHMgJiYgZW50aXR5U3RhdGUuaXNBZGRlZCgpICYmIGdldE1hcHBlZEtleSh0ZW1wS2V5TWFwISwgZW50aXR5S2V5KTtcclxuICAgIHRhcmdldEVudGl0eSA9IG5ld1RlbXBLZXkgPyB1bmRlZmluZWQgOiBlbnRpdHlHcm91cC5maW5kRW50aXR5QnlLZXkoZW50aXR5S2V5KTtcclxuXHJcbiAgICBpZiAodGFyZ2V0RW50aXR5KSB7XHJcbiAgICAgIGlmIChtZXJnZVN0cmF0ZWd5ID09PSBNZXJnZVN0cmF0ZWd5LlNraXBNZXJnZSkge1xyXG4gICAgICAgIC8vIGRlbGliZXJhdGUgZmFsbCB0aHJ1XHJcbiAgICAgIH0gZWxzZSBpZiAobWVyZ2VTdHJhdGVneSA9PT0gTWVyZ2VTdHJhdGVneS5EaXNhbGxvd2VkKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQSBNZXJnZVN0cmF0ZWd5IG9mICdEaXNhbGxvd2VkJyBwcmV2ZW50cyBcIiArIGVudGl0eUtleS50b1N0cmluZygpICsgXCIgZnJvbSBiZWluZyBtZXJnZWRcIik7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbGV0IHRhcmdldEVudGl0eVN0YXRlID0gdGFyZ2V0RW50aXR5LmVudGl0eUFzcGVjdC5lbnRpdHlTdGF0ZTtcclxuICAgICAgICBsZXQgd2FzVW5jaGFuZ2VkID0gdGFyZ2V0RW50aXR5U3RhdGUuaXNVbmNoYW5nZWQoKTtcclxuICAgICAgICBpZiAobWVyZ2VTdHJhdGVneSA9PT0gTWVyZ2VTdHJhdGVneS5PdmVyd3JpdGVDaGFuZ2VzIHx8IHdhc1VuY2hhbmdlZCkge1xyXG4gICAgICAgICAgZW50aXR5VHlwZS5fdXBkYXRlVGFyZ2V0RnJvbVJhdyh0YXJnZXRFbnRpdHksIHJhd0VudGl0eSwgcmF3VmFsdWVGbik7XHJcbiAgICAgICAgICB0YXJnZXRFbnRpdHkuZW50aXR5QXNwZWN0LnNldEVudGl0eVN0YXRlKGVudGl0eVN0YXRlKTtcclxuICAgICAgICAgIGVudGl0eUNoYW5nZWQucHVibGlzaCh7IGVudGl0eUFjdGlvbjogRW50aXR5QWN0aW9uLk1lcmdlT25JbXBvcnQsIGVudGl0eTogdGFyZ2V0RW50aXR5IH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGFyZ2V0RW50aXR5ID0gZW50aXR5VHlwZS5fY3JlYXRlSW5zdGFuY2VDb3JlKCkgYXMgRW50aXR5O1xyXG4gICAgICBlbnRpdHlUeXBlLl91cGRhdGVUYXJnZXRGcm9tUmF3KHRhcmdldEVudGl0eSwgcmF3RW50aXR5LCByYXdWYWx1ZUZuKTtcclxuICAgICAgaWYgKG5ld1RlbXBLZXkpIHtcclxuICAgICAgICB0YXJnZXRFbnRpdHkuZW50aXR5QXNwZWN0Lmhhc1RlbXBLZXkgPSB0cnVlO1xyXG4gICAgICAgIC8vIGZpeHVwIHBrXHJcbiAgICAgICAgdGFyZ2V0RW50aXR5LnNldFByb3BlcnR5KGVudGl0eVR5cGUua2V5UHJvcGVydGllc1swXS5uYW1lLCBuZXdUZW1wS2V5LnZhbHVlc1swXSk7XHJcblxyXG4gICAgICAgIC8vIGZpeHVwIGZvcmVpZ24ga2V5c1xyXG4gICAgICAgIC8vIFRoaXMgaXMgc2FmZSBiZWNhdXNlIHRoZSBlbnRpdHkgaXMgZGV0YWNoZWQgaGVyZSBhbmQgdGhlcmVmb3JlIG9yaWdpbmFsVmFsdWVzIHdpbGwgbm90IGJlIHVwZGF0ZWQuXHJcbiAgICAgICAgaWYgKG5ld0FzcGVjdC50ZW1wTmF2UHJvcE5hbWVzKSB7XHJcbiAgICAgICAgICBuZXdBc3BlY3QudGVtcE5hdlByb3BOYW1lcy5mb3JFYWNoKGZ1bmN0aW9uIChucE5hbWU6IHN0cmluZykge1xyXG4gICAgICAgICAgICBsZXQgbnAgPSBlbnRpdHlUeXBlLmdldE5hdmlnYXRpb25Qcm9wZXJ0eShucE5hbWUpO1xyXG4gICAgICAgICAgICBsZXQgZmtQcm9wTmFtZSA9IG5wIS5yZWxhdGVkRGF0YVByb3BlcnRpZXNbMF0ubmFtZTtcclxuICAgICAgICAgICAgbGV0IG9sZEZrVmFsdWUgPSB0YXJnZXRFbnRpdHkhLmdldFByb3BlcnR5KGZrUHJvcE5hbWUpO1xyXG4gICAgICAgICAgICBsZXQgZmsgPSBuZXcgRW50aXR5S2V5KG5wIS5lbnRpdHlUeXBlLCBbb2xkRmtWYWx1ZV0pO1xyXG4gICAgICAgICAgICBsZXQgbmV3RmsgPSBnZXRNYXBwZWRLZXkodGVtcEtleU1hcCEsIGZrKTtcclxuICAgICAgICAgICAgdGFyZ2V0RW50aXR5IS5zZXRQcm9wZXJ0eShma1Byb3BOYW1lLCBuZXdGayEudmFsdWVzWzBdKTtcclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICAvLyBOb3cgcGVyZm9ybWVkIGluIGF0dGFjaEVudGl0eVxyXG4gICAgICB0YXJnZXRFbnRpdHkgPSBlbnRpdHlHcm91cC5hdHRhY2hFbnRpdHkodGFyZ2V0RW50aXR5LCBlbnRpdHlTdGF0ZSk7XHJcbiAgICAgIGVudGl0eUNoYW5nZWQucHVibGlzaCh7IGVudGl0eUFjdGlvbjogRW50aXR5QWN0aW9uLkF0dGFjaE9uSW1wb3J0LCBlbnRpdHk6IHRhcmdldEVudGl0eSB9KTtcclxuICAgICAgaWYgKCFlbnRpdHlTdGF0ZS5pc1VuY2hhbmdlZCgpKSB7XHJcbiAgICAgICAgZW0uX25vdGlmeVN0YXRlQ2hhbmdlKHRhcmdldEVudGl0eSwgdHJ1ZSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBlbnRpdGllc1RvTGluay5wdXNoKHRhcmdldEVudGl0eSk7XHJcbiAgfSk7XHJcbiAgcmV0dXJuIGVudGl0aWVzVG9MaW5rO1xyXG59XHJcblxyXG5mdW5jdGlvbiBnZXRNYXBwZWRLZXkodGVtcEtleU1hcDogSVRlbXBLZXlNYXAsIGVudGl0eUtleTogRW50aXR5S2V5KSB7XHJcbiAgbGV0IG5ld0tleSA9IHRlbXBLZXlNYXBbZW50aXR5S2V5LnRvU3RyaW5nKCldO1xyXG4gIGlmIChuZXdLZXkpIHJldHVybiBuZXdLZXk7XHJcbiAgbGV0IHN1YnR5cGVzID0gZW50aXR5S2V5Ll9zdWJ0eXBlcztcclxuICBpZiAoIXN1YnR5cGVzKSByZXR1cm4gbnVsbDtcclxuICBmb3IgKGxldCBpID0gMCwgaiA9IHN1YnR5cGVzLmxlbmd0aDsgaSA8IGo7IGkrKykge1xyXG4gICAgbmV3S2V5ID0gdGVtcEtleU1hcFtlbnRpdHlLZXkudG9TdHJpbmcoc3VidHlwZXNbaV0pXTtcclxuICAgIGlmIChuZXdLZXkpIHJldHVybiBuZXdLZXk7XHJcbiAgfVxyXG4gIHJldHVybiBudWxsO1xyXG59XHJcblxyXG5mdW5jdGlvbiBwcm9taXNlV2l0aENhbGxiYWNrczxUPihwcm9taXNlOiBQcm9taXNlPFQ+LCBjYWxsYmFjaz86IENhbGxiYWNrLCBlcnJvckNhbGxiYWNrPzogRXJyb3JDYWxsYmFjaykge1xyXG4gIHByb21pc2UgPSBwcm9taXNlLnRoZW4oZnVuY3Rpb24gKGRhdGEpIHtcclxuICAgIGlmIChjYWxsYmFjaykgY2FsbGJhY2soZGF0YSk7XHJcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGRhdGEpO1xyXG4gIH0sIGZ1bmN0aW9uIChlcnJvcikge1xyXG4gICAgaWYgKGVycm9yQ2FsbGJhY2spIGVycm9yQ2FsbGJhY2soZXJyb3IpO1xyXG4gICAgcmV0dXJuIFByb21pc2UucmVqZWN0KGVycm9yKTtcclxuICB9KTtcclxuICByZXR1cm4gcHJvbWlzZTtcclxufVxyXG5cclxuZnVuY3Rpb24gZ2V0RW50aXRpZXNUb1NhdmUoZW06IEVudGl0eU1hbmFnZXIsIGVudGl0aWVzPzogRW50aXR5W10pIHtcclxuICBsZXQgZW50aXRpZXNUb1NhdmU6IEVudGl0eVtdO1xyXG4gIGlmIChlbnRpdGllcykge1xyXG4gICAgZW50aXRpZXNUb1NhdmUgPSBlbnRpdGllcy5maWx0ZXIoZnVuY3Rpb24gKGUpIHtcclxuICAgICAgaWYgKGUuZW50aXR5QXNwZWN0LmVudGl0eU1hbmFnZXIgIT09IGVtKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiT25seSBlbnRpdGllcyBpbiB0aGlzIGVudGl0eU1hbmFnZXIgbWF5IGJlIHNhdmVkXCIpO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiAhZS5lbnRpdHlBc3BlY3QuZW50aXR5U3RhdGUuaXNEZXRhY2hlZCgpO1xyXG4gICAgfSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGVudGl0aWVzVG9TYXZlID0gZW0uZ2V0Q2hhbmdlcygpO1xyXG4gIH1cclxuICByZXR1cm4gZW50aXRpZXNUb1NhdmU7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGZpeHVwS2V5cyhlbTogRW50aXR5TWFuYWdlciwga2V5TWFwcGluZ3M6IEtleU1hcHBpbmdbXSkge1xyXG4gIGVtLl9pbktleUZpeHVwID0gdHJ1ZTtcclxuICBrZXlNYXBwaW5ncy5mb3JFYWNoKGZ1bmN0aW9uIChrbSkge1xyXG4gICAgbGV0IGdyb3VwID0gZW0uX2VudGl0eUdyb3VwTWFwW2ttLmVudGl0eVR5cGVOYW1lXTtcclxuICAgIGlmICghZ3JvdXApIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVW5hYmxlIHRvIGxvY2F0ZSB0aGUgZm9sbG93aW5nIGZ1bGx5IHF1YWxpZmllZCBFbnRpdHlUeXBlIG5hbWU6IFwiICsga20uZW50aXR5VHlwZU5hbWUpO1xyXG4gICAgfVxyXG4gICAgZ3JvdXAuX2ZpeHVwS2V5KGttLnRlbXBWYWx1ZSwga20ucmVhbFZhbHVlKTtcclxuICB9KTtcclxuICBlbS5faW5LZXlGaXh1cCA9IGZhbHNlO1xyXG59XHJcblxyXG5mdW5jdGlvbiBnZXRFbnRpdHlHcm91cHMoZW06IEVudGl0eU1hbmFnZXIsIGVudGl0eVR5cGVzPzogRW50aXR5VHlwZSB8IEVudGl0eVR5cGVbXSkge1xyXG4gIGxldCBncm91cE1hcCA9IGVtLl9lbnRpdHlHcm91cE1hcDtcclxuICBpZiAoZW50aXR5VHlwZXMpIHtcclxuICAgIHJldHVybiBjb3JlLnRvQXJyYXkoZW50aXR5VHlwZXMpLm1hcChmdW5jdGlvbiAoZXQ6IEVudGl0eVR5cGUpIHtcclxuICAgICAgaWYgKGV0IGluc3RhbmNlb2YgRW50aXR5VHlwZSkge1xyXG4gICAgICAgIHJldHVybiBncm91cE1hcFtldC5uYW1lXTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUaGUgRW50aXR5TWFuYWdlci5nZXRDaGFuZ2VzKCkgJ2VudGl0eVR5cGVzJyBwYXJhbWV0ZXIgbXVzdCBiZSBlaXRoZXIgYW4gZW50aXR5VHlwZSBvciBhbiBhcnJheSBvZiBlbnRpdHlUeXBlcyBvciBudWxsXCIpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGVsc2Uge1xyXG4gICAgcmV0dXJuIGNvcmUuZ2V0T3duUHJvcGVydHlWYWx1ZXMoZ3JvdXBNYXApIGFzIEVudGl0eUdyb3VwW107XHJcbiAgfVxyXG59XHJcblxyXG5mdW5jdGlvbiBjaGVja0VudGl0eUtleShlbTogRW50aXR5TWFuYWdlciwgZW50aXR5OiBFbnRpdHkpIHtcclxuICBsZXQgZWsgPSBlbnRpdHkuZW50aXR5QXNwZWN0LmdldEtleSgpO1xyXG4gIC8vIHJldHVybiBwcm9wZXJ0aWVzIHRoYXQgYXJlID0gdG8gZGVmYXVsdFZhbHVlc1xyXG4gIGxldCBrZXlQcm9wc1dpdGhEZWZhdWx0VmFsdWVzID0gY29yZS5hcnJheVppcChlbnRpdHkuZW50aXR5VHlwZS5rZXlQcm9wZXJ0aWVzLCBlay52YWx1ZXMsIGZ1bmN0aW9uIChrcCwga3YpIHtcclxuICAgIHJldHVybiAoa3AuZGVmYXVsdFZhbHVlID09PSBrdikgPyBrcCA6IG51bGw7XHJcbiAgfSkuZmlsdGVyKGZ1bmN0aW9uIChrcCkge1xyXG4gICAgcmV0dXJuIGtwICE9PSBudWxsO1xyXG4gIH0pO1xyXG4gIGlmIChrZXlQcm9wc1dpdGhEZWZhdWx0VmFsdWVzLmxlbmd0aCkge1xyXG4gICAgaWYgKGVudGl0eS5lbnRpdHlUeXBlLmF1dG9HZW5lcmF0ZWRLZXlUeXBlICE9PSBBdXRvR2VuZXJhdGVkS2V5VHlwZS5Ob25lKSB7XHJcbiAgICAgIGVtLmdlbmVyYXRlVGVtcEtleVZhbHVlKGVudGl0eSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyB3ZSB3aWxsIGFsbG93IGF0dGFjaGVzIG9mIGVudGl0aWVzIHdoZXJlIG9ubHkgcGFydCBvZiB0aGUga2V5IGlzIHNldC5cclxuICAgICAgaWYgKGtleVByb3BzV2l0aERlZmF1bHRWYWx1ZXMubGVuZ3RoID09PSBlay52YWx1ZXMubGVuZ3RoKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2Fubm90IGF0dGFjaCBhbiBvYmplY3Qgb2YgdHlwZSAgKFwiICsgZW50aXR5LmVudGl0eVR5cGUubmFtZSArIFwiKSB0byBhbiBFbnRpdHlNYW5hZ2VyIHdpdGhvdXQgZmlyc3Qgc2V0dGluZyBpdHMga2V5IG9yIHNldHRpbmcgaXRzIGVudGl0eVR5cGUgJ0F1dG9HZW5lcmF0ZWRLZXlUeXBlJyBwcm9wZXJ0eSB0byBzb21ldGhpbmcgb3RoZXIgdGhhbiAnTm9uZSdcIik7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmZ1bmN0aW9uIHZhbGlkYXRlRW50aXR5U3RhdGVzKGVtOiBFbnRpdHlNYW5hZ2VyLCBlbnRpdHlTdGF0ZXM/OiBFbnRpdHlTdGF0ZSB8IEVudGl0eVN0YXRlW10pIHtcclxuICBpZiAoIWVudGl0eVN0YXRlcykgcmV0dXJuIFtdIGFzIEVudGl0eVN0YXRlW107XHJcbiAgbGV0IGVudFN0YXRlcyA9IGNvcmUudG9BcnJheShlbnRpdHlTdGF0ZXMpIGFzIEVudGl0eVN0YXRlW107XHJcbiAgZW50U3RhdGVzLmZvckVhY2goKGVzKSA9PiB7XHJcbiAgICBpZiAoIShlcyBpbnN0YW5jZW9mIEVudGl0eVN0YXRlKSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUaGUgRW50aXR5TWFuYWdlci5nZXRDaGFuZ2VzKCkgJ2VudGl0eVN0YXRlcycgcGFyYW1ldGVyIG11c3QgZWl0aGVyIGJlIG51bGwsIGFuIGVudGl0eVN0YXRlIG9yIGFuIGFycmF5IG9mIGVudGl0eVN0YXRlc1wiKTtcclxuICAgIH1cclxuICB9KTtcclxuICByZXR1cm4gZW50U3RhdGVzO1xyXG59XHJcblxyXG5mdW5jdGlvbiBhdHRhY2hSZWxhdGVkRW50aXRpZXMoZW06IEVudGl0eU1hbmFnZXIsIGVudGl0eTogRW50aXR5LCBlbnRpdHlTdGF0ZTogRW50aXR5U3RhdGUsIG1lcmdlU3RyYXRlZ3k6IE1lcmdlU3RyYXRlZ3kpIHtcclxuICBsZXQgbmF2UHJvcHMgPSBlbnRpdHkuZW50aXR5VHlwZS5uYXZpZ2F0aW9uUHJvcGVydGllcztcclxuICBuYXZQcm9wcy5mb3JFYWNoKGZ1bmN0aW9uIChucCkge1xyXG4gICAgbGV0IHJlbGF0ZWQgPSBlbnRpdHkuZ2V0UHJvcGVydHkobnAubmFtZSk7XHJcbiAgICBpZiAobnAuaXNTY2FsYXIpIHtcclxuICAgICAgaWYgKCFyZWxhdGVkKSByZXR1cm47XHJcbiAgICAgIGVtLmF0dGFjaEVudGl0eShyZWxhdGVkLCBlbnRpdHlTdGF0ZSwgbWVyZ2VTdHJhdGVneSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZWxhdGVkLmZvckVhY2goZnVuY3Rpb24gKGU6IEVudGl0eSkge1xyXG4gICAgICAgIGVtLmF0dGFjaEVudGl0eShlLCBlbnRpdHlTdGF0ZSwgbWVyZ2VTdHJhdGVneSk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vLyByZXR1cm5zIGEgcHJvbWlzZVxyXG5mdW5jdGlvbiBleGVjdXRlUXVlcnlDb3JlKGVtOiBFbnRpdHlNYW5hZ2VyLCBxdWVyeTogRW50aXR5UXVlcnkgfCBzdHJpbmcsIHF1ZXJ5T3B0aW9uczogUXVlcnlPcHRpb25zLCBkYXRhU2VydmljZTogRGF0YVNlcnZpY2UpOiBQcm9taXNlPFF1ZXJ5UmVzdWx0PiB7XHJcbiAgdHJ5IHtcclxuICAgIGxldCByZXN1bHRzOiBhbnlbXTtcclxuICAgIGxldCBtZXRhZGF0YVN0b3JlID0gZW0ubWV0YWRhdGFTdG9yZTtcclxuXHJcbiAgICBpZiAobWV0YWRhdGFTdG9yZS5pc0VtcHR5KCkgJiYgZGF0YVNlcnZpY2UuaGFzU2VydmVyTWV0YWRhdGEpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiY2Fubm90IGV4ZWN1dGUgX2V4ZWN1dGVRdWVyeUNvcmUgdW50aWwgbWV0YWRhdGFTdG9yZSBpcyBwb3B1bGF0ZWQuXCIpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChxdWVyeU9wdGlvbnMuZmV0Y2hTdHJhdGVneSA9PT0gRmV0Y2hTdHJhdGVneS5Gcm9tTG9jYWxDYWNoZSkge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGlmICh0eXBlb2YgcXVlcnkgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJjYW5ub3QgZXhlY3V0ZSAnc3RyaW5nJyBFbnRpdHlRdWVyeSBsb2NhbGx5LlwiKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgbGV0IHFyID0gZXhlY3V0ZVF1ZXJ5TG9jYWxseUNvcmUoZW0sIHF1ZXJ5KTtcclxuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHsgcmVzdWx0czogcXIucmVzdWx0cywgZW50aXR5TWFuYWdlcjogZW0sIGlubGluZUNvdW50OiBxci5pbmxpbmVDb3VudCwgcXVlcnk6IHF1ZXJ5IH0pO1xyXG4gICAgICB9IGNhdGNoIChlKSB7XHJcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KGUpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgbGV0IG1hcHBpbmdDb250ZXh0OiBNYXBwaW5nQ29udGV4dCB8IHVuZGVmaW5lZCA9IG5ldyBNYXBwaW5nQ29udGV4dCh7XHJcbiAgICAgIHF1ZXJ5OiBxdWVyeSxcclxuICAgICAgZW50aXR5TWFuYWdlcjogZW0sXHJcbiAgICAgIGRhdGFTZXJ2aWNlOiBkYXRhU2VydmljZSxcclxuICAgICAgbWVyZ2VPcHRpb25zOiB7XHJcbiAgICAgICAgbWVyZ2VTdHJhdGVneTogcXVlcnlPcHRpb25zLm1lcmdlU3RyYXRlZ3ksXHJcbiAgICAgICAgbm9UcmFja2luZzogISEocXVlcnkgYXMgYW55KS5ub1RyYWNraW5nRW5hYmxlZCxcclxuICAgICAgICBpbmNsdWRlRGVsZXRlZDogcXVlcnlPcHRpb25zLmluY2x1ZGVEZWxldGVkXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIGxldCB2YWxpZGF0ZU9uUXVlcnkgPSBlbS52YWxpZGF0aW9uT3B0aW9ucy52YWxpZGF0ZU9uUXVlcnk7XHJcblxyXG4gICAgcmV0dXJuIGRhdGFTZXJ2aWNlLmFkYXB0ZXJJbnN0YW5jZSEuZXhlY3V0ZVF1ZXJ5KG1hcHBpbmdDb250ZXh0KS50aGVuKGZ1bmN0aW9uIChkYXRhOiBhbnkpIHtcclxuICAgICAgbGV0IHJlc3VsdCA9IGNvcmUud3JhcEV4ZWN1dGlvbihmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgbGV0IHN0YXRlID0geyBpc0xvYWRpbmc6IGVtLmlzTG9hZGluZyB9O1xyXG4gICAgICAgIGVtLmlzTG9hZGluZyA9IHRydWU7XHJcbiAgICAgICAgZW0uX3BlbmRpbmdQdWJzID0gW107XHJcbiAgICAgICAgcmV0dXJuIHN0YXRlO1xyXG4gICAgICB9LCBmdW5jdGlvbiAoc3RhdGUpIHtcclxuICAgICAgICAvLyBjbGVhbnVwXHJcbiAgICAgICAgZW0uaXNMb2FkaW5nID0gc3RhdGUuaXNMb2FkaW5nO1xyXG4gICAgICAgIGVtLl9wZW5kaW5nUHVicyEuZm9yRWFjaChmdW5jdGlvbiAoZm4pIHtcclxuICAgICAgICAgIGZuKCk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgZW0uX3BlbmRpbmdQdWJzID0gdW5kZWZpbmVkO1xyXG4gICAgICAgIGVtLl9oYXNDaGFuZ2VzQWN0aW9uICYmIGVtLl9oYXNDaGFuZ2VzQWN0aW9uKCk7XHJcbiAgICAgICAgLy8gVE9ETzogcmVtb3ZlZCAtIG5vdCBzdXJlIHdoeSBuZWVkZWQgaW4gZmlyc3QgcGxhY2UuLi5cclxuICAgICAgICAvLyAvLyBIQUNLIGZvciBHQ1xyXG4gICAgICAgIC8vIHF1ZXJ5ID0gdW5kZWZpbmVkO1xyXG4gICAgICAgIG1hcHBpbmdDb250ZXh0ID0gdW5kZWZpbmVkO1xyXG4gICAgICAgIC8vIEhBQ0s6IHNvbWUgZXJyb3JzIHRocm93biBpbiBuZXh0IGZ1bmN0aW9uIGRvIG5vdCBwcm9wb2dhdGUgcHJvcGVybHkgLSB0aGlzIGNhdGNoZXMgdGhlbS5cclxuXHJcbiAgICAgICAgaWYgKHN0YXRlLmVycm9yKSB7XHJcbiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3Qoc3RhdGUuZXJyb3IpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgIH0sIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICBsZXQgbm9kZXMgPSBkYXRhU2VydmljZS5qc29uUmVzdWx0c0FkYXB0ZXIuZXh0cmFjdFJlc3VsdHMoZGF0YSk7XHJcbiAgICAgICAgbm9kZXMgPSBjb3JlLnRvQXJyYXkobm9kZXMpO1xyXG5cclxuICAgICAgICByZXN1bHRzID0gbWFwcGluZ0NvbnRleHQhLnZpc2l0QW5kTWVyZ2Uobm9kZXMsIHsgbm9kZVR5cGU6IFwicm9vdFwiIH0pO1xyXG4gICAgICAgIGlmICh2YWxpZGF0ZU9uUXVlcnkpIHtcclxuICAgICAgICAgIHJlc3VsdHMuZm9yRWFjaChmdW5jdGlvbiAocjogYW55KSB7XHJcbiAgICAgICAgICAgIC8vIGFub24gdHlwZXMgYW5kIHNpbXBsZSB0eXBlcyB3aWxsIG5vdCBoYXZlIGFuIGVudGl0eUFzcGVjdC5cclxuICAgICAgICAgICAgci5lbnRpdHlBc3BlY3QgJiYgci5lbnRpdHlBc3BlY3QudmFsaWRhdGVFbnRpdHkoKTtcclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgICBtYXBwaW5nQ29udGV4dCEucHJvY2Vzc0RlZmVycmVkKCk7XHJcbiAgICAgICAgLy8gaWYgcXVlcnkgaGFzIGV4cGFuZCBjbGF1c2VzIHdhbGsgZWFjaCBvZiB0aGUgJ3Jlc3VsdHMnIGFuZCBtYXJrIHRoZSBleHBhbmRlZCBwcm9wcyBhcyBsb2FkZWQuXHJcbiAgICAgICAgaWYgKHF1ZXJ5IGluc3RhbmNlb2YgRW50aXR5UXVlcnkpIHtcclxuICAgICAgICAgIG1hcmtMb2FkZWROYXZQcm9wcyhyZXN1bHRzLCBxdWVyeSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCByZXRyaWV2ZWRFbnRpdGllcyA9IGNvcmUub2JqZWN0TWFwKG1hcHBpbmdDb250ZXh0IS5yZWZNYXApO1xyXG4gICAgICAgIHJldHVybiB7IHJlc3VsdHM6IHJlc3VsdHMsIHF1ZXJ5OiBxdWVyeSwgZW50aXR5TWFuYWdlcjogZW0sIGh0dHBSZXNwb25zZTogZGF0YS5odHRwUmVzcG9uc2UsIGlubGluZUNvdW50OiBkYXRhLmlubGluZUNvdW50LCByZXRyaWV2ZWRFbnRpdGllczogcmV0cmlldmVkRW50aXRpZXMgfTtcclxuICAgICAgfSk7XHJcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUocmVzdWx0KTtcclxuICAgIH0sIGZ1bmN0aW9uIChlOiBhbnkpIHtcclxuICAgICAgaWYgKGUpIHtcclxuICAgICAgICBlLnF1ZXJ5ID0gcXVlcnk7XHJcbiAgICAgICAgZS5lbnRpdHlNYW5hZ2VyID0gZW07XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KGUpO1xyXG4gICAgfSk7XHJcblxyXG4gIH0gY2F0Y2ggKGUpIHtcclxuICAgIGlmIChlKSB7XHJcbiAgICAgIGUucXVlcnkgPSBxdWVyeTtcclxuICAgIH1cclxuICAgIHJldHVybiBQcm9taXNlLnJlamVjdChlKTtcclxuICB9XHJcbn1cclxuXHJcbmZ1bmN0aW9uIG1hcmtMb2FkZWROYXZQcm9wcyhlbnRpdGllczogRW50aXR5W10sIHF1ZXJ5OiBFbnRpdHlRdWVyeSkge1xyXG4gIGlmIChxdWVyeS5ub1RyYWNraW5nRW5hYmxlZCkgcmV0dXJuO1xyXG4gIGxldCBleHBhbmRDbGF1c2UgPSBxdWVyeS5leHBhbmRDbGF1c2U7XHJcbiAgaWYgKGV4cGFuZENsYXVzZSA9PSBudWxsKSByZXR1cm47XHJcbiAgZXhwYW5kQ2xhdXNlLnByb3BlcnR5UGF0aHMuZm9yRWFjaChmdW5jdGlvbiAocHJvcGVydHlQYXRoKSB7XHJcbiAgICBsZXQgcHJvcE5hbWVzID0gcHJvcGVydHlQYXRoLnNwbGl0KCcuJyk7XHJcbiAgICBtYXJrTG9hZGVkTmF2UGF0aChlbnRpdGllcywgcHJvcE5hbWVzKTtcclxuICB9KTtcclxufVxyXG5cclxuZnVuY3Rpb24gbWFya0xvYWRlZE5hdlBhdGgoZW50aXRpZXM6IEVudGl0eVtdLCBwcm9wTmFtZXM6IHN0cmluZ1tdKSB7XHJcbiAgbGV0IHByb3BOYW1lID0gcHJvcE5hbWVzWzBdO1xyXG4gIGVudGl0aWVzLmZvckVhY2goKGVudGl0eSkgPT4ge1xyXG4gICAgbGV0IGVhID0gZW50aXR5LmVudGl0eUFzcGVjdDtcclxuICAgIGlmICghZWEpIHJldHVybjsgLy8gZW50aXR5IG1heSBub3QgYmUgYSAncmVhbCcgZW50aXR5IGluIHRoZSBjYXNlIG9mIGEgcHJvamVjdGlvbi5cclxuICAgIGVhLl9tYXJrQXNMb2FkZWQocHJvcE5hbWUpO1xyXG4gICAgaWYgKHByb3BOYW1lcy5sZW5ndGggPT09IDEpIHJldHVybjtcclxuICAgIGxldCBuZXh0ID0gZW50aXR5LmdldFByb3BlcnR5KHByb3BOYW1lKTtcclxuICAgIGlmICghbmV4dCkgcmV0dXJuOyAvLyBubyBjaGlsZHJlbiB0byBwcm9jZXNzLlxyXG4gICAgLy8gc3RyYW5nZSBsb2dpYyBiZWNhdXNlIG5vbnNjYWxhciBuYXYgdmFsdWVzIGFyZSBOT1QgcmVhbGx5IGFycmF5c1xyXG4gICAgLy8gb3RoZXJ3aXNlIHdlIGNvdWxkIHVzZSBBcnJheS5pc0FycmF5XHJcbiAgICBpZiAoIW5leHQuYXJyYXlDaGFuZ2VkKSBuZXh0ID0gW25leHRdO1xyXG4gICAgbWFya0xvYWRlZE5hdlBhdGgobmV4dCwgcHJvcE5hbWVzLnNsaWNlKDEpKTtcclxuICB9KTtcclxufVxyXG5cclxuZnVuY3Rpb24gdXBkYXRlQ29uY3VycmVuY3lQcm9wZXJ0aWVzKGVudGl0aWVzOiBFbnRpdHlbXSkge1xyXG4gIGxldCBjYW5kaWRhdGVzID0gZW50aXRpZXMuZmlsdGVyKChlKSA9PiB7XHJcbiAgICBlLmVudGl0eUFzcGVjdC5pc0JlaW5nU2F2ZWQgPSB0cnVlO1xyXG4gICAgcmV0dXJuIGUuZW50aXR5QXNwZWN0LmVudGl0eVN0YXRlLmlzTW9kaWZpZWQoKVxyXG4gICAgICAmJiBlLmVudGl0eVR5cGUuY29uY3VycmVuY3lQcm9wZXJ0aWVzLmxlbmd0aCA+IDA7XHJcblxyXG4gIH0pO1xyXG4gIGlmIChjYW5kaWRhdGVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xyXG4gIGNhbmRpZGF0ZXMuZm9yRWFjaChmdW5jdGlvbiAoYykge1xyXG4gICAgYy5lbnRpdHlUeXBlLmNvbmN1cnJlbmN5UHJvcGVydGllcy5mb3JFYWNoKGZ1bmN0aW9uIChjcCkge1xyXG4gICAgICB1cGRhdGVDb25jdXJyZW5jeVByb3BlcnR5KGMsIGNwKTtcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG5mdW5jdGlvbiB1cGRhdGVDb25jdXJyZW5jeVByb3BlcnR5KGVudGl0eTogRW50aXR5LCBwcm9wZXJ0eTogRGF0YVByb3BlcnR5KSB7XHJcbiAgLy8gY2hlY2sgaWYgcHJvcGVydHkgaGFzIGFscmVhZHkgYmVlbiB1cGRhdGVkXHJcbiAgaWYgKGVudGl0eS5lbnRpdHlBc3BlY3Qub3JpZ2luYWxWYWx1ZXNbcHJvcGVydHkubmFtZV0pIHJldHVybjtcclxuICBsZXQgdmFsdWUgPSBlbnRpdHkuZ2V0UHJvcGVydHkocHJvcGVydHkubmFtZSk7XHJcbiAgbGV0IGRhdGFUeXBlID0gcHJvcGVydHkuZGF0YVR5cGUgYXMgRGF0YVR5cGU7XHJcbiAgaWYgKCF2YWx1ZSkgdmFsdWUgPSBkYXRhVHlwZS5kZWZhdWx0VmFsdWU7XHJcbiAgaWYgKGRhdGFUeXBlLmlzTnVtZXJpYykge1xyXG4gICAgZW50aXR5LnNldFByb3BlcnR5KHByb3BlcnR5Lm5hbWUsIHZhbHVlICsgMSk7XHJcbiAgfSBlbHNlIGlmIChkYXRhVHlwZS5nZXRDb25jdXJyZW5jeVZhbHVlKSB7XHJcbiAgICAvLyBEYXRhVHlwZSBoYXMgaXRzIG93biBpbXBsZW1lbnRhdGlvblxyXG4gICAgbGV0IG5leHRWYWx1ZSA9IGRhdGFUeXBlLmdldENvbmN1cnJlbmN5VmFsdWUodmFsdWUpO1xyXG4gICAgZW50aXR5LnNldFByb3BlcnR5KHByb3BlcnR5Lm5hbWUsIG5leHRWYWx1ZSk7XHJcbiAgfSBlbHNlIGlmIChkYXRhVHlwZSA9PT0gRGF0YVR5cGUuQmluYXJ5KSB7XHJcbiAgICAvLyBiZXN0IGd1ZXNzIC0gdGhhdCB0aGlzIGlzIGEgdGltZXN0YW1wIGNvbHVtbiBhbmQgaXMgY29tcHV0ZWQgb24gdGhlIHNlcnZlciBkdXJpbmcgc2F2ZVxyXG4gICAgLy8gLSBzbyBubyBuZWVkIHRvIHNldCBpdCBoZXJlLlxyXG4gICAgcmV0dXJuO1xyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyB0aGlzIGp1c3QgbGVhdmVzIERhdGFUeXBlcyBvZiBCb29sZWFuLCBTdHJpbmcgYW5kIEJ5dGUgLSBub25lIG9mIHdoaWNoIHNob3VsZCBiZSB0aGVcclxuICAgIC8vIHR5cGUgZm9yIGEgY29uY3VycmVuY3kgY29sdW1uLlxyXG4gICAgLy8gTk9URTogdGhvdWdodCBhYm91dCBqdXN0IHJldHVybmluZyBoZXJlIGJ1dCB3b3VsZCByYXRoZXIgYmUgc2FmZSBmb3Igbm93LlxyXG4gICAgdGhyb3cgbmV3IEVycm9yKFwiVW5hYmxlIHRvIHVwZGF0ZSB0aGUgdmFsdWUgb2YgY29uY3VycmVuY3kgcHJvcGVydHkgYmVmb3JlIHNhdmluZzogXCIgKyBwcm9wZXJ0eS5uYW1lKTtcclxuICB9XHJcbn1cclxuXHJcblxyXG5mdW5jdGlvbiBmaW5kT3JDcmVhdGVFbnRpdHlHcm91cChlbTogRW50aXR5TWFuYWdlciwgZW50aXR5VHlwZTogRW50aXR5VHlwZSkge1xyXG4gIGxldCBncm91cCA9IGVtLl9lbnRpdHlHcm91cE1hcFtlbnRpdHlUeXBlLm5hbWVdO1xyXG4gIGlmICghZ3JvdXApIHtcclxuICAgIGdyb3VwID0gbmV3IEVudGl0eUdyb3VwKGVtLCBlbnRpdHlUeXBlKTtcclxuICAgIGVtLl9lbnRpdHlHcm91cE1hcFtlbnRpdHlUeXBlLm5hbWVdID0gZ3JvdXA7XHJcbiAgfVxyXG4gIHJldHVybiBncm91cDtcclxufVxyXG5cclxuZnVuY3Rpb24gZmluZE9yQ3JlYXRlRW50aXR5R3JvdXBzKGVtOiBFbnRpdHlNYW5hZ2VyLCBlbnRpdHlUeXBlOiBFbnRpdHlUeXBlKSB7XHJcbiAgbGV0IGVudGl0eVR5cGVzID0gZW50aXR5VHlwZS5nZXRTZWxmQW5kU3VidHlwZXMoKTtcclxuICByZXR1cm4gZW50aXR5VHlwZXMubWFwKChldCkgPT4ge1xyXG4gICAgcmV0dXJuIGZpbmRPckNyZWF0ZUVudGl0eUdyb3VwKGVtLCBldCk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIHVud3JhcEluc3RhbmNlKHN0cnVjdE9iajogU3RydWN0dXJhbE9iamVjdCwgdHJhbnNmb3JtRm4/OiAoZHA6IERhdGFQcm9wZXJ0eSwgdmFsOiBhbnkpID0+IGFueSkge1xyXG5cclxuICBsZXQgcmF3T2JqZWN0OiBhbnkgPSB7fTtcclxuICBsZXQgc3R5cGUgPSBFbnRpdHlBc3BlY3QuaXNFbnRpdHkoc3RydWN0T2JqKSA/IHN0cnVjdE9iai5lbnRpdHlUeXBlIDogc3RydWN0T2JqLmNvbXBsZXhUeXBlO1xyXG4gIGxldCBzZXJpYWxpemVyRm4gPSBnZXRTZXJpYWxpemVyRm4oc3R5cGUpO1xyXG4gIGxldCB1bm1hcHBlZCA9IHt9O1xyXG4gIHN0eXBlLmRhdGFQcm9wZXJ0aWVzLmZvckVhY2goZnVuY3Rpb24gKGRwKSB7XHJcbiAgICBpZiAoZHAuaXNDb21wbGV4UHJvcGVydHkpIHtcclxuICAgICAgcmF3T2JqZWN0W2RwLm5hbWVPblNlcnZlcl0gPSBjb3JlLm1hcChzdHJ1Y3RPYmouZ2V0UHJvcGVydHkoZHAubmFtZSksIGZ1bmN0aW9uIChjbykge1xyXG4gICAgICAgIHJldHVybiB1bndyYXBJbnN0YW5jZShjbywgdHJhbnNmb3JtRm4pO1xyXG4gICAgICB9KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxldCB2YWwgPSBzdHJ1Y3RPYmouZ2V0UHJvcGVydHkoZHAubmFtZSk7XHJcbiAgICAgIHZhbCA9IHRyYW5zZm9ybUZuID8gdHJhbnNmb3JtRm4oZHAsIHZhbCkgOiB2YWw7XHJcbiAgICAgIGlmICh2YWwgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xyXG4gICAgICB2YWwgPSBzZXJpYWxpemVyRm4gPyBzZXJpYWxpemVyRm4oZHAsIHZhbCkgOiB2YWw7XHJcbiAgICAgIGlmICh2YWwgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGlmIChkcC5pc1VubWFwcGVkKSB7XHJcbiAgICAgICAgICB1bm1hcHBlZFtkcC5uYW1lT25TZXJ2ZXJdID0gY29yZS50b0pTT05TYWZlKHZhbCwgY29yZS50b0pTT05TYWZlUmVwbGFjZXIpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICByYXdPYmplY3RbZHAubmFtZU9uU2VydmVyXSA9IHZhbDtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgaWYgKCFjb3JlLmlzRW1wdHkodW5tYXBwZWQpKSB7XHJcbiAgICAvLyBUT0RPOiByZXZpZXcgdGhpcy5cclxuICAgIChyYXdPYmplY3QgYXMgYW55KS5fX3VubWFwcGVkID0gdW5tYXBwZWQ7XHJcbiAgfVxyXG4gIHJldHVybiByYXdPYmplY3Q7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIHVud3JhcE9yaWdpbmFsVmFsdWVzKHRhcmdldDogU3RydWN0dXJhbE9iamVjdCwgbWV0YWRhdGFTdG9yZTogTWV0YWRhdGFTdG9yZSwgdHJhbnNmb3JtRm4/OiAoZHA6IERhdGFQcm9wZXJ0eSwgdmFsOiBhbnkpID0+IGFueSkge1xyXG4gIGxldCBzdHlwZSA9IEVudGl0eUFzcGVjdC5pc0VudGl0eSh0YXJnZXQpID8gdGFyZ2V0LmVudGl0eVR5cGUgOiB0YXJnZXQuY29tcGxleFR5cGU7XHJcbiAgbGV0IGFzcGVjdCA9IEVudGl0eUFzcGVjdC5pc0VudGl0eSh0YXJnZXQpID8gdGFyZ2V0LmVudGl0eUFzcGVjdCA6IHRhcmdldC5jb21wbGV4QXNwZWN0O1xyXG4gIGxldCBmbiA9IG1ldGFkYXRhU3RvcmUubmFtaW5nQ29udmVudGlvbi5jbGllbnRQcm9wZXJ0eU5hbWVUb1NlcnZlcjtcclxuICBsZXQgcmVzdWx0ID0ge30gYXMgUmVjb3JkPHN0cmluZywgYW55PjtcclxuICBjb3JlLm9iamVjdEZvckVhY2goYXNwZWN0Lm9yaWdpbmFsVmFsdWVzLCBmdW5jdGlvbiAocHJvcE5hbWUsIHZhbCkge1xyXG4gICAgbGV0IHByb3AgPSBzdHlwZS5nZXRQcm9wZXJ0eShwcm9wTmFtZSkgYXMgRGF0YVByb3BlcnR5O1xyXG4gICAgdmFsID0gdHJhbnNmb3JtRm4gPyB0cmFuc2Zvcm1Gbihwcm9wLCB2YWwpIDogdmFsO1xyXG4gICAgaWYgKHZhbCAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgIHJlc3VsdFtmbihwcm9wTmFtZSwgcHJvcCldID0gdmFsO1xyXG4gICAgfVxyXG4gIH0pO1xyXG4gIHN0eXBlLmNvbXBsZXhQcm9wZXJ0aWVzLmZvckVhY2goZnVuY3Rpb24gKGNwKSB7XHJcbiAgICBsZXQgbmV4dFRhcmdldCA9IHRhcmdldC5nZXRQcm9wZXJ0eShjcC5uYW1lKTtcclxuICAgIGlmIChjcC5pc1NjYWxhcikge1xyXG4gICAgICBsZXQgdW53cmFwcGVkQ28gPSB1bndyYXBPcmlnaW5hbFZhbHVlcyhuZXh0VGFyZ2V0LCBtZXRhZGF0YVN0b3JlLCB0cmFuc2Zvcm1Gbik7XHJcbiAgICAgIGlmICghY29yZS5pc0VtcHR5KHVud3JhcHBlZENvKSkge1xyXG4gICAgICAgIHJlc3VsdFtmbihjcC5uYW1lLCBjcCldID0gdW53cmFwcGVkQ287XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxldCB1bndyYXBwZWRDb3MgPSBuZXh0VGFyZ2V0Lm1hcCgoaXRlbTogYW55KSA9PiB7XHJcbiAgICAgICAgcmV0dXJuIHVud3JhcE9yaWdpbmFsVmFsdWVzKGl0ZW0sIG1ldGFkYXRhU3RvcmUsIHRyYW5zZm9ybUZuKTtcclxuICAgICAgfSk7XHJcbiAgICAgIHJlc3VsdFtmbihjcC5uYW1lLCBjcCldID0gdW53cmFwcGVkQ29zO1xyXG4gICAgfVxyXG4gIH0pO1xyXG4gIHJldHVybiByZXN1bHQ7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIHVud3JhcENoYW5nZWRWYWx1ZXMoZW50aXR5OiBFbnRpdHksIG1ldGFkYXRhU3RvcmU6IE1ldGFkYXRhU3RvcmUsIHRyYW5zZm9ybUZuOiAoZHA6IERhdGFQcm9wZXJ0eSwgdmFsOiBhbnkpID0+IGFueSkge1xyXG4gIGxldCBzdHlwZSA9IGVudGl0eS5lbnRpdHlUeXBlO1xyXG4gIGxldCBzZXJpYWxpemVyRm4gPSBnZXRTZXJpYWxpemVyRm4oc3R5cGUpO1xyXG4gIGxldCBmbiA9IG1ldGFkYXRhU3RvcmUubmFtaW5nQ29udmVudGlvbi5jbGllbnRQcm9wZXJ0eU5hbWVUb1NlcnZlcjtcclxuICBsZXQgcmVzdWx0ID0ge30gYXMgUmVjb3JkPHN0cmluZywgYW55PjtcclxuICBjb3JlLm9iamVjdEZvckVhY2goZW50aXR5LmVudGl0eUFzcGVjdC5vcmlnaW5hbFZhbHVlcywgZnVuY3Rpb24gKHByb3BOYW1lLCB2YWx1ZSkge1xyXG4gICAgbGV0IHByb3AgPSBzdHlwZS5nZXRQcm9wZXJ0eShwcm9wTmFtZSkgYXMgRGF0YVByb3BlcnR5O1xyXG4gICAgbGV0IHZhbCA9IGVudGl0eS5nZXRQcm9wZXJ0eShwcm9wTmFtZSk7XHJcbiAgICB2YWwgPSB0cmFuc2Zvcm1GbiA/IHRyYW5zZm9ybUZuKHByb3AsIHZhbCkgOiB2YWw7XHJcbiAgICBpZiAodmFsID09PSB1bmRlZmluZWQpIHJldHVybjtcclxuICAgIHZhbCA9IHNlcmlhbGl6ZXJGbiA/IHNlcmlhbGl6ZXJGbihwcm9wLCB2YWwpIDogdmFsO1xyXG4gICAgaWYgKHZhbCAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgIHJlc3VsdFtmbihwcm9wTmFtZSwgcHJvcCldID0gdmFsO1xyXG4gICAgfVxyXG4gIH0pO1xyXG4gIC8vIGFueSBjaGFuZ2UgdG8gYW55IGNvbXBsZXggb2JqZWN0IG9yIGFycmF5IG9mIGNvbXBsZXggb2JqZWN0cyByZXR1cm5zIHRoZSBFTlRJUkVcclxuICAvLyBjdXJyZW50IGNvbXBsZXggb2JqZWN0IG9yIGNvbXBsZXggb2JqZWN0IGFycmF5LiAgVGhpcyBpcyBieSBkZXNpZ24uIENvbXBsZXggT2JqZWN0c1xyXG4gIC8vIGFyZSBhdG9taWMuXHJcbiAgc3R5cGUuY29tcGxleFByb3BlcnRpZXMuZm9yRWFjaCgoY3ApID0+IHtcclxuICAgIGlmIChjcEhhc09yaWdpbmFsVmFsdWVzKGVudGl0eSwgY3ApKSB7XHJcbiAgICAgIGxldCBjb09yQ29zID0gZW50aXR5LmdldFByb3BlcnR5KGNwLm5hbWUpO1xyXG4gICAgICByZXN1bHRbZm4oY3AubmFtZSwgY3ApXSA9IGNvcmUubWFwKGNvT3JDb3MsIGZ1bmN0aW9uIChjbykge1xyXG4gICAgICAgIHJldHVybiB1bndyYXBJbnN0YW5jZShjbywgdHJhbnNmb3JtRm4pO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9KTtcclxuICByZXR1cm4gcmVzdWx0O1xyXG59XHJcblxyXG5mdW5jdGlvbiBjcEhhc09yaWdpbmFsVmFsdWVzKHN0cnVjdHVyYWxPYmplY3Q6IFN0cnVjdHVyYWxPYmplY3QsIGNwOiBEYXRhUHJvcGVydHkpOiBib29sZWFuIHtcclxuICBsZXQgY29PckNvcyA9IHN0cnVjdHVyYWxPYmplY3QuZ2V0UHJvcGVydHkoY3AubmFtZSk7XHJcbiAgaWYgKGNwLmlzU2NhbGFyKSB7XHJcbiAgICByZXR1cm4gY29IYXNPcmlnaW5hbFZhbHVlcyhjb09yQ29zKTtcclxuICB9IGVsc2Uge1xyXG4gICAgLy8gdGhpcyBvY2N1cnMgd2hlbiBhIG5vbnNjYWxhciBjbyBhcnJheSBoYXMgaGFkIGNvcyBhZGRlZCBvciByZW1vdmVkLlxyXG4gICAgaWYgKGNvT3JDb3MuX29yaWdWYWx1ZXMpIHJldHVybiB0cnVlO1xyXG4gICAgcmV0dXJuIGNvT3JDb3Muc29tZShmdW5jdGlvbiAoY286IENvbXBsZXhPYmplY3QpIHtcclxuICAgICAgcmV0dXJuIGNvSGFzT3JpZ2luYWxWYWx1ZXMoY28pO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59XHJcblxyXG5mdW5jdGlvbiBleGVjdXRlUXVlcnlMb2NhbGx5Q29yZShlbTogRW50aXR5TWFuYWdlciwgcXVlcnk6IEVudGl0eVF1ZXJ5KSB7XHJcbiAgYXNzZXJ0UGFyYW0ocXVlcnksIFwicXVlcnlcIikuaXNJbnN0YW5jZU9mKEVudGl0eVF1ZXJ5KS5jaGVjaygpO1xyXG5cclxuICBsZXQgbWV0YWRhdGFTdG9yZSA9IGVtLm1ldGFkYXRhU3RvcmU7XHJcbiAgbGV0IGVudGl0eVR5cGUgPSBxdWVyeS5fZ2V0RnJvbUVudGl0eVR5cGUobWV0YWRhdGFTdG9yZSwgdHJ1ZSk7XHJcbiAgLy8gdGhlcmUgbWF5IGJlIG11bHRpcGxlIGdyb3VwcyBpcyB0aGlzIGlzIGEgYmFzZSBlbnRpdHkgdHlwZS5cclxuICBsZXQgZ3JvdXBzID0gZmluZE9yQ3JlYXRlRW50aXR5R3JvdXBzKGVtLCBlbnRpdHlUeXBlISk7XHJcbiAgLy8gZmlsdGVyIHRoZW4gb3JkZXIgdGhlbiBza2lwIHRoZW4gdGFrZVxyXG4gIGxldCBmaWx0ZXJGdW5jID0gcXVlcnkud2hlcmVQcmVkaWNhdGUgJiYgcXVlcnkud2hlcmVQcmVkaWNhdGUudG9GdW5jdGlvbih7IGVudGl0eVR5cGU6IGVudGl0eVR5cGUgfSk7XHJcblxyXG4gIGxldCBxdWVyeU9wdGlvbnMgPSBRdWVyeU9wdGlvbnMucmVzb2x2ZShbcXVlcnkucXVlcnlPcHRpb25zLCBlbS5xdWVyeU9wdGlvbnMsIFF1ZXJ5T3B0aW9ucy5kZWZhdWx0SW5zdGFuY2VdKTtcclxuICBsZXQgaW5jbHVkZURlbGV0ZWQgPSBxdWVyeU9wdGlvbnMuaW5jbHVkZURlbGV0ZWQgPT09IHRydWU7XHJcblxyXG4gIGxldCBuZXdGaWx0ZXJGdW5jID0gZnVuY3Rpb24gKGVudGl0eTogRW50aXR5KSB7XHJcbiAgICByZXR1cm4gZW50aXR5ICYmIChpbmNsdWRlRGVsZXRlZCB8fCAhZW50aXR5LmVudGl0eUFzcGVjdC5lbnRpdHlTdGF0ZS5pc0RlbGV0ZWQoKSkgJiYgKGZpbHRlckZ1bmMgPyBmaWx0ZXJGdW5jKGVudGl0eSkgOiB0cnVlKTtcclxuICB9O1xyXG5cclxuICBsZXQgcmVzdWx0OiBhbnlbXSA9IFtdO1xyXG4gIC8vIFRPRE86IG1hcE1hbnlcclxuICBncm91cHMuZm9yRWFjaCgoZ3JvdXApID0+IHtcclxuICAgIGxldCBlbnRpdGllcyA9IGdyb3VwLl9lbnRpdGllcy5maWx0ZXIobmV3RmlsdGVyRnVuYykgYXMgRW50aXR5W107XHJcbiAgICBpZiAoZW50aXRpZXMubGVuZ3RoKSB7XHJcbiAgICAgIHJlc3VsdCA9IHJlc3VsdC5sZW5ndGggPyByZXN1bHQuY29uY2F0KGVudGl0aWVzKSA6IGVudGl0aWVzO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICBsZXQgb3JkZXJCeUNvbXBhcmVyID0gcXVlcnkub3JkZXJCeUNsYXVzZSAmJiBxdWVyeS5vcmRlckJ5Q2xhdXNlLmdldENvbXBhcmVyKGVudGl0eVR5cGUhKTtcclxuICBpZiAob3JkZXJCeUNvbXBhcmVyKSB7XHJcbiAgICByZXN1bHQuc29ydChvcmRlckJ5Q29tcGFyZXIpO1xyXG4gIH1cclxuXHJcbiAgbGV0IGlubGluZUNvdW50ID0gcXVlcnkuaW5saW5lQ291bnRFbmFibGVkID8gcmVzdWx0Lmxlbmd0aCA6IHVuZGVmaW5lZDtcclxuXHJcbiAgbGV0IHNraXBDb3VudCA9IHF1ZXJ5LnNraXBDb3VudDtcclxuICBpZiAoc2tpcENvdW50KSB7XHJcbiAgICByZXN1bHQgPSByZXN1bHQuc2xpY2Uoc2tpcENvdW50KTtcclxuICB9XHJcbiAgbGV0IHRha2VDb3VudCA9IHF1ZXJ5LnRha2VDb3VudDtcclxuICBpZiAodGFrZUNvdW50KSB7XHJcbiAgICByZXN1bHQgPSByZXN1bHQuc2xpY2UoMCwgdGFrZUNvdW50KTtcclxuICB9XHJcblxyXG4gIGxldCBzZWxlY3RDbGF1c2UgPSBxdWVyeS5zZWxlY3RDbGF1c2U7XHJcbiAgaWYgKHNlbGVjdENsYXVzZSkge1xyXG4gICAgbGV0IHNlbGVjdEZuID0gc2VsZWN0Q2xhdXNlLnRvRnVuY3Rpb24oKTtcclxuICAgIHJlc3VsdCA9IHJlc3VsdC5tYXAoc2VsZWN0Rm4pO1xyXG4gIH1cclxuICByZXR1cm4geyByZXN1bHRzOiByZXN1bHQsIGlubGluZUNvdW50OiBpbmxpbmVDb3VudCB9O1xyXG59XHJcblxyXG5mdW5jdGlvbiBjb0hhc09yaWdpbmFsVmFsdWVzKGNvOiBDb21wbGV4T2JqZWN0KSB7XHJcbiAgLy8gbmV4dCBsaW5lIGNoZWNrcyBhbGwgbm9uIGNvbXBsZXggcHJvcGVydGllcyBvZiB0aGUgY28uXHJcbiAgaWYgKCFjb3JlLmlzRW1wdHkoY28uY29tcGxleEFzcGVjdC5vcmlnaW5hbFZhbHVlcykpIHJldHVybiB0cnVlO1xyXG4gIC8vIG5vdyBuZWVkIHRvIHJlY3Vyc2l2ZWx5IGNoZWNrIGVhY2ggb2YgdGhlIGNwc1xyXG4gIHJldHVybiBjby5jb21wbGV4VHlwZS5jb21wbGV4UHJvcGVydGllcy5zb21lKGZ1bmN0aW9uIChjcCkge1xyXG4gICAgcmV0dXJuIGNwSGFzT3JpZ2luYWxWYWx1ZXMoY28sIGNwKTtcclxuICB9KTtcclxufVxyXG5cclxuZnVuY3Rpb24gZ2V0U2VyaWFsaXplckZuKHN0eXBlOiBFbnRpdHlUeXBlIHwgQ29tcGxleFR5cGUpIHtcclxuICByZXR1cm4gc3R5cGUuc2VyaWFsaXplckZuIHx8IChzdHlwZS5tZXRhZGF0YVN0b3JlICYmIHN0eXBlLm1ldGFkYXRhU3RvcmUuc2VyaWFsaXplckZuKTtcclxufVxyXG5cclxuIl19
|