breeze-client 2.1.2 → 2.1.3-mjs
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/adapter-ajax-angularjs/{breeze-client-adapter-ajax-angularjs.d.ts → index.d.ts} +1 -0
- package/adapter-ajax-fetch/{breeze-client-adapter-ajax-fetch.d.ts → index.d.ts} +1 -0
- package/adapter-ajax-httpclient/{breeze-client-adapter-ajax-httpclient.d.ts → index.d.ts} +1 -0
- package/adapter-ajax-jquery/{breeze-client-adapter-ajax-jquery.d.ts → index.d.ts} +1 -0
- package/adapter-ajax-post/{breeze-client-adapter-ajax-post.d.ts → index.d.ts} +1 -0
- package/adapter-data-service-odata/{breeze-client-adapter-data-service-odata.d.ts → index.d.ts} +1 -0
- package/adapter-data-service-webapi/{breeze-client-adapter-data-service-webapi.d.ts → index.d.ts} +1 -0
- package/adapter-model-library-backing-store/{breeze-client-adapter-model-library-backing-store.d.ts → index.d.ts} +1 -0
- package/adapter-model-library-ko/{breeze-client-adapter-model-library-ko.d.ts → index.d.ts} +1 -0
- package/adapter-uri-builder-json/{breeze-client-adapter-uri-builder-json.d.ts → index.d.ts} +1 -0
- package/adapter-uri-builder-odata/{breeze-client-adapter-uri-builder-odata.d.ts → index.d.ts} +1 -0
- package/esm2020/adapter-ajax-angularjs/adapter-ajax-angularjs.mjs +130 -0
- package/esm2020/adapter-ajax-angularjs/adapter-core.mjs +49 -0
- package/esm2020/adapter-ajax-angularjs/breeze-client-adapter-ajax-angularjs.mjs +5 -0
- package/esm2020/adapter-ajax-fetch/adapter-ajax-fetch.mjs +132 -0
- package/esm2020/adapter-ajax-fetch/adapter-core.mjs +49 -0
- package/esm2020/adapter-ajax-fetch/breeze-client-adapter-ajax-fetch.mjs +5 -0
- package/esm2020/adapter-ajax-httpclient/adapter-ajax-httpclient.mjs +137 -0
- package/esm2020/adapter-ajax-httpclient/adapter-core.mjs +49 -0
- package/esm2020/adapter-ajax-httpclient/breeze-client-adapter-ajax-httpclient.mjs +5 -0
- package/esm2020/adapter-ajax-jquery/adapter-ajax-jquery.mjs +103 -0
- package/esm2020/adapter-ajax-jquery/breeze-client-adapter-ajax-jquery.mjs +5 -0
- package/esm2020/adapter-ajax-post/adapter-ajax-post.mjs +77 -0
- package/esm2020/adapter-ajax-post/breeze-client-adapter-ajax-post.mjs +5 -0
- package/esm2020/adapter-data-service-odata/adapter-core.mjs +49 -0
- package/esm2020/adapter-data-service-odata/adapter-data-service-odata.mjs +456 -0
- package/esm2020/adapter-data-service-odata/breeze-client-adapter-data-service-odata.mjs +5 -0
- package/esm2020/adapter-data-service-webapi/adapter-data-service-webapi.mjs +93 -0
- package/esm2020/adapter-data-service-webapi/breeze-client-adapter-data-service-webapi.mjs +5 -0
- package/esm2020/adapter-model-library-backing-store/adapter-model-library-backing-store.mjs +268 -0
- package/esm2020/adapter-model-library-backing-store/breeze-client-adapter-model-library-backing-store.mjs +5 -0
- package/esm2020/adapter-model-library-ko/adapter-model-library-ko.mjs +240 -0
- package/esm2020/adapter-model-library-ko/breeze-client-adapter-model-library-ko.mjs +5 -0
- package/esm2020/adapter-uri-builder-json/adapter-core.mjs +49 -0
- package/esm2020/adapter-uri-builder-json/adapter-uri-builder-json.mjs +36 -0
- package/esm2020/adapter-uri-builder-json/breeze-client-adapter-uri-builder-json.mjs +5 -0
- package/esm2020/adapter-uri-builder-odata/adapter-core.mjs +49 -0
- package/esm2020/adapter-uri-builder-odata/adapter-uri-builder-odata.mjs +190 -0
- package/esm2020/adapter-uri-builder-odata/breeze-client-adapter-uri-builder-odata.mjs +5 -0
- package/esm2020/breeze-client.mjs +5 -0
- package/esm2020/index.mjs +2 -0
- package/esm2020/mixin-get-entity-graph/breeze-client-mixin-get-entity-graph.mjs +5 -0
- package/esm2020/mixin-get-entity-graph/mixin-get-entity-graph.mjs +269 -0
- package/esm2020/mixin-save-queuing/breeze-client-mixin-save-queuing.mjs +5 -0
- package/esm2020/mixin-save-queuing/mixin-save-queuing.mjs +400 -0
- package/esm2020/src/abstract-data-service-adapter.mjs +296 -0
- package/esm2020/src/array.mjs +4 -0
- package/esm2020/src/assert-param.mjs +312 -0
- package/esm2020/src/breeze.mjs +85 -0
- package/esm2020/src/complex-array.mjs +117 -0
- package/esm2020/src/config.mjs +223 -0
- package/esm2020/src/core.mjs +707 -0
- package/esm2020/src/csdl-metadata-parser.mjs +385 -0
- package/esm2020/src/data-service.mjs +203 -0
- package/esm2020/src/data-type.mjs +444 -0
- package/esm2020/src/default-property-interceptor.mjs +460 -0
- package/esm2020/src/entity-action.mjs +45 -0
- package/esm2020/src/entity-aspect.mjs +806 -0
- package/esm2020/src/entity-group.mjs +187 -0
- package/esm2020/src/entity-key.mjs +116 -0
- package/esm2020/src/entity-manager.mjs +2094 -0
- package/esm2020/src/entity-metadata.mjs +2109 -0
- package/esm2020/src/entity-query.mjs +996 -0
- package/esm2020/src/entity-state.mjs +99 -0
- package/esm2020/src/enum.mjs +141 -0
- package/esm2020/src/event.mjs +256 -0
- package/esm2020/src/interface-registry.mjs +41 -0
- package/esm2020/src/key-generator.mjs +108 -0
- package/esm2020/src/local-query-comparison-options.mjs +65 -0
- package/esm2020/src/mapping-context.mjs +405 -0
- package/esm2020/src/naming-convention.mjs +88 -0
- package/esm2020/src/observable-array.mjs +183 -0
- package/esm2020/src/predicate.mjs +1232 -0
- package/esm2020/src/primitive-array.mjs +85 -0
- package/esm2020/src/query-options.mjs +152 -0
- package/esm2020/src/relation-array.mjs +173 -0
- package/esm2020/src/save-options.mjs +41 -0
- package/esm2020/src/unattached-children-map.mjs +58 -0
- package/esm2020/src/validate.mjs +988 -0
- package/esm2020/src/validation-options.mjs +64 -0
- package/fesm2015/{breeze-client-adapter-ajax-angularjs.js → breeze-client-adapter-ajax-angularjs.mjs} +1 -1
- package/fesm2015/breeze-client-adapter-ajax-angularjs.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-ajax-fetch.js → breeze-client-adapter-ajax-fetch.mjs} +5 -3
- package/fesm2015/breeze-client-adapter-ajax-fetch.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-ajax-httpclient.js → breeze-client-adapter-ajax-httpclient.mjs} +1 -1
- package/fesm2015/breeze-client-adapter-ajax-httpclient.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-ajax-jquery.js → breeze-client-adapter-ajax-jquery.mjs} +2 -2
- package/fesm2015/breeze-client-adapter-ajax-jquery.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-ajax-post.js → breeze-client-adapter-ajax-post.mjs} +1 -1
- package/fesm2015/breeze-client-adapter-ajax-post.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-data-service-odata.js → breeze-client-adapter-data-service-odata.mjs} +20 -22
- package/fesm2015/breeze-client-adapter-data-service-odata.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-data-service-webapi.js → breeze-client-adapter-data-service-webapi.mjs} +13 -13
- package/fesm2015/breeze-client-adapter-data-service-webapi.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-model-library-backing-store.js → breeze-client-adapter-model-library-backing-store.mjs} +13 -13
- package/fesm2015/breeze-client-adapter-model-library-backing-store.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-model-library-ko.js → breeze-client-adapter-model-library-ko.mjs} +13 -13
- package/fesm2015/breeze-client-adapter-model-library-ko.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-uri-builder-json.js → breeze-client-adapter-uri-builder-json.mjs} +8 -8
- package/fesm2015/breeze-client-adapter-uri-builder-json.mjs.map +1 -0
- package/fesm2015/{breeze-client-adapter-uri-builder-odata.js → breeze-client-adapter-uri-builder-odata.mjs} +85 -86
- package/fesm2015/breeze-client-adapter-uri-builder-odata.mjs.map +1 -0
- package/fesm2015/{breeze-client-mixin-get-entity-graph.js → breeze-client-mixin-get-entity-graph.mjs} +1 -1
- package/fesm2015/breeze-client-mixin-get-entity-graph.mjs.map +1 -0
- package/fesm2015/{breeze-client-mixin-save-queuing.js → breeze-client-mixin-save-queuing.mjs} +1 -1
- package/fesm2015/breeze-client-mixin-save-queuing.mjs.map +1 -0
- package/fesm2015/{breeze-client.js → breeze-client.mjs} +417 -422
- package/fesm2015/breeze-client.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-ajax-angularjs.js → fesm2020/breeze-client-adapter-ajax-angularjs.mjs} +41 -42
- package/fesm2020/breeze-client-adapter-ajax-angularjs.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-ajax-fetch.js → fesm2020/breeze-client-adapter-ajax-fetch.mjs} +44 -43
- package/fesm2020/breeze-client-adapter-ajax-fetch.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-ajax-httpclient.js → fesm2020/breeze-client-adapter-ajax-httpclient.mjs} +43 -44
- package/fesm2020/breeze-client-adapter-ajax-httpclient.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-ajax-jquery.js → fesm2020/breeze-client-adapter-ajax-jquery.mjs} +18 -19
- package/fesm2020/breeze-client-adapter-ajax-jquery.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-ajax-post.js → fesm2020/breeze-client-adapter-ajax-post.mjs} +8 -11
- package/fesm2020/breeze-client-adapter-ajax-post.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-data-service-odata.js → fesm2020/breeze-client-adapter-data-service-odata.mjs} +126 -134
- package/fesm2020/breeze-client-adapter-data-service-odata.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-data-service-webapi.js → fesm2020/breeze-client-adapter-data-service-webapi.mjs} +38 -42
- package/fesm2020/breeze-client-adapter-data-service-webapi.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-model-library-backing-store.js → fesm2020/breeze-client-adapter-model-library-backing-store.mjs} +63 -64
- package/fesm2020/breeze-client-adapter-model-library-backing-store.mjs.map +1 -0
- package/{fesm5/breeze-client-adapter-model-library-ko.js → fesm2020/breeze-client-adapter-model-library-ko.mjs} +57 -58
- package/fesm2020/breeze-client-adapter-model-library-ko.mjs.map +1 -0
- package/fesm2020/breeze-client-adapter-uri-builder-json.mjs +91 -0
- package/fesm2020/breeze-client-adapter-uri-builder-json.mjs.map +1 -0
- package/fesm2020/breeze-client-adapter-uri-builder-odata.mjs +245 -0
- package/fesm2020/breeze-client-adapter-uri-builder-odata.mjs.map +1 -0
- package/{fesm5/breeze-client-mixin-get-entity-graph.js → fesm2020/breeze-client-mixin-get-entity-graph.mjs} +45 -45
- package/fesm2020/breeze-client-mixin-get-entity-graph.mjs.map +1 -0
- package/{fesm5/breeze-client-mixin-save-queuing.js → fesm2020/breeze-client-mixin-save-queuing.mjs} +116 -126
- package/fesm2020/breeze-client-mixin-save-queuing.mjs.map +1 -0
- package/{fesm5/breeze-client.js → fesm2020/breeze-client.mjs} +3403 -3615
- package/fesm2020/breeze-client.mjs.map +1 -0
- package/mixin-get-entity-graph/{breeze-client-mixin-get-entity-graph.d.ts → index.d.ts} +1 -0
- package/mixin-save-queuing/{breeze-client-mixin-save-queuing.d.ts → index.d.ts} +1 -0
- package/package.json +126 -12
- package/src/entity-metadata.d.ts +6 -4
- package/src/entity-query.d.ts +1 -1
- package/adapter-ajax-angularjs/breeze-client-adapter-ajax-angularjs.metadata.json +0 -1
- package/adapter-ajax-angularjs/package.json +0 -13
- package/adapter-ajax-fetch/breeze-client-adapter-ajax-fetch.metadata.json +0 -1
- package/adapter-ajax-fetch/package.json +0 -13
- package/adapter-ajax-httpclient/breeze-client-adapter-ajax-httpclient.metadata.json +0 -1
- package/adapter-ajax-httpclient/package.json +0 -17
- package/adapter-ajax-jquery/breeze-client-adapter-ajax-jquery.metadata.json +0 -1
- package/adapter-ajax-jquery/package.json +0 -13
- package/adapter-ajax-post/breeze-client-adapter-ajax-post.metadata.json +0 -1
- package/adapter-ajax-post/package.json +0 -13
- package/adapter-data-service-odata/breeze-client-adapter-data-service-odata.metadata.json +0 -1
- package/adapter-data-service-odata/package.json +0 -13
- package/adapter-data-service-webapi/breeze-client-adapter-data-service-webapi.metadata.json +0 -1
- package/adapter-data-service-webapi/package.json +0 -13
- package/adapter-model-library-backing-store/breeze-client-adapter-model-library-backing-store.metadata.json +0 -1
- package/adapter-model-library-backing-store/package.json +0 -13
- package/adapter-model-library-ko/breeze-client-adapter-model-library-ko.metadata.json +0 -1
- package/adapter-model-library-ko/package.json +0 -13
- package/adapter-uri-builder-json/breeze-client-adapter-uri-builder-json.metadata.json +0 -1
- package/adapter-uri-builder-json/package.json +0 -13
- package/adapter-uri-builder-odata/breeze-client-adapter-uri-builder-odata.metadata.json +0 -1
- package/adapter-uri-builder-odata/package.json +0 -13
- package/breeze-client.d.ts +0 -8
- package/breeze-client.metadata.json +0 -1
- package/bundles/breeze-client-adapter-ajax-angularjs.umd.js +0 -190
- package/bundles/breeze-client-adapter-ajax-angularjs.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-angularjs.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-ajax-angularjs.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-fetch.umd.js +0 -190
- package/bundles/breeze-client-adapter-ajax-fetch.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-fetch.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-ajax-fetch.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-httpclient.umd.js +0 -195
- package/bundles/breeze-client-adapter-ajax-httpclient.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-httpclient.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-ajax-httpclient.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-jquery.umd.js +0 -115
- package/bundles/breeze-client-adapter-ajax-jquery.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-jquery.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-ajax-jquery.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-post.umd.js +0 -92
- package/bundles/breeze-client-adapter-ajax-post.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-ajax-post.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-ajax-post.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-data-service-odata.umd.js +0 -743
- package/bundles/breeze-client-adapter-data-service-odata.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-data-service-odata.umd.min.js +0 -16
- package/bundles/breeze-client-adapter-data-service-odata.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-data-service-webapi.umd.js +0 -326
- package/bundles/breeze-client-adapter-data-service-webapi.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-data-service-webapi.umd.min.js +0 -16
- package/bundles/breeze-client-adapter-data-service-webapi.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-model-library-backing-store.umd.js +0 -280
- package/bundles/breeze-client-adapter-model-library-backing-store.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-model-library-backing-store.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-model-library-backing-store.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-model-library-ko.umd.js +0 -252
- package/bundles/breeze-client-adapter-model-library-ko.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-model-library-ko.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-model-library-ko.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-uri-builder-json.umd.js +0 -96
- package/bundles/breeze-client-adapter-uri-builder-json.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-uri-builder-json.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-uri-builder-json.umd.min.js.map +0 -1
- package/bundles/breeze-client-adapter-uri-builder-odata.umd.js +0 -262
- package/bundles/breeze-client-adapter-uri-builder-odata.umd.js.map +0 -1
- package/bundles/breeze-client-adapter-uri-builder-odata.umd.min.js +0 -2
- package/bundles/breeze-client-adapter-uri-builder-odata.umd.min.js.map +0 -1
- package/bundles/breeze-client-mixin-get-entity-graph.umd.js +0 -258
- package/bundles/breeze-client-mixin-get-entity-graph.umd.js.map +0 -1
- package/bundles/breeze-client-mixin-get-entity-graph.umd.min.js +0 -2
- package/bundles/breeze-client-mixin-get-entity-graph.umd.min.js.map +0 -1
- package/bundles/breeze-client-mixin-save-queuing.umd.js +0 -579
- package/bundles/breeze-client-mixin-save-queuing.umd.js.map +0 -1
- package/bundles/breeze-client-mixin-save-queuing.umd.min.js +0 -16
- package/bundles/breeze-client-mixin-save-queuing.umd.min.js.map +0 -1
- package/bundles/breeze-client.umd.js +0 -14094
- package/bundles/breeze-client.umd.js.map +0 -1
- package/bundles/breeze-client.umd.min.js +0 -16
- package/bundles/breeze-client.umd.min.js.map +0 -1
- package/esm2015/adapter-ajax-angularjs/adapter-ajax-angularjs.js +0 -130
- package/esm2015/adapter-ajax-angularjs/adapter-core.js +0 -49
- package/esm2015/adapter-ajax-angularjs/breeze-client-adapter-ajax-angularjs.js +0 -5
- package/esm2015/adapter-ajax-fetch/adapter-ajax-fetch.js +0 -130
- package/esm2015/adapter-ajax-fetch/adapter-core.js +0 -49
- package/esm2015/adapter-ajax-fetch/breeze-client-adapter-ajax-fetch.js +0 -5
- package/esm2015/adapter-ajax-httpclient/adapter-ajax-httpclient.js +0 -137
- package/esm2015/adapter-ajax-httpclient/adapter-core.js +0 -49
- package/esm2015/adapter-ajax-httpclient/breeze-client-adapter-ajax-httpclient.js +0 -5
- package/esm2015/adapter-ajax-jquery/adapter-ajax-jquery.js +0 -103
- package/esm2015/adapter-ajax-jquery/breeze-client-adapter-ajax-jquery.js +0 -5
- package/esm2015/adapter-ajax-post/adapter-ajax-post.js +0 -77
- package/esm2015/adapter-ajax-post/breeze-client-adapter-ajax-post.js +0 -5
- package/esm2015/adapter-data-service-odata/adapter-core.js +0 -49
- package/esm2015/adapter-data-service-odata/adapter-data-service-odata.js +0 -459
- package/esm2015/adapter-data-service-odata/breeze-client-adapter-data-service-odata.js +0 -5
- package/esm2015/adapter-data-service-webapi/adapter-data-service-webapi.js +0 -93
- package/esm2015/adapter-data-service-webapi/breeze-client-adapter-data-service-webapi.js +0 -5
- package/esm2015/adapter-model-library-backing-store/adapter-model-library-backing-store.js +0 -268
- package/esm2015/adapter-model-library-backing-store/breeze-client-adapter-model-library-backing-store.js +0 -5
- package/esm2015/adapter-model-library-ko/adapter-model-library-ko.js +0 -240
- package/esm2015/adapter-model-library-ko/breeze-client-adapter-model-library-ko.js +0 -5
- package/esm2015/adapter-uri-builder-json/adapter-core.js +0 -49
- package/esm2015/adapter-uri-builder-json/adapter-uri-builder-json.js +0 -36
- package/esm2015/adapter-uri-builder-json/breeze-client-adapter-uri-builder-json.js +0 -5
- package/esm2015/adapter-uri-builder-odata/adapter-core.js +0 -49
- package/esm2015/adapter-uri-builder-odata/adapter-uri-builder-odata.js +0 -192
- package/esm2015/adapter-uri-builder-odata/breeze-client-adapter-uri-builder-odata.js +0 -5
- package/esm2015/breeze-client.js +0 -9
- package/esm2015/index.js +0 -2
- package/esm2015/mixin-get-entity-graph/breeze-client-mixin-get-entity-graph.js +0 -5
- package/esm2015/mixin-get-entity-graph/mixin-get-entity-graph.js +0 -269
- package/esm2015/mixin-save-queuing/breeze-client-mixin-save-queuing.js +0 -5
- package/esm2015/mixin-save-queuing/mixin-save-queuing.js +0 -400
- package/esm2015/public_api.js +0 -2
- package/esm2015/src/abstract-data-service-adapter.js +0 -296
- package/esm2015/src/array.js +0 -4
- package/esm2015/src/assert-param.js +0 -312
- package/esm2015/src/breeze.js +0 -85
- package/esm2015/src/complex-array.js +0 -119
- package/esm2015/src/config.js +0 -223
- package/esm2015/src/core.js +0 -706
- package/esm2015/src/csdl-metadata-parser.js +0 -385
- package/esm2015/src/data-service.js +0 -203
- package/esm2015/src/data-type.js +0 -444
- package/esm2015/src/default-property-interceptor.js +0 -459
- package/esm2015/src/entity-action.js +0 -45
- package/esm2015/src/entity-aspect.js +0 -806
- package/esm2015/src/entity-group.js +0 -187
- package/esm2015/src/entity-key.js +0 -116
- package/esm2015/src/entity-manager.js +0 -2094
- package/esm2015/src/entity-metadata.js +0 -2109
- package/esm2015/src/entity-query.js +0 -996
- package/esm2015/src/entity-state.js +0 -99
- package/esm2015/src/enum.js +0 -141
- package/esm2015/src/event.js +0 -256
- package/esm2015/src/interface-registry.js +0 -41
- package/esm2015/src/key-generator.js +0 -108
- package/esm2015/src/local-query-comparison-options.js +0 -65
- package/esm2015/src/mapping-context.js +0 -405
- package/esm2015/src/naming-convention.js +0 -88
- package/esm2015/src/observable-array.js +0 -185
- package/esm2015/src/predicate.js +0 -1235
- package/esm2015/src/primitive-array.js +0 -87
- package/esm2015/src/query-options.js +0 -152
- package/esm2015/src/relation-array.js +0 -175
- package/esm2015/src/save-options.js +0 -41
- package/esm2015/src/unattached-children-map.js +0 -58
- package/esm2015/src/validate.js +0 -991
- package/esm2015/src/validation-options.js +0 -64
- package/esm5/adapter-ajax-angularjs/adapter-ajax-angularjs.js +0 -132
- package/esm5/adapter-ajax-angularjs/adapter-core.js +0 -49
- package/esm5/adapter-ajax-angularjs/breeze-client-adapter-ajax-angularjs.js +0 -5
- package/esm5/adapter-ajax-fetch/adapter-ajax-fetch.js +0 -132
- package/esm5/adapter-ajax-fetch/adapter-core.js +0 -49
- package/esm5/adapter-ajax-fetch/breeze-client-adapter-ajax-fetch.js +0 -5
- package/esm5/adapter-ajax-httpclient/adapter-ajax-httpclient.js +0 -139
- package/esm5/adapter-ajax-httpclient/adapter-core.js +0 -49
- package/esm5/adapter-ajax-httpclient/breeze-client-adapter-ajax-httpclient.js +0 -5
- package/esm5/adapter-ajax-jquery/adapter-ajax-jquery.js +0 -105
- package/esm5/adapter-ajax-jquery/breeze-client-adapter-ajax-jquery.js +0 -5
- package/esm5/adapter-ajax-post/adapter-ajax-post.js +0 -81
- package/esm5/adapter-ajax-post/breeze-client-adapter-ajax-post.js +0 -5
- package/esm5/adapter-data-service-odata/adapter-core.js +0 -49
- package/esm5/adapter-data-service-odata/adapter-data-service-odata.js +0 -466
- package/esm5/adapter-data-service-odata/breeze-client-adapter-data-service-odata.js +0 -5
- package/esm5/adapter-data-service-webapi/adapter-data-service-webapi.js +0 -98
- package/esm5/adapter-data-service-webapi/breeze-client-adapter-data-service-webapi.js +0 -5
- package/esm5/adapter-model-library-backing-store/adapter-model-library-backing-store.js +0 -270
- package/esm5/adapter-model-library-backing-store/breeze-client-adapter-model-library-backing-store.js +0 -5
- package/esm5/adapter-model-library-ko/adapter-model-library-ko.js +0 -242
- package/esm5/adapter-model-library-ko/breeze-client-adapter-model-library-ko.js +0 -5
- package/esm5/adapter-uri-builder-json/adapter-core.js +0 -49
- package/esm5/adapter-uri-builder-json/adapter-uri-builder-json.js +0 -38
- package/esm5/adapter-uri-builder-json/breeze-client-adapter-uri-builder-json.js +0 -5
- package/esm5/adapter-uri-builder-odata/adapter-core.js +0 -49
- package/esm5/adapter-uri-builder-odata/adapter-uri-builder-odata.js +0 -197
- package/esm5/adapter-uri-builder-odata/breeze-client-adapter-uri-builder-odata.js +0 -5
- package/esm5/breeze-client.js +0 -9
- package/esm5/index.js +0 -2
- package/esm5/mixin-get-entity-graph/breeze-client-mixin-get-entity-graph.js +0 -5
- package/esm5/mixin-get-entity-graph/mixin-get-entity-graph.js +0 -269
- package/esm5/mixin-save-queuing/breeze-client-mixin-save-queuing.js +0 -5
- package/esm5/mixin-save-queuing/mixin-save-queuing.js +0 -412
- package/esm5/public_api.js +0 -2
- package/esm5/src/abstract-data-service-adapter.js +0 -302
- package/esm5/src/array.js +0 -4
- package/esm5/src/assert-param.js +0 -317
- package/esm5/src/breeze.js +0 -85
- package/esm5/src/complex-array.js +0 -119
- package/esm5/src/config.js +0 -228
- package/esm5/src/core.js +0 -714
- package/esm5/src/csdl-metadata-parser.js +0 -385
- package/esm5/src/data-service.js +0 -207
- package/esm5/src/data-type.js +0 -451
- package/esm5/src/default-property-interceptor.js +0 -459
- package/esm5/src/entity-action.js +0 -52
- package/esm5/src/entity-aspect.js +0 -812
- package/esm5/src/entity-group.js +0 -189
- package/esm5/src/entity-key.js +0 -118
- package/esm5/src/entity-manager.js +0 -2112
- package/esm5/src/entity-metadata.js +0 -2144
- package/esm5/src/entity-query.js +0 -1023
- package/esm5/src/entity-state.js +0 -106
- package/esm5/src/enum.js +0 -144
- package/esm5/src/event.js +0 -259
- package/esm5/src/interface-registry.js +0 -43
- package/esm5/src/key-generator.js +0 -111
- package/esm5/src/local-query-comparison-options.js +0 -67
- package/esm5/src/mapping-context.js +0 -407
- package/esm5/src/naming-convention.js +0 -90
- package/esm5/src/observable-array.js +0 -201
- package/esm5/src/predicate.js +0 -1300
- package/esm5/src/primitive-array.js +0 -87
- package/esm5/src/query-options.js +0 -167
- package/esm5/src/relation-array.js +0 -175
- package/esm5/src/save-options.js +0 -43
- package/esm5/src/unattached-children-map.js +0 -60
- package/esm5/src/validate.js +0 -996
- package/esm5/src/validation-options.js +0 -66
- package/fesm2015/breeze-client-adapter-ajax-angularjs.js.map +0 -1
- package/fesm2015/breeze-client-adapter-ajax-fetch.js.map +0 -1
- package/fesm2015/breeze-client-adapter-ajax-httpclient.js.map +0 -1
- package/fesm2015/breeze-client-adapter-ajax-jquery.js.map +0 -1
- package/fesm2015/breeze-client-adapter-ajax-post.js.map +0 -1
- package/fesm2015/breeze-client-adapter-data-service-odata.js.map +0 -1
- package/fesm2015/breeze-client-adapter-data-service-webapi.js.map +0 -1
- package/fesm2015/breeze-client-adapter-model-library-backing-store.js.map +0 -1
- package/fesm2015/breeze-client-adapter-model-library-ko.js.map +0 -1
- package/fesm2015/breeze-client-adapter-uri-builder-json.js.map +0 -1
- package/fesm2015/breeze-client-adapter-uri-builder-odata.js.map +0 -1
- package/fesm2015/breeze-client-mixin-get-entity-graph.js.map +0 -1
- package/fesm2015/breeze-client-mixin-save-queuing.js.map +0 -1
- package/fesm2015/breeze-client.js.map +0 -1
- package/fesm5/breeze-client-adapter-ajax-angularjs.js.map +0 -1
- package/fesm5/breeze-client-adapter-ajax-fetch.js.map +0 -1
- package/fesm5/breeze-client-adapter-ajax-httpclient.js.map +0 -1
- package/fesm5/breeze-client-adapter-ajax-jquery.js.map +0 -1
- package/fesm5/breeze-client-adapter-ajax-post.js.map +0 -1
- package/fesm5/breeze-client-adapter-data-service-odata.js.map +0 -1
- package/fesm5/breeze-client-adapter-data-service-webapi.js.map +0 -1
- package/fesm5/breeze-client-adapter-model-library-backing-store.js.map +0 -1
- package/fesm5/breeze-client-adapter-model-library-ko.js.map +0 -1
- package/fesm5/breeze-client-adapter-uri-builder-json.js +0 -92
- package/fesm5/breeze-client-adapter-uri-builder-json.js.map +0 -1
- package/fesm5/breeze-client-adapter-uri-builder-odata.js +0 -250
- package/fesm5/breeze-client-adapter-uri-builder-odata.js.map +0 -1
- package/fesm5/breeze-client-mixin-get-entity-graph.js.map +0 -1
- package/fesm5/breeze-client-mixin-save-queuing.js.map +0 -1
- package/fesm5/breeze-client.js.map +0 -1
- package/mixin-get-entity-graph/breeze-client-mixin-get-entity-graph.metadata.json +0 -1
- package/mixin-get-entity-graph/package.json +0 -13
- package/mixin-save-queuing/breeze-client-mixin-save-queuing.metadata.json +0 -1
- package/mixin-save-queuing/package.json +0 -13
- package/public_api.d.ts +0 -1
|
@@ -0,0 +1,2109 @@
|
|
|
1
|
+
import { core } from './core';
|
|
2
|
+
import { config } from './config';
|
|
3
|
+
import { BreezeEvent } from './event';
|
|
4
|
+
import { assertParam, assertConfig, Param } from './assert-param';
|
|
5
|
+
import { DataType } from './data-type';
|
|
6
|
+
import { EntityAspect, ComplexAspect } from './entity-aspect';
|
|
7
|
+
import { EntityKey } from './entity-key';
|
|
8
|
+
import { Validator } from './validate';
|
|
9
|
+
import { BreezeEnum } from './enum';
|
|
10
|
+
import { DataService } from './data-service';
|
|
11
|
+
import { NamingConvention } from './naming-convention';
|
|
12
|
+
import { CsdlMetadataParser } from './csdl-metadata-parser'; // TODO isolate this later;
|
|
13
|
+
import { LocalQueryComparisonOptions } from './local-query-comparison-options';
|
|
14
|
+
import { defaultPropertyInterceptor } from './default-property-interceptor';
|
|
15
|
+
/**
|
|
16
|
+
An instance of the MetadataStore contains all of the metadata about a collection of [[EntityType]]'s.
|
|
17
|
+
MetadataStores may be shared across [[EntityManager]]'s. If an EntityManager is created without an
|
|
18
|
+
explicit MetadataStore, the MetadataStore from the MetadataStore.defaultInstance property will be used.
|
|
19
|
+
@dynamic
|
|
20
|
+
**/
|
|
21
|
+
export class MetadataStore {
|
|
22
|
+
/**
|
|
23
|
+
Constructs a new MetadataStore.
|
|
24
|
+
|
|
25
|
+
> let ms = new MetadataStore();
|
|
26
|
+
|
|
27
|
+
The store can then be associated with an EntityManager
|
|
28
|
+
> let entityManager = new EntityManager( {
|
|
29
|
+
> serviceName: "breeze/NorthwindIBModel",
|
|
30
|
+
> metadataStore: ms
|
|
31
|
+
> });
|
|
32
|
+
|
|
33
|
+
or for an existing EntityManager
|
|
34
|
+
> // Assume em1 is an existing EntityManager
|
|
35
|
+
> em1.setProperties( { metadataStore: ms });
|
|
36
|
+
|
|
37
|
+
@param config - Configuration settings .
|
|
38
|
+
- namingConvention - (default=NamingConvention.defaultInstance) NamingConvention to be used in mapping property names
|
|
39
|
+
between client and server. Uses the NamingConvention.defaultInstance if not specified.
|
|
40
|
+
- localQueryComparisonOptions - (default=LocalQueryComparisonOptions.defaultInstance) The LocalQueryComparisonOptions to be
|
|
41
|
+
used when performing "local queries" in order to match the semantics of queries against a remote service.
|
|
42
|
+
- serializerFn - A function that is used to mediate the serialization of instances of this type.
|
|
43
|
+
**/
|
|
44
|
+
constructor(config) {
|
|
45
|
+
config = config || {};
|
|
46
|
+
assertConfig(config)
|
|
47
|
+
.whereParam("namingConvention").isOptional().isInstanceOf(NamingConvention).withDefault(NamingConvention.defaultInstance)
|
|
48
|
+
.whereParam("localQueryComparisonOptions").isOptional().isInstanceOf(LocalQueryComparisonOptions).withDefault(LocalQueryComparisonOptions.defaultInstance)
|
|
49
|
+
.whereParam("serializerFn").isOptional().isFunction()
|
|
50
|
+
.applyAll(this);
|
|
51
|
+
this.dataServices = []; // array of dataServices;
|
|
52
|
+
this._resourceEntityTypeMap = {}; // key is resource name - value is qualified entityType name
|
|
53
|
+
this._structuralTypeMap = {}; // key is qualified structuraltype name - value is structuralType. ( structural = entityType or complexType).
|
|
54
|
+
this._shortNameMap = {}; // key is shortName, value is qualified name - does not need to be serialized.
|
|
55
|
+
this._ctorRegistry = {}; // key is either short or qual type name - value is ctor;
|
|
56
|
+
this._incompleteTypeMap = {}; // key is entityTypeName; value is array of nav props
|
|
57
|
+
this._incompleteComplexTypeMap = {}; // key is complexTypeName; value is array of complexType props
|
|
58
|
+
this._id = MetadataStore.__id++;
|
|
59
|
+
this.metadataFetched = new BreezeEvent("metadataFetched", this);
|
|
60
|
+
}
|
|
61
|
+
// for debugging use the line below instead.
|
|
62
|
+
//ctor.normalizeTypeName = function (rawTypeName) { return parseTypeName(rawTypeName).typeName; };
|
|
63
|
+
/**
|
|
64
|
+
General purpose property set method
|
|
65
|
+
|
|
66
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
67
|
+
> em1.metadataStore.setProperties( {
|
|
68
|
+
> version: "6.1.3",
|
|
69
|
+
> serializerFn: function(prop, value) {
|
|
70
|
+
> return (prop.isUnmapped) ? undefined : value;
|
|
71
|
+
> }
|
|
72
|
+
> )};
|
|
73
|
+
@param config - An object containing the selected properties and values to set.
|
|
74
|
+
**/
|
|
75
|
+
setProperties(config) {
|
|
76
|
+
assertConfig(config)
|
|
77
|
+
.whereParam("name").isString().isOptional()
|
|
78
|
+
.whereParam("serializerFn").isFunction().isOptional()
|
|
79
|
+
.applyAll(this);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
Adds a DataService to this MetadataStore. If a DataService with the same serviceName is already
|
|
83
|
+
in the MetadataStore an exception will be thrown.
|
|
84
|
+
@param dataService - The [[DataService]] to add
|
|
85
|
+
@param shouldOverwrite - (default=false) Permit overwrite of existing DataService rather than throw exception
|
|
86
|
+
**/
|
|
87
|
+
addDataService(dataService, shouldOverwrite) {
|
|
88
|
+
assertParam(dataService, "dataService").isInstanceOf(DataService).check();
|
|
89
|
+
assertParam(shouldOverwrite, "shouldOverwrite").isBoolean().isOptional().check();
|
|
90
|
+
let ix = this._getDataServiceIndex(dataService.serviceName);
|
|
91
|
+
if (ix >= 0) {
|
|
92
|
+
if (!!shouldOverwrite) {
|
|
93
|
+
this.dataServices[ix] = dataService;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
throw new Error("A dataService with this name '" + dataService.serviceName + "' already exists in this MetadataStore");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
this.dataServices.push(dataService);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** @hidden @internal */
|
|
104
|
+
_getDataServiceIndex(serviceName) {
|
|
105
|
+
return core.arrayIndexOf(this.dataServices, function (ds) {
|
|
106
|
+
return ds.serviceName === serviceName;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
Adds an EntityType to this MetadataStore. No additional properties may be added to the EntityType after its has
|
|
111
|
+
been added to the MetadataStore.
|
|
112
|
+
@param structuralType - The EntityType or ComplexType to add
|
|
113
|
+
**/
|
|
114
|
+
addEntityType(stype) {
|
|
115
|
+
let structuralType;
|
|
116
|
+
if (stype instanceof EntityType || stype instanceof ComplexType) {
|
|
117
|
+
structuralType = stype;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
structuralType = stype.isComplexType ? new ComplexType(stype) : new EntityType(stype);
|
|
121
|
+
}
|
|
122
|
+
// if (!structuralType.isComplexType) { // same as below but isn't a 'type guard'
|
|
123
|
+
if (structuralType instanceof EntityType) {
|
|
124
|
+
if (structuralType.baseTypeName && !structuralType.baseEntityType) {
|
|
125
|
+
let baseEntityType = this._getStructuralType(structuralType.baseTypeName, true);
|
|
126
|
+
// safe cast because we know that baseEntityType must be an EntityType if the structuralType is an EntityType
|
|
127
|
+
structuralType._updateFromBase(baseEntityType);
|
|
128
|
+
}
|
|
129
|
+
if (structuralType.keyProperties.length === 0 && !structuralType.isAbstract) {
|
|
130
|
+
throw new Error("Unable to add " + structuralType.name +
|
|
131
|
+
" to this MetadataStore. An EntityType must have at least one property designated as a key property - See the 'DataProperty.isPartOfKey' property.");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
structuralType.metadataStore = this;
|
|
135
|
+
// don't register anon types
|
|
136
|
+
if (!structuralType.isAnonymous) {
|
|
137
|
+
if (this._structuralTypeMap[structuralType.name]) {
|
|
138
|
+
throw new Error("Type " + structuralType.name + " already exists in this MetadataStore.");
|
|
139
|
+
}
|
|
140
|
+
this._structuralTypeMap[structuralType.name] = structuralType;
|
|
141
|
+
this._shortNameMap[structuralType.shortName] = structuralType.name;
|
|
142
|
+
}
|
|
143
|
+
structuralType.getProperties().forEach(p => {
|
|
144
|
+
structuralType._updateNames(p);
|
|
145
|
+
if (!p.isUnmapped) {
|
|
146
|
+
structuralType._mappedPropertiesCount++;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
structuralType._updateCps();
|
|
150
|
+
// 'isEntityType' is a type guard
|
|
151
|
+
if (structuralType instanceof EntityType) {
|
|
152
|
+
structuralType._updateNps();
|
|
153
|
+
// give the type it's base's resource name if it doesn't have its own.
|
|
154
|
+
let defResourceName = structuralType.defaultResourceName || (structuralType.baseEntityType && structuralType.baseEntityType.defaultResourceName);
|
|
155
|
+
if (defResourceName && !this.getEntityTypeNameForResourceName(defResourceName)) {
|
|
156
|
+
this.setEntityTypeForResourceName(defResourceName, structuralType.name);
|
|
157
|
+
}
|
|
158
|
+
structuralType.defaultResourceName = defResourceName;
|
|
159
|
+
// check if this structural type's name, short version or qualified version has a registered ctor.
|
|
160
|
+
structuralType.getEntityCtor();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
Exports this MetadataStore to a serialized string appropriate for local storage. This operation is also called
|
|
165
|
+
internally when exporting an EntityManager.
|
|
166
|
+
> // assume ms is a previously created MetadataStore
|
|
167
|
+
> let metadataAsString = ms.exportMetadata();
|
|
168
|
+
> window.localStorage.setItem("metadata", metadataAsString);
|
|
169
|
+
> // and later, usually in a different session imported
|
|
170
|
+
> let metadataFromStorage = window.localStorage.getItem("metadata");
|
|
171
|
+
> let newMetadataStore = new MetadataStore();
|
|
172
|
+
> newMetadataStore.importMetadata(metadataFromStorage);
|
|
173
|
+
@return A serialized version of this MetadataStore that may be stored locally and later restored.
|
|
174
|
+
**/
|
|
175
|
+
exportMetadata() {
|
|
176
|
+
let result = JSON.stringify({
|
|
177
|
+
"metadataVersion": MetadataStore.metadataVersion,
|
|
178
|
+
"name": this.name,
|
|
179
|
+
"namingConvention": this.namingConvention.name,
|
|
180
|
+
"localQueryComparisonOptions": this.localQueryComparisonOptions.name,
|
|
181
|
+
"dataServices": this.dataServices,
|
|
182
|
+
"structuralTypes": core.objectMap(this._structuralTypeMap),
|
|
183
|
+
"resourceEntityTypeMap": this._resourceEntityTypeMap
|
|
184
|
+
}, null, config.stringifyPad);
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
Imports a previously exported serialized MetadataStore into this MetadataStore.
|
|
189
|
+
|
|
190
|
+
> // assume ms is a previously created MetadataStore
|
|
191
|
+
> let metadataAsString = ms.exportMetadata();
|
|
192
|
+
> window.localStorage.setItem("metadata", metadataAsString);
|
|
193
|
+
> // and later, usually in a different session
|
|
194
|
+
> let metadataFromStorage = window.localStorage.getItem("metadata");
|
|
195
|
+
> let newMetadataStore = new MetadataStore();
|
|
196
|
+
> newMetadataStore.importMetadata(metadataFromStorage);
|
|
197
|
+
@param exportedMetadata - A previously exported MetadataStore.
|
|
198
|
+
@param allowMerge - Allows custom metadata to be merged into existing metadata types.
|
|
199
|
+
@return This MetadataStore.
|
|
200
|
+
@chainable
|
|
201
|
+
**/
|
|
202
|
+
importMetadata(exportedMetadata, allowMerge = false) {
|
|
203
|
+
assertParam(allowMerge, "allowMerge").isOptional().isBoolean().check();
|
|
204
|
+
this._deferredTypes = {};
|
|
205
|
+
// insure that we don't mutate incoming exportedMetadata ( if its an object)
|
|
206
|
+
let metadataAsString = (typeof (exportedMetadata) === "string") ? exportedMetadata : JSON.stringify(exportedMetadata);
|
|
207
|
+
const metadataJson = JSON.parse(metadataAsString);
|
|
208
|
+
if (metadataJson.schema) {
|
|
209
|
+
return CsdlMetadataParser.parse(this, metadataJson.schema, metadataJson.altMetadata);
|
|
210
|
+
}
|
|
211
|
+
let json = metadataJson;
|
|
212
|
+
if (json.metadataVersion && json.metadataVersion !== MetadataStore.metadataVersion) {
|
|
213
|
+
let msg = core.formatString("Cannot import metadata with a different 'metadataVersion' (%1) than the current 'MetadataStore.metadataVersion' (%2) ", json.metadataVersion, MetadataStore.metadataVersion);
|
|
214
|
+
throw new Error(msg);
|
|
215
|
+
}
|
|
216
|
+
let ncName = json.namingConvention;
|
|
217
|
+
let lqcoName = json.localQueryComparisonOptions;
|
|
218
|
+
if (this.isEmpty()) {
|
|
219
|
+
this.namingConvention = config._fetchObject(NamingConvention, ncName) || this.namingConvention;
|
|
220
|
+
this.localQueryComparisonOptions = config._fetchObject(LocalQueryComparisonOptions, lqcoName) || this.localQueryComparisonOptions;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
if (ncName && this.namingConvention.name !== ncName) {
|
|
224
|
+
throw new Error("Cannot import metadata with a different 'namingConvention' from the current MetadataStore");
|
|
225
|
+
}
|
|
226
|
+
if (lqcoName && this.localQueryComparisonOptions.name !== lqcoName) {
|
|
227
|
+
throw new Error("Cannot import metadata with different 'localQueryComparisonOptions' from the current MetadataStore");
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
//noinspection JSHint
|
|
231
|
+
json.dataServices && json.dataServices.forEach((ds) => {
|
|
232
|
+
let realDs = DataService.fromJSON(ds);
|
|
233
|
+
this.addDataService(realDs, true);
|
|
234
|
+
});
|
|
235
|
+
json.structuralTypes && json.structuralTypes.forEach((stype) => {
|
|
236
|
+
structuralTypeFromJson(this, stype, allowMerge);
|
|
237
|
+
});
|
|
238
|
+
core.extend(this._resourceEntityTypeMap, json.resourceEntityTypeMap);
|
|
239
|
+
core.extend(this._incompleteTypeMap, json.incompleteTypeMap);
|
|
240
|
+
return this;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
Creates a new MetadataStore from a previously exported serialized MetadataStore
|
|
244
|
+
> // assume ms is a previously created MetadataStore
|
|
245
|
+
> let metadataAsString = ms.exportMetadata();
|
|
246
|
+
> window.localStorage.setItem("metadata", metadataAsString);
|
|
247
|
+
> // and later, usually in a different session
|
|
248
|
+
> let metadataFromStorage = window.localStorage.getItem("metadata");
|
|
249
|
+
> let newMetadataStore = MetadataStore.importMetadata(metadataFromStorage);
|
|
250
|
+
@param exportedString - A previously exported MetadataStore.
|
|
251
|
+
@return A new MetadataStore.
|
|
252
|
+
**/
|
|
253
|
+
static importMetadata(exportedString) {
|
|
254
|
+
let ms = new MetadataStore();
|
|
255
|
+
ms.importMetadata(exportedString);
|
|
256
|
+
return ms;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
Returns whether Metadata has been retrieved for a specified service name.
|
|
260
|
+
> // Assume em1 is an existing EntityManager.
|
|
261
|
+
> if (!em1.metadataStore.hasMetadataFor("breeze/NorthwindIBModel"))) {
|
|
262
|
+
> // do something interesting
|
|
263
|
+
> }
|
|
264
|
+
@param serviceName - The service name.
|
|
265
|
+
@return Whether metadata has already been retrieved for the specified service name.
|
|
266
|
+
**/
|
|
267
|
+
hasMetadataFor(serviceName) {
|
|
268
|
+
return !!this.getDataService(serviceName);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
Returns the DataService for a specified service name
|
|
272
|
+
> // Assume em1 is an existing EntityManager.
|
|
273
|
+
> let ds = em1.metadataStore.getDataService("breeze/NorthwindIBModel");
|
|
274
|
+
> let adapterName = ds.adapterName; // may be null
|
|
275
|
+
@param serviceName - The service name.
|
|
276
|
+
@return The DataService with the specified name.
|
|
277
|
+
**/
|
|
278
|
+
getDataService(serviceName) {
|
|
279
|
+
assertParam(serviceName, "serviceName").isString().check();
|
|
280
|
+
serviceName = DataService._normalizeServiceName(serviceName);
|
|
281
|
+
return core.arrayFirst(this.dataServices, function (ds) {
|
|
282
|
+
return ds.serviceName === serviceName;
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
Fetches the metadata for a specified 'service'. This method is automatically called
|
|
287
|
+
internally by an EntityManager before its first query against a new service. __Async__
|
|
288
|
+
|
|
289
|
+
Usually you will not actually process the results of a fetchMetadata call directly, but will instead
|
|
290
|
+
ask for the metadata from the EntityManager after the fetchMetadata call returns.
|
|
291
|
+
> let ms = new MetadataStore();
|
|
292
|
+
> // or more commonly
|
|
293
|
+
> // let ms = anEntityManager.metadataStore;
|
|
294
|
+
> ms.fetchMetadata("breeze/NorthwindIBModel").then(function(rawMetadata) {
|
|
295
|
+
> // do something with the metadata
|
|
296
|
+
> }).catch(function(exception) {
|
|
297
|
+
> // handle exception here
|
|
298
|
+
> });
|
|
299
|
+
@param dataService - Either a DataService or just the name of the DataService to fetch metadata for.
|
|
300
|
+
@param callback - Function called on success.
|
|
301
|
+
@param errorCallback - Function called on failure.
|
|
302
|
+
@return Promise
|
|
303
|
+
**/
|
|
304
|
+
fetchMetadata(dataService, callback, errorCallback) {
|
|
305
|
+
try {
|
|
306
|
+
assertParam(dataService, "dataService").isString().or().isInstanceOf(DataService).check();
|
|
307
|
+
assertParam(callback, "callback").isFunction().isOptional().check();
|
|
308
|
+
assertParam(errorCallback, "errorCallback").isFunction().isOptional().check();
|
|
309
|
+
if (typeof dataService === "string") {
|
|
310
|
+
// use the dataService with a matching name or create a new one.
|
|
311
|
+
dataService = this.getDataService(dataService) || new DataService({ serviceName: dataService });
|
|
312
|
+
}
|
|
313
|
+
dataService = DataService.resolve([dataService]);
|
|
314
|
+
if (this.hasMetadataFor(dataService.serviceName)) {
|
|
315
|
+
throw new Error("Metadata for a specific serviceName may only be fetched once per MetadataStore. ServiceName: " + dataService.serviceName);
|
|
316
|
+
}
|
|
317
|
+
return dataService.adapterInstance.fetchMetadata(this, dataService).then((rawMetadata) => {
|
|
318
|
+
this.metadataFetched.publish({ metadataStore: this, dataService: dataService, rawMetadata: rawMetadata });
|
|
319
|
+
if (callback)
|
|
320
|
+
callback(rawMetadata);
|
|
321
|
+
return Promise.resolve(rawMetadata);
|
|
322
|
+
}, function (error) {
|
|
323
|
+
if (errorCallback)
|
|
324
|
+
errorCallback(error);
|
|
325
|
+
return Promise.reject(error);
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
catch (e) {
|
|
329
|
+
return Promise.reject(e);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// TODO: strongly type interceptor below.
|
|
333
|
+
/**
|
|
334
|
+
Used to register a constructor for an EntityType that is not known via standard Metadata discovery;
|
|
335
|
+
i.e. an unmapped type.
|
|
336
|
+
@param entityCtor - The constructor function for the 'unmapped' type.
|
|
337
|
+
@param interceptor - An interceptor function
|
|
338
|
+
**/
|
|
339
|
+
trackUnmappedType(entityCtor, interceptor) {
|
|
340
|
+
assertParam(entityCtor, "entityCtor").isFunction().check();
|
|
341
|
+
assertParam(interceptor, "interceptor").isFunction().isOptional().check();
|
|
342
|
+
// TODO: think about adding this to the MetadataStore.
|
|
343
|
+
let entityType = new EntityType(this);
|
|
344
|
+
entityType._setCtor(entityCtor, interceptor);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
Provides a mechanism to register a 'custom' constructor to be used when creating new instances
|
|
348
|
+
of the specified entity type. If this call is not made, a default constructor is created for
|
|
349
|
+
the entity as needed.
|
|
350
|
+
This call may be made before or after the corresponding EntityType has been discovered via
|
|
351
|
+
Metadata discovery.
|
|
352
|
+
> let Customer = function () {
|
|
353
|
+
> this.miscData = "asdf";
|
|
354
|
+
> };
|
|
355
|
+
> Customer.prototype.doFoo() {
|
|
356
|
+
> ...
|
|
357
|
+
> }
|
|
358
|
+
> // assume em1 is a preexisting EntityManager;
|
|
359
|
+
> em1.metadataStore.registerEntityTypeCtor("Customer", Customer);
|
|
360
|
+
> // any queries or EntityType.create calls from this point on will call the Customer constructor
|
|
361
|
+
> // registered above.
|
|
362
|
+
@param structuralTypeName - The name of the EntityType or ComplexType.
|
|
363
|
+
@param aCtor - The constructor for this EntityType or ComplexType; may be null if all you want to do is set the next parameter.
|
|
364
|
+
@param initFn - A function or the name of a function on the entity that is to be executed immediately after the entity has been created
|
|
365
|
+
and populated with any initial values. Called with 'initFn(entity)'
|
|
366
|
+
@param noTrackingFn - A function that is executed immediately after a noTracking entity has been created and whose return
|
|
367
|
+
value will be used in place of the noTracking entity.
|
|
368
|
+
**/
|
|
369
|
+
registerEntityTypeCtor(structuralTypeName, aCtor, initFn, noTrackingFn) {
|
|
370
|
+
assertParam(structuralTypeName, "structuralTypeName").isString().check();
|
|
371
|
+
assertParam(aCtor, "aCtor").isFunction().isOptional().check();
|
|
372
|
+
assertParam(initFn, "initFn").isOptional().isFunction().or().isString().check();
|
|
373
|
+
assertParam(noTrackingFn, "noTrackingFn").isOptional().isFunction().check();
|
|
374
|
+
let qualifiedTypeName = getQualifiedTypeName(this, structuralTypeName, false);
|
|
375
|
+
let typeName = qualifiedTypeName || structuralTypeName;
|
|
376
|
+
if (aCtor) {
|
|
377
|
+
if (aCtor._$typeName && aCtor._$typeName !== typeName) {
|
|
378
|
+
// TODO: wrap this - console and especially console.warn does not exist in all browsers.
|
|
379
|
+
console.warn("Registering a constructor for " + typeName + " that is already used for " + aCtor._$typeName + ".");
|
|
380
|
+
}
|
|
381
|
+
aCtor._$typeName = typeName;
|
|
382
|
+
}
|
|
383
|
+
this._ctorRegistry[typeName] = { ctor: aCtor, initFn: initFn, noTrackingFn: noTrackingFn };
|
|
384
|
+
if (qualifiedTypeName) {
|
|
385
|
+
let stype = this._structuralTypeMap[qualifiedTypeName];
|
|
386
|
+
stype && stype.getCtor(true); // this will complete the registration if avail now.
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
Returns whether this MetadataStore contains any metadata yet.
|
|
391
|
+
> // assume em1 is a preexisting EntityManager;
|
|
392
|
+
> if (em1.metadataStore.isEmpty()) {
|
|
393
|
+
> // do something interesting
|
|
394
|
+
> }
|
|
395
|
+
**/
|
|
396
|
+
isEmpty() {
|
|
397
|
+
return core.isEmpty(this._structuralTypeMap);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
Returns an [[EntityType]] or null given its name.
|
|
401
|
+
> // assume em1 is a preexisting EntityManager
|
|
402
|
+
> let odType = em1.metadataStore.getAsEntityType("OrderDetail");
|
|
403
|
+
|
|
404
|
+
or to throw an error if the type is not found
|
|
405
|
+
> let badType = em1.metadataStore.getAsEntityType("Foo", false);
|
|
406
|
+
> // badType will not get set and an exception will be thrown.
|
|
407
|
+
@param structuralTypeName - Either the fully qualified name or a short name may be used. If a short name is specified and multiple types share
|
|
408
|
+
that same short name an exception will be thrown.
|
|
409
|
+
@param okIfNotFound - (default=false) Whether to throw an error if the specified EntityType is not found.
|
|
410
|
+
@return The EntityType. ComplexType or 'null' if not not found.
|
|
411
|
+
**/
|
|
412
|
+
getAsEntityType(typeName, okIfNotFound = false) {
|
|
413
|
+
const st = this.getStructuralType(typeName, okIfNotFound);
|
|
414
|
+
if (st instanceof EntityType) {
|
|
415
|
+
return st;
|
|
416
|
+
}
|
|
417
|
+
else if (okIfNotFound) {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
let msg = core.formatString("Unable to locate an 'EntityType' by the name: '%1'. Be sure to execute a query or call fetchMetadata first.", typeName);
|
|
422
|
+
throw new Error(msg);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
Returns an [[EntityType]] or null given its name.
|
|
427
|
+
> // assume em1 is a preexisting EntityManager
|
|
428
|
+
> let locType = em1.metadataStore.getAsComplexType("Location");
|
|
429
|
+
|
|
430
|
+
or to throw an error if the type is not found
|
|
431
|
+
> let badType = em1.metadataStore.getAsComplexType("Foo", false);
|
|
432
|
+
> // badType will not get set and an exception will be thrown.
|
|
433
|
+
@param structuralTypeName - Either the fully qualified name or a short name may be used. If a short name is specified and multiple types share
|
|
434
|
+
that same short name an exception will be thrown.
|
|
435
|
+
@param okIfNotFound - (default=false) Whether to throw an error if the specified EntityType is not found.
|
|
436
|
+
@return The EntityType. ComplexType or 'null' if not not found.
|
|
437
|
+
**/
|
|
438
|
+
getAsComplexType(typeName, okIfNotFound = false) {
|
|
439
|
+
const st = this.getStructuralType(typeName, okIfNotFound);
|
|
440
|
+
if (st instanceof ComplexType) {
|
|
441
|
+
return st;
|
|
442
|
+
}
|
|
443
|
+
else if (okIfNotFound) {
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
let msg = core.formatString("Unable to locate an 'ComplexType' by the name: '%1'. Be sure to execute a query or call fetchMetadata first.", typeName);
|
|
448
|
+
throw new Error(msg);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
Returns an [[EntityType]] or a [[ComplexType]] given its name.
|
|
453
|
+
@deprecated Replaced by getStructuralType but ... it is probably more usefull to call either getAsEntityType or getAsComplexType instead
|
|
454
|
+
@param typeName - Either the fully qualified name or a short name may be used. If a short name is specified and multiple types share
|
|
455
|
+
that same short name an exception will be thrown.
|
|
456
|
+
@param okIfNotFound - (default=false) Whether to throw an error if the specified EntityType is not found.
|
|
457
|
+
@return The EntityType. ComplexType or 'null' if not not found.
|
|
458
|
+
**/
|
|
459
|
+
getEntityType(typeName, okIfNotFound = false) {
|
|
460
|
+
return this.getStructuralType(typeName, okIfNotFound);
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
Returns an [[EntityType]] or a [[ComplexType]] given its name.
|
|
464
|
+
> // assume em1 is a preexisting EntityManager
|
|
465
|
+
> let odType = em1.metadataStore.getStructuralType("OrderDetail");
|
|
466
|
+
|
|
467
|
+
or to throw an error if the type is not found
|
|
468
|
+
> let badType = em1.metadataStore.getStructuralType("Foo", false);
|
|
469
|
+
> // badType will not get set and an exception will be thrown.
|
|
470
|
+
@deprecated Preferably use either getAsEntityType or getAsComplexType. Get
|
|
471
|
+
@param typeName - Either the fully qualified name or a short name may be used. If a short name is specified and multiple types share
|
|
472
|
+
that same short name an exception will be thrown.
|
|
473
|
+
@param okIfNotFound - (default=false) Whether to throw an error if the specified EntityType is not found.
|
|
474
|
+
@return The EntityType. ComplexType or 'null' if not not found.
|
|
475
|
+
**/
|
|
476
|
+
getStructuralType(typeName, okIfNotFound = false) {
|
|
477
|
+
assertParam(typeName, "typeName").isString().check();
|
|
478
|
+
assertParam(okIfNotFound, "okIfNotFound").isBoolean().isOptional().check(false);
|
|
479
|
+
return this._getStructuralType(typeName, okIfNotFound);
|
|
480
|
+
}
|
|
481
|
+
/** @hidden @internal */
|
|
482
|
+
_getStructuralType(typeName, okIfNotFound = false) {
|
|
483
|
+
let qualTypeName = getQualifiedTypeName(this, typeName, false);
|
|
484
|
+
let type = this._structuralTypeMap[qualTypeName];
|
|
485
|
+
if (!type) {
|
|
486
|
+
if (okIfNotFound)
|
|
487
|
+
return null;
|
|
488
|
+
let msg = core.formatString("Unable to locate a 'Type' by the name: '%1'. Be sure to execute a query or call fetchMetadata first.", typeName);
|
|
489
|
+
throw new Error(msg);
|
|
490
|
+
}
|
|
491
|
+
return type;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
Returns an array containing all of the [[EntityType]]s or [[ComplexType]]s in this MetadataStore.
|
|
495
|
+
> // assume em1 is a preexisting EntityManager
|
|
496
|
+
> let allTypes = em1.metadataStore.getEntityTypes();
|
|
497
|
+
**/
|
|
498
|
+
getEntityTypes() {
|
|
499
|
+
return getTypesFromMap(this._structuralTypeMap);
|
|
500
|
+
}
|
|
501
|
+
getIncompleteNavigationProperties() {
|
|
502
|
+
return core.objectMap(this._incompleteTypeMap, function (key, value) {
|
|
503
|
+
return value;
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
Returns a fully qualified entityTypeName for a specified resource name. The reverse of this operation
|
|
508
|
+
can be obtained via the [[EntityType.defaultResourceName]] property
|
|
509
|
+
**/
|
|
510
|
+
getEntityTypeNameForResourceName(resourceName) {
|
|
511
|
+
assertParam(resourceName, "resourceName").isString().check();
|
|
512
|
+
return this._resourceEntityTypeMap[resourceName];
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
Associates a resourceName with an entityType.
|
|
516
|
+
|
|
517
|
+
This method is only needed in those cases where multiple resources return the same
|
|
518
|
+
entityType. In this case Metadata discovery will only determine a single resource name for
|
|
519
|
+
each entityType.
|
|
520
|
+
@param resourceName - The resource name
|
|
521
|
+
@param entityTypeOrName - If passing a string either the fully qualified name or a short name may be used. If a short name is specified and multiple types share
|
|
522
|
+
that same short name an exception will be thrown. If the entityType has not yet been discovered then a fully qualified name must be used.
|
|
523
|
+
**/
|
|
524
|
+
setEntityTypeForResourceName(resourceName, entityTypeOrName) {
|
|
525
|
+
assertParam(resourceName, "resourceName").isString().check();
|
|
526
|
+
assertParam(entityTypeOrName, "entityTypeOrName").isInstanceOf(EntityType).or().isString().check();
|
|
527
|
+
let entityTypeName;
|
|
528
|
+
if (entityTypeOrName instanceof EntityType) {
|
|
529
|
+
entityTypeName = entityTypeOrName.name;
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
entityTypeName = getQualifiedTypeName(this, entityTypeOrName, true);
|
|
533
|
+
}
|
|
534
|
+
this._resourceEntityTypeMap[resourceName] = entityTypeName;
|
|
535
|
+
let entityType = this._getStructuralType(entityTypeName, true);
|
|
536
|
+
if (entityType && entityType instanceof EntityType && !entityType.defaultResourceName) {
|
|
537
|
+
entityType.defaultResourceName = resourceName;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
/** __Dev Only__ - for use when creating a new MetadataParserAdapter */
|
|
541
|
+
static parseTypeName(entityTypeName) {
|
|
542
|
+
// TODO: removed
|
|
543
|
+
// if (!entityTypeName) {
|
|
544
|
+
// return null;
|
|
545
|
+
// }
|
|
546
|
+
let typeParts = entityTypeName.split(":#");
|
|
547
|
+
if (typeParts.length > 1) {
|
|
548
|
+
return MetadataStore.makeTypeHash(typeParts[0], typeParts[1]);
|
|
549
|
+
}
|
|
550
|
+
if (core.stringStartsWith(entityTypeName, MetadataStore.ANONTYPE_PREFIX)) {
|
|
551
|
+
let typeHash = MetadataStore.makeTypeHash(entityTypeName);
|
|
552
|
+
typeHash.isAnonymous = true;
|
|
553
|
+
return typeHash;
|
|
554
|
+
}
|
|
555
|
+
let entityTypeNameNoAssembly = entityTypeName.split(",")[0];
|
|
556
|
+
typeParts = entityTypeNameNoAssembly.split(".");
|
|
557
|
+
if (typeParts.length > 1) {
|
|
558
|
+
let shortName = typeParts[typeParts.length - 1];
|
|
559
|
+
let namespaceParts = typeParts.slice(0, typeParts.length - 1);
|
|
560
|
+
let ns = namespaceParts.join(".");
|
|
561
|
+
return MetadataStore.makeTypeHash(shortName, ns);
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
return MetadataStore.makeTypeHash(entityTypeName);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
/** __Dev Only__ - for use when creating a new MetadataParserAdapter */
|
|
568
|
+
static makeTypeHash(shortName, ns) {
|
|
569
|
+
return {
|
|
570
|
+
shortTypeName: shortName,
|
|
571
|
+
namespace: ns,
|
|
572
|
+
typeName: qualifyTypeName(shortName, ns)
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
// protected methods
|
|
576
|
+
/** @hidden @internal */
|
|
577
|
+
_checkEntityType(entity) {
|
|
578
|
+
if (entity.entityType)
|
|
579
|
+
return;
|
|
580
|
+
let typeName = entity.prototype._$typeName;
|
|
581
|
+
if (!typeName) {
|
|
582
|
+
throw new Error("This entity has not been registered. See the MetadataStore.registerEntityTypeCtor method");
|
|
583
|
+
}
|
|
584
|
+
// we know that it is an EntityType ( as opposed to a ComplexType)
|
|
585
|
+
let entityType = this._getStructuralType(typeName);
|
|
586
|
+
if (entityType) {
|
|
587
|
+
entity.entityType = entityType;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
/** @hidden @internal */
|
|
592
|
+
MetadataStore.__id = 0;
|
|
593
|
+
/** @hidden @internal */
|
|
594
|
+
MetadataStore.ANONTYPE_PREFIX = "_IB_";
|
|
595
|
+
/** The version of any MetadataStores created by this class */
|
|
596
|
+
MetadataStore.metadataVersion = '1.0.5';
|
|
597
|
+
// needs to be made avail to dataService.xxx files
|
|
598
|
+
MetadataStore.normalizeTypeName = core.memoize(function (rawTypeName) {
|
|
599
|
+
return rawTypeName && MetadataStore.parseTypeName(rawTypeName).typeName;
|
|
600
|
+
});
|
|
601
|
+
MetadataStore.prototype._$typeName = "MetadataStore";
|
|
602
|
+
BreezeEvent.bubbleEvent(MetadataStore.prototype);
|
|
603
|
+
function getTypesFromMap(typeMap) {
|
|
604
|
+
let types = [];
|
|
605
|
+
for (let key in typeMap) {
|
|
606
|
+
let value = typeMap[key];
|
|
607
|
+
// skip 'shortName' entries
|
|
608
|
+
if (key === value.name) {
|
|
609
|
+
types.push(typeMap[key]);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return types;
|
|
613
|
+
}
|
|
614
|
+
function structuralTypeFromJson(metadataStore, json, allowMerge) {
|
|
615
|
+
let typeName = qualifyTypeName(json.shortName, json.namespace);
|
|
616
|
+
let stype = metadataStore._getStructuralType(typeName, true);
|
|
617
|
+
if (stype) {
|
|
618
|
+
if (allowMerge) {
|
|
619
|
+
return mergeStructuralType(stype, json);
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
// allow it but don't replace anything.
|
|
623
|
+
return stype;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
let config = {
|
|
627
|
+
shortName: json.shortName,
|
|
628
|
+
namespace: json.namespace,
|
|
629
|
+
isAbstract: json.isAbstract,
|
|
630
|
+
autoGeneratedKeyType: AutoGeneratedKeyType.fromName(json.autoGeneratedKeyType),
|
|
631
|
+
defaultResourceName: json.defaultResourceName,
|
|
632
|
+
custom: json.custom
|
|
633
|
+
};
|
|
634
|
+
stype = json.isComplexType ? new ComplexType(config) : new EntityType(config);
|
|
635
|
+
// baseType may not have been imported yet so we need to defer handling this type until later.
|
|
636
|
+
if (json.baseTypeName && stype instanceof EntityType) {
|
|
637
|
+
stype.baseTypeName = json.baseTypeName;
|
|
638
|
+
let baseEntityType = metadataStore._getStructuralType(json.baseTypeName, true);
|
|
639
|
+
if (baseEntityType) {
|
|
640
|
+
completeStructuralTypeFromJson(metadataStore, json, stype);
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
core.getArray(metadataStore._deferredTypes, json.baseTypeName).push({ json: json, stype: stype });
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
completeStructuralTypeFromJson(metadataStore, json, stype);
|
|
648
|
+
}
|
|
649
|
+
// stype may or may not have been added to the metadataStore at this point.
|
|
650
|
+
return stype;
|
|
651
|
+
}
|
|
652
|
+
function mergeStructuralType(stype, json) {
|
|
653
|
+
if (json.custom) {
|
|
654
|
+
stype.custom = json.custom;
|
|
655
|
+
}
|
|
656
|
+
mergeProps(stype, json.dataProperties);
|
|
657
|
+
mergeProps(stype, json.navigationProperties);
|
|
658
|
+
return stype;
|
|
659
|
+
}
|
|
660
|
+
function mergeProps(stype, jsonProps) {
|
|
661
|
+
if (!jsonProps)
|
|
662
|
+
return;
|
|
663
|
+
jsonProps.forEach((jsonProp) => {
|
|
664
|
+
let propName = jsonProp.name;
|
|
665
|
+
if (!propName) {
|
|
666
|
+
if (jsonProp.nameOnServer) {
|
|
667
|
+
propName = stype.metadataStore.namingConvention.serverPropertyNameToClient(jsonProp.nameOnServer, {});
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
// backslash-quote works around compiler bug
|
|
671
|
+
const msg = "Unable to complete \'importMetadata\' - cannot locate a \'name\' or \'nameOnServer\' for one of the imported property nodes";
|
|
672
|
+
throw new Error(msg);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
if (jsonProp.custom) {
|
|
676
|
+
let prop = stype.getProperty(propName, true);
|
|
677
|
+
prop.custom = jsonProp.custom;
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
function completeStructuralTypeFromJson(metadataStore, json, stype) {
|
|
682
|
+
// validators from baseType work because validation walks thru base types
|
|
683
|
+
// so no need to copy down.
|
|
684
|
+
if (json.validators) {
|
|
685
|
+
stype.validators = json.validators.map(Validator.fromJSON);
|
|
686
|
+
}
|
|
687
|
+
json.dataProperties.forEach(function (dp) {
|
|
688
|
+
stype._addPropertyCore(DataProperty.fromJSON(dp));
|
|
689
|
+
});
|
|
690
|
+
let isEntityType = !json.isComplexType;
|
|
691
|
+
if (isEntityType) {
|
|
692
|
+
//noinspection JSHint
|
|
693
|
+
json.navigationProperties && json.navigationProperties.forEach(function (np) {
|
|
694
|
+
stype._addPropertyCore(NavigationProperty.fromJSON(np));
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
metadataStore.addEntityType(stype);
|
|
698
|
+
let deferredTypes = metadataStore._deferredTypes;
|
|
699
|
+
let deferrals = deferredTypes[stype.name];
|
|
700
|
+
if (deferrals) {
|
|
701
|
+
deferrals.forEach(function (d) {
|
|
702
|
+
completeStructuralTypeFromJson(metadataStore, d.json, d.stype);
|
|
703
|
+
});
|
|
704
|
+
delete deferredTypes[stype.name];
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
function getQualifiedTypeName(metadataStore, structTypeName, throwIfNotFound) {
|
|
708
|
+
if (isQualifiedTypeName(structTypeName))
|
|
709
|
+
return structTypeName;
|
|
710
|
+
let result = metadataStore._shortNameMap[structTypeName];
|
|
711
|
+
if (!result && throwIfNotFound) {
|
|
712
|
+
throw new Error("Unable to locate 'entityTypeName' of: " + structTypeName);
|
|
713
|
+
}
|
|
714
|
+
return result;
|
|
715
|
+
}
|
|
716
|
+
/** Container for all of the metadata about a specific type of Entity.
|
|
717
|
+
**/
|
|
718
|
+
export class EntityType {
|
|
719
|
+
/** EntityType constructor
|
|
720
|
+
> let entityType = new EntityType( {
|
|
721
|
+
> shortName: "person",
|
|
722
|
+
> namespace: "myAppNamespace"
|
|
723
|
+
> });
|
|
724
|
+
@param config - Configuration settings or a MetadataStore. If this parameter is just a MetadataStore
|
|
725
|
+
then what will be created is an 'anonymous' type that will never be communicated to or from the server. It is purely for
|
|
726
|
+
client side use and will be given an automatically generated name. Normally, however, you will use a configuration object.
|
|
727
|
+
**/
|
|
728
|
+
constructor(config) {
|
|
729
|
+
/** Always false for an EntityType. **/
|
|
730
|
+
this.isComplexType = false;
|
|
731
|
+
/**
|
|
732
|
+
@deprecated Use [[getCtor]] instead.
|
|
733
|
+
*/
|
|
734
|
+
this.getEntityCtor = this.getCtor;
|
|
735
|
+
if (arguments.length > 1) {
|
|
736
|
+
throw new Error("The EntityType ctor has a single argument that is either a 'MetadataStore' or a configuration object.");
|
|
737
|
+
}
|
|
738
|
+
// let etConfig = <EntityTypeConfig> <any> undefined;
|
|
739
|
+
let etConfig = undefined;
|
|
740
|
+
if (config._$typeName === "MetadataStore") {
|
|
741
|
+
this.metadataStore = config;
|
|
742
|
+
this.shortName = "Anon_" + (++EntityType.__nextAnonIx);
|
|
743
|
+
this.namespace = "";
|
|
744
|
+
this.isAnonymous = true;
|
|
745
|
+
// etConfig = undefined;
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
etConfig = config;
|
|
749
|
+
assertConfig(config)
|
|
750
|
+
.whereParam("shortName").isNonEmptyString()
|
|
751
|
+
.whereParam("namespace").isString().isOptional().withDefault("")
|
|
752
|
+
.whereParam("baseTypeName").isString().isOptional()
|
|
753
|
+
.whereParam("isAbstract").isBoolean().isOptional().withDefault(false)
|
|
754
|
+
.whereParam("autoGeneratedKeyType").isEnumOf(AutoGeneratedKeyType).isOptional().withDefault(AutoGeneratedKeyType.None)
|
|
755
|
+
.whereParam("defaultResourceName").isNonEmptyString().isOptional().withDefault(null)
|
|
756
|
+
.whereParam("dataProperties").isOptional()
|
|
757
|
+
.whereParam("navigationProperties").isOptional()
|
|
758
|
+
.whereParam("serializerFn").isOptional().isFunction()
|
|
759
|
+
.whereParam("custom").isOptional()
|
|
760
|
+
.applyAll(this);
|
|
761
|
+
}
|
|
762
|
+
this.name = qualifyTypeName(this.shortName, this.namespace);
|
|
763
|
+
// the defaultResourceName may also be set up either via metadata lookup or first query or via the 'setProperties' method
|
|
764
|
+
this.dataProperties = [];
|
|
765
|
+
this.navigationProperties = [];
|
|
766
|
+
this.complexProperties = [];
|
|
767
|
+
this.keyProperties = [];
|
|
768
|
+
this.foreignKeyProperties = [];
|
|
769
|
+
this.inverseForeignKeyProperties = [];
|
|
770
|
+
this.concurrencyProperties = [];
|
|
771
|
+
this.unmappedProperties = []; // will be updated later.
|
|
772
|
+
this.validators = [];
|
|
773
|
+
this.warnings = [];
|
|
774
|
+
this._mappedPropertiesCount = 0;
|
|
775
|
+
this.subtypes = [];
|
|
776
|
+
// now process any data/nav props
|
|
777
|
+
if (etConfig && etConfig.dataProperties) {
|
|
778
|
+
addProperties(this, etConfig.dataProperties, DataProperty);
|
|
779
|
+
}
|
|
780
|
+
if (etConfig && etConfig.navigationProperties) {
|
|
781
|
+
addProperties(this, etConfig.navigationProperties, NavigationProperty);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
General purpose property set method
|
|
786
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
787
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
788
|
+
> custType.setProperties( {
|
|
789
|
+
> autoGeneratedKeyType: AutoGeneratedKeyType.Identity;
|
|
790
|
+
> defaultResourceName: "CustomersAndIncludedOrders"
|
|
791
|
+
> )};
|
|
792
|
+
@param config - a configuration object
|
|
793
|
+
**/
|
|
794
|
+
setProperties(config) {
|
|
795
|
+
assertConfig(config)
|
|
796
|
+
.whereParam("autoGeneratedKeyType").isEnumOf(AutoGeneratedKeyType).isOptional()
|
|
797
|
+
.whereParam("defaultResourceName").isString().isOptional()
|
|
798
|
+
.whereParam("serializerFn").isFunction().isOptional()
|
|
799
|
+
.whereParam("custom").isOptional()
|
|
800
|
+
.applyAll(this);
|
|
801
|
+
if (config.defaultResourceName) {
|
|
802
|
+
this.defaultResourceName = config.defaultResourceName;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
Returns whether this type is a subtype of a specified type.
|
|
807
|
+
**/
|
|
808
|
+
isSubtypeOf(entityType) {
|
|
809
|
+
assertParam(entityType, "entityType").isInstanceOf(EntityType).check();
|
|
810
|
+
let baseType = this;
|
|
811
|
+
do {
|
|
812
|
+
if (baseType === entityType)
|
|
813
|
+
return true;
|
|
814
|
+
baseType = baseType.baseEntityType;
|
|
815
|
+
} while (baseType);
|
|
816
|
+
return false;
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
Returns an array containing this type and any/all subtypes of this type down thru the hierarchy.
|
|
820
|
+
**/
|
|
821
|
+
getSelfAndSubtypes() {
|
|
822
|
+
let result = [this];
|
|
823
|
+
this.subtypes.forEach(function (st) {
|
|
824
|
+
let subtypes = st.getSelfAndSubtypes();
|
|
825
|
+
result.push.apply(result, subtypes);
|
|
826
|
+
});
|
|
827
|
+
return result;
|
|
828
|
+
}
|
|
829
|
+
getAllValidators() {
|
|
830
|
+
let result = this.validators.slice(0);
|
|
831
|
+
let bt = this.baseEntityType;
|
|
832
|
+
while (bt) {
|
|
833
|
+
result.push.apply(result, bt.validators);
|
|
834
|
+
bt = bt.baseEntityType;
|
|
835
|
+
}
|
|
836
|
+
return result;
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
Adds a [[DataProperty]] or a [[NavigationProperty]] to this EntityType.
|
|
840
|
+
> // assume myEntityType is a newly constructed EntityType.
|
|
841
|
+
> myEntityType.addProperty(dataProperty1);
|
|
842
|
+
> myEntityType.addProperty(dataProperty2);
|
|
843
|
+
> myEntityType.addProperty(navigationProperty1);
|
|
844
|
+
**/
|
|
845
|
+
addProperty(property) {
|
|
846
|
+
assertParam(property, "property").isInstanceOf(DataProperty).or().isInstanceOf(NavigationProperty).check();
|
|
847
|
+
// true is 2nd arg to force resolve of any navigation properties.
|
|
848
|
+
let newprop = this._addPropertyCore(property, true);
|
|
849
|
+
if (this.subtypes && this.subtypes.length) {
|
|
850
|
+
let stype = this;
|
|
851
|
+
stype.getSelfAndSubtypes().forEach(function (st) {
|
|
852
|
+
if (st !== stype) {
|
|
853
|
+
if (property.isNavigationProperty) {
|
|
854
|
+
st._addPropertyCore(new NavigationProperty(property), true);
|
|
855
|
+
}
|
|
856
|
+
else {
|
|
857
|
+
st._addPropertyCore(new DataProperty(property), true);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
return newprop;
|
|
863
|
+
}
|
|
864
|
+
/** @hidden @internal */
|
|
865
|
+
_updateFromBase(baseEntityType) {
|
|
866
|
+
this.baseEntityType = baseEntityType;
|
|
867
|
+
if (this.autoGeneratedKeyType === AutoGeneratedKeyType.None) {
|
|
868
|
+
this.autoGeneratedKeyType = baseEntityType.autoGeneratedKeyType;
|
|
869
|
+
}
|
|
870
|
+
baseEntityType.dataProperties.forEach((dp) => {
|
|
871
|
+
let newDp = new DataProperty(dp);
|
|
872
|
+
// don't need to copy validators becaue we will walk the hierarchy to find them
|
|
873
|
+
newDp.validators = [];
|
|
874
|
+
newDp.baseProperty = dp;
|
|
875
|
+
this._addPropertyCore(newDp);
|
|
876
|
+
}, this);
|
|
877
|
+
baseEntityType.navigationProperties.forEach((np) => {
|
|
878
|
+
let newNp = new NavigationProperty(np);
|
|
879
|
+
// don't need to copy validators becaue we will walk the hierarchy to find them
|
|
880
|
+
newNp.validators = [];
|
|
881
|
+
newNp.baseProperty = np;
|
|
882
|
+
this._addPropertyCore(newNp);
|
|
883
|
+
}, this);
|
|
884
|
+
baseEntityType.subtypes.push(this);
|
|
885
|
+
}
|
|
886
|
+
/** @hidden @internal */
|
|
887
|
+
_addPropertyCore(property, shouldResolve = false) {
|
|
888
|
+
if (this.isFrozen) {
|
|
889
|
+
throw new Error("The '" + this.name + "' EntityType/ComplexType has been frozen. You can only add properties to an EntityType/ComplexType before any instances of that type have been created and attached to an entityManager.");
|
|
890
|
+
}
|
|
891
|
+
let parentType = property.parentType;
|
|
892
|
+
if (parentType) {
|
|
893
|
+
if (parentType !== this) {
|
|
894
|
+
throw new Error("This property: " + property.name + " has already been added to " + property.parentType.name);
|
|
895
|
+
}
|
|
896
|
+
else {
|
|
897
|
+
// adding the same property more than once to the same entityType is just ignored.
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
property.parentType = this;
|
|
902
|
+
let ms = this.metadataStore;
|
|
903
|
+
// if (property.isDataProperty) { // modified because doesn't act as a type guard
|
|
904
|
+
if (property instanceof DataProperty) {
|
|
905
|
+
this._addDataProperty(property);
|
|
906
|
+
}
|
|
907
|
+
else {
|
|
908
|
+
this._addNavigationProperty(property);
|
|
909
|
+
// metadataStore can be undefined if this entityType has not yet been added to a MetadataStore.
|
|
910
|
+
if (shouldResolve && ms) {
|
|
911
|
+
tryResolveNp(property, ms);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
// unmapped properties can be added AFTER entityType has already resolved all property names.
|
|
915
|
+
if (ms && !(property.name && property.nameOnServer)) {
|
|
916
|
+
updateClientServerNames(ms.namingConvention, property, "name");
|
|
917
|
+
}
|
|
918
|
+
// props can be added after entity prototype has already been wrapped.
|
|
919
|
+
if (ms && this._extra) {
|
|
920
|
+
if (this._extra.alreadyWrappedProps) {
|
|
921
|
+
let proto = this._ctor.prototype;
|
|
922
|
+
config.interfaceRegistry.modelLibrary.getDefaultInstance().initializeEntityPrototype(proto);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
Create a new entity of this type.
|
|
928
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
929
|
+
> let custType = em1.metadataStore.getAsEntityType("Customer");
|
|
930
|
+
> let cust1 = custType.createEntity();
|
|
931
|
+
> em1.addEntity(cust1);
|
|
932
|
+
@param initialValues- Configuration object of the properties to set immediately after creation.
|
|
933
|
+
@return The new entity.
|
|
934
|
+
**/
|
|
935
|
+
createEntity(initialValues) {
|
|
936
|
+
// ignore the _$eref once the entity is attached to an entityManager.
|
|
937
|
+
if (initialValues && initialValues._$eref && !initialValues._$eref.entityAspect.entityManager)
|
|
938
|
+
return initialValues._$eref;
|
|
939
|
+
let instance = this._createInstanceCore();
|
|
940
|
+
if (initialValues) {
|
|
941
|
+
// only assign an _eref if the object is fully "keyed"
|
|
942
|
+
if (this.keyProperties.every(function (kp) {
|
|
943
|
+
return initialValues[kp.name] != null;
|
|
944
|
+
})) {
|
|
945
|
+
initialValues._$eref = instance;
|
|
946
|
+
}
|
|
947
|
+
this._updateTargetFromRaw(instance, initialValues, getRawValueFromConfig);
|
|
948
|
+
this.navigationProperties.forEach(function (np) {
|
|
949
|
+
let relatedEntity;
|
|
950
|
+
let val = initialValues[np.name];
|
|
951
|
+
if (val != undefined) {
|
|
952
|
+
let navEntityType = np.entityType;
|
|
953
|
+
if (np.isScalar) {
|
|
954
|
+
relatedEntity = val.entityAspect ? val : navEntityType.createEntity(val);
|
|
955
|
+
instance.setProperty(np.name, relatedEntity);
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
let relatedEntities = instance.getProperty(np.name);
|
|
959
|
+
val.forEach((v) => {
|
|
960
|
+
relatedEntity = v.entityAspect ? v : navEntityType.createEntity(v);
|
|
961
|
+
relatedEntities.push(relatedEntity);
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
this._initializeInstance(instance);
|
|
968
|
+
return instance;
|
|
969
|
+
}
|
|
970
|
+
/** @hidden @internal */
|
|
971
|
+
_createInstanceCore() {
|
|
972
|
+
let aCtor = this.getCtor();
|
|
973
|
+
let instance = new aCtor();
|
|
974
|
+
new EntityAspect(instance);
|
|
975
|
+
return instance;
|
|
976
|
+
}
|
|
977
|
+
/** @hidden @internal */
|
|
978
|
+
_initializeInstance(instance) {
|
|
979
|
+
if (this.baseEntityType) {
|
|
980
|
+
this.baseEntityType._initializeInstance(instance);
|
|
981
|
+
}
|
|
982
|
+
let initFn = this.initFn;
|
|
983
|
+
if (initFn) {
|
|
984
|
+
let fn = (typeof initFn === "string") ? instance[initFn] : initFn;
|
|
985
|
+
fn(instance);
|
|
986
|
+
}
|
|
987
|
+
this.complexProperties && this.complexProperties.forEach(function (cp) {
|
|
988
|
+
let complexType = cp.dataType;
|
|
989
|
+
let ctInstance = instance.getProperty(cp.name);
|
|
990
|
+
if (Array.isArray(ctInstance)) {
|
|
991
|
+
ctInstance.forEach((ctInst) => {
|
|
992
|
+
complexType._initializeInstance(ctInst);
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
else {
|
|
996
|
+
complexType._initializeInstance(ctInstance);
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
// not needed for complexObjects
|
|
1000
|
+
if (instance.entityAspect) {
|
|
1001
|
+
instance.entityAspect._initialized = true;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
Returns the constructor for this EntityType.
|
|
1006
|
+
@param forceRefresh - Whether to ignore any cached version of this constructor. (default == false)
|
|
1007
|
+
@return The constructor for this EntityType.
|
|
1008
|
+
**/
|
|
1009
|
+
getCtor(forceRefresh = false) {
|
|
1010
|
+
if (this._ctor && !forceRefresh)
|
|
1011
|
+
return this._ctor;
|
|
1012
|
+
let ctorRegistry = this.metadataStore._ctorRegistry;
|
|
1013
|
+
let r = ctorRegistry[this.name] || ctorRegistry[this.shortName] || {};
|
|
1014
|
+
let aCtor = r.ctor || this._ctor;
|
|
1015
|
+
let ctorType = aCtor && aCtor.prototype && (aCtor.prototype.entityType || aCtor.prototype.complexType);
|
|
1016
|
+
if (ctorType && ctorType.metadataStore !== this.metadataStore) {
|
|
1017
|
+
// We can't risk a mismatch between the ctor and the type info in a specific metadatastore
|
|
1018
|
+
// because modelLibraries rely on type info to intercept ctor properties
|
|
1019
|
+
throw new Error("Cannot register the same constructor for " + this.name + " in different metadata stores. Please define a separate constructor for each metadata store.");
|
|
1020
|
+
}
|
|
1021
|
+
if (r.ctor && forceRefresh) {
|
|
1022
|
+
this._extra = undefined;
|
|
1023
|
+
}
|
|
1024
|
+
if (!aCtor) {
|
|
1025
|
+
let createCtor = config.interfaceRegistry.modelLibrary.getDefaultInstance().createCtor;
|
|
1026
|
+
aCtor = createCtor ? createCtor(this) : createEmptyCtor(this);
|
|
1027
|
+
}
|
|
1028
|
+
this.initFn = r.initFn;
|
|
1029
|
+
this.noTrackingFn = r.noTrackingFn;
|
|
1030
|
+
aCtor.prototype._$typeName = this.name;
|
|
1031
|
+
this._setCtor(aCtor);
|
|
1032
|
+
return aCtor;
|
|
1033
|
+
}
|
|
1034
|
+
/** @hidden @internal */
|
|
1035
|
+
// May make public later.
|
|
1036
|
+
_setCtor(aCtor, interceptor) {
|
|
1037
|
+
let instanceProto = aCtor.prototype;
|
|
1038
|
+
// place for extra breeze related data
|
|
1039
|
+
this._extra = this._extra || {};
|
|
1040
|
+
let instance = new aCtor();
|
|
1041
|
+
calcUnmappedProperties(this, instance);
|
|
1042
|
+
if (this._$typeName === "EntityType") {
|
|
1043
|
+
// insure that all of the properties are on the 'template' instance before watching the class.
|
|
1044
|
+
instanceProto.entityType = this;
|
|
1045
|
+
}
|
|
1046
|
+
else {
|
|
1047
|
+
instanceProto.complexType = this;
|
|
1048
|
+
}
|
|
1049
|
+
// defaultPropertyInterceptor is a 'global' (but internal to breeze) function;
|
|
1050
|
+
instanceProto._$interceptor = interceptor || defaultPropertyInterceptor;
|
|
1051
|
+
config.interfaceRegistry.modelLibrary.getDefaultInstance().initializeEntityPrototype(instanceProto);
|
|
1052
|
+
this._ctor = aCtor;
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
Adds either an entity or property level validator to this EntityType.
|
|
1056
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
1057
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
1058
|
+
> let countryProp = custType.getProperty("Country");
|
|
1059
|
+
> let valFn = function (v) {
|
|
1060
|
+
> if (v == null) return true;
|
|
1061
|
+
> return (core.stringStartsWith(v, "US"));
|
|
1062
|
+
> };
|
|
1063
|
+
> let countryValidator = new Validator("countryIsUS", valFn,
|
|
1064
|
+
> { displayName: "Country", messageTemplate: "'%displayName%' must start with 'US'" });
|
|
1065
|
+
> custType.addValidator(countryValidator, countryProp);
|
|
1066
|
+
|
|
1067
|
+
This is the same as adding an entity level validator via the 'validators' property of DataProperty or NavigationProperty
|
|
1068
|
+
> countryProp.validators.push(countryValidator);
|
|
1069
|
+
|
|
1070
|
+
Entity level validators can also be added by omitting the 'property' parameter.
|
|
1071
|
+
> custType.addValidator(someEntityLevelValidator);
|
|
1072
|
+
|
|
1073
|
+
or
|
|
1074
|
+
> custType.validators.push(someEntityLevelValidator);
|
|
1075
|
+
@param validator - Validator to add.
|
|
1076
|
+
@param property - Property to add this validator to. If omitted, the validator is assumed to be an
|
|
1077
|
+
entity level validator and is added to the EntityType's 'validators'.
|
|
1078
|
+
**/
|
|
1079
|
+
addValidator(validator, property) {
|
|
1080
|
+
assertParam(validator, "validator").isInstanceOf(Validator).check();
|
|
1081
|
+
assertParam(property, "property").isOptional().isString().or().isEntityProperty().check();
|
|
1082
|
+
if (property != null) {
|
|
1083
|
+
let prop = (typeof property === 'string') ? this.getProperty(property, true) : property;
|
|
1084
|
+
prop.validators.push(validator);
|
|
1085
|
+
}
|
|
1086
|
+
else {
|
|
1087
|
+
this.validators.push(validator);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
Returns all of the properties ( dataProperties and navigationProperties) for this EntityType.
|
|
1092
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
1093
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
1094
|
+
> let arrayOfProps = custType.getProperties();
|
|
1095
|
+
@return An array of Data and Navigation properties.
|
|
1096
|
+
**/
|
|
1097
|
+
getProperties() {
|
|
1098
|
+
return this.dataProperties.concat(this.navigationProperties);
|
|
1099
|
+
}
|
|
1100
|
+
/**
|
|
1101
|
+
Returns all of the property names ( for both dataProperties and navigationProperties) for this EntityType.
|
|
1102
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
1103
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
1104
|
+
> let arrayOfPropNames = custType.getPropertyNames();
|
|
1105
|
+
**/
|
|
1106
|
+
getPropertyNames() {
|
|
1107
|
+
return this.getProperties().map(core.pluck('name'));
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
Returns a data property with the specified name or null.
|
|
1111
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
1112
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
1113
|
+
> let customerNameDataProp = custType.getDataProperty("CustomerName");
|
|
1114
|
+
@return A DataProperty or null if not found.
|
|
1115
|
+
**/
|
|
1116
|
+
getDataProperty(propertyName) {
|
|
1117
|
+
return core.arrayFirst(this.dataProperties, core.propEq('name', propertyName));
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
Returns a navigation property with the specified name or null.
|
|
1121
|
+
> // assume em1 is an EntityManager containing a number of existing entities.
|
|
1122
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
1123
|
+
> let customerOrdersNavProp = custType.getDataProperty("Orders");
|
|
1124
|
+
@return A NavigationProperty or null if not found.
|
|
1125
|
+
**/
|
|
1126
|
+
getNavigationProperty(propertyName) {
|
|
1127
|
+
return core.arrayFirst(this.navigationProperties, core.propEq('name', propertyName));
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
Returns either a DataProperty or a NavigationProperty with the specified name or null.
|
|
1131
|
+
|
|
1132
|
+
This method also accepts a '.' delimited property path and will return the 'property' at the
|
|
1133
|
+
end of the path.
|
|
1134
|
+
> let custType = em1.metadataStore.getEntityType("Customer");
|
|
1135
|
+
> let companyNameProp = custType.getProperty("CompanyName");
|
|
1136
|
+
|
|
1137
|
+
This method can also walk a property path to return a property
|
|
1138
|
+
> let orderDetailType = em1.metadataStore.getEntityType("OrderDetail");
|
|
1139
|
+
> let companyNameProp2 = orderDetailType.getProperty("Order.Customer.CompanyName");
|
|
1140
|
+
> // companyNameProp === companyNameProp2
|
|
1141
|
+
@param [throwIfNotFound=false] {Boolean} Whether to throw an exception if not found.
|
|
1142
|
+
@return A DataProperty or NavigationProperty or null if not found.
|
|
1143
|
+
**/
|
|
1144
|
+
getProperty(propertyPath, throwIfNotFound = false) {
|
|
1145
|
+
let props = this.getPropertiesOnPath(propertyPath, false, throwIfNotFound);
|
|
1146
|
+
return (props && props.length > 0) ? props[props.length - 1] : null;
|
|
1147
|
+
}
|
|
1148
|
+
/** @hidden @internal */
|
|
1149
|
+
// TODO: have this return empty array instead of null and fix consumers.
|
|
1150
|
+
// TODO: think about renaming with '_' prefix.
|
|
1151
|
+
getPropertiesOnPath(propertyPath, useServerName, throwIfNotFound = false) {
|
|
1152
|
+
let propertyNames = (Array.isArray(propertyPath)) ? propertyPath : propertyPath.trim().split('.');
|
|
1153
|
+
let ok = true;
|
|
1154
|
+
let key = useServerName === true ? "nameOnServer" : useServerName === false ? "name" : null;
|
|
1155
|
+
let parentType = this;
|
|
1156
|
+
const getProps = (propName) => {
|
|
1157
|
+
const fn = key === null ? core.propsEq("name", "nameOnServer", propName) : core.propEq(key, propName);
|
|
1158
|
+
let prop = core.arrayFirst(parentType.getProperties(), fn);
|
|
1159
|
+
if (prop) {
|
|
1160
|
+
parentType = (prop instanceof NavigationProperty) ? prop.entityType : prop.dataType;
|
|
1161
|
+
// parentType = prop.isNavigationProperty ? prop.entityType : prop.dataType;
|
|
1162
|
+
}
|
|
1163
|
+
else if (throwIfNotFound) {
|
|
1164
|
+
throw new Error("unable to locate property: " + propName + " on entityType: " + parentType.name);
|
|
1165
|
+
}
|
|
1166
|
+
else {
|
|
1167
|
+
ok = false;
|
|
1168
|
+
}
|
|
1169
|
+
return prop;
|
|
1170
|
+
};
|
|
1171
|
+
let props = propertyNames.map(getProps);
|
|
1172
|
+
return ok ? props : null;
|
|
1173
|
+
}
|
|
1174
|
+
/** For use in pluggable adapters. */
|
|
1175
|
+
// TODO: document use
|
|
1176
|
+
clientPropertyPathToServer(propertyPath, delimiter = '.') {
|
|
1177
|
+
let propNames;
|
|
1178
|
+
if (this.isAnonymous) {
|
|
1179
|
+
let fn = this.metadataStore.namingConvention.clientPropertyNameToServer;
|
|
1180
|
+
propNames = propertyPath.split(".").map(function (propName) {
|
|
1181
|
+
return fn(propName);
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
else {
|
|
1185
|
+
let props = this.getPropertiesOnPath(propertyPath, false, true);
|
|
1186
|
+
propNames = props.map((prop) => prop.nameOnServer);
|
|
1187
|
+
}
|
|
1188
|
+
return propNames.join(delimiter);
|
|
1189
|
+
}
|
|
1190
|
+
/** For use in pluggable adapters. */
|
|
1191
|
+
// TODO: document use
|
|
1192
|
+
getEntityKeyFromRawEntity(rawEntity, rawValueFn) {
|
|
1193
|
+
let keyValues = this.keyProperties.map((dp) => {
|
|
1194
|
+
let val = rawValueFn(rawEntity, dp);
|
|
1195
|
+
return DataType.parseRawValue(val, dp.dataType);
|
|
1196
|
+
});
|
|
1197
|
+
return new EntityKey(this, keyValues);
|
|
1198
|
+
}
|
|
1199
|
+
/** @hidden @internal */
|
|
1200
|
+
_updateTargetFromRaw(target, raw, rawValueFn) {
|
|
1201
|
+
// called recursively for complex properties
|
|
1202
|
+
this.dataProperties.forEach((dp) => {
|
|
1203
|
+
if (!dp.isSettable)
|
|
1204
|
+
return;
|
|
1205
|
+
let rawVal = rawValueFn(raw, dp);
|
|
1206
|
+
if (rawVal === undefined)
|
|
1207
|
+
return;
|
|
1208
|
+
let dataType = dp.dataType; // this will be a complexType when dp is a complexProperty
|
|
1209
|
+
let oldVal;
|
|
1210
|
+
if (dp.isComplexProperty) {
|
|
1211
|
+
let complexType = dp.dataType;
|
|
1212
|
+
if (rawVal === null)
|
|
1213
|
+
return; // rawVal may be null in nosql dbs where it was never defined for the given row.
|
|
1214
|
+
oldVal = target.getProperty(dp.name);
|
|
1215
|
+
if (dp.isScalar) {
|
|
1216
|
+
complexType._updateTargetFromRaw(oldVal, rawVal, rawValueFn);
|
|
1217
|
+
}
|
|
1218
|
+
else {
|
|
1219
|
+
if (Array.isArray(rawVal)) {
|
|
1220
|
+
let newVal = rawVal.map(function (rawCo) {
|
|
1221
|
+
let newCo = complexType._createInstanceCore(target, dp);
|
|
1222
|
+
complexType._updateTargetFromRaw(newCo, rawCo, rawValueFn);
|
|
1223
|
+
complexType._initializeInstance(newCo);
|
|
1224
|
+
return newCo;
|
|
1225
|
+
});
|
|
1226
|
+
if (!core.arrayEquals(oldVal, newVal, coEquals)) {
|
|
1227
|
+
// clear the old array and push new objects into it.
|
|
1228
|
+
oldVal.length = 0;
|
|
1229
|
+
newVal.forEach(function (nv) {
|
|
1230
|
+
oldVal.push(nv);
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
else {
|
|
1235
|
+
oldVal.length = 0;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
else {
|
|
1240
|
+
if (dp.isScalar) {
|
|
1241
|
+
let newVal = DataType.parseRawValue(rawVal, dataType);
|
|
1242
|
+
target.setProperty(dp.name, newVal);
|
|
1243
|
+
}
|
|
1244
|
+
else {
|
|
1245
|
+
oldVal = target.getProperty(dp.name);
|
|
1246
|
+
if (Array.isArray(rawVal)) {
|
|
1247
|
+
// need to compare values
|
|
1248
|
+
let newVal = rawVal.map((rv) => {
|
|
1249
|
+
return DataType.parseRawValue(rv, dataType);
|
|
1250
|
+
});
|
|
1251
|
+
if (!core.arrayEquals(oldVal, newVal)) {
|
|
1252
|
+
// clear the old array and push new objects into it.
|
|
1253
|
+
oldVal.length = 0;
|
|
1254
|
+
newVal.forEach(function (nv) {
|
|
1255
|
+
oldVal.push(nv);
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
else {
|
|
1260
|
+
oldVal.length = 0;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
// if merging from an import then raw will have an entityAspect or a complexAspect
|
|
1266
|
+
let rawAspect = raw.entityAspect || raw.complexAspect;
|
|
1267
|
+
if (rawAspect) {
|
|
1268
|
+
let targetAspect = EntityAspect.isEntity(target) ? target.entityAspect : target.complexAspect;
|
|
1269
|
+
if (rawAspect.originalValuesMap) {
|
|
1270
|
+
targetAspect.originalValues = rawAspect.originalValuesMap;
|
|
1271
|
+
}
|
|
1272
|
+
if (rawAspect.extraMetadata) {
|
|
1273
|
+
targetAspect.extraMetadata = rawAspect.extraMetadata;
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
Returns a string representation of this EntityType.
|
|
1279
|
+
**/
|
|
1280
|
+
toString() {
|
|
1281
|
+
return this.name;
|
|
1282
|
+
}
|
|
1283
|
+
toJSON() {
|
|
1284
|
+
return core.toJson(this, {
|
|
1285
|
+
shortName: null,
|
|
1286
|
+
namespace: null,
|
|
1287
|
+
baseTypeName: null,
|
|
1288
|
+
isAbstract: false,
|
|
1289
|
+
autoGeneratedKeyType: null,
|
|
1290
|
+
defaultResourceName: null,
|
|
1291
|
+
dataProperties: localPropsOnly,
|
|
1292
|
+
navigationProperties: localPropsOnly,
|
|
1293
|
+
validators: null,
|
|
1294
|
+
custom: null
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
/** @hidden @internal */
|
|
1298
|
+
_updateNames(property) {
|
|
1299
|
+
let nc = this.metadataStore.namingConvention;
|
|
1300
|
+
updateClientServerNames(nc, property, "name");
|
|
1301
|
+
if (property.isNavigationProperty) {
|
|
1302
|
+
updateClientServerNames(nc, property, "foreignKeyNames");
|
|
1303
|
+
updateClientServerNames(nc, property, "invForeignKeyNames");
|
|
1304
|
+
// these will get set later via _updateNps
|
|
1305
|
+
// this.inverse
|
|
1306
|
+
// this.entityType
|
|
1307
|
+
// this.relatedDataProperties
|
|
1308
|
+
// dataProperty.relatedNavigationProperty
|
|
1309
|
+
// dataProperty.inverseNavigationProperty
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
/** @hidden @internal */
|
|
1313
|
+
_checkNavProperty(navigationProperty) {
|
|
1314
|
+
// if (navigationProperty.isNavigationProperty) {
|
|
1315
|
+
if (navigationProperty instanceof NavigationProperty) {
|
|
1316
|
+
if (navigationProperty.parentType !== this) {
|
|
1317
|
+
throw new Error(core.formatString("The navigationProperty '%1' is not a property of entity type '%2'", navigationProperty.name, this.name));
|
|
1318
|
+
}
|
|
1319
|
+
return navigationProperty;
|
|
1320
|
+
}
|
|
1321
|
+
if (typeof (navigationProperty) === 'string') {
|
|
1322
|
+
let np = this.getProperty(navigationProperty);
|
|
1323
|
+
// if (np && np.isNavigationProperty) return np;
|
|
1324
|
+
if (np && np instanceof NavigationProperty)
|
|
1325
|
+
return np;
|
|
1326
|
+
}
|
|
1327
|
+
throw new Error("The 'navigationProperty' parameter must either be a NavigationProperty or the name of a NavigationProperty");
|
|
1328
|
+
}
|
|
1329
|
+
/** @hidden @internal */
|
|
1330
|
+
_addDataProperty(dp) {
|
|
1331
|
+
this.dataProperties.push(dp);
|
|
1332
|
+
if (dp.isPartOfKey) {
|
|
1333
|
+
this.keyProperties.push(dp);
|
|
1334
|
+
}
|
|
1335
|
+
if (dp.isComplexProperty) {
|
|
1336
|
+
this.complexProperties.push(dp);
|
|
1337
|
+
}
|
|
1338
|
+
if (dp.concurrencyMode && dp.concurrencyMode !== "None") {
|
|
1339
|
+
this.concurrencyProperties.push(dp);
|
|
1340
|
+
}
|
|
1341
|
+
if (dp.isUnmapped) {
|
|
1342
|
+
this.unmappedProperties.push(dp);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
/** @hidden @internal */
|
|
1346
|
+
_addNavigationProperty(np) {
|
|
1347
|
+
this.navigationProperties.push(np);
|
|
1348
|
+
if (!isQualifiedTypeName(np.entityTypeName)) {
|
|
1349
|
+
np.entityTypeName = qualifyTypeName(np.entityTypeName, this.namespace);
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
/** @hidden @internal */
|
|
1353
|
+
_updateCps() {
|
|
1354
|
+
let metadataStore = this.metadataStore;
|
|
1355
|
+
let incompleteTypeMap = metadataStore._incompleteComplexTypeMap;
|
|
1356
|
+
this.complexProperties.forEach(function (cp) {
|
|
1357
|
+
if (cp.complexType)
|
|
1358
|
+
return;
|
|
1359
|
+
if (!resolveCp(cp, metadataStore)) {
|
|
1360
|
+
core.getArray(incompleteTypeMap, cp.complexTypeName).push(cp);
|
|
1361
|
+
}
|
|
1362
|
+
});
|
|
1363
|
+
if (this.isComplexType) {
|
|
1364
|
+
(incompleteTypeMap[this.name] || []).forEach(function (cp) {
|
|
1365
|
+
resolveCp(cp, metadataStore);
|
|
1366
|
+
});
|
|
1367
|
+
delete incompleteTypeMap[this.name];
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
/** @hidden @internal */
|
|
1371
|
+
_updateNps() {
|
|
1372
|
+
let metadataStore = this.metadataStore;
|
|
1373
|
+
// resolve all navProps for this entityType
|
|
1374
|
+
this.navigationProperties.forEach(function (np) {
|
|
1375
|
+
tryResolveNp(np, metadataStore);
|
|
1376
|
+
});
|
|
1377
|
+
let incompleteTypeMap = metadataStore._incompleteTypeMap;
|
|
1378
|
+
// next resolve all navProp that point to this entityType.
|
|
1379
|
+
(incompleteTypeMap[this.name] || []).forEach(function (np) {
|
|
1380
|
+
tryResolveNp(np, metadataStore);
|
|
1381
|
+
});
|
|
1382
|
+
// every navProp that pointed to this type should now be resolved
|
|
1383
|
+
delete incompleteTypeMap[this.name];
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
/** @hidden @internal */
|
|
1387
|
+
EntityType.__nextAnonIx = 0;
|
|
1388
|
+
/** @hidden @internal */
|
|
1389
|
+
EntityType.qualifyTypeName = qualifyTypeName;
|
|
1390
|
+
EntityType.prototype._$typeName = "EntityType";
|
|
1391
|
+
function getRawValueFromConfig(rawEntity, dp) {
|
|
1392
|
+
// 'true' fork can happen if an initializer contains an actaul instance of an already created complex object.
|
|
1393
|
+
return (rawEntity.entityAspect || rawEntity.complexAspect) ? rawEntity.getProperty(dp.name) : rawEntity[dp.name];
|
|
1394
|
+
}
|
|
1395
|
+
function updateClientServerNames(nc, parent, clientPropName) {
|
|
1396
|
+
let serverPropName = clientPropName + "OnServer";
|
|
1397
|
+
let clientName = parent[clientPropName];
|
|
1398
|
+
if (clientName && clientName.length) {
|
|
1399
|
+
// if (parent.isUnmapped) return;
|
|
1400
|
+
let serverNames = core.toArray(clientName).map(function (cName) {
|
|
1401
|
+
let sName = nc.clientPropertyNameToServer(cName, parent);
|
|
1402
|
+
let testName = nc.serverPropertyNameToClient(sName, parent);
|
|
1403
|
+
if (cName !== testName) {
|
|
1404
|
+
throw new Error("NamingConvention for this client property name does not roundtrip properly:" + cName + "-->" + testName);
|
|
1405
|
+
}
|
|
1406
|
+
return sName;
|
|
1407
|
+
});
|
|
1408
|
+
parent[serverPropName] = Array.isArray(clientName) ? serverNames : serverNames[0];
|
|
1409
|
+
}
|
|
1410
|
+
else {
|
|
1411
|
+
let serverName = parent[serverPropName];
|
|
1412
|
+
if ((!serverName) || serverName.length === 0)
|
|
1413
|
+
return;
|
|
1414
|
+
let clientNames = core.toArray(serverName).map(function (sName) {
|
|
1415
|
+
let cName = nc.serverPropertyNameToClient(sName, parent);
|
|
1416
|
+
let testName = nc.clientPropertyNameToServer(cName, parent);
|
|
1417
|
+
if (sName !== testName) {
|
|
1418
|
+
throw new Error("NamingConvention for this server property name does not roundtrip properly:" + sName + "-->" + testName);
|
|
1419
|
+
}
|
|
1420
|
+
return cName;
|
|
1421
|
+
});
|
|
1422
|
+
parent[clientPropName] = Array.isArray(serverName) ? clientNames : clientNames[0];
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
function createEmptyCtor(type) {
|
|
1426
|
+
if (config.noEval) {
|
|
1427
|
+
let Entity = function () { };
|
|
1428
|
+
return Entity;
|
|
1429
|
+
}
|
|
1430
|
+
else {
|
|
1431
|
+
let name = type.name.replace(/\W/g, '_');
|
|
1432
|
+
return Function('return function ' + name + '(){}')();
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
function coEquals(co1, co2) {
|
|
1436
|
+
let complexType = co1.complexAspect.parentProperty.dataType;
|
|
1437
|
+
let dataProps = complexType.dataProperties;
|
|
1438
|
+
let areEqual = dataProps.every(function (dp) {
|
|
1439
|
+
if (!dp.isSettable)
|
|
1440
|
+
return true;
|
|
1441
|
+
let v1 = co1.getProperty(dp.name);
|
|
1442
|
+
let v2 = co2.getProperty(dp.name);
|
|
1443
|
+
if (dp.isComplexProperty && dp.isScalar) {
|
|
1444
|
+
return coEquals(v1, v2);
|
|
1445
|
+
}
|
|
1446
|
+
else if (dp.isComplexProperty && !dp.isScalar) {
|
|
1447
|
+
return core.arrayEquals(v1, v2, coEquals);
|
|
1448
|
+
}
|
|
1449
|
+
else {
|
|
1450
|
+
let dataType = dp.dataType; // this will be a complexType when dp is a complexProperty
|
|
1451
|
+
return (v1 === v2 || (dataType && dataType.normalize && v1 && v2 && dataType.normalize(v1) === dataType.normalize(v2)));
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
return areEqual;
|
|
1455
|
+
}
|
|
1456
|
+
function localPropsOnly(props) {
|
|
1457
|
+
return props.filter(function (prop) {
|
|
1458
|
+
return prop.baseProperty == null;
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
function resolveCp(cp, metadataStore) {
|
|
1462
|
+
let complexType = metadataStore._getStructuralType(cp.complexTypeName, true);
|
|
1463
|
+
if (!complexType)
|
|
1464
|
+
return false;
|
|
1465
|
+
if (!(complexType instanceof ComplexType)) {
|
|
1466
|
+
throw new Error("Unable to resolve ComplexType with the name: " + cp.complexTypeName + " for the property: " + cp.name);
|
|
1467
|
+
}
|
|
1468
|
+
cp.dataType = complexType;
|
|
1469
|
+
cp.defaultValue = null;
|
|
1470
|
+
return true;
|
|
1471
|
+
}
|
|
1472
|
+
function tryResolveNp(np, metadataStore) {
|
|
1473
|
+
if (np.entityType)
|
|
1474
|
+
return true;
|
|
1475
|
+
let entityType = metadataStore._getStructuralType(np.entityTypeName, true);
|
|
1476
|
+
if (entityType) {
|
|
1477
|
+
np.entityType = entityType;
|
|
1478
|
+
np._resolveNp();
|
|
1479
|
+
// don't bother removing - _updateNps will do it later.
|
|
1480
|
+
// __arrayRemoveItem(incompleteNps, np, false);
|
|
1481
|
+
}
|
|
1482
|
+
else {
|
|
1483
|
+
let incompleteNps = core.getArray(metadataStore._incompleteTypeMap, np.entityTypeName);
|
|
1484
|
+
core.arrayAddItemUnique(incompleteNps, np);
|
|
1485
|
+
}
|
|
1486
|
+
return !!entityType;
|
|
1487
|
+
}
|
|
1488
|
+
function calcUnmappedProperties(stype, instance) {
|
|
1489
|
+
let metadataPropNames = stype.getPropertyNames();
|
|
1490
|
+
let modelLib = config.interfaceRegistry.modelLibrary.getDefaultInstance();
|
|
1491
|
+
let trackablePropNames = modelLib.getTrackablePropertyNames(instance);
|
|
1492
|
+
trackablePropNames.forEach(function (pn) {
|
|
1493
|
+
if (metadataPropNames.indexOf(pn) === -1) {
|
|
1494
|
+
let val = instance[pn];
|
|
1495
|
+
try {
|
|
1496
|
+
if (typeof val === "function")
|
|
1497
|
+
val = val();
|
|
1498
|
+
}
|
|
1499
|
+
catch (e) {
|
|
1500
|
+
}
|
|
1501
|
+
let dt = DataType.fromValue(val);
|
|
1502
|
+
let newProp = new DataProperty({
|
|
1503
|
+
name: pn,
|
|
1504
|
+
dataType: dt,
|
|
1505
|
+
isNullable: true,
|
|
1506
|
+
isUnmapped: true
|
|
1507
|
+
});
|
|
1508
|
+
newProp.isSettable = core.isSettable(instance, pn);
|
|
1509
|
+
if (stype instanceof EntityType && stype.subtypes != null && stype.subtypes.length) {
|
|
1510
|
+
stype.getSelfAndSubtypes().forEach((st) => {
|
|
1511
|
+
st._addPropertyCore(new DataProperty(newProp));
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1514
|
+
else {
|
|
1515
|
+
stype._addPropertyCore(newProp);
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
});
|
|
1519
|
+
}
|
|
1520
|
+
/** Container for all of the metadata about a specific type of Complex object.
|
|
1521
|
+
> let complexType = new ComplexType( {
|
|
1522
|
+
> shortName: "address",
|
|
1523
|
+
> namespace: "myAppNamespace"
|
|
1524
|
+
> });
|
|
1525
|
+
@param config - Configuration settings
|
|
1526
|
+
**/
|
|
1527
|
+
export class ComplexType {
|
|
1528
|
+
constructor(config) {
|
|
1529
|
+
/** For polymorphic purpose only - always true here */
|
|
1530
|
+
this.isComplexType = true;
|
|
1531
|
+
// copy entityType methods onto complexType
|
|
1532
|
+
/** See [[EntityType.getCtor]] */
|
|
1533
|
+
this.getCtor = EntityType.prototype.getCtor;
|
|
1534
|
+
// note the name change.
|
|
1535
|
+
this.createInstance = EntityType.prototype.createEntity;
|
|
1536
|
+
/** See [EntityType.addValidator] */
|
|
1537
|
+
this.addValidator = EntityType.prototype.addValidator;
|
|
1538
|
+
this.getProperty = EntityType.prototype.getProperty;
|
|
1539
|
+
this.getPropertiesOnPath = EntityType.prototype.getPropertiesOnPath;
|
|
1540
|
+
this.getPropertyNames = EntityType.prototype.getPropertyNames;
|
|
1541
|
+
/** @hidden @internal */
|
|
1542
|
+
this._addPropertyCore = EntityType.prototype._addPropertyCore;
|
|
1543
|
+
/** @hidden @internal */
|
|
1544
|
+
this._addDataProperty = EntityType.prototype._addDataProperty;
|
|
1545
|
+
/** @hidden @internal */
|
|
1546
|
+
this._updateNames = EntityType.prototype._updateNames;
|
|
1547
|
+
/** @hidden @internal */
|
|
1548
|
+
this._updateCps = EntityType.prototype._updateCps;
|
|
1549
|
+
/** @hidden @internal */
|
|
1550
|
+
this._initializeInstance = EntityType.prototype._initializeInstance;
|
|
1551
|
+
/** @hidden @internal */
|
|
1552
|
+
this._updateTargetFromRaw = EntityType.prototype._updateTargetFromRaw;
|
|
1553
|
+
/** @hidden @internal */
|
|
1554
|
+
this._setCtor = EntityType.prototype._setCtor;
|
|
1555
|
+
if (arguments.length > 1) {
|
|
1556
|
+
throw new Error("The ComplexType ctor has a single argument that is a configuration object.");
|
|
1557
|
+
}
|
|
1558
|
+
assertConfig(config)
|
|
1559
|
+
.whereParam("shortName").isNonEmptyString()
|
|
1560
|
+
.whereParam("namespace").isString().isOptional().withDefault("")
|
|
1561
|
+
.whereParam("dataProperties").isOptional()
|
|
1562
|
+
.whereParam("isComplexType").isOptional().isBoolean() // needed because this ctor can get called from the addEntityType method which needs the isComplexType prop
|
|
1563
|
+
.whereParam("custom").isOptional()
|
|
1564
|
+
.applyAll(this);
|
|
1565
|
+
this.name = qualifyTypeName(this.shortName, this.namespace);
|
|
1566
|
+
this.isComplexType = true;
|
|
1567
|
+
this.dataProperties = [];
|
|
1568
|
+
this.complexProperties = [];
|
|
1569
|
+
this.validators = [];
|
|
1570
|
+
this.concurrencyProperties = [];
|
|
1571
|
+
this.unmappedProperties = [];
|
|
1572
|
+
this._mappedPropertiesCount = 0;
|
|
1573
|
+
// keyProperties and navigationProperties are not used on complexTypes - but here to allow sharing of code between EntityType and ComplexType.
|
|
1574
|
+
this.navigationProperties = [];
|
|
1575
|
+
this.keyProperties = []; // may be used later to enforce uniqueness on arrays of complextypes.
|
|
1576
|
+
if (config.dataProperties) {
|
|
1577
|
+
addProperties(this, config.dataProperties, DataProperty);
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
/**
|
|
1581
|
+
General purpose property set method
|
|
1582
|
+
> // assume em1 is an EntityManager
|
|
1583
|
+
> let addresstType = em1.metadataStore.getEntityType("Address");
|
|
1584
|
+
> addressType.setProperties( {
|
|
1585
|
+
> custom: { foo: 7, bar: "test" }
|
|
1586
|
+
> });
|
|
1587
|
+
@param config - Custom config object
|
|
1588
|
+
@param config.custom - {Object}
|
|
1589
|
+
**/
|
|
1590
|
+
setProperties(config) {
|
|
1591
|
+
assertConfig(config)
|
|
1592
|
+
.whereParam("custom").isOptional()
|
|
1593
|
+
.applyAll(this);
|
|
1594
|
+
}
|
|
1595
|
+
getAllValidators() {
|
|
1596
|
+
// ComplexType inheritance is not YET supported.
|
|
1597
|
+
return this.validators;
|
|
1598
|
+
}
|
|
1599
|
+
/** @hidden @internal */
|
|
1600
|
+
_createInstanceCore(parent, parentProperty) {
|
|
1601
|
+
let aCtor = this.getCtor();
|
|
1602
|
+
let instance = new aCtor();
|
|
1603
|
+
new ComplexAspect(instance, parent, parentProperty);
|
|
1604
|
+
// initialization occurs during either attach or in createInstance call.
|
|
1605
|
+
return instance;
|
|
1606
|
+
}
|
|
1607
|
+
addProperty(dataProperty) {
|
|
1608
|
+
assertParam(dataProperty, "dataProperty").isInstanceOf(DataProperty).check();
|
|
1609
|
+
return this._addPropertyCore(dataProperty);
|
|
1610
|
+
}
|
|
1611
|
+
getProperties() {
|
|
1612
|
+
return this.dataProperties;
|
|
1613
|
+
}
|
|
1614
|
+
toJSON() {
|
|
1615
|
+
return core.toJson(this, {
|
|
1616
|
+
shortName: null,
|
|
1617
|
+
namespace: null,
|
|
1618
|
+
isComplexType: null,
|
|
1619
|
+
dataProperties: null,
|
|
1620
|
+
validators: null,
|
|
1621
|
+
custom: null
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
ComplexType.prototype._$typeName = "ComplexType";
|
|
1626
|
+
/** Creates an instance of this complexType */
|
|
1627
|
+
ComplexType.prototype.createInstance = EntityType.prototype.createEntity;
|
|
1628
|
+
/**
|
|
1629
|
+
A DataProperty describes the metadata for a single property of an [[EntityType]] that contains simple data.
|
|
1630
|
+
|
|
1631
|
+
Instances of the DataProperty class are constructed automatically during Metadata retrieval. However it is also possible to construct them
|
|
1632
|
+
directly via the constructor.
|
|
1633
|
+
**/
|
|
1634
|
+
export class DataProperty {
|
|
1635
|
+
/** DataProperty constructor
|
|
1636
|
+
> let lastNameProp = new DataProperty( {
|
|
1637
|
+
> name: "lastName",
|
|
1638
|
+
> dataType: DataType.String,
|
|
1639
|
+
> isNullable: true,
|
|
1640
|
+
> maxLength: 20
|
|
1641
|
+
> });
|
|
1642
|
+
> // assuming personEntityType is a newly constructed EntityType
|
|
1643
|
+
> personEntityType.addProperty(lastNameProperty);
|
|
1644
|
+
@param config - A configuration Object or a DataProperty
|
|
1645
|
+
*/
|
|
1646
|
+
constructor(config) {
|
|
1647
|
+
/** Is this a DataProperty? - always true here. Allows polymorphic treatment of DataProperties and NavigationProperties. __Read Only__ */
|
|
1648
|
+
this.isDataProperty = true;
|
|
1649
|
+
/** Is this a NavigationProperty? - always false here. Allows polymorphic treatment of DataProperties and NavigationProperties. __Read Only__ */
|
|
1650
|
+
this.isNavigationProperty = false;
|
|
1651
|
+
assertConfig(config)
|
|
1652
|
+
.whereParam("name").isString().isOptional()
|
|
1653
|
+
.whereParam("nameOnServer").isString().isOptional()
|
|
1654
|
+
.whereParam("dataType").isEnumOf(DataType).isOptional().or().isString().or().isInstanceOf(ComplexType)
|
|
1655
|
+
.whereParam("complexTypeName").isOptional()
|
|
1656
|
+
.whereParam("isNullable").isBoolean().isOptional().withDefault(true)
|
|
1657
|
+
.whereParam("isScalar").isOptional().withDefault(true) // will be false for some NoSQL databases.
|
|
1658
|
+
.whereParam("defaultValue").isOptional()
|
|
1659
|
+
.whereParam("isPartOfKey").isBoolean().isOptional()
|
|
1660
|
+
.whereParam("isUnmapped").isBoolean().isOptional()
|
|
1661
|
+
.whereParam("isSettable").isBoolean().isOptional().withDefault(true)
|
|
1662
|
+
.whereParam("concurrencyMode").isString().isOptional()
|
|
1663
|
+
.whereParam("maxLength").isNumber().isOptional()
|
|
1664
|
+
.whereParam("validators").isInstanceOf(Validator).isArray().isOptional().withDefault([])
|
|
1665
|
+
.whereParam("displayName").isOptional()
|
|
1666
|
+
.whereParam("enumType").isOptional()
|
|
1667
|
+
.whereParam("rawTypeName").isOptional() // occurs with undefined datatypes
|
|
1668
|
+
.whereParam("custom").isOptional()
|
|
1669
|
+
.applyAll(this);
|
|
1670
|
+
let hasName = !!(this.name || this.nameOnServer);
|
|
1671
|
+
if (!hasName) {
|
|
1672
|
+
throw new Error("A DataProperty must be instantiated with either a 'name' or a 'nameOnServer' property");
|
|
1673
|
+
}
|
|
1674
|
+
// name/nameOnServer is resolved later when a metadataStore is available.
|
|
1675
|
+
if (this.complexTypeName) {
|
|
1676
|
+
this.isComplexProperty = true;
|
|
1677
|
+
// this.dataType = null; // TODO: would like to remove this line because dataType will be set later.
|
|
1678
|
+
}
|
|
1679
|
+
else if (typeof (this.dataType) === "string") {
|
|
1680
|
+
let dt = DataType.fromName(this.dataType);
|
|
1681
|
+
if (!dt) {
|
|
1682
|
+
throw new Error("Unable to find a DataType enumeration by the name of: " + this.dataType);
|
|
1683
|
+
}
|
|
1684
|
+
this.dataType = dt;
|
|
1685
|
+
}
|
|
1686
|
+
else if (!this.dataType) {
|
|
1687
|
+
this.dataType = DataType.String;
|
|
1688
|
+
}
|
|
1689
|
+
// == as opposed to === is deliberate here.
|
|
1690
|
+
if (this.defaultValue == null) {
|
|
1691
|
+
if (this.isNullable) {
|
|
1692
|
+
this.defaultValue = null;
|
|
1693
|
+
}
|
|
1694
|
+
else {
|
|
1695
|
+
if (this.isComplexProperty) {
|
|
1696
|
+
// what to do? - shouldn't happen from EF - but otherwise ???
|
|
1697
|
+
}
|
|
1698
|
+
else if (this.dataType === DataType.Binary) {
|
|
1699
|
+
this.defaultValue = "AAAAAAAAJ3U="; // hack for all binary fields but value is specifically valid for timestamp fields - arbitrary valid 8 byte base64 value.
|
|
1700
|
+
}
|
|
1701
|
+
else {
|
|
1702
|
+
this.defaultValue = this.dataType.defaultValue;
|
|
1703
|
+
const msg = "A nonnullable DataProperty cannot have a null defaultValue. Name: " + (this.name || this.nameOnServer);
|
|
1704
|
+
if (this.defaultValue === null) {
|
|
1705
|
+
throw new Error(msg); // if defaultValue is explicity set to null, that's an error
|
|
1706
|
+
}
|
|
1707
|
+
else if (this.defaultValue == null) {
|
|
1708
|
+
console.warn(msg); // if defaultValue is not set, that's a warning
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
else if (this.dataType.isNumeric) {
|
|
1714
|
+
// in case the defaultValue comes in as a string ( which it does in EF6).
|
|
1715
|
+
if (typeof (this.defaultValue) === "string") {
|
|
1716
|
+
this.defaultValue = parseFloat(this.defaultValue);
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
if (this.isComplexProperty) {
|
|
1720
|
+
this.isScalar = this.isScalar == null || this.isScalar === true;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
static getRawValueFromServer(rawEntity, dp) {
|
|
1724
|
+
if (dp.isUnmapped) {
|
|
1725
|
+
return rawEntity[dp.nameOnServer || dp.name];
|
|
1726
|
+
}
|
|
1727
|
+
else {
|
|
1728
|
+
let val = rawEntity[dp.nameOnServer];
|
|
1729
|
+
return val !== undefined ? val : dp.defaultValue;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
static getRawValueFromClient(rawEntity, dp) {
|
|
1733
|
+
let val = rawEntity[dp.name];
|
|
1734
|
+
return val !== undefined ? val : dp.defaultValue;
|
|
1735
|
+
}
|
|
1736
|
+
resolveProperty(propName) {
|
|
1737
|
+
let result = this[propName];
|
|
1738
|
+
let baseProp = this.baseProperty;
|
|
1739
|
+
while (result == undefined && baseProp != null) {
|
|
1740
|
+
result = baseProp[propName];
|
|
1741
|
+
baseProp = baseProp.baseProperty;
|
|
1742
|
+
}
|
|
1743
|
+
return result;
|
|
1744
|
+
}
|
|
1745
|
+
formatName() {
|
|
1746
|
+
return this.parentType.name + "--" + this.name;
|
|
1747
|
+
}
|
|
1748
|
+
/**
|
|
1749
|
+
General purpose property set method
|
|
1750
|
+
> // assume em1 is an EntityManager
|
|
1751
|
+
> let prop = myEntityType.getProperty("myProperty");
|
|
1752
|
+
> prop.setProperties( {
|
|
1753
|
+
> custom: { foo: 7, bar: "test" }
|
|
1754
|
+
> });
|
|
1755
|
+
@param config - A configuration object.
|
|
1756
|
+
**/
|
|
1757
|
+
setProperties(config) {
|
|
1758
|
+
assertConfig(config)
|
|
1759
|
+
.whereParam("displayName").isOptional()
|
|
1760
|
+
.whereParam("custom").isOptional()
|
|
1761
|
+
.applyAll(this);
|
|
1762
|
+
}
|
|
1763
|
+
getAllValidators() {
|
|
1764
|
+
let validators = this.validators.slice(0);
|
|
1765
|
+
let baseProp = this.baseProperty;
|
|
1766
|
+
while (baseProp) {
|
|
1767
|
+
validators.push.apply(validators, baseProp.validators);
|
|
1768
|
+
baseProp = baseProp.baseProperty;
|
|
1769
|
+
}
|
|
1770
|
+
return validators;
|
|
1771
|
+
}
|
|
1772
|
+
toJSON() {
|
|
1773
|
+
// do not serialize dataTypes that are complexTypes
|
|
1774
|
+
return core.toJson(this, {
|
|
1775
|
+
name: null,
|
|
1776
|
+
dataType: function (v) {
|
|
1777
|
+
return (v && v instanceof DataType) ? v.name : undefined;
|
|
1778
|
+
},
|
|
1779
|
+
complexTypeName: null,
|
|
1780
|
+
isNullable: true,
|
|
1781
|
+
defaultValue: null,
|
|
1782
|
+
isPartOfKey: false,
|
|
1783
|
+
isUnmapped: false,
|
|
1784
|
+
isSettable: true,
|
|
1785
|
+
concurrencyMode: null,
|
|
1786
|
+
maxLength: null,
|
|
1787
|
+
validators: null,
|
|
1788
|
+
displayName: null,
|
|
1789
|
+
enumType: null,
|
|
1790
|
+
rawTypeName: null,
|
|
1791
|
+
isScalar: true,
|
|
1792
|
+
custom: null
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
static fromJSON(json) {
|
|
1796
|
+
json.dataType = DataType.fromName(json.dataType);
|
|
1797
|
+
// Parse default value into correct data type. (dateTime instances require extra work to deserialize properly.)
|
|
1798
|
+
if (json.defaultValue && json.dataType && json.dataType.parse) {
|
|
1799
|
+
json.defaultValue = json.dataType.parse(json.defaultValue, typeof json.defaultValue);
|
|
1800
|
+
}
|
|
1801
|
+
if (json.validators) {
|
|
1802
|
+
json.validators = json.validators.map(Validator.fromJSON);
|
|
1803
|
+
}
|
|
1804
|
+
return new DataProperty(json);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
DataProperty.prototype._$typeName = "DataProperty";
|
|
1808
|
+
/** A NavigationProperty describes the metadata for a single property of an [[EntityType]] that return instances of other EntityTypes.
|
|
1809
|
+
|
|
1810
|
+
Instances of the NavigationProperty class are constructed automatically during Metadata retrieval. However it is also possible to construct them
|
|
1811
|
+
directly via the constructor.
|
|
1812
|
+
**/
|
|
1813
|
+
export class NavigationProperty {
|
|
1814
|
+
/** NavigationProperty constructor
|
|
1815
|
+
> let homeAddressProp = new NavigationProperty( {
|
|
1816
|
+
> name: "homeAddress",
|
|
1817
|
+
> entityTypeName: "Address:#myNamespace",
|
|
1818
|
+
> isScalar: true,
|
|
1819
|
+
> associationName: "address_person",
|
|
1820
|
+
> foreignKeyNames: ["homeAddressId"]
|
|
1821
|
+
> });
|
|
1822
|
+
> let homeAddressIdProp = new DataProperty( {
|
|
1823
|
+
> name: "homeAddressId"
|
|
1824
|
+
> dataType: DataType.Integer
|
|
1825
|
+
> });
|
|
1826
|
+
> // assuming personEntityType is a newly constructed EntityType
|
|
1827
|
+
> personEntityType.addProperty(homeAddressProp);
|
|
1828
|
+
> personEntityType.addProperty(homeAddressIdProp);
|
|
1829
|
+
@param config - A configuration object.
|
|
1830
|
+
**/
|
|
1831
|
+
constructor(config) {
|
|
1832
|
+
/** Is this a DataProperty? - always false here
|
|
1833
|
+
Allows polymorphic treatment of DataProperties and NavigationProperties. __Read Only__ */
|
|
1834
|
+
this.isDataProperty = false;
|
|
1835
|
+
/** Is this a NavigationProperty? - always true here
|
|
1836
|
+
Allows polymorphic treatment of DataProperties and NavigationProperties. __Read Only__ */
|
|
1837
|
+
this.isNavigationProperty = true;
|
|
1838
|
+
this.formatName = DataProperty.prototype.formatName;
|
|
1839
|
+
this.getAllValidators = DataProperty.prototype.getAllValidators;
|
|
1840
|
+
this.resolveProperty = DataProperty.prototype.resolveProperty;
|
|
1841
|
+
assertConfig(config)
|
|
1842
|
+
.whereParam("name").isString().isOptional()
|
|
1843
|
+
.whereParam("nameOnServer").isString().isOptional()
|
|
1844
|
+
.whereParam("entityTypeName").isString()
|
|
1845
|
+
.whereParam("isScalar").isBoolean().isOptional().withDefault(true)
|
|
1846
|
+
.whereParam("associationName").isString().isOptional()
|
|
1847
|
+
.whereParam("foreignKeyNames").isArray().isString().isOptional().withDefault([])
|
|
1848
|
+
.whereParam("foreignKeyNamesOnServer").isArray().isString().isOptional().withDefault([])
|
|
1849
|
+
.whereParam("invForeignKeyNames").isArray().isString().isOptional().withDefault([])
|
|
1850
|
+
.whereParam("invForeignKeyNamesOnServer").isArray().isString().isOptional().withDefault([])
|
|
1851
|
+
.whereParam("validators").isInstanceOf(Validator).isArray().isOptional().withDefault([])
|
|
1852
|
+
.whereParam("displayName").isOptional()
|
|
1853
|
+
.whereParam("custom").isOptional()
|
|
1854
|
+
.applyAll(this);
|
|
1855
|
+
let hasName = !!(this.name || this.nameOnServer);
|
|
1856
|
+
if (!hasName) {
|
|
1857
|
+
throw new Error("A Navigation property must be instantiated with either a 'name' or a 'nameOnServer' property");
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
/**
|
|
1861
|
+
General purpose property set method
|
|
1862
|
+
> // assume myEntityType is an EntityType
|
|
1863
|
+
> let prop = myEntityType.getProperty("myProperty");
|
|
1864
|
+
> prop.setProperties( {
|
|
1865
|
+
> custom: { foo: 7, bar: "test" }
|
|
1866
|
+
> });
|
|
1867
|
+
@param config - A config object
|
|
1868
|
+
**/
|
|
1869
|
+
// TODO: create an interface for this.
|
|
1870
|
+
setProperties(config) {
|
|
1871
|
+
if (!this.parentType) {
|
|
1872
|
+
throw new Error("Cannot call NavigationProperty.setProperties until the parent EntityType of the NavigationProperty has been set.");
|
|
1873
|
+
}
|
|
1874
|
+
let inverse = config.inverse;
|
|
1875
|
+
if (inverse)
|
|
1876
|
+
delete config.inverse;
|
|
1877
|
+
assertConfig(config)
|
|
1878
|
+
.whereParam("displayName").isOptional()
|
|
1879
|
+
.whereParam("foreignKeyNames").isArray().isString().isOptional().withDefault([])
|
|
1880
|
+
.whereParam("invForeignKeyNames").isArray().isString().isOptional().withDefault([])
|
|
1881
|
+
.whereParam("custom").isOptional()
|
|
1882
|
+
.applyAll(this);
|
|
1883
|
+
this.parentType._updateNames(this);
|
|
1884
|
+
this._resolveNp();
|
|
1885
|
+
if (inverse) {
|
|
1886
|
+
this.setInverse(inverse);
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
/** The inverse of this NavigationProperty. The NavigationProperty that represents a navigation in the opposite direction
|
|
1890
|
+
to this NavigationProperty. May be undefined for a undirectional NavigationProperty. __Read Only__ */
|
|
1891
|
+
get inverse() {
|
|
1892
|
+
return this.getInverse();
|
|
1893
|
+
}
|
|
1894
|
+
/** @hidden @internal */
|
|
1895
|
+
getInverse() {
|
|
1896
|
+
let np = this;
|
|
1897
|
+
while (!np._inverse && np.baseProperty) {
|
|
1898
|
+
np = np.baseProperty;
|
|
1899
|
+
}
|
|
1900
|
+
return np._inverse;
|
|
1901
|
+
}
|
|
1902
|
+
setInverse(inverseNp) {
|
|
1903
|
+
// let invNp: NavigationProperty;
|
|
1904
|
+
let invNp = (inverseNp instanceof NavigationProperty) ? inverseNp : this.entityType.getNavigationProperty(inverseNp);
|
|
1905
|
+
if (!invNp) {
|
|
1906
|
+
throw throwSetInverseError(this, "Unable to find inverse property: " + inverseNp);
|
|
1907
|
+
}
|
|
1908
|
+
if (this._inverse || invNp._inverse) {
|
|
1909
|
+
throwSetInverseError(this, "It has already been set on one side or the other.");
|
|
1910
|
+
}
|
|
1911
|
+
if (invNp.entityType !== this.parentType) {
|
|
1912
|
+
throwSetInverseError(this, invNp.formatName + " is not a valid inverse property for this.");
|
|
1913
|
+
}
|
|
1914
|
+
if (this.associationName) {
|
|
1915
|
+
invNp.associationName = this.associationName;
|
|
1916
|
+
}
|
|
1917
|
+
else {
|
|
1918
|
+
if (!invNp.associationName) {
|
|
1919
|
+
invNp.associationName = this.formatName() + "_" + invNp.formatName();
|
|
1920
|
+
}
|
|
1921
|
+
this.associationName = invNp.associationName;
|
|
1922
|
+
}
|
|
1923
|
+
this._resolveNp();
|
|
1924
|
+
invNp._resolveNp();
|
|
1925
|
+
}
|
|
1926
|
+
// // In progress - will be used for manual metadata config
|
|
1927
|
+
// createInverse(config: any) {
|
|
1928
|
+
// if (!this.entityType) {
|
|
1929
|
+
// throwCreateInverseError(this, "has not yet been defined.");
|
|
1930
|
+
// }
|
|
1931
|
+
// if (this.entityType.isFrozen) {
|
|
1932
|
+
// throwCreateInverseError(this, "is frozen.");
|
|
1933
|
+
// }
|
|
1934
|
+
// let metadataStore = this.entityType.metadataStore;
|
|
1935
|
+
// if (metadataStore == null) {
|
|
1936
|
+
// throwCreateInverseError(this, "has not yet been added to the metadataStore.");
|
|
1937
|
+
// }
|
|
1938
|
+
// config.entityTypeName = this.parentEntityType.name;
|
|
1939
|
+
// config.associationName = this.associationName;
|
|
1940
|
+
// let invNp = new NavigationProperty(config);
|
|
1941
|
+
// this.parentEntityType.addNavigationProperty(invNp);
|
|
1942
|
+
// return invNp;
|
|
1943
|
+
// };
|
|
1944
|
+
toJSON() {
|
|
1945
|
+
return core.toJson(this, {
|
|
1946
|
+
name: null,
|
|
1947
|
+
entityTypeName: null,
|
|
1948
|
+
isScalar: null,
|
|
1949
|
+
associationName: null,
|
|
1950
|
+
validators: null,
|
|
1951
|
+
displayName: null,
|
|
1952
|
+
foreignKeyNames: null,
|
|
1953
|
+
invForeignKeyNames: null,
|
|
1954
|
+
custom: null
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1957
|
+
static fromJSON(json) {
|
|
1958
|
+
if (json.validators) {
|
|
1959
|
+
json.validators = json.validators.map(Validator.fromJSON);
|
|
1960
|
+
}
|
|
1961
|
+
return new NavigationProperty(json);
|
|
1962
|
+
}
|
|
1963
|
+
/** @hidden @internal */
|
|
1964
|
+
_resolveNp() {
|
|
1965
|
+
let np = this;
|
|
1966
|
+
let entityType = np.entityType;
|
|
1967
|
+
let invNp = core.arrayFirst(entityType.navigationProperties, (altNp) => {
|
|
1968
|
+
// Can't do this because of possibility of comparing a base class np with a subclass altNp.
|
|
1969
|
+
// return altNp.associationName === np.associationName
|
|
1970
|
+
// && altNp !== np;
|
|
1971
|
+
// So use this instead.
|
|
1972
|
+
return altNp.associationName === np.associationName &&
|
|
1973
|
+
(altNp.name !== np.name || altNp.entityTypeName !== np.entityTypeName);
|
|
1974
|
+
});
|
|
1975
|
+
np._inverse = invNp || undefined;
|
|
1976
|
+
//if (invNp && invNp.inverse == null) {
|
|
1977
|
+
// invNp._resolveNp();
|
|
1978
|
+
//}
|
|
1979
|
+
if (!invNp) {
|
|
1980
|
+
// unidirectional 1-n relationship
|
|
1981
|
+
np.invForeignKeyNames.forEach(function (invFkName) {
|
|
1982
|
+
let fkProp = entityType.getDataProperty(invFkName);
|
|
1983
|
+
if (fkProp == null) {
|
|
1984
|
+
throw new Error("EntityType '" + np.entityTypeName + "' has no foreign key matching '" + invFkName + "'");
|
|
1985
|
+
}
|
|
1986
|
+
let invEntityType = np.parentType;
|
|
1987
|
+
invNp = core.arrayFirst(invEntityType.navigationProperties, (np2) => {
|
|
1988
|
+
return np2.invForeignKeyNames && np2.invForeignKeyNames.indexOf(fkProp.name) >= 0 && np2.entityType === fkProp.parentType;
|
|
1989
|
+
});
|
|
1990
|
+
fkProp.inverseNavigationProperty = invNp || undefined;
|
|
1991
|
+
core.arrayAddItemUnique(entityType.foreignKeyProperties, fkProp);
|
|
1992
|
+
});
|
|
1993
|
+
}
|
|
1994
|
+
resolveRelated(np);
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
NavigationProperty.prototype._$typeName = "NavigationProperty";
|
|
1998
|
+
function throwSetInverseError(np, message) {
|
|
1999
|
+
throw new Error("Cannot set the inverse property for: " + np.formatName() + ". " + message);
|
|
2000
|
+
}
|
|
2001
|
+
// Not current used.
|
|
2002
|
+
// function throwCreateInverseError(np: NavigationProperty, message: string) {
|
|
2003
|
+
// throw new Error("Cannot create inverse for: " + np.formatName() + ". The entityType for this navigation property " + message);
|
|
2004
|
+
// }
|
|
2005
|
+
// sets navigation property: relatedDataProperties and dataProperty: relatedNavigationProperty
|
|
2006
|
+
function resolveRelated(np) {
|
|
2007
|
+
let fkNames = np.foreignKeyNames;
|
|
2008
|
+
if (fkNames.length === 0)
|
|
2009
|
+
return;
|
|
2010
|
+
let parentEntityType = np.parentType;
|
|
2011
|
+
let fkProps = fkNames.map(function (fkName) {
|
|
2012
|
+
return parentEntityType.getDataProperty(fkName);
|
|
2013
|
+
});
|
|
2014
|
+
let fkPropCollection = parentEntityType.foreignKeyProperties;
|
|
2015
|
+
fkProps.forEach((dp) => {
|
|
2016
|
+
core.arrayAddItemUnique(fkPropCollection, dp);
|
|
2017
|
+
dp.relatedNavigationProperty = np;
|
|
2018
|
+
// now update the inverse
|
|
2019
|
+
core.arrayAddItemUnique(np.entityType.inverseForeignKeyProperties, dp);
|
|
2020
|
+
if (np.relatedDataProperties) {
|
|
2021
|
+
core.arrayAddItemUnique(np.relatedDataProperties, dp);
|
|
2022
|
+
}
|
|
2023
|
+
else {
|
|
2024
|
+
np.relatedDataProperties = [dp];
|
|
2025
|
+
}
|
|
2026
|
+
});
|
|
2027
|
+
}
|
|
2028
|
+
/**
|
|
2029
|
+
AutoGeneratedKeyType is an 'Enum' containing all of the valid states for an automatically generated key.
|
|
2030
|
+
**/
|
|
2031
|
+
export class AutoGeneratedKeyType extends BreezeEnum {
|
|
2032
|
+
}
|
|
2033
|
+
/**
|
|
2034
|
+
This entity does not have an autogenerated key.
|
|
2035
|
+
The client must set the key before adding the entity to the EntityManager
|
|
2036
|
+
**/
|
|
2037
|
+
AutoGeneratedKeyType.None = new AutoGeneratedKeyType();
|
|
2038
|
+
/**
|
|
2039
|
+
This entity's key is an Identity column and is set by the backend database.
|
|
2040
|
+
Keys for new entities will be temporary until the entities are saved at which point the keys will
|
|
2041
|
+
be converted to their 'real' versions.
|
|
2042
|
+
**/
|
|
2043
|
+
AutoGeneratedKeyType.Identity = new AutoGeneratedKeyType();
|
|
2044
|
+
/**
|
|
2045
|
+
This entity's key is generated by a KeyGenerator and is set by the backend database.
|
|
2046
|
+
Keys for new entities will be temporary until the entities are saved at which point the keys will
|
|
2047
|
+
be converted to their 'real' versions.
|
|
2048
|
+
**/
|
|
2049
|
+
AutoGeneratedKeyType.KeyGenerator = new AutoGeneratedKeyType();
|
|
2050
|
+
AutoGeneratedKeyType.prototype._$typeName = "AutoGeneratedKeyType";
|
|
2051
|
+
Error['x'] = AutoGeneratedKeyType.resolveSymbols();
|
|
2052
|
+
let proto = Param.prototype;
|
|
2053
|
+
// 'this' below is TS annotation
|
|
2054
|
+
proto.isEntity = function () {
|
|
2055
|
+
return this._addContext({
|
|
2056
|
+
fn: isEntity,
|
|
2057
|
+
msg: " must be an entity"
|
|
2058
|
+
});
|
|
2059
|
+
};
|
|
2060
|
+
function isEntity(context, v) {
|
|
2061
|
+
if (v == null)
|
|
2062
|
+
return false;
|
|
2063
|
+
return (v.entityType !== undefined);
|
|
2064
|
+
}
|
|
2065
|
+
proto.isEntityProperty = function () {
|
|
2066
|
+
return this._addContext({
|
|
2067
|
+
fn: isEntityProperty,
|
|
2068
|
+
msg: " must be either a DataProperty or a NavigationProperty"
|
|
2069
|
+
});
|
|
2070
|
+
};
|
|
2071
|
+
function isEntityProperty(context, v) {
|
|
2072
|
+
if (v == null)
|
|
2073
|
+
return false;
|
|
2074
|
+
return (v.isDataProperty || v.isNavigationProperty);
|
|
2075
|
+
}
|
|
2076
|
+
// functions shared between classes related to Metadata
|
|
2077
|
+
function isQualifiedTypeName(entityTypeName) {
|
|
2078
|
+
return entityTypeName.indexOf(":#") >= 0;
|
|
2079
|
+
}
|
|
2080
|
+
export function qualifyTypeName(shortName, ns) {
|
|
2081
|
+
if (ns && ns.length > 0) {
|
|
2082
|
+
return shortName + ":#" + ns;
|
|
2083
|
+
}
|
|
2084
|
+
else {
|
|
2085
|
+
return shortName;
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
// Used by both ComplexType and EntityType
|
|
2089
|
+
function addProperties(entityType, propObj, ctor) {
|
|
2090
|
+
if (propObj == null)
|
|
2091
|
+
return;
|
|
2092
|
+
if (Array.isArray(propObj)) {
|
|
2093
|
+
propObj.forEach(entityType._addPropertyCore.bind(entityType));
|
|
2094
|
+
}
|
|
2095
|
+
else if (typeof (propObj) === 'object') {
|
|
2096
|
+
for (let key in propObj) {
|
|
2097
|
+
if (core.hasOwnProperty(propObj, key)) {
|
|
2098
|
+
let value = propObj[key];
|
|
2099
|
+
value.name = key;
|
|
2100
|
+
let prop = new ctor(value);
|
|
2101
|
+
entityType._addPropertyCore(prop);
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
else {
|
|
2106
|
+
throw new Error("The 'dataProperties' or 'navigationProperties' values must be either an array of data/nav properties or an object where each property defines a data/nav property");
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LW1ldGFkYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2VudGl0eS1tZXRhZGF0YS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsSUFBSSxFQUFpQixNQUFNLFFBQVEsQ0FBQztBQUM3QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQ2xDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDdEMsT0FBTyxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbEUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN2QyxPQUFPLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBMkMsTUFBTSxpQkFBaUIsQ0FBQztBQUN2RyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDdkMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUNwQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sd0JBQXdCLENBQUMsQ0FBQywyQkFBMkI7QUFDeEYsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDL0UsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUF1QzVFOzs7OztHQUtHO0FBQ0gsTUFBTSxPQUFPLGFBQWE7SUFxRHhCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FxQkc7SUFDSCxZQUFZLE1BQTRCO1FBQ3RDLE1BQU0sR0FBRyxNQUFNLElBQUksRUFBRSxDQUFDO1FBQ3RCLFlBQVksQ0FB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QUksS0FBSyxDQUFDLG1LQUFtSyxDQUFDLENBQUM7S0FDdEw7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY29yZSwgRXJyb3JDYWxsYmFjayB9IGZyb20gJy4vY29yZSc7XHJcbmltcG9ydCB7IGNvbmZpZyB9IGZyb20gJy4vY29uZmlnJztcclxuaW1wb3J0IHsgQnJlZXplRXZlbnQgfSBmcm9tICcuL2V2ZW50JztcclxuaW1wb3J0IHsgYXNzZXJ0UGFyYW0sIGFzc2VydENvbmZpZywgUGFyYW0gfSBmcm9tICcuL2Fzc2VydC1wYXJhbSc7XHJcbmltcG9ydCB7IERhdGFUeXBlIH0gZnJvbSAnLi9kYXRhLXR5cGUnO1xyXG5pbXBvcnQgeyBFbnRpdHlBc3BlY3QsIENvbXBsZXhBc3BlY3QsIEVudGl0eSwgQ29tcGxleE9iamVjdCwgU3RydWN0dXJhbE9iamVjdCB9IGZyb20gJy4vZW50aXR5LWFzcGVjdCc7XHJcbmltcG9ydCB7IEVudGl0eUtleSB9IGZyb20gJy4vZW50aXR5LWtleSc7XHJcbmltcG9ydCB7IFZhbGlkYXRvciB9IGZyb20gJy4vdmFsaWRhdGUnO1xyXG5pbXBvcnQgeyBCcmVlemVFbnVtIH0gZnJvbSAnLi9lbnVtJztcclxuaW1wb3J0IHsgRGF0YVNlcnZpY2UgfSBmcm9tICcuL2RhdGEtc2VydmljZSc7XHJcbmltcG9ydCB7IE5hbWluZ0NvbnZlbnRpb24gfSBmcm9tICcuL25hbWluZy1jb252ZW50aW9uJztcclxuaW1wb3J0IHsgQ3NkbE1ldGFkYXRhUGFyc2VyIH0gZnJvbSAnLi9jc2RsLW1ldGFkYXRhLXBhcnNlcic7IC8vIFRPRE8gaXNvbGF0ZSB0aGlzIGxhdGVyO1xyXG5pbXBvcnQgeyBMb2NhbFF1ZXJ5Q29tcGFyaXNvbk9wdGlvbnMgfSBmcm9tICcuL2xvY2FsLXF1ZXJ5LWNvbXBhcmlzb24tb3B0aW9ucyc7XHJcbmltcG9ydCB7IGRlZmF1bHRQcm9wZXJ0eUludGVyY2VwdG9yIH0gZnJvbSAnLi9kZWZhdWx0LXByb3BlcnR5LWludGVyY2VwdG9yJztcclxuXHJcbmV4cG9ydCB0eXBlIEVudGl0eVByb3BlcnR5ID0gRGF0YVByb3BlcnR5IHwgTmF2aWdhdGlvblByb3BlcnR5O1xyXG5leHBvcnQgdHlwZSBTdHJ1Y3R1cmFsVHlwZSA9IEVudGl0eVR5cGUgfCBDb21wbGV4VHlwZTtcclxuXHJcbi8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIElTdHJ1Y3R1cmFsVHlwZU1hcCB7XHJcbiAgW2luZGV4OiBzdHJpbmddOiBTdHJ1Y3R1cmFsVHlwZTtcclxufVxyXG5cclxuLy8gVE9ETzogY29uc2lkZXIgZXhwb3NpbmcgbGF0ZXJcclxuLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbmV4cG9ydCBpbnRlcmZhY2UgSU1ldGFkYXRhSnNvbiB7XHJcbiAgbWV0YWRhdGFWZXJzaW9uOiBzdHJpbmc7XHJcbiAgbmFtZTogc3RyaW5nO1xyXG4gIG5hbWluZ0NvbnZlbnRpb246IHN0cmluZztcclxuICBsb2NhbFF1ZXJ5Q29tcGFyaXNvbk9wdGlvbnM6IHN0cmluZztcclxuICBkYXRhU2VydmljZXM6IE9iamVjdFtdOyAvLyBJRGF0YVNlcnZpY2VKc29uW11cclxuICBzdHJ1Y3R1cmFsVHlwZXM6IE9iamVjdFtdOyAvLyBJU3RydWN0dXJhbFR5cGVKc29uW107IFxyXG4gIHJlc291cmNlRW50aXR5VHlwZU1hcDogT2JqZWN0W107IC8vIElSZXNvdXJjZUVudGl0eVR5cGVKc29uW11cclxuICBpbmNvbXBsZXRlVHlwZU1hcDogT2JqZWN0W107XHJcbn1cclxuXHJcbi8qKiBDb25maWd1cmF0aW9uIGluZm8gdG8gYmUgcGFzc2VkIHRvIHRoZSBbW01ldGFkYXRhU3RvcmVdXSBjb25zdHJ1Y3RvciAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIE1ldGFkYXRhU3RvcmVDb25maWcge1xyXG4gIC8qKiBUaGUgIFtbTmFtaW5nQ29udmVudGlvbl1dIGFzc29jaWF0ZWQgd2l0aCB0aGlzIE1ldGFkYXRhU3RvcmUuICovXHJcbiAgbmFtaW5nQ29udmVudGlvbj86IE5hbWluZ0NvbnZlbnRpb247XHJcbiAgLyoqIFRoZSAgW1tMb2NhbFF1ZXJ5Q29tcGFyaXNvbk9wdGlvbnNdXSBhc3NvY2lhdGVkIHdpdGggdGhpcyBNZXRhZGF0YVN0b3JlLiAqL1xyXG4gIGxvY2FsUXVlcnlDb21wYXJpc29uT3B0aW9ucz86IExvY2FsUXVlcnlDb21wYXJpc29uT3B0aW9ucztcclxuICBzZXJpYWxpemVyRm4/OiAocHJvcDogRW50aXR5UHJvcGVydHksIHZhbDogYW55KSA9PiBhbnk7XHJcbiAgbmFtZT86IHN0cmluZztcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBNZXRhZGF0YUZldGNoZWRFdmVudEFyZ3Mge1xyXG4gIG1ldGFkYXRhU3RvcmU6IE1ldGFkYXRhU3RvcmU7XHJcbiAgZGF0YVNlcnZpY2U6IERhdGFTZXJ2aWNlIHwgc3RyaW5nO1xyXG4gIHJhd01ldGFkYXRhOiBhbnk7XHJcbn1cclxuXHJcbi8qKlxyXG5BbiBpbnN0YW5jZSBvZiB0aGUgTWV0YWRhdGFTdG9yZSBjb250YWlucyBhbGwgb2YgdGhlIG1ldGFkYXRhIGFib3V0IGEgY29sbGVjdGlvbiBvZiBbW0VudGl0eVR5cGVdXSdzLlxyXG5NZXRhZGF0YVN0b3JlcyBtYXkgYmUgc2hhcmVkIGFjcm9zcyBbW0VudGl0eU1hbmFnZXJdXSdzLiAgSWYgYW4gRW50aXR5TWFuYWdlciBpcyBjcmVhdGVkIHdpdGhvdXQgYW5cclxuZXhwbGljaXQgTWV0YWRhdGFTdG9yZSwgdGhlIE1ldGFkYXRhU3RvcmUgZnJvbSB0aGUgTWV0YWRhdGFTdG9yZS5kZWZhdWx0SW5zdGFuY2UgcHJvcGVydHkgd2lsbCBiZSB1c2VkLlxyXG5AZHluYW1pY1xyXG4qKi9cclxuZXhwb3J0IGNsYXNzIE1ldGFkYXRhU3RvcmUge1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF8kdHlwZU5hbWU6IHN0cmluZzsgLy8gb24gcHJvdG9cclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgc3RhdGljIF9faWQgPSAwO1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIHN0YXRpYyBBTk9OVFlQRV9QUkVGSVggPSBcIl9JQl9cIjtcclxuICAvKiogVGhlIHZlcnNpb24gb2YgYW55IE1ldGFkYXRhU3RvcmVzIGNyZWF0ZWQgYnkgdGhpcyBjbGFzcyAqL1xyXG4gIHN0YXRpYyBtZXRhZGF0YVZlcnNpb24gPSAnMS4wLjUnO1xyXG5cclxuICBuYW1lOiBzdHJpbmc7XHJcbiAgZGF0YVNlcnZpY2VzOiBEYXRhU2VydmljZVtdO1xyXG5cclxuICAvKiogVGhlICBbW05hbWluZ0NvbnZlbnRpb25dXSBhc3NvY2lhdGVkIHdpdGggdGhpcyBNZXRhZGF0YVN0b3JlLiBfX1JlYWQgT25seV9fICovXHJcbiAgbmFtaW5nQ29udmVudGlvbjogTmFtaW5nQ29udmVudGlvbjtcclxuICAvKiogVGhlICBbW0xvY2FsUXVlcnlDb21wYXJpc29uT3B0aW9uc11dIGFzc29jaWF0ZWQgd2l0aCB0aGlzIE1ldGFkYXRhU3RvcmUuIF9fUmVhZCBPbmx5X18gKi9cclxuICBsb2NhbFF1ZXJ5Q29tcGFyaXNvbk9wdGlvbnM6IExvY2FsUXVlcnlDb21wYXJpc29uT3B0aW9ucztcclxuICBzZXJpYWxpemVyRm4/OiAocHJvcDogRW50aXR5UHJvcGVydHksIHZhbDogYW55KSA9PiBhbnk7XHJcbiAgLyoqXHJcbiAgQW4gW1tCcmVlemVFdmVudF1dIHRoYXQgZmlyZXMgYWZ0ZXIgYSBNZXRhZGF0YVN0b3JlIGhhcyBjb21wbGV0ZWQgZmV0Y2hpbmcgbWV0YWRhdGEgZnJvbSBhIHJlbW90ZSBzZXJ2aWNlLlxyXG4gIFxyXG4gIEBldmVudEFyZ3MgLVxyXG4gICAgLSBtZXRhZGF0YVN0b3JlIC0gVGhlIE1ldGFkYXRhU3RvcmUgaW50byB3aGljaCB0aGUgbWV0YWRhdGEgd2FzIGZldGNoZWQuXHJcbiAgICAtIGRhdGFTZXJ2aWNlIC0gVGhlIFtbRGF0YVNlcnZpY2VdXSB0aGF0IG1ldGFkYXRhIHdhcyBmZXRjaGVkIGZyb20uXHJcbiAgICAtIHJhd01ldGFkYXRhIC0ge09iamVjdH0gVGhlIHJhdyBtZXRhZGF0YSByZXR1cm5lZCBmcm9tIHRoZSBzZXJ2aWNlLiAoSXQgd2lsbCBoYXZlIGFscmVhZHkgYmVlbiBwcm9jZXNzZWQgYnkgdGhpcyBwb2ludCkuXHJcbiAgPiAgICAgIGxldCBtcyA9IG15RW50aXR5TWFuYWdlci5tZXRhZGF0YVN0b3JlO1xyXG4gID4gICAgICBtcy5tZXRhZGF0YUZldGNoZWQuc3Vic2NyaWJlKGZ1bmN0aW9uKGFyZ3MpIHtcclxuICA+ICAgICAgICAgIGxldCBtZXRhZGF0YVN0b3JlID0gYXJncy5tZXRhZGF0YVN0b3JlO1xyXG4gID4gICAgICAgICAgbGV0IGRhdGFTZXJ2aWNlID0gYXJncy5kYXRhU2VydmljZTtcclxuICA+ICAgICAgfSk7XHJcbiAgQGV2ZW50XHJcbiAgKiovXHJcbiAgbWV0YWRhdGFGZXRjaGVkOiBCcmVlemVFdmVudDxNZXRhZGF0YUZldGNoZWRFdmVudEFyZ3M+O1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF9yZXNvdXJjZUVudGl0eVR5cGVNYXA6IHt9O1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF9lbnRpdHlUeXBlUmVzb3VyY2VNYXA6IHt9O1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF9zdHJ1Y3R1cmFsVHlwZU1hcDogSVN0cnVjdHVyYWxUeXBlTWFwOyAvLyBrZXkgaXMgcXVhbGlmaWVkIHN0cnVjdHVyYWx0eXBlIG5hbWUgLSB2YWx1ZSBpcyBzdHJ1Y3R1cmFsVHlwZS4gKCBzdHJ1Y3R1cmFsID0gZW50aXR5VHlwZSBvciBjb21wbGV4VHlwZSkuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICoqL1xyXG4gIF9zaG9ydE5hbWVNYXA6IHt9OyAvLyBrZXkgaXMgc2hvcnROYW1lLCB2YWx1ZSBpcyBxdWFsaWZpZWQgbmFtZSAtIGRvZXMgbm90IG5lZWQgdG8gYmUgc2VyaWFsaXplZC5cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKiovXHJcbiAgX2N0b3JSZWdpc3RyeToge307IC8vIGtleSBpcyBlaXRoZXIgc2hvcnQgb3IgcXVhbCB0eXBlIG5hbWUgLSB2YWx1ZSBpcyBjdG9yO1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqKi9cclxuICBfaW5jb21wbGV0ZVR5cGVNYXA6IHt9OyAvLyBrZXkgaXMgZW50aXR5VHlwZU5hbWU7IHZhbHVlIGlzIGFycmF5IG9mIG5hdiBwcm9wc1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqKi9cclxuICBfaW5jb21wbGV0ZUNvbXBsZXhUeXBlTWFwOiB7fTsgLy9cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKiovXHJcbiAgX2RlZmVycmVkVHlwZXM6IHt9O1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqKi9cclxuICBfaWQ6IG51bWJlcjtcclxuXHJcbiAgLyoqXHJcbiAgQ29uc3RydWN0cyBhIG5ldyBNZXRhZGF0YVN0b3JlLlxyXG4gIFxyXG4gID4gICAgIGxldCBtcyA9IG5ldyBNZXRhZGF0YVN0b3JlKCk7XHJcblxyXG4gIFRoZSBzdG9yZSBjYW4gdGhlbiBiZSBhc3NvY2lhdGVkIHdpdGggYW4gRW50aXR5TWFuYWdlclxyXG4gID4gICAgIGxldCBlbnRpdHlNYW5hZ2VyID0gbmV3IEVudGl0eU1hbmFnZXIoIHtcclxuICA+ICAgICAgICAgc2VydmljZU5hbWU6IFwiYnJlZXplL05vcnRod2luZElCTW9kZWxcIiwgXHJcbiAgPiAgICAgICAgIG1ldGFkYXRhU3RvcmU6IG1zIFxyXG4gID4gICAgIH0pO1xyXG5cclxuICBvciBmb3IgYW4gZXhpc3RpbmcgRW50aXR5TWFuYWdlclxyXG4gID4gICAgLy8gQXNzdW1lIGVtMSBpcyBhbiBleGlzdGluZyBFbnRpdHlNYW5hZ2VyXHJcbiAgPiAgICBlbTEuc2V0UHJvcGVydGllcyggeyBtZXRhZGF0YVN0b3JlOiBtcyB9KTtcclxuICBcclxuICBAcGFyYW0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBzZXR0aW5ncyAuXHJcbiAgICAtIG5hbWluZ0NvbnZlbnRpb24gLSAoZGVmYXVsdD1OYW1pbmdDb252ZW50aW9uLmRlZmF1bHRJbnN0YW5jZSkgTmFtaW5nQ29udmVudGlvbiB0byBiZSB1c2VkIGluIG1hcHBpbmcgcHJvcGVydHkgbmFtZXNcclxuICBiZXR3ZWVuIGNsaWVudCBhbmQgc2VydmVyLiBVc2VzIHRoZSBOYW1pbmdDb252ZW50aW9uLmRlZmF1bHRJbnN0YW5jZSBpZiBub3Qgc3BlY2lmaWVkLlxyXG4gICAgLSBsb2NhbFF1ZXJ5Q29tcGFyaXNvbk9wdGlvbnMgLSAoZGVmYXVsdD1Mb2NhbFF1ZXJ5Q29tcGFyaXNvbk9wdGlvbnMuZGVmYXVsdEluc3RhbmNlKSBUaGUgTG9jYWxRdWVyeUNvbXBhcmlzb25PcHRpb25zIHRvIGJlXHJcbiAgdXNlZCB3aGVuIHBlcmZvcm1pbmcgXCJsb2NhbCBxdWVyaWVzXCIgaW4gb3JkZXIgdG8gbWF0Y2ggdGhlIHNlbWFudGljcyBvZiBxdWVyaWVzIGFnYWluc3QgYSByZW1vdGUgc2VydmljZS5cclxuICAgIC0gc2VyaWFsaXplckZuIC0gQSBmdW5jdGlvbiB0aGF0IGlzIHVzZWQgdG8gbWVkaWF0ZSB0aGUgc2VyaWFsaXphdGlvbiBvZiBpbnN0YW5jZXMgb2YgdGhpcyB0eXBlLlxyXG4gICoqL1xyXG4gIGNvbnN0cnVjdG9yKGNvbmZpZz86IE1ldGFkYXRhU3RvcmVDb25maWcpIHtcclxuICAgIGNvbmZpZyA9IGNvbmZpZyB8fCB7fTtcclxuICAgIGFzc2VydENvbmZpZyhjb25maWcpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwibmFtaW5nQ29udmVudGlvblwiKS5pc09wdGlvbmFsKCkuaXNJbnN0YW5jZU9mKE5hbWluZ0NvbnZlbnRpb24pLndpdGhEZWZhdWx0KE5hbWluZ0NvbnZlbnRpb24uZGVmYXVsdEluc3RhbmNlKVxyXG4gICAgICAud2hlcmVQYXJhbShcImxvY2FsUXVlcnlDb21wYXJpc29uT3B0aW9uc1wiKS5pc09wdGlvbmFsKCkuaXNJbnN0YW5jZU9mKExvY2FsUXVlcnlDb21wYXJpc29uT3B0aW9ucykud2l0aERlZmF1bHQoTG9jYWxRdWVyeUNvbXBhcmlzb25PcHRpb25zLmRlZmF1bHRJbnN0YW5jZSlcclxuICAgICAgLndoZXJlUGFyYW0oXCJzZXJpYWxpemVyRm5cIikuaXNPcHRpb25hbCgpLmlzRnVuY3Rpb24oKVxyXG4gICAgICAuYXBwbHlBbGwodGhpcyk7XHJcbiAgICB0aGlzLmRhdGFTZXJ2aWNlcyA9IFtdOyAvLyBhcnJheSBvZiBkYXRhU2VydmljZXM7XHJcbiAgICB0aGlzLl9yZXNvdXJjZUVudGl0eVR5cGVNYXAgPSB7fTsgLy8ga2V5IGlzIHJlc291cmNlIG5hbWUgLSB2YWx1ZSBpcyBxdWFsaWZpZWQgZW50aXR5VHlwZSBuYW1lXHJcbiAgICB0aGlzLl9zdHJ1Y3R1cmFsVHlwZU1hcCA9IHt9OyAvLyBrZXkgaXMgcXVhbGlmaWVkIHN0cnVjdHVyYWx0eXBlIG5hbWUgLSB2YWx1ZSBpcyBzdHJ1Y3R1cmFsVHlwZS4gKCBzdHJ1Y3R1cmFsID0gZW50aXR5VHlwZSBvciBjb21wbGV4VHlwZSkuXHJcbiAgICB0aGlzLl9zaG9ydE5hbWVNYXAgPSB7fTsgLy8ga2V5IGlzIHNob3J0TmFtZSwgdmFsdWUgaXMgcXVhbGlmaWVkIG5hbWUgLSBkb2VzIG5vdCBuZWVkIHRvIGJlIHNlcmlhbGl6ZWQuXHJcbiAgICB0aGlzLl9jdG9yUmVnaXN0cnkgPSB7fTsgLy8ga2V5IGlzIGVpdGhlciBzaG9ydCBvciBxdWFsIHR5cGUgbmFtZSAtIHZhbHVlIGlzIGN0b3I7XHJcblxyXG4gICAgdGhpcy5faW5jb21wbGV0ZVR5cGVNYXAgPSB7fTsgLy8ga2V5IGlzIGVudGl0eVR5cGVOYW1lOyB2YWx1ZSBpcyBhcnJheSBvZiBuYXYgcHJvcHNcclxuICAgIHRoaXMuX2luY29tcGxldGVDb21wbGV4VHlwZU1hcCA9IHt9OyAvLyBrZXkgaXMgY29tcGxleFR5cGVOYW1lOyB2YWx1ZSBpcyBhcnJheSBvZiBjb21wbGV4VHlwZSBwcm9wc1xyXG4gICAgdGhpcy5faWQgPSBNZXRhZGF0YVN0b3JlLl9faWQrKztcclxuICAgIHRoaXMubWV0YWRhdGFGZXRjaGVkID0gbmV3IEJyZWV6ZUV2ZW50KFwibWV0YWRhdGFGZXRjaGVkXCIsIHRoaXMpO1xyXG5cclxuICB9XHJcblxyXG4gIC8vIG5lZWRzIHRvIGJlIG1hZGUgYXZhaWwgdG8gZGF0YVNlcnZpY2UueHh4IGZpbGVzXHJcbiAgc3RhdGljIG5vcm1hbGl6ZVR5cGVOYW1lID0gY29yZS5tZW1vaXplKGZ1bmN0aW9uIChyYXdUeXBlTmFtZTogc3RyaW5nKSB7XHJcbiAgICByZXR1cm4gcmF3VHlwZU5hbWUgJiYgTWV0YWRhdGFTdG9yZS5wYXJzZVR5cGVOYW1lKHJhd1R5cGVOYW1lKS50eXBlTmFtZTtcclxuICB9KTtcclxuICAvLyBmb3IgZGVidWdnaW5nIHVzZSB0aGUgbGluZSBiZWxvdyBpbnN0ZWFkLlxyXG4gIC8vY3Rvci5ub3JtYWxpemVUeXBlTmFtZSA9IGZ1bmN0aW9uIChyYXdUeXBlTmFtZSkgeyByZXR1cm4gcGFyc2VUeXBlTmFtZShyYXdUeXBlTmFtZSkudHlwZU5hbWU7IH07XHJcblxyXG4gIC8qKlxyXG4gIEdlbmVyYWwgcHVycG9zZSBwcm9wZXJ0eSBzZXQgbWV0aG9kXHJcbiAgXHJcbiAgPiAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgZW0xLm1ldGFkYXRhU3RvcmUuc2V0UHJvcGVydGllcygge1xyXG4gID4gICAgICAgICB2ZXJzaW9uOiBcIjYuMS4zXCIsXHJcbiAgPiAgICAgICAgIHNlcmlhbGl6ZXJGbjogZnVuY3Rpb24ocHJvcCwgdmFsdWUpIHtcclxuICA+ICAgICAgICAgcmV0dXJuIChwcm9wLmlzVW5tYXBwZWQpID8gdW5kZWZpbmVkIDogdmFsdWU7XHJcbiAgPiAgICAgICAgIH1cclxuICA+ICAgICApfTtcclxuICBAcGFyYW0gY29uZmlnIC0gIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBzZWxlY3RlZCBwcm9wZXJ0aWVzIGFuZCB2YWx1ZXMgdG8gc2V0LlxyXG4gICoqL1xyXG4gIHNldFByb3BlcnRpZXMoY29uZmlnOiBNZXRhZGF0YVN0b3JlQ29uZmlnKSB7XHJcbiAgICBhc3NlcnRDb25maWcoY29uZmlnKVxyXG4gICAgICAud2hlcmVQYXJhbShcIm5hbWVcIikuaXNTdHJpbmcoKS5pc09wdGlvbmFsKClcclxuICAgICAgLndoZXJlUGFyYW0oXCJzZXJpYWxpemVyRm5cIikuaXNGdW5jdGlvbigpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAuYXBwbHlBbGwodGhpcyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBBZGRzIGEgRGF0YVNlcnZpY2UgdG8gdGhpcyBNZXRhZGF0YVN0b3JlLiBJZiBhIERhdGFTZXJ2aWNlIHdpdGggdGhlIHNhbWUgc2VydmljZU5hbWUgaXMgYWxyZWFkeVxyXG4gIGluIHRoZSBNZXRhZGF0YVN0b3JlIGFuIGV4Y2VwdGlvbiB3aWxsIGJlIHRocm93bi5cclxuICBAcGFyYW0gZGF0YVNlcnZpY2UgLSBUaGUgW1tEYXRhU2VydmljZV1dIHRvIGFkZFxyXG4gIEBwYXJhbSBzaG91bGRPdmVyd3JpdGUgLSAoZGVmYXVsdD1mYWxzZSkgUGVybWl0IG92ZXJ3cml0ZSBvZiBleGlzdGluZyBEYXRhU2VydmljZSByYXRoZXIgdGhhbiB0aHJvdyBleGNlcHRpb25cclxuICAqKi9cclxuICBhZGREYXRhU2VydmljZShkYXRhU2VydmljZTogRGF0YVNlcnZpY2UsIHNob3VsZE92ZXJ3cml0ZT86IGJvb2xlYW4pIHtcclxuICAgIGFzc2VydFBhcmFtKGRhdGFTZXJ2aWNlLCBcImRhdGFTZXJ2aWNlXCIpLmlzSW5zdGFuY2VPZihEYXRhU2VydmljZSkuY2hlY2soKTtcclxuICAgIGFzc2VydFBhcmFtKHNob3VsZE92ZXJ3cml0ZSwgXCJzaG91bGRPdmVyd3JpdGVcIikuaXNCb29sZWFuKCkuaXNPcHRpb25hbCgpLmNoZWNrKCk7XHJcbiAgICBsZXQgaXggPSB0aGlzLl9nZXREYXRhU2VydmljZUluZGV4KGRhdGFTZXJ2aWNlLnNlcnZpY2VOYW1lKTtcclxuICAgIGlmIChpeCA+PSAwKSB7XHJcbiAgICAgIGlmICghIXNob3VsZE92ZXJ3cml0ZSkge1xyXG4gICAgICAgIHRoaXMuZGF0YVNlcnZpY2VzW2l4XSA9IGRhdGFTZXJ2aWNlO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkEgZGF0YVNlcnZpY2Ugd2l0aCB0aGlzIG5hbWUgJ1wiICsgZGF0YVNlcnZpY2Uuc2VydmljZU5hbWUgKyBcIicgYWxyZWFkeSBleGlzdHMgaW4gdGhpcyBNZXRhZGF0YVN0b3JlXCIpO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLmRhdGFTZXJ2aWNlcy5wdXNoKGRhdGFTZXJ2aWNlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF9nZXREYXRhU2VydmljZUluZGV4KHNlcnZpY2VOYW1lOiBzdHJpbmcpIHtcclxuICAgIHJldHVybiBjb3JlLmFycmF5SW5kZXhPZih0aGlzLmRhdGFTZXJ2aWNlcywgZnVuY3Rpb24gKGRzKSB7XHJcbiAgICAgIHJldHVybiBkcy5zZXJ2aWNlTmFtZSA9PT0gc2VydmljZU5hbWU7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIEFkZHMgYW4gRW50aXR5VHlwZSB0byB0aGlzIE1ldGFkYXRhU3RvcmUuICBObyBhZGRpdGlvbmFsIHByb3BlcnRpZXMgbWF5IGJlIGFkZGVkIHRvIHRoZSBFbnRpdHlUeXBlIGFmdGVyIGl0cyBoYXNcclxuICBiZWVuIGFkZGVkIHRvIHRoZSBNZXRhZGF0YVN0b3JlLlxyXG4gIEBwYXJhbSBzdHJ1Y3R1cmFsVHlwZSAtIFRoZSBFbnRpdHlUeXBlIG9yIENvbXBsZXhUeXBlIHRvIGFkZFxyXG4gICoqL1xyXG4gIGFkZEVudGl0eVR5cGUoc3R5cGU6IFN0cnVjdHVyYWxUeXBlIHwgRW50aXR5VHlwZUNvbmZpZyB8IENvbXBsZXhUeXBlQ29uZmlnKSB7XHJcbiAgICBsZXQgc3RydWN0dXJhbFR5cGU6IFN0cnVjdHVyYWxUeXBlO1xyXG4gICAgaWYgKHN0eXBlIGluc3RhbmNlb2YgRW50aXR5VHlwZSB8fCBzdHlwZSBpbnN0YW5jZW9mIENvbXBsZXhUeXBlKSB7XHJcbiAgICAgIHN0cnVjdHVyYWxUeXBlID0gc3R5cGU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBzdHJ1Y3R1cmFsVHlwZSA9IChzdHlwZSBhcyBhbnkpLmlzQ29tcGxleFR5cGUgPyBuZXcgQ29tcGxleFR5cGUoc3R5cGUpIDogbmV3IEVudGl0eVR5cGUoc3R5cGUpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGlmICghc3RydWN0dXJhbFR5cGUuaXNDb21wbGV4VHlwZSkgeyAvLyBzYW1lIGFzIGJlbG93IGJ1dCBpc24ndCBhICd0eXBlIGd1YXJkJ1xyXG4gICAgaWYgKHN0cnVjdHVyYWxUeXBlIGluc3RhbmNlb2YgRW50aXR5VHlwZSkge1xyXG4gICAgICBpZiAoc3RydWN0dXJhbFR5cGUuYmFzZVR5cGVOYW1lICYmICFzdHJ1Y3R1cmFsVHlwZS5iYXNlRW50aXR5VHlwZSkge1xyXG4gICAgICAgIGxldCBiYXNlRW50aXR5VHlwZSA9IHRoaXMuX2dldFN0cnVjdHVyYWxUeXBlKHN0cnVjdHVyYWxUeXBlLmJhc2VUeXBlTmFtZSwgdHJ1ZSk7XHJcbiAgICAgICAgLy8gc2FmZSBjYXN0IGJlY2F1c2Ugd2Uga25vdyB0aGF0IGJhc2VFbnRpdHlUeXBlIG11c3QgYmUgYW4gRW50aXR5VHlwZSBpZiB0aGUgc3RydWN0dXJhbFR5cGUgaXMgYW4gRW50aXR5VHlwZVxyXG4gICAgICAgIHN0cnVjdHVyYWxUeXBlLl91cGRhdGVGcm9tQmFzZShiYXNlRW50aXR5VHlwZSBhcyBFbnRpdHlUeXBlKTtcclxuICAgICAgfVxyXG4gICAgICBpZiAoc3RydWN0dXJhbFR5cGUua2V5UHJvcGVydGllcy5sZW5ndGggPT09IDAgJiYgIXN0cnVjdHVyYWxUeXBlLmlzQWJzdHJhY3QpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJVbmFibGUgdG8gYWRkIFwiICsgc3RydWN0dXJhbFR5cGUubmFtZSArXHJcbiAgICAgICAgICBcIiB0byB0aGlzIE1ldGFkYXRhU3RvcmUuICBBbiBFbnRpdHlUeXBlIG11c3QgaGF2ZSBhdCBsZWFzdCBvbmUgcHJvcGVydHkgZGVzaWduYXRlZCBhcyBhIGtleSBwcm9wZXJ0eSAtIFNlZSB0aGUgJ0RhdGFQcm9wZXJ0eS5pc1BhcnRPZktleScgcHJvcGVydHkuXCIpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgc3RydWN0dXJhbFR5cGUubWV0YWRhdGFTdG9yZSA9IHRoaXM7XHJcbiAgICAvLyBkb24ndCByZWdpc3RlciBhbm9uIHR5cGVzXHJcbiAgICBpZiAoIShzdHJ1Y3R1cmFsVHlwZSBhcyBhbnkpLmlzQW5vbnltb3VzKSB7XHJcbiAgICAgIGlmICh0aGlzLl9zdHJ1Y3R1cmFsVHlwZU1hcFtzdHJ1Y3R1cmFsVHlwZS5uYW1lXSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlR5cGUgXCIgKyBzdHJ1Y3R1cmFsVHlwZS5uYW1lICsgXCIgYWxyZWFkeSBleGlzdHMgaW4gdGhpcyBNZXRhZGF0YVN0b3JlLlwiKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy5fc3RydWN0dXJhbFR5cGVNYXBbc3RydWN0dXJhbFR5cGUubmFtZV0gPSBzdHJ1Y3R1cmFsVHlwZTtcclxuICAgICAgdGhpcy5fc2hvcnROYW1lTWFwW3N0cnVjdHVyYWxUeXBlLnNob3J0TmFtZV0gPSBzdHJ1Y3R1cmFsVHlwZS5uYW1lO1xyXG4gICAgfVxyXG5cclxuICAgIHN0cnVjdHVyYWxUeXBlLmdldFByb3BlcnRpZXMoKS5mb3JFYWNoKHAgPT4ge1xyXG4gICAgICBzdHJ1Y3R1cmFsVHlwZS5fdXBkYXRlTmFtZXMocCk7XHJcbiAgICAgIGlmICghcC5pc1VubWFwcGVkKSB7XHJcbiAgICAgICAgc3RydWN0dXJhbFR5cGUuX21hcHBlZFByb3BlcnRpZXNDb3VudCsrO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICBzdHJ1Y3R1cmFsVHlwZS5fdXBkYXRlQ3BzKCk7XHJcblxyXG4gICAgLy8gJ2lzRW50aXR5VHlwZScgaXMgYSB0eXBlIGd1YXJkXHJcbiAgICBpZiAoc3RydWN0dXJhbFR5cGUgaW5zdGFuY2VvZiBFbnRpdHlUeXBlKSB7XHJcbiAgICAgIHN0cnVjdHVyYWxUeXBlLl91cGRhdGVOcHMoKTtcclxuICAgICAgLy8gZ2l2ZSB0aGUgdHlwZSBpdCdzIGJhc2UncyByZXNvdXJjZSBuYW1lIGlmIGl0IGRvZXNuJ3QgaGF2ZSBpdHMgb3duLlxyXG4gICAgICBsZXQgZGVmUmVzb3VyY2VOYW1lID0gc3RydWN0dXJhbFR5cGUuZGVmYXVsdFJlc291cmNlTmFtZSB8fCAoc3RydWN0dXJhbFR5cGUuYmFzZUVudGl0eVR5cGUgJiYgc3RydWN0dXJhbFR5cGUuYmFzZUVudGl0eVR5cGUuZGVmYXVsdFJlc291cmNlTmFtZSk7XHJcbiAgICAgIGlmIChkZWZSZXNvdXJjZU5hbWUgJiYgIXRoaXMuZ2V0RW50aXR5VHlwZU5hbWVGb3JSZXNvdXJjZU5hbWUoZGVmUmVzb3VyY2VOYW1lKSkge1xyXG4gICAgICAgIHRoaXMuc2V0RW50aXR5VHlwZUZvclJlc291cmNlTmFtZShkZWZSZXNvdXJjZU5hbWUsIHN0cnVjdHVyYWxUeXBlLm5hbWUpO1xyXG4gICAgICB9XHJcbiAgICAgIHN0cnVjdHVyYWxUeXBlLmRlZmF1bHRSZXNvdXJjZU5hbWUgPSBkZWZSZXNvdXJjZU5hbWU7XHJcbiAgICAgIC8vIGNoZWNrIGlmIHRoaXMgc3RydWN0dXJhbCB0eXBlJ3MgbmFtZSwgc2hvcnQgdmVyc2lvbiBvciBxdWFsaWZpZWQgdmVyc2lvbiBoYXMgYSByZWdpc3RlcmVkIGN0b3IuXHJcbiAgICAgIHN0cnVjdHVyYWxUeXBlLmdldEVudGl0eUN0b3IoKTtcclxuICAgIH1cclxuXHJcbiAgfVxyXG5cclxuXHJcbiAgLyoqXHJcbiAgRXhwb3J0cyB0aGlzIE1ldGFkYXRhU3RvcmUgdG8gYSBzZXJpYWxpemVkIHN0cmluZyBhcHByb3ByaWF0ZSBmb3IgbG9jYWwgc3RvcmFnZS4gICBUaGlzIG9wZXJhdGlvbiBpcyBhbHNvIGNhbGxlZFxyXG4gIGludGVybmFsbHkgd2hlbiBleHBvcnRpbmcgYW4gRW50aXR5TWFuYWdlci5cclxuICA+ICAgICAgLy8gYXNzdW1lIG1zIGlzIGEgcHJldmlvdXNseSBjcmVhdGVkIE1ldGFkYXRhU3RvcmVcclxuICA+ICAgICAgbGV0IG1ldGFkYXRhQXNTdHJpbmcgPSBtcy5leHBvcnRNZXRhZGF0YSgpO1xyXG4gID4gICAgICB3aW5kb3cubG9jYWxTdG9yYWdlLnNldEl0ZW0oXCJtZXRhZGF0YVwiLCBtZXRhZGF0YUFzU3RyaW5nKTtcclxuICA+ICAgICAgLy8gYW5kIGxhdGVyLCB1c3VhbGx5IGluIGEgZGlmZmVyZW50IHNlc3Npb24gaW1wb3J0ZWRcclxuICA+ICAgICAgbGV0IG1ldGFkYXRhRnJvbVN0b3JhZ2UgPSB3aW5kb3cubG9jYWxTdG9yYWdlLmdldEl0ZW0oXCJtZXRhZGF0YVwiKTtcclxuICA+ICAgICAgbGV0IG5ld01ldGFkYXRhU3RvcmUgPSBuZXcgTWV0YWRhdGFTdG9yZSgpO1xyXG4gID4gICAgICBuZXdNZXRhZGF0YVN0b3JlLmltcG9ydE1ldGFkYXRhKG1ldGFkYXRhRnJvbVN0b3JhZ2UpO1xyXG4gIEByZXR1cm4gQSBzZXJpYWxpemVkIHZlcnNpb24gb2YgdGhpcyBNZXRhZGF0YVN0b3JlIHRoYXQgbWF5IGJlIHN0b3JlZCBsb2NhbGx5IGFuZCBsYXRlciByZXN0b3JlZC5cclxuICAqKi9cclxuICBleHBvcnRNZXRhZGF0YSgpIHtcclxuICAgIGxldCByZXN1bHQgPSBKU09OLnN0cmluZ2lmeSh7XHJcbiAgICAgIFwibWV0YWRhdGFWZXJzaW9uXCI6IE1ldGFkYXRhU3RvcmUubWV0YWRhdGFWZXJzaW9uLFxyXG4gICAgICBcIm5hbWVcIjogdGhpcy5uYW1lLFxyXG4gICAgICBcIm5hbWluZ0NvbnZlbnRpb25cIjogdGhpcy5uYW1pbmdDb252ZW50aW9uLm5hbWUsXHJcbiAgICAgIFwibG9jYWxRdWVyeUNvbXBhcmlzb25PcHRpb25zXCI6IHRoaXMubG9jYWxRdWVyeUNvbXBhcmlzb25PcHRpb25zLm5hbWUsXHJcbiAgICAgIFwiZGF0YVNlcnZpY2VzXCI6IHRoaXMuZGF0YVNlcnZpY2VzLFxyXG4gICAgICBcInN0cnVjdHVyYWxUeXBlc1wiOiBjb3JlLm9iamVjdE1hcCh0aGlzLl9zdHJ1Y3R1cmFsVHlwZU1hcCksXHJcbiAgICAgIFwicmVzb3VyY2VFbnRpdHlUeXBlTWFwXCI6IHRoaXMuX3Jlc291cmNlRW50aXR5VHlwZU1hcFxyXG4gICAgfSwgbnVsbCwgY29uZmlnLnN0cmluZ2lmeVBhZCk7XHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgSW1wb3J0cyBhIHByZXZpb3VzbHkgZXhwb3J0ZWQgc2VyaWFsaXplZCBNZXRhZGF0YVN0b3JlIGludG8gdGhpcyBNZXRhZGF0YVN0b3JlLlxyXG4gICAgXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBtcyBpcyBhIHByZXZpb3VzbHkgY3JlYXRlZCBNZXRhZGF0YVN0b3JlXHJcbiAgPiAgICAgIGxldCBtZXRhZGF0YUFzU3RyaW5nID0gbXMuZXhwb3J0TWV0YWRhdGEoKTtcclxuICA+ICAgICAgd2luZG93LmxvY2FsU3RvcmFnZS5zZXRJdGVtKFwibWV0YWRhdGFcIiwgbWV0YWRhdGFBc1N0cmluZyk7XHJcbiAgPiAgICAgIC8vIGFuZCBsYXRlciwgdXN1YWxseSBpbiBhIGRpZmZlcmVudCBzZXNzaW9uXHJcbiAgPiAgICAgIGxldCBtZXRhZGF0YUZyb21TdG9yYWdlID0gd2luZG93LmxvY2FsU3RvcmFnZS5nZXRJdGVtKFwibWV0YWRhdGFcIik7XHJcbiAgPiAgICAgIGxldCBuZXdNZXRhZGF0YVN0b3JlID0gbmV3IE1ldGFkYXRhU3RvcmUoKTtcclxuICA+ICAgICAgbmV3TWV0YWRhdGFTdG9yZS5pbXBvcnRNZXRhZGF0YShtZXRhZGF0YUZyb21TdG9yYWdlKTtcclxuICBAcGFyYW0gZXhwb3J0ZWRNZXRhZGF0YSAtIEEgcHJldmlvdXNseSBleHBvcnRlZCBNZXRhZGF0YVN0b3JlLlxyXG4gIEBwYXJhbSBhbGxvd01lcmdlIC0gIEFsbG93cyBjdXN0b20gbWV0YWRhdGEgdG8gYmUgbWVyZ2VkIGludG8gZXhpc3RpbmcgbWV0YWRhdGEgdHlwZXMuXHJcbiAgQHJldHVybiBUaGlzIE1ldGFkYXRhU3RvcmUuXHJcbiAgQGNoYWluYWJsZVxyXG4gICoqL1xyXG4gIGltcG9ydE1ldGFkYXRhKGV4cG9ydGVkTWV0YWRhdGE6IHN0cmluZyB8IE9iamVjdCwgYWxsb3dNZXJnZTogYm9vbGVhbiA9IGZhbHNlKSB7XHJcbiAgICBhc3NlcnRQYXJhbShhbGxvd01lcmdlLCBcImFsbG93TWVyZ2VcIikuaXNPcHRpb25hbCgpLmlzQm9vbGVhbigpLmNoZWNrKCk7XHJcbiAgICB0aGlzLl9kZWZlcnJlZFR5cGVzID0ge307XHJcbiAgICAvLyBpbnN1cmUgdGhhdCB3ZSBkb24ndCBtdXRhdGUgaW5jb21pbmcgZXhwb3J0ZWRNZXRhZGF0YSAoIGlmIGl0cyBhbiBvYmplY3QpXHJcbiAgICBsZXQgbWV0YWRhdGFBc1N0cmluZyA9ICh0eXBlb2YgKGV4cG9ydGVkTWV0YWRhdGEpID09PSBcInN0cmluZ1wiKSA/IGV4cG9ydGVkTWV0YWRhdGEgOiBKU09OLnN0cmluZ2lmeShleHBvcnRlZE1ldGFkYXRhKTtcclxuICAgIGNvbnN0IG1ldGFkYXRhSnNvbiA9IEpTT04ucGFyc2UobWV0YWRhdGFBc1N0cmluZyk7XHJcblxyXG4gICAgaWYgKG1ldGFkYXRhSnNvbi5zY2hlbWEpIHtcclxuICAgICAgcmV0dXJuIENzZGxNZXRhZGF0YVBhcnNlci5wYXJzZSh0aGlzLCBtZXRhZGF0YUpzb24uc2NoZW1hLCBtZXRhZGF0YUpzb24uYWx0TWV0YWRhdGEpO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBqc29uID0gbWV0YWRhdGFKc29uIGFzIElNZXRhZGF0YUpzb247XHJcbiAgICBpZiAoanNvbi5tZXRhZGF0YVZlcnNpb24gJiYganNvbi5tZXRhZGF0YVZlcnNpb24gIT09IE1ldGFkYXRhU3RvcmUubWV0YWRhdGFWZXJzaW9uKSB7XHJcbiAgICAgIGxldCBtc2cgPSBjb3JlLmZvcm1hdFN0cmluZyhcIkNhbm5vdCBpbXBvcnQgbWV0YWRhdGEgd2l0aCBhIGRpZmZlcmVudCAnbWV0YWRhdGFWZXJzaW9uJyAoJTEpIHRoYW4gdGhlIGN1cnJlbnQgJ01ldGFkYXRhU3RvcmUubWV0YWRhdGFWZXJzaW9uJyAoJTIpIFwiLFxyXG4gICAgICAgIGpzb24ubWV0YWRhdGFWZXJzaW9uLCBNZXRhZGF0YVN0b3JlLm1ldGFkYXRhVmVyc2lvbik7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihtc2cpO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBuY05hbWUgPSBqc29uLm5hbWluZ0NvbnZlbnRpb247XHJcbiAgICBsZXQgbHFjb05hbWUgPSBqc29uLmxvY2FsUXVlcnlDb21wYXJpc29uT3B0aW9ucztcclxuICAgIGlmICh0aGlzLmlzRW1wdHkoKSkge1xyXG4gICAgICB0aGlzLm5hbWluZ0NvbnZlbnRpb24gPSBjb25maWcuX2ZldGNoT2JqZWN0KE5hbWluZ0NvbnZlbnRpb24sIG5jTmFtZSkgfHwgdGhpcy5uYW1pbmdDb252ZW50aW9uO1xyXG4gICAgICB0aGlzLmxvY2FsUXVlcnlDb21wYXJpc29uT3B0aW9ucyA9IGNvbmZpZy5fZmV0Y2hPYmplY3QoTG9jYWxRdWVyeUNvbXBhcmlzb25PcHRpb25zLCBscWNvTmFtZSkgfHwgdGhpcy5sb2NhbFF1ZXJ5Q29tcGFyaXNvbk9wdGlvbnM7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBpZiAobmNOYW1lICYmIHRoaXMubmFtaW5nQ29udmVudGlvbi5uYW1lICE9PSBuY05hbWUpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgaW1wb3J0IG1ldGFkYXRhIHdpdGggYSBkaWZmZXJlbnQgJ25hbWluZ0NvbnZlbnRpb24nIGZyb20gdGhlIGN1cnJlbnQgTWV0YWRhdGFTdG9yZVwiKTtcclxuICAgICAgfVxyXG4gICAgICBpZiAobHFjb05hbWUgJiYgdGhpcy5sb2NhbFF1ZXJ5Q29tcGFyaXNvbk9wdGlvbnMubmFtZSAhPT0gbHFjb05hbWUpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgaW1wb3J0IG1ldGFkYXRhIHdpdGggZGlmZmVyZW50ICdsb2NhbFF1ZXJ5Q29tcGFyaXNvbk9wdGlvbnMnIGZyb20gdGhlIGN1cnJlbnQgTWV0YWRhdGFTdG9yZVwiKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vbm9pbnNwZWN0aW9uIEpTSGludFxyXG4gICAganNvbi5kYXRhU2VydmljZXMgJiYganNvbi5kYXRhU2VydmljZXMuZm9yRWFjaCgoZHMpID0+IHtcclxuICAgICAgbGV0IHJlYWxEcyA9IERhdGFTZXJ2aWNlLmZyb21KU09OKGRzKTtcclxuICAgICAgdGhpcy5hZGREYXRhU2VydmljZShyZWFsRHMsIHRydWUpO1xyXG4gICAgfSk7XHJcblxyXG4gICAganNvbi5zdHJ1Y3R1cmFsVHlwZXMgJiYganNvbi5zdHJ1Y3R1cmFsVHlwZXMuZm9yRWFjaCgoc3R5cGUpID0+IHtcclxuICAgICAgc3RydWN0dXJhbFR5cGVGcm9tSnNvbih0aGlzLCBzdHlwZSwgYWxsb3dNZXJnZSk7XHJcbiAgICB9KTtcclxuICAgIGNvcmUuZXh0ZW5kKHRoaXMuX3Jlc291cmNlRW50aXR5VHlwZU1hcCwganNvbi5yZXNvdXJjZUVudGl0eVR5cGVNYXApO1xyXG4gICAgY29yZS5leHRlbmQodGhpcy5faW5jb21wbGV0ZVR5cGVNYXAsIGpzb24uaW5jb21wbGV0ZVR5cGVNYXApO1xyXG5cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgQ3JlYXRlcyBhIG5ldyBNZXRhZGF0YVN0b3JlIGZyb20gYSBwcmV2aW91c2x5IGV4cG9ydGVkIHNlcmlhbGl6ZWQgTWV0YWRhdGFTdG9yZVxyXG4gID4gICAgICAvLyBhc3N1bWUgbXMgaXMgYSBwcmV2aW91c2x5IGNyZWF0ZWQgTWV0YWRhdGFTdG9yZVxyXG4gID4gICAgICBsZXQgbWV0YWRhdGFBc1N0cmluZyA9IG1zLmV4cG9ydE1ldGFkYXRhKCk7XHJcbiAgPiAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbShcIm1ldGFkYXRhXCIsIG1ldGFkYXRhQXNTdHJpbmcpO1xyXG4gID4gICAgICAvLyBhbmQgbGF0ZXIsIHVzdWFsbHkgaW4gYSBkaWZmZXJlbnQgc2Vzc2lvblxyXG4gID4gICAgICBsZXQgbWV0YWRhdGFGcm9tU3RvcmFnZSA9IHdpbmRvdy5sb2NhbFN0b3JhZ2UuZ2V0SXRlbShcIm1ldGFkYXRhXCIpO1xyXG4gID4gICAgICBsZXQgbmV3TWV0YWRhdGFTdG9yZSA9IE1ldGFkYXRhU3RvcmUuaW1wb3J0TWV0YWRhdGEobWV0YWRhdGFGcm9tU3RvcmFnZSk7XHJcbiAgQHBhcmFtIGV4cG9ydGVkU3RyaW5nIC0gQSBwcmV2aW91c2x5IGV4cG9ydGVkIE1ldGFkYXRhU3RvcmUuXHJcbiAgQHJldHVybiBBIG5ldyBNZXRhZGF0YVN0b3JlLlxyXG4gICoqL1xyXG4gIHN0YXRpYyBpbXBvcnRNZXRhZGF0YShleHBvcnRlZFN0cmluZzogc3RyaW5nKSB7XHJcbiAgICBsZXQgbXMgPSBuZXcgTWV0YWRhdGFTdG9yZSgpO1xyXG4gICAgbXMuaW1wb3J0TWV0YWRhdGEoZXhwb3J0ZWRTdHJpbmcpO1xyXG4gICAgcmV0dXJuIG1zO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgUmV0dXJucyB3aGV0aGVyIE1ldGFkYXRhIGhhcyBiZWVuIHJldHJpZXZlZCBmb3IgYSBzcGVjaWZpZWQgc2VydmljZSBuYW1lLlxyXG4gID4gICAgICAvLyBBc3N1bWUgZW0xIGlzIGFuIGV4aXN0aW5nIEVudGl0eU1hbmFnZXIuXHJcbiAgPiAgICAgIGlmICghZW0xLm1ldGFkYXRhU3RvcmUuaGFzTWV0YWRhdGFGb3IoXCJicmVlemUvTm9ydGh3aW5kSUJNb2RlbFwiKSkpIHtcclxuICA+ICAgICAgICAgIC8vIGRvIHNvbWV0aGluZyBpbnRlcmVzdGluZ1xyXG4gID4gICAgICB9XHJcbiAgQHBhcmFtIHNlcnZpY2VOYW1lIC0gVGhlIHNlcnZpY2UgbmFtZS5cclxuICBAcmV0dXJuIFdoZXRoZXIgbWV0YWRhdGEgaGFzIGFscmVhZHkgYmVlbiByZXRyaWV2ZWQgZm9yIHRoZSBzcGVjaWZpZWQgc2VydmljZSBuYW1lLlxyXG4gICoqL1xyXG4gIGhhc01ldGFkYXRhRm9yKHNlcnZpY2VOYW1lOiBzdHJpbmcpIHtcclxuICAgIHJldHVybiAhIXRoaXMuZ2V0RGF0YVNlcnZpY2Uoc2VydmljZU5hbWUpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgUmV0dXJucyB0aGUgRGF0YVNlcnZpY2UgZm9yIGEgc3BlY2lmaWVkIHNlcnZpY2UgbmFtZVxyXG4gID4gICAgICAvLyBBc3N1bWUgZW0xIGlzIGFuIGV4aXN0aW5nIEVudGl0eU1hbmFnZXIuXHJcbiAgPiAgICAgIGxldCBkcyA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldERhdGFTZXJ2aWNlKFwiYnJlZXplL05vcnRod2luZElCTW9kZWxcIik7XHJcbiAgPiAgICAgIGxldCBhZGFwdGVyTmFtZSA9IGRzLmFkYXB0ZXJOYW1lOyAvLyBtYXkgYmUgbnVsbFxyXG4gIEBwYXJhbSBzZXJ2aWNlTmFtZSAtIFRoZSBzZXJ2aWNlIG5hbWUuXHJcbiAgQHJldHVybiBUaGUgRGF0YVNlcnZpY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIG5hbWUuXHJcbiAgKiovXHJcbiAgZ2V0RGF0YVNlcnZpY2Uoc2VydmljZU5hbWU6IHN0cmluZykge1xyXG4gICAgYXNzZXJ0UGFyYW0oc2VydmljZU5hbWUsIFwic2VydmljZU5hbWVcIikuaXNTdHJpbmcoKS5jaGVjaygpO1xyXG5cclxuICAgIHNlcnZpY2VOYW1lID0gRGF0YVNlcnZpY2UuX25vcm1hbGl6ZVNlcnZpY2VOYW1lKHNlcnZpY2VOYW1lKTtcclxuICAgIHJldHVybiBjb3JlLmFycmF5Rmlyc3QodGhpcy5kYXRhU2VydmljZXMsIGZ1bmN0aW9uIChkczogRGF0YVNlcnZpY2UpIHtcclxuICAgICAgcmV0dXJuIGRzLnNlcnZpY2VOYW1lID09PSBzZXJ2aWNlTmFtZTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgRmV0Y2hlcyB0aGUgbWV0YWRhdGEgZm9yIGEgc3BlY2lmaWVkICdzZXJ2aWNlJy4gVGhpcyBtZXRob2QgaXMgYXV0b21hdGljYWxseSBjYWxsZWRcclxuICBpbnRlcm5hbGx5IGJ5IGFuIEVudGl0eU1hbmFnZXIgYmVmb3JlIGl0cyBmaXJzdCBxdWVyeSBhZ2FpbnN0IGEgbmV3IHNlcnZpY2UuIF9fQXN5bmNfX1xyXG5cclxuICBVc3VhbGx5IHlvdSB3aWxsIG5vdCBhY3R1YWxseSBwcm9jZXNzIHRoZSByZXN1bHRzIG9mIGEgZmV0Y2hNZXRhZGF0YSBjYWxsIGRpcmVjdGx5LCBidXQgd2lsbCBpbnN0ZWFkXHJcbiAgYXNrIGZvciB0aGUgbWV0YWRhdGEgZnJvbSB0aGUgRW50aXR5TWFuYWdlciBhZnRlciB0aGUgZmV0Y2hNZXRhZGF0YSBjYWxsIHJldHVybnMuXHJcbiAgPiAgICAgIGxldCBtcyA9IG5ldyBNZXRhZGF0YVN0b3JlKCk7XHJcbiAgPiAgICAgIC8vIG9yIG1vcmUgY29tbW9ubHlcclxuICA+ICAgICAgLy8gbGV0IG1zID0gYW5FbnRpdHlNYW5hZ2VyLm1ldGFkYXRhU3RvcmU7XHJcbiAgPiAgICAgIG1zLmZldGNoTWV0YWRhdGEoXCJicmVlemUvTm9ydGh3aW5kSUJNb2RlbFwiKS50aGVuKGZ1bmN0aW9uKHJhd01ldGFkYXRhKSB7XHJcbiAgPiAgICAgICAgICAgIC8vIGRvIHNvbWV0aGluZyB3aXRoIHRoZSBtZXRhZGF0YVxyXG4gID4gICAgICB9KS5jYXRjaChmdW5jdGlvbihleGNlcHRpb24pIHtcclxuICA+ICAgICAgICAgIC8vIGhhbmRsZSBleGNlcHRpb24gaGVyZVxyXG4gID4gICAgICB9KTtcclxuICBAcGFyYW0gZGF0YVNlcnZpY2UgLSAgRWl0aGVyIGEgRGF0YVNlcnZpY2Ugb3IganVzdCB0aGUgbmFtZSBvZiB0aGUgRGF0YVNlcnZpY2UgdG8gZmV0Y2ggbWV0YWRhdGEgZm9yLlxyXG4gIEBwYXJhbSBjYWxsYmFjayAtIEZ1bmN0aW9uIGNhbGxlZCBvbiBzdWNjZXNzLlxyXG4gIEBwYXJhbSBlcnJvckNhbGxiYWNrIC0gRnVuY3Rpb24gY2FsbGVkIG9uIGZhaWx1cmUuXHJcbiAgQHJldHVybiBQcm9taXNlXHJcbiAgKiovXHJcbiAgZmV0Y2hNZXRhZGF0YShkYXRhU2VydmljZTogc3RyaW5nIHwgRGF0YVNlcnZpY2UsIGNhbGxiYWNrPzogKHNjaGVtYTogYW55KSA9PiB2b2lkLCBlcnJvckNhbGxiYWNrPzogRXJyb3JDYWxsYmFjaykge1xyXG4gICAgdHJ5IHtcclxuICAgICAgYXNzZXJ0UGFyYW0oZGF0YVNlcnZpY2UsIFwiZGF0YVNlcnZpY2VcIikuaXNTdHJpbmcoKS5vcigpLmlzSW5zdGFuY2VPZihEYXRhU2VydmljZSkuY2hlY2soKTtcclxuICAgICAgYXNzZXJ0UGFyYW0oY2FsbGJhY2ssIFwiY2FsbGJhY2tcIikuaXNGdW5jdGlvbigpLmlzT3B0aW9uYWwoKS5jaGVjaygpO1xyXG4gICAgICBhc3NlcnRQYXJhbShlcnJvckNhbGxiYWNrLCBcImVycm9yQ2FsbGJhY2tcIikuaXNGdW5jdGlvbigpLmlzT3B0aW9uYWwoKS5jaGVjaygpO1xyXG5cclxuICAgICAgaWYgKHR5cGVvZiBkYXRhU2VydmljZSA9PT0gXCJzdHJpbmdcIikge1xyXG4gICAgICAgIC8vIHVzZSB0aGUgZGF0YVNlcnZpY2Ugd2l0aCBhIG1hdGNoaW5nIG5hbWUgb3IgY3JlYXRlIGEgbmV3IG9uZS5cclxuICAgICAgICBkYXRhU2VydmljZSA9IHRoaXMuZ2V0RGF0YVNlcnZpY2UoZGF0YVNlcnZpY2UpIHx8IG5ldyBEYXRhU2VydmljZSh7IHNlcnZpY2VOYW1lOiBkYXRhU2VydmljZSB9KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgZGF0YVNlcnZpY2UgPSBEYXRhU2VydmljZS5yZXNvbHZlKFtkYXRhU2VydmljZV0pO1xyXG5cclxuICAgICAgaWYgKHRoaXMuaGFzTWV0YWRhdGFGb3IoZGF0YVNlcnZpY2Uuc2VydmljZU5hbWUpKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTWV0YWRhdGEgZm9yIGEgc3BlY2lmaWMgc2VydmljZU5hbWUgbWF5IG9ubHkgYmUgZmV0Y2hlZCBvbmNlIHBlciBNZXRhZGF0YVN0b3JlLiBTZXJ2aWNlTmFtZTogXCIgKyBkYXRhU2VydmljZS5zZXJ2aWNlTmFtZSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiBkYXRhU2VydmljZS5hZGFwdGVySW5zdGFuY2UhLmZldGNoTWV0YWRhdGEodGhpcywgZGF0YVNlcnZpY2UpLnRoZW4oKHJhd01ldGFkYXRhOiBhbnkpID0+IHtcclxuICAgICAgICB0aGlzLm1ldGFkYXRhRmV0Y2hlZC5wdWJsaXNoKHsgbWV0YWRhdGFTdG9yZTogdGhpcywgZGF0YVNlcnZpY2U6IGRhdGFTZXJ2aWNlLCByYXdNZXRhZGF0YTogcmF3TWV0YWRhdGEgfSk7XHJcbiAgICAgICAgaWYgKGNhbGxiYWNrKSBjYWxsYmFjayhyYXdNZXRhZGF0YSk7XHJcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShyYXdNZXRhZGF0YSk7XHJcbiAgICAgIH0sIGZ1bmN0aW9uIChlcnJvcjogYW55KSB7XHJcbiAgICAgICAgaWYgKGVycm9yQ2FsbGJhY2spIGVycm9yQ2FsbGJhY2soZXJyb3IpO1xyXG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuXHJcbiAgLy8gVE9ETzogc3Ryb25nbHkgdHlwZSBpbnRlcmNlcHRvciBiZWxvdy5cclxuICAvKipcclxuICBVc2VkIHRvIHJlZ2lzdGVyIGEgY29uc3RydWN0b3IgZm9yIGFuIEVudGl0eVR5cGUgdGhhdCBpcyBub3Qga25vd24gdmlhIHN0YW5kYXJkIE1ldGFkYXRhIGRpc2NvdmVyeTtcclxuICBpLmUuIGFuIHVubWFwcGVkIHR5cGUuXHJcbiAgQHBhcmFtIGVudGl0eUN0b3IgLSBUaGUgY29uc3RydWN0b3IgZnVuY3Rpb24gZm9yIHRoZSAndW5tYXBwZWQnIHR5cGUuXHJcbiAgQHBhcmFtIGludGVyY2VwdG9yIC0gQW4gaW50ZXJjZXB0b3IgZnVuY3Rpb25cclxuICAqKi9cclxuICB0cmFja1VubWFwcGVkVHlwZShlbnRpdHlDdG9yOiBhbnksIGludGVyY2VwdG9yOiBhbnkpIHtcclxuICAgIGFzc2VydFBhcmFtKGVudGl0eUN0b3IsIFwiZW50aXR5Q3RvclwiKS5pc0Z1bmN0aW9uKCkuY2hlY2soKTtcclxuICAgIGFzc2VydFBhcmFtKGludGVyY2VwdG9yLCBcImludGVyY2VwdG9yXCIpLmlzRnVuY3Rpb24oKS5pc09wdGlvbmFsKCkuY2hlY2soKTtcclxuICAgIC8vIFRPRE86IHRoaW5rIGFib3V0IGFkZGluZyB0aGlzIHRvIHRoZSBNZXRhZGF0YVN0b3JlLlxyXG4gICAgbGV0IGVudGl0eVR5cGUgPSBuZXcgRW50aXR5VHlwZSh0aGlzKTtcclxuICAgIGVudGl0eVR5cGUuX3NldEN0b3IoZW50aXR5Q3RvciwgaW50ZXJjZXB0b3IpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgUHJvdmlkZXMgYSBtZWNoYW5pc20gdG8gcmVnaXN0ZXIgYSAnY3VzdG9tJyBjb25zdHJ1Y3RvciB0byBiZSB1c2VkIHdoZW4gY3JlYXRpbmcgbmV3IGluc3RhbmNlc1xyXG4gIG9mIHRoZSBzcGVjaWZpZWQgZW50aXR5IHR5cGUuICBJZiB0aGlzIGNhbGwgaXMgbm90IG1hZGUsIGEgZGVmYXVsdCBjb25zdHJ1Y3RvciBpcyBjcmVhdGVkIGZvclxyXG4gIHRoZSBlbnRpdHkgYXMgbmVlZGVkLlxyXG4gIFRoaXMgY2FsbCBtYXkgYmUgbWFkZSBiZWZvcmUgb3IgYWZ0ZXIgdGhlIGNvcnJlc3BvbmRpbmcgRW50aXR5VHlwZSBoYXMgYmVlbiBkaXNjb3ZlcmVkIHZpYVxyXG4gIE1ldGFkYXRhIGRpc2NvdmVyeS5cclxuICA+ICAgICAgbGV0IEN1c3RvbWVyID0gZnVuY3Rpb24gKCkge1xyXG4gID4gICAgICAgICAgICAgIHRoaXMubWlzY0RhdGEgPSBcImFzZGZcIjtcclxuICA+ICAgICAgICAgIH07XHJcbiAgPiAgICAgIEN1c3RvbWVyLnByb3RvdHlwZS5kb0ZvbygpIHtcclxuICA+ICAgICAgICAgICAgICAuLi5cclxuICA+ICAgICAgICAgIH1cclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhIHByZWV4aXN0aW5nIEVudGl0eU1hbmFnZXI7XHJcbiAgPiAgICAgIGVtMS5tZXRhZGF0YVN0b3JlLnJlZ2lzdGVyRW50aXR5VHlwZUN0b3IoXCJDdXN0b21lclwiLCBDdXN0b21lcik7XHJcbiAgPiAgICAgIC8vIGFueSBxdWVyaWVzIG9yIEVudGl0eVR5cGUuY3JlYXRlIGNhbGxzIGZyb20gdGhpcyBwb2ludCBvbiB3aWxsIGNhbGwgdGhlIEN1c3RvbWVyIGNvbnN0cnVjdG9yXHJcbiAgPiAgICAgIC8vIHJlZ2lzdGVyZWQgYWJvdmUuXHJcbiAgQHBhcmFtIHN0cnVjdHVyYWxUeXBlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBFbnRpdHlUeXBlIG9yIENvbXBsZXhUeXBlLlxyXG4gIEBwYXJhbSBhQ3RvciAtIFRoZSBjb25zdHJ1Y3RvciBmb3IgdGhpcyBFbnRpdHlUeXBlIG9yIENvbXBsZXhUeXBlOyBtYXkgYmUgbnVsbCBpZiBhbGwgeW91IHdhbnQgdG8gZG8gaXMgc2V0IHRoZSBuZXh0IHBhcmFtZXRlci5cclxuICBAcGFyYW0gaW5pdEZuIC0gQSBmdW5jdGlvbiBvciB0aGUgbmFtZSBvZiBhIGZ1bmN0aW9uIG9uIHRoZSBlbnRpdHkgdGhhdCBpcyB0byBiZSBleGVjdXRlZCBpbW1lZGlhdGVseSBhZnRlciB0aGUgZW50aXR5IGhhcyBiZWVuIGNyZWF0ZWRcclxuICBhbmQgcG9wdWxhdGVkIHdpdGggYW55IGluaXRpYWwgdmFsdWVzLiBDYWxsZWQgd2l0aCAnaW5pdEZuKGVudGl0eSknXHJcbiAgQHBhcmFtIG5vVHJhY2tpbmdGbiAtIEEgZnVuY3Rpb24gdGhhdCBpcyBleGVjdXRlZCBpbW1lZGlhdGVseSBhZnRlciBhIG5vVHJhY2tpbmcgZW50aXR5IGhhcyBiZWVuIGNyZWF0ZWQgYW5kIHdob3NlIHJldHVyblxyXG4gIHZhbHVlIHdpbGwgYmUgdXNlZCBpbiBwbGFjZSBvZiB0aGUgbm9UcmFja2luZyBlbnRpdHkuXHJcbiAgKiovXHJcbiAgcmVnaXN0ZXJFbnRpdHlUeXBlQ3RvcihzdHJ1Y3R1cmFsVHlwZU5hbWU6IHN0cmluZywgYUN0b3I/OiBhbnksIGluaXRGbj86IEZ1bmN0aW9uIHwgc3RyaW5nLCBub1RyYWNraW5nRm4/OiBGdW5jdGlvbikge1xyXG4gICAgYXNzZXJ0UGFyYW0oc3RydWN0dXJhbFR5cGVOYW1lLCBcInN0cnVjdHVyYWxUeXBlTmFtZVwiKS5pc1N0cmluZygpLmNoZWNrKCk7XHJcbiAgICBhc3NlcnRQYXJhbShhQ3RvciwgXCJhQ3RvclwiKS5pc0Z1bmN0aW9uKCkuaXNPcHRpb25hbCgpLmNoZWNrKCk7XHJcbiAgICBhc3NlcnRQYXJhbShpbml0Rm4sIFwiaW5pdEZuXCIpLmlzT3B0aW9uYWwoKS5pc0Z1bmN0aW9uKCkub3IoKS5pc1N0cmluZygpLmNoZWNrKCk7XHJcbiAgICBhc3NlcnRQYXJhbShub1RyYWNraW5nRm4sIFwibm9UcmFja2luZ0ZuXCIpLmlzT3B0aW9uYWwoKS5pc0Z1bmN0aW9uKCkuY2hlY2soKTtcclxuXHJcbiAgICBsZXQgcXVhbGlmaWVkVHlwZU5hbWUgPSBnZXRRdWFsaWZpZWRUeXBlTmFtZSh0aGlzLCBzdHJ1Y3R1cmFsVHlwZU5hbWUsIGZhbHNlKTtcclxuICAgIGxldCB0eXBlTmFtZSA9IHF1YWxpZmllZFR5cGVOYW1lIHx8IHN0cnVjdHVyYWxUeXBlTmFtZTtcclxuXHJcbiAgICBpZiAoYUN0b3IpIHtcclxuICAgICAgaWYgKGFDdG9yLl8kdHlwZU5hbWUgJiYgYUN0b3IuXyR0eXBlTmFtZSAhPT0gdHlwZU5hbWUpIHtcclxuICAgICAgICAvLyBUT0RPOiB3cmFwIHRoaXMgLSBjb25zb2xlIGFuZCBlc3BlY2lhbGx5IGNvbnNvbGUud2FybiBkb2VzIG5vdCBleGlzdCBpbiBhbGwgYnJvd3NlcnMuXHJcbiAgICAgICAgY29uc29sZS53YXJuKFwiUmVnaXN0ZXJpbmcgYSBjb25zdHJ1Y3RvciBmb3IgXCIgKyB0eXBlTmFtZSArIFwiIHRoYXQgaXMgYWxyZWFkeSB1c2VkIGZvciBcIiArIGFDdG9yLl8kdHlwZU5hbWUgKyBcIi5cIik7XHJcbiAgICAgIH1cclxuICAgICAgYUN0b3IuXyR0eXBlTmFtZSA9IHR5cGVOYW1lO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuX2N0b3JSZWdpc3RyeVt0eXBlTmFtZV0gPSB7IGN0b3I6IGFDdG9yLCBpbml0Rm46IGluaXRGbiwgbm9UcmFja2luZ0ZuOiBub1RyYWNraW5nRm4gfTtcclxuICAgIGlmIChxdWFsaWZpZWRUeXBlTmFtZSkge1xyXG4gICAgICBsZXQgc3R5cGUgPSB0aGlzLl9zdHJ1Y3R1cmFsVHlwZU1hcFtxdWFsaWZpZWRUeXBlTmFtZV07XHJcbiAgICAgIHN0eXBlICYmIHN0eXBlLmdldEN0b3IodHJ1ZSk7IC8vIHRoaXMgd2lsbCBjb21wbGV0ZSB0aGUgcmVnaXN0cmF0aW9uIGlmIGF2YWlsIG5vdy5cclxuICAgIH1cclxuXHJcbiAgfVxyXG5cclxuICAvKipcclxuICBSZXR1cm5zIHdoZXRoZXIgdGhpcyBNZXRhZGF0YVN0b3JlIGNvbnRhaW5zIGFueSBtZXRhZGF0YSB5ZXQuXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBlbTEgaXMgYSBwcmVleGlzdGluZyBFbnRpdHlNYW5hZ2VyO1xyXG4gID4gICAgICBpZiAoZW0xLm1ldGFkYXRhU3RvcmUuaXNFbXB0eSgpKSB7XHJcbiAgPiAgICAgICAgICAvLyBkbyBzb21ldGhpbmcgaW50ZXJlc3RpbmdcclxuICA+ICAgICAgfVxyXG4gICoqL1xyXG4gIGlzRW1wdHkoKSB7XHJcbiAgICByZXR1cm4gY29yZS5pc0VtcHR5KHRoaXMuX3N0cnVjdHVyYWxUeXBlTWFwKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYW4gW1tFbnRpdHlUeXBlXV0gb3IgbnVsbCBnaXZlbiBpdHMgbmFtZS5cclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhIHByZWV4aXN0aW5nIEVudGl0eU1hbmFnZXJcclxuICA+ICAgICAgbGV0IG9kVHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEFzRW50aXR5VHlwZShcIk9yZGVyRGV0YWlsXCIpO1xyXG5cclxuICBvciB0byB0aHJvdyBhbiBlcnJvciBpZiB0aGUgdHlwZSBpcyBub3QgZm91bmRcclxuICA+ICAgICAgbGV0IGJhZFR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRBc0VudGl0eVR5cGUoXCJGb29cIiwgZmFsc2UpO1xyXG4gID4gICAgICAvLyBiYWRUeXBlIHdpbGwgbm90IGdldCBzZXQgYW5kIGFuIGV4Y2VwdGlvbiB3aWxsIGJlIHRocm93bi5cclxuICBAcGFyYW0gc3RydWN0dXJhbFR5cGVOYW1lIC0gRWl0aGVyIHRoZSBmdWxseSBxdWFsaWZpZWQgbmFtZSBvciBhIHNob3J0IG5hbWUgbWF5IGJlIHVzZWQuIElmIGEgc2hvcnQgbmFtZSBpcyBzcGVjaWZpZWQgYW5kIG11bHRpcGxlIHR5cGVzIHNoYXJlXHJcbiAgdGhhdCBzYW1lIHNob3J0IG5hbWUgYW4gZXhjZXB0aW9uIHdpbGwgYmUgdGhyb3duLlxyXG4gIEBwYXJhbSBva0lmTm90Rm91bmQgLSAoZGVmYXVsdD1mYWxzZSkgV2hldGhlciB0byB0aHJvdyBhbiBlcnJvciBpZiB0aGUgc3BlY2lmaWVkIEVudGl0eVR5cGUgaXMgbm90IGZvdW5kLlxyXG4gIEByZXR1cm4gVGhlIEVudGl0eVR5cGUuIENvbXBsZXhUeXBlIG9yICdudWxsJyBpZiBub3Qgbm90IGZvdW5kLlxyXG4gICoqL1xyXG4gIGdldEFzRW50aXR5VHlwZSh0eXBlTmFtZTogc3RyaW5nLCBva0lmTm90Rm91bmQ6IGJvb2xlYW4gPSBmYWxzZSkge1xyXG4gICAgY29uc3Qgc3QgPSB0aGlzLmdldFN0cnVjdHVyYWxUeXBlKHR5cGVOYW1lLCBva0lmTm90Rm91bmQpO1xyXG4gICAgaWYgKHN0IGluc3RhbmNlb2YgRW50aXR5VHlwZSkge1xyXG4gICAgICByZXR1cm4gc3QgYXMgRW50aXR5VHlwZTtcclxuICAgIH0gZWxzZSBpZiAob2tJZk5vdEZvdW5kKSB7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbGV0IG1zZyA9IGNvcmUuZm9ybWF0U3RyaW5nKFwiVW5hYmxlIHRvIGxvY2F0ZSBhbiAnRW50aXR5VHlwZScgYnkgdGhlIG5hbWU6ICclMScuIEJlIHN1cmUgdG8gZXhlY3V0ZSBhIHF1ZXJ5IG9yIGNhbGwgZmV0Y2hNZXRhZGF0YSBmaXJzdC5cIiwgdHlwZU5hbWUpO1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IobXNnKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYW4gW1tFbnRpdHlUeXBlXV0gb3IgbnVsbCBnaXZlbiBpdHMgbmFtZS5cclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhIHByZWV4aXN0aW5nIEVudGl0eU1hbmFnZXJcclxuICA+ICAgICAgbGV0IGxvY1R5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRBc0NvbXBsZXhUeXBlKFwiTG9jYXRpb25cIik7XHJcblxyXG4gIG9yIHRvIHRocm93IGFuIGVycm9yIGlmIHRoZSB0eXBlIGlzIG5vdCBmb3VuZFxyXG4gID4gICAgICBsZXQgYmFkVHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEFzQ29tcGxleFR5cGUoXCJGb29cIiwgZmFsc2UpO1xyXG4gID4gICAgICAvLyBiYWRUeXBlIHdpbGwgbm90IGdldCBzZXQgYW5kIGFuIGV4Y2VwdGlvbiB3aWxsIGJlIHRocm93bi5cclxuICBAcGFyYW0gc3RydWN0dXJhbFR5cGVOYW1lIC0gRWl0aGVyIHRoZSBmdWxseSBxdWFsaWZpZWQgbmFtZSBvciBhIHNob3J0IG5hbWUgbWF5IGJlIHVzZWQuIElmIGEgc2hvcnQgbmFtZSBpcyBzcGVjaWZpZWQgYW5kIG11bHRpcGxlIHR5cGVzIHNoYXJlXHJcbiAgdGhhdCBzYW1lIHNob3J0IG5hbWUgYW4gZXhjZXB0aW9uIHdpbGwgYmUgdGhyb3duLlxyXG4gIEBwYXJhbSBva0lmTm90Rm91bmQgLSAoZGVmYXVsdD1mYWxzZSkgV2hldGhlciB0byB0aHJvdyBhbiBlcnJvciBpZiB0aGUgc3BlY2lmaWVkIEVudGl0eVR5cGUgaXMgbm90IGZvdW5kLlxyXG4gIEByZXR1cm4gVGhlIEVudGl0eVR5cGUuIENvbXBsZXhUeXBlIG9yICdudWxsJyBpZiBub3Qgbm90IGZvdW5kLlxyXG4gICoqL1xyXG4gZ2V0QXNDb21wbGV4VHlwZSh0eXBlTmFtZTogc3RyaW5nLCBva0lmTm90Rm91bmQ6IGJvb2xlYW4gPSBmYWxzZSkge1xyXG4gIGNvbnN0IHN0ID0gdGhpcy5nZXRTdHJ1Y3R1cmFsVHlwZSh0eXBlTmFtZSwgb2tJZk5vdEZvdW5kKTtcclxuICBpZiAoc3QgaW5zdGFuY2VvZiBDb21wbGV4VHlwZSkge1xyXG4gICAgcmV0dXJuIHN0IGFzIENvbXBsZXhUeXBlO1xyXG4gIH0gZWxzZSBpZiAob2tJZk5vdEZvdW5kKSB7XHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9IGVsc2Uge1xyXG4gICAgbGV0IG1zZyA9IGNvcmUuZm9ybWF0U3RyaW5nKFwiVW5hYmxlIHRvIGxvY2F0ZSBhbiAnQ29tcGxleFR5cGUnIGJ5IHRoZSBuYW1lOiAnJTEnLiBCZSBzdXJlIHRvIGV4ZWN1dGUgYSBxdWVyeSBvciBjYWxsIGZldGNoTWV0YWRhdGEgZmlyc3QuXCIsIHR5cGVOYW1lKTtcclxuICAgIHRocm93IG5ldyBFcnJvcihtc2cpO1xyXG4gIH1cclxufVxyXG5cclxuXHJcbiAgLyoqXHJcbiAgUmV0dXJucyBhbiBbW0VudGl0eVR5cGVdXSBvciBhIFtbQ29tcGxleFR5cGVdXSBnaXZlbiBpdHMgbmFtZS5cclxuICBAZGVwcmVjYXRlZCBSZXBsYWNlZCBieSBnZXRTdHJ1Y3R1cmFsVHlwZSBidXQgLi4uIGl0IGlzIHByb2JhYmx5IG1vcmUgdXNlZnVsbCB0byBjYWxsIGVpdGhlciBnZXRBc0VudGl0eVR5cGUgb3IgZ2V0QXNDb21wbGV4VHlwZSBpbnN0ZWFkXHJcbiAgQHBhcmFtIHR5cGVOYW1lIC0gRWl0aGVyIHRoZSBmdWxseSBxdWFsaWZpZWQgbmFtZSBvciBhIHNob3J0IG5hbWUgbWF5IGJlIHVzZWQuIElmIGEgc2hvcnQgbmFtZSBpcyBzcGVjaWZpZWQgYW5kIG11bHRpcGxlIHR5cGVzIHNoYXJlXHJcbiAgdGhhdCBzYW1lIHNob3J0IG5hbWUgYW4gZXhjZXB0aW9uIHdpbGwgYmUgdGhyb3duLlxyXG4gIEBwYXJhbSBva0lmTm90Rm91bmQgLSAoZGVmYXVsdD1mYWxzZSkgV2hldGhlciB0byB0aHJvdyBhbiBlcnJvciBpZiB0aGUgc3BlY2lmaWVkIEVudGl0eVR5cGUgaXMgbm90IGZvdW5kLlxyXG4gIEByZXR1cm4gVGhlIEVudGl0eVR5cGUuIENvbXBsZXhUeXBlIG9yICdudWxsJyBpZiBub3Qgbm90IGZvdW5kLlxyXG4gICoqL1xyXG4gIGdldEVudGl0eVR5cGUodHlwZU5hbWU6IHN0cmluZywgb2tJZk5vdEZvdW5kOiBib29sZWFuID0gZmFsc2UpIHtcclxuICAgIHJldHVybiB0aGlzLmdldFN0cnVjdHVyYWxUeXBlKHR5cGVOYW1lLCBva0lmTm90Rm91bmQpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgUmV0dXJucyBhbiBbW0VudGl0eVR5cGVdXSBvciBhIFtbQ29tcGxleFR5cGVdXSBnaXZlbiBpdHMgbmFtZS5cclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhIHByZWV4aXN0aW5nIEVudGl0eU1hbmFnZXJcclxuICA+ICAgICAgbGV0IG9kVHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldFN0cnVjdHVyYWxUeXBlKFwiT3JkZXJEZXRhaWxcIik7XHJcblxyXG4gIG9yIHRvIHRocm93IGFuIGVycm9yIGlmIHRoZSB0eXBlIGlzIG5vdCBmb3VuZFxyXG4gID4gICAgICBsZXQgYmFkVHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldFN0cnVjdHVyYWxUeXBlKFwiRm9vXCIsIGZhbHNlKTtcclxuICA+ICAgICAgLy8gYmFkVHlwZSB3aWxsIG5vdCBnZXQgc2V0IGFuZCBhbiBleGNlcHRpb24gd2lsbCBiZSB0aHJvd24uXHJcbiAgQGRlcHJlY2F0ZWQgUHJlZmVyYWJseSB1c2UgZWl0aGVyIGdldEFzRW50aXR5VHlwZSBvciBnZXRBc0NvbXBsZXhUeXBlLiAgR2V0XHJcbiAgQHBhcmFtIHR5cGVOYW1lIC0gRWl0aGVyIHRoZSBmdWxseSBxdWFsaWZpZWQgbmFtZSBvciBhIHNob3J0IG5hbWUgbWF5IGJlIHVzZWQuIElmIGEgc2hvcnQgbmFtZSBpcyBzcGVjaWZpZWQgYW5kIG11bHRpcGxlIHR5cGVzIHNoYXJlXHJcbiAgdGhhdCBzYW1lIHNob3J0IG5hbWUgYW4gZXhjZXB0aW9uIHdpbGwgYmUgdGhyb3duLlxyXG4gIEBwYXJhbSBva0lmTm90Rm91bmQgLSAoZGVmYXVsdD1mYWxzZSkgV2hldGhlciB0byB0aHJvdyBhbiBlcnJvciBpZiB0aGUgc3BlY2lmaWVkIEVudGl0eVR5cGUgaXMgbm90IGZvdW5kLlxyXG4gIEByZXR1cm4gVGhlIEVudGl0eVR5cGUuIENvbXBsZXhUeXBlIG9yICdudWxsJyBpZiBub3Qgbm90IGZvdW5kLlxyXG4gICoqL1xyXG4gIGdldFN0cnVjdHVyYWxUeXBlKHR5cGVOYW1lOiBzdHJpbmcsIG9rSWZOb3RGb3VuZDogYm9vbGVhbiA9IGZhbHNlKSB7XHJcbiAgICBhc3NlcnRQYXJhbSh0eXBlTmFtZSwgXCJ0eXBlTmFtZVwiKS5pc1N0cmluZygpLmNoZWNrKCk7XHJcbiAgICBhc3NlcnRQYXJhbShva0lmTm90Rm91bmQsIFwib2tJZk5vdEZvdW5kXCIpLmlzQm9vbGVhbigpLmlzT3B0aW9uYWwoKS5jaGVjayhmYWxzZSk7XHJcbiAgICByZXR1cm4gdGhpcy5fZ2V0U3RydWN0dXJhbFR5cGUodHlwZU5hbWUsIG9rSWZOb3RGb3VuZCk7XHJcbiAgfVxyXG5cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfZ2V0U3RydWN0dXJhbFR5cGUodHlwZU5hbWU6IHN0cmluZywgb2tJZk5vdEZvdW5kOiBib29sZWFuID0gZmFsc2UpIHtcclxuICAgIGxldCBxdWFsVHlwZU5hbWUgPSBnZXRRdWFsaWZpZWRUeXBlTmFtZSh0aGlzLCB0eXBlTmFtZSwgZmFsc2UpO1xyXG4gICAgbGV0IHR5cGUgPSB0aGlzLl9zdHJ1Y3R1cmFsVHlwZU1hcFtxdWFsVHlwZU5hbWVdO1xyXG4gICAgaWYgKCF0eXBlKSB7XHJcbiAgICAgIGlmIChva0lmTm90Rm91bmQpIHJldHVybiBudWxsO1xyXG4gICAgICBsZXQgbXNnID0gY29yZS5mb3JtYXRTdHJpbmcoXCJVbmFibGUgdG8gbG9jYXRlIGEgJ1R5cGUnIGJ5IHRoZSBuYW1lOiAnJTEnLiBCZSBzdXJlIHRvIGV4ZWN1dGUgYSBxdWVyeSBvciBjYWxsIGZldGNoTWV0YWRhdGEgZmlyc3QuXCIsIHR5cGVOYW1lKTtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKG1zZyk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdHlwZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYW4gYXJyYXkgY29udGFpbmluZyBhbGwgb2YgdGhlIFtbRW50aXR5VHlwZV1dcyBvciBbW0NvbXBsZXhUeXBlXV1zIGluIHRoaXMgTWV0YWRhdGFTdG9yZS5cclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhIHByZWV4aXN0aW5nIEVudGl0eU1hbmFnZXJcclxuICA+ICAgICAgbGV0IGFsbFR5cGVzID0gZW0xLm1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZXMoKTtcclxuICAqKi9cclxuICBnZXRFbnRpdHlUeXBlcygpIHtcclxuICAgIHJldHVybiBnZXRUeXBlc0Zyb21NYXAodGhpcy5fc3RydWN0dXJhbFR5cGVNYXApO1xyXG4gIH1cclxuXHJcbiAgZ2V0SW5jb21wbGV0ZU5hdmlnYXRpb25Qcm9wZXJ0aWVzKCkge1xyXG4gICAgcmV0dXJuIGNvcmUub2JqZWN0TWFwKHRoaXMuX2luY29tcGxldGVUeXBlTWFwLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xyXG4gICAgICByZXR1cm4gdmFsdWU7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBmdWxseSBxdWFsaWZpZWQgZW50aXR5VHlwZU5hbWUgZm9yIGEgc3BlY2lmaWVkIHJlc291cmNlIG5hbWUuICBUaGUgcmV2ZXJzZSBvZiB0aGlzIG9wZXJhdGlvblxyXG4gIGNhbiBiZSBvYnRhaW5lZCB2aWEgdGhlICBbW0VudGl0eVR5cGUuZGVmYXVsdFJlc291cmNlTmFtZV1dIHByb3BlcnR5XHJcbiAgKiovXHJcbiAgZ2V0RW50aXR5VHlwZU5hbWVGb3JSZXNvdXJjZU5hbWUocmVzb3VyY2VOYW1lOiBzdHJpbmcpIHtcclxuICAgIGFzc2VydFBhcmFtKHJlc291cmNlTmFtZSwgXCJyZXNvdXJjZU5hbWVcIikuaXNTdHJpbmcoKS5jaGVjaygpO1xyXG4gICAgcmV0dXJuIHRoaXMuX3Jlc291cmNlRW50aXR5VHlwZU1hcFtyZXNvdXJjZU5hbWVdO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgQXNzb2NpYXRlcyBhIHJlc291cmNlTmFtZSB3aXRoIGFuIGVudGl0eVR5cGUuXHJcblxyXG4gIFRoaXMgbWV0aG9kIGlzIG9ubHkgbmVlZGVkIGluIHRob3NlIGNhc2VzIHdoZXJlIG11bHRpcGxlIHJlc291cmNlcyByZXR1cm4gdGhlIHNhbWVcclxuICBlbnRpdHlUeXBlLiAgSW4gdGhpcyBjYXNlIE1ldGFkYXRhIGRpc2NvdmVyeSB3aWxsIG9ubHkgZGV0ZXJtaW5lIGEgc2luZ2xlIHJlc291cmNlIG5hbWUgZm9yXHJcbiAgZWFjaCBlbnRpdHlUeXBlLlxyXG4gIEBwYXJhbSByZXNvdXJjZU5hbWUgLSBUaGUgcmVzb3VyY2UgbmFtZVxyXG4gIEBwYXJhbSBlbnRpdHlUeXBlT3JOYW1lIC0gSWYgcGFzc2luZyBhIHN0cmluZyBlaXRoZXIgdGhlIGZ1bGx5IHF1YWxpZmllZCBuYW1lIG9yIGEgc2hvcnQgbmFtZSBtYXkgYmUgdXNlZC4gSWYgYSBzaG9ydCBuYW1lIGlzIHNwZWNpZmllZCBhbmQgbXVsdGlwbGUgdHlwZXMgc2hhcmVcclxuICB0aGF0IHNhbWUgc2hvcnQgbmFtZSBhbiBleGNlcHRpb24gd2lsbCBiZSB0aHJvd24uIElmIHRoZSBlbnRpdHlUeXBlIGhhcyBub3QgeWV0IGJlZW4gZGlzY292ZXJlZCB0aGVuIGEgZnVsbHkgcXVhbGlmaWVkIG5hbWUgbXVzdCBiZSB1c2VkLlxyXG4gICoqL1xyXG4gIHNldEVudGl0eVR5cGVGb3JSZXNvdXJjZU5hbWUocmVzb3VyY2VOYW1lOiBzdHJpbmcsIGVudGl0eVR5cGVPck5hbWU6IEVudGl0eVR5cGUgfCBzdHJpbmcpIHtcclxuICAgIGFzc2VydFBhcmFtKHJlc291cmNlTmFtZSwgXCJyZXNvdXJjZU5hbWVcIikuaXNTdHJpbmcoKS5jaGVjaygpO1xyXG4gICAgYXNzZXJ0UGFyYW0oZW50aXR5VHlwZU9yTmFtZSwgXCJlbnRpdHlUeXBlT3JOYW1lXCIpLmlzSW5zdGFuY2VPZihFbnRpdHlUeXBlKS5vcigpLmlzU3RyaW5nKCkuY2hlY2soKTtcclxuXHJcbiAgICBsZXQgZW50aXR5VHlwZU5hbWU6IHN0cmluZztcclxuICAgIGlmIChlbnRpdHlUeXBlT3JOYW1lIGluc3RhbmNlb2YgRW50aXR5VHlwZSkge1xyXG4gICAgICBlbnRpdHlUeXBlTmFtZSA9IGVudGl0eVR5cGVPck5hbWUubmFtZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGVudGl0eVR5cGVOYW1lID0gZ2V0UXVhbGlmaWVkVHlwZU5hbWUodGhpcywgZW50aXR5VHlwZU9yTmFtZSwgdHJ1ZSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5fcmVzb3VyY2VFbnRpdHlUeXBlTWFwW3Jlc291cmNlTmFtZV0gPSBlbnRpdHlUeXBlTmFtZTtcclxuICAgIGxldCBlbnRpdHlUeXBlID0gdGhpcy5fZ2V0U3RydWN0dXJhbFR5cGUoZW50aXR5VHlwZU5hbWUsIHRydWUpO1xyXG4gICAgaWYgKGVudGl0eVR5cGUgJiYgZW50aXR5VHlwZSBpbnN0YW5jZW9mIEVudGl0eVR5cGUgJiYgIWVudGl0eVR5cGUuZGVmYXVsdFJlc291cmNlTmFtZSkge1xyXG4gICAgICBlbnRpdHlUeXBlLmRlZmF1bHRSZXNvdXJjZU5hbWUgPSByZXNvdXJjZU5hbWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKiogX19EZXYgT25seV9fIC0gZm9yIHVzZSB3aGVuIGNyZWF0aW5nIGEgbmV3IE1ldGFkYXRhUGFyc2VyQWRhcHRlciAgKi9cclxuICBzdGF0aWMgcGFyc2VUeXBlTmFtZShlbnRpdHlUeXBlTmFtZTogc3RyaW5nKSB7XHJcbiAgICAvLyBUT0RPOiByZW1vdmVkIFxyXG4gICAgLy8gaWYgKCFlbnRpdHlUeXBlTmFtZSkge1xyXG4gICAgLy8gICByZXR1cm4gbnVsbDtcclxuICAgIC8vIH1cclxuXHJcbiAgICBsZXQgdHlwZVBhcnRzID0gZW50aXR5VHlwZU5hbWUuc3BsaXQoXCI6I1wiKTtcclxuICAgIGlmICh0eXBlUGFydHMubGVuZ3RoID4gMSkge1xyXG4gICAgICByZXR1cm4gTWV0YWRhdGFTdG9yZS5tYWtlVHlwZUhhc2godHlwZVBhcnRzWzBdLCB0eXBlUGFydHNbMV0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChjb3JlLnN0cmluZ1N0YXJ0c1dpdGgoZW50aXR5VHlwZU5hbWUsIE1ldGFkYXRhU3RvcmUuQU5PTlRZUEVfUFJFRklYKSkge1xyXG4gICAgICBsZXQgdHlwZUhhc2ggPSBNZXRhZGF0YVN0b3JlLm1ha2VUeXBlSGFzaChlbnRpdHlUeXBlTmFtZSk7XHJcbiAgICAgICh0eXBlSGFzaCBhcyBhbnkpLmlzQW5vbnltb3VzID0gdHJ1ZTtcclxuICAgICAgcmV0dXJuIHR5cGVIYXNoO1xyXG4gICAgfVxyXG4gICAgbGV0IGVudGl0eVR5cGVOYW1lTm9Bc3NlbWJseSA9IGVudGl0eVR5cGVOYW1lLnNwbGl0KFwiLFwiKVswXTtcclxuICAgIHR5cGVQYXJ0cyA9IGVudGl0eVR5cGVOYW1lTm9Bc3NlbWJseS5zcGxpdChcIi5cIik7XHJcbiAgICBpZiAodHlwZVBhcnRzLmxlbmd0aCA+IDEpIHtcclxuICAgICAgbGV0IHNob3J0TmFtZSA9IHR5cGVQYXJ0c1t0eXBlUGFydHMubGVuZ3RoIC0gMV07XHJcbiAgICAgIGxldCBuYW1lc3BhY2VQYXJ0cyA9IHR5cGVQYXJ0cy5zbGljZSgwLCB0eXBlUGFydHMubGVuZ3RoIC0gMSk7XHJcbiAgICAgIGxldCBucyA9IG5hbWVzcGFjZVBhcnRzLmpvaW4oXCIuXCIpO1xyXG4gICAgICByZXR1cm4gTWV0YWRhdGFTdG9yZS5tYWtlVHlwZUhhc2goc2hvcnROYW1lLCBucyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gTWV0YWRhdGFTdG9yZS5tYWtlVHlwZUhhc2goZW50aXR5VHlwZU5hbWUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqIF9fRGV2IE9ubHlfXyAtIGZvciB1c2Ugd2hlbiBjcmVhdGluZyBhIG5ldyBNZXRhZGF0YVBhcnNlckFkYXB0ZXIgICovXHJcbiAgc3RhdGljIG1ha2VUeXBlSGFzaChzaG9ydE5hbWU6IHN0cmluZywgbnM/OiBzdHJpbmcpIHtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHNob3J0VHlwZU5hbWU6IHNob3J0TmFtZSxcclxuICAgICAgbmFtZXNwYWNlOiBucyxcclxuICAgICAgdHlwZU5hbWU6IHF1YWxpZnlUeXBlTmFtZShzaG9ydE5hbWUsIG5zKVxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIC8vIHByb3RlY3RlZCBtZXRob2RzXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2NoZWNrRW50aXR5VHlwZShlbnRpdHk6IEVudGl0eSkge1xyXG4gICAgaWYgKGVudGl0eS5lbnRpdHlUeXBlKSByZXR1cm47XHJcbiAgICBsZXQgdHlwZU5hbWUgPSBlbnRpdHkucHJvdG90eXBlLl8kdHlwZU5hbWU7XHJcbiAgICBpZiAoIXR5cGVOYW1lKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIlRoaXMgZW50aXR5IGhhcyBub3QgYmVlbiByZWdpc3RlcmVkLiBTZWUgdGhlIE1ldGFkYXRhU3RvcmUucmVnaXN0ZXJFbnRpdHlUeXBlQ3RvciBtZXRob2RcIik7XHJcbiAgICB9XHJcbiAgICAvLyB3ZSBrbm93IHRoYXQgaXQgaXMgYW4gRW50aXR5VHlwZSAoIGFzIG9wcG9zZWQgdG8gYSBDb21wbGV4VHlwZSlcclxuICAgIGxldCBlbnRpdHlUeXBlID0gdGhpcy5fZ2V0U3RydWN0dXJhbFR5cGUodHlwZU5hbWUpIGFzIEVudGl0eVR5cGU7XHJcbiAgICBpZiAoZW50aXR5VHlwZSkge1xyXG4gICAgICBlbnRpdHkuZW50aXR5VHlwZSA9IGVudGl0eVR5cGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuXHJcbn1cclxuTWV0YWRhdGFTdG9yZS5wcm90b3R5cGUuXyR0eXBlTmFtZSA9IFwiTWV0YWRhdGFTdG9yZVwiO1xyXG5cclxuQnJlZXplRXZlbnQuYnViYmxlRXZlbnQoTWV0YWRhdGFTdG9yZS5wcm90b3R5cGUpO1xyXG5cclxuZnVuY3Rpb24gZ2V0VHlwZXNGcm9tTWFwKHR5cGVNYXA6IElTdHJ1Y3R1cmFsVHlwZU1hcCkge1xyXG4gIGxldCB0eXBlczogKFN0cnVjdHVyYWxUeXBlKVtdID0gW107XHJcbiAgZm9yIChsZXQga2V5IGluIHR5cGVNYXApIHtcclxuICAgIGxldCB2YWx1ZSA9IHR5cGVNYXBba2V5XTtcclxuICAgIC8vIHNraXAgJ3Nob3J0TmFtZScgZW50cmllc1xyXG4gICAgaWYgKGtleSA9PT0gdmFsdWUubmFtZSkge1xyXG4gICAgICB0eXBlcy5wdXNoKHR5cGVNYXBba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG4gIHJldHVybiB0eXBlcztcclxufVxyXG5cclxuZnVuY3Rpb24gc3RydWN0dXJhbFR5cGVGcm9tSnNvbihtZXRhZGF0YVN0b3JlOiBNZXRhZGF0YVN0b3JlLCBqc29uOiBhbnksIGFsbG93TWVyZ2U6IGJvb2xlYW4pIHtcclxuICBsZXQgdHlwZU5hbWUgPSBxdWFsaWZ5VHlwZU5hbWUoanNvbi5zaG9ydE5hbWUsIGpzb24ubmFtZXNwYWNlKTtcclxuICBsZXQgc3R5cGUgPSBtZXRhZGF0YVN0b3JlLl9nZXRTdHJ1Y3R1cmFsVHlwZSh0eXBlTmFtZSwgdHJ1ZSk7XHJcbiAgaWYgKHN0eXBlKSB7XHJcbiAgICBpZiAoYWxsb3dNZXJnZSkge1xyXG4gICAgICByZXR1cm4gbWVyZ2VTdHJ1Y3R1cmFsVHlwZShzdHlwZSwganNvbik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBhbGxvdyBpdCBidXQgZG9uJ3QgcmVwbGFjZSBhbnl0aGluZy5cclxuICAgICAgcmV0dXJuIHN0eXBlO1xyXG4gICAgfVxyXG4gIH1cclxuICBsZXQgY29uZmlnID0ge1xyXG4gICAgc2hvcnROYW1lOiBqc29uLnNob3J0TmFtZSxcclxuICAgIG5hbWVzcGFjZToganNvbi5uYW1lc3BhY2UsXHJcbiAgICBpc0Fic3RyYWN0OiBqc29uLmlzQWJzdHJhY3QsXHJcbiAgICBhdXRvR2VuZXJhdGVkS2V5VHlwZTogQXV0b0dlbmVyYXRlZEtleVR5cGUuZnJvbU5hbWUoanNvbi5hdXRvR2VuZXJhdGVkS2V5VHlwZSksXHJcbiAgICBkZWZhdWx0UmVzb3VyY2VOYW1lOiBqc29uLmRlZmF1bHRSZXNvdXJjZU5hbWUsXHJcbiAgICBjdXN0b206IGpzb24uY3VzdG9tXHJcbiAgfTtcclxuXHJcbiAgc3R5cGUgPSBqc29uLmlzQ29tcGxleFR5cGUgPyBuZXcgQ29tcGxleFR5cGUoY29uZmlnKSA6IG5ldyBFbnRpdHlUeXBlKGNvbmZpZyk7XHJcblxyXG4gIC8vIGJhc2VUeXBlIG1heSBub3QgaGF2ZSBiZWVuIGltcG9ydGVkIHlldCBzbyB3ZSBuZWVkIHRvIGRlZmVyIGhhbmRsaW5nIHRoaXMgdHlwZSB1bnRpbCBsYXRlci5cclxuICBpZiAoanNvbi5iYXNlVHlwZU5hbWUgJiYgc3R5cGUgaW5zdGFuY2VvZiBFbnRpdHlUeXBlKSB7XHJcbiAgICBzdHlwZS5iYXNlVHlwZU5hbWUgPSBqc29uLmJhc2VUeXBlTmFtZTtcclxuICAgIGxldCBiYXNlRW50aXR5VHlwZSA9IG1ldGFkYXRhU3RvcmUuX2dldFN0cnVjdHVyYWxUeXBlKGpzb24uYmFzZVR5cGVOYW1lLCB0cnVlKTtcclxuICAgIGlmIChiYXNlRW50aXR5VHlwZSkge1xyXG4gICAgICBjb21wbGV0ZVN0cnVjdHVyYWxUeXBlRnJvbUpzb24obWV0YWRhdGFTdG9yZSwganNvbiwgc3R5cGUpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgY29yZS5nZXRBcnJheShtZXRhZGF0YVN0b3JlLl9kZWZlcnJlZFR5cGVzLCBqc29uLmJhc2VUeXBlTmFtZSkucHVzaCh7IGpzb246IGpzb24sIHN0eXBlOiBzdHlwZSB9KTtcclxuXHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIGNvbXBsZXRlU3RydWN0dXJhbFR5cGVGcm9tSnNvbihtZXRhZGF0YVN0b3JlLCBqc29uLCBzdHlwZSk7XHJcbiAgfVxyXG5cclxuICAvLyBzdHlwZSBtYXkgb3IgbWF5IG5vdCBoYXZlIGJlZW4gYWRkZWQgdG8gdGhlIG1ldGFkYXRhU3RvcmUgYXQgdGhpcyBwb2ludC5cclxuICByZXR1cm4gc3R5cGU7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIG1lcmdlU3RydWN0dXJhbFR5cGUoc3R5cGU6IFN0cnVjdHVyYWxUeXBlLCBqc29uOiBhbnkpIHtcclxuICBpZiAoanNvbi5jdXN0b20pIHtcclxuICAgIHN0eXBlLmN1c3RvbSA9IGpzb24uY3VzdG9tO1xyXG4gIH1cclxuXHJcbiAgbWVyZ2VQcm9wcyhzdHlwZSwganNvbi5kYXRhUHJvcGVydGllcyk7XHJcbiAgbWVyZ2VQcm9wcyhzdHlwZSwganNvbi5uYXZpZ2F0aW9uUHJvcGVydGllcyk7XHJcbiAgcmV0dXJuIHN0eXBlO1xyXG59XHJcblxyXG5mdW5jdGlvbiBtZXJnZVByb3BzKHN0eXBlOiBTdHJ1Y3R1cmFsVHlwZSwganNvblByb3BzOiBhbnlbXSkge1xyXG4gIGlmICghanNvblByb3BzKSByZXR1cm47XHJcbiAganNvblByb3BzLmZvckVhY2goKGpzb25Qcm9wKSA9PiB7XHJcbiAgICBsZXQgcHJvcE5hbWUgPSBqc29uUHJvcC5uYW1lO1xyXG4gICAgaWYgKCFwcm9wTmFtZSkge1xyXG4gICAgICBpZiAoanNvblByb3AubmFtZU9uU2VydmVyKSB7XHJcbiAgICAgICAgcHJvcE5hbWUgPSBzdHlwZS5tZXRhZGF0YVN0b3JlLm5hbWluZ0NvbnZlbnRpb24uc2VydmVyUHJvcGVydHlOYW1lVG9DbGllbnQoanNvblByb3AubmFtZU9uU2VydmVyLCB7fSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gYmFja3NsYXNoLXF1b3RlIHdvcmtzIGFyb3VuZCBjb21waWxlciBidWdcclxuICAgICAgICBjb25zdCBtc2cgPSBcIlVuYWJsZSB0byBjb21wbGV0ZSBcXCdpbXBvcnRNZXRhZGF0YVxcJyAtIGNhbm5vdCBsb2NhdGUgYSBcXCduYW1lXFwnIG9yIFxcJ25hbWVPblNlcnZlclxcJyBmb3Igb25lIG9mIHRoZSBpbXBvcnRlZCBwcm9wZXJ0eSBub2Rlc1wiO1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihtc2cpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiAoanNvblByb3AuY3VzdG9tKSB7XHJcbiAgICAgIGxldCBwcm9wID0gc3R5cGUuZ2V0UHJvcGVydHkocHJvcE5hbWUsIHRydWUpO1xyXG4gICAgICBwcm9wIS5jdXN0b20gPSBqc29uUHJvcC5jdXN0b207XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNvbXBsZXRlU3RydWN0dXJhbFR5cGVGcm9tSnNvbihtZXRhZGF0YVN0b3JlOiBNZXRhZGF0YVN0b3JlLCBqc29uOiBhbnksIHN0eXBlOiBhbnkpIHtcclxuXHJcbiAgLy8gdmFsaWRhdG9ycyBmcm9tIGJhc2VUeXBlIHdvcmsgYmVjYXVzZSB2YWxpZGF0aW9uIHdhbGtzIHRocnUgYmFzZSB0eXBlc1xyXG4gIC8vIHNvIG5vIG5lZWQgdG8gY29weSBkb3duLlxyXG4gIGlmIChqc29uLnZhbGlkYXRvcnMpIHtcclxuICAgIHN0eXBlLnZhbGlkYXRvcnMgPSBqc29uLnZhbGlkYXRvcnMubWFwKFZhbGlkYXRvci5mcm9tSlNPTik7XHJcbiAgfVxyXG5cclxuICBqc29uLmRhdGFQcm9wZXJ0aWVzLmZvckVhY2goZnVuY3Rpb24gKGRwOiBPYmplY3QpIHtcclxuICAgIHN0eXBlLl9hZGRQcm9wZXJ0eUNvcmUoRGF0YVByb3BlcnR5LmZyb21KU09OKGRwKSk7XHJcbiAgfSk7XHJcblxyXG5cclxuICBsZXQgaXNFbnRpdHlUeXBlID0gIWpzb24uaXNDb21wbGV4VHlwZTtcclxuICBpZiAoaXNFbnRpdHlUeXBlKSB7XHJcbiAgICAvL25vaW5zcGVjdGlvbiBKU0hpbnRcclxuICAgIGpzb24ubmF2aWdhdGlvblByb3BlcnRpZXMgJiYganNvbi5uYXZpZ2F0aW9uUHJvcGVydGllcy5mb3JFYWNoKGZ1bmN0aW9uIChucDogT2JqZWN0KSB7XHJcbiAgICAgIHN0eXBlLl9hZGRQcm9wZXJ0eUNvcmUoTmF2aWdhdGlvblByb3BlcnR5LmZyb21KU09OKG5wKSk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIG1ldGFkYXRhU3RvcmUuYWRkRW50aXR5VHlwZShzdHlwZSk7XHJcblxyXG4gIGxldCBkZWZlcnJlZFR5cGVzID0gbWV0YWRhdGFTdG9yZS5fZGVmZXJyZWRUeXBlcztcclxuICBsZXQgZGVmZXJyYWxzID0gZGVmZXJyZWRUeXBlc1tzdHlwZS5uYW1lXTtcclxuICBpZiAoZGVmZXJyYWxzKSB7XHJcbiAgICBkZWZlcnJhbHMuZm9yRWFjaChmdW5jdGlvbiAoZDogYW55KSB7XHJcbiAgICAgIGNvbXBsZXRlU3RydWN0dXJhbFR5cGVGcm9tSnNvbihtZXRhZGF0YVN0b3JlLCBkLmpzb24sIGQuc3R5cGUpO1xyXG4gICAgfSk7XHJcbiAgICBkZWxldGUgZGVmZXJyZWRUeXBlc1tzdHlwZS5uYW1lXTtcclxuICB9XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGdldFF1YWxpZmllZFR5cGVOYW1lKG1ldGFkYXRhU3RvcmU6IE1ldGFkYXRhU3RvcmUsIHN0cnVjdFR5cGVOYW1lOiBzdHJpbmcsIHRocm93SWZOb3RGb3VuZD86IGJvb2xlYW4pIHtcclxuICBpZiAoaXNRdWFsaWZpZWRUeXBlTmFtZShzdHJ1Y3RUeXBlTmFtZSkpIHJldHVybiBzdHJ1Y3RUeXBlTmFtZTtcclxuICBsZXQgcmVzdWx0ID0gbWV0YWRhdGFTdG9yZS5fc2hvcnROYW1lTWFwW3N0cnVjdFR5cGVOYW1lXTtcclxuICBpZiAoIXJlc3VsdCAmJiB0aHJvd0lmTm90Rm91bmQpIHtcclxuICAgIHRocm93IG5ldyBFcnJvcihcIlVuYWJsZSB0byBsb2NhdGUgJ2VudGl0eVR5cGVOYW1lJyBvZjogXCIgKyBzdHJ1Y3RUeXBlTmFtZSk7XHJcbiAgfVxyXG4gIHJldHVybiByZXN1bHQ7XHJcbn1cclxuXHJcbi8qKiBDb25maWd1cmF0aW9uIGluZm8gdG8gYmUgcGFzc2VkIHRvIHRoZSBbW0VudGl0eVR5cGVdXSBjb25zdHJ1Y3RvciAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIEVudGl0eVR5cGVDb25maWcge1xyXG4gIHNob3J0TmFtZT86IHN0cmluZztcclxuICBuYW1lc3BhY2U/OiBzdHJpbmc7XHJcbiAgYmFzZVR5cGVOYW1lPzogc3RyaW5nO1xyXG4gIGlzQWJzdHJhY3Q/OiBib29sZWFuO1xyXG4gIGF1dG9HZW5lcmF0ZWRLZXlUeXBlPzogQXV0b0dlbmVyYXRlZEtleVR5cGU7XHJcbiAgZGVmYXVsdFJlc291cmNlTmFtZT86IHN0cmluZztcclxuICBkYXRhUHJvcGVydGllcz86IERhdGFQcm9wZXJ0eVtdIHwgT2JqZWN0W10gfCBPYmplY3Q7ICAvLyBUT0RPOiBzZWUgaWYgd2UgY2FuJ3QgcXVhbGlmeSBPYmplY3RbXSBhIGxpdHRsZSBiZXR0ZXIuXHJcbiAgbmF2aWdhdGlvblByb3BlcnRpZXM/OiBOYXZpZ2F0aW9uUHJvcGVydHlbXSB8IE9iamVjdFtdIHwgT2JqZWN0O1xyXG4gIHNlcmlhbGl6ZXJGbj86IChwcm9wOiBFbnRpdHlQcm9wZXJ0eSwgdmFsOiBhbnkpID0+IGFueTtcclxuICBjdXN0b20/OiBPYmplY3Q7XHJcbn1cclxuXHJcbi8qKiBDb25maWd1cmF0aW9uIGluZm8gdG8gYmUgcGFzc2VkIHRvIHRoZSBbW0VudGl0eVR5cGUuc2V0UHJvcGVydGllc11dIG1ldGhvZCAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIEVudGl0eVR5cGVTZXRDb25maWcge1xyXG4gIGF1dG9HZW5lcmF0ZWRLZXlUeXBlPzogQXV0b0dlbmVyYXRlZEtleVR5cGU7XHJcbiAgZGVmYXVsdFJlc291cmNlTmFtZT86IHN0cmluZztcclxuICBzZXJpYWxpemVyRm4/OiAocHJvcDogRW50aXR5UHJvcGVydHksIHZhbDogYW55KSA9PiBhbnk7XHJcbiAgY3VzdG9tPzogT2JqZWN0O1xyXG59XHJcblxyXG4vKiogQ29udGFpbmVyIGZvciBhbGwgb2YgdGhlIG1ldGFkYXRhIGFib3V0IGEgc3BlY2lmaWMgdHlwZSBvZiBFbnRpdHkuXHJcbioqL1xyXG5leHBvcnQgY2xhc3MgRW50aXR5VHlwZSB7XHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgXyR0eXBlTmFtZTogc3RyaW5nOyAvLyBvbiBwcm90b1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIHN0YXRpYyBfX25leHRBbm9uSXggPSAwO1xyXG4gIC8qKiBBbHdheXMgZmFsc2UgZm9yIGFuIEVudGl0eVR5cGUuICoqL1xyXG4gIGlzQ29tcGxleFR5cGUgPSBmYWxzZTtcclxuICAvKiogVGhlIFtbTWV0YWRhdGFTdG9yZV1dIHRoYXQgY29udGFpbnMgdGhpcyBFbnRpdHlUeXBlLiBfX1JlYWQgT25seV9fICoqL1xyXG4gIG1ldGFkYXRhU3RvcmU6IE1ldGFkYXRhU3RvcmU7XHJcbiAgLyoqIFRoZSBEYXRhUHJvcGVydGllcyAoc2VlIFtbRGF0YVByb3BlcnR5XV0gYXNzb2NpYXRlZCB3aXRoIHRoaXMgRW50aXR5VHlwZS4gX19SZWFkIE9ubHlfXyAgKiovXHJcbiAgZGF0YVByb3BlcnRpZXM6IERhdGFQcm9wZXJ0eVtdO1xyXG4gIC8qKiAgVGhlIE5hdmlnYXRpb25Qcm9wZXJ0aWVzIChzZWUgW1tOYXZpZ2F0aW9uUHJvcGVydHldXSBhc3NvY2lhdGVkIHdpdGggdGhpcyBFbnRpdHlUeXBlLiBfX1JlYWQgT25seV9fICAqKi9cclxuICBuYXZpZ2F0aW9uUHJvcGVydGllczogTmF2aWdhdGlvblByb3BlcnR5W107XHJcbiAgLyoqXHJcbiAgVGhlIERhdGFQcm9wZXJ0aWVzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEVudGl0eVR5cGUgdGhhdCBtYWtlIHVwIGl0J3MgW1tFbnRpdHlLZXldXS4gX19SZWFkIE9ubHlfXyAqKi9cclxuICBrZXlQcm9wZXJ0aWVzOiBEYXRhUHJvcGVydHlbXTtcclxuICAvKiogVGhlIERhdGFQcm9wZXJ0aWVzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEVudGl0eVR5cGUgdGhhdCBhcmUgZm9yZWlnbiBrZXkgcHJvcGVydGllcy4gX19SZWFkIE9ubHlfXyAqKi9cclxuICBmb3JlaWduS2V5UHJvcGVydGllczogRGF0YVByb3BlcnR5W107XHJcbiAgaW52ZXJzZUZvcmVpZ25LZXlQcm9wZXJ0aWVzOiBEYXRhUHJvcGVydHlbXTtcclxuICAvKiogIFRoZSBEYXRhUHJvcGVydGllcyBhc3NvY2lhdGVkIHdpdGggdGhpcyBFbnRpdHlUeXBlIHRoYXQgYXJlIGNvbmN1cnJlbmN5IHByb3BlcnRpZXMuIF9fUmVhZCBPbmx5X18gKiovXHJcbiAgY29uY3VycmVuY3lQcm9wZXJ0aWVzOiBEYXRhUHJvcGVydHlbXTtcclxuICAvKiogVGhlIERhdGFQcm9wZXJ0aWVzIGZvciB0aGlzIEVudGl0eVR5cGUgdGhhdCBjb250YWluIGluc3RhbmNlcyBvZiBhIFtbQ29tcGxleFR5cGVdXS4gX19SZWFkIE9ubHlfXyAgICoqL1xyXG4gIGNvbXBsZXhQcm9wZXJ0aWVzOiBEYXRhUHJvcGVydHlbXTtcclxuICAvKiogVGhlIERhdGFQcm9wZXJ0aWVzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEVudGl0eVR5cGUgdGhhdCBhcmUgbm90IG1hcHBlZCB0byBhbnkgYmFja2VuZCBkYXRhc3RvcmUuIFRoZXNlIGFyZSBlZmZlY3RpdmVseSBmcmVlIHN0YW5kaW5nXHJcbiAgcHJvcGVydGllcy4gX19SZWFkIE9ubHlfXyAqKi9cclxuICB1bm1hcHBlZFByb3BlcnRpZXM6IERhdGFQcm9wZXJ0eVtdO1xyXG5cclxuICAvKiogVGhlIGZ1bGx5IHF1YWxpZmllZCBuYW1lIG9mIHRoaXMgRW50aXR5VHlwZS4gX19SZWFkIE9ubHlfXyAgKiovXHJcbiAgbmFtZTogc3RyaW5nO1xyXG4gIC8qKiBUaGUgc2hvcnQsIHVucXVhbGlmaWVkLCBuYW1lIGZvciB0aGlzIEVudGl0eVR5cGUuIF9fUmVhZCBPbmx5X18gICoqL1xyXG4gIHNob3J0TmFtZTogc3RyaW5nO1xyXG4gIC8qKiBUaGUgbmFtZXNwYWNlIGZvciB0aGlzIEVudGl0eVR5cGUuIF9fUmVhZCBPbmx5X18gICoqL1xyXG4gIG5hbWVzcGFjZTogc3RyaW5nO1xyXG4gIC8qKiBUaGUgbmFtZSBvZiB0aGlzIEVudGl0eVR5cGUncyBiYXNlIEVudGl0eVR5cGUgIChpZiBhbnkpICovXHJcbiAgYmFzZVR5cGVOYW1lPzogc3RyaW5nO1xyXG4gIC8qKiBUaGUgYmFzZSBFbnRpdHlUeXBlIChpZiBhbnkpIGZvciB0aGlzIEVudGl0eVR5cGUuIF9fUmVhZCBPbmx5X18gICAqKi9cclxuICBiYXNlRW50aXR5VHlwZTogRW50aXR5VHlwZTtcclxuICBzdWJ0eXBlczogRW50aXR5VHlwZVtdO1xyXG5cclxuICAvKiogIFdoZXRoZXIgdGhpcyBFbnRpdHlUeXBlIGlzIGFic3RyYWN0LiBfX1JlYWQgT25seV9fICoqL1xyXG4gIGlzQWJzdHJhY3Q6IGJvb2xlYW47XHJcbiAgLyoqICBXaGV0aGVyIHRoaXMgRW50aXR5VHlwZSBpcyBhbm9ueW1vdXMuIEFub255bW91cyB0eXBlcyB3aWxsIG5ldmVyIGJlIGNvbW11bmljYXRlZCB0byBvciBmcm9tIHRoZSBzZXJ2ZXIuIFRoZXkgYXJlIHB1cmVseSBmb3JcclxuICBjbGllbnQgc2lkZSB1c2UgYW5kIGFyZSBnaXZlbiBhbiBhdXRvbWF0aWNhbGx5IGdlbmVyYXRlZCBuYW1lLiAgX19SZWFkIE9ubHlfXyAqKi9cclxuICBpc0Fub255bW91czogYm9vbGVhbjtcclxuICAvKiogV2hldGhlciB0aGlzIEVudGl0eVR5cGUgaGFzIGJlZW4gJ2Zyb3plbicuICBFbnRpdHlUeXBlcyBiZWNvbWUgZnJvemVuIGFmdGVyIHRoZSBmaXJzdCBpbnN0YW5jZSBcclxuICBvZiB0aGF0IHR5cGUgaGFzIGJlZW4gY3JlYXRlZCBhbmQgYXR0YWNoZWQgdG8gYW4gRW50aXR5TWFuYWdlci4gKi9cclxuICBpc0Zyb3plbjogYm9vbGVhbjtcclxuXHJcbiAgLyoqIFRoZSBbW0F1dG9HZW5lcmF0ZWRLZXlUeXBlXV0gZm9yIHRoaXMgRW50aXR5VHlwZS4gX19SZWFkIE9ubHlfXyAqKi9cclxuICBhdXRvR2VuZXJhdGVkS2V5VHlwZTogQXV0b0dlbmVyYXRlZEtleVR5cGU7XHJcbiAgLyoqICAgVGhlIGRlZmF1bHQgcmVzb3VyY2UgbmFtZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBFbnRpdHlUeXBlLiAgQW4gRW50aXR5VHlwZSBtYXkgYmUgcXVlcmllZCB2aWEgYSB2YXJpZXR5IG9mICdyZXNvdXJjZSBuYW1lcycgYnV0IHRoaXMgb25lXHJcbiAgaXMgdXNlZCBhcyB0aGUgZGVmYXVsdCB3aGVuIG5vIHJlc291cmNlIG5hbWUgaXMgcHJvdmlkZWQuICBUaGlzIHdpbGwgb2NjdXIgd2hlbiBjYWxsaW5nIFtbRW50aXR5QXNwZWN0LmxvYWROYXZpZ2F0aW9uUHJvcGVydHldXVxyXG4gIG9yIHdoZW4gZXhlY3V0aW5nIGFueSBbW0VudGl0eVF1ZXJ5XV0gdGhhdCB3YXMgY3JlYXRlZCB2aWEgYW4gW1tFbnRpdHlLZXldXS4gX19SZWFkIE9ubHlfXyAqKi9cclxuICBkZWZhdWx0UmVzb3VyY2VOYW1lOiBzdHJpbmc7XHJcbiAgLyoqIEEgZnVuY3Rpb24gdGhhdCBpcyB1c2VkIHRvIGN1c3RvbWl6ZSB0aGUgc2VyaWFsaXphdGlvbiBvZiBhbnkgRW50aXR5UHJvcGVydGllcyBvZiB0aGlzIHR5cGUuICovXHJcbiAgc2VyaWFsaXplckZuPzogKHByb3A6IEVudGl0eVByb3BlcnR5LCB2YWw6IGFueSkgPT4gYW55O1xyXG4gIC8qKiAgQSBmcmVlIGZvcm0gb2JqZWN0IHRoYXQgY2FuIGJlIHVzZWQgdG8gZGVmaW5lIGFueSBjdXN0b20gbWV0YWRhdGEgZm9yIHRoaXMgRW50aXR5VHlwZS4gX19SZWFkIE9ubHlfXyAgKiovXHJcbiAgY3VzdG9tPzogT2JqZWN0O1xyXG4gIC8qKiBUaGUgZW50aXR5IGxldmVsIHZhbGlkYXRvcnMgYXNzb2NpYXRlZCB3aXRoIHRoaXMgRW50aXR5VHlwZS4gVmFsaWRhdG9ycyBjYW4gYmUgYWRkZWQgYW5kXHJcbiAgcmVtb3ZlZCBmcm9tIHRoaXMgY29sbGVjdGlvbi4gX19SZWFkIE9ubHlfXy4gICAqKi9cclxuICB2YWxpZGF0b3JzOiBWYWxpZGF0b3JbXTtcclxuXHJcbiAgd2FybmluZ3M6IGFueVtdO1xyXG4gIGluaXRGbjogRnVuY3Rpb24gfCBzdHJpbmc7XHJcbiAgbm9UcmFja2luZ0ZuOiBGdW5jdGlvbjtcclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2V4dHJhOiBhbnk7XHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2N0b3I6IHsgbmV3ICgpOiBTdHJ1Y3R1cmFsT2JqZWN0IH07XHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX21hcHBlZFByb3BlcnRpZXNDb3VudDogbnVtYmVyO1xyXG5cclxuICAvKiogXHJcbiAgQGRlcHJlY2F0ZWQgVXNlIFtbZ2V0Q3Rvcl1dIGluc3RlYWQuICAgXHJcbiAgKi9cclxuICBnZXRFbnRpdHlDdG9yID0gdGhpcy5nZXRDdG9yO1xyXG5cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBzdGF0aWMgcXVhbGlmeVR5cGVOYW1lID0gcXVhbGlmeVR5cGVOYW1lO1xyXG5cclxuXHJcbiAgLyoqIEVudGl0eVR5cGUgY29uc3RydWN0b3IgIFxyXG4gID4gICAgICBsZXQgZW50aXR5VHlwZSA9IG5ldyBFbnRpdHlUeXBlKCB7XHJcbiAgPiAgICAgICAgICBzaG9ydE5hbWU6IFwicGVyc29uXCIsXHJcbiAgPiAgICAgICAgICBuYW1lc3BhY2U6IFwibXlBcHBOYW1lc3BhY2VcIlxyXG4gID4gICAgICB9KTtcclxuICBAcGFyYW0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBzZXR0aW5ncyBvciBhIE1ldGFkYXRhU3RvcmUuICBJZiB0aGlzIHBhcmFtZXRlciBpcyBqdXN0IGEgTWV0YWRhdGFTdG9yZVxyXG4gIHRoZW4gd2hhdCB3aWxsIGJlIGNyZWF0ZWQgaXMgYW4gJ2Fub255bW91cycgdHlwZSB0aGF0IHdpbGwgbmV2ZXIgYmUgY29tbXVuaWNhdGVkIHRvIG9yIGZyb20gdGhlIHNlcnZlci4gSXQgaXMgcHVyZWx5IGZvclxyXG4gIGNsaWVudCBzaWRlIHVzZSBhbmQgd2lsbCBiZSBnaXZlbiBhbiBhdXRvbWF0aWNhbGx5IGdlbmVyYXRlZCBuYW1lLiBOb3JtYWxseSwgaG93ZXZlciwgeW91IHdpbGwgdXNlIGEgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAgKiovXHJcbiAgY29uc3RydWN0b3IoY29uZmlnOiBNZXRhZGF0YVN0b3JlIHwgRW50aXR5VHlwZUNvbmZpZykge1xyXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIlRoZSBFbnRpdHlUeXBlIGN0b3IgaGFzIGEgc2luZ2xlIGFyZ3VtZW50IHRoYXQgaXMgZWl0aGVyIGEgJ01ldGFkYXRhU3RvcmUnIG9yIGEgY29uZmlndXJhdGlvbiBvYmplY3QuXCIpO1xyXG4gICAgfVxyXG4gICAgLy8gbGV0IGV0Q29uZmlnID0gIDxFbnRpdHlUeXBlQ29uZmlnPiA8YW55PiB1bmRlZmluZWQ7XHJcbiAgICBsZXQgZXRDb25maWc6IEVudGl0eVR5cGVDb25maWcgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XHJcblxyXG4gICAgaWYgKChjb25maWcgYXMgYW55KS5fJHR5cGVOYW1lID09PSBcIk1ldGFkYXRhU3RvcmVcIikge1xyXG4gICAgICB0aGlzLm1ldGFkYXRhU3RvcmUgPSBjb25maWcgYXMgTWV0YWRhdGFTdG9yZTtcclxuICAgICAgdGhpcy5zaG9ydE5hbWUgPSBcIkFub25fXCIgKyAoKytFbnRpdHlUeXBlLl9fbmV4dEFub25JeCk7XHJcbiAgICAgIHRoaXMubmFtZXNwYWNlID0gXCJcIjtcclxuICAgICAgdGhpcy5pc0Fub255bW91cyA9IHRydWU7XHJcbiAgICAgIC8vIGV0Q29uZmlnID0gdW5kZWZpbmVkO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgZXRDb25maWcgPSBjb25maWcgYXMgRW50aXR5VHlwZUNvbmZpZztcclxuICAgICAgYXNzZXJ0Q29uZmlnKGNvbmZpZylcclxuICAgICAgICAud2hlcmVQYXJhbShcInNob3J0TmFtZVwiKS5pc05vbkVtcHR5U3RyaW5nKClcclxuICAgICAgICAud2hlcmVQYXJhbShcIm5hbWVzcGFjZVwiKS5pc1N0cmluZygpLmlzT3B0aW9uYWwoKS53aXRoRGVmYXVsdChcIlwiKVxyXG4gICAgICAgIC53aGVyZVBhcmFtKFwiYmFzZVR5cGVOYW1lXCIpLmlzU3RyaW5nKCkuaXNPcHRpb25hbCgpXHJcbiAgICAgICAgLndoZXJlUGFyYW0oXCJpc0Fic3RyYWN0XCIpLmlzQm9vbGVhbigpLmlzT3B0aW9uYWwoKS53aXRoRGVmYXVsdChmYWxzZSlcclxuICAgICAgICAud2hlcmVQYXJhbShcImF1dG9HZW5lcmF0ZWRLZXlUeXBlXCIpLmlzRW51bU9mKEF1dG9HZW5lcmF0ZWRLZXlUeXBlKS5pc09wdGlvbmFsKCkud2l0aERlZmF1bHQoQXV0b0dlbmVyYXRlZEtleVR5cGUuTm9uZSlcclxuICAgICAgICAud2hlcmVQYXJhbShcImRlZmF1bHRSZXNvdXJjZU5hbWVcIikuaXNOb25FbXB0eVN0cmluZygpLmlzT3B0aW9uYWwoKS53aXRoRGVmYXVsdChudWxsKVxyXG4gICAgICAgIC53aGVyZVBhcmFtKFwiZGF0YVByb3BlcnRpZXNcIikuaXNPcHRpb25hbCgpXHJcbiAgICAgICAgLndoZXJlUGFyYW0oXCJuYXZpZ2F0aW9uUHJvcGVydGllc1wiKS5pc09wdGlvbmFsKClcclxuICAgICAgICAud2hlcmVQYXJhbShcInNlcmlhbGl6ZXJGblwiKS5pc09wdGlvbmFsKCkuaXNGdW5jdGlvbigpXHJcbiAgICAgICAgLndoZXJlUGFyYW0oXCJjdXN0b21cIikuaXNPcHRpb25hbCgpXHJcbiAgICAgICAgLmFwcGx5QWxsKHRoaXMpO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMubmFtZSA9IHF1YWxpZnlUeXBlTmFtZSh0aGlzLnNob3J0TmFtZSwgdGhpcy5uYW1lc3BhY2UpO1xyXG5cclxuICAgIC8vIHRoZSBkZWZhdWx0UmVzb3VyY2VOYW1lIG1heSBhbHNvIGJlIHNldCB1cCBlaXRoZXIgdmlhIG1ldGFkYXRhIGxvb2t1cCBvciBmaXJzdCBxdWVyeSBvciB2aWEgdGhlICdzZXRQcm9wZXJ0aWVzJyBtZXRob2RcclxuICAgIHRoaXMuZGF0YVByb3BlcnRpZXMgPSBbXTtcclxuICAgIHRoaXMubmF2aWdhdGlvblByb3BlcnRpZXMgPSBbXTtcclxuICAgIHRoaXMuY29tcGxleFByb3BlcnRpZXMgPSBbXTtcclxuICAgIHRoaXMua2V5UHJvcGVydGllcyA9IFtdO1xyXG4gICAgdGhpcy5mb3JlaWduS2V5UHJvcGVydGllcyA9IFtdO1xyXG4gICAgdGhpcy5pbnZlcnNlRm9yZWlnbktleVByb3BlcnRpZXMgPSBbXTtcclxuICAgIHRoaXMuY29uY3VycmVuY3lQcm9wZXJ0aWVzID0gW107XHJcbiAgICB0aGlzLnVubWFwcGVkUHJvcGVydGllcyA9IFtdOyAvLyB3aWxsIGJlIHVwZGF0ZWQgbGF0ZXIuXHJcbiAgICB0aGlzLnZhbGlkYXRvcnMgPSBbXTtcclxuICAgIHRoaXMud2FybmluZ3MgPSBbXTtcclxuICAgIHRoaXMuX21hcHBlZFByb3BlcnRpZXNDb3VudCA9IDA7XHJcbiAgICB0aGlzLnN1YnR5cGVzID0gW107XHJcbiAgICAvLyBub3cgcHJvY2VzcyBhbnkgZGF0YS9uYXYgcHJvcHNcclxuICAgIGlmIChldENvbmZpZyAmJiBldENvbmZpZy5kYXRhUHJvcGVydGllcykge1xyXG4gICAgICBhZGRQcm9wZXJ0aWVzKHRoaXMsIGV0Q29uZmlnLmRhdGFQcm9wZXJ0aWVzLCBEYXRhUHJvcGVydHkpO1xyXG4gICAgfVxyXG4gICAgaWYgKGV0Q29uZmlnICYmIGV0Q29uZmlnLm5hdmlnYXRpb25Qcm9wZXJ0aWVzKSB7XHJcbiAgICAgIGFkZFByb3BlcnRpZXModGhpcywgZXRDb25maWcubmF2aWdhdGlvblByb3BlcnRpZXMsIE5hdmlnYXRpb25Qcm9wZXJ0eSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBHZW5lcmFsIHB1cnBvc2UgcHJvcGVydHkgc2V0IG1ldGhvZFxyXG4gID4gICAgICAvLyBhc3N1bWUgZW0xIGlzIGFuIEVudGl0eU1hbmFnZXIgY29udGFpbmluZyBhIG51bWJlciBvZiBleGlzdGluZyBlbnRpdGllcy5cclxuICA+ICAgICAgbGV0IGN1c3RUeXBlID0gZW0xLm1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZShcIkN1c3RvbWVyXCIpO1xyXG4gID4gICAgICBjdXN0VHlwZS5zZXRQcm9wZXJ0aWVzKCB7XHJcbiAgPiAgICAgICAgICBhdXRvR2VuZXJhdGVkS2V5VHlwZTogQXV0b0dlbmVyYXRlZEtleVR5cGUuSWRlbnRpdHk7XHJcbiAgPiAgICAgICAgICBkZWZhdWx0UmVzb3VyY2VOYW1lOiBcIkN1c3RvbWVyc0FuZEluY2x1ZGVkT3JkZXJzXCJcclxuICA+ICAgICAgKX07XHJcbiAgQHBhcmFtIGNvbmZpZyAtIGEgY29uZmlndXJhdGlvbiBvYmplY3RcclxuICAqKi9cclxuICBzZXRQcm9wZXJ0aWVzKGNvbmZpZzogRW50aXR5VHlwZVNldENvbmZpZykge1xyXG4gICAgYXNzZXJ0Q29uZmlnKGNvbmZpZylcclxuICAgICAgLndoZXJlUGFyYW0oXCJhdXRvR2VuZXJhdGVkS2V5VHlwZVwiKS5pc0VudW1PZihBdXRvR2VuZXJhdGVkS2V5VHlwZSkuaXNPcHRpb25hbCgpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwiZGVmYXVsdFJlc291cmNlTmFtZVwiKS5pc1N0cmluZygpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAud2hlcmVQYXJhbShcInNlcmlhbGl6ZXJGblwiKS5pc0Z1bmN0aW9uKCkuaXNPcHRpb25hbCgpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwiY3VzdG9tXCIpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAuYXBwbHlBbGwodGhpcyk7XHJcbiAgICBpZiAoY29uZmlnLmRlZmF1bHRSZXNvdXJjZU5hbWUpIHtcclxuICAgICAgdGhpcy5kZWZhdWx0UmVzb3VyY2VOYW1lID0gY29uZmlnLmRlZmF1bHRSZXNvdXJjZU5hbWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBSZXR1cm5zIHdoZXRoZXIgdGhpcyB0eXBlIGlzIGEgc3VidHlwZSBvZiBhIHNwZWNpZmllZCB0eXBlLlxyXG4gICoqL1xyXG4gIGlzU3VidHlwZU9mKGVudGl0eVR5cGU6IEVudGl0eVR5cGUpIHtcclxuICAgIGFzc2VydFBhcmFtKGVudGl0eVR5cGUsIFwiZW50aXR5VHlwZVwiKS5pc0luc3RhbmNlT2YoRW50aXR5VHlwZSkuY2hlY2soKTtcclxuICAgIGxldCBiYXNlVHlwZTogRW50aXR5VHlwZSA9IHRoaXM7XHJcbiAgICBkbyB7XHJcbiAgICAgIGlmIChiYXNlVHlwZSA9PT0gZW50aXR5VHlwZSkgcmV0dXJuIHRydWU7XHJcbiAgICAgIGJhc2VUeXBlID0gYmFzZVR5cGUuYmFzZUVudGl0eVR5cGU7XHJcbiAgICB9IHdoaWxlIChiYXNlVHlwZSk7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBSZXR1cm5zIGFuIGFycmF5IGNvbnRhaW5pbmcgdGhpcyB0eXBlIGFuZCBhbnkvYWxsIHN1YnR5cGVzIG9mIHRoaXMgdHlwZSBkb3duIHRocnUgdGhlIGhpZXJhcmNoeS5cclxuICAqKi9cclxuICBnZXRTZWxmQW5kU3VidHlwZXMoKSB7XHJcbiAgICBsZXQgcmVzdWx0ID0gW3RoaXNdO1xyXG4gICAgdGhpcy5zdWJ0eXBlcy5mb3JFYWNoKGZ1bmN0aW9uIChzdCkge1xyXG4gICAgICBsZXQgc3VidHlwZXMgPSBzdC5nZXRTZWxmQW5kU3VidHlwZXMoKTtcclxuICAgICAgcmVzdWx0LnB1c2guYXBwbHkocmVzdWx0LCBzdWJ0eXBlcyk7XHJcbiAgICB9KTtcclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfVxyXG5cclxuICBnZXRBbGxWYWxpZGF0b3JzKCkge1xyXG4gICAgbGV0IHJlc3VsdCA9IHRoaXMudmFsaWRhdG9ycy5zbGljZSgwKTtcclxuICAgIGxldCBidCA9IHRoaXMuYmFzZUVudGl0eVR5cGU7XHJcbiAgICB3aGlsZSAoYnQpIHtcclxuICAgICAgcmVzdWx0LnB1c2guYXBwbHkocmVzdWx0LCBidC52YWxpZGF0b3JzKTtcclxuICAgICAgYnQgPSBidC5iYXNlRW50aXR5VHlwZTtcclxuICAgIH1cclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBBZGRzIGEgIFtbRGF0YVByb3BlcnR5XV0gb3IgYSBbW05hdmlnYXRpb25Qcm9wZXJ0eV1dIHRvIHRoaXMgRW50aXR5VHlwZS5cclxuICA+ICAgICAgLy8gYXNzdW1lIG15RW50aXR5VHlwZSBpcyBhIG5ld2x5IGNvbnN0cnVjdGVkIEVudGl0eVR5cGUuXHJcbiAgPiAgICAgIG15RW50aXR5VHlwZS5hZGRQcm9wZXJ0eShkYXRhUHJvcGVydHkxKTtcclxuICA+ICAgICAgbXlFbnRpdHlUeXBlLmFkZFByb3BlcnR5KGRhdGFQcm9wZXJ0eTIpO1xyXG4gID4gICAgICBteUVudGl0eVR5cGUuYWRkUHJvcGVydHkobmF2aWdhdGlvblByb3BlcnR5MSk7XHJcbiAgKiovXHJcbiAgYWRkUHJvcGVydHkocHJvcGVydHk6IEVudGl0eVByb3BlcnR5KSB7XHJcbiAgICBhc3NlcnRQYXJhbShwcm9wZXJ0eSwgXCJwcm9wZXJ0eVwiKS5pc0luc3RhbmNlT2YoRGF0YVByb3BlcnR5KS5vcigpLmlzSW5zdGFuY2VPZihOYXZpZ2F0aW9uUHJvcGVydHkpLmNoZWNrKCk7XHJcblxyXG4gICAgLy8gdHJ1ZSBpcyAybmQgYXJnIHRvIGZvcmNlIHJlc29sdmUgb2YgYW55IG5hdmlnYXRpb24gcHJvcGVydGllcy5cclxuICAgIGxldCBuZXdwcm9wID0gdGhpcy5fYWRkUHJvcGVydHlDb3JlKHByb3BlcnR5LCB0cnVlKTtcclxuXHJcbiAgICBpZiAodGhpcy5zdWJ0eXBlcyAmJiB0aGlzLnN1YnR5cGVzLmxlbmd0aCkge1xyXG4gICAgICBsZXQgc3R5cGUgPSB0aGlzO1xyXG4gICAgICBzdHlwZS5nZXRTZWxmQW5kU3VidHlwZXMoKS5mb3JFYWNoKGZ1bmN0aW9uIChzdCkge1xyXG4gICAgICAgIGlmIChzdCAhPT0gc3R5cGUpIHtcclxuICAgICAgICAgIGlmIChwcm9wZXJ0eS5pc05hdmlnYXRpb25Qcm9wZXJ0eSkge1xyXG4gICAgICAgICAgICBzdC5fYWRkUHJvcGVydHlDb3JlKG5ldyBOYXZpZ2F0aW9uUHJvcGVydHkocHJvcGVydHkpLCB0cnVlKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHN0Ll9hZGRQcm9wZXJ0eUNvcmUobmV3IERhdGFQcm9wZXJ0eShwcm9wZXJ0eSBhcyBEYXRhUHJvcGVydHkpLCB0cnVlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIG5ld3Byb3A7XHJcbiAgfVxyXG5cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfdXBkYXRlRnJvbUJhc2UoYmFzZUVudGl0eVR5cGU6IEVudGl0eVR5cGUpIHtcclxuICAgIHRoaXMuYmFzZUVudGl0eVR5cGUgPSBiYXNlRW50aXR5VHlwZTtcclxuICAgIGlmICh0aGlzLmF1dG9HZW5lcmF0ZWRLZXlUeXBlID09PSBBdXRvR2VuZXJhdGVkS2V5VHlwZS5Ob25lKSB7XHJcbiAgICAgIHRoaXMuYXV0b0dlbmVyYXRlZEtleVR5cGUgPSBiYXNlRW50aXR5VHlwZS5hdXRvR2VuZXJhdGVkS2V5VHlwZTtcclxuICAgIH1cclxuXHJcbiAgICBiYXNlRW50aXR5VHlwZS5kYXRhUHJvcGVydGllcy5mb3JFYWNoKChkcCkgPT4ge1xyXG4gICAgICBsZXQgbmV3RHAgPSBuZXcgRGF0YVByb3BlcnR5KGRwKTtcclxuICAgICAgLy8gZG9uJ3QgbmVlZCB0byBjb3B5IHZhbGlkYXRvcnMgYmVjYXVlIHdlIHdpbGwgd2FsayB0aGUgaGllcmFyY2h5IHRvIGZpbmQgdGhlbVxyXG4gICAgICBuZXdEcC52YWxpZGF0b3JzID0gW107XHJcbiAgICAgIG5ld0RwLmJhc2VQcm9wZXJ0eSA9IGRwO1xyXG4gICAgICB0aGlzLl9hZGRQcm9wZXJ0eUNvcmUobmV3RHApO1xyXG4gICAgfSwgdGhpcyk7XHJcbiAgICBiYXNlRW50aXR5VHlwZS5uYXZpZ2F0aW9uUHJvcGVydGllcy5mb3JFYWNoKChucCkgPT4ge1xyXG4gICAgICBsZXQgbmV3TnAgPSBuZXcgTmF2aWdhdGlvblByb3BlcnR5KG5wKTtcclxuICAgICAgLy8gZG9uJ3QgbmVlZCB0byBjb3B5IHZhbGlkYXRvcnMgYmVjYXVlIHdlIHdpbGwgd2FsayB0aGUgaGllcmFyY2h5IHRvIGZpbmQgdGhlbVxyXG4gICAgICBuZXdOcC52YWxpZGF0b3JzID0gW107XHJcbiAgICAgIG5ld05wLmJhc2VQcm9wZXJ0eSA9IG5wO1xyXG4gICAgICB0aGlzLl9hZGRQcm9wZXJ0eUNvcmUobmV3TnApO1xyXG4gICAgfSwgdGhpcyk7XHJcbiAgICBiYXNlRW50aXR5VHlwZS5zdWJ0eXBlcy5wdXNoKHRoaXMpO1xyXG4gIH1cclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2FkZFByb3BlcnR5Q29yZShwcm9wZXJ0eTogRW50aXR5UHJvcGVydHksIHNob3VsZFJlc29sdmU6IGJvb2xlYW4gPSBmYWxzZSkge1xyXG4gICAgaWYgKHRoaXMuaXNGcm96ZW4pIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGhlICdcIiArIHRoaXMubmFtZSArIFwiJyBFbnRpdHlUeXBlL0NvbXBsZXhUeXBlIGhhcyBiZWVuIGZyb3plbi4gWW91IGNhbiBvbmx5IGFkZCBwcm9wZXJ0aWVzIHRvIGFuIEVudGl0eVR5cGUvQ29tcGxleFR5cGUgYmVmb3JlIGFueSBpbnN0YW5jZXMgb2YgdGhhdCB0eXBlIGhhdmUgYmVlbiBjcmVhdGVkIGFuZCBhdHRhY2hlZCB0byBhbiBlbnRpdHlNYW5hZ2VyLlwiKTtcclxuICAgIH1cclxuICAgIGxldCBwYXJlbnRUeXBlID0gcHJvcGVydHkucGFyZW50VHlwZTtcclxuICAgIGlmIChwYXJlbnRUeXBlKSB7XHJcbiAgICAgIGlmIChwYXJlbnRUeXBlICE9PSB0aGlzKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGhpcyBwcm9wZXJ0eTogXCIgKyBwcm9wZXJ0eS5uYW1lICsgXCIgaGFzIGFscmVhZHkgYmVlbiBhZGRlZCB0byBcIiArIHByb3BlcnR5LnBhcmVudFR5cGUubmFtZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gYWRkaW5nIHRoZSBzYW1lIHByb3BlcnR5IG1vcmUgdGhhbiBvbmNlIHRvIHRoZSBzYW1lIGVudGl0eVR5cGUgaXMganVzdCBpZ25vcmVkLlxyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcHJvcGVydHkucGFyZW50VHlwZSA9IHRoaXM7XHJcbiAgICBsZXQgbXMgPSB0aGlzLm1ldGFkYXRhU3RvcmU7XHJcbiAgICAvLyBpZiAocHJvcGVydHkuaXNEYXRhUHJvcGVydHkpIHsgLy8gbW9kaWZpZWQgYmVjYXVzZSBkb2Vzbid0IGFjdCBhcyBhIHR5cGUgZ3VhcmQgXHJcbiAgICBpZiAocHJvcGVydHkgaW5zdGFuY2VvZiBEYXRhUHJvcGVydHkpIHtcclxuICAgICAgdGhpcy5fYWRkRGF0YVByb3BlcnR5KHByb3BlcnR5KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuX2FkZE5hdmlnYXRpb25Qcm9wZXJ0eShwcm9wZXJ0eSk7XHJcbiAgICAgIC8vIG1ldGFkYXRhU3RvcmUgY2FuIGJlIHVuZGVmaW5lZCBpZiB0aGlzIGVudGl0eVR5cGUgaGFzIG5vdCB5ZXQgYmVlbiBhZGRlZCB0byBhIE1ldGFkYXRhU3RvcmUuXHJcbiAgICAgIGlmIChzaG91bGRSZXNvbHZlICYmIG1zKSB7XHJcbiAgICAgICAgdHJ5UmVzb2x2ZU5wKHByb3BlcnR5LCBtcyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIC8vIHVubWFwcGVkIHByb3BlcnRpZXMgY2FuIGJlIGFkZGVkIEFGVEVSIGVudGl0eVR5cGUgaGFzIGFscmVhZHkgcmVzb2x2ZWQgYWxsIHByb3BlcnR5IG5hbWVzLlxyXG4gICAgaWYgKG1zICYmICEocHJvcGVydHkubmFtZSAmJiBwcm9wZXJ0eS5uYW1lT25TZXJ2ZXIpKSB7XHJcbiAgICAgIHVwZGF0ZUNsaWVudFNlcnZlck5hbWVzKG1zLm5hbWluZ0NvbnZlbnRpb24sIHByb3BlcnR5LCBcIm5hbWVcIik7XHJcbiAgICB9XHJcbiAgICAvLyBwcm9wcyBjYW4gYmUgYWRkZWQgYWZ0ZXIgZW50aXR5IHByb3RvdHlwZSBoYXMgYWxyZWFkeSBiZWVuIHdyYXBwZWQuXHJcbiAgICBpZiAobXMgJiYgdGhpcy5fZXh0cmEpIHtcclxuICAgICAgaWYgKHRoaXMuX2V4dHJhLmFscmVhZHlXcmFwcGVkUHJvcHMpIHtcclxuICAgICAgICBsZXQgcHJvdG8gPSB0aGlzLl9jdG9yLnByb3RvdHlwZTtcclxuICAgICAgICBjb25maWcuaW50ZXJmYWNlUmVnaXN0cnkubW9kZWxMaWJyYXJ5LmdldERlZmF1bHRJbnN0YW5jZSgpLmluaXRpYWxpemVFbnRpdHlQcm90b3R5cGUocHJvdG8pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBDcmVhdGUgYSBuZXcgZW50aXR5IG9mIHRoaXMgdHlwZS5cclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgIGxldCBjdXN0VHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEFzRW50aXR5VHlwZShcIkN1c3RvbWVyXCIpO1xyXG4gID4gICAgICBsZXQgY3VzdDEgPSBjdXN0VHlwZS5jcmVhdGVFbnRpdHkoKTtcclxuICA+ICAgICAgZW0xLmFkZEVudGl0eShjdXN0MSk7XHJcbiAgQHBhcmFtIGluaXRpYWxWYWx1ZXMtIENvbmZpZ3VyYXRpb24gb2JqZWN0IG9mIHRoZSBwcm9wZXJ0aWVzIHRvIHNldCBpbW1lZGlhdGVseSBhZnRlciBjcmVhdGlvbi5cclxuICBAcmV0dXJuIFRoZSBuZXcgZW50aXR5LlxyXG4gICoqL1xyXG4gIGNyZWF0ZUVudGl0eShpbml0aWFsVmFsdWVzPzogYW55KTogYW55IHtcclxuICAgIC8vIGlnbm9yZSB0aGUgXyRlcmVmIG9uY2UgdGhlIGVudGl0eSBpcyBhdHRhY2hlZCB0byBhbiBlbnRpdHlNYW5hZ2VyLlxyXG4gICAgaWYgKGluaXRpYWxWYWx1ZXMgJiYgaW5pdGlhbFZhbHVlcy5fJGVyZWYgJiYgIWluaXRpYWxWYWx1ZXMuXyRlcmVmLmVudGl0eUFzcGVjdC5lbnRpdHlNYW5hZ2VyKSByZXR1cm4gaW5pdGlhbFZhbHVlcy5fJGVyZWY7XHJcblxyXG4gICAgbGV0IGluc3RhbmNlID0gdGhpcy5fY3JlYXRlSW5zdGFuY2VDb3JlKCk7XHJcblxyXG4gICAgaWYgKGluaXRpYWxWYWx1ZXMpIHtcclxuICAgICAgLy8gb25seSBhc3NpZ24gYW4gX2VyZWYgaWYgdGhlIG9iamVjdCBpcyBmdWxseSBcImtleWVkXCJcclxuICAgICAgaWYgKHRoaXMua2V5UHJvcGVydGllcy5ldmVyeShmdW5jdGlvbiAoa3ApIHtcclxuICAgICAgICByZXR1cm4gaW5pdGlhbFZhbHVlc1trcC5uYW1lXSAhPSBudWxsO1xyXG4gICAgICB9KSkge1xyXG4gICAgICAgIGluaXRpYWxWYWx1ZXMuXyRlcmVmID0gaW5zdGFuY2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuX3VwZGF0ZVRhcmdldEZyb21SYXcoaW5zdGFuY2UsIGluaXRpYWxWYWx1ZXMsIGdldFJhd1ZhbHVlRnJvbUNvbmZpZyk7XHJcblxyXG4gICAgICB0aGlzLm5hdmlnYXRpb25Qcm9wZXJ0aWVzLmZvckVhY2goZnVuY3Rpb24gKG5wKSB7XHJcbiAgICAgICAgbGV0IHJlbGF0ZWRFbnRpdHk6IGFueTtcclxuICAgICAgICBsZXQgdmFsID0gaW5pdGlhbFZhbHVlc1tucC5uYW1lXTtcclxuICAgICAgICBpZiAodmFsICE9IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgbGV0IG5hdkVudGl0eVR5cGUgPSBucC5lbnRpdHlUeXBlO1xyXG4gICAgICAgICAgaWYgKG5wLmlzU2NhbGFyKSB7XHJcbiAgICAgICAgICAgIHJlbGF0ZWRFbnRpdHkgPSB2YWwuZW50aXR5QXNwZWN0ID8gdmFsIDogbmF2RW50aXR5VHlwZS5jcmVhdGVFbnRpdHkodmFsKTtcclxuICAgICAgICAgICAgaW5zdGFuY2Uuc2V0UHJvcGVydHkobnAubmFtZSwgcmVsYXRlZEVudGl0eSk7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBsZXQgcmVsYXRlZEVudGl0aWVzID0gaW5zdGFuY2UuZ2V0UHJvcGVydHkobnAubmFtZSk7XHJcbiAgICAgICAgICAgIHZhbC5mb3JFYWNoKCh2OiBhbnkpID0+IHtcclxuICAgICAgICAgICAgICByZWxhdGVkRW50aXR5ID0gdi5lbnRpdHlBc3BlY3QgPyB2IDogbmF2RW50aXR5VHlwZS5jcmVhdGVFbnRpdHkodik7XHJcbiAgICAgICAgICAgICAgcmVsYXRlZEVudGl0aWVzLnB1c2gocmVsYXRlZEVudGl0eSk7XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5faW5pdGlhbGl6ZUluc3RhbmNlKGluc3RhbmNlKTtcclxuICAgIHJldHVybiBpbnN0YW5jZTtcclxuICB9XHJcblxyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF9jcmVhdGVJbnN0YW5jZUNvcmUoKSB7XHJcbiAgICBsZXQgYUN0b3IgPSB0aGlzLmdldEN0b3IoKTtcclxuICAgIGxldCBpbnN0YW5jZSA9IG5ldyBhQ3RvcigpO1xyXG4gICAgbmV3IEVudGl0eUFzcGVjdChpbnN0YW5jZSBhcyBFbnRpdHkpO1xyXG4gICAgcmV0dXJuIGluc3RhbmNlO1xyXG4gIH1cclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2luaXRpYWxpemVJbnN0YW5jZShpbnN0YW5jZTogYW55KSB7XHJcbiAgICBpZiAodGhpcy5iYXNlRW50aXR5VHlwZSkge1xyXG4gICAgICB0aGlzLmJhc2VFbnRpdHlUeXBlLl9pbml0aWFsaXplSW5zdGFuY2UoaW5zdGFuY2UpO1xyXG4gICAgfVxyXG4gICAgbGV0IGluaXRGbiA9IHRoaXMuaW5pdEZuO1xyXG4gICAgaWYgKGluaXRGbikge1xyXG4gICAgICBsZXQgZm4gPSAodHlwZW9mIGluaXRGbiA9PT0gXCJzdHJpbmdcIikgPyBpbnN0YW5jZVtpbml0Rm5dIDogaW5pdEZuO1xyXG4gICAgICBmbihpbnN0YW5jZSk7XHJcbiAgICB9XHJcbiAgICB0aGlzLmNvbXBsZXhQcm9wZXJ0aWVzICYmIHRoaXMuY29tcGxleFByb3BlcnRpZXMuZm9yRWFjaChmdW5jdGlvbiAoY3ApIHtcclxuICAgICAgbGV0IGNvbXBsZXhUeXBlID0gY3AuZGF0YVR5cGUgYXMgQ29tcGxleFR5cGU7XHJcbiAgICAgIGxldCBjdEluc3RhbmNlID0gaW5zdGFuY2UuZ2V0UHJvcGVydHkoY3AubmFtZSk7XHJcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KGN0SW5zdGFuY2UpKSB7XHJcbiAgICAgICAgY3RJbnN0YW5jZS5mb3JFYWNoKChjdEluc3QpID0+IHtcclxuICAgICAgICAgIGNvbXBsZXhUeXBlLl9pbml0aWFsaXplSW5zdGFuY2UoY3RJbnN0KTtcclxuICAgICAgICB9KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBjb21wbGV4VHlwZS5faW5pdGlhbGl6ZUluc3RhbmNlKGN0SW5zdGFuY2UpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICAgIC8vIG5vdCBuZWVkZWQgZm9yIGNvbXBsZXhPYmplY3RzXHJcbiAgICBpZiAoaW5zdGFuY2UuZW50aXR5QXNwZWN0KSB7XHJcbiAgICAgIGluc3RhbmNlLmVudGl0eUFzcGVjdC5faW5pdGlhbGl6ZWQgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgUmV0dXJucyB0aGUgY29uc3RydWN0b3IgZm9yIHRoaXMgRW50aXR5VHlwZS5cclxuICBAcGFyYW0gZm9yY2VSZWZyZXNoIC0gV2hldGhlciB0byBpZ25vcmUgYW55IGNhY2hlZCB2ZXJzaW9uIG9mIHRoaXMgY29uc3RydWN0b3IuIChkZWZhdWx0ID09IGZhbHNlKVxyXG4gIEByZXR1cm4gVGhlIGNvbnN0cnVjdG9yIGZvciB0aGlzIEVudGl0eVR5cGUuXHJcbiAgKiovXHJcbiAgZ2V0Q3Rvcihmb3JjZVJlZnJlc2g6IGJvb2xlYW4gPSBmYWxzZSk6IHsgbmV3ICgpOiBTdHJ1Y3R1cmFsT2JqZWN0IH0ge1xyXG4gICAgaWYgKHRoaXMuX2N0b3IgJiYgIWZvcmNlUmVmcmVzaCkgcmV0dXJuIHRoaXMuX2N0b3I7XHJcblxyXG4gICAgbGV0IGN0b3JSZWdpc3RyeSA9IHRoaXMubWV0YWRhdGFTdG9yZS5fY3RvclJlZ2lzdHJ5O1xyXG4gICAgbGV0IHIgPSBjdG9yUmVnaXN0cnlbdGhpcy5uYW1lXSB8fCBjdG9yUmVnaXN0cnlbdGhpcy5zaG9ydE5hbWVdIHx8IHt9O1xyXG4gICAgbGV0IGFDdG9yID0gci5jdG9yIHx8IHRoaXMuX2N0b3I7XHJcblxyXG4gICAgbGV0IGN0b3JUeXBlID0gYUN0b3IgJiYgYUN0b3IucHJvdG90eXBlICYmIChhQ3Rvci5wcm90b3R5cGUuZW50aXR5VHlwZSB8fCBhQ3Rvci5wcm90b3R5cGUuY29tcGxleFR5cGUpO1xyXG4gICAgaWYgKGN0b3JUeXBlICYmIGN0b3JUeXBlLm1ldGFkYXRhU3RvcmUgIT09IHRoaXMubWV0YWRhdGFTdG9yZSkge1xyXG4gICAgICAvLyBXZSBjYW4ndCByaXNrIGEgbWlzbWF0Y2ggYmV0d2VlbiB0aGUgY3RvciBhbmQgdGhlIHR5cGUgaW5mbyBpbiBhIHNwZWNpZmljIG1ldGFkYXRhc3RvcmVcclxuICAgICAgLy8gYmVjYXVzZSBtb2RlbExpYnJhcmllcyByZWx5IG9uIHR5cGUgaW5mbyB0byBpbnRlcmNlcHQgY3RvciBwcm9wZXJ0aWVzXHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkNhbm5vdCByZWdpc3RlciB0aGUgc2FtZSBjb25zdHJ1Y3RvciBmb3IgXCIgKyB0aGlzLm5hbWUgKyBcIiBpbiBkaWZmZXJlbnQgbWV0YWRhdGEgc3RvcmVzLiAgUGxlYXNlIGRlZmluZSBhIHNlcGFyYXRlIGNvbnN0cnVjdG9yIGZvciBlYWNoIG1ldGFkYXRhIHN0b3JlLlwiKTtcclxuICAgIH1cclxuXHJcblxyXG4gICAgaWYgKHIuY3RvciAmJiBmb3JjZVJlZnJlc2gpIHtcclxuICAgICAgdGhpcy5fZXh0cmEgPSB1bmRlZmluZWQ7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFhQ3Rvcikge1xyXG4gICAgICBsZXQgY3JlYXRlQ3RvciA9IGNvbmZpZy5pbnRlcmZhY2VSZWdpc3RyeS5tb2RlbExpYnJhcnkuZ2V0RGVmYXVsdEluc3RhbmNlKCkuY3JlYXRlQ3RvcjtcclxuICAgICAgYUN0b3IgPSBjcmVhdGVDdG9yID8gY3JlYXRlQ3Rvcih0aGlzKSA6IGNyZWF0ZUVtcHR5Q3Rvcih0aGlzKTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmluaXRGbiA9IHIuaW5pdEZuO1xyXG4gICAgdGhpcy5ub1RyYWNraW5nRm4gPSByLm5vVHJhY2tpbmdGbjtcclxuXHJcbiAgICBhQ3Rvci5wcm90b3R5cGUuXyR0eXBlTmFtZSA9IHRoaXMubmFtZTtcclxuICAgIHRoaXMuX3NldEN0b3IoYUN0b3IpO1xyXG4gICAgcmV0dXJuIGFDdG9yO1xyXG4gIH1cclxuXHJcblxyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIC8vIE1heSBtYWtlIHB1YmxpYyBsYXRlci5cclxuICBfc2V0Q3RvcihhQ3RvcjogeyBuZXcgKCk6IFN0cnVjdHVyYWxPYmplY3QgfSwgaW50ZXJjZXB0b3I/OiBhbnkpIHtcclxuXHJcbiAgICBsZXQgaW5zdGFuY2VQcm90byA9IGFDdG9yLnByb3RvdHlwZTtcclxuXHJcbiAgICAvLyBwbGFjZSBmb3IgZXh0cmEgYnJlZXplIHJlbGF0ZWQgZGF0YVxyXG4gICAgdGhpcy5fZXh0cmEgPSB0aGlzLl9leHRyYSB8fCB7fTtcclxuXHJcbiAgICBsZXQgaW5zdGFuY2UgPSBuZXcgYUN0b3IoKTtcclxuICAgIGNhbGNVbm1hcHBlZFByb3BlcnRpZXModGhpcywgaW5zdGFuY2UpO1xyXG5cclxuICAgIGlmICh0aGlzLl8kdHlwZU5hbWUgPT09IFwiRW50aXR5VHlwZVwiKSB7XHJcbiAgICAgIC8vIGluc3VyZSB0aGF0IGFsbCBvZiB0aGUgcHJvcGVydGllcyBhcmUgb24gdGhlICd0ZW1wbGF0ZScgaW5zdGFuY2UgYmVmb3JlIHdhdGNoaW5nIHRoZSBjbGFzcy5cclxuICAgICAgaW5zdGFuY2VQcm90by5lbnRpdHlUeXBlID0gdGhpcztcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGluc3RhbmNlUHJvdG8uY29tcGxleFR5cGUgPSB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGRlZmF1bHRQcm9wZXJ0eUludGVyY2VwdG9yIGlzIGEgJ2dsb2JhbCcgKGJ1dCBpbnRlcm5hbCB0byBicmVlemUpIGZ1bmN0aW9uO1xyXG4gICAgKGluc3RhbmNlUHJvdG8gYXMgYW55KS5fJGludGVyY2VwdG9yID0gaW50ZXJjZXB0b3IgfHwgZGVmYXVsdFByb3BlcnR5SW50ZXJjZXB0b3I7XHJcbiAgICBjb25maWcuaW50ZXJmYWNlUmVnaXN0cnkubW9kZWxMaWJyYXJ5LmdldERlZmF1bHRJbnN0YW5jZSgpLmluaXRpYWxpemVFbnRpdHlQcm90b3R5cGUoaW5zdGFuY2VQcm90byk7XHJcbiAgICB0aGlzLl9jdG9yID0gYUN0b3I7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBBZGRzIGVpdGhlciBhbiBlbnRpdHkgb3IgcHJvcGVydHkgbGV2ZWwgdmFsaWRhdG9yIHRvIHRoaXMgRW50aXR5VHlwZS5cclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyIGNvbnRhaW5pbmcgYSBudW1iZXIgb2YgZXhpc3RpbmcgZW50aXRpZXMuXHJcbiAgPiAgICAgIGxldCBjdXN0VHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJDdXN0b21lclwiKTtcclxuICA+ICAgICAgbGV0IGNvdW50cnlQcm9wID0gY3VzdFR5cGUuZ2V0UHJvcGVydHkoXCJDb3VudHJ5XCIpO1xyXG4gID4gICAgICBsZXQgdmFsRm4gPSBmdW5jdGlvbiAodikge1xyXG4gID4gICAgICAgICAgICAgIGlmICh2ID09IG51bGwpIHJldHVybiB0cnVlO1xyXG4gID4gICAgICAgICAgICAgIHJldHVybiAoY29yZS5zdHJpbmdTdGFydHNXaXRoKHYsIFwiVVNcIikpO1xyXG4gID4gICAgICAgICAgfTtcclxuICA+ICAgICAgbGV0IGNvdW50cnlWYWxpZGF0b3IgPSBuZXcgVmFsaWRhdG9yKFwiY291bnRyeUlzVVNcIiwgdmFsRm4sXHJcbiAgPiAgICAgIHsgZGlzcGxheU5hbWU6IFwiQ291bnRyeVwiLCBtZXNzYWdlVGVtcGxhdGU6IFwiJyVkaXNwbGF5TmFtZSUnIG11c3Qgc3RhcnQgd2l0aCAnVVMnXCIgfSk7XHJcbiAgPiAgICAgIGN1c3RUeXBlLmFkZFZhbGlkYXRvcihjb3VudHJ5VmFsaWRhdG9yLCBjb3VudHJ5UHJvcCk7XHJcblxyXG4gIFRoaXMgaXMgdGhlIHNhbWUgYXMgYWRkaW5nIGFuIGVudGl0eSBsZXZlbCB2YWxpZGF0b3IgdmlhIHRoZSAndmFsaWRhdG9ycycgcHJvcGVydHkgb2YgRGF0YVByb3BlcnR5IG9yIE5hdmlnYXRpb25Qcm9wZXJ0eVxyXG4gID4gICAgICBjb3VudHJ5UHJvcC52YWxpZGF0b3JzLnB1c2goY291bnRyeVZhbGlkYXRvcik7XHJcblxyXG4gIEVudGl0eSBsZXZlbCB2YWxpZGF0b3JzIGNhbiBhbHNvIGJlIGFkZGVkIGJ5IG9taXR0aW5nIHRoZSAncHJvcGVydHknIHBhcmFtZXRlci5cclxuICA+ICAgICAgY3VzdFR5cGUuYWRkVmFsaWRhdG9yKHNvbWVFbnRpdHlMZXZlbFZhbGlkYXRvcik7XHJcblxyXG4gIG9yXHJcbiAgPiAgICAgIGN1c3RUeXBlLnZhbGlkYXRvcnMucHVzaChzb21lRW50aXR5TGV2ZWxWYWxpZGF0b3IpO1xyXG4gIEBwYXJhbSB2YWxpZGF0b3IgLSBWYWxpZGF0b3IgdG8gYWRkLlxyXG4gIEBwYXJhbSBwcm9wZXJ0eSAtIFByb3BlcnR5IHRvIGFkZCB0aGlzIHZhbGlkYXRvciB0by4gIElmIG9taXR0ZWQsIHRoZSB2YWxpZGF0b3IgaXMgYXNzdW1lZCB0byBiZSBhblxyXG4gIGVudGl0eSBsZXZlbCB2YWxpZGF0b3IgYW5kIGlzIGFkZGVkIHRvIHRoZSBFbnRpdHlUeXBlJ3MgJ3ZhbGlkYXRvcnMnLlxyXG4gICoqL1xyXG4gIGFkZFZhbGlkYXRvcih2YWxpZGF0b3I6IFZhbGlkYXRvciwgcHJvcGVydHk/OiBFbnRpdHlQcm9wZXJ0eSB8IHN0cmluZykge1xyXG4gICAgYXNzZXJ0UGFyYW0odmFsaWRhdG9yLCBcInZhbGlkYXRvclwiKS5pc0luc3RhbmNlT2YoVmFsaWRhdG9yKS5jaGVjaygpO1xyXG4gICAgYXNzZXJ0UGFyYW0ocHJvcGVydHksIFwicHJvcGVydHlcIikuaXNPcHRpb25hbCgpLmlzU3RyaW5nKCkub3IoKS5pc0VudGl0eVByb3BlcnR5KCkuY2hlY2soKTtcclxuICAgIGlmIChwcm9wZXJ0eSAhPSBudWxsKSB7XHJcbiAgICAgIGxldCBwcm9wID0gKHR5cGVvZiBwcm9wZXJ0eSA9PT0gJ3N0cmluZycpID8gdGhpcy5nZXRQcm9wZXJ0eShwcm9wZXJ0eSwgdHJ1ZSkgOiBwcm9wZXJ0eTtcclxuICAgICAgcHJvcCEudmFsaWRhdG9ycy5wdXNoKHZhbGlkYXRvcik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLnZhbGlkYXRvcnMucHVzaCh2YWxpZGF0b3IpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgUmV0dXJucyBhbGwgb2YgdGhlIHByb3BlcnRpZXMgKCBkYXRhUHJvcGVydGllcyBhbmQgbmF2aWdhdGlvblByb3BlcnRpZXMpIGZvciB0aGlzIEVudGl0eVR5cGUuXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIGV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgICBsZXQgY3VzdFR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQ3VzdG9tZXJcIik7XHJcbiAgPiAgICAgIGxldCBhcnJheU9mUHJvcHMgPSBjdXN0VHlwZS5nZXRQcm9wZXJ0aWVzKCk7XHJcbiAgQHJldHVybiBBbiBhcnJheSBvZiBEYXRhIGFuZCBOYXZpZ2F0aW9uIHByb3BlcnRpZXMuXHJcbiAgKiovXHJcbiAgZ2V0UHJvcGVydGllcygpOiBFbnRpdHlQcm9wZXJ0eVtdIHtcclxuICAgIHJldHVybiAodGhpcy5kYXRhUHJvcGVydGllcyBhcyBFbnRpdHlQcm9wZXJ0eVtdKS5jb25jYXQodGhpcy5uYXZpZ2F0aW9uUHJvcGVydGllcyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBSZXR1cm5zIGFsbCBvZiB0aGUgcHJvcGVydHkgbmFtZXMgKCBmb3IgYm90aCBkYXRhUHJvcGVydGllcyBhbmQgbmF2aWdhdGlvblByb3BlcnRpZXMpIGZvciB0aGlzIEVudGl0eVR5cGUuXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIGV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgICBsZXQgY3VzdFR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQ3VzdG9tZXJcIik7XHJcbiAgPiAgICAgIGxldCBhcnJheU9mUHJvcE5hbWVzID0gY3VzdFR5cGUuZ2V0UHJvcGVydHlOYW1lcygpO1xyXG4gICoqL1xyXG4gIGdldFByb3BlcnR5TmFtZXMoKSB7XHJcbiAgICByZXR1cm4gdGhpcy5nZXRQcm9wZXJ0aWVzKCkubWFwKGNvcmUucGx1Y2soJ25hbWUnKSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBSZXR1cm5zIGEgZGF0YSBwcm9wZXJ0eSB3aXRoIHRoZSBzcGVjaWZpZWQgbmFtZSBvciBudWxsLlxyXG4gID4gICAgICAvLyBhc3N1bWUgZW0xIGlzIGFuIEVudGl0eU1hbmFnZXIgY29udGFpbmluZyBhIG51bWJlciBvZiBleGlzdGluZyBlbnRpdGllcy5cclxuICA+ICAgICAgbGV0IGN1c3RUeXBlID0gZW0xLm1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZShcIkN1c3RvbWVyXCIpO1xyXG4gID4gICAgICBsZXQgY3VzdG9tZXJOYW1lRGF0YVByb3AgPSBjdXN0VHlwZS5nZXREYXRhUHJvcGVydHkoXCJDdXN0b21lck5hbWVcIik7XHJcbiAgQHJldHVybiBBIERhdGFQcm9wZXJ0eSBvciBudWxsIGlmIG5vdCBmb3VuZC5cclxuICAqKi9cclxuICBnZXREYXRhUHJvcGVydHkocHJvcGVydHlOYW1lOiBzdHJpbmcpIHtcclxuICAgIHJldHVybiBjb3JlLmFycmF5Rmlyc3QodGhpcy5kYXRhUHJvcGVydGllcywgY29yZS5wcm9wRXEoJ25hbWUnLCBwcm9wZXJ0eU5hbWUpKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBuYXZpZ2F0aW9uIHByb3BlcnR5IHdpdGggdGhlIHNwZWNpZmllZCBuYW1lIG9yIG51bGwuXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlciBjb250YWluaW5nIGEgbnVtYmVyIG9mIGV4aXN0aW5nIGVudGl0aWVzLlxyXG4gID4gICAgICBsZXQgY3VzdFR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQ3VzdG9tZXJcIik7XHJcbiAgPiAgICAgIGxldCBjdXN0b21lck9yZGVyc05hdlByb3AgPSBjdXN0VHlwZS5nZXREYXRhUHJvcGVydHkoXCJPcmRlcnNcIik7XHJcbiAgQHJldHVybiBBIE5hdmlnYXRpb25Qcm9wZXJ0eSBvciBudWxsIGlmIG5vdCBmb3VuZC5cclxuICAqKi9cclxuICBnZXROYXZpZ2F0aW9uUHJvcGVydHkocHJvcGVydHlOYW1lOiBzdHJpbmcpIHtcclxuICAgIHJldHVybiBjb3JlLmFycmF5Rmlyc3QodGhpcy5uYXZpZ2F0aW9uUHJvcGVydGllcywgY29yZS5wcm9wRXEoJ25hbWUnLCBwcm9wZXJ0eU5hbWUpKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgZWl0aGVyIGEgRGF0YVByb3BlcnR5IG9yIGEgTmF2aWdhdGlvblByb3BlcnR5IHdpdGggdGhlIHNwZWNpZmllZCBuYW1lIG9yIG51bGwuXHJcbiAgXHJcbiAgVGhpcyBtZXRob2QgYWxzbyBhY2NlcHRzIGEgJy4nIGRlbGltaXRlZCBwcm9wZXJ0eSBwYXRoIGFuZCB3aWxsIHJldHVybiB0aGUgJ3Byb3BlcnR5JyBhdCB0aGVcclxuICBlbmQgb2YgdGhlIHBhdGguXHJcbiAgPiAgICAgIGxldCBjdXN0VHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJDdXN0b21lclwiKTtcclxuICA+ICAgICAgbGV0IGNvbXBhbnlOYW1lUHJvcCA9IGN1c3RUeXBlLmdldFByb3BlcnR5KFwiQ29tcGFueU5hbWVcIik7XHJcblxyXG4gIFRoaXMgbWV0aG9kIGNhbiBhbHNvIHdhbGsgYSBwcm9wZXJ0eSBwYXRoIHRvIHJldHVybiBhIHByb3BlcnR5XHJcbiAgPiAgICAgIGxldCBvcmRlckRldGFpbFR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiT3JkZXJEZXRhaWxcIik7XHJcbiAgPiAgICAgIGxldCBjb21wYW55TmFtZVByb3AyID0gb3JkZXJEZXRhaWxUeXBlLmdldFByb3BlcnR5KFwiT3JkZXIuQ3VzdG9tZXIuQ29tcGFueU5hbWVcIik7XHJcbiAgPiAgICAgIC8vIGNvbXBhbnlOYW1lUHJvcCA9PT0gY29tcGFueU5hbWVQcm9wMlxyXG4gIEBwYXJhbSBbdGhyb3dJZk5vdEZvdW5kPWZhbHNlXSB7Qm9vbGVhbn0gV2hldGhlciB0byB0aHJvdyBhbiBleGNlcHRpb24gaWYgbm90IGZvdW5kLlxyXG4gIEByZXR1cm4gQSBEYXRhUHJvcGVydHkgb3IgTmF2aWdhdGlvblByb3BlcnR5IG9yIG51bGwgaWYgbm90IGZvdW5kLlxyXG4gICoqL1xyXG4gIGdldFByb3BlcnR5KHByb3BlcnR5UGF0aDogc3RyaW5nLCB0aHJvd0lmTm90Rm91bmQ6IGJvb2xlYW4gPSBmYWxzZSkge1xyXG4gICAgbGV0IHByb3BzID0gdGhpcy5nZXRQcm9wZXJ0aWVzT25QYXRoKHByb3BlcnR5UGF0aCwgZmFsc2UsIHRocm93SWZOb3RGb3VuZCk7XHJcbiAgICByZXR1cm4gKHByb3BzICYmIHByb3BzLmxlbmd0aCA+IDApID8gcHJvcHNbcHJvcHMubGVuZ3RoIC0gMV0gOiBudWxsO1xyXG4gIH1cclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgLy8gVE9ETzogaGF2ZSB0aGlzIHJldHVybiBlbXB0eSBhcnJheSBpbnN0ZWFkIG9mIG51bGwgYW5kIGZpeCBjb25zdW1lcnMuXHJcbiAgLy8gVE9ETzogdGhpbmsgYWJvdXQgcmVuYW1pbmcgd2l0aCAnXycgcHJlZml4LlxyXG4gIGdldFByb3BlcnRpZXNPblBhdGgocHJvcGVydHlQYXRoOiBzdHJpbmcsIHVzZVNlcnZlck5hbWU6IGJvb2xlYW4gfCBudWxsLCB0aHJvd0lmTm90Rm91bmQ6IGJvb2xlYW4gPSBmYWxzZSkge1xyXG4gICAgbGV0IHByb3BlcnR5TmFtZXM6IHN0cmluZ1tdID0gKEFycmF5LmlzQXJyYXkocHJvcGVydHlQYXRoKSkgPyBwcm9wZXJ0eVBhdGggOiBwcm9wZXJ0eVBhdGgudHJpbSgpLnNwbGl0KCcuJyk7XHJcblxyXG4gICAgbGV0IG9rID0gdHJ1ZTtcclxuICAgIGxldCBrZXkgPSB1c2VTZXJ2ZXJOYW1lID09PSB0cnVlID8gXCJuYW1lT25TZXJ2ZXJcIiA6IHVzZVNlcnZlck5hbWUgPT09IGZhbHNlID8gXCJuYW1lXCIgOiBudWxsO1xyXG4gICAgbGV0IHBhcmVudFR5cGUgPSB0aGlzIGFzIFN0cnVjdHVyYWxUeXBlO1xyXG4gICAgXHJcbiAgICBjb25zdCBnZXRQcm9wcyA9IChwcm9wTmFtZTogc3RyaW5nKSA9PiB7IFxyXG4gICAgICBjb25zdCBmbiA9IGtleSA9PT0gbnVsbCA/IGNvcmUucHJvcHNFcShcIm5hbWVcIiwgXCJuYW1lT25TZXJ2ZXJcIiwgcHJvcE5hbWUpIDogY29yZS5wcm9wRXEoa2V5LCBwcm9wTmFtZSk7XHJcbiAgICAgIGxldCBwcm9wID0gY29yZS5hcnJheUZpcnN0KHBhcmVudFR5cGUuZ2V0UHJvcGVydGllcygpLCBmbik7XHJcbiAgICAgIGlmIChwcm9wKSB7XHJcbiAgICAgICAgcGFyZW50VHlwZSA9IChwcm9wIGluc3RhbmNlb2YgTmF2aWdhdGlvblByb3BlcnR5KSA/IHByb3AuZW50aXR5VHlwZSA6IHByb3AuZGF0YVR5cGUgYXMgQ29tcGxleFR5cGU7XHJcbiAgICAgICAgLy8gcGFyZW50VHlwZSA9IHByb3AuaXNOYXZpZ2F0aW9uUHJvcGVydHkgPyBwcm9wLmVudGl0eVR5cGUgOiBwcm9wLmRhdGFUeXBlO1xyXG4gICAgICB9IGVsc2UgaWYgKHRocm93SWZOb3RGb3VuZCkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcInVuYWJsZSB0byBsb2NhdGUgcHJvcGVydHk6IFwiICsgcHJvcE5hbWUgKyBcIiBvbiBlbnRpdHlUeXBlOiBcIiArIHBhcmVudFR5cGUubmFtZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgb2sgPSBmYWxzZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gcHJvcDtcclxuICAgIH07XHJcblxyXG4gICAgbGV0IHByb3BzID0gcHJvcGVydHlOYW1lcy5tYXAoZ2V0UHJvcHMpIGFzIEVudGl0eVByb3BlcnR5W107XHJcbiAgICByZXR1cm4gb2sgPyBwcm9wcyA6IG51bGw7XHJcbiAgfVxyXG5cclxuICAvKiogRm9yIHVzZSBpbiBwbHVnZ2FibGUgYWRhcHRlcnMuICovXHJcbiAgLy8gVE9ETzogZG9jdW1lbnQgdXNlXHJcbiAgY2xpZW50UHJvcGVydHlQYXRoVG9TZXJ2ZXIocHJvcGVydHlQYXRoOiBzdHJpbmcsIGRlbGltaXRlcjogc3RyaW5nID0gJy4nKSB7XHJcbiAgICBsZXQgcHJvcE5hbWVzOiBzdHJpbmdbXTtcclxuICAgIGlmICh0aGlzLmlzQW5vbnltb3VzKSB7XHJcbiAgICAgIGxldCBmbiA9IHRoaXMubWV0YWRhdGFTdG9yZS5uYW1pbmdDb252ZW50aW9uLmNsaWVudFByb3BlcnR5TmFtZVRvU2VydmVyO1xyXG4gICAgICBwcm9wTmFtZXMgPSBwcm9wZXJ0eVBhdGguc3BsaXQoXCIuXCIpLm1hcChmdW5jdGlvbiAocHJvcE5hbWUpIHtcclxuICAgICAgICByZXR1cm4gZm4ocHJvcE5hbWUpO1xyXG4gICAgICB9KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxldCBwcm9wcyA9IHRoaXMuZ2V0UHJvcGVydGllc09uUGF0aChwcm9wZXJ0eVBhdGgsIGZhbHNlLCB0cnVlKTtcclxuICAgICAgcHJvcE5hbWVzID0gcHJvcHMhLm1hcCgocHJvcDogRW50aXR5UHJvcGVydHkpID0+IHByb3AubmFtZU9uU2VydmVyKTtcclxuICAgIH1cclxuICAgIHJldHVybiBwcm9wTmFtZXMuam9pbihkZWxpbWl0ZXIpO1xyXG4gIH1cclxuXHJcbiAgLyoqIEZvciB1c2UgaW4gcGx1Z2dhYmxlIGFkYXB0ZXJzLiAqL1xyXG4gIC8vIFRPRE86IGRvY3VtZW50IHVzZVxyXG4gIGdldEVudGl0eUtleUZyb21SYXdFbnRpdHkocmF3RW50aXR5OiBhbnksIHJhd1ZhbHVlRm46IEZ1bmN0aW9uKSB7XHJcbiAgICBsZXQga2V5VmFsdWVzID0gdGhpcy5rZXlQcm9wZXJ0aWVzLm1hcCgoZHApID0+IHtcclxuICAgICAgbGV0IHZhbCA9IHJhd1ZhbHVlRm4ocmF3RW50aXR5LCBkcCk7XHJcbiAgICAgIHJldHVybiBEYXRhVHlwZS5wYXJzZVJhd1ZhbHVlKHZhbCwgZHAuZGF0YVR5cGUgYXMgRGF0YVR5cGUpO1xyXG4gICAgfSk7XHJcbiAgICByZXR1cm4gbmV3IEVudGl0eUtleSh0aGlzLCBrZXlWYWx1ZXMpO1xyXG4gIH1cclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX3VwZGF0ZVRhcmdldEZyb21SYXcodGFyZ2V0OiBTdHJ1Y3R1cmFsT2JqZWN0LCByYXc6IGFueSwgcmF3VmFsdWVGbjogRnVuY3Rpb24pIHtcclxuICAgIC8vIGNhbGxlZCByZWN1cnNpdmVseSBmb3IgY29tcGxleCBwcm9wZXJ0aWVzXHJcbiAgICB0aGlzLmRhdGFQcm9wZXJ0aWVzLmZvckVhY2goKGRwKSA9PiB7XHJcbiAgICAgIGlmICghZHAuaXNTZXR0YWJsZSkgcmV0dXJuO1xyXG4gICAgICBsZXQgcmF3VmFsID0gcmF3VmFsdWVGbihyYXcsIGRwKTtcclxuICAgICAgaWYgKHJhd1ZhbCA9PT0gdW5kZWZpbmVkKSByZXR1cm47XHJcbiAgICAgIGxldCBkYXRhVHlwZSA9IGRwLmRhdGFUeXBlOyAvLyB0aGlzIHdpbGwgYmUgYSBjb21wbGV4VHlwZSB3aGVuIGRwIGlzIGEgY29tcGxleFByb3BlcnR5XHJcbiAgICAgIGxldCBvbGRWYWw6IGFueTtcclxuICAgICAgaWYgKGRwLmlzQ29tcGxleFByb3BlcnR5KSB7XHJcbiAgICAgICAgbGV0IGNvbXBsZXhUeXBlID0gZHAuZGF0YVR5cGUgYXMgQ29tcGxleFR5cGU7XHJcbiAgICAgICAgaWYgKHJhd1ZhbCA9PT0gbnVsbCkgcmV0dXJuOyAvLyByYXdWYWwgbWF5IGJlIG51bGwgaW4gbm9zcWwgZGJzIHdoZXJlIGl0IHdhcyBuZXZlciBkZWZpbmVkIGZvciB0aGUgZ2l2ZW4gcm93LlxyXG4gICAgICAgIG9sZFZhbCA9IHRhcmdldC5nZXRQcm9wZXJ0eShkcC5uYW1lKTtcclxuICAgICAgICBpZiAoZHAuaXNTY2FsYXIpIHtcclxuICAgICAgICAgIGNvbXBsZXhUeXBlLl91cGRhdGVUYXJnZXRGcm9tUmF3KG9sZFZhbCwgcmF3VmFsLCByYXdWYWx1ZUZuKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocmF3VmFsKSkge1xyXG4gICAgICAgICAgICBsZXQgbmV3VmFsID0gcmF3VmFsLm1hcChmdW5jdGlvbiAocmF3Q28pIHtcclxuICAgICAgICAgICAgICBsZXQgbmV3Q28gPSBjb21wbGV4VHlwZS5fY3JlYXRlSW5zdGFuY2VDb3JlKHRhcmdldCwgZHApO1xyXG4gICAgICAgICAgICAgIGNvbXBsZXhUeXBlLl91cGRhdGVUYXJnZXRGcm9tUmF3KG5ld0NvLCByYXdDbywgcmF3VmFsdWVGbik7XHJcbiAgICAgICAgICAgICAgY29tcGxleFR5cGUuX2luaXRpYWxpemVJbnN0YW5jZShuZXdDbyk7XHJcbiAgICAgICAgICAgICAgcmV0dXJuIG5ld0NvO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgaWYgKCFjb3JlLmFycmF5RXF1YWxzKG9sZFZhbCwgbmV3VmFsLCBjb0VxdWFscykpIHtcclxuICAgICAgICAgICAgICAvLyBjbGVhciB0aGUgb2xkIGFycmF5IGFuZCBwdXNoIG5ldyBvYmplY3RzIGludG8gaXQuXHJcbiAgICAgICAgICAgICAgb2xkVmFsLmxlbmd0aCA9IDA7XHJcbiAgICAgICAgICAgICAgbmV3VmFsLmZvckVhY2goZnVuY3Rpb24gKG52KSB7XHJcbiAgICAgICAgICAgICAgICBvbGRWYWwucHVzaChudik7XHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIG9sZFZhbC5sZW5ndGggPSAwO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBpZiAoZHAuaXNTY2FsYXIpIHtcclxuICAgICAgICAgIGxldCBuZXdWYWwgPSBEYXRhVHlwZS5wYXJzZVJhd1ZhbHVlKHJhd1ZhbCwgZGF0YVR5cGUgYXMgRGF0YVR5cGUpO1xyXG4gICAgICAgICAgdGFyZ2V0LnNldFByb3BlcnR5KGRwLm5hbWUsIG5ld1ZhbCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIG9sZFZhbCA9IHRhcmdldC5nZXRQcm9wZXJ0eShkcC5uYW1lKTtcclxuICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KHJhd1ZhbCkpIHtcclxuICAgICAgICAgICAgLy8gbmVlZCB0byBjb21wYXJlIHZhbHVlc1xyXG4gICAgICAgICAgICBsZXQgbmV3VmFsID0gcmF3VmFsLm1hcCgocnYpID0+IHtcclxuICAgICAgICAgICAgICByZXR1cm4gRGF0YVR5cGUucGFyc2VSYXdWYWx1ZShydiwgZGF0YVR5cGUgYXMgRGF0YVR5cGUpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgaWYgKCFjb3JlLmFycmF5RXF1YWxzKG9sZFZhbCwgbmV3VmFsKSkge1xyXG4gICAgICAgICAgICAgIC8vIGNsZWFyIHRoZSBvbGQgYXJyYXkgYW5kIHB1c2ggbmV3IG9iamVjdHMgaW50byBpdC5cclxuICAgICAgICAgICAgICBvbGRWYWwubGVuZ3RoID0gMDtcclxuICAgICAgICAgICAgICBuZXdWYWwuZm9yRWFjaChmdW5jdGlvbiAobnYpIHtcclxuICAgICAgICAgICAgICAgIG9sZFZhbC5wdXNoKG52KTtcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgb2xkVmFsLmxlbmd0aCA9IDA7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gaWYgbWVyZ2luZyBmcm9tIGFuIGltcG9ydCB0aGVuIHJhdyB3aWxsIGhhdmUgYW4gZW50aXR5QXNwZWN0IG9yIGEgY29tcGxleEFzcGVjdFxyXG4gICAgbGV0IHJhd0FzcGVjdCA9IHJhdy5lbnRpdHlBc3BlY3QgfHwgcmF3LmNvbXBsZXhBc3BlY3Q7XHJcbiAgICBpZiAocmF3QXNwZWN0KSB7XHJcblxyXG4gICAgICBsZXQgdGFyZ2V0QXNwZWN0ID0gRW50aXR5QXNwZWN0LmlzRW50aXR5KHRhcmdldCkgPyB0YXJnZXQuZW50aXR5QXNwZWN0IDogdGFyZ2V0LmNvbXBsZXhBc3BlY3Q7XHJcbiAgICAgIGlmIChyYXdBc3BlY3Qub3JpZ2luYWxWYWx1ZXNNYXApIHtcclxuICAgICAgICB0YXJnZXRBc3BlY3Qub3JpZ2luYWxWYWx1ZXMgPSByYXdBc3BlY3Qub3JpZ2luYWxWYWx1ZXNNYXA7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKHJhd0FzcGVjdC5leHRyYU1ldGFkYXRhKSB7XHJcbiAgICAgICAgdGFyZ2V0QXNwZWN0LmV4dHJhTWV0YWRhdGEgPSByYXdBc3BlY3QuZXh0cmFNZXRhZGF0YTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcblxyXG5cclxuICAvKipcclxuICBSZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoaXMgRW50aXR5VHlwZS5cclxuICAqKi9cclxuICB0b1N0cmluZygpIHtcclxuICAgIHJldHVybiB0aGlzLm5hbWU7XHJcbiAgfVxyXG5cclxuICB0b0pTT04oKSB7XHJcbiAgICByZXR1cm4gY29yZS50b0pzb24odGhpcywge1xyXG4gICAgICBzaG9ydE5hbWU6IG51bGwsXHJcbiAgICAgIG5hbWVzcGFjZTogbnVsbCxcclxuICAgICAgYmFzZVR5cGVOYW1lOiBudWxsLFxyXG4gICAgICBpc0Fic3RyYWN0OiBmYWxzZSxcclxuICAgICAgYXV0b0dlbmVyYXRlZEtleVR5cGU6IG51bGwsIC8vIGRvIG5vdCBzdXBwcmVzcyBkZWZhdWx0IHZhbHVlXHJcbiAgICAgIGRlZmF1bHRSZXNvdXJjZU5hbWU6IG51bGwsXHJcbiAgICAgIGRhdGFQcm9wZXJ0aWVzOiBsb2NhbFByb3BzT25seSxcclxuICAgICAgbmF2aWdhdGlvblByb3BlcnRpZXM6IGxvY2FsUHJvcHNPbmx5LFxyXG4gICAgICB2YWxpZGF0b3JzOiBudWxsLFxyXG4gICAgICBjdXN0b206IG51bGxcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX3VwZGF0ZU5hbWVzKHByb3BlcnR5OiBFbnRpdHlQcm9wZXJ0eSkge1xyXG4gICAgbGV0IG5jID0gdGhpcy5tZXRhZGF0YVN0b3JlLm5hbWluZ0NvbnZlbnRpb247XHJcbiAgICB1cGRhdGVDbGllbnRTZXJ2ZXJOYW1lcyhuYywgcHJvcGVydHksIFwibmFtZVwiKTtcclxuXHJcbiAgICBpZiAocHJvcGVydHkuaXNOYXZpZ2F0aW9uUHJvcGVydHkpIHtcclxuICAgICAgdXBkYXRlQ2xpZW50U2VydmVyTmFtZXMobmMsIHByb3BlcnR5LCBcImZvcmVpZ25LZXlOYW1lc1wiKTtcclxuICAgICAgdXBkYXRlQ2xpZW50U2VydmVyTmFtZXMobmMsIHByb3BlcnR5LCBcImludkZvcmVpZ25LZXlOYW1lc1wiKTtcclxuXHJcbiAgICAgIC8vIHRoZXNlIHdpbGwgZ2V0IHNldCBsYXRlciB2aWEgX3VwZGF0ZU5wc1xyXG4gICAgICAvLyB0aGlzLmludmVyc2VcclxuICAgICAgLy8gdGhpcy5lbnRpdHlUeXBlXHJcbiAgICAgIC8vIHRoaXMucmVsYXRlZERhdGFQcm9wZXJ0aWVzXHJcbiAgICAgIC8vICAgIGRhdGFQcm9wZXJ0eS5yZWxhdGVkTmF2aWdhdGlvblByb3BlcnR5XHJcbiAgICAgIC8vICAgIGRhdGFQcm9wZXJ0eS5pbnZlcnNlTmF2aWdhdGlvblByb3BlcnR5XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfY2hlY2tOYXZQcm9wZXJ0eShuYXZpZ2F0aW9uUHJvcGVydHk6IE5hdmlnYXRpb25Qcm9wZXJ0eSB8IHN0cmluZykge1xyXG4gICAgLy8gaWYgKG5hdmlnYXRpb25Qcm9wZXJ0eS5pc05hdmlnYXRpb25Qcm9wZXJ0eSkge1xyXG4gICAgaWYgKG5hdmlnYXRpb25Qcm9wZXJ0eSBpbnN0YW5jZW9mIE5hdmlnYXRpb25Qcm9wZXJ0eSkge1xyXG4gICAgICBpZiAobmF2aWdhdGlvblByb3BlcnR5LnBhcmVudFR5cGUgIT09IHRoaXMpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoY29yZS5mb3JtYXRTdHJpbmcoXCJUaGUgbmF2aWdhdGlvblByb3BlcnR5ICclMScgaXMgbm90IGEgcHJvcGVydHkgb2YgZW50aXR5IHR5cGUgJyUyJ1wiLFxyXG4gICAgICAgICAgbmF2aWdhdGlvblByb3BlcnR5Lm5hbWUsIHRoaXMubmFtZSkpO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBuYXZpZ2F0aW9uUHJvcGVydHk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHR5cGVvZiAobmF2aWdhdGlvblByb3BlcnR5KSA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgbGV0IG5wID0gdGhpcy5nZXRQcm9wZXJ0eShuYXZpZ2F0aW9uUHJvcGVydHkpO1xyXG4gICAgICAvLyBpZiAobnAgJiYgbnAuaXNOYXZpZ2F0aW9uUHJvcGVydHkpIHJldHVybiBucDtcclxuICAgICAgaWYgKG5wICYmIG5wIGluc3RhbmNlb2YgTmF2aWdhdGlvblByb3BlcnR5KSByZXR1cm4gbnA7XHJcbiAgICB9XHJcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJUaGUgJ25hdmlnYXRpb25Qcm9wZXJ0eScgcGFyYW1ldGVyIG11c3QgZWl0aGVyIGJlIGEgTmF2aWdhdGlvblByb3BlcnR5IG9yIHRoZSBuYW1lIG9mIGEgTmF2aWdhdGlvblByb3BlcnR5XCIpO1xyXG4gIH1cclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2FkZERhdGFQcm9wZXJ0eShkcDogRGF0YVByb3BlcnR5KSB7XHJcblxyXG4gICAgdGhpcy5kYXRhUHJvcGVydGllcy5wdXNoKGRwKTtcclxuXHJcbiAgICBpZiAoZHAuaXNQYXJ0T2ZLZXkpIHtcclxuICAgICAgdGhpcy5rZXlQcm9wZXJ0aWVzLnB1c2goZHApO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChkcC5pc0NvbXBsZXhQcm9wZXJ0eSkge1xyXG4gICAgICB0aGlzLmNvbXBsZXhQcm9wZXJ0aWVzLnB1c2goZHApO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChkcC5jb25jdXJyZW5jeU1vZGUgJiYgZHAuY29uY3VycmVuY3lNb2RlICE9PSBcIk5vbmVcIikge1xyXG4gICAgICB0aGlzLmNvbmN1cnJlbmN5UHJvcGVydGllcy5wdXNoKGRwKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoZHAuaXNVbm1hcHBlZCkge1xyXG4gICAgICB0aGlzLnVubWFwcGVkUHJvcGVydGllcy5wdXNoKGRwKTtcclxuICAgIH1cclxuXHJcbiAgfVxyXG5cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfYWRkTmF2aWdhdGlvblByb3BlcnR5KG5wOiBOYXZpZ2F0aW9uUHJvcGVydHkpIHtcclxuXHJcbiAgICB0aGlzLm5hdmlnYXRpb25Qcm9wZXJ0aWVzLnB1c2gobnApO1xyXG5cclxuICAgIGlmICghaXNRdWFsaWZpZWRUeXBlTmFtZShucC5lbnRpdHlUeXBlTmFtZSkpIHtcclxuICAgICAgbnAuZW50aXR5VHlwZU5hbWUgPSBxdWFsaWZ5VHlwZU5hbWUobnAuZW50aXR5VHlwZU5hbWUsIHRoaXMubmFtZXNwYWNlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF91cGRhdGVDcHMoKSB7XHJcbiAgICBsZXQgbWV0YWRhdGFTdG9yZSA9IHRoaXMubWV0YWRhdGFTdG9yZTtcclxuICAgIGxldCBpbmNvbXBsZXRlVHlwZU1hcCA9IG1ldGFkYXRhU3RvcmUuX2luY29tcGxldGVDb21wbGV4VHlwZU1hcDtcclxuICAgIHRoaXMuY29tcGxleFByb3BlcnRpZXMuZm9yRWFjaChmdW5jdGlvbiAoY3ApIHtcclxuICAgICAgaWYgKGNwLmNvbXBsZXhUeXBlKSByZXR1cm47XHJcbiAgICAgIGlmICghcmVzb2x2ZUNwKGNwLCBtZXRhZGF0YVN0b3JlKSkge1xyXG4gICAgICAgIGNvcmUuZ2V0QXJyYXkoaW5jb21wbGV0ZVR5cGVNYXAsIGNwLmNvbXBsZXhUeXBlTmFtZSkucHVzaChjcCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIGlmICh0aGlzLmlzQ29tcGxleFR5cGUpIHtcclxuICAgICAgKGluY29tcGxldGVUeXBlTWFwW3RoaXMubmFtZV0gfHwgW10pLmZvckVhY2goZnVuY3Rpb24gKGNwOiBEYXRhUHJvcGVydHkpIHtcclxuICAgICAgICByZXNvbHZlQ3AoY3AsIG1ldGFkYXRhU3RvcmUpO1xyXG4gICAgICB9KTtcclxuICAgICAgZGVsZXRlIGluY29tcGxldGVUeXBlTWFwW3RoaXMubmFtZV07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfdXBkYXRlTnBzKCkge1xyXG4gICAgbGV0IG1ldGFkYXRhU3RvcmUgPSB0aGlzLm1ldGFkYXRhU3RvcmU7XHJcblxyXG4gICAgLy8gcmVzb2x2ZSBhbGwgbmF2UHJvcHMgZm9yIHRoaXMgZW50aXR5VHlwZVxyXG4gICAgdGhpcy5uYXZpZ2F0aW9uUHJvcGVydGllcy5mb3JFYWNoKGZ1bmN0aW9uIChucCkge1xyXG4gICAgICB0cnlSZXNvbHZlTnAobnAsIG1ldGFkYXRhU3RvcmUpO1xyXG4gICAgfSk7XHJcbiAgICBsZXQgaW5jb21wbGV0ZVR5cGVNYXAgPSBtZXRhZGF0YVN0b3JlLl9pbmNvbXBsZXRlVHlwZU1hcDtcclxuICAgIC8vIG5leHQgcmVzb2x2ZSBhbGwgbmF2UHJvcCB0aGF0IHBvaW50IHRvIHRoaXMgZW50aXR5VHlwZS5cclxuICAgIChpbmNvbXBsZXRlVHlwZU1hcFt0aGlzLm5hbWVdIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChucDogTmF2aWdhdGlvblByb3BlcnR5KSB7XHJcbiAgICAgIHRyeVJlc29sdmVOcChucCwgbWV0YWRhdGFTdG9yZSk7XHJcbiAgICB9KTtcclxuICAgIC8vIGV2ZXJ5IG5hdlByb3AgdGhhdCBwb2ludGVkIHRvIHRoaXMgdHlwZSBzaG91bGQgbm93IGJlIHJlc29sdmVkXHJcbiAgICBkZWxldGUgaW5jb21wbGV0ZVR5cGVNYXBbdGhpcy5uYW1lXTtcclxuICB9XHJcbn1cclxuXHJcbkVudGl0eVR5cGUucHJvdG90eXBlLl8kdHlwZU5hbWUgPSBcIkVudGl0eVR5cGVcIjtcclxuXHJcbmZ1bmN0aW9uIGdldFJhd1ZhbHVlRnJvbUNvbmZpZyhyYXdFbnRpdHk6IGFueSwgZHA6IERhdGFQcm9wZXJ0eSkge1xyXG4gIC8vICd0cnVlJyBmb3JrIGNhbiBoYXBwZW4gaWYgYW4gaW5pdGlhbGl6ZXIgY29udGFpbnMgYW4gYWN0YXVsIGluc3RhbmNlIG9mIGFuIGFscmVhZHkgY3JlYXRlZCBjb21wbGV4IG9iamVjdC5cclxuICByZXR1cm4gKHJhd0VudGl0eS5lbnRpdHlBc3BlY3QgfHwgcmF3RW50aXR5LmNvbXBsZXhBc3BlY3QpID8gcmF3RW50aXR5LmdldFByb3BlcnR5KGRwLm5hbWUpIDogcmF3RW50aXR5W2RwLm5hbWVdO1xyXG59XHJcblxyXG5mdW5jdGlvbiB1cGRhdGVDbGllbnRTZXJ2ZXJOYW1lcyhuYzogTmFtaW5nQ29udmVudGlvbiwgcGFyZW50OiBhbnksIGNsaWVudFByb3BOYW1lOiBzdHJpbmcpIHtcclxuICBsZXQgc2VydmVyUHJvcE5hbWUgPSBjbGllbnRQcm9wTmFtZSArIFwiT25TZXJ2ZXJcIjtcclxuICBsZXQgY2xpZW50TmFtZSA9IHBhcmVudFtjbGllbnRQcm9wTmFtZV07XHJcbiAgaWYgKGNsaWVudE5hbWUgJiYgY2xpZW50TmFtZS5sZW5ndGgpIHtcclxuICAgIC8vIGlmIChwYXJlbnQuaXNVbm1hcHBlZCkgcmV0dXJuO1xyXG4gICAgbGV0IHNlcnZlck5hbWVzID0gY29yZS50b0FycmF5KGNsaWVudE5hbWUpLm1hcChmdW5jdGlvbiAoY05hbWUpIHtcclxuICAgICAgbGV0IHNOYW1lID0gbmMuY2xpZW50UHJvcGVydHlOYW1lVG9TZXJ2ZXIoY05hbWUsIHBhcmVudCk7XHJcbiAgICAgIGxldCB0ZXN0TmFtZSA9IG5jLnNlcnZlclByb3BlcnR5TmFtZVRvQ2xpZW50KHNOYW1lLCBwYXJlbnQpO1xyXG4gICAgICBpZiAoY05hbWUgIT09IHRlc3ROYW1lKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTmFtaW5nQ29udmVudGlvbiBmb3IgdGhpcyBjbGllbnQgcHJvcGVydHkgbmFtZSBkb2VzIG5vdCByb3VuZHRyaXAgcHJvcGVybHk6XCIgKyBjTmFtZSArIFwiLS0+XCIgKyB0ZXN0TmFtZSk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHNOYW1lO1xyXG4gICAgfSk7XHJcbiAgICBwYXJlbnRbc2VydmVyUHJvcE5hbWVdID0gQXJyYXkuaXNBcnJheShjbGllbnROYW1lKSA/IHNlcnZlck5hbWVzIDogc2VydmVyTmFtZXNbMF07XHJcbiAgfSBlbHNlIHtcclxuICAgIGxldCBzZXJ2ZXJOYW1lID0gcGFyZW50W3NlcnZlclByb3BOYW1lXTtcclxuICAgIGlmICgoIXNlcnZlck5hbWUpIHx8IHNlcnZlck5hbWUubGVuZ3RoID09PSAwKSByZXR1cm47XHJcbiAgICBsZXQgY2xpZW50TmFtZXMgPSBjb3JlLnRvQXJyYXkoc2VydmVyTmFtZSkubWFwKGZ1bmN0aW9uIChzTmFtZSkge1xyXG4gICAgICBsZXQgY05hbWUgPSBuYy5zZXJ2ZXJQcm9wZXJ0eU5hbWVUb0NsaWVudChzTmFtZSwgcGFyZW50KTtcclxuICAgICAgbGV0IHRlc3ROYW1lID0gbmMuY2xpZW50UHJvcGVydHlOYW1lVG9TZXJ2ZXIoY05hbWUsIHBhcmVudCk7XHJcbiAgICAgIGlmIChzTmFtZSAhPT0gdGVzdE5hbWUpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJOYW1pbmdDb252ZW50aW9uIGZvciB0aGlzIHNlcnZlciBwcm9wZXJ0eSBuYW1lIGRvZXMgbm90IHJvdW5kdHJpcCBwcm9wZXJseTpcIiArIHNOYW1lICsgXCItLT5cIiArIHRlc3ROYW1lKTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gY05hbWU7XHJcbiAgICB9KTtcclxuICAgIHBhcmVudFtjbGllbnRQcm9wTmFtZV0gPSBBcnJheS5pc0FycmF5KHNlcnZlck5hbWUpID8gY2xpZW50TmFtZXMgOiBjbGllbnROYW1lc1swXTtcclxuICB9XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNyZWF0ZUVtcHR5Q3Rvcih0eXBlOiBhbnkpIHtcclxuICBpZiAoY29uZmlnLm5vRXZhbCkge1xyXG4gICAgbGV0IEVudGl0eSA9IGZ1bmN0aW9uKCkge307XHJcbiAgICByZXR1cm4gRW50aXR5O1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsZXQgbmFtZSA9IHR5cGUubmFtZS5yZXBsYWNlKC9cXFcvZywgJ18nKTtcclxuICAgIHJldHVybiBGdW5jdGlvbigncmV0dXJuIGZ1bmN0aW9uICcgKyBuYW1lICsgJygpe30nKSgpO1xyXG4gIH1cclxufVxyXG5cclxuZnVuY3Rpb24gY29FcXVhbHMoY28xOiBDb21wbGV4T2JqZWN0LCBjbzI6IENvbXBsZXhPYmplY3QpOiBib29sZWFuIHtcclxuICBsZXQgY29tcGxleFR5cGUgPSBjbzEuY29tcGxleEFzcGVjdCEucGFyZW50UHJvcGVydHkhLmRhdGFUeXBlIGFzIENvbXBsZXhUeXBlO1xyXG4gIGxldCBkYXRhUHJvcHMgPSBjb21wbGV4VHlwZS5kYXRhUHJvcGVydGllcztcclxuICBsZXQgYXJlRXF1YWwgPSBkYXRhUHJvcHMuZXZlcnkoZnVuY3Rpb24gKGRwKSB7XHJcbiAgICBpZiAoIWRwLmlzU2V0dGFibGUpIHJldHVybiB0cnVlO1xyXG4gICAgbGV0IHYxID0gY28xLmdldFByb3BlcnR5KGRwLm5hbWUpO1xyXG4gICAgbGV0IHYyID0gY28yLmdldFByb3BlcnR5KGRwLm5hbWUpO1xyXG4gICAgaWYgKGRwLmlzQ29tcGxleFByb3BlcnR5ICYmIGRwLmlzU2NhbGFyKSB7XHJcbiAgICAgIHJldHVybiBjb0VxdWFscyh2MSwgdjIpO1xyXG4gICAgfVxyXG4gICAgZWxzZSBpZiAoZHAuaXNDb21wbGV4UHJvcGVydHkgJiYgIWRwLmlzU2NhbGFyKSB7XHJcbiAgICAgIHJldHVybiBjb3JlLmFycmF5RXF1YWxzKHYxLCB2MiwgY29FcXVhbHMpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbGV0IGRhdGFUeXBlID0gPGFueT5kcC5kYXRhVHlwZTsgLy8gdGhpcyB3aWxsIGJlIGEgY29tcGxleFR5cGUgd2hlbiBkcCBpcyBhIGNvbXBsZXhQcm9wZXJ0eVxyXG4gICAgICByZXR1cm4gKHYxID09PSB2MiB8fCAoZGF0YVR5cGUgJiYgZGF0YVR5cGUubm9ybWFsaXplICYmIHYxICYmIHYyICYmIGRhdGFUeXBlLm5vcm1hbGl6ZSh2MSkgPT09IGRhdGFUeXBlLm5vcm1hbGl6ZSh2MikpKTtcclxuICAgIH1cclxuICB9KTtcclxuICByZXR1cm4gYXJlRXF1YWw7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGxvY2FsUHJvcHNPbmx5KHByb3BzOiBFbnRpdHlQcm9wZXJ0eVtdKSB7XHJcbiAgcmV0dXJuIHByb3BzLmZpbHRlcihmdW5jdGlvbiAocHJvcCkge1xyXG4gICAgcmV0dXJuIHByb3AuYmFzZVByb3BlcnR5ID09IG51bGw7XHJcbiAgfSk7XHJcbn1cclxuXHJcblxyXG5mdW5jdGlvbiByZXNvbHZlQ3AoY3A6IERhdGFQcm9wZXJ0eSwgbWV0YWRhdGFTdG9yZTogTWV0YWRhdGFTdG9yZSkge1xyXG4gIGxldCBjb21wbGV4VHlwZSA9IG1ldGFkYXRhU3RvcmUuX2dldFN0cnVjdHVyYWxUeXBlKGNwLmNvbXBsZXhUeXBlTmFtZSwgdHJ1ZSk7XHJcbiAgaWYgKCFjb21wbGV4VHlwZSkgcmV0dXJuIGZhbHNlO1xyXG4gIGlmICghKGNvbXBsZXhUeXBlIGluc3RhbmNlb2YgQ29tcGxleFR5cGUpKSB7XHJcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJVbmFibGUgdG8gcmVzb2x2ZSBDb21wbGV4VHlwZSB3aXRoIHRoZSBuYW1lOiBcIiArIGNwLmNvbXBsZXhUeXBlTmFtZSArIFwiIGZvciB0aGUgcHJvcGVydHk6IFwiICsgY3AubmFtZSk7XHJcbiAgfVxyXG4gIGNwLmRhdGFUeXBlID0gY29tcGxleFR5cGU7XHJcbiAgY3AuZGVmYXVsdFZhbHVlID0gbnVsbDtcclxuICByZXR1cm4gdHJ1ZTtcclxufVxyXG5cclxuZnVuY3Rpb24gdHJ5UmVzb2x2ZU5wKG5wOiBOYXZpZ2F0aW9uUHJvcGVydHksIG1ldGFkYXRhU3RvcmU6IE1ldGFkYXRhU3RvcmUpIHtcclxuICBpZiAobnAuZW50aXR5VHlwZSkgcmV0dXJuIHRydWU7XHJcblxyXG4gIGxldCBlbnRpdHlUeXBlID0gbWV0YWRhdGFTdG9yZS5fZ2V0U3RydWN0dXJhbFR5cGUobnAuZW50aXR5VHlwZU5hbWUsIHRydWUpIGFzIEVudGl0eVR5cGU7XHJcbiAgaWYgKGVudGl0eVR5cGUpIHtcclxuICAgIG5wLmVudGl0eVR5cGUgPSBlbnRpdHlUeXBlO1xyXG4gICAgbnAuX3Jlc29sdmVOcCgpO1xyXG4gICAgLy8gZG9uJ3QgYm90aGVyIHJlbW92aW5nIC0gX3VwZGF0ZU5wcyB3aWxsIGRvIGl0IGxhdGVyLlxyXG4gICAgLy8gX19hcnJheVJlbW92ZUl0ZW0oaW5jb21wbGV0ZU5wcywgbnAsIGZhbHNlKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbGV0IGluY29tcGxldGVOcHMgPSBjb3JlLmdldEFycmF5KG1ldGFkYXRhU3RvcmUuX2luY29tcGxldGVUeXBlTWFwLCBucC5lbnRpdHlUeXBlTmFtZSk7XHJcbiAgICBjb3JlLmFycmF5QWRkSXRlbVVuaXF1ZShpbmNvbXBsZXRlTnBzLCBucCk7XHJcbiAgfVxyXG4gIHJldHVybiAhIWVudGl0eVR5cGU7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNhbGNVbm1hcHBlZFByb3BlcnRpZXMoc3R5cGU6IFN0cnVjdHVyYWxUeXBlLCBpbnN0YW5jZTogYW55KSB7XHJcbiAgbGV0IG1ldGFkYXRhUHJvcE5hbWVzID0gc3R5cGUuZ2V0UHJvcGVydHlOYW1lcygpO1xyXG4gIGxldCBtb2RlbExpYiA9IGNvbmZpZy5pbnRlcmZhY2VSZWdpc3RyeS5tb2RlbExpYnJhcnkuZ2V0RGVmYXVsdEluc3RhbmNlKCk7XHJcbiAgbGV0IHRyYWNrYWJsZVByb3BOYW1lcyA9IG1vZGVsTGliLmdldFRyYWNrYWJsZVByb3BlcnR5TmFtZXMoaW5zdGFuY2UpO1xyXG4gIHRyYWNrYWJsZVByb3BOYW1lcy5mb3JFYWNoKGZ1bmN0aW9uIChwbjogc3RyaW5nKSB7XHJcbiAgICBpZiAobWV0YWRhdGFQcm9wTmFtZXMuaW5kZXhPZihwbikgPT09IC0xKSB7XHJcbiAgICAgIGxldCB2YWwgPSBpbnN0YW5jZVtwbl07XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgaWYgKHR5cGVvZiB2YWwgPT09IFwiZnVuY3Rpb25cIikgdmFsID0gdmFsKCk7XHJcbiAgICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgfVxyXG4gICAgICBsZXQgZHQgPSBEYXRhVHlwZS5mcm9tVmFsdWUodmFsKTtcclxuICAgICAgbGV0IG5ld1Byb3AgPSBuZXcgRGF0YVByb3BlcnR5KHtcclxuICAgICAgICBuYW1lOiBwbixcclxuICAgICAgICBkYXRhVHlwZTogZHQsXHJcbiAgICAgICAgaXNOdWxsYWJsZTogdHJ1ZSxcclxuICAgICAgICBpc1VubWFwcGVkOiB0cnVlXHJcbiAgICAgIH0pO1xyXG4gICAgICBuZXdQcm9wLmlzU2V0dGFibGUgPSBjb3JlLmlzU2V0dGFibGUoaW5zdGFuY2UsIHBuKTtcclxuICAgICAgaWYgKHN0eXBlIGluc3RhbmNlb2YgRW50aXR5VHlwZSAmJiBzdHlwZS5zdWJ0eXBlcyAhPSBudWxsICYmIHN0eXBlLnN1YnR5cGVzLmxlbmd0aCkge1xyXG4gICAgICAgIHN0eXBlLmdldFNlbGZBbmRTdWJ0eXBlcygpLmZvckVhY2goKHN0KSA9PiB7XHJcbiAgICAgICAgICBzdC5fYWRkUHJvcGVydHlDb3JlKG5ldyBEYXRhUHJvcGVydHkobmV3UHJvcCkpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHN0eXBlLl9hZGRQcm9wZXJ0eUNvcmUobmV3UHJvcCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBDb21wbGV4VHlwZUNvbmZpZyB7XHJcbiAgc2hvcnROYW1lPzogc3RyaW5nO1xyXG4gIG5hbWVzcGFjZT86IHN0cmluZztcclxuICBkYXRhUHJvcGVydGllcz86IERhdGFQcm9wZXJ0eVtdIHwgT2JqZWN0W10gfCBPYmplY3Q7XHJcbiAgaXNDb21wbGV4VHlwZT86IGJvb2xlYW47ICAvLyBuZWVkZWQgYmVjYXVzZSB0aGlzIGN0b3IgY2FuIGdldCBjYWxsZWQgZnJvbSB0aGUgYWRkRW50aXR5VHlwZSBtZXRob2Qgd2hpY2ggbmVlZHMgdGhlIGlzQ29tcGxleFR5cGUgcHJvcFxyXG4gIGN1c3RvbT86IE9iamVjdDtcclxufVxyXG5cclxuLyoqICBDb250YWluZXIgZm9yIGFsbCBvZiB0aGUgbWV0YWRhdGEgYWJvdXQgYSBzcGVjaWZpYyB0eXBlIG9mIENvbXBsZXggb2JqZWN0LlxyXG4+ICAgICBsZXQgY29tcGxleFR5cGUgPSBuZXcgQ29tcGxleFR5cGUoIHtcclxuPiAgICAgICAgIHNob3J0TmFtZTogXCJhZGRyZXNzXCIsXHJcbj4gICAgICAgICBuYW1lc3BhY2U6IFwibXlBcHBOYW1lc3BhY2VcIlxyXG4+ICAgICB9KTtcclxuQHBhcmFtIGNvbmZpZyAtIENvbmZpZ3VyYXRpb24gc2V0dGluZ3NcclxuKiovXHJcbmV4cG9ydCBjbGFzcyBDb21wbGV4VHlwZSB7XHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgXyR0eXBlTmFtZTogc3RyaW5nOyAvLyBvbiBwcm90b1xyXG4gIC8qKiBGb3IgcG9seW1vcnBoaWMgcHVycG9zZSBvbmx5IC0gYWx3YXlzIHRydWUgaGVyZSAqL1xyXG4gIGlzQ29tcGxleFR5cGUgPSB0cnVlO1xyXG5cclxuICAvKiogVGhlIFtbTWV0YWRhdGFTdG9yZV1dIGNvbnRhaW5pbmcgdGhpcyBDb21wbGV4VHlwZS4gKi9cclxuICBtZXRhZGF0YVN0b3JlOiBNZXRhZGF0YVN0b3JlO1xyXG5cclxuICAvKiogIFRoZSBmdWxseSBxdWFsaWZlZCBuYW1lIG9mIHRoaXMgQ29tcGxleFR5cGUuIF9fUmVhZCBPbmx5X18gICoqL1xyXG4gIG5hbWU6IHN0cmluZztcclxuICAvKiogIFRoZSBzaG9ydCwgdW5xdWFsaWZpZWQsIG5hbWUgZm9yIHRoaXMgQ29tcGxleFR5cGUuIF9fUmVhZCBPbmx5X18gKiovXHJcbiAgc2hvcnROYW1lOiBzdHJpbmc7XHJcblxyXG4gIC8qKiBUaGUgbmFtZXNwYWNlIGZvciB0aGlzIENvbXBsZXhUeXBlLiBfX1JlYWQgT25seV9fICoqL1xyXG4gIG5hbWVzcGFjZTogc3RyaW5nO1xyXG4gIC8qKiBUaGUgRGF0YVByb3BlcnRpZXMgKHNlZSBbW0RhdGFQcm9wZXJ0eV1dIGFzc29jaWF0ZWQgd2l0aCB0aGlzIENvbXBsZXhUeXBlLiBfX1JlYWQgT25seV9fICovXHJcbiAgZGF0YVByb3BlcnRpZXM6IERhdGFQcm9wZXJ0eVtdO1xyXG4gIC8qKiBUaGUgRGF0YVByb3BlcnRpZXMgZm9yIHRoaXMgQ29tcGxleFR5cGUgdGhhdCBjb250YWluIGluc3RhbmNlcyBvZiBhIFtbQ29tcGxleFR5cGVdXS4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIGNvbXBsZXhQcm9wZXJ0aWVzOiBEYXRhUHJvcGVydHlbXTtcclxuXHJcbiAgLyoqXHJcbiAgVGhlIGVudGl0eSBsZXZlbCB2YWxpZGF0b3JzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIENvbXBsZXhUeXBlLiBWYWxpZGF0b3JzIGNhbiBiZSBhZGRlZCBhbmRcclxuICByZW1vdmVkIGZyb20gdGhpcyBjb2xsZWN0aW9uLiBfX1JlYWQgT25seV9fICAqKi9cclxuICB2YWxpZGF0b3JzOiBWYWxpZGF0b3JbXTtcclxuICAvKiogRm9yIHBvbHltb3JwaGljIHB1cnBvc2Ugb25seSAtIGFsd2F5cyBlbXB0eSBoZXJlICovXHJcbiAgY29uY3VycmVuY3lQcm9wZXJ0aWVzOiBEYXRhUHJvcGVydHlbXTtcclxuICAvKiogVGhlIERhdGFQcm9wZXJ0aWVzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIENvbXBsZXhUeXBlIHRoYXQgYXJlIG5vdCBtYXBwZWQgdG8gYW55IGJhY2tlbmQgZGF0YXN0b3JlLiBUaGVzZSBhcmUgZWZmZWN0aXZlbHkgZnJlZSBzdGFuZGluZ1xyXG4gIHByb3BlcnRpZXMuIF9fUmVhZCBPbmx5X18gICAqKi9cclxuICB1bm1hcHBlZFByb3BlcnRpZXM6IERhdGFQcm9wZXJ0eVtdO1xyXG5cclxuICAvLyBrZXlQcm9wZXJ0aWVzIGFuZCBuYXZpZ2F0aW9uUHJvcGVydGllcyBhcmUgbm90IHVzZWQgb24gY29tcGxleFR5cGVzIC0gYnV0IGhlcmUgdG8gYWxsb3cgc2hhcmluZyBvZiBjb2RlIGJldHdlZW4gRW50aXR5VHlwZSBhbmQgQ29tcGxleFR5cGUuXHJcbiAgbmF2aWdhdGlvblByb3BlcnRpZXM6IERhdGFQcm9wZXJ0eVtdO1xyXG4gIC8vIGFuZCBtYXkgYmUgdXNlZCBsYXRlciB0byBlbmZvcmNlIHVuaXF1ZW5lc3Mgb24gYXJyYXlzIG9mIGNvbXBsZXh0eXBlcy5cclxuICBrZXlQcm9wZXJ0aWVzOiBEYXRhUHJvcGVydHlbXTtcclxuICB3YXJuaW5nczogYW55W107XHJcbiAgc2VyaWFsaXplckZuPzogKHByb3A6IEVudGl0eVByb3BlcnR5LCB2YWw6IGFueSkgPT4gYW55O1xyXG5cclxuICAvKiogQSBmcmVlIGZvcm0gb2JqZWN0IHRoYXQgY2FuIGJlIHVzZWQgdG8gZGVmaW5lIGFueSBjdXN0b20gbWV0YWRhdGEgZm9yIHRoaXMgQ29tcGxleFR5cGUuICoqKi9cclxuICBjdXN0b20/OiBhbnk7XHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX21hcHBlZFByb3BlcnRpZXNDb3VudDogbnVtYmVyO1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF9leHRyYT86IGFueTtcclxuXHJcbiAgLy8gY29weSBlbnRpdHlUeXBlIG1ldGhvZHMgb250byBjb21wbGV4VHlwZVxyXG4gIC8qKiBTZWUgW1tFbnRpdHlUeXBlLmdldEN0b3JdXSAqL1xyXG4gIGdldEN0b3IgPSBFbnRpdHlUeXBlLnByb3RvdHlwZS5nZXRDdG9yO1xyXG4gIC8vIG5vdGUgdGhlIG5hbWUgY2hhbmdlLlxyXG4gIGNyZWF0ZUluc3RhbmNlID0gRW50aXR5VHlwZS5wcm90b3R5cGUuY3JlYXRlRW50aXR5O1xyXG4gIC8qKiBTZWUgW0VudGl0eVR5cGUuYWRkVmFsaWRhdG9yXSAqL1xyXG4gIGFkZFZhbGlkYXRvciA9IEVudGl0eVR5cGUucHJvdG90eXBlLmFkZFZhbGlkYXRvcjtcclxuICBnZXRQcm9wZXJ0eSA9IEVudGl0eVR5cGUucHJvdG90eXBlLmdldFByb3BlcnR5O1xyXG4gIGdldFByb3BlcnRpZXNPblBhdGggPSBFbnRpdHlUeXBlLnByb3RvdHlwZS5nZXRQcm9wZXJ0aWVzT25QYXRoO1xyXG4gIGdldFByb3BlcnR5TmFtZXMgPSBFbnRpdHlUeXBlLnByb3RvdHlwZS5nZXRQcm9wZXJ0eU5hbWVzO1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF9hZGRQcm9wZXJ0eUNvcmUgPSBFbnRpdHlUeXBlLnByb3RvdHlwZS5fYWRkUHJvcGVydHlDb3JlO1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF9hZGREYXRhUHJvcGVydHkgPSBFbnRpdHlUeXBlLnByb3RvdHlwZS5fYWRkRGF0YVByb3BlcnR5O1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF91cGRhdGVOYW1lcyA9IEVudGl0eVR5cGUucHJvdG90eXBlLl91cGRhdGVOYW1lcztcclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfdXBkYXRlQ3BzID0gRW50aXR5VHlwZS5wcm90b3R5cGUuX3VwZGF0ZUNwcztcclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfaW5pdGlhbGl6ZUluc3RhbmNlID0gRW50aXR5VHlwZS5wcm90b3R5cGUuX2luaXRpYWxpemVJbnN0YW5jZTtcclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBfdXBkYXRlVGFyZ2V0RnJvbVJhdyA9IEVudGl0eVR5cGUucHJvdG90eXBlLl91cGRhdGVUYXJnZXRGcm9tUmF3O1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF9zZXRDdG9yID0gRW50aXR5VHlwZS5wcm90b3R5cGUuX3NldEN0b3I7XHJcblxyXG4gIGNvbnN0cnVjdG9yKGNvbmZpZzogQ29tcGxleFR5cGVDb25maWcpIHtcclxuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUaGUgQ29tcGxleFR5cGUgY3RvciBoYXMgYSBzaW5nbGUgYXJndW1lbnQgdGhhdCBpcyBhIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlwiKTtcclxuICAgIH1cclxuXHJcbiAgICBhc3NlcnRDb25maWcoY29uZmlnKVxyXG4gICAgICAud2hlcmVQYXJhbShcInNob3J0TmFtZVwiKS5pc05vbkVtcHR5U3RyaW5nKClcclxuICAgICAgLndoZXJlUGFyYW0oXCJuYW1lc3BhY2VcIikuaXNTdHJpbmcoKS5pc09wdGlvbmFsKCkud2l0aERlZmF1bHQoXCJcIilcclxuICAgICAgLndoZXJlUGFyYW0oXCJkYXRhUHJvcGVydGllc1wiKS5pc09wdGlvbmFsKClcclxuICAgICAgLndoZXJlUGFyYW0oXCJpc0NvbXBsZXhUeXBlXCIpLmlzT3B0aW9uYWwoKS5pc0Jvb2xlYW4oKSAgIC8vIG5lZWRlZCBiZWNhdXNlIHRoaXMgY3RvciBjYW4gZ2V0IGNhbGxlZCBmcm9tIHRoZSBhZGRFbnRpdHlUeXBlIG1ldGhvZCB3aGljaCBuZWVkcyB0aGUgaXNDb21wbGV4VHlwZSBwcm9wXHJcbiAgICAgIC53aGVyZVBhcmFtKFwiY3VzdG9tXCIpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAuYXBwbHlBbGwodGhpcyk7XHJcblxyXG4gICAgdGhpcy5uYW1lID0gcXVhbGlmeVR5cGVOYW1lKHRoaXMuc2hvcnROYW1lLCB0aGlzLm5hbWVzcGFjZSk7XHJcbiAgICB0aGlzLmlzQ29tcGxleFR5cGUgPSB0cnVlO1xyXG4gICAgdGhpcy5kYXRhUHJvcGVydGllcyA9IFtdO1xyXG4gICAgdGhpcy5jb21wbGV4UHJvcGVydGllcyA9IFtdO1xyXG4gICAgdGhpcy52YWxpZGF0b3JzID0gW107XHJcbiAgICB0aGlzLmNvbmN1cnJlbmN5UHJvcGVydGllcyA9IFtdO1xyXG4gICAgdGhpcy51bm1hcHBlZFByb3BlcnRpZXMgPSBbXTtcclxuICAgIHRoaXMuX21hcHBlZFByb3BlcnRpZXNDb3VudCA9IDA7XHJcbiAgICAvLyBrZXlQcm9wZXJ0aWVzIGFuZCBuYXZpZ2F0aW9uUHJvcGVydGllcyBhcmUgbm90IHVzZWQgb24gY29tcGxleFR5cGVzIC0gYnV0IGhlcmUgdG8gYWxsb3cgc2hhcmluZyBvZiBjb2RlIGJldHdlZW4gRW50aXR5VHlwZSBhbmQgQ29tcGxleFR5cGUuXHJcbiAgICB0aGlzLm5hdmlnYXRpb25Qcm9wZXJ0aWVzID0gW107XHJcbiAgICB0aGlzLmtleVByb3BlcnRpZXMgPSBbXTsgLy8gbWF5IGJlIHVzZWQgbGF0ZXIgdG8gZW5mb3JjZSB1bmlxdWVuZXNzIG9uIGFycmF5cyBvZiBjb21wbGV4dHlwZXMuXHJcbiAgICBpZiAoY29uZmlnLmRhdGFQcm9wZXJ0aWVzKSB7XHJcbiAgICAgIGFkZFByb3BlcnRpZXModGhpcywgY29uZmlnLmRhdGFQcm9wZXJ0aWVzLCBEYXRhUHJvcGVydHkpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgR2VuZXJhbCBwdXJwb3NlIHByb3BlcnR5IHNldCBtZXRob2RcclxuICA+ICAgICAgLy8gYXNzdW1lIGVtMSBpcyBhbiBFbnRpdHlNYW5hZ2VyXHJcbiAgPiAgICAgIGxldCBhZGRyZXNzdFR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQWRkcmVzc1wiKTtcclxuICA+ICAgICAgYWRkcmVzc1R5cGUuc2V0UHJvcGVydGllcygge1xyXG4gID4gICAgICAgICAgY3VzdG9tOiB7IGZvbzogNywgYmFyOiBcInRlc3RcIiB9XHJcbiAgPiAgICAgIH0pO1xyXG4gIEBwYXJhbSBjb25maWcgLSBDdXN0b20gY29uZmlnIG9iamVjdFxyXG4gIEBwYXJhbSBjb25maWcuY3VzdG9tIC0ge09iamVjdH1cclxuICAqKi9cclxuICBzZXRQcm9wZXJ0aWVzKGNvbmZpZzogeyBjdXN0b20/OiBPYmplY3QgfSkge1xyXG4gICAgYXNzZXJ0Q29uZmlnKGNvbmZpZylcclxuICAgICAgLndoZXJlUGFyYW0oXCJjdXN0b21cIikuaXNPcHRpb25hbCgpXHJcbiAgICAgIC5hcHBseUFsbCh0aGlzKTtcclxuICB9XHJcblxyXG5cclxuICBnZXRBbGxWYWxpZGF0b3JzKCkge1xyXG4gICAgLy8gQ29tcGxleFR5cGUgaW5oZXJpdGFuY2UgaXMgbm90IFlFVCBzdXBwb3J0ZWQuXHJcbiAgICByZXR1cm4gdGhpcy52YWxpZGF0b3JzO1xyXG4gIH1cclxuXHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgX2NyZWF0ZUluc3RhbmNlQ29yZShwYXJlbnQ6IFN0cnVjdHVyYWxPYmplY3QsIHBhcmVudFByb3BlcnR5OiBEYXRhUHJvcGVydHkpIHtcclxuICAgIGxldCBhQ3RvciA9IHRoaXMuZ2V0Q3RvcigpO1xyXG4gICAgbGV0IGluc3RhbmNlID0gbmV3IGFDdG9yKCkgYXMgQ29tcGxleE9iamVjdDtcclxuICAgIG5ldyBDb21wbGV4QXNwZWN0KGluc3RhbmNlLCBwYXJlbnQsIHBhcmVudFByb3BlcnR5KTtcclxuICAgIC8vIGluaXRpYWxpemF0aW9uIG9jY3VycyBkdXJpbmcgZWl0aGVyIGF0dGFjaCBvciBpbiBjcmVhdGVJbnN0YW5jZSBjYWxsLlxyXG4gICAgcmV0dXJuIGluc3RhbmNlO1xyXG4gIH1cclxuXHJcblxyXG4gIGFkZFByb3BlcnR5KGRhdGFQcm9wZXJ0eTogRGF0YVByb3BlcnR5KSB7XHJcbiAgICBhc3NlcnRQYXJhbShkYXRhUHJvcGVydHksIFwiZGF0YVByb3BlcnR5XCIpLmlzSW5zdGFuY2VPZihEYXRhUHJvcGVydHkpLmNoZWNrKCk7XHJcbiAgICByZXR1cm4gdGhpcy5fYWRkUHJvcGVydHlDb3JlKGRhdGFQcm9wZXJ0eSk7XHJcbiAgfVxyXG5cclxuICBnZXRQcm9wZXJ0aWVzKCk6IEVudGl0eVByb3BlcnR5W10ge1xyXG4gICAgcmV0dXJuIHRoaXMuZGF0YVByb3BlcnRpZXM7XHJcbiAgfVxyXG5cclxuICB0b0pTT04oKSB7XHJcbiAgICByZXR1cm4gY29yZS50b0pzb24odGhpcywge1xyXG4gICAgICBzaG9ydE5hbWU6IG51bGwsXHJcbiAgICAgIG5hbWVzcGFjZTogbnVsbCxcclxuICAgICAgaXNDb21wbGV4VHlwZTogbnVsbCxcclxuICAgICAgZGF0YVByb3BlcnRpZXM6IG51bGwsXHJcbiAgICAgIHZhbGlkYXRvcnM6IG51bGwsXHJcbiAgICAgIGN1c3RvbTogbnVsbFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxufVxyXG5Db21wbGV4VHlwZS5wcm90b3R5cGUuXyR0eXBlTmFtZSA9IFwiQ29tcGxleFR5cGVcIjtcclxuLyoqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgdGhpcyBjb21wbGV4VHlwZSAqL1xyXG5Db21wbGV4VHlwZS5wcm90b3R5cGUuY3JlYXRlSW5zdGFuY2UgPSBFbnRpdHlUeXBlLnByb3RvdHlwZS5jcmVhdGVFbnRpdHk7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIERhdGFQcm9wZXJ0eUNvbmZpZyB7XHJcbiAgbmFtZT86IHN0cmluZztcclxuICBuYW1lT25TZXJ2ZXI/OiBzdHJpbmc7XHJcbiAgZGF0YVR5cGU/OiBEYXRhVHlwZSB8IHN0cmluZyB8IENvbXBsZXhUeXBlO1xyXG4gIGNvbXBsZXhUeXBlTmFtZT86IHN0cmluZztcclxuICBpc051bGxhYmxlPzogYm9vbGVhbjtcclxuICBpc1NjYWxhcj86IGJvb2xlYW47IC8vIHdpbGwgYmUgZmFsc2UgZm9yIHNvbWUgTm9TUUwgZGF0YWJhc2VzLlxyXG4gIGRlZmF1bHRWYWx1ZT86IGFueTtcclxuICBpc1BhcnRPZktleT86IGJvb2xlYW47XHJcbiAgaXNVbm1hcHBlZD86IGJvb2xlYW47XHJcbiAgaXNTZXR0YWJsZT86IGJvb2xlYW47XHJcbiAgY29uY3VycmVuY3lNb2RlPzogc3RyaW5nO1xyXG4gIG1heExlbmd0aD86IG51bWJlcjtcclxuICB2YWxpZGF0b3JzPzogVmFsaWRhdG9yW107XHJcbiAgZGlzcGxheU5hbWU/OiBzdHJpbmc7XHJcbiAgZW51bVR5cGU/OiBhbnk7XHJcbiAgcmF3VHlwZU5hbWU/OiBzdHJpbmc7ICAvLyBvY2N1cnMgd2l0aCB1bmRlZmluZWQgZGF0YXR5cGVzXHJcbiAgY3VzdG9tPzogT2JqZWN0O1xyXG59XHJcblxyXG4vKipcclxuQSBEYXRhUHJvcGVydHkgZGVzY3JpYmVzIHRoZSBtZXRhZGF0YSBmb3IgYSBzaW5nbGUgcHJvcGVydHkgb2YgYW4gIFtbRW50aXR5VHlwZV1dIHRoYXQgY29udGFpbnMgc2ltcGxlIGRhdGEuXHJcblxyXG5JbnN0YW5jZXMgb2YgdGhlIERhdGFQcm9wZXJ0eSBjbGFzcyBhcmUgY29uc3RydWN0ZWQgYXV0b21hdGljYWxseSBkdXJpbmcgTWV0YWRhdGEgcmV0cmlldmFsLiBIb3dldmVyIGl0IGlzIGFsc28gcG9zc2libGUgdG8gY29uc3RydWN0IHRoZW1cclxuZGlyZWN0bHkgdmlhIHRoZSBjb25zdHJ1Y3Rvci5cclxuKiovXHJcbmV4cG9ydCBjbGFzcyBEYXRhUHJvcGVydHkge1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF8kdHlwZU5hbWU6IHN0cmluZzsgLy8gb24gcHJvdG9cclxuICAvKiogSXMgdGhpcyBhIERhdGFQcm9wZXJ0eT8gLSBhbHdheXMgdHJ1ZSBoZXJlLiBBbGxvd3MgcG9seW1vcnBoaWMgdHJlYXRtZW50IG9mIERhdGFQcm9wZXJ0aWVzIGFuZCBOYXZpZ2F0aW9uUHJvcGVydGllcy4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIGlzRGF0YVByb3BlcnR5ID0gdHJ1ZTtcclxuICAvKiogSXMgdGhpcyBhIE5hdmlnYXRpb25Qcm9wZXJ0eT8gLSBhbHdheXMgZmFsc2UgaGVyZS4gIEFsbG93cyBwb2x5bW9ycGhpYyB0cmVhdG1lbnQgb2YgRGF0YVByb3BlcnRpZXMgYW5kIE5hdmlnYXRpb25Qcm9wZXJ0aWVzLiBfX1JlYWQgT25seV9fICovXHJcbiAgaXNOYXZpZ2F0aW9uUHJvcGVydHkgPSBmYWxzZTtcclxuICAvKiogVGhlIG5hbWUgb2YgdGhpcyBwcm9wZXJ0eS4gX19SZWFkIE9ubHlfXyAgKiovXHJcbiAgbmFtZTogc3RyaW5nO1xyXG4gIC8qKiBUaGUgbmFtZSBvZiB0aGlzIHByb3BlcnR5IG9uIHRoZSBzZXJ2ZXIuIF9fUmVhZCBPbmx5X18gKiovXHJcbiAgbmFtZU9uU2VydmVyOiBzdHJpbmc7XHJcbiAgLyoqIFRoZSBbW0RhdGFUeXBlXV0gb2YgdGhpcyBwcm9wZXJ0eS4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIGRhdGFUeXBlOiBEYXRhVHlwZSB8IENvbXBsZXhUeXBlOyAvLyB0aGlzIHdpbGwgYmUgYSBjb21wbGV4VHlwZSB3aGVuIGRwIGlzIGEgY29tcGxleFByb3BlcnR5XHJcbiAgLyoqIFRoZSBuYW1lIG9mIHRoZSBbW0NvbXBsZXhUeXBlXV0gYXNzb2NpYXRlZCB3aXRoIHRoaXMgcHJvcGVydHk7IG1heSBiZSBudWxsLiBfX1JlYWQgT25seV9fICovXHJcbiAgY29tcGxleFR5cGVOYW1lOiBzdHJpbmc7XHJcbiAgLyoqIFRoZSBbW0NvbXBsZXhUeXBlXV0gYXNzb2NpYXRlZCB3aXRoIHRoaXMgcHJvcGVydHk7IG1heSBiZSB1bmRlZmluZWQuIF9fUmVhZCBPbmx5X18gKi9cclxuICBjb21wbGV4VHlwZT86IENvbXBsZXhUeXBlO1xyXG4gIC8qKiAgV2hldGhlciB0aGUgY29udGVudHMgb2YgdGhpcyBwcm9wZXJ0eSBpcyBhbiBpbnN0YW5jZSBvZiBhIFtbQ29tcGxleFR5cGVdXS4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIGlzQ29tcGxleFByb3BlcnR5OiBib29sZWFuO1xyXG4gIC8qKiBXaGV0aGVyIHRoaXMgcHJvcGVydHkgaXMgbnVsbGFibGUuIF9fUmVhZCBPbmx5X18gKi9cclxuICBpc051bGxhYmxlOiBib29sZWFuO1xyXG4gIC8qKiAgV2hldGhlciB0aGlzIHByb3BlcnR5IGlzIHNjYWxhciAoaS5lLiwgcmV0dXJucyBhIHNpbmdsZSB2YWx1ZSBhcyBvcHBvc2VkIHRvIGFuIGFycmF5KS4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIGlzU2NhbGFyOiBib29sZWFuOyAvLyB3aWxsIGJlIGZhbHNlIGZvciBzb21lIE5vU1FMIGRhdGFiYXNlcy5cclxuICAvKiogVGhlIGRlZmF1bHQgdmFsdWUgZm9yIHRoaXMgcHJvcGVydHkuIF9fUmVhZCBPbmx5X18gKi9cclxuICBkZWZhdWx0VmFsdWU6IGFueTtcclxuICAvKiogIFdoZXRoZXIgdGhpcyBwcm9wZXJ0eSBpcyBhICdrZXknIHByb3BlcnR5LiBfX1JlYWQgT25seV9fICovXHJcbiAgaXNQYXJ0T2ZLZXk6IGJvb2xlYW47XHJcbiAgLyoqIFdoZXRoZXIgdGhpcyBwcm9wZXJ0eSBpcyBhbiAndW5tYXBwZWQnIHByb3BlcnR5LiBfX1JlYWQgT25seV9fICovXHJcbiAgaXNVbm1hcHBlZDogYm9vbGVhbjtcclxuICAvKiogV2hldGhlciB0aGlzIHByb3BlcnR5IGlzICdzZXR0YWJsZScuIF9fUmVhZCBPbmx5X18gKi9cclxuICBpc1NldHRhYmxlOiBib29sZWFuO1xyXG4gIC8vIFRPRE86IGRvYyB0aGlzXHJcbiAgY29uY3VycmVuY3lNb2RlOiBzdHJpbmc7XHJcbiAgLyoqICBUaGUgbWF4aW11bSBsZW5ndGggZm9yIHRoZSB2YWx1ZSBvZiB0aGlzIHByb3BlcnR5LiBPbmx5IG1lYW5pbmdmdWwgZm9yIHN0cmluZ3MuIF9fUmVhZCBPbmx5X18gKi9cclxuICBtYXhMZW5ndGg/OiBudW1iZXI7XHJcbiAgLyoqIFRoZSBbW1ZhbGlkYXRvcl1dIGluc3RhbmNlcyB0aGF0IGFyZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBwcm9wZXJ0eS4gVmFsaWRhdG9ycyBjYW4gYmUgYWRkZWQgYW5kXHJcbiAgcmVtb3ZlZCBmcm9tIHRoaXMgY29sbGVjdGlvbi4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIHZhbGlkYXRvcnM6IFZhbGlkYXRvcltdO1xyXG4gIC8qKiBUaGUgZGlzcGxheSBuYW1lIG9mIHRoaXMgcHJvcGVydHkuIF9fUmVhZCBPbmx5X18gKi9cclxuICBkaXNwbGF5TmFtZTogc3RyaW5nO1xyXG4gIC8vIFRPRE86IGRvYyB0aGlzXHJcbiAgZW51bVR5cGU/OiBhbnk7XHJcbiAgLyoqIFRoZSByYXcgdHlwZSBuYW1lIG9mIHRoaXMgcHJvcGVydHkuIHdpbGwgb25seSBiZSBkZWZpbmVkIGZvciBwcm9wZXJ0aWVzIHdpdGggYSBEYXRhVHlwZSBvZiAnVW5kZWZpbmVkJyAqL1xyXG4gIHJhd1R5cGVOYW1lPzogc3RyaW5nOyAgLy8gb2NjdXJzIHdpdGggdW5kZWZpbmVkIGRhdGF0eXBlc1xyXG4gIC8qKiAgQSBmcmVlIGZvcm0gb2JqZWN0IHRoYXQgY2FuIGJlIHVzZWQgdG8gZGVmaW5lIGFueSBjdXN0b20gbWV0YWRhdGEgZm9yIHRoaXMgRGF0YVByb3BlcnR5LiBfX1JlYWQgT25seV9fICovXHJcbiAgY3VzdG9tPzogT2JqZWN0O1xyXG4gIC8vIFRPRE86IGRvYyB0aGlzXHJcbiAgaW52ZXJzZU5hdmlnYXRpb25Qcm9wZXJ0eT86IE5hdmlnYXRpb25Qcm9wZXJ0eTtcclxuICAvKipcclxuICBUaGUgbmF2aWdhdGlvbiBwcm9wZXJ0eSByZWxhdGVkIHRvIHRoaXMgcHJvcGVydHkuICBXaWxsIG9ubHkgYmUgc2V0IGlmIHRoaXMgaXMgYSBmb3JlaWduIGtleSBwcm9wZXJ0eS4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIHJlbGF0ZWROYXZpZ2F0aW9uUHJvcGVydHk/OiBOYXZpZ2F0aW9uUHJvcGVydHk7XHJcbiAgLyoqIFRoZSBwYXJlbnQgdHlwZSB0aGF0IHRoaXMgcHJvcGVydHkgYmVsb25ncyB0byAtIHdpbGwgYmUgZWl0aGVyIGEgW1tFbnRpdHlUeXBlXV0gb3IgYSBbW0NvbXBsZXhUeXBlXV0uIF9fUmVhZCBPbmx5X18gKi9cclxuICBwYXJlbnRUeXBlOiBTdHJ1Y3R1cmFsVHlwZTtcclxuICAvKiogUHJvcGVydHkgb24gdGhlIGJhc2UgdHlwZSB0aGF0IHRoaXMgcHJvcGVydHkgaXMgaW5oZXJpdGVkIGZyb20uIFdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvcGVydHkgaXMgbm90IG9uIHRoZSBiYXNlIHR5cGUuIF9fUmVhZCBPbmx5X18gKi9cclxuICBiYXNlUHJvcGVydHk/OiBEYXRhUHJvcGVydHk7XHJcblxyXG4gIC8qKiBEYXRhUHJvcGVydHkgY29uc3RydWN0b3JcclxuICA+ICAgICAgbGV0IGxhc3ROYW1lUHJvcCA9IG5ldyBEYXRhUHJvcGVydHkoIHtcclxuICA+ICAgICAgICAgIG5hbWU6IFwibGFzdE5hbWVcIixcclxuICA+ICAgICAgICAgIGRhdGFUeXBlOiBEYXRhVHlwZS5TdHJpbmcsXHJcbiAgPiAgICAgICAgICBpc051bGxhYmxlOiB0cnVlLFxyXG4gID4gICAgICAgICAgbWF4TGVuZ3RoOiAyMFxyXG4gID4gICAgICB9KTtcclxuICA+ICAgICAgLy8gYXNzdW1pbmcgcGVyc29uRW50aXR5VHlwZSBpcyBhIG5ld2x5IGNvbnN0cnVjdGVkIEVudGl0eVR5cGVcclxuICA+ICAgICAgcGVyc29uRW50aXR5VHlwZS5hZGRQcm9wZXJ0eShsYXN0TmFtZVByb3BlcnR5KTtcclxuICBAcGFyYW0gY29uZmlnIC0gQSBjb25maWd1cmF0aW9uIE9iamVjdCBvciBhIERhdGFQcm9wZXJ0eVxyXG4gICovXHJcbiAgY29uc3RydWN0b3IoY29uZmlnOiBEYXRhUHJvcGVydHlDb25maWcgfCBEYXRhUHJvcGVydHkpIHtcclxuICAgIGFzc2VydENvbmZpZyhjb25maWcpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwibmFtZVwiKS5pc1N0cmluZygpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAud2hlcmVQYXJhbShcIm5hbWVPblNlcnZlclwiKS5pc1N0cmluZygpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAud2hlcmVQYXJhbShcImRhdGFUeXBlXCIpLmlzRW51bU9mKERhdGFUeXBlKS5pc09wdGlvbmFsKCkub3IoKS5pc1N0cmluZygpLm9yKCkuaXNJbnN0YW5jZU9mKENvbXBsZXhUeXBlKVxyXG4gICAgICAud2hlcmVQYXJhbShcImNvbXBsZXhUeXBlTmFtZVwiKS5pc09wdGlvbmFsKClcclxuICAgICAgLndoZXJlUGFyYW0oXCJpc051bGxhYmxlXCIpLmlzQm9vbGVhbigpLmlzT3B0aW9uYWwoKS53aXRoRGVmYXVsdCh0cnVlKVxyXG4gICAgICAud2hlcmVQYXJhbShcImlzU2NhbGFyXCIpLmlzT3B0aW9uYWwoKS53aXRoRGVmYXVsdCh0cnVlKS8vIHdpbGwgYmUgZmFsc2UgZm9yIHNvbWUgTm9TUUwgZGF0YWJhc2VzLlxyXG4gICAgICAud2hlcmVQYXJhbShcImRlZmF1bHRWYWx1ZVwiKS5pc09wdGlvbmFsKClcclxuICAgICAgLndoZXJlUGFyYW0oXCJpc1BhcnRPZktleVwiKS5pc0Jvb2xlYW4oKS5pc09wdGlvbmFsKClcclxuICAgICAgLndoZXJlUGFyYW0oXCJpc1VubWFwcGVkXCIpLmlzQm9vbGVhbigpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAud2hlcmVQYXJhbShcImlzU2V0dGFibGVcIikuaXNCb29sZWFuKCkuaXNPcHRpb25hbCgpLndpdGhEZWZhdWx0KHRydWUpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwiY29uY3VycmVuY3lNb2RlXCIpLmlzU3RyaW5nKCkuaXNPcHRpb25hbCgpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwibWF4TGVuZ3RoXCIpLmlzTnVtYmVyKCkuaXNPcHRpb25hbCgpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwidmFsaWRhdG9yc1wiKS5pc0luc3RhbmNlT2YoVmFsaWRhdG9yKS5pc0FycmF5KCkuaXNPcHRpb25hbCgpLndpdGhEZWZhdWx0KFtdKVxyXG4gICAgICAud2hlcmVQYXJhbShcImRpc3BsYXlOYW1lXCIpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAud2hlcmVQYXJhbShcImVudW1UeXBlXCIpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAud2hlcmVQYXJhbShcInJhd1R5cGVOYW1lXCIpLmlzT3B0aW9uYWwoKSAvLyBvY2N1cnMgd2l0aCB1bmRlZmluZWQgZGF0YXR5cGVzXHJcbiAgICAgIC53aGVyZVBhcmFtKFwiY3VzdG9tXCIpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAuYXBwbHlBbGwodGhpcyk7XHJcbiAgICBsZXQgaGFzTmFtZSA9ICEhKHRoaXMubmFtZSB8fCB0aGlzLm5hbWVPblNlcnZlcik7XHJcbiAgICBpZiAoIWhhc05hbWUpIHtcclxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQSBEYXRhUHJvcGVydHkgbXVzdCBiZSBpbnN0YW50aWF0ZWQgd2l0aCBlaXRoZXIgYSAnbmFtZScgb3IgYSAnbmFtZU9uU2VydmVyJyBwcm9wZXJ0eVwiKTtcclxuICAgIH1cclxuICAgIC8vIG5hbWUvbmFtZU9uU2VydmVyIGlzIHJlc29sdmVkIGxhdGVyIHdoZW4gYSBtZXRhZGF0YVN0b3JlIGlzIGF2YWlsYWJsZS5cclxuXHJcbiAgICBpZiAodGhpcy5jb21wbGV4VHlwZU5hbWUpIHtcclxuICAgICAgdGhpcy5pc0NvbXBsZXhQcm9wZXJ0eSA9IHRydWU7XHJcbiAgICAgIC8vIHRoaXMuZGF0YVR5cGUgPSBudWxsOyAvLyBUT0RPOiB3b3VsZCBsaWtlIHRvIHJlbW92ZSB0aGlzIGxpbmUgYmVjYXVzZSBkYXRhVHlwZSB3aWxsIGJlIHNldCBsYXRlci5cclxuICAgIH0gZWxzZSBpZiAodHlwZW9mICh0aGlzLmRhdGFUeXBlKSA9PT0gXCJzdHJpbmdcIikge1xyXG4gICAgICBsZXQgZHQgPSBEYXRhVHlwZS5mcm9tTmFtZSh0aGlzLmRhdGFUeXBlKTtcclxuICAgICAgaWYgKCFkdCkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlVuYWJsZSB0byBmaW5kIGEgRGF0YVR5cGUgZW51bWVyYXRpb24gYnkgdGhlIG5hbWUgb2Y6IFwiICsgdGhpcy5kYXRhVHlwZSk7XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy5kYXRhVHlwZSA9IGR0O1xyXG4gICAgfSBlbHNlIGlmICghdGhpcy5kYXRhVHlwZSkge1xyXG4gICAgICB0aGlzLmRhdGFUeXBlID0gRGF0YVR5cGUuU3RyaW5nO1xyXG4gICAgfVxyXG5cclxuICAgIC8vID09IGFzIG9wcG9zZWQgdG8gPT09IGlzIGRlbGliZXJhdGUgaGVyZS5cclxuICAgIGlmICh0aGlzLmRlZmF1bHRWYWx1ZSA9PSBudWxsKSB7XHJcbiAgICAgIGlmICh0aGlzLmlzTnVsbGFibGUpIHtcclxuICAgICAgICB0aGlzLmRlZmF1bHRWYWx1ZSA9IG51bGw7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgaWYgKHRoaXMuaXNDb21wbGV4UHJvcGVydHkpIHtcclxuICAgICAgICAgIC8vIHdoYXQgdG8gZG8/IC0gc2hvdWxkbid0IGhhcHBlbiBmcm9tIEVGIC0gYnV0IG90aGVyd2lzZSA/Pz9cclxuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuZGF0YVR5cGUgPT09IERhdGFUeXBlLkJpbmFyeSkge1xyXG4gICAgICAgICAgdGhpcy5kZWZhdWx0VmFsdWUgPSBcIkFBQUFBQUFBSjNVPVwiOyAvLyBoYWNrIGZvciBhbGwgYmluYXJ5IGZpZWxkcyBidXQgdmFsdWUgaXMgc3BlY2lmaWNhbGx5IHZhbGlkIGZvciB0aW1lc3RhbXAgZmllbGRzIC0gYXJiaXRyYXJ5IHZhbGlkIDggYnl0ZSBiYXNlNjQgdmFsdWUuXHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRoaXMuZGVmYXVsdFZhbHVlID0gKHRoaXMuZGF0YVR5cGUgYXMgYW55KS5kZWZhdWx0VmFsdWU7XHJcbiAgICAgICAgICBjb25zdCBtc2cgPSBcIkEgbm9ubnVsbGFibGUgRGF0YVByb3BlcnR5IGNhbm5vdCBoYXZlIGEgbnVsbCBkZWZhdWx0VmFsdWUuIE5hbWU6IFwiICsgKHRoaXMubmFtZSB8fCB0aGlzLm5hbWVPblNlcnZlcik7XHJcbiAgICAgICAgICBpZiAodGhpcy5kZWZhdWx0VmFsdWUgPT09IG51bGwpIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKG1zZyk7ICAvLyBpZiBkZWZhdWx0VmFsdWUgaXMgZXhwbGljaXR5IHNldCB0byBudWxsLCB0aGF0J3MgYW4gZXJyb3JcclxuICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5kZWZhdWx0VmFsdWUgPT0gbnVsbCkge1xyXG4gICAgICAgICAgICBjb25zb2xlLndhcm4obXNnKTsgIC8vIGlmIGRlZmF1bHRWYWx1ZSBpcyBub3Qgc2V0LCB0aGF0J3MgYSB3YXJuaW5nXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9IGVsc2UgaWYgKCh0aGlzLmRhdGFUeXBlIGFzIGFueSkuaXNOdW1lcmljKSB7XHJcbiAgICAgIC8vIGluIGNhc2UgdGhlIGRlZmF1bHRWYWx1ZSBjb21lcyBpbiBhcyBhIHN0cmluZyAoIHdoaWNoIGl0IGRvZXMgaW4gRUY2KS5cclxuICAgICAgaWYgKHR5cGVvZiAodGhpcy5kZWZhdWx0VmFsdWUpID09PSBcInN0cmluZ1wiKSB7XHJcbiAgICAgICAgdGhpcy5kZWZhdWx0VmFsdWUgPSBwYXJzZUZsb2F0KHRoaXMuZGVmYXVsdFZhbHVlKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLmlzQ29tcGxleFByb3BlcnR5KSB7XHJcbiAgICAgIHRoaXMuaXNTY2FsYXIgPSB0aGlzLmlzU2NhbGFyID09IG51bGwgfHwgdGhpcy5pc1NjYWxhciA9PT0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgfVxyXG5cclxuICBzdGF0aWMgZ2V0UmF3VmFsdWVGcm9tU2VydmVyKHJhd0VudGl0eTogT2JqZWN0LCBkcDogRGF0YVByb3BlcnR5KSB7XHJcbiAgICBpZiAoZHAuaXNVbm1hcHBlZCkge1xyXG4gICAgICByZXR1cm4gcmF3RW50aXR5W2RwLm5hbWVPblNlcnZlciB8fCBkcC5uYW1lXTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxldCB2YWwgPSByYXdFbnRpdHlbZHAubmFtZU9uU2VydmVyXTtcclxuICAgICAgcmV0dXJuIHZhbCAhPT0gdW5kZWZpbmVkID8gdmFsIDogZHAuZGVmYXVsdFZhbHVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgc3RhdGljIGdldFJhd1ZhbHVlRnJvbUNsaWVudChyYXdFbnRpdHk6IE9iamVjdCwgZHA6IERhdGFQcm9wZXJ0eSkge1xyXG4gICAgbGV0IHZhbCA9IHJhd0VudGl0eVtkcC5uYW1lXTtcclxuICAgIHJldHVybiB2YWwgIT09IHVuZGVmaW5lZCA/IHZhbCA6IGRwLmRlZmF1bHRWYWx1ZTtcclxuICB9XHJcblxyXG4gIHJlc29sdmVQcm9wZXJ0eShwcm9wTmFtZTogc3RyaW5nKSB7XHJcbiAgICBsZXQgcmVzdWx0ID0gdGhpc1twcm9wTmFtZV07XHJcbiAgICBsZXQgYmFzZVByb3AgPSB0aGlzLmJhc2VQcm9wZXJ0eTtcclxuICAgIHdoaWxlIChyZXN1bHQgPT0gdW5kZWZpbmVkICYmIGJhc2VQcm9wICE9IG51bGwpIHtcclxuICAgICAgcmVzdWx0ID0gYmFzZVByb3BbcHJvcE5hbWVdO1xyXG4gICAgICBiYXNlUHJvcCA9IGJhc2VQcm9wLmJhc2VQcm9wZXJ0eTtcclxuICAgIH1cclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfVxyXG5cclxuICBmb3JtYXROYW1lKCkge1xyXG4gICAgcmV0dXJuIHRoaXMucGFyZW50VHlwZS5uYW1lICsgXCItLVwiICsgdGhpcy5uYW1lO1xyXG4gIH1cclxuXHJcblxyXG4gIC8qKlxyXG4gIEdlbmVyYWwgcHVycG9zZSBwcm9wZXJ0eSBzZXQgbWV0aG9kXHJcbiAgPiAgICAgIC8vIGFzc3VtZSBlbTEgaXMgYW4gRW50aXR5TWFuYWdlclxyXG4gID4gICAgICBsZXQgcHJvcCA9IG15RW50aXR5VHlwZS5nZXRQcm9wZXJ0eShcIm15UHJvcGVydHlcIik7XHJcbiAgPiAgICAgIHByb3Auc2V0UHJvcGVydGllcygge1xyXG4gID4gICAgICAgICAgY3VzdG9tOiB7IGZvbzogNywgYmFyOiBcInRlc3RcIiB9XHJcbiAgPiAgICAgIH0pO1xyXG4gIEBwYXJhbSBjb25maWcgLSBBIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gICoqL1xyXG4gIHNldFByb3BlcnRpZXMoY29uZmlnOiB7IGRpc3BsYXlOYW1lPzogc3RyaW5nLCBjdXN0b20/OiBPYmplY3QgfSkge1xyXG4gICAgYXNzZXJ0Q29uZmlnKGNvbmZpZylcclxuICAgICAgLndoZXJlUGFyYW0oXCJkaXNwbGF5TmFtZVwiKS5pc09wdGlvbmFsKClcclxuICAgICAgLndoZXJlUGFyYW0oXCJjdXN0b21cIikuaXNPcHRpb25hbCgpXHJcbiAgICAgIC5hcHBseUFsbCh0aGlzKTtcclxuICB9XHJcblxyXG4gIGdldEFsbFZhbGlkYXRvcnMoKSB7XHJcbiAgICBsZXQgdmFsaWRhdG9ycyA9IHRoaXMudmFsaWRhdG9ycy5zbGljZSgwKTtcclxuICAgIGxldCBiYXNlUHJvcCA9IHRoaXMuYmFzZVByb3BlcnR5O1xyXG4gICAgd2hpbGUgKGJhc2VQcm9wKSB7XHJcbiAgICAgIHZhbGlkYXRvcnMucHVzaC5hcHBseSh2YWxpZGF0b3JzLCBiYXNlUHJvcC52YWxpZGF0b3JzKTtcclxuICAgICAgYmFzZVByb3AgPSBiYXNlUHJvcC5iYXNlUHJvcGVydHk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdmFsaWRhdG9ycztcclxuICB9XHJcblxyXG4gIHRvSlNPTigpIHtcclxuICAgIC8vIGRvIG5vdCBzZXJpYWxpemUgZGF0YVR5cGVzIHRoYXQgYXJlIGNvbXBsZXhUeXBlc1xyXG4gICAgcmV0dXJuIGNvcmUudG9Kc29uKHRoaXMsIHtcclxuICAgICAgbmFtZTogbnVsbCxcclxuICAgICAgZGF0YVR5cGU6IGZ1bmN0aW9uICh2OiBhbnkpIHtcclxuICAgICAgICByZXR1cm4gKHYgJiYgdiBpbnN0YW5jZW9mIERhdGFUeXBlKSA/IHYubmFtZSA6IHVuZGVmaW5lZDtcclxuICAgICAgfSwgLy8gZG8gbm90IHNlcmlhbGl6ZSBkYXRhVHlwZXMgdGhhdCBhcmUgY29tcGxleFR5cGVzXHJcbiAgICAgIGNvbXBsZXhUeXBlTmFtZTogbnVsbCxcclxuICAgICAgaXNOdWxsYWJsZTogdHJ1ZSxcclxuICAgICAgZGVmYXVsdFZhbHVlOiBudWxsLFxyXG4gICAgICBpc1BhcnRPZktleTogZmFsc2UsXHJcbiAgICAgIGlzVW5tYXBwZWQ6IGZhbHNlLFxyXG4gICAgICBpc1NldHRhYmxlOiB0cnVlLFxyXG4gICAgICBjb25jdXJyZW5jeU1vZGU6IG51bGwsXHJcbiAgICAgIG1heExlbmd0aDogbnVsbCxcclxuICAgICAgdmFsaWRhdG9yczogbnVsbCxcclxuICAgICAgZGlzcGxheU5hbWU6IG51bGwsXHJcbiAgICAgIGVudW1UeXBlOiBudWxsLFxyXG4gICAgICByYXdUeXBlTmFtZTogbnVsbCxcclxuICAgICAgaXNTY2FsYXI6IHRydWUsXHJcbiAgICAgIGN1c3RvbTogbnVsbFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBzdGF0aWMgZnJvbUpTT04oanNvbjogYW55KSB7XHJcbiAgICBqc29uLmRhdGFUeXBlID0gRGF0YVR5cGUuZnJvbU5hbWUoanNvbi5kYXRhVHlwZSk7XHJcbiAgICAvLyBQYXJzZSBkZWZhdWx0IHZhbHVlIGludG8gY29ycmVjdCBkYXRhIHR5cGUuIChkYXRlVGltZSBpbnN0YW5jZXMgcmVxdWlyZSBleHRyYSB3b3JrIHRvIGRlc2VyaWFsaXplIHByb3Blcmx5LilcclxuICAgIGlmIChqc29uLmRlZmF1bHRWYWx1ZSAmJiBqc29uLmRhdGFUeXBlICYmIGpzb24uZGF0YVR5cGUucGFyc2UpIHtcclxuICAgICAganNvbi5kZWZhdWx0VmFsdWUgPSBqc29uLmRhdGFUeXBlLnBhcnNlKGpzb24uZGVmYXVsdFZhbHVlLCB0eXBlb2YganNvbi5kZWZhdWx0VmFsdWUpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChqc29uLnZhbGlkYXRvcnMpIHtcclxuICAgICAganNvbi52YWxpZGF0b3JzID0ganNvbi52YWxpZGF0b3JzLm1hcChWYWxpZGF0b3IuZnJvbUpTT04pO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBuZXcgRGF0YVByb3BlcnR5KGpzb24pO1xyXG4gIH1cclxuXHJcbn1cclxuRGF0YVByb3BlcnR5LnByb3RvdHlwZS5fJHR5cGVOYW1lID0gXCJEYXRhUHJvcGVydHlcIjtcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgTmF2aWdhdGlvblByb3BlcnR5Q29uZmlnIHtcclxuICBuYW1lPzogc3RyaW5nO1xyXG4gIG5hbWVPblNlcnZlcj86IHN0cmluZztcclxuICBlbnRpdHlUeXBlTmFtZT86IHN0cmluZztcclxuICBpc1NjYWxhcj86IGJvb2xlYW47XHJcbiAgYXNzb2NpYXRpb25OYW1lPzogc3RyaW5nO1xyXG4gIGZvcmVpZ25LZXlOYW1lcz86IHN0cmluZ1tdO1xyXG4gIGZvcmVpZ25LZXlOYW1lc09uU2VydmVyPzogc3RyaW5nW107XHJcbiAgaW52Rm9yZWlnbktleU5hbWVzPzogc3RyaW5nW107XHJcbiAgaW52Rm9yZWlnbktleU5hbWVzT25TZXJ2ZXI/OiBzdHJpbmdbXTtcclxuICB2YWxpZGF0b3JzPzogVmFsaWRhdG9yW107XHJcbiAgZGlzcGxheU5hbWU/OiBzdHJpbmc7XHJcbiAgY3VzdG9tPzogT2JqZWN0O1xyXG59XHJcblxyXG4vKiogICBBIE5hdmlnYXRpb25Qcm9wZXJ0eSBkZXNjcmliZXMgdGhlIG1ldGFkYXRhIGZvciBhIHNpbmdsZSBwcm9wZXJ0eSBvZiBhbiBbW0VudGl0eVR5cGVdXSB0aGF0IHJldHVybiBpbnN0YW5jZXMgb2Ygb3RoZXIgRW50aXR5VHlwZXMuXHJcblxyXG5JbnN0YW5jZXMgb2YgdGhlIE5hdmlnYXRpb25Qcm9wZXJ0eSBjbGFzcyBhcmUgY29uc3RydWN0ZWQgYXV0b21hdGljYWxseSBkdXJpbmcgTWV0YWRhdGEgcmV0cmlldmFsLiAgIEhvd2V2ZXIgaXQgaXMgYWxzbyBwb3NzaWJsZSB0byBjb25zdHJ1Y3QgdGhlbVxyXG5kaXJlY3RseSB2aWEgdGhlIGNvbnN0cnVjdG9yLlxyXG4qKi9cclxuZXhwb3J0IGNsYXNzIE5hdmlnYXRpb25Qcm9wZXJ0eSB7XHJcbiAgLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbiAgXyR0eXBlTmFtZTogc3RyaW5nO1xyXG4gIC8qKiBJcyB0aGlzIGEgRGF0YVByb3BlcnR5PyAtIGFsd2F5cyBmYWxzZSBoZXJlIFxyXG4gIEFsbG93cyBwb2x5bW9ycGhpYyB0cmVhdG1lbnQgb2YgRGF0YVByb3BlcnRpZXMgYW5kIE5hdmlnYXRpb25Qcm9wZXJ0aWVzLiBfX1JlYWQgT25seV9fICovXHJcbiAgaXNEYXRhUHJvcGVydHkgPSBmYWxzZTtcclxuICAvKiogSXMgdGhpcyBhIE5hdmlnYXRpb25Qcm9wZXJ0eT8gLSBhbHdheXMgdHJ1ZSBoZXJlXHJcbiAgQWxsb3dzIHBvbHltb3JwaGljIHRyZWF0bWVudCBvZiBEYXRhUHJvcGVydGllcyBhbmQgTmF2aWdhdGlvblByb3BlcnRpZXMuIF9fUmVhZCBPbmx5X18gKi9cclxuICBpc05hdmlnYXRpb25Qcm9wZXJ0eSA9IHRydWU7XHJcblxyXG4gIGZvcm1hdE5hbWUgPSBEYXRhUHJvcGVydHkucHJvdG90eXBlLmZvcm1hdE5hbWU7XHJcbiAgZ2V0QWxsVmFsaWRhdG9ycyA9IERhdGFQcm9wZXJ0eS5wcm90b3R5cGUuZ2V0QWxsVmFsaWRhdG9ycztcclxuICByZXNvbHZlUHJvcGVydHkgPSBEYXRhUHJvcGVydHkucHJvdG90eXBlLnJlc29sdmVQcm9wZXJ0eTtcclxuXHJcbiAgLyoqIFRoZSBbW0VudGl0eVR5cGVdXSByZXR1cm5lZCBieSB0aGlzIHByb3BlcnR5LiBfX1JlYWQgT25seV9fICovXHJcbiAgZW50aXR5VHlwZTogRW50aXR5VHlwZTtcclxuICAvKiogVGhlIG5hbWUgb2YgdGhlIFtbRW50aXR5VHlwZV1dIHJldHVybmVkIGJ5IHRoaXMgcHJvcGVydHkuIF9fUmVhZCBPbmx5X18gKi9cclxuICBlbnRpdHlUeXBlTmFtZTogc3RyaW5nO1xyXG4gIC8qKiBUaGUgW1tFbnRpdHlUeXBlXV0gdGhhdCB0aGlzIHByb3BlcnR5IGJlbG9uZ3MgdG8uICggc2FtZSBhcyBlbnRpdHlUeXBlKS4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIHBhcmVudFR5cGU6IEVudGl0eVR5cGU7IC8vID8/IHNhbWUgYXMgZW50aXR5VHlwZVxyXG4gIC8qKiBUaGUgW1tFbnRpdHlUeXBlXV0gdGhhdCB0aGlzIHByb3BlcnR5IGJlbG9uZ3MgdG8uICggc2FtZSBhcyBlbnRpdHlUeXBlKS4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIHBhcmVudEVudGl0eVR5cGU6IEVudGl0eVR5cGU7IC8vID8/IHNhbWUgYXMgYWJvdmVcclxuICAvKiogUHJvcGVydHkgb24gdGhlIGJhc2UgdHlwZSB0aGF0IHRoaXMgcHJvcGVydHkgaXMgaW5oZXJpdGVkIGZyb20uIFdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvcGVydHkgaXMgbm90IG9uIHRoZSBiYXNlIHR5cGUuIF9fUmVhZCBPbmx5X18gKi9cclxuICBiYXNlUHJvcGVydHk/OiBOYXZpZ2F0aW9uUHJvcGVydHk7XHJcbiAgLyoqIFRoZSBpbnZlcnNlIG9mIHRoaXMgTmF2aWdhdGlvblByb3BlcnR5LiAgVGhlIE5hdmlnYXRpb25Qcm9wZXJ0eSB0aGF0IHJlcHJlc2VudHMgYSBuYXZpZ2F0aW9uIGluIHRoZSBvcHBvc2l0ZSBkaXJlY3Rpb25cclxuICB0byB0aGlzIE5hdmlnYXRpb25Qcm9wZXJ0eS4gTWF5IGJlIHVuZGVmaW5lZCBmb3IgYSB1bmRpcmVjdGlvbmFsIE5hdmlnYXRpb25Qcm9wZXJ0eS4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIHByaXZhdGUgX2ludmVyc2U/OiBOYXZpZ2F0aW9uUHJvcGVydHk7XHJcbiAgLyoqIFRoZSBuYW1lIG9mIHRoaXMgcHJvcGVydHkuIF9fUmVhZCBPbmx5X18gKi9cclxuICBuYW1lOiBzdHJpbmc7XHJcbiAgLyoqIFRoZSBuYW1lIG9mIHRoaXMgcHJvcGVydHkgb24gdGhlIHNlcnZlci4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIG5hbWVPblNlcnZlcjogc3RyaW5nO1xyXG4gIC8qKlxyXG4gIFdoZXRoZXIgdGhpcyBwcm9wZXJ0eSByZXR1cm5zIGEgc2luZ2xlIGVudGl0eSBhcyBvcHBvc2VkIHRvICBhbiBhcnJheSBvZiBlbnRpdGllcy4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIGlzU2NhbGFyOiBib29sZWFuO1xyXG4gIC8qKiBUaGUgbmFtZSBvZiB0aGUgYXNzb2NpYXRpb24gdG8gd2hpY2ggdGhhdCB0aGlzIHByb3BlcnR5IGJlbG9uZ3MuICBUaGlzIGFzc29jaWF0aW9uTmFtZSB3aWxsIGJlIHNoYXJlZCB3aXRoIHRoaXNcclxuICBwcm9wZXJ0aWVzICdpbnZlcnNlJy4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIGFzc29jaWF0aW9uTmFtZTogc3RyaW5nO1xyXG4gIC8qKiBUaGUgbmFtZXMgb2YgdGhlIGZvcmVpZ24ga2V5IERhdGFQcm9wZXJ0aWVzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIE5hdmlnYXRpb25Qcm9wZXJ0eS4gVGhlcmUgd2lsbCB1c3VhbGx5IG9ubHkgYmUgYSBzaW5nbGUgRGF0YVByb3BlcnR5IGFzc29jaWF0ZWRcclxuICB3aXRoIGEgTmF2aWdhdGlvbiBwcm9wZXJ0eSBleGNlcHQgaW4gdGhlIGNhc2Ugb2YgZW50aXRpZXMgd2l0aCBtdWx0aXBhcnQga2V5cy4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIGZvcmVpZ25LZXlOYW1lczogc3RyaW5nW107XHJcbiAgLyoqIFRoZSBzZXJ2ZXIgc2lkZSBuYW1lcyBvZiB0aGUgZm9yZWlnbiBrZXkgRGF0YVByb3BlcnRpZXMgYXNzb2NpYXRlZCB3aXRoIHRoaXMgTmF2aWdhdGlvblByb3BlcnR5LiBUaGVyZSB3aWxsIHVzdWFsbHkgb25seSBiZSBhIHNpbmdsZSBEYXRhUHJvcGVydHkgYXNzb2NpYXRlZFxyXG4gIHdpdGggYSBOYXZpZ2F0aW9uIHByb3BlcnR5IGV4Y2VwdCBpbiB0aGUgY2FzZSBvZiBlbnRpdGllcyB3aXRoIG11bHRpcGFydCBrZXlzLiBfX1JlYWQgT25seV9fICovXHJcbiAgZm9yZWlnbktleU5hbWVzT25TZXJ2ZXI6IHN0cmluZ1tdO1xyXG4gIC8qKiBUaGUgbmFtZXMgb2YgdGhlIGZvcmVpZ24ga2V5IERhdGFQcm9wZXJ0aWVzIGF0IHRoZSBvdGhlciBlbmQgb2YgdGhlIHJlbGF0aW9uc2hpcC4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIGludkZvcmVpZ25LZXlOYW1lczogc3RyaW5nW107XHJcbiAgLyoqIFRoZSBzZXJ2ZXIgc2lkZSBuYW1lcyBvZiB0aGUgZm9yZWlnbiBrZXkgRGF0YVByb3BlcnRpZXMgYXQgdGhlIG90aGVyIGVuZCBvZiB0aGUgcmVsYXRpb25zaGlwLiBfX1JlYWQgT25seV9fICovXHJcbiAgaW52Rm9yZWlnbktleU5hbWVzT25TZXJ2ZXI6IHN0cmluZ1tdO1xyXG4gIC8qKiBUaGUgJ2ZvcmVpZ24ga2V5JyBEYXRhUHJvcGVydGllcyBhc3NvY2lhdGVkIHdpdGggdGhpcyBOYXZpZ2F0aW9uUHJvcGVydHkuIFRoZXJlIHdpbGwgdXN1YWxseSBvbmx5IGJlIGEgc2luZ2xlIERhdGFQcm9wZXJ0eSBhc3NvY2lhdGVkXHJcbiAgd2l0aCBhIE5hdmlnYXRpb24gcHJvcGVydHkgZXhjZXB0IGluIHRoZSBjYXNlIG9mIGVudGl0aWVzIHdpdGggbXVsdGlwYXJ0IGtleXMuIF9fUmVhZCBPbmx5X18gKi9cclxuICByZWxhdGVkRGF0YVByb3BlcnRpZXM6IERhdGFQcm9wZXJ0eVtdO1xyXG4gIC8qKiBUaGUgW1tWYWxpZGF0b3JdXSBpbnN0YW5jZXMgdGhhdCBhcmUgYXNzb2NpYXRlZCB3aXRoIHRoaXMgcHJvcGVydHkuIFZhbGlkYXRvcnMgY2FuIGJlIGFkZGVkIGFuZFxyXG4gIHJlbW92ZWQgZnJvbSB0aGlzIGNvbGxlY3Rpb24uIF9fUmVhZCBPbmx5X18gKi9cclxuICB2YWxpZGF0b3JzOiBWYWxpZGF0b3JbXTtcclxuICAvKiogVGhlIGRpc3BsYXkgbmFtZSBvZiB0aGlzIHByb3BlcnR5LiBfX1JlYWQgT25seV9fICovXHJcbiAgZGlzcGxheU5hbWU6IHN0cmluZztcclxuICBpc1VubWFwcGVkOiBib29sZWFuO1xyXG4gIC8qKiBBIGZyZWUgZm9ybSBvYmplY3QgdGhhdCBjYW4gYmUgdXNlZCB0byBkZWZpbmUgYW55IGN1c3RvbSBtZXRhZGF0YSBmb3IgdGhpcyBOYXZpZ2F0aW9uUHJvcGVydHkuICAgKiovXHJcbiAgY3VzdG9tOiBPYmplY3Q7XHJcblxyXG4gIC8qKiBOYXZpZ2F0aW9uUHJvcGVydHkgY29uc3RydWN0b3JcclxuICA+ICAgICAgbGV0IGhvbWVBZGRyZXNzUHJvcCA9IG5ldyBOYXZpZ2F0aW9uUHJvcGVydHkoIHtcclxuICA+ICAgICAgICAgIG5hbWU6IFwiaG9tZUFkZHJlc3NcIixcclxuICA+ICAgICAgICAgIGVudGl0eVR5cGVOYW1lOiBcIkFkZHJlc3M6I215TmFtZXNwYWNlXCIsXHJcbiAgPiAgICAgICAgICBpc1NjYWxhcjogdHJ1ZSxcclxuICA+ICAgICAgICAgIGFzc29jaWF0aW9uTmFtZTogXCJhZGRyZXNzX3BlcnNvblwiLFxyXG4gID4gICAgICAgICAgZm9yZWlnbktleU5hbWVzOiBbXCJob21lQWRkcmVzc0lkXCJdXHJcbiAgPiAgICAgIH0pO1xyXG4gID4gICAgICBsZXQgaG9tZUFkZHJlc3NJZFByb3AgPSBuZXcgRGF0YVByb3BlcnR5KCB7XHJcbiAgPiAgICAgICAgICBuYW1lOiBcImhvbWVBZGRyZXNzSWRcIlxyXG4gID4gICAgICAgICAgZGF0YVR5cGU6IERhdGFUeXBlLkludGVnZXJcclxuICA+ICAgICAgfSk7XHJcbiAgPiAgICAgIC8vIGFzc3VtaW5nIHBlcnNvbkVudGl0eVR5cGUgaXMgYSBuZXdseSBjb25zdHJ1Y3RlZCBFbnRpdHlUeXBlXHJcbiAgPiAgICAgIHBlcnNvbkVudGl0eVR5cGUuYWRkUHJvcGVydHkoaG9tZUFkZHJlc3NQcm9wKTtcclxuICA+ICAgICAgcGVyc29uRW50aXR5VHlwZS5hZGRQcm9wZXJ0eShob21lQWRkcmVzc0lkUHJvcCk7XHJcbiAgQHBhcmFtIGNvbmZpZyAtIEEgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAgKiovXHJcbiAgY29uc3RydWN0b3IoY29uZmlnOiBOYXZpZ2F0aW9uUHJvcGVydHlDb25maWcpIHtcclxuICAgIGFzc2VydENvbmZpZyhjb25maWcpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwibmFtZVwiKS5pc1N0cmluZygpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAud2hlcmVQYXJhbShcIm5hbWVPblNlcnZlclwiKS5pc1N0cmluZygpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAud2hlcmVQYXJhbShcImVudGl0eVR5cGVOYW1lXCIpLmlzU3RyaW5nKClcclxuICAgICAgLndoZXJlUGFyYW0oXCJpc1NjYWxhclwiKS5pc0Jvb2xlYW4oKS5pc09wdGlvbmFsKCkud2l0aERlZmF1bHQodHJ1ZSlcclxuICAgICAgLndoZXJlUGFyYW0oXCJhc3NvY2lhdGlvbk5hbWVcIikuaXNTdHJpbmcoKS5pc09wdGlvbmFsKClcclxuICAgICAgLndoZXJlUGFyYW0oXCJmb3JlaWduS2V5TmFtZXNcIikuaXNBcnJheSgpLmlzU3RyaW5nKCkuaXNPcHRpb25hbCgpLndpdGhEZWZhdWx0KFtdKVxyXG4gICAgICAud2hlcmVQYXJhbShcImZvcmVpZ25LZXlOYW1lc09uU2VydmVyXCIpLmlzQXJyYXkoKS5pc1N0cmluZygpLmlzT3B0aW9uYWwoKS53aXRoRGVmYXVsdChbXSlcclxuICAgICAgLndoZXJlUGFyYW0oXCJpbnZGb3JlaWduS2V5TmFtZXNcIikuaXNBcnJheSgpLmlzU3RyaW5nKCkuaXNPcHRpb25hbCgpLndpdGhEZWZhdWx0KFtdKVxyXG4gICAgICAud2hlcmVQYXJhbShcImludkZvcmVpZ25LZXlOYW1lc09uU2VydmVyXCIpLmlzQXJyYXkoKS5pc1N0cmluZygpLmlzT3B0aW9uYWwoKS53aXRoRGVmYXVsdChbXSlcclxuICAgICAgLndoZXJlUGFyYW0oXCJ2YWxpZGF0b3JzXCIpLmlzSW5zdGFuY2VPZihWYWxpZGF0b3IpLmlzQXJyYXkoKS5pc09wdGlvbmFsKCkud2l0aERlZmF1bHQoW10pXHJcbiAgICAgIC53aGVyZVBhcmFtKFwiZGlzcGxheU5hbWVcIikuaXNPcHRpb25hbCgpXHJcbiAgICAgIC53aGVyZVBhcmFtKFwiY3VzdG9tXCIpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAuYXBwbHlBbGwodGhpcyk7XHJcbiAgICBsZXQgaGFzTmFtZSA9ICEhKHRoaXMubmFtZSB8fCB0aGlzLm5hbWVPblNlcnZlcik7XHJcblxyXG4gICAgaWYgKCFoYXNOYW1lKSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkEgTmF2aWdhdGlvbiBwcm9wZXJ0eSBtdXN0IGJlIGluc3RhbnRpYXRlZCB3aXRoIGVpdGhlciBhICduYW1lJyBvciBhICduYW1lT25TZXJ2ZXInIHByb3BlcnR5XCIpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgR2VuZXJhbCBwdXJwb3NlIHByb3BlcnR5IHNldCBtZXRob2RcclxuICA+ICAgICAgLy8gYXNzdW1lIG15RW50aXR5VHlwZSBpcyBhbiBFbnRpdHlUeXBlXHJcbiAgPiAgICAgIGxldCBwcm9wID0gbXlFbnRpdHlUeXBlLmdldFByb3BlcnR5KFwibXlQcm9wZXJ0eVwiKTtcclxuICA+ICAgICAgcHJvcC5zZXRQcm9wZXJ0aWVzKCB7XHJcbiAgPiAgICAgICAgICBjdXN0b206IHsgZm9vOiA3LCBiYXI6IFwidGVzdFwiIH1cclxuICA+ICAgICAgfSk7XHJcbiAgQHBhcmFtIGNvbmZpZyAtIEEgY29uZmlnIG9iamVjdFxyXG4gICoqL1xyXG4gIC8vIFRPRE86IGNyZWF0ZSBhbiBpbnRlcmZhY2UgZm9yIHRoaXMuXHJcbiAgc2V0UHJvcGVydGllcyhjb25maWc6IHtcclxuICAgIGRpc3BsYXlOYW1lPzogc3RyaW5nLFxyXG4gICAgZm9yZWlnbktleU5hbWVzPzogc3RyaW5nW10sXHJcbiAgICBpbnZGb3JlaWduS2V5TmFtZXM/OiBzdHJpbmdbXSxcclxuICAgIGludmVyc2U/OiBOYXZpZ2F0aW9uUHJvcGVydHkgfCBzdHJpbmcsXHJcbiAgICBjdXN0b20/OiBPYmplY3RcclxuICB9KSB7XHJcbiAgICBpZiAoIXRoaXMucGFyZW50VHlwZSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgY2FsbCBOYXZpZ2F0aW9uUHJvcGVydHkuc2V0UHJvcGVydGllcyB1bnRpbCB0aGUgcGFyZW50IEVudGl0eVR5cGUgb2YgdGhlIE5hdmlnYXRpb25Qcm9wZXJ0eSBoYXMgYmVlbiBzZXQuXCIpO1xyXG4gICAgfVxyXG4gICAgbGV0IGludmVyc2UgPSBjb25maWcuaW52ZXJzZTtcclxuICAgIGlmIChpbnZlcnNlKSBkZWxldGUgY29uZmlnLmludmVyc2U7XHJcbiAgICBhc3NlcnRDb25maWcoY29uZmlnKVxyXG4gICAgICAud2hlcmVQYXJhbShcImRpc3BsYXlOYW1lXCIpLmlzT3B0aW9uYWwoKVxyXG4gICAgICAud2hlcmVQYXJhbShcImZvcmVpZ25LZXlOYW1lc1wiKS5pc0FycmF5KCkuaXNTdHJpbmcoKS5pc09wdGlvbmFsKCkud2l0aERlZmF1bHQoW10pXHJcbiAgICAgIC53aGVyZVBhcmFtKFwiaW52Rm9yZWlnbktleU5hbWVzXCIpLmlzQXJyYXkoKS5pc1N0cmluZygpLmlzT3B0aW9uYWwoKS53aXRoRGVmYXVsdChbXSlcclxuICAgICAgLndoZXJlUGFyYW0oXCJjdXN0b21cIikuaXNPcHRpb25hbCgpXHJcbiAgICAgIC5hcHBseUFsbCh0aGlzKTtcclxuICAgIHRoaXMucGFyZW50VHlwZS5fdXBkYXRlTmFtZXModGhpcyk7XHJcblxyXG4gICAgdGhpcy5fcmVzb2x2ZU5wKCk7XHJcbiAgICBpZiAoaW52ZXJzZSkge1xyXG4gICAgICB0aGlzLnNldEludmVyc2UoaW52ZXJzZSk7XHJcbiAgICB9XHJcblxyXG4gIH1cclxuXHJcbiAgLyoqIFRoZSBpbnZlcnNlIG9mIHRoaXMgTmF2aWdhdGlvblByb3BlcnR5LiAgVGhlIE5hdmlnYXRpb25Qcm9wZXJ0eSB0aGF0IHJlcHJlc2VudHMgYSBuYXZpZ2F0aW9uIGluIHRoZSBvcHBvc2l0ZSBkaXJlY3Rpb25cclxuICB0byB0aGlzIE5hdmlnYXRpb25Qcm9wZXJ0eS4gTWF5IGJlIHVuZGVmaW5lZCBmb3IgYSB1bmRpcmVjdGlvbmFsIE5hdmlnYXRpb25Qcm9wZXJ0eS4gX19SZWFkIE9ubHlfXyAqL1xyXG4gIGdldCBpbnZlcnNlKCk6IE5hdmlnYXRpb25Qcm9wZXJ0eSB8IHVuZGVmaW5lZCB7XHJcbiAgICByZXR1cm4gdGhpcy5nZXRJbnZlcnNlKCk7XHJcbiAgfVxyXG5cclxuICAvKiogQGhpZGRlbiBAaW50ZXJuYWwgKi9cclxuICBnZXRJbnZlcnNlKCk6IE5hdmlnYXRpb25Qcm9wZXJ0eSB8IHVuZGVmaW5lZCB7XHJcbiAgICBsZXQgbnA6IE5hdmlnYXRpb25Qcm9wZXJ0eSA9IHRoaXM7XHJcbiAgICB3aGlsZSAoIW5wLl9pbnZlcnNlICYmIG5wLmJhc2VQcm9wZXJ0eSkge1xyXG4gICAgICBucCA9IG5wLmJhc2VQcm9wZXJ0eTtcclxuICAgIH1cclxuICAgIHJldHVybiBucC5faW52ZXJzZTtcclxuICB9XHJcblxyXG4gIHNldEludmVyc2UoaW52ZXJzZU5wOiBOYXZpZ2F0aW9uUHJvcGVydHkgfCBzdHJpbmcpIHtcclxuICAgIC8vIGxldCBpbnZOcDogTmF2aWdhdGlvblByb3BlcnR5O1xyXG4gICAgbGV0IGludk5wID0gKGludmVyc2VOcCBpbnN0YW5jZW9mIE5hdmlnYXRpb25Qcm9wZXJ0eSkgPyBpbnZlcnNlTnAgOiB0aGlzLmVudGl0eVR5cGUuZ2V0TmF2aWdhdGlvblByb3BlcnR5KGludmVyc2VOcCk7XHJcblxyXG4gICAgaWYgKCFpbnZOcCkge1xyXG4gICAgICB0aHJvdyB0aHJvd1NldEludmVyc2VFcnJvcih0aGlzLCBcIlVuYWJsZSB0byBmaW5kIGludmVyc2UgcHJvcGVydHk6IFwiICsgaW52ZXJzZU5wKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5faW52ZXJzZSB8fCBpbnZOcC5faW52ZXJzZSkge1xyXG4gICAgICB0aHJvd1NldEludmVyc2VFcnJvcih0aGlzLCBcIkl0IGhhcyBhbHJlYWR5IGJlZW4gc2V0IG9uIG9uZSBzaWRlIG9yIHRoZSBvdGhlci5cIik7XHJcbiAgICB9XHJcbiAgICBpZiAoaW52TnAuZW50aXR5VHlwZSAhPT0gdGhpcy5wYXJlbnRUeXBlKSB7XHJcbiAgICAgIHRocm93U2V0SW52ZXJzZUVycm9yKHRoaXMsIGludk5wLmZvcm1hdE5hbWUgKyBcIiBpcyBub3QgYSB2YWxpZCBpbnZlcnNlIHByb3BlcnR5IGZvciB0aGlzLlwiKTtcclxuICAgIH1cclxuICAgIGlmICh0aGlzLmFzc29jaWF0aW9uTmFtZSkge1xyXG4gICAgICBpbnZOcC5hc3NvY2lhdGlvbk5hbWUgPSB0aGlzLmFzc29jaWF0aW9uTmFtZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGlmICghaW52TnAuYXNzb2NpYXRpb25OYW1lKSB7XHJcbiAgICAgICAgaW52TnAuYXNzb2NpYXRpb25OYW1lID0gdGhpcy5mb3JtYXROYW1lKCkgKyBcIl9cIiArIGludk5wLmZvcm1hdE5hbWUoKTtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLmFzc29jaWF0aW9uTmFtZSA9IGludk5wLmFzc29jaWF0aW9uTmFtZTtcclxuICAgIH1cclxuICAgIHRoaXMuX3Jlc29sdmVOcCgpO1xyXG4gICAgaW52TnAuX3Jlc29sdmVOcCgpO1xyXG4gIH1cclxuXHJcbiAgLy8gLy8gSW4gcHJvZ3Jlc3MgLSB3aWxsIGJlIHVzZWQgZm9yIG1hbnVhbCBtZXRhZGF0YSBjb25maWdcclxuICAvLyBjcmVhdGVJbnZlcnNlKGNvbmZpZzogYW55KSB7XHJcblxyXG4gIC8vICAgaWYgKCF0aGlzLmVudGl0eVR5cGUpIHtcclxuICAvLyAgICAgdGhyb3dDcmVhdGVJbnZlcnNlRXJyb3IodGhpcywgXCJoYXMgbm90IHlldCBiZWVuIGRlZmluZWQuXCIpO1xyXG4gIC8vICAgfVxyXG4gIC8vICAgaWYgKHRoaXMuZW50aXR5VHlwZS5pc0Zyb3plbikge1xyXG4gIC8vICAgICB0aHJvd0NyZWF0ZUludmVyc2VFcnJvcih0aGlzLCBcImlzIGZyb3plbi5cIik7XHJcbiAgLy8gICB9XHJcbiAgLy8gICBsZXQgbWV0YWRhdGFTdG9yZSA9IHRoaXMuZW50aXR5VHlwZS5tZXRhZGF0YVN0b3JlO1xyXG4gIC8vICAgaWYgKG1ldGFkYXRhU3RvcmUgPT0gbnVsbCkge1xyXG4gIC8vICAgICB0aHJvd0NyZWF0ZUludmVyc2VFcnJvcih0aGlzLCBcImhhcyBub3QgeWV0IGJlZW4gYWRkZWQgdG8gdGhlIG1ldGFkYXRhU3RvcmUuXCIpO1xyXG4gIC8vICAgfVxyXG5cclxuICAvLyAgIGNvbmZpZy5lbnRpdHlUeXBlTmFtZSA9IHRoaXMucGFyZW50RW50aXR5VHlwZS5uYW1lO1xyXG4gIC8vICAgY29uZmlnLmFzc29jaWF0aW9uTmFtZSA9IHRoaXMuYXNzb2NpYXRpb25OYW1lO1xyXG4gIC8vICAgbGV0IGludk5wID0gbmV3IE5hdmlnYXRpb25Qcm9wZXJ0eShjb25maWcpO1xyXG4gIC8vICAgdGhpcy5wYXJlbnRFbnRpdHlUeXBlLmFkZE5hdmlnYXRpb25Qcm9wZXJ0eShpbnZOcCk7XHJcbiAgLy8gICByZXR1cm4gaW52TnA7XHJcbiAgLy8gfTtcclxuXHJcblxyXG5cclxuICB0b0pTT04oKSB7XHJcbiAgICByZXR1cm4gY29yZS50b0pzb24odGhpcywge1xyXG4gICAgICBuYW1lOiBudWxsLFxyXG4gICAgICBlbnRpdHlUeXBlTmFtZTogbnVsbCxcclxuICAgICAgaXNTY2FsYXI6IG51bGwsXHJcbiAgICAgIGFzc29jaWF0aW9uTmFtZTogbnVsbCxcclxuICAgICAgdmFsaWRhdG9yczogbnVsbCxcclxuICAgICAgZGlzcGxheU5hbWU6IG51bGwsXHJcbiAgICAgIGZvcmVpZ25LZXlOYW1lczogbnVsbCxcclxuICAgICAgaW52Rm9yZWlnbktleU5hbWVzOiBudWxsLFxyXG4gICAgICBjdXN0b206IG51bGxcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgc3RhdGljIGZyb21KU09OKGpzb246IGFueSkge1xyXG4gICAgaWYgKGpzb24udmFsaWRhdG9ycykge1xyXG4gICAgICBqc29uLnZhbGlkYXRvcnMgPSBqc29uLnZhbGlkYXRvcnMubWFwKFZhbGlkYXRvci5mcm9tSlNPTik7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gbmV3IE5hdmlnYXRpb25Qcm9wZXJ0eShqc29uKTtcclxuICB9XHJcblxyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIF9yZXNvbHZlTnAoKSB7XHJcbiAgICBsZXQgbnAgPSB0aGlzO1xyXG4gICAgbGV0IGVudGl0eVR5cGUgPSBucC5lbnRpdHlUeXBlO1xyXG4gICAgbGV0IGludk5wID0gY29yZS5hcnJheUZpcnN0KGVudGl0eVR5cGUubmF2aWdhdGlvblByb3BlcnRpZXMsIChhbHROcCkgPT4ge1xyXG4gICAgICAvLyBDYW4ndCBkbyB0aGlzIGJlY2F1c2Ugb2YgcG9zc2liaWxpdHkgb2YgY29tcGFyaW5nIGEgYmFzZSBjbGFzcyBucCB3aXRoIGEgc3ViY2xhc3MgYWx0TnAuXHJcbiAgICAgIC8vIHJldHVybiBhbHROcC5hc3NvY2lhdGlvbk5hbWUgPT09IG5wLmFzc29jaWF0aW9uTmFtZVxyXG4gICAgICAvLyAgICAmJiBhbHROcCAhPT0gbnA7XHJcbiAgICAgIC8vIFNvIHVzZSB0aGlzIGluc3RlYWQuXHJcbiAgICAgIHJldHVybiBhbHROcC5hc3NvY2lhdGlvbk5hbWUgPT09IG5wLmFzc29jaWF0aW9uTmFtZSAmJlxyXG4gICAgICAgIChhbHROcC5uYW1lICE9PSBucC5uYW1lIHx8IGFsdE5wLmVudGl0eVR5cGVOYW1lICE9PSBucC5lbnRpdHlUeXBlTmFtZSk7XHJcbiAgICB9KTtcclxuICAgIG5wLl9pbnZlcnNlID0gaW52TnAgfHwgdW5kZWZpbmVkO1xyXG4gICAgLy9pZiAoaW52TnAgJiYgaW52TnAuaW52ZXJzZSA9PSBudWxsKSB7XHJcbiAgICAvLyAgICBpbnZOcC5fcmVzb2x2ZU5wKCk7XHJcbiAgICAvL31cclxuICAgIGlmICghaW52TnApIHtcclxuICAgICAgLy8gdW5pZGlyZWN0aW9uYWwgMS1uIHJlbGF0aW9uc2hpcFxyXG4gICAgICBucC5pbnZGb3JlaWduS2V5TmFtZXMuZm9yRWFjaChmdW5jdGlvbiAoaW52RmtOYW1lKSB7XHJcbiAgICAgICAgbGV0IGZrUHJvcCA9IGVudGl0eVR5cGUuZ2V0RGF0YVByb3BlcnR5KGludkZrTmFtZSk7XHJcbiAgICAgICAgaWYgKGZrUHJvcCA9PSBudWxsKSB7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJFbnRpdHlUeXBlICdcIiArIG5wLmVudGl0eVR5cGVOYW1lICsgXCInIGhhcyBubyBmb3JlaWduIGtleSBtYXRjaGluZyAnXCIgKyBpbnZGa05hbWUgKyBcIidcIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCBpbnZFbnRpdHlUeXBlID0gbnAucGFyZW50VHlwZTtcclxuICAgICAgICBpbnZOcCA9IGNvcmUuYXJyYXlGaXJzdChpbnZFbnRpdHlUeXBlLm5hdmlnYXRpb25Qcm9wZXJ0aWVzLCAobnAyKSA9PiB7XHJcbiAgICAgICAgICByZXR1cm4gbnAyLmludkZvcmVpZ25LZXlOYW1lcyAmJiBucDIuaW52Rm9yZWlnbktleU5hbWVzLmluZGV4T2YoZmtQcm9wIS5uYW1lKSA+PSAwICYmIG5wMi5lbnRpdHlUeXBlID09PSBma1Byb3AhLnBhcmVudFR5cGU7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgZmtQcm9wLmludmVyc2VOYXZpZ2F0aW9uUHJvcGVydHkgPSBpbnZOcCB8fCB1bmRlZmluZWQ7XHJcbiAgICAgICAgY29yZS5hcnJheUFkZEl0ZW1VbmlxdWUoZW50aXR5VHlwZS5mb3JlaWduS2V5UHJvcGVydGllcywgZmtQcm9wKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcmVzb2x2ZVJlbGF0ZWQobnApO1xyXG4gIH1cclxuXHJcbn1cclxuTmF2aWdhdGlvblByb3BlcnR5LnByb3RvdHlwZS5fJHR5cGVOYW1lID0gXCJOYXZpZ2F0aW9uUHJvcGVydHlcIjtcclxuXHJcbmZ1bmN0aW9uIHRocm93U2V0SW52ZXJzZUVycm9yKG5wOiBOYXZpZ2F0aW9uUHJvcGVydHksIG1lc3NhZ2U6IHN0cmluZykge1xyXG4gIHRocm93IG5ldyBFcnJvcihcIkNhbm5vdCBzZXQgdGhlIGludmVyc2UgcHJvcGVydHkgZm9yOiBcIiArIG5wLmZvcm1hdE5hbWUoKSArIFwiLiBcIiArIG1lc3NhZ2UpO1xyXG59XHJcblxyXG4vLyBOb3QgY3VycmVudCB1c2VkLlxyXG4vLyBmdW5jdGlvbiB0aHJvd0NyZWF0ZUludmVyc2VFcnJvcihucDogTmF2aWdhdGlvblByb3BlcnR5LCBtZXNzYWdlOiBzdHJpbmcpIHtcclxuLy8gICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgY3JlYXRlIGludmVyc2UgZm9yOiBcIiArIG5wLmZvcm1hdE5hbWUoKSArIFwiLiBUaGUgZW50aXR5VHlwZSBmb3IgdGhpcyBuYXZpZ2F0aW9uIHByb3BlcnR5IFwiICsgbWVzc2FnZSk7XHJcbi8vIH1cclxuXHJcbi8vIHNldHMgbmF2aWdhdGlvbiBwcm9wZXJ0eTogcmVsYXRlZERhdGFQcm9wZXJ0aWVzIGFuZCBkYXRhUHJvcGVydHk6IHJlbGF0ZWROYXZpZ2F0aW9uUHJvcGVydHlcclxuZnVuY3Rpb24gcmVzb2x2ZVJlbGF0ZWQobnA6IE5hdmlnYXRpb25Qcm9wZXJ0eSkge1xyXG5cclxuICBsZXQgZmtOYW1lcyA9IG5wLmZvcmVpZ25LZXlOYW1lcztcclxuICBpZiAoZmtOYW1lcy5sZW5ndGggPT09IDApIHJldHVybjtcclxuXHJcbiAgbGV0IHBhcmVudEVudGl0eVR5cGUgPSBucC5wYXJlbnRUeXBlO1xyXG4gIGxldCBma1Byb3BzID0gZmtOYW1lcy5tYXAoZnVuY3Rpb24gKGZrTmFtZSkge1xyXG4gICAgcmV0dXJuIHBhcmVudEVudGl0eVR5cGUuZ2V0RGF0YVByb3BlcnR5KGZrTmFtZSk7XHJcbiAgfSk7XHJcbiAgbGV0IGZrUHJvcENvbGxlY3Rpb24gPSBwYXJlbnRFbnRpdHlUeXBlLmZvcmVpZ25LZXlQcm9wZXJ0aWVzO1xyXG5cclxuICBma1Byb3BzLmZvckVhY2goKGRwOiBEYXRhUHJvcGVydHkpID0+IHtcclxuICAgIGNvcmUuYXJyYXlBZGRJdGVtVW5pcXVlKGZrUHJvcENvbGxlY3Rpb24sIGRwKTtcclxuICAgIGRwLnJlbGF0ZWROYXZpZ2F0aW9uUHJvcGVydHkgPSBucDtcclxuICAgIC8vIG5vdyB1cGRhdGUgdGhlIGludmVyc2VcclxuICAgIGNvcmUuYXJyYXlBZGRJdGVtVW5pcXVlKG5wLmVudGl0eVR5cGUuaW52ZXJzZUZvcmVpZ25LZXlQcm9wZXJ0aWVzLCBkcCk7XHJcbiAgICBpZiAobnAucmVsYXRlZERhdGFQcm9wZXJ0aWVzKSB7XHJcbiAgICAgIGNvcmUuYXJyYXlBZGRJdGVtVW5pcXVlKG5wLnJlbGF0ZWREYXRhUHJvcGVydGllcywgZHApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbnAucmVsYXRlZERhdGFQcm9wZXJ0aWVzID0gW2RwXTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG5cclxuXHJcbi8qKlxyXG5BdXRvR2VuZXJhdGVkS2V5VHlwZSBpcyBhbiAnRW51bScgY29udGFpbmluZyBhbGwgb2YgdGhlIHZhbGlkIHN0YXRlcyBmb3IgYW4gYXV0b21hdGljYWxseSBnZW5lcmF0ZWQga2V5LlxyXG4qKi9cclxuZXhwb3J0IGNsYXNzIEF1dG9HZW5lcmF0ZWRLZXlUeXBlIGV4dGVuZHMgQnJlZXplRW51bSB7XHJcblxyXG4gIC8qKlxyXG4gIFRoaXMgZW50aXR5IGRvZXMgbm90IGhhdmUgYW4gYXV0b2dlbmVyYXRlZCBrZXkuXHJcbiAgVGhlIGNsaWVudCBtdXN0IHNldCB0aGUga2V5IGJlZm9yZSBhZGRpbmcgdGhlIGVudGl0eSB0byB0aGUgRW50aXR5TWFuYWdlclxyXG4gICoqL1xyXG4gIHN0YXRpYyBOb25lID0gbmV3IEF1dG9HZW5lcmF0ZWRLZXlUeXBlKCk7XHJcbiAgLyoqIFxyXG4gIFRoaXMgZW50aXR5J3Mga2V5IGlzIGFuIElkZW50aXR5IGNvbHVtbiBhbmQgaXMgc2V0IGJ5IHRoZSBiYWNrZW5kIGRhdGFiYXNlLlxyXG4gIEtleXMgZm9yIG5ldyBlbnRpdGllcyB3aWxsIGJlIHRlbXBvcmFyeSB1bnRpbCB0aGUgZW50aXRpZXMgYXJlIHNhdmVkIGF0IHdoaWNoIHBvaW50IHRoZSBrZXlzIHdpbGxcclxuICBiZSBjb252ZXJ0ZWQgdG8gdGhlaXIgJ3JlYWwnIHZlcnNpb25zLlxyXG4gICoqL1xyXG4gIHN0YXRpYyBJZGVudGl0eSA9IG5ldyBBdXRvR2VuZXJhdGVkS2V5VHlwZSgpO1xyXG4gIC8qKlxyXG4gIFRoaXMgZW50aXR5J3Mga2V5IGlzIGdlbmVyYXRlZCBieSBhIEtleUdlbmVyYXRvciBhbmQgaXMgc2V0IGJ5IHRoZSBiYWNrZW5kIGRhdGFiYXNlLlxyXG4gIEtleXMgZm9yIG5ldyBlbnRpdGllcyB3aWxsIGJlIHRlbXBvcmFyeSB1bnRpbCB0aGUgZW50aXRpZXMgYXJlIHNhdmVkIGF0IHdoaWNoIHBvaW50IHRoZSBrZXlzIHdpbGxcclxuICBiZSBjb252ZXJ0ZWQgdG8gdGhlaXIgJ3JlYWwnIHZlcnNpb25zLlxyXG4gICoqL1xyXG4gIHN0YXRpYyBLZXlHZW5lcmF0b3IgPSBuZXcgQXV0b0dlbmVyYXRlZEtleVR5cGUoKTtcclxuXHJcbn1cclxuQXV0b0dlbmVyYXRlZEtleVR5cGUucHJvdG90eXBlLl8kdHlwZU5hbWUgPSBcIkF1dG9HZW5lcmF0ZWRLZXlUeXBlXCI7XHJcbkVycm9yWyd4J10gPSBBdXRvR2VuZXJhdGVkS2V5VHlwZS5yZXNvbHZlU3ltYm9scygpO1xyXG5cclxuXHJcbi8vIG1peGluIG1ldGhvZHNcclxuLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbmRlY2xhcmUgbW9kdWxlIFwiLi9hc3NlcnQtcGFyYW1cIiB7XHJcbiAgaW50ZXJmYWNlIFBhcmFtIHtcclxuICAgIGlzRW50aXR5KCk6IFBhcmFtO1xyXG4gICAgaXNFbnRpdHlQcm9wZXJ0eSgpOiBQYXJhbTtcclxuICB9XHJcbn1cclxuXHJcbmxldCBwcm90byA9IFBhcmFtLnByb3RvdHlwZTtcclxuXHJcbi8vICd0aGlzJyBiZWxvdyBpcyBUUyBhbm5vdGF0aW9uIFxyXG5wcm90by5pc0VudGl0eSA9IGZ1bmN0aW9uICh0aGlzOiBQYXJhbSkge1xyXG4gIHJldHVybiB0aGlzLl9hZGRDb250ZXh0KHtcclxuICAgIGZuOiBpc0VudGl0eSxcclxuICAgIG1zZzogXCIgbXVzdCBiZSBhbiBlbnRpdHlcIlxyXG4gIH0pO1xyXG59O1xyXG5cclxuZnVuY3Rpb24gaXNFbnRpdHkoY29udGV4dDogYW55LCB2OiBhbnkpIHtcclxuICBpZiAodiA9PSBudWxsKSByZXR1cm4gZmFsc2U7XHJcbiAgcmV0dXJuICh2LmVudGl0eVR5cGUgIT09IHVuZGVmaW5lZCk7XHJcbn1cclxuXHJcbnByb3RvLmlzRW50aXR5UHJvcGVydHkgPSBmdW5jdGlvbiAodGhpczogUGFyYW0pIHtcclxuICByZXR1cm4gdGhpcy5fYWRkQ29udGV4dCh7XHJcbiAgICBmbjogaXNFbnRpdHlQcm9wZXJ0eSxcclxuICAgIG1zZzogXCIgbXVzdCBiZSBlaXRoZXIgYSBEYXRhUHJvcGVydHkgb3IgYSBOYXZpZ2F0aW9uUHJvcGVydHlcIlxyXG4gIH0pO1xyXG59O1xyXG5cclxuZnVuY3Rpb24gaXNFbnRpdHlQcm9wZXJ0eShjb250ZXh0OiBhbnksIHY6IGFueSkge1xyXG4gIGlmICh2ID09IG51bGwpIHJldHVybiBmYWxzZTtcclxuICByZXR1cm4gKHYuaXNEYXRhUHJvcGVydHkgfHwgdi5pc05hdmlnYXRpb25Qcm9wZXJ0eSk7XHJcbn1cclxuXHJcbi8vIGZ1bmN0aW9ucyBzaGFyZWQgYmV0d2VlbiBjbGFzc2VzIHJlbGF0ZWQgdG8gTWV0YWRhdGFcclxuXHJcbmZ1bmN0aW9uIGlzUXVhbGlmaWVkVHlwZU5hbWUoZW50aXR5VHlwZU5hbWU6IHN0cmluZykge1xyXG4gIHJldHVybiBlbnRpdHlUeXBlTmFtZS5pbmRleE9mKFwiOiNcIikgPj0gMDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIHF1YWxpZnlUeXBlTmFtZShzaG9ydE5hbWU6IHN0cmluZywgbnM/OiBzdHJpbmcpIHtcclxuICBpZiAobnMgJiYgbnMubGVuZ3RoID4gMCkge1xyXG4gICAgcmV0dXJuIHNob3J0TmFtZSArIFwiOiNcIiArIG5zO1xyXG4gIH0gZWxzZSB7XHJcbiAgICByZXR1cm4gc2hvcnROYW1lO1xyXG4gIH1cclxufVxyXG5cclxuLy8gVXNlZCBieSBib3RoIENvbXBsZXhUeXBlIGFuZCBFbnRpdHlUeXBlXHJcbmZ1bmN0aW9uIGFkZFByb3BlcnRpZXMoZW50aXR5VHlwZTogU3RydWN0dXJhbFR5cGUsIHByb3BPYmo6IE9iamVjdCB8IHVuZGVmaW5lZCwgY3RvcjogYW55KSB7XHJcbiAgaWYgKHByb3BPYmogPT0gbnVsbCkgcmV0dXJuO1xyXG4gIGlmIChBcnJheS5pc0FycmF5KHByb3BPYmopKSB7XHJcbiAgICBwcm9wT2JqLmZvckVhY2goZW50aXR5VHlwZS5fYWRkUHJvcGVydHlDb3JlLmJpbmQoZW50aXR5VHlwZSkpO1xyXG4gIH0gZWxzZSBpZiAodHlwZW9mIChwcm9wT2JqKSA9PT0gJ29iamVjdCcpIHtcclxuICAgIGZvciAobGV0IGtleSBpbiBwcm9wT2JqKSB7XHJcbiAgICAgIGlmIChjb3JlLmhhc093blByb3BlcnR5KHByb3BPYmosIGtleSkpIHtcclxuICAgICAgICBsZXQgdmFsdWUgPSBwcm9wT2JqW2tleV07XHJcbiAgICAgICAgdmFsdWUubmFtZSA9IGtleTtcclxuICAgICAgICBsZXQgcHJvcCA9IG5ldyBjdG9yKHZhbHVlKTtcclxuICAgICAgICBlbnRpdHlUeXBlLl9hZGRQcm9wZXJ0eUNvcmUocHJvcCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgdGhyb3cgbmV3IEVycm9yKFwiVGhlICdkYXRhUHJvcGVydGllcycgb3IgJ25hdmlnYXRpb25Qcm9wZXJ0aWVzJyB2YWx1ZXMgbXVzdCBiZSBlaXRoZXIgYW4gYXJyYXkgb2YgZGF0YS9uYXYgcHJvcGVydGllcyBvciBhbiBvYmplY3Qgd2hlcmUgZWFjaCBwcm9wZXJ0eSBkZWZpbmVzIGEgZGF0YS9uYXYgcHJvcGVydHlcIik7XHJcbiAgfVxyXG59XHJcblxyXG5cclxuXHJcblxyXG5cclxuIl19
|