breeze-client 2.2.2 → 3.0.0

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.
Files changed (299) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +83 -63
  3. package/adapters/abstract-data-service-adapter.d.ts +120 -0
  4. package/adapters/abstract-data-service-adapter.js +395 -0
  5. package/adapters/abstract-data-service-adapter.js.map +1 -0
  6. package/adapters/adapter-ajax-fetch.d.ts +12 -0
  7. package/adapters/adapter-ajax-fetch.js +13 -0
  8. package/adapters/adapter-ajax-fetch.js.map +1 -0
  9. package/{adapter-ajax-post → adapters}/adapter-ajax-post.d.ts +40 -36
  10. package/{fesm2022/breeze-client-adapter-ajax-post.mjs → adapters/adapter-ajax-post.js} +80 -82
  11. package/adapters/adapter-ajax-post.js.map +1 -0
  12. package/{adapter-ajax-fetch → adapters}/adapter-core.d.ts +4 -4
  13. package/{fesm2022/breeze-client-adapter-uri-builder-json.mjs → adapters/adapter-core.js} +48 -91
  14. package/adapters/adapter-core.js.map +1 -0
  15. package/adapters/adapter-data-service-webapi.d.ts +9 -0
  16. package/{fesm2022/breeze-client-adapter-data-service-webapi.mjs → adapters/adapter-data-service-webapi.js} +105 -107
  17. package/adapters/adapter-data-service-webapi.js.map +1 -0
  18. package/adapters/adapter-model-library-backing-store.d.ts +32 -0
  19. package/adapters/adapter-model-library-backing-store.js +321 -0
  20. package/adapters/adapter-model-library-backing-store.js.map +1 -0
  21. package/adapters/adapter-uri-builder-json.d.ts +11 -0
  22. package/adapters/adapter-uri-builder-json.js +40 -0
  23. package/adapters/adapter-uri-builder-json.js.map +1 -0
  24. package/adapters/http.d.ts +52 -0
  25. package/adapters/http.js +202 -0
  26. package/adapters/http.js.map +1 -0
  27. package/angular/adapter-angular-httpclient.d.ts +21 -0
  28. package/angular/adapter-angular-httpclient.js +70 -0
  29. package/angular/adapter-angular-httpclient.js.map +1 -0
  30. package/breeze.d.ts +215 -0
  31. package/breeze.js +141 -0
  32. package/breeze.js.map +1 -0
  33. package/config/config.d.ts +212 -0
  34. package/config/config.js +392 -0
  35. package/config/config.js.map +1 -0
  36. package/config/configure.d.ts +66 -0
  37. package/config/configure.js +46 -0
  38. package/config/configure.js.map +1 -0
  39. package/config/default-adapters.d.ts +1 -0
  40. package/config/default-adapters.js +40 -0
  41. package/config/default-adapters.js.map +1 -0
  42. package/config/interface-registry.d.ts +191 -0
  43. package/config/interface-registry.js +5 -0
  44. package/config/interface-registry.js.map +1 -0
  45. package/{src → core}/assert-param.d.ts +52 -60
  46. package/core/assert-param.js +390 -0
  47. package/core/assert-param.js.map +1 -0
  48. package/core/core.d.ts +285 -0
  49. package/core/core.js +772 -0
  50. package/core/core.js.map +1 -0
  51. package/core/enum.d.ts +116 -0
  52. package/core/enum.js +167 -0
  53. package/core/enum.js.map +1 -0
  54. package/core/event.d.ts +169 -0
  55. package/core/event.js +338 -0
  56. package/core/event.js.map +1 -0
  57. package/entity/array.d.ts +3 -0
  58. package/entity/array.js +4 -0
  59. package/entity/array.js.map +1 -0
  60. package/entity/complex-array.d.ts +17 -0
  61. package/entity/complex-array.js +104 -0
  62. package/entity/complex-array.js.map +1 -0
  63. package/entity/default-property-interceptor.d.ts +1 -0
  64. package/entity/default-property-interceptor.js +496 -0
  65. package/entity/default-property-interceptor.js.map +1 -0
  66. package/{src → entity}/entity-action.d.ts +36 -42
  67. package/entity/entity-action.js +45 -0
  68. package/entity/entity-action.js.map +1 -0
  69. package/entity/entity-aspect.d.ts +457 -0
  70. package/entity/entity-aspect.js +1262 -0
  71. package/entity/entity-aspect.js.map +1 -0
  72. package/entity/entity-base.d.ts +55 -0
  73. package/entity/entity-base.js +41 -0
  74. package/entity/entity-base.js.map +1 -0
  75. package/entity/entity-group.d.ts +1 -0
  76. package/entity/entity-group.js +224 -0
  77. package/entity/entity-group.js.map +1 -0
  78. package/entity/entity-key.d.ts +95 -0
  79. package/entity/entity-key.js +189 -0
  80. package/entity/entity-key.js.map +1 -0
  81. package/{src → entity}/entity-state.d.ts +112 -84
  82. package/entity/entity-state.js +135 -0
  83. package/entity/entity-state.js.map +1 -0
  84. package/entity/key-generator.d.ts +57 -0
  85. package/entity/key-generator.js +155 -0
  86. package/entity/key-generator.js.map +1 -0
  87. package/entity/observable-array.d.ts +25 -0
  88. package/entity/observable-array.js +230 -0
  89. package/entity/observable-array.js.map +1 -0
  90. package/entity/primitive-array.d.ts +12 -0
  91. package/entity/primitive-array.js +71 -0
  92. package/entity/primitive-array.js.map +1 -0
  93. package/entity/relation-array.d.ts +24 -0
  94. package/entity/relation-array.js +176 -0
  95. package/entity/relation-array.js.map +1 -0
  96. package/entity/unattached-children-map.d.ts +1 -0
  97. package/entity/unattached-children-map.js +105 -0
  98. package/entity/unattached-children-map.js.map +1 -0
  99. package/generate-entity-classes.js +1176 -0
  100. package/manager/entity-manager.d.ts +801 -0
  101. package/manager/entity-manager.js +2395 -0
  102. package/manager/entity-manager.js.map +1 -0
  103. package/{src → manager}/save-options.d.ts +48 -42
  104. package/manager/save-options.js +51 -0
  105. package/manager/save-options.js.map +1 -0
  106. package/{src → metadata}/data-service.d.ts +229 -184
  107. package/metadata/data-service.js +246 -0
  108. package/metadata/data-service.js.map +1 -0
  109. package/metadata/data-type.d.ts +122 -0
  110. package/metadata/data-type.js +465 -0
  111. package/metadata/data-type.js.map +1 -0
  112. package/metadata/entity-metadata.d.ts +1193 -0
  113. package/metadata/entity-metadata.js +2502 -0
  114. package/metadata/entity-metadata.js.map +1 -0
  115. package/{src → metadata}/local-query-comparison-options.d.ts +65 -59
  116. package/metadata/local-query-comparison-options.js +69 -0
  117. package/metadata/local-query-comparison-options.js.map +1 -0
  118. package/{src → metadata}/naming-convention.d.ts +75 -72
  119. package/metadata/naming-convention.js +97 -0
  120. package/metadata/naming-convention.js.map +1 -0
  121. package/mixins/mixin-get-entity-graph.d.ts +63 -0
  122. package/{fesm2022/breeze-client-mixin-get-entity-graph.mjs → mixins/mixin-get-entity-graph.js} +331 -253
  123. package/mixins/mixin-get-entity-graph.js.map +1 -0
  124. package/mixins/mixin-save-queuing.d.ts +98 -0
  125. package/{fesm2022/breeze-client-mixin-save-queuing.mjs → mixins/mixin-save-queuing.js} +493 -365
  126. package/mixins/mixin-save-queuing.js.map +1 -0
  127. package/package.json +63 -94
  128. package/query/entity-query.d.ts +521 -0
  129. package/query/entity-query.js +1149 -0
  130. package/query/entity-query.js.map +1 -0
  131. package/{src → query}/mapping-context.d.ts +44 -46
  132. package/query/mapping-context.js +412 -0
  133. package/query/mapping-context.js.map +1 -0
  134. package/query/predicate.d.ts +394 -0
  135. package/query/predicate.js +1294 -0
  136. package/query/predicate.js.map +1 -0
  137. package/query/property-path.d.ts +252 -0
  138. package/query/property-path.js +2 -0
  139. package/query/property-path.js.map +1 -0
  140. package/{src → query}/query-options.d.ts +143 -119
  141. package/query/query-options.js +180 -0
  142. package/query/query-options.js.map +1 -0
  143. package/rxjs/breeze-rxjs.d.ts +72 -0
  144. package/rxjs/breeze-rxjs.js +117 -0
  145. package/rxjs/breeze-rxjs.js.map +1 -0
  146. package/validation/validate.d.ts +583 -0
  147. package/validation/validate.js +961 -0
  148. package/validation/validate.js.map +1 -0
  149. package/{src → validation}/validation-options.d.ts +67 -63
  150. package/validation/validation-options.js +70 -0
  151. package/validation/validation-options.js.map +1 -0
  152. package/adapter-ajax-angularjs/adapter-ajax-angularjs.d.ts +0 -17
  153. package/adapter-ajax-angularjs/adapter-core.d.ts +0 -4
  154. package/adapter-ajax-angularjs/index.d.ts +0 -5
  155. package/adapter-ajax-fetch/adapter-ajax-fetch.d.ts +0 -18
  156. package/adapter-ajax-fetch/index.d.ts +0 -5
  157. package/adapter-ajax-httpclient/adapter-ajax-httpclient.d.ts +0 -13
  158. package/adapter-ajax-httpclient/adapter-core.d.ts +0 -4
  159. package/adapter-ajax-httpclient/index.d.ts +0 -5
  160. package/adapter-ajax-jquery/adapter-ajax-jquery.d.ts +0 -15
  161. package/adapter-ajax-jquery/index.d.ts +0 -5
  162. package/adapter-ajax-post/index.d.ts +0 -5
  163. package/adapter-data-service-odata/adapter-core.d.ts +0 -4
  164. package/adapter-data-service-odata/adapter-data-service-odata.d.ts +0 -17
  165. package/adapter-data-service-odata/index.d.ts +0 -5
  166. package/adapter-data-service-webapi/adapter-data-service-webapi.d.ts +0 -15
  167. package/adapter-data-service-webapi/index.d.ts +0 -5
  168. package/adapter-model-library-backing-store/adapter-model-library-backing-store.d.ts +0 -10
  169. package/adapter-model-library-backing-store/index.d.ts +0 -5
  170. package/adapter-model-library-ko/adapter-model-library-ko.d.ts +0 -10
  171. package/adapter-model-library-ko/index.d.ts +0 -5
  172. package/adapter-uri-builder-json/adapter-core.d.ts +0 -4
  173. package/adapter-uri-builder-json/adapter-uri-builder-json.d.ts +0 -8
  174. package/adapter-uri-builder-json/index.d.ts +0 -5
  175. package/adapter-uri-builder-odata/adapter-core.d.ts +0 -4
  176. package/adapter-uri-builder-odata/adapter-uri-builder-odata.d.ts +0 -8
  177. package/adapter-uri-builder-odata/index.d.ts +0 -5
  178. package/esm2022/adapter-ajax-angularjs/adapter-ajax-angularjs.mjs +0 -135
  179. package/esm2022/adapter-ajax-angularjs/adapter-core.mjs +0 -49
  180. package/esm2022/adapter-ajax-angularjs/breeze-client-adapter-ajax-angularjs.mjs +0 -5
  181. package/esm2022/adapter-ajax-fetch/adapter-ajax-fetch.mjs +0 -135
  182. package/esm2022/adapter-ajax-fetch/adapter-core.mjs +0 -49
  183. package/esm2022/adapter-ajax-fetch/breeze-client-adapter-ajax-fetch.mjs +0 -5
  184. package/esm2022/adapter-ajax-httpclient/adapter-ajax-httpclient.mjs +0 -139
  185. package/esm2022/adapter-ajax-httpclient/adapter-core.mjs +0 -49
  186. package/esm2022/adapter-ajax-httpclient/breeze-client-adapter-ajax-httpclient.mjs +0 -5
  187. package/esm2022/adapter-ajax-jquery/adapter-ajax-jquery.mjs +0 -107
  188. package/esm2022/adapter-ajax-jquery/breeze-client-adapter-ajax-jquery.mjs +0 -5
  189. package/esm2022/adapter-ajax-post/adapter-ajax-post.mjs +0 -77
  190. package/esm2022/adapter-ajax-post/breeze-client-adapter-ajax-post.mjs +0 -5
  191. package/esm2022/adapter-data-service-odata/adapter-core.mjs +0 -49
  192. package/esm2022/adapter-data-service-odata/adapter-data-service-odata.mjs +0 -461
  193. package/esm2022/adapter-data-service-odata/breeze-client-adapter-data-service-odata.mjs +0 -5
  194. package/esm2022/adapter-data-service-webapi/adapter-data-service-webapi.mjs +0 -100
  195. package/esm2022/adapter-data-service-webapi/breeze-client-adapter-data-service-webapi.mjs +0 -5
  196. package/esm2022/adapter-model-library-backing-store/adapter-model-library-backing-store.mjs +0 -269
  197. package/esm2022/adapter-model-library-backing-store/breeze-client-adapter-model-library-backing-store.mjs +0 -5
  198. package/esm2022/adapter-model-library-ko/adapter-model-library-ko.mjs +0 -241
  199. package/esm2022/adapter-model-library-ko/breeze-client-adapter-model-library-ko.mjs +0 -5
  200. package/esm2022/adapter-uri-builder-json/adapter-core.mjs +0 -49
  201. package/esm2022/adapter-uri-builder-json/adapter-uri-builder-json.mjs +0 -37
  202. package/esm2022/adapter-uri-builder-json/breeze-client-adapter-uri-builder-json.mjs +0 -5
  203. package/esm2022/adapter-uri-builder-odata/adapter-core.mjs +0 -49
  204. package/esm2022/adapter-uri-builder-odata/adapter-uri-builder-odata.mjs +0 -191
  205. package/esm2022/adapter-uri-builder-odata/breeze-client-adapter-uri-builder-odata.mjs +0 -5
  206. package/esm2022/breeze-client.mjs +0 -5
  207. package/esm2022/index.mjs +0 -2
  208. package/esm2022/mixin-get-entity-graph/breeze-client-mixin-get-entity-graph.mjs +0 -5
  209. package/esm2022/mixin-get-entity-graph/mixin-get-entity-graph.mjs +0 -269
  210. package/esm2022/mixin-save-queuing/breeze-client-mixin-save-queuing.mjs +0 -5
  211. package/esm2022/mixin-save-queuing/mixin-save-queuing.mjs +0 -421
  212. package/esm2022/src/abstract-data-service-adapter.mjs +0 -325
  213. package/esm2022/src/array.mjs +0 -4
  214. package/esm2022/src/assert-param.mjs +0 -330
  215. package/esm2022/src/breeze.mjs +0 -85
  216. package/esm2022/src/complex-array.mjs +0 -117
  217. package/esm2022/src/config.mjs +0 -232
  218. package/esm2022/src/core.mjs +0 -712
  219. package/esm2022/src/csdl-metadata-parser.mjs +0 -385
  220. package/esm2022/src/data-service.mjs +0 -221
  221. package/esm2022/src/data-type.mjs +0 -510
  222. package/esm2022/src/default-property-interceptor.mjs +0 -460
  223. package/esm2022/src/entity-action.mjs +0 -45
  224. package/esm2022/src/entity-aspect.mjs +0 -897
  225. package/esm2022/src/entity-group.mjs +0 -192
  226. package/esm2022/src/entity-key.mjs +0 -125
  227. package/esm2022/src/entity-manager.mjs +0 -2163
  228. package/esm2022/src/entity-metadata.mjs +0 -2242
  229. package/esm2022/src/entity-query.mjs +0 -1024
  230. package/esm2022/src/entity-state.mjs +0 -107
  231. package/esm2022/src/enum.mjs +0 -143
  232. package/esm2022/src/event.mjs +0 -264
  233. package/esm2022/src/interface-registry.mjs +0 -39
  234. package/esm2022/src/key-generator.mjs +0 -110
  235. package/esm2022/src/local-query-comparison-options.mjs +0 -65
  236. package/esm2022/src/mapping-context.mjs +0 -411
  237. package/esm2022/src/naming-convention.mjs +0 -92
  238. package/esm2022/src/observable-array.mjs +0 -183
  239. package/esm2022/src/predicate.mjs +0 -1259
  240. package/esm2022/src/primitive-array.mjs +0 -85
  241. package/esm2022/src/query-options.mjs +0 -152
  242. package/esm2022/src/relation-array.mjs +0 -173
  243. package/esm2022/src/save-options.mjs +0 -41
  244. package/esm2022/src/unattached-children-map.mjs +0 -56
  245. package/esm2022/src/validate.mjs +0 -995
  246. package/esm2022/src/validation-options.mjs +0 -64
  247. package/fesm2022/breeze-client-adapter-ajax-angularjs.mjs +0 -190
  248. package/fesm2022/breeze-client-adapter-ajax-angularjs.mjs.map +0 -1
  249. package/fesm2022/breeze-client-adapter-ajax-fetch.mjs +0 -190
  250. package/fesm2022/breeze-client-adapter-ajax-fetch.mjs.map +0 -1
  251. package/fesm2022/breeze-client-adapter-ajax-httpclient.mjs +0 -194
  252. package/fesm2022/breeze-client-adapter-ajax-httpclient.mjs.map +0 -1
  253. package/fesm2022/breeze-client-adapter-ajax-jquery.mjs +0 -114
  254. package/fesm2022/breeze-client-adapter-ajax-jquery.mjs.map +0 -1
  255. package/fesm2022/breeze-client-adapter-ajax-post.mjs.map +0 -1
  256. package/fesm2022/breeze-client-adapter-data-service-odata.mjs +0 -516
  257. package/fesm2022/breeze-client-adapter-data-service-odata.mjs.map +0 -1
  258. package/fesm2022/breeze-client-adapter-data-service-webapi.mjs.map +0 -1
  259. package/fesm2022/breeze-client-adapter-model-library-backing-store.mjs +0 -276
  260. package/fesm2022/breeze-client-adapter-model-library-backing-store.mjs.map +0 -1
  261. package/fesm2022/breeze-client-adapter-model-library-ko.mjs +0 -248
  262. package/fesm2022/breeze-client-adapter-model-library-ko.mjs.map +0 -1
  263. package/fesm2022/breeze-client-adapter-uri-builder-json.mjs.map +0 -1
  264. package/fesm2022/breeze-client-adapter-uri-builder-odata.mjs +0 -246
  265. package/fesm2022/breeze-client-adapter-uri-builder-odata.mjs.map +0 -1
  266. package/fesm2022/breeze-client-mixin-get-entity-graph.mjs.map +0 -1
  267. package/fesm2022/breeze-client-mixin-save-queuing.mjs.map +0 -1
  268. package/fesm2022/breeze-client.mjs +0 -14144
  269. package/fesm2022/breeze-client.mjs.map +0 -1
  270. package/index.d.ts +0 -1
  271. package/mixin-get-entity-graph/index.d.ts +0 -5
  272. package/mixin-get-entity-graph/mixin-get-entity-graph.d.ts +0 -31
  273. package/mixin-save-queuing/index.d.ts +0 -5
  274. package/mixin-save-queuing/mixin-save-queuing.d.ts +0 -32
  275. package/src/abstract-data-service-adapter.d.ts +0 -84
  276. package/src/array.d.ts +0 -3
  277. package/src/breeze.d.ts +0 -139
  278. package/src/complex-array.d.ts +0 -13
  279. package/src/config.d.ts +0 -104
  280. package/src/core.d.ts +0 -164
  281. package/src/csdl-metadata-parser.d.ts +0 -7
  282. package/src/data-type.d.ts +0 -89
  283. package/src/default-property-interceptor.d.ts +0 -4
  284. package/src/entity-aspect.d.ts +0 -332
  285. package/src/entity-group.d.ts +0 -28
  286. package/src/entity-key.d.ts +0 -77
  287. package/src/entity-manager.d.ts +0 -680
  288. package/src/entity-metadata.d.ts +0 -988
  289. package/src/entity-query.d.ts +0 -444
  290. package/src/enum.d.ts +0 -100
  291. package/src/event.d.ts +0 -142
  292. package/src/interface-registry.d.ts +0 -150
  293. package/src/key-generator.d.ts +0 -12
  294. package/src/observable-array.d.ts +0 -52
  295. package/src/predicate.d.ts +0 -376
  296. package/src/primitive-array.d.ts +0 -7
  297. package/src/relation-array.d.ts +0 -18
  298. package/src/unattached-children-map.d.ts +0 -19
  299. package/src/validate.d.ts +0 -650
@@ -1,995 +0,0 @@
1
- import { core } from './core';
2
- import { assertParam } from './assert-param';
3
- import { config } from './config';
4
- export const INT16_MIN = -32768;
5
- export const INT16_MAX = 32767;
6
- export const INT32_MIN = -2147483648;
7
- export const INT32_MAX = 2147483647;
8
- export const BYTE_MIN = 0;
9
- export const BYTE_MAX = 255;
10
- // add common props and methods for every validator 'context' here.
11
- let rootContext = {
12
- displayName: function (context) {
13
- if (context.property) {
14
- return context.property.resolveProperty("displayName") || context.propertyName || context.property.name;
15
- }
16
- else {
17
- return "Value";
18
- }
19
- }
20
- };
21
- /**
22
- Instances of the Validator class provide the logic to validate another object and provide a description of any errors
23
- encountered during the validation process. They are typically associated with a 'validators' property on the following types: [[EntityType]],
24
- [[DataProperty]] or [[NavigationProperty]].
25
-
26
- A number of property level validators are registered automatically, i.e added to each DataProperty.validators property
27
- based on [[DataProperty]] metadata. For example,
28
-
29
- - DataProperty.dataType -> one of the 'dataType' validator methods such as Validator.int64, Validator.date, Validator.bool etc.
30
- - DataProperty.maxLength -> Validator.maxLength
31
- - DataProperty.isNullable -> Validator.required (if not nullable)
32
-
33
- @class Validator
34
- **/
35
- /**
36
- Validator constructor - This method is used to create create custom validations. Several
37
- basic "Validator" construction methods are also provided as static methods to this class. These methods
38
- provide a simpler syntax for creating basic validations.
39
-
40
- Many of these stock validators are inspired by and implemented to conform to the validators defined at
41
- http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx
42
-
43
- Sometimes a custom validator will be required.
44
- @example
45
- Most validators will be 'property' level validators, like this.
46
- @example
47
- // v is this function is the value to be validated, in this case a "country" string.
48
- var valFn = function (v) {
49
- if (v == null) return true;
50
- return (core.stringStartsWith(v, "US"));
51
- };
52
- var countryValidator = new Validator("countryIsUS", valFn, {
53
- displayName: "Country",
54
- messageTemplate: "'%displayName%' must start with 'US'"
55
- });
56
-
57
- // Now plug it into Breeze.
58
- // Assume em1 is a preexisting EntityManager.
59
- var custType = metadataStore.getEntityType("Customer");
60
- var countryProp = custType.getProperty("Country");
61
- // Note that validator is added to a 'DataProperty' validators collection.
62
- prop.validators.push(countryValidator);
63
- Entity level validators are also possible
64
- @example
65
- function isValidZipCode(value) {
66
- var re = /^\d{5}([\-]\d{4})?$/;
67
- return (re.test(value));
68
- }
69
-
70
- // v in this case will be a Customer entity
71
- var valFn = function (v) {
72
- // This validator only validates US Zip Codes.
73
- if ( v.getProperty("Country") === "USA") {
74
- var postalCode = v.getProperty("PostalCode");
75
- return isValidZipCode(postalCode);
76
- }
77
- return true;
78
- };
79
- var zipCodeValidator = new Validator("zipCodeValidator", valFn,
80
- { messageTemplate: "For the US, this is not a valid PostalCode" });
81
-
82
- // Now plug it into Breeze.
83
- // Assume em1 is a preexisting EntityManager.
84
- var custType = em1.metadataStore.getEntityType("Customer");
85
- // Note that validator is added to an 'EntityType' validators collection.
86
- custType.validators.push(zipCodeValidator);
87
- What is commonly needed is a way of creating a parameterized function that will itself
88
- return a new Validator. This requires the use of a 'context' object.
89
- @example
90
- // create a function that will take in a config object
91
- // and will return a validator
92
- var numericRangeValidator = function(context) {
93
- var valFn = function(v, ctx) {
94
- if (v == null) return true;
95
- if (typeof(v) !== "number") return false;
96
- if (ctx.min != null && v < ctx.min) return false;
97
- if (ctx.max != null && v > ctx.max) return false;
98
- return true;
99
- };
100
- // The last parameter below is the 'context' object that will be passed into the 'ctx' parameter above
101
- // when this validator executes. Several other properties, such as displayName will get added to this object as well.
102
- return new Validator("numericRange", valFn, {
103
- messageTemplate: "'%displayName%' must be a number between the values of %min% and %max%",
104
- min: context.min,
105
- max: context.max
106
- });
107
- };
108
- // Assume that freightProperty is a DataEntityProperty that describes numeric values.
109
- // register the validator
110
- freightProperty.validators.push(numericRangeValidator({ min: 100, max: 500 }));
111
-
112
- Breeze substitutes context values and functions for the tokens in the messageTemplate when preparing the runtime error message;
113
- 'displayName' is a pre-defined context function that is always available.
114
-
115
- Please note that Breeze substitutes the empty string for falsey parameters. That usually works in your favor.
116
- Sometimes it doesn't as when the 'min' value is zero in which case the message text would have a hole
117
- where the 'min' value goes, saying: "... an integer between the values of and ...". That is not what you want.
118
-
119
- To avoid this effect, you may can bake certain of the context values into the 'messageTemplate' itself
120
- as shown in this revision to the pertinent part of the previous example:
121
- @example
122
- // ... as before
123
- // ... but bake the min/max values into the message template.
124
- var template = breeze.core.formatString(
125
- "'%displayName%' must be a number between the values of %1 and %2",
126
- context.min, context.max);
127
- return new Validator("numericRange", valFn, {
128
- messageTemplate: template,
129
- min: context.min,
130
- max: context.max
131
- });
132
-
133
- @method <ctor> Validator
134
- @param name {String} The name of this validator.
135
- @param validatorFn {Function} A function to perform validation.
136
-
137
- validatorFn(value, context)
138
- @param validatorFn.value {Object} Value to be validated
139
- @param validatorFn.context {Object} The same context object passed into the constructor with the following additional properties if not
140
- otherwise specified.
141
- @param validatorFn.context.value {Object} The value being validated.
142
- @param validatorFn.context.name {String} The name of the validator being executed.
143
- @param validatorFn.context.displayName {String} This will be either the value of the property's 'displayName' property or
144
- the value of its 'name' property or the string 'Value'
145
- @param validatorFn.context.messageTemplate {String} This will either be the value of Validator.messageTemplates[ {this validators name}] or null. Validator.messageTemplates
146
- is an object that is keyed by validator name and that can be added to in order to 'register' your own message for a given validator.
147
- The following property can also be specified for any validator to force a specific errorMessage string
148
- @param [validatorFn.context.message] {String} If this property is set it will be used instead of the 'messageTemplate' property when an
149
- error message is generated.
150
-
151
- @param [context] {Object} A free form object whose properties will made available during the validation and error message creation process.
152
- This object will be passed into the Validator's validation function whenever 'validate' is called. See above for a description
153
- of additional properties that will be automatically added to this object if not otherwise specified.
154
- @dynamic
155
- **/
156
- export class Validator {
157
- constructor(name, valFn, context) {
158
- // _baseContext is what will get serialized
159
- this._baseContext = context || {};
160
- this._baseContext.name = name;
161
- context = core.extend(Object.create(rootContext), this._baseContext);
162
- context.messageTemplate = context.messageTemplate || Validator.messageTemplates[name];
163
- this.name = name;
164
- this.valFn = valFn;
165
- this.context = context;
166
- }
167
- /**
168
- The name of this validator.
169
-
170
- __readOnly__
171
- @property name {String}
172
- **/
173
- /**
174
- The context for this validator.
175
-
176
- This object will typically contain at a minimum the following properties. "name", "displayName", and "message" or "messageTemplate".
177
- __readOnly__
178
- @property context {Object}
179
- **/
180
- /**
181
- Run this validator against the specified value. This method will usually be called internally either
182
- automatically by an property change, entity attach, query or save operation, or manually as a result of
183
- a validateEntity call on the EntityAspect. The resulting ValidationResults are available via the
184
- EntityAspect.getValidationErrors method.
185
-
186
- However, you can also call a validator directly either for testing purposes or some other reason if needed.
187
- @example
188
- // using one of the predefined validators
189
- var validator = Validator.maxLength({ maxLength: 5, displayName: "City" });
190
- // should be ok because "asdf".length < 5
191
- var result = validator.validate("asdf");
192
- ok(result === null);
193
- result = validator.validate("adasdfasdf");
194
- // extract all of the properties of the 'result'
195
- var errMsg = result.errorMessage;
196
- var context = result.context;
197
- var sameValidator = result.validator;
198
- @method validate
199
- @param value {Object} Value to validate
200
- @param additionalContext {Object} Any additional contextual information that the Validator
201
- can make use of.
202
- @return {ValidationError|null} A ValidationError if validation fails, null otherwise
203
- **/
204
- validate(value, additionalContext) {
205
- let currentContext; // { value?: Object };
206
- if (additionalContext) {
207
- currentContext = core.extend(Object.create(this.context), additionalContext);
208
- }
209
- else {
210
- currentContext = this.context;
211
- }
212
- this.currentContext = currentContext;
213
- try {
214
- if (this.valFn(value, currentContext)) {
215
- return null;
216
- }
217
- else {
218
- currentContext.value = value;
219
- return new ValidationError(this, currentContext, this.getMessage());
220
- }
221
- }
222
- catch (e) {
223
- return new ValidationError(this, currentContext, "Exception occured while executing this validator: " + this.name);
224
- }
225
- }
226
- // context.value is not avail unless validate was called first.
227
- /**
228
- Returns the message generated by the most recent execution of this Validator.
229
- @example
230
- var v0 = Validator.maxLength({ maxLength: 5, displayName: "City" });
231
- v0.validate("adasdfasdf");
232
- var errMessage = v0.getMessage());
233
- @method getMessage
234
- @return {String}
235
- **/
236
- getMessage() {
237
- try {
238
- let context = this.currentContext;
239
- let message = context.message;
240
- if (message) {
241
- if (typeof (message) === "function") {
242
- return message(context);
243
- }
244
- else {
245
- return message;
246
- }
247
- }
248
- else if (context.messageTemplate) {
249
- return formatTemplate(context.messageTemplate, context);
250
- }
251
- else {
252
- return "invalid value: " + (this.name || "{unnamed validator}");
253
- }
254
- }
255
- catch (e) {
256
- return "Unable to format error message" + e.toString();
257
- }
258
- }
259
- toJSON() {
260
- return this._baseContext;
261
- }
262
- /**
263
- Creates a validator instance from a JSON object or an array of instances from an array of JSON objects.
264
- @method fromJSON
265
- @static
266
- @param json {Object} JSON object that represents the serialized version of a validator.
267
- **/
268
- static fromJSON(json) {
269
- if (Array.isArray(json)) {
270
- return json.map(function (js) {
271
- return Validator.fromJSON(js);
272
- });
273
- }
274
- if (json instanceof Validator) {
275
- return json;
276
- }
277
- let validatorName = "Validator." + json.name;
278
- let fn = config.getRegisteredFunction(validatorName);
279
- if (!fn) {
280
- throw new Error("Unable to locate a validator named:" + json.name);
281
- }
282
- return fn(json);
283
- }
284
- /**
285
- Register a validator instance so that any deserialized metadata can reference it.
286
- @method register
287
- @static
288
- @param validator {Validator} Validator to register.
289
- **/
290
- static register(validator) {
291
- config.registerFunction(function () {
292
- return validator;
293
- }, "Validator." + validator.name);
294
- }
295
- /**
296
- Register a validator factory so that any deserialized metadata can reference it.
297
- @method registerFactory
298
- @static
299
- @param validatorFactory {Function} A function that optionally takes a context property and returns a Validator instance.
300
- @param name {String} The name of the validator.
301
- **/
302
- static registerFactory(validatorFactory, name) {
303
- config.registerFunction(validatorFactory, "Validator." + name);
304
- }
305
- /**
306
- Map of standard error message templates keyed by validator name.
307
- You can add to or modify this object to customize the template used for any validation error message.
308
- @example
309
- // v is this function is the value to be validated, in this case a "country" string.
310
- var valFn = function (v) {
311
- if (v == null) return true;
312
- return (core.stringStartsWith(v, "US"));
313
- };
314
- var countryValidator = new Validator("countryIsUS", valFn, { displayName: "Country" });
315
- Validator.messageTemplates.countryIsUS = "'%displayName%' must start with 'US'";
316
- // This will have a similar effect to this
317
- var countryValidator = new Validator("countryIsUS", valFn, {
318
- displayName: "Country",
319
- messageTemplate: "'%displayName%' must start with 'US'"
320
- });
321
- @property messageTemplates {Object}
322
- @static
323
- **/
324
- static messageTemplates = {
325
- bool: "'%displayName%' must be a 'true' or 'false' value",
326
- creditCard: "The %displayName% is not a valid credit card number",
327
- date: "'%displayName%' must be a date",
328
- duration: "'%displayName%' must be a ISO8601 duration string, such as 'P3H24M60S'",
329
- emailAddress: "The %displayName% '%value%' is not a valid email address",
330
- guid: "'%displayName%' must be a GUID",
331
- integer: "'%displayName%' must be an integer",
332
- integerRange: "'%displayName%' must be an integer between the values of %minValue% and %maxValue%",
333
- maxLength: "'%displayName%' must be a string with %maxLength% characters or less",
334
- number: "'%displayName%' must be a number",
335
- phone: "The %displayName% '%value%' is not a valid phone number",
336
- regularExpression: "The %displayName% '%value%' does not match '%expression%'",
337
- required: "'%displayName%' is required",
338
- string: "'%displayName%' must be a string",
339
- stringLength: "'%displayName%' must be a string with between %minLength% and %maxLength% characters",
340
- url: "The %displayName% '%value%' is not a valid url"
341
- };
342
- /**
343
- Returns a standard 'required value' Validator
344
- @example
345
- // Assume em1 is a preexisting EntityManager.
346
- var custType = em1.metadataStore.getEntityType("Customer");
347
- var regionProperty - custType.getProperty("Region");
348
- // Makes "Region" on Customer a required property.
349
- regionProperty.validators.push(Validator.required());
350
- // or to allow empty strings
351
- regionProperty.validators.push(Validator.required({ allowEmptyStrings: true }););
352
- @method required
353
- @static
354
- @param context {Object}
355
- @param [context.allowEmptyStrings] {Boolean} If this parameter is omitted or false then empty strings do NOT pass validation.
356
- @return {Validator} A new Validator
357
- **/
358
- static required = function (context) {
359
- let valFn = function (v, ctx) {
360
- if (typeof v === "string") {
361
- if (ctx && ctx.allowEmptyStrings)
362
- return true;
363
- return v.length > 0;
364
- }
365
- else {
366
- return v != null;
367
- }
368
- };
369
- return new Validator("required", valFn, context);
370
- };
371
- /**
372
- Returns a standard maximum string length Validator; the maximum length must be specified
373
- @example
374
- // Assume em1 is a preexisting EntityManager.
375
- var custType = em1.metadataStore.getEntityType("Customer");
376
- var regionProperty - custType.getProperty("Region");
377
- // Validates that the value of the Region property on Customer will be less than or equal to 5 characters.
378
- regionProperty.validators.push(Validator.maxLength( {maxLength: 5}));
379
- @method maxLength
380
- @static
381
- @param context {Object}
382
- @param context.maxLength {Integer}
383
- @return {Validator} A new Validator
384
- **/
385
- static maxLength = function (context) {
386
- let valFn = function (v, ctx) {
387
- if (v == null)
388
- return true;
389
- if (typeof (v) !== "string")
390
- return false;
391
- return v.length <= ctx.maxLength;
392
- };
393
- return new Validator("maxLength", valFn, context);
394
- };
395
- /**
396
- Returns a standard string length Validator; both minimum and maximum lengths must be specified.
397
- @example
398
- // Assume em1 is a preexisting EntityManager.
399
- var custType = em1.metadataStore.getEntityType("Customer");
400
- var regionProperty - custType.getProperty("Region");
401
- // Validates that the value of the Region property on Customer will be
402
- // between 2 and 5 characters
403
- regionProperty.validators.push(Validator.stringLength( {minLength: 2, maxLength: 5});
404
- @method stringLength
405
- @static
406
- @param context {Object}
407
- @param context.maxLength {Integer}
408
- @param context.minLength {Integer}
409
- @return {Validator} A new Validator
410
- **/
411
- static stringLength = function (context) {
412
- let valFn = function (v, ctx) {
413
- if (v == null)
414
- return true;
415
- if (typeof (v) !== "string")
416
- return false;
417
- if (ctx.minLength != null && v.length < ctx.minLength)
418
- return false;
419
- if (ctx.maxLength != null && v.length > ctx.maxLength)
420
- return false;
421
- return true;
422
- };
423
- return new Validator("stringLength", valFn, context);
424
- };
425
- /**
426
- Returns a standard string dataType Validator.
427
- @example
428
- // Assume em1 is a preexisting EntityManager.
429
- var custType = em1.metadataStore.getEntityType("Customer");
430
- var regionProperty - custType.getProperty("Region");
431
- // Validates that the value of the Region property on Customer is a string.
432
- regionProperty.validators.push(Validator.string());
433
- @method string
434
- @static
435
- @return {Validator} A new Validator
436
- **/
437
- static string = function () {
438
- let valFn = function (v) {
439
- if (v == null)
440
- return true;
441
- return (typeof v === "string");
442
- };
443
- return new Validator("string", valFn);
444
- };
445
- /**
446
- Returns a Guid data type Validator.
447
- @example
448
- // Assume em1 is a preexisting EntityManager.
449
- var custType = em1.metadataStore.getEntityType("Customer");
450
- var customerIdProperty - custType.getProperty("CustomerID");
451
- // Validates that the value of the CustomerID property on Customer is a Guid.
452
- customerIdProperty.validators.push(Validator.guid());
453
- @method guid
454
- @static
455
- @return {Validator} A new Validator
456
- **/
457
- static guid = function () {
458
- let valFn = function (v) {
459
- if (v == null)
460
- return true;
461
- return core.isGuid(v);
462
- };
463
- return new Validator("guid", valFn);
464
- };
465
- /**
466
- Returns a ISO 8601 duration string Validator.
467
- @example
468
- // Assume em1 is a preexisting EntityManager.
469
- var eventType = em1.metadataStore.getEntityType("Event");
470
- var elapsedTimeProperty - eventType.getProperty("ElapsedTime");
471
- // Validates that the value of the ElapsedTime property on Customer is a duration.
472
- elapsedTimeProperty.validators.push(Validator.duration());
473
- @method duration
474
- @static
475
- @return {Validator} A new Validator
476
- **/
477
- static duration = function () {
478
- let valFn = function (v) {
479
- if (v == null)
480
- return true;
481
- return core.isDuration(v);
482
- };
483
- return new Validator("duration", valFn);
484
- };
485
- /**
486
- Returns a standard numeric data type Validator.
487
- @example
488
- // Assume em1 is a preexisting EntityManager.
489
- var orderType = em1.metadataStore.getEntityType("Order");
490
- var freightProperty - orderType.getProperty("Freight");
491
- // Validates that the value of the Freight property on Order is a number.
492
- freightProperty.validators.push(Validator.number());
493
- @method number
494
- @static
495
- @return {Validator} A new Validator
496
- **/
497
- // TODO: may need to have seperate logic for single.
498
- static number = function (context) {
499
- let valFn = function (v, ctx) {
500
- if (v == null)
501
- return true;
502
- if (typeof v === "string" && ctx && ctx.allowString) {
503
- v = parseFloat(v);
504
- }
505
- return (typeof v === "number" && !isNaN(v));
506
- };
507
- return new Validator("number", valFn, context);
508
- };
509
- static double = Validator.number;
510
- static single = Validator.number;
511
- /**
512
- Returns a standard large integer data type - 64 bit - Validator.
513
- @example
514
- // Assume em1 is a preexisting EntityManager.
515
- var orderType = em1.metadataStore.getEntityType("Order");
516
- var freightProperty - orderType.getProperty("Freight");
517
- // Validates that the value of the Freight property on Order is within the range of a 64 bit integer.
518
- freightProperty.validators.push(Validator.int64());
519
- @method int64
520
- @static
521
- @return {Validator} A new Validator
522
- **/
523
- static integer = function (context) {
524
- let valFn = function (v, ctx) {
525
- if (v == null)
526
- return true;
527
- if (typeof v === "string" && ctx && ctx.allowString) {
528
- v = parseInt(v, 10);
529
- }
530
- return (typeof v === "number") && (!isNaN(v)) && Math.floor(v) === v;
531
- };
532
- return new Validator("integer", valFn, context);
533
- };
534
- static int64 = Validator.integer;
535
- /**
536
- Returns a standard 32 bit integer data type Validator.
537
- @example
538
- // Assume em1 is a preexisting EntityManager.
539
- var orderType = em1.metadataStore.getEntityType("Order");
540
- var freightProperty - orderType.getProperty("Freight");
541
- freightProperty.validators.push(Validator.int32());
542
- @method int32
543
- @static
544
- @return {Validator} A new Validator
545
- **/
546
- static int32 = function (context) {
547
- return intRangeValidatorCtor("int32", INT32_MIN, INT32_MAX, context)();
548
- };
549
- /**
550
- Returns a standard 16 bit integer data type Validator.
551
- @example
552
- // Assume em1 is a preexisting EntityManager.
553
- var orderType = em1.metadataStore.getEntityType("Order");
554
- var freightProperty - orderType.getProperty("Freight");
555
- // Validates that the value of the Freight property on Order is within the range of a 16 bit integer.
556
- freightProperty.validators.push(Validator.int16());
557
- @method int16
558
- @static
559
- @return {Validator} A new Validator
560
- **/
561
- static int16 = function (context) {
562
- return intRangeValidatorCtor("int16", INT16_MIN, INT16_MAX, context)();
563
- };
564
- /**
565
- Returns a standard byte data type Validator. (This is a integer between 0 and 255 inclusive for js purposes).
566
- @example
567
- // Assume em1 is a preexisting EntityManager.
568
- var orderType = em1.metadataStore.getEntityType("Order");
569
- var freightProperty - orderType.getProperty("Freight");
570
- // Validates that the value of the Freight property on Order is within the range of a 16 bit integer.
571
- // Probably not a very good validation to place on the Freight property.
572
- regionProperty.validators.push(Validator.byte());
573
- @method byte
574
- @static
575
- @return {Validator} A new Validator
576
- **/
577
- static byte = function (context) {
578
- return intRangeValidatorCtor("byte", BYTE_MIN, BYTE_MAX, context)();
579
- };
580
- /**
581
- Returns a standard boolean data type Validator.
582
- @example
583
- // Assume em1 is a preexisting EntityManager.
584
- var productType = em1.metadataStore.getEntityType("Product");
585
- var discontinuedProperty - productType.getProperty("Discontinued");
586
- // Validates that the value of the Discontinued property on Product is a boolean
587
- discontinuedProperty.validators.push(Validator.bool());
588
- @method bool
589
- @static
590
- @return {Validator} A new Validator
591
- **/
592
- static bool = function () {
593
- let valFn = function (v) {
594
- if (v == null)
595
- return true;
596
- return (v === true) || (v === false);
597
- };
598
- return new Validator("bool", valFn);
599
- };
600
- static none = function () {
601
- let valFn = function (v) {
602
- return true;
603
- };
604
- return new Validator("none", valFn);
605
- };
606
- /**
607
- Returns a standard date data type Validator.
608
- @example
609
- // Assume em1 is a preexisting EntityManager.
610
- var orderType = em1.metadataStore.getEntityType("Order");
611
- var orderDateProperty - orderType.getProperty("OrderDate");
612
- // Validates that the value of the OrderDate property on Order is a date
613
- // Probably not a very good validation to place on the Freight property.
614
- orderDateProperty.validators.push(Validator.date());
615
- @method date
616
- @static
617
- @return {Validator} A new Validator
618
- **/
619
- static date = function () {
620
- let valFn = function (v) {
621
- if (v == null)
622
- return true;
623
- if (typeof v === "string") {
624
- try {
625
- return !isNaN(Date.parse(v));
626
- // old code
627
- // return __isDate(new Date(v));
628
- }
629
- catch (e) {
630
- return false;
631
- }
632
- }
633
- else {
634
- return core.isDate(v);
635
- }
636
- };
637
- return new Validator("date", valFn);
638
- };
639
- /**
640
- Returns a credit card number validator
641
- Performs a luhn algorithm checksum test for plausability
642
- catches simple mistakes; only service knows for sure
643
- @example
644
- // Assume em is a preexisting EntityManager.
645
- var personType = em.metadataStore.getEntityType("Person");
646
- var creditCardProperty = personType.getProperty("creditCard");
647
- // Validates that the value of the Person.creditCard property is credit card.
648
- creditCardProperty.validators.push(Validator.creditCard());
649
- @method creditCard
650
- @static
651
- @param [context] {Object} optional parameters to pass through to validation constructor
652
- @return {Validator} A new Validator
653
- **/
654
- static creditCard = function (context) {
655
- function valFn(v) {
656
- if (v == null || v === '')
657
- return true;
658
- if (typeof (v) !== 'string')
659
- return false;
660
- v = v.replace(/(\-|\s)/g, ""); // remove dashes and spaces
661
- if (!v || /\D/.test(v))
662
- return false; // all digits, not empty
663
- return luhn(v);
664
- }
665
- return new Validator('creditCard', valFn, context);
666
- };
667
- /**
668
- Returns a regular expression validator; the expression must be specified
669
- @example
670
- // Add validator to a property. Assume em is a preexisting EntityManager.
671
- var customerType = em.metadataStore.getEntityType("Customer");
672
- var regionProperty = customerType.getProperty("Region");
673
- // Validates that the value of Customer.Region is 2 char uppercase alpha.
674
- regionProperty.validators.push(Validator.regularExpression( {expression: '^[A-Z]{2}$'} );
675
- @method regularExpression
676
- @static
677
- @param context {Object}
678
- @param context.expression {String} String form of the regular expression to apply
679
- @return {Validator} A new Validator
680
- **/
681
- static regularExpression = function (context) {
682
- function valFn(v, ctx) {
683
- // do not invalidate if empty; use a separate required test
684
- if (v == null || v === '')
685
- return true;
686
- if (typeof (v) !== 'string')
687
- return false;
688
- try {
689
- let re = new RegExp(ctx.expression);
690
- return re.test(v);
691
- }
692
- catch (e) {
693
- throw new Error('Missing or invalid expression parameter to regExp validator');
694
- }
695
- }
696
- return new Validator('regularExpression', valFn, context);
697
- };
698
- /**
699
- Returns the email address validator
700
- @example
701
- // Assume em is a preexisting EntityManager.
702
- var personType = em.metadataStore.getEntityType("Person");
703
- var emailProperty = personType.getProperty("email");
704
- // Validates that the value of the Person.email property is an email address.
705
- emailProperty.validators.push(Validator.emailAddress());
706
- @method emailAddress
707
- @static
708
- @param [context] {Object} optional parameters to pass through to validation constructor
709
- @return {Validator} A new Validator
710
- **/
711
- static emailAddress = function (context) {
712
- // See https://github.com/srkirkland/DataAnnotationsExtensions/blob/master/DataAnnotationsExtensions/EmailAttribute.cs
713
- let reEmailAddress = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i;
714
- return makeRegExpValidator('emailAddress', reEmailAddress, null, context);
715
- };
716
- /**
717
- Returns the phone validator
718
- Provides basic assertions on the format and will help to eliminate most nonsense input
719
- Matches:
720
- International dialing prefix: {{}, +, 0, 0000} (with or without a trailing break character, if not '+': [-/. ])
721
- > ((\+)|(0(\d+)?[-/.\s]))
722
- Country code: {{}, 1, ..., 999} (with or without a trailing break character: [-/. ])
723
- > [1-9]\d{,2}[-/.\s]?
724
- Area code: {(0), ..., (000000), 0, ..., 000000} (with or without a trailing break character: [-/. ])
725
- > ((\(\d{1,6}\)|\d{1,6})[-/.\s]?)?
726
- Local: {0, ...}+ (with or without a trailing break character: [-/. ])
727
- > (\d+[-/.\s]?)+\d+
728
- @example
729
- // Assume em is a preexisting EntityManager.
730
- var customerType = em.metadataStore.getEntityType("Customer");
731
- var phoneProperty = customerType.getProperty("phone");
732
- // Validates that the value of the Customer.phone property is phone.
733
- phoneProperty.validators.push(Validator.phone());
734
- @method phone
735
- @static
736
- @param [context] {Object} optional parameters to pass through to validation constructor
737
- @return {Validator} A new Validator
738
- **/
739
- static phone = function (context) {
740
- // See https://github.com/srkirkland/DataAnnotationsExtensions/blob/master/DataAnnotationsExtensions/Expressions.cs
741
- let rePhone = /^((\+|(0(\d+)?[-/.\s]?))[1-9]\d{0,2}[-/.\s]?)?((\(\d{1,6}\)|\d{1,6})[-/.\s]?)?(\d+[-/.\s]?)+\d+$/;
742
- return makeRegExpValidator('phone', rePhone, null, context);
743
- };
744
- /**
745
- Returns the URL (protocol required) validator
746
- @example
747
- // Assume em is a preexisting EntityManager.
748
- var personType = em.metadataStore.getEntityType("Person");
749
- var websiteProperty = personType.getProperty("website");
750
- // Validates that the value of the Person.website property is a URL.
751
- websiteProperty.validators.push(Validator.url());
752
- @method url
753
- @static
754
- @param [context] {Object} optional parameters to pass through to validation constructor
755
- @return {Validator} A new Validator
756
- **/
757
- static url = function (context) {
758
- //See https://github.com/srkirkland/DataAnnotationsExtensions/blob/master/DataAnnotationsExtensions/UrlAttribute.cs
759
- let reUrlProtocolRequired = /^(https?|ftp):\/\/(((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|([a-zA-Z][\-a-zA-Z0-9]*)|((([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/;
760
- return makeRegExpValidator('url', reUrlProtocolRequired, null, context);
761
- };
762
- /**
763
- Creates a regular expression validator with a fixed expression.
764
- Many of the stock validators are built with this factory method.
765
- Their expressions are often derived from
766
- https://github.com/srkirkland/DataAnnotationsExtensions/blob/master/DataAnnotationsExtensions
767
- You can try many of them at http://dataannotationsextensions.org/
768
- @example
769
- // Make a zipcode validator
770
- function zipValidator = Validator.makeRegExpValidator(
771
- "zipVal,
772
- /^\d{5}([\-]\d{4})?$/,
773
- "The %displayName% '%value%' is not a valid U.S. zipcode");
774
- // Register it.
775
- Validator.register(zipValidator);
776
- // Add it to a data property. Assume em is a preexisting EntityManager.
777
- var custType = em.metadataStore.getEntityType("Customer");
778
- var zipProperty = custType.getProperty("PostalCode");
779
- zipProperty.validators.push(zipValidator);
780
- @method makeRegExpValidator
781
- @static
782
- @param validatorName {String} name of this validator
783
- @param expression {String | RegExp} regular expression to apply
784
- @param [defaultMessage] {String} default message for failed validations
785
- @param [context] {Object} optional parameters to pass through to validation constructor
786
- @return {Validator} A new Validator
787
- **/
788
- static makeRegExpValidator = makeRegExpValidator;
789
- }
790
- Validator.prototype._$typeName = "Validator";
791
- // register all validators
792
- Error['x'] = core.objectForEach(Validator, function (key, value) {
793
- if (typeof (value) !== "function") {
794
- return;
795
- }
796
- if (key === "fromJSON" || key === "register" ||
797
- key === "registerFactory" || key === "makeRegExpValidator") {
798
- return;
799
- }
800
- config.registerFunction(value, "Validator." + key);
801
- });
802
- function formatTemplate(template, vars, ownPropertiesOnly = false) {
803
- if (!vars)
804
- return template;
805
- return template.replace(/%([^%]+)%/g, function (_, key) {
806
- let valOrFn;
807
- if (ownPropertiesOnly) {
808
- valOrFn = vars.hasOwnProperty(key) ? vars[key] : '';
809
- }
810
- else {
811
- valOrFn = vars[key];
812
- }
813
- if (valOrFn != null) {
814
- if (core.isFunction(valOrFn)) {
815
- return valOrFn(vars);
816
- }
817
- else {
818
- return valOrFn;
819
- }
820
- }
821
- else {
822
- return "";
823
- }
824
- });
825
- }
826
- function intRangeValidatorCtor(validatorName, minValue, maxValue, context) {
827
- context = context || {};
828
- if (minValue !== undefined) {
829
- context.min = minValue;
830
- }
831
- if (maxValue !== undefined) {
832
- context.max = maxValue;
833
- }
834
- let templateExists = context.messageTemplate || Validator.messageTemplates[validatorName];
835
- if (!templateExists) {
836
- Validator.messageTemplates[validatorName] = core.formatString("'%displayName%' must be an integer between the values of %1 and %2", minValue, maxValue);
837
- }
838
- return function () {
839
- let valFn = function (v, ctx) {
840
- if (v == null)
841
- return true;
842
- if (typeof v === "string" && ctx && ctx.allowString) {
843
- v = parseInt(v, 0);
844
- }
845
- if ((typeof v === "number") && (!isNaN(v)) && Math.floor(v) === v) {
846
- if (minValue != null && v < minValue) {
847
- return false;
848
- }
849
- if (maxValue != null && v > maxValue) {
850
- return false;
851
- }
852
- return true;
853
- }
854
- else {
855
- return false;
856
- }
857
- };
858
- return new Validator(validatorName, valFn, context);
859
- };
860
- }
861
- export function makeRegExpValidator(validatorName, expression, defaultMessage, context) {
862
- if (defaultMessage) {
863
- Validator.messageTemplates[validatorName] = defaultMessage;
864
- }
865
- let re = (typeof (expression) === 'string') ? new RegExp(expression) : expression;
866
- let valFn = function (v) {
867
- // do not invalidate if empty; use a separate required test
868
- if (v == null || v === '')
869
- return true;
870
- if (typeof (v) !== 'string')
871
- return false;
872
- return re.test(v);
873
- };
874
- return new Validator(validatorName, valFn, context);
875
- }
876
- // http://rosettacode.org/wiki/Luhn_test_of_credit_card_numbers#JavaScript
877
- // function luhn(a: string, b: number, c: number, d: number, e: number) {
878
- // for (d = +a[b = a.length - 1], e = 0; b--; ) {
879
- // c = +a[b], d += ++e % 2 ? 2 * c % 10 + (c > 4) : c;
880
- // }
881
- // return !(d % 10);
882
- // };
883
- let luhn = (function () {
884
- let luhnArr = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9];
885
- return function (str) {
886
- let counter = 0;
887
- let incNum;
888
- let odd = false;
889
- let temp = String(str).replace(/[^\d]/g, "");
890
- if (temp.length === 0)
891
- return false;
892
- for (let i = temp.length - 1; i >= 0; --i) {
893
- incNum = parseInt(temp.charAt(i), 10);
894
- counter += (odd = !odd) ? incNum : luhnArr[incNum];
895
- }
896
- return (counter % 10 === 0);
897
- };
898
- })();
899
- /**
900
- A ValidationError is used to describe a failed validation.
901
-
902
- @class ValidationError
903
- **/
904
- /**
905
- Constructs a new ValidationError
906
- @method <ctor> ValidationError
907
-
908
- @param validator {Validator || null} The Validator used to create this error, if any.
909
- @param context { ContextObject || null} The Context object used in conjunction with the Validator to create this error.
910
- @param errorMessage { String} The actual error message
911
- @param [key] {String} An optional key used to define a key for this error. One will be created automatically if not provided here.
912
- **/
913
- export class ValidationError {
914
- validator;
915
- key;
916
- context;
917
- errorMessage;
918
- property; // IProperty
919
- propertyName;
920
- isServerError;
921
- constructor(validator, context, errorMessage, key) {
922
- // Error is with isInstanceOf(Validator)
923
- assertParam(validator, "validator").isOptional().isInstanceOf(Validator).check();
924
- assertParam(errorMessage, "errorMessage").isNonEmptyString().check();
925
- assertParam(key, "key").isOptional().isNonEmptyString().check();
926
- this.validator = validator || undefined;
927
- context = context || {};
928
- this.context = context;
929
- this.errorMessage = errorMessage;
930
- this.property = context.property;
931
- this.propertyName = context.propertyName || (context.property && context.property.name);
932
- if (key) {
933
- this.key = key;
934
- }
935
- else {
936
- this.key = ValidationError.getKey(validator || errorMessage, this.propertyName);
937
- }
938
- this.isServerError = false;
939
- }
940
- /**
941
- The Validator associated with this ValidationError.
942
-
943
- __readOnly__
944
- @property validator {Validator}
945
- **/
946
- /**
947
- A 'context' object associated with this ValidationError.
948
-
949
- __readOnly__
950
- @property context {Object}
951
- **/
952
- /**
953
- The DataProperty or NavigationProperty associated with this ValidationError.
954
-
955
- __readOnly__
956
- @property property {DataProperty|NavigationProperty}
957
- **/
958
- /**
959
- The property name associated with this ValidationError. This will be a "property path" for any properties of a complex object.
960
-
961
- __readOnly__
962
- @property propertyName {String}
963
- **/
964
- /**
965
- The error message associated with the ValidationError.
966
-
967
- __readOnly__
968
- @property errorMessage {string}
969
- **/
970
- /**
971
- The key by which this validation error may be removed from a collection of ValidationErrors.
972
-
973
- __readOnly__
974
- @property key {string}
975
- **/
976
- /**
977
- Whether this is a server error.
978
-
979
- __readOnly__
980
- @property isServerError {bool}
981
- **/
982
- /**
983
- Composes a ValidationError 'key' given a validator or an errorName and an optional propertyName
984
- @method getKey
985
- @static
986
- @param validator {ValidatorOrErrorKey} A Validator or an "error name" if no validator is available.
987
- @param [propertyName] A property name
988
- @return {String} A ValidationError 'key'
989
- **/
990
- static getKey(validatorOrErrorName, propertyName) {
991
- let name = (typeof validatorOrErrorName === 'string') ? validatorOrErrorName : validatorOrErrorName.name;
992
- return name + (propertyName ? ":" + propertyName : "");
993
- }
994
- }
995
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdmFsaWRhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUM5QixPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUlsQyxNQUFNLENBQUMsTUFBTSxTQUFTLEdBQUcsQ0FBQyxLQUFLLENBQUM7QUFDaEMsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQztBQUUvQixNQUFNLENBQUMsTUFBTSxTQUFTLEdBQUcsQ0FBQyxVQUFVLENBQUM7QUFDckMsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUFHLFVBQVUsQ0FBQztBQUVwQyxNQUFNLENBQUMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxDQUFDO0FBQzFCLE1BQU0sQ0FBQyxNQUFNLFFBQVEsR0FBRyxHQUFHLENBQUM7QUF3QjVCLG1FQUFtRTtBQUNuRSxJQUFJLFdBQVcsR0FBRztJQUNoQixXQUFXLEVBQUUsVUFBVSxPQUEwQjtRQUMvQyxJQUFJLE9BQU8sQ0FBQyxRQUFRLEVBQUU7WUFDcEIsT0FBTyxPQUFPLENBQUMsUUFBUSxDQUFDLGVBQWUsQ0FBQyxhQUFhLENBQUMsSUFBSSxPQUFPLENBQUMsWUFBWSxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDO1NBQ3pHO2FBQU07WUFDTCxPQUFPLE9BQU8sQ0FBQztTQUNoQjtJQUNILENBQUM7Q0FDRixDQUFDO0FBRUY7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUVIOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F3SEc7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UUFDRCxJQUFJLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQztJQUM3QixDQUFDO0lBR0Q7Ozs7O09BS0c7SUFFSDs7Ozs7T0FLRztJQUVIOzs7OztPQUtHO0lBRUg7Ozs7O09BS0c7SUFFSDs7Ozs7T0FLRztJQUVIOzs7OztPQUtHO0lBRUg7Ozs7O09BS0c7SUFHSDs7Ozs7OztPQU9HO0lBQ0ksTUFBTSxDQUFDLE1BQU0sQ0FBQyxvQkFBd0MsRUFBRSxZQUFxQjtRQUNsRixJQUFJLElBQUksR0FBRyxDQUFDLE9BQU8sb0JBQW9CLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLG9CQUFvQixDQUFDLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUM7UUFDekcsT0FBTyxJQUFJLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxZQUFZLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3pELENBQUM7Q0FFRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNvcmUgfSBmcm9tICcuL2NvcmUnO1xyXG5pbXBvcnQgeyBhc3NlcnRQYXJhbSB9IGZyb20gJy4vYXNzZXJ0LXBhcmFtJztcclxuaW1wb3J0IHsgY29uZmlnIH0gZnJvbSAnLi9jb25maWcnO1xyXG5pbXBvcnQgeyBOYXZpZ2F0aW9uUHJvcGVydHksIERhdGFQcm9wZXJ0eSB9IGZyb20gJy4vZW50aXR5LW1ldGFkYXRhJztcclxuaW1wb3J0IHsgRW50aXR5IH0gZnJvbSAnLi9lbnRpdHktYXNwZWN0JztcclxuXHJcbmV4cG9ydCBjb25zdCBJTlQxNl9NSU4gPSAtMzI3Njg7XHJcbmV4cG9ydCBjb25zdCBJTlQxNl9NQVggPSAzMjc2NztcclxuXHJcbmV4cG9ydCBjb25zdCBJTlQzMl9NSU4gPSAtMjE0NzQ4MzY0ODtcclxuZXhwb3J0IGNvbnN0IElOVDMyX01BWCA9IDIxNDc0ODM2NDc7XHJcblxyXG5leHBvcnQgY29uc3QgQllURV9NSU4gPSAwO1xyXG5leHBvcnQgY29uc3QgQllURV9NQVggPSAyNTU7XHJcblxyXG4vKiogUGFzc2VkIHRvIFZhbGlkYXRpb25GbiAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIFZhbGlkYXRpb25Db250ZXh0IHtcclxuICBlbnRpdHk/OiBFbnRpdHk7XHJcbiAgcHJvcGVydHk/OiBEYXRhUHJvcGVydHkgfCBOYXZpZ2F0aW9uUHJvcGVydHk7XHJcbiAgcHJvcGVydHlOYW1lPzogc3RyaW5nO1xyXG4gIHZhbHVlPzogYW55O1xyXG59XHJcblxyXG4vKiogVXNlZCBieSBWYWxpZGF0b3IgdG8gY29tcG9zZSBtZXNzYWdlcyAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIFZhbGlkYXRpb25NZXNzYWdlQ29udGV4dCBleHRlbmRzIFZhbGlkYXRpb25Db250ZXh0IHtcclxuICBuYW1lPzogc3RyaW5nO1xyXG4gIGRpc3BsYXlOYW1lPzogc3RyaW5nO1xyXG4gIG1lc3NhZ2VUZW1wbGF0ZT86IHN0cmluZztcclxuICBtZXNzYWdlPzogc3RyaW5nIHwgKCh2YzogVmFsaWRhdGlvbkNvbnRleHQpID0+IHN0cmluZyk7XHJcbiAgW2tleTpzdHJpbmddOiBhbnk7XHJcbn1cclxuXHJcbi8qKiBGdW5jdGlvbiBjYWxsZWQgdG8gdmFsaWRhdGUgYW4gZW50aXR5IG9yIHByb3BlcnR5ICovXHJcbmV4cG9ydCBpbnRlcmZhY2UgVmFsaWRhdGlvbkZuIHtcclxuICAgICh2YWx1ZTogYW55LCBjb250ZXh0PzogVmFsaWRhdGlvbkNvbnRleHQpOiBib29sZWFuO1xyXG59XHJcblxyXG4vLyBhZGQgY29tbW9uIHByb3BzIGFuZCBtZXRob2RzIGZvciBldmVyeSB2YWxpZGF0b3IgJ2NvbnRleHQnIGhlcmUuXHJcbmxldCByb290Q29udGV4dCA9IHtcclxuICBkaXNwbGF5TmFtZTogZnVuY3Rpb24gKGNvbnRleHQ6IFZhbGlkYXRpb25Db250ZXh0KSB7XHJcbiAgICBpZiAoY29udGV4dC5wcm9wZXJ0eSkge1xyXG4gICAgICByZXR1cm4gY29udGV4dC5wcm9wZXJ0eS5yZXNvbHZlUHJvcGVydHkoXCJkaXNwbGF5TmFtZVwiKSB8fCBjb250ZXh0LnByb3BlcnR5TmFtZSB8fCBjb250ZXh0LnByb3BlcnR5Lm5hbWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gXCJWYWx1ZVwiO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG5JbnN0YW5jZXMgb2YgdGhlIFZhbGlkYXRvciBjbGFzcyBwcm92aWRlIHRoZSBsb2dpYyB0byB2YWxpZGF0ZSBhbm90aGVyIG9iamVjdCBhbmQgcHJvdmlkZSBhIGRlc2NyaXB0aW9uIG9mIGFueSBlcnJvcnNcclxuZW5jb3VudGVyZWQgZHVyaW5nIHRoZSB2YWxpZGF0aW9uIHByb2Nlc3MuICBUaGV5IGFyZSB0eXBpY2FsbHkgYXNzb2NpYXRlZCB3aXRoIGEgJ3ZhbGlkYXRvcnMnIHByb3BlcnR5IG9uIHRoZSBmb2xsb3dpbmcgdHlwZXM6IFtbRW50aXR5VHlwZV1dLFxyXG5bW0RhdGFQcm9wZXJ0eV1dIG9yIFtbTmF2aWdhdGlvblByb3BlcnR5XV0uXHJcblxyXG5BIG51bWJlciBvZiBwcm9wZXJ0eSBsZXZlbCB2YWxpZGF0b3JzIGFyZSByZWdpc3RlcmVkIGF1dG9tYXRpY2FsbHksIGkuZSBhZGRlZCB0byBlYWNoIERhdGFQcm9wZXJ0eS52YWxpZGF0b3JzIHByb3BlcnR5XHJcbmJhc2VkIG9uIFtbRGF0YVByb3BlcnR5XV0gbWV0YWRhdGEuICBGb3IgZXhhbXBsZSxcclxuXHJcbi0gRGF0YVByb3BlcnR5LmRhdGFUeXBlIC0+IG9uZSBvZiB0aGUgJ2RhdGFUeXBlJyB2YWxpZGF0b3IgbWV0aG9kcyBzdWNoIGFzIFZhbGlkYXRvci5pbnQ2NCwgVmFsaWRhdG9yLmRhdGUsIFZhbGlkYXRvci5ib29sIGV0Yy5cclxuLSBEYXRhUHJvcGVydHkubWF4TGVuZ3RoIC0+IFZhbGlkYXRvci5tYXhMZW5ndGhcclxuLSBEYXRhUHJvcGVydHkuaXNOdWxsYWJsZSAtPiBWYWxpZGF0b3IucmVxdWlyZWQgKGlmIG5vdCBudWxsYWJsZSlcclxuXHJcbkBjbGFzcyBWYWxpZGF0b3JcclxuKiovXHJcblxyXG4vKipcclxuVmFsaWRhdG9yIGNvbnN0cnVjdG9yIC0gVGhpcyBtZXRob2QgaXMgdXNlZCB0byBjcmVhdGUgY3JlYXRlIGN1c3RvbSB2YWxpZGF0aW9ucy4gIFNldmVyYWxcclxuYmFzaWMgXCJWYWxpZGF0b3JcIiBjb25zdHJ1Y3Rpb24gbWV0aG9kcyBhcmUgYWxzbyBwcm92aWRlZCBhcyBzdGF0aWMgbWV0aG9kcyB0byB0aGlzIGNsYXNzLiBUaGVzZSBtZXRob2RzXHJcbnByb3ZpZGUgYSBzaW1wbGVyIHN5bnRheCBmb3IgY3JlYXRpbmcgYmFzaWMgdmFsaWRhdGlvbnMuXHJcblxyXG5NYW55IG9mIHRoZXNlIHN0b2NrIHZhbGlkYXRvcnMgYXJlIGluc3BpcmVkIGJ5IGFuZCBpbXBsZW1lbnRlZCB0byBjb25mb3JtIHRvIHRoZSB2YWxpZGF0b3JzIGRlZmluZWQgYXRcclxuaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbS9lbi11cy9saWJyYXJ5L3N5c3RlbS5jb21wb25lbnRtb2RlbC5kYXRhYW5ub3RhdGlvbnMuYXNweFxyXG5cclxuU29tZXRpbWVzIGEgY3VzdG9tIHZhbGlkYXRvciB3aWxsIGJlIHJlcXVpcmVkLlxyXG5AZXhhbXBsZVxyXG5Nb3N0IHZhbGlkYXRvcnMgd2lsbCBiZSAncHJvcGVydHknIGxldmVsIHZhbGlkYXRvcnMsIGxpa2UgdGhpcy5cclxuQGV4YW1wbGVcclxuICAgIC8vIHYgaXMgdGhpcyBmdW5jdGlvbiBpcyB0aGUgdmFsdWUgdG8gYmUgdmFsaWRhdGVkLCBpbiB0aGlzIGNhc2UgYSBcImNvdW50cnlcIiBzdHJpbmcuXHJcbiAgICB2YXIgdmFsRm4gPSBmdW5jdGlvbiAodikge1xyXG4gICAgICAgIGlmICh2ID09IG51bGwpIHJldHVybiB0cnVlO1xyXG4gICAgICAgIHJldHVybiAoY29yZS5zdHJpbmdTdGFydHNXaXRoKHYsIFwiVVNcIikpO1xyXG4gICAgfTtcclxuICAgIHZhciBjb3VudHJ5VmFsaWRhdG9yID0gbmV3IFZhbGlkYXRvcihcImNvdW50cnlJc1VTXCIsIHZhbEZuLCB7XHJcbiAgICAgICAgZGlzcGxheU5hbWU6IFwiQ291bnRyeVwiLCBcclxuICAgICAgICBtZXNzYWdlVGVtcGxhdGU6IFwiJyVkaXNwbGF5TmFtZSUnIG11c3Qgc3RhcnQgd2l0aCAnVVMnXCIgXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBOb3cgcGx1ZyBpdCBpbnRvIEJyZWV6ZS5cclxuICAgIC8vIEFzc3VtZSBlbTEgaXMgYSBwcmVleGlzdGluZyBFbnRpdHlNYW5hZ2VyLlxyXG4gICAgdmFyIGN1c3RUeXBlID0gbWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQ3VzdG9tZXJcIik7XHJcbiAgICB2YXIgY291bnRyeVByb3AgPSBjdXN0VHlwZS5nZXRQcm9wZXJ0eShcIkNvdW50cnlcIik7XHJcbiAgICAvLyBOb3RlIHRoYXQgdmFsaWRhdG9yIGlzIGFkZGVkIHRvIGEgJ0RhdGFQcm9wZXJ0eScgdmFsaWRhdG9ycyBjb2xsZWN0aW9uLlxyXG4gICAgcHJvcC52YWxpZGF0b3JzLnB1c2goY291bnRyeVZhbGlkYXRvcik7XHJcbkVudGl0eSBsZXZlbCB2YWxpZGF0b3JzIGFyZSBhbHNvIHBvc3NpYmxlXHJcbkBleGFtcGxlXHJcbiAgICBmdW5jdGlvbiBpc1ZhbGlkWmlwQ29kZSh2YWx1ZSkge1xyXG4gICAgICAgIHZhciByZSA9IC9eXFxkezV9KFtcXC1dXFxkezR9KT8kLztcclxuICAgICAgICByZXR1cm4gKHJlLnRlc3QodmFsdWUpKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyB2IGluIHRoaXMgY2FzZSB3aWxsIGJlIGEgQ3VzdG9tZXIgZW50aXR5XHJcbiAgICB2YXIgdmFsRm4gPSBmdW5jdGlvbiAodikge1xyXG4gICAgICAgIC8vIFRoaXMgdmFsaWRhdG9yIG9ubHkgdmFsaWRhdGVzIFVTIFppcCBDb2Rlcy5cclxuICAgICAgICBpZiAoIHYuZ2V0UHJvcGVydHkoXCJDb3VudHJ5XCIpID09PSBcIlVTQVwiKSB7XHJcbiAgICAgICAgICAgIHZhciBwb3N0YWxDb2RlID0gdi5nZXRQcm9wZXJ0eShcIlBvc3RhbENvZGVcIik7XHJcbiAgICAgICAgICAgIHJldHVybiBpc1ZhbGlkWmlwQ29kZShwb3N0YWxDb2RlKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9O1xyXG4gICAgdmFyIHppcENvZGVWYWxpZGF0b3IgPSBuZXcgVmFsaWRhdG9yKFwiemlwQ29kZVZhbGlkYXRvclwiLCB2YWxGbixcclxuICAgICAgICB7IG1lc3NhZ2VUZW1wbGF0ZTogXCJGb3IgdGhlIFVTLCB0aGlzIGlzIG5vdCBhIHZhbGlkIFBvc3RhbENvZGVcIiB9KTtcclxuXHJcbiAgICAvLyBOb3cgcGx1ZyBpdCBpbnRvIEJyZWV6ZS5cclxuICAgIC8vIEFzc3VtZSBlbTEgaXMgYSBwcmVleGlzdGluZyBFbnRpdHlNYW5hZ2VyLlxyXG4gICAgdmFyIGN1c3RUeXBlID0gZW0xLm1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZShcIkN1c3RvbWVyXCIpO1xyXG4gICAgLy8gTm90ZSB0aGF0IHZhbGlkYXRvciBpcyBhZGRlZCB0byBhbiAnRW50aXR5VHlwZScgdmFsaWRhdG9ycyBjb2xsZWN0aW9uLlxyXG4gICAgY3VzdFR5cGUudmFsaWRhdG9ycy5wdXNoKHppcENvZGVWYWxpZGF0b3IpO1xyXG5XaGF0IGlzIGNvbW1vbmx5IG5lZWRlZCBpcyBhIHdheSBvZiBjcmVhdGluZyBhIHBhcmFtZXRlcml6ZWQgZnVuY3Rpb24gdGhhdCB3aWxsIGl0c2VsZlxyXG5yZXR1cm4gYSBuZXcgVmFsaWRhdG9yLiAgVGhpcyByZXF1aXJlcyB0aGUgdXNlIG9mIGEgJ2NvbnRleHQnIG9iamVjdC5cclxuQGV4YW1wbGVcclxuICAgIC8vIGNyZWF0ZSBhIGZ1bmN0aW9uIHRoYXQgd2lsbCB0YWtlIGluIGEgY29uZmlnIG9iamVjdFxyXG4gICAgLy8gYW5kIHdpbGwgcmV0dXJuIGEgdmFsaWRhdG9yXHJcbiAgICB2YXIgbnVtZXJpY1JhbmdlVmFsaWRhdG9yID0gZnVuY3Rpb24oY29udGV4dCkge1xyXG4gICAgICAgIHZhciB2YWxGbiA9IGZ1bmN0aW9uKHYsIGN0eCkge1xyXG4gICAgICAgICAgICBpZiAodiA9PSBudWxsKSByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgICAgaWYgKHR5cGVvZih2KSAhPT0gXCJudW1iZXJcIikgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgICBpZiAoY3R4Lm1pbiAhPSBudWxsICYmIHYgPCBjdHgubWluKSByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIGlmIChjdHgubWF4ICE9IG51bGwgJiYgdiA+IGN0eC5tYXgpIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfTtcclxuICAgICAgICAvLyBUaGUgbGFzdCBwYXJhbWV0ZXIgYmVsb3cgaXMgdGhlICdjb250ZXh0JyBvYmplY3QgdGhhdCB3aWxsIGJlIHBhc3NlZCBpbnRvIHRoZSAnY3R4JyBwYXJhbWV0ZXIgYWJvdmVcclxuICAgICAgICAvLyB3aGVuIHRoaXMgdmFsaWRhdG9yIGV4ZWN1dGVzLiBTZXZlcmFsIG90aGVyIHByb3BlcnRpZXMsIHN1Y2ggYXMgZGlzcGxheU5hbWUgd2lsbCBnZXQgYWRkZWQgdG8gdGhpcyBvYmplY3QgYXMgd2VsbC5cclxuICAgICAgICByZXR1cm4gbmV3IFZhbGlkYXRvcihcIm51bWVyaWNSYW5nZVwiLCB2YWxGbiwge1xyXG4gICAgICAgICAgICBtZXNzYWdlVGVtcGxhdGU6IFwiJyVkaXNwbGF5TmFtZSUnIG11c3QgYmUgYSBudW1iZXIgYmV0d2VlbiB0aGUgdmFsdWVzIG9mICVtaW4lIGFuZCAlbWF4JVwiLFxyXG4gICAgICAgICAgICBtaW46IGNvbnRleHQubWluLFxyXG4gICAgICAgICAgICBtYXg6IGNvbnRleHQubWF4XHJcbiAgICAgICAgfSk7XHJcbiAgICB9O1xyXG4gICAgLy8gQXNzdW1lIHRoYXQgZnJlaWdodFByb3BlcnR5IGlzIGEgRGF0YUVudGl0eVByb3BlcnR5IHRoYXQgZGVzY3JpYmVzIG51bWVyaWMgdmFsdWVzLlxyXG4gICAgLy8gcmVnaXN0ZXIgdGhlIHZhbGlkYXRvclxyXG4gICAgZnJlaWdodFByb3BlcnR5LnZhbGlkYXRvcnMucHVzaChudW1lcmljUmFuZ2VWYWxpZGF0b3IoeyBtaW46IDEwMCwgbWF4OiA1MDAgfSkpO1xyXG5cclxuQnJlZXplIHN1YnN0aXR1dGVzIGNvbnRleHQgdmFsdWVzIGFuZCBmdW5jdGlvbnMgZm9yIHRoZSB0b2tlbnMgaW4gdGhlIG1lc3NhZ2VUZW1wbGF0ZSB3aGVuIHByZXBhcmluZyB0aGUgcnVudGltZSBlcnJvciBtZXNzYWdlO1xyXG4nZGlzcGxheU5hbWUnIGlzIGEgcHJlLWRlZmluZWQgY29udGV4dCBmdW5jdGlvbiB0aGF0IGlzIGFsd2F5cyBhdmFpbGFibGUuXHJcblxyXG5QbGVhc2Ugbm90ZSB0aGF0IEJyZWV6ZSBzdWJzdGl0dXRlcyB0aGUgZW1wdHkgc3RyaW5nIGZvciBmYWxzZXkgcGFyYW1ldGVycy4gVGhhdCB1c3VhbGx5IHdvcmtzIGluIHlvdXIgZmF2b3IuXHJcblNvbWV0aW1lcyBpdCBkb2Vzbid0IGFzIHdoZW4gdGhlICdtaW4nIHZhbHVlIGlzIHplcm8gaW4gd2hpY2ggY2FzZSB0aGUgbWVzc2FnZSB0ZXh0IHdvdWxkIGhhdmUgYSBob2xlXHJcbndoZXJlIHRoZSAnbWluJyB2YWx1ZSBnb2VzLCBzYXlpbmc6IFwiLi4uIGFuIGludGVnZXIgYmV0d2VlbiB0aGUgdmFsdWVzIG9mIGFuZCAuLi5cIi4gVGhhdCBpcyBub3Qgd2hhdCB5b3Ugd2FudC5cclxuXHJcblRvIGF2b2lkIHRoaXMgZWZmZWN0LCB5b3UgbWF5IGNhbiBiYWtlIGNlcnRhaW4gb2YgdGhlIGNvbnRleHQgdmFsdWVzIGludG8gdGhlICdtZXNzYWdlVGVtcGxhdGUnIGl0c2VsZlxyXG5hcyBzaG93biBpbiB0aGlzIHJldmlzaW9uIHRvIHRoZSBwZXJ0aW5lbnQgcGFydCBvZiB0aGUgcHJldmlvdXMgZXhhbXBsZTpcclxuQGV4YW1wbGVcclxuICAgIC8vIC4uLiBhcyBiZWZvcmVcclxuICAgIC8vIC4uLiBidXQgYmFrZSB0aGUgbWluL21heCB2YWx1ZXMgaW50byB0aGUgbWVzc2FnZSB0ZW1wbGF0ZS5cclxuICAgIHZhciB0ZW1wbGF0ZSA9IGJyZWV6ZS5jb3JlLmZvcm1hdFN0cmluZyhcclxuICAgICAgICBcIiclZGlzcGxheU5hbWUlJyBtdXN0IGJlIGEgbnVtYmVyIGJldHdlZW4gdGhlIHZhbHVlcyBvZiAlMSBhbmQgJTJcIixcclxuICAgICAgICBjb250ZXh0Lm1pbiwgY29udGV4dC5tYXgpO1xyXG4gICAgcmV0dXJuIG5ldyBWYWxpZGF0b3IoXCJudW1lcmljUmFuZ2VcIiwgdmFsRm4sIHtcclxuICAgICAgICBtZXNzYWdlVGVtcGxhdGU6IHRlbXBsYXRlLFxyXG4gICAgICAgIG1pbjogY29udGV4dC5taW4sXHJcbiAgICAgICAgbWF4OiBjb250ZXh0Lm1heFxyXG4gICAgfSk7XHJcblxyXG5AbWV0aG9kIDxjdG9yPiBWYWxpZGF0b3JcclxuQHBhcmFtIG5hbWUge1N0cmluZ30gVGhlIG5hbWUgb2YgdGhpcyB2YWxpZGF0b3IuXHJcbkBwYXJhbSB2YWxpZGF0b3JGbiB7RnVuY3Rpb259IEEgZnVuY3Rpb24gdG8gcGVyZm9ybSB2YWxpZGF0aW9uLlxyXG5cclxudmFsaWRhdG9yRm4odmFsdWUsIGNvbnRleHQpXHJcbkBwYXJhbSB2YWxpZGF0b3JGbi52YWx1ZSB7T2JqZWN0fSBWYWx1ZSB0byBiZSB2YWxpZGF0ZWRcclxuQHBhcmFtIHZhbGlkYXRvckZuLmNvbnRleHQge09iamVjdH0gVGhlIHNhbWUgY29udGV4dCBvYmplY3QgcGFzc2VkIGludG8gdGhlIGNvbnN0cnVjdG9yIHdpdGggdGhlIGZvbGxvd2luZyBhZGRpdGlvbmFsIHByb3BlcnRpZXMgaWYgbm90XHJcbm90aGVyd2lzZSBzcGVjaWZpZWQuXHJcbkBwYXJhbSB2YWxpZGF0b3JGbi5jb250ZXh0LnZhbHVlIHtPYmplY3R9IFRoZSB2YWx1ZSBiZWluZyB2YWxpZGF0ZWQuXHJcbkBwYXJhbSB2YWxpZGF0b3JGbi5jb250ZXh0Lm5hbWUge1N0cmluZ30gVGhlIG5hbWUgb2YgdGhlIHZhbGlkYXRvciBiZWluZyBleGVjdXRlZC5cclxuQHBhcmFtIHZhbGlkYXRvckZuLmNvbnRleHQuZGlzcGxheU5hbWUge1N0cmluZ30gVGhpcyB3aWxsIGJlIGVpdGhlciB0aGUgdmFsdWUgb2YgdGhlIHByb3BlcnR5J3MgJ2Rpc3BsYXlOYW1lJyBwcm9wZXJ0eSBvclxyXG50aGUgdmFsdWUgb2YgaXRzICduYW1lJyBwcm9wZXJ0eSBvciB0aGUgc3RyaW5nICdWYWx1ZSdcclxuQHBhcmFtIHZhbGlkYXRvckZuLmNvbnRleHQubWVzc2FnZVRlbXBsYXRlIHtTdHJpbmd9IFRoaXMgd2lsbCBlaXRoZXIgYmUgdGhlIHZhbHVlIG9mIFZhbGlkYXRvci5tZXNzYWdlVGVtcGxhdGVzWyB7dGhpcyB2YWxpZGF0b3JzIG5hbWV9XSBvciBudWxsLiBWYWxpZGF0b3IubWVzc2FnZVRlbXBsYXRlc1xyXG5pcyBhbiBvYmplY3QgdGhhdCBpcyBrZXllZCBieSB2YWxpZGF0b3IgbmFtZSBhbmQgdGhhdCBjYW4gYmUgYWRkZWQgdG8gaW4gb3JkZXIgdG8gJ3JlZ2lzdGVyJyB5b3VyIG93biBtZXNzYWdlIGZvciBhIGdpdmVuIHZhbGlkYXRvci5cclxuVGhlIGZvbGxvd2luZyBwcm9wZXJ0eSBjYW4gYWxzbyBiZSBzcGVjaWZpZWQgZm9yIGFueSB2YWxpZGF0b3IgdG8gZm9yY2UgYSBzcGVjaWZpYyBlcnJvck1lc3NhZ2Ugc3RyaW5nXHJcbkBwYXJhbSBbdmFsaWRhdG9yRm4uY29udGV4dC5tZXNzYWdlXSB7U3RyaW5nfSBJZiB0aGlzIHByb3BlcnR5IGlzIHNldCBpdCB3aWxsIGJlIHVzZWQgaW5zdGVhZCBvZiB0aGUgJ21lc3NhZ2VUZW1wbGF0ZScgcHJvcGVydHkgd2hlbiBhblxyXG5lcnJvciBtZXNzYWdlIGlzIGdlbmVyYXRlZC5cclxuXHJcbkBwYXJhbSBbY29udGV4dF0ge09iamVjdH0gQSBmcmVlIGZvcm0gb2JqZWN0IHdob3NlIHByb3BlcnRpZXMgd2lsbCBtYWRlIGF2YWlsYWJsZSBkdXJpbmcgdGhlIHZhbGlkYXRpb24gYW5kIGVycm9yIG1lc3NhZ2UgY3JlYXRpb24gcHJvY2Vzcy5cclxuVGhpcyBvYmplY3Qgd2lsbCBiZSBwYXNzZWQgaW50byB0aGUgVmFsaWRhdG9yJ3MgdmFsaWRhdGlvbiBmdW5jdGlvbiB3aGVuZXZlciAndmFsaWRhdGUnIGlzIGNhbGxlZC4gU2VlIGFib3ZlIGZvciBhIGRlc2NyaXB0aW9uXHJcbm9mIGFkZGl0aW9uYWwgcHJvcGVydGllcyB0aGF0IHdpbGwgYmUgYXV0b21hdGljYWxseSBhZGRlZCB0byB0aGlzIG9iamVjdCBpZiBub3Qgb3RoZXJ3aXNlIHNwZWNpZmllZC5cclxuQGR5bmFtaWNcclxuKiovXHJcbmV4cG9ydCBjbGFzcyBWYWxpZGF0b3Ige1xyXG4gIC8qKiBAaGlkZGVuIEBpbnRlcm5hbCAqL1xyXG4gIGRlY2xhcmUgXyR0eXBlTmFtZTogc3RyaW5nOyAvLyBvbiBwcm90b1xyXG5cclxuICBkZWNsYXJlIG5hbWU6IHN0cmluZztcclxuICBkZWNsYXJlIHZhbEZuOiBWYWxpZGF0aW9uRm47XHJcbiAgZGVjbGFyZSBjb250ZXh0OiBWYWxpZGF0aW9uTWVzc2FnZUNvbnRleHQ7XHJcbiAgZGVjbGFyZSBjdXJyZW50Q29udGV4dDogVmFsaWRhdGlvbk1lc3NhZ2VDb250ZXh0O1xyXG4gIGRlY2xhcmUgcHJpdmF0ZSBfYmFzZUNvbnRleHQ6IFZhbGlkYXRpb25NZXNzYWdlQ29udGV4dDtcclxuXHJcbiAgY29uc3RydWN0b3IobmFtZTogc3RyaW5nLCB2YWxGbjogVmFsaWRhdGlvbkZuLCBjb250ZXh0PzogVmFsaWRhdGlvbk1lc3NhZ2VDb250ZXh0KSB7XHJcbiAgICAvLyBfYmFzZUNvbnRleHQgaXMgd2hhdCB3aWxsIGdldCBzZXJpYWxpemVkXHJcbiAgICB0aGlzLl9iYXNlQ29udGV4dCA9IGNvbnRleHQgfHwge30gYXMgVmFsaWRhdGlvbk1lc3NhZ2VDb250ZXh0O1xyXG4gICAgdGhpcy5fYmFzZUNvbnRleHQubmFtZSA9IG5hbWU7XHJcbiAgICBjb250ZXh0ID0gY29yZS5leHRlbmQoT2JqZWN0LmNyZWF0ZShyb290Q29udGV4dCksIHRoaXMuX2Jhc2VDb250ZXh0KSBhcyBWYWxpZGF0aW9uTWVzc2FnZUNvbnRleHQ7XHJcbiAgICBjb250ZXh0Lm1lc3NhZ2VUZW1wbGF0ZSA9IGNvbnRleHQubWVzc2FnZVRlbXBsYXRlIHx8IFZhbGlkYXRvci5tZXNzYWdlVGVtcGxhdGVzW25hbWVdO1xyXG4gICAgdGhpcy5uYW1lID0gbmFtZTtcclxuICAgIHRoaXMudmFsRm4gPSB2YWxGbjtcclxuICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBUaGUgbmFtZSBvZiB0aGlzIHZhbGlkYXRvci5cclxuXHJcbiAgX19yZWFkT25seV9fXHJcbiAgQHByb3BlcnR5IG5hbWUge1N0cmluZ31cclxuICAqKi9cclxuXHJcbiAgLyoqXHJcbiAgVGhlIGNvbnRleHQgZm9yIHRoaXMgdmFsaWRhdG9yLlxyXG5cclxuICBUaGlzIG9iamVjdCB3aWxsIHR5cGljYWxseSBjb250YWluIGF0IGEgbWluaW11bSB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXMuIFwibmFtZVwiLCBcImRpc3BsYXlOYW1lXCIsIGFuZCBcIm1lc3NhZ2VcIiBvciBcIm1lc3NhZ2VUZW1wbGF0ZVwiLlxyXG4gIF9fcmVhZE9ubHlfX1xyXG4gIEBwcm9wZXJ0eSBjb250ZXh0IHtPYmplY3R9XHJcbiAgKiovXHJcblxyXG5cclxuICAvKipcclxuICBSdW4gdGhpcyB2YWxpZGF0b3IgYWdhaW5zdCB0aGUgc3BlY2lmaWVkIHZhbHVlLiAgVGhpcyBtZXRob2Qgd2lsbCB1c3VhbGx5IGJlIGNhbGxlZCBpbnRlcm5hbGx5IGVpdGhlclxyXG4gIGF1dG9tYXRpY2FsbHkgYnkgYW4gcHJvcGVydHkgY2hhbmdlLCBlbnRpdHkgYXR0YWNoLCBxdWVyeSBvciBzYXZlIG9wZXJhdGlvbiwgb3IgbWFudWFsbHkgYXMgYSByZXN1bHQgb2ZcclxuICBhIHZhbGlkYXRlRW50aXR5IGNhbGwgb24gdGhlIEVudGl0eUFzcGVjdC4gVGhlIHJlc3VsdGluZyBWYWxpZGF0aW9uUmVzdWx0cyBhcmUgYXZhaWxhYmxlIHZpYSB0aGVcclxuICBFbnRpdHlBc3BlY3QuZ2V0VmFsaWRhdGlvbkVycm9ycyBtZXRob2QuXHJcblxyXG4gIEhvd2V2ZXIsIHlvdSBjYW4gYWxzbyBjYWxsIGEgdmFsaWRhdG9yIGRpcmVjdGx5IGVpdGhlciBmb3IgdGVzdGluZyBwdXJwb3NlcyBvciBzb21lIG90aGVyIHJlYXNvbiBpZiBuZWVkZWQuXHJcbiAgQGV4YW1wbGVcclxuICAgICAgLy8gdXNpbmcgb25lIG9mIHRoZSBwcmVkZWZpbmVkIHZhbGlkYXRvcnNcclxuICAgICAgdmFyIHZhbGlkYXRvciA9IFZhbGlkYXRvci5tYXhMZW5ndGgoeyBtYXhMZW5ndGg6IDUsIGRpc3BsYXlOYW1lOiBcIkNpdHlcIiB9KTtcclxuICAgICAgLy8gc2hvdWxkIGJlIG9rIGJlY2F1c2UgXCJhc2RmXCIubGVuZ3RoIDwgNVxyXG4gICAgICB2YXIgcmVzdWx0ID0gdmFsaWRhdG9yLnZhbGlkYXRlKFwiYXNkZlwiKTtcclxuICAgICAgb2socmVzdWx0ID09PSBudWxsKTtcclxuICAgICAgcmVzdWx0ID0gdmFsaWRhdG9yLnZhbGlkYXRlKFwiYWRhc2RmYXNkZlwiKTtcclxuICAgICAgLy8gZXh0cmFjdCBhbGwgb2YgdGhlIHByb3BlcnRpZXMgb2YgdGhlICdyZXN1bHQnXHJcbiAgICAgIHZhciBlcnJNc2cgPSByZXN1bHQuZXJyb3JNZXNzYWdlO1xyXG4gICAgICB2YXIgY29udGV4dCA9IHJlc3VsdC5jb250ZXh0O1xyXG4gICAgICB2YXIgc2FtZVZhbGlkYXRvciA9IHJlc3VsdC52YWxpZGF0b3I7XHJcbiAgQG1ldGhvZCB2YWxpZGF0ZVxyXG4gIEBwYXJhbSB2YWx1ZSB7T2JqZWN0fSBWYWx1ZSB0byB2YWxpZGF0ZVxyXG4gIEBwYXJhbSBhZGRpdGlvbmFsQ29udGV4dCB7T2JqZWN0fSBBbnkgYWRkaXRpb25hbCBjb250ZXh0dWFsIGluZm9ybWF0aW9uIHRoYXQgdGhlIFZhbGlkYXRvclxyXG4gIGNhbiBtYWtlIHVzZSBvZi5cclxuICBAcmV0dXJuIHtWYWxpZGF0aW9uRXJyb3J8bnVsbH0gQSBWYWxpZGF0aW9uRXJyb3IgaWYgdmFsaWRhdGlvbiBmYWlscywgbnVsbCBvdGhlcndpc2VcclxuICAqKi9cclxuICB2YWxpZGF0ZSh2YWx1ZTogYW55LCBhZGRpdGlvbmFsQ29udGV4dD86IFZhbGlkYXRpb25NZXNzYWdlQ29udGV4dCkge1xyXG4gICAgbGV0IGN1cnJlbnRDb250ZXh0OiBWYWxpZGF0aW9uTWVzc2FnZUNvbnRleHQ7IC8vIHsgdmFsdWU/OiBPYmplY3QgfTtcclxuICAgIGlmIChhZGRpdGlvbmFsQ29udGV4dCkge1xyXG4gICAgICBjdXJyZW50Q29udGV4dCA9IGNvcmUuZXh0ZW5kKE9iamVjdC5jcmVhdGUodGhpcy5jb250ZXh0KSwgYWRkaXRpb25hbENvbnRleHQpIGFzIFZhbGlkYXRpb25NZXNzYWdlQ29udGV4dDtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGN1cnJlbnRDb250ZXh0ID0gdGhpcy5jb250ZXh0O1xyXG4gICAgfVxyXG4gICAgdGhpcy5jdXJyZW50Q29udGV4dCA9IGN1cnJlbnRDb250ZXh0O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGlmICh0aGlzLnZhbEZuKHZhbHVlLCBjdXJyZW50Q29udGV4dCkpIHtcclxuICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBjdXJyZW50Q29udGV4dC52YWx1ZSA9IHZhbHVlO1xyXG4gICAgICAgIHJldHVybiBuZXcgVmFsaWRhdGlvbkVycm9yKHRoaXMsIGN1cnJlbnRDb250ZXh0LCB0aGlzLmdldE1lc3NhZ2UoKSk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgcmV0dXJuIG5ldyBWYWxpZGF0aW9uRXJyb3IodGhpcywgY3VycmVudENvbnRleHQsIFwiRXhjZXB0aW9uIG9jY3VyZWQgd2hpbGUgZXhlY3V0aW5nIHRoaXMgdmFsaWRhdG9yOiBcIiArIHRoaXMubmFtZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuXHJcbiAgLy8gY29udGV4dC52YWx1ZSBpcyBub3QgYXZhaWwgdW5sZXNzIHZhbGlkYXRlIHdhcyBjYWxsZWQgZmlyc3QuXHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgdGhlIG1lc3NhZ2UgZ2VuZXJhdGVkIGJ5IHRoZSBtb3N0IHJlY2VudCBleGVjdXRpb24gb2YgdGhpcyBWYWxpZGF0b3IuXHJcbiAgQGV4YW1wbGVcclxuICAgICAgdmFyIHYwID0gVmFsaWRhdG9yLm1heExlbmd0aCh7IG1heExlbmd0aDogNSwgZGlzcGxheU5hbWU6IFwiQ2l0eVwiIH0pO1xyXG4gICAgICB2MC52YWxpZGF0ZShcImFkYXNkZmFzZGZcIik7XHJcbiAgICAgIHZhciBlcnJNZXNzYWdlID0gdjAuZ2V0TWVzc2FnZSgpKTtcclxuICBAbWV0aG9kIGdldE1lc3NhZ2VcclxuICBAcmV0dXJuIHtTdHJpbmd9XHJcbiAgKiovXHJcbiAgZ2V0TWVzc2FnZSgpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxldCBjb250ZXh0ID0gdGhpcy5jdXJyZW50Q29udGV4dDtcclxuICAgICAgbGV0IG1lc3NhZ2UgPSBjb250ZXh0Lm1lc3NhZ2U7XHJcbiAgICAgIGlmIChtZXNzYWdlKSB7XHJcbiAgICAgICAgaWYgKHR5cGVvZiAobWVzc2FnZSkgPT09IFwiZnVuY3Rpb25cIikge1xyXG4gICAgICAgICAgcmV0dXJuIG1lc3NhZ2UoY29udGV4dCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHJldHVybiBtZXNzYWdlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIGlmIChjb250ZXh0Lm1lc3NhZ2VUZW1wbGF0ZSkge1xyXG4gICAgICAgIHJldHVybiBmb3JtYXRUZW1wbGF0ZShjb250ZXh0Lm1lc3NhZ2VUZW1wbGF0ZSwgY29udGV4dCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgcmV0dXJuIFwiaW52YWxpZCB2YWx1ZTogXCIgKyAodGhpcy5uYW1lIHx8IFwie3VubmFtZWQgdmFsaWRhdG9yfVwiKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICByZXR1cm4gXCJVbmFibGUgdG8gZm9ybWF0IGVycm9yIG1lc3NhZ2VcIiArIGUudG9TdHJpbmcoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRvSlNPTigpIHtcclxuICAgIHJldHVybiB0aGlzLl9iYXNlQ29udGV4dDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIENyZWF0ZXMgYSB2YWxpZGF0b3IgaW5zdGFuY2UgZnJvbSBhIEpTT04gb2JqZWN0IG9yIGFuIGFycmF5IG9mIGluc3RhbmNlcyBmcm9tIGFuIGFycmF5IG9mIEpTT04gb2JqZWN0cy5cclxuICBAbWV0aG9kIGZyb21KU09OXHJcbiAgQHN0YXRpY1xyXG4gIEBwYXJhbSBqc29uIHtPYmplY3R9IEpTT04gb2JqZWN0IHRoYXQgcmVwcmVzZW50cyB0aGUgc2VyaWFsaXplZCB2ZXJzaW9uIG9mIGEgdmFsaWRhdG9yLlxyXG4gICoqL1xyXG4gIHB1YmxpYyBzdGF0aWMgZnJvbUpTT04oanNvbjogYW55KTogYW55IHtcclxuICAgIGlmIChBcnJheS5pc0FycmF5KGpzb24pKSB7XHJcbiAgICAgIHJldHVybiBqc29uLm1hcChmdW5jdGlvbiAoanMpIHtcclxuICAgICAgICByZXR1cm4gVmFsaWRhdG9yLmZyb21KU09OKGpzKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBpZiAoanNvbiBpbnN0YW5jZW9mIFZhbGlkYXRvcikge1xyXG4gICAgICByZXR1cm4ganNvbjtcclxuICAgIH1cclxuICAgIGxldCB2YWxpZGF0b3JOYW1lID0gXCJWYWxpZGF0b3IuXCIgKyBqc29uLm5hbWU7XHJcbiAgICBsZXQgZm4gPSBjb25maWcuZ2V0UmVnaXN0ZXJlZEZ1bmN0aW9uKHZhbGlkYXRvck5hbWUpO1xyXG4gICAgaWYgKCFmbikge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJVbmFibGUgdG8gbG9jYXRlIGEgdmFsaWRhdG9yIG5hbWVkOlwiICsganNvbi5uYW1lKTtcclxuICAgIH1cclxuICAgIHJldHVybiBmbihqc29uKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gIFJlZ2lzdGVyIGEgdmFsaWRhdG9yIGluc3RhbmNlIHNvIHRoYXQgYW55IGRlc2VyaWFsaXplZCBtZXRhZGF0YSBjYW4gcmVmZXJlbmNlIGl0LlxyXG4gIEBtZXRob2QgcmVnaXN0ZXJcclxuICBAc3RhdGljXHJcbiAgQHBhcmFtIHZhbGlkYXRvciB7VmFsaWRhdG9yfSBWYWxpZGF0b3IgdG8gcmVnaXN0ZXIuXHJcbiAgKiovXHJcbiAgcHVibGljIHN0YXRpYyByZWdpc3Rlcih2YWxpZGF0b3I6IFZhbGlkYXRvcikge1xyXG4gICAgY29uZmlnLnJlZ2lzdGVyRnVuY3Rpb24oZnVuY3Rpb24gKCkge1xyXG4gICAgICByZXR1cm4gdmFsaWRhdG9yO1xyXG4gICAgfSwgXCJWYWxpZGF0b3IuXCIgKyB2YWxpZGF0b3IubmFtZSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICBSZWdpc3RlciBhIHZhbGlkYXRvciBmYWN0b3J5IHNvIHRoYXQgYW55IGRlc2VyaWFsaXplZCBtZXRhZGF0YSBjYW4gcmVmZXJlbmNlIGl0LlxyXG4gIEBtZXRob2QgcmVnaXN0ZXJGYWN0b3J5XHJcbiAgQHN0YXRpY1xyXG4gIEBwYXJhbSB2YWxpZGF0b3JGYWN0b3J5IHtGdW5jdGlvbn0gQSBmdW5jdGlvbiB0aGF0IG9wdGlvbmFsbHkgdGFrZXMgYSBjb250ZXh0IHByb3BlcnR5IGFuZCByZXR1cm5zIGEgVmFsaWRhdG9yIGluc3RhbmNlLlxyXG4gIEBwYXJhbSBuYW1lIHtTdHJpbmd9IFRoZSBuYW1lIG9mIHRoZSB2YWxpZGF0b3IuXHJcbiAgKiovXHJcbiAgcHVibGljIHN0YXRpYyByZWdpc3RlckZhY3RvcnkodmFsaWRhdG9yRmFjdG9yeTogKG9wdGlvbnM/OiBhbnkpID0+IFZhbGlkYXRvciwgbmFtZTogc3RyaW5nKSB7XHJcbiAgICBjb25maWcucmVnaXN0ZXJGdW5jdGlvbih2YWxpZGF0b3JGYWN0b3J5LCBcIlZhbGlkYXRvci5cIiArIG5hbWUpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgTWFwIG9mIHN0YW5kYXJkIGVycm9yIG1lc3NhZ2UgdGVtcGxhdGVzIGtleWVkIGJ5IHZhbGlkYXRvciBuYW1lLlxyXG4gIFlvdSBjYW4gYWRkIHRvIG9yIG1vZGlmeSB0aGlzIG9iamVjdCB0byBjdXN0b21pemUgdGhlIHRlbXBsYXRlIHVzZWQgZm9yIGFueSB2YWxpZGF0aW9uIGVycm9yIG1lc3NhZ2UuXHJcbiAgQGV4YW1wbGVcclxuICAgICAgLy8gdiBpcyB0aGlzIGZ1bmN0aW9uIGlzIHRoZSB2YWx1ZSB0byBiZSB2YWxpZGF0ZWQsIGluIHRoaXMgY2FzZSBhIFwiY291bnRyeVwiIHN0cmluZy5cclxuICAgICAgdmFyIHZhbEZuID0gZnVuY3Rpb24gKHYpIHtcclxuICAgICAgICAgIGlmICh2ID09IG51bGwpIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgcmV0dXJuIChjb3JlLnN0cmluZ1N0YXJ0c1dpdGgodiwgXCJVU1wiKSk7XHJcbiAgICAgIH07XHJcbiAgICAgIHZhciBjb3VudHJ5VmFsaWRhdG9yID0gbmV3IFZhbGlkYXRvcihcImNvdW50cnlJc1VTXCIsIHZhbEZuLCB7IGRpc3BsYXlOYW1lOiBcIkNvdW50cnlcIiB9KTtcclxuICAgICAgVmFsaWRhdG9yLm1lc3NhZ2VUZW1wbGF0ZXMuY291bnRyeUlzVVMgPSBcIiclZGlzcGxheU5hbWUlJyBtdXN0IHN0YXJ0IHdpdGggJ1VTJ1wiO1xyXG4gICAgICAvLyBUaGlzIHdpbGwgaGF2ZSBhIHNpbWlsYXIgZWZmZWN0IHRvIHRoaXNcclxuICAgICAgdmFyIGNvdW50cnlWYWxpZGF0b3IgPSBuZXcgVmFsaWRhdG9yKFwiY291bnRyeUlzVVNcIiwgdmFsRm4sIHtcclxuICAgICAgICAgIGRpc3BsYXlOYW1lOiBcIkNvdW50cnlcIiwgXHJcbiAgICAgICAgICBtZXNzYWdlVGVtcGxhdGU6IFwiJyVkaXNwbGF5TmFtZSUnIG11c3Qgc3RhcnQgd2l0aCAnVVMnXCIgXHJcbiAgICAgIH0pO1xyXG4gIEBwcm9wZXJ0eSBtZXNzYWdlVGVtcGxhdGVzIHtPYmplY3R9XHJcbiAgQHN0YXRpY1xyXG4gICoqL1xyXG4gIHB1YmxpYyBzdGF0aWMgbWVzc2FnZVRlbXBsYXRlcyA9IHtcclxuICAgIGJvb2w6IFwiJyVkaXNwbGF5TmFtZSUnIG11c3QgYmUgYSAndHJ1ZScgb3IgJ2ZhbHNlJyB2YWx1ZVwiLFxyXG4gICAgY3JlZGl0Q2FyZDogXCJUaGUgJWRpc3BsYXlOYW1lJSBpcyBub3QgYSB2YWxpZCBjcmVkaXQgY2FyZCBudW1iZXJcIixcclxuICAgIGRhdGU6IFwiJyVkaXNwbGF5TmFtZSUnIG11c3QgYmUgYSBkYXRlXCIsXHJcbiAgICBkdXJhdGlvbjogXCInJWRpc3BsYXlOYW1lJScgbXVzdCBiZSBhIElTTzg2MDEgZHVyYXRpb24gc3RyaW5nLCBzdWNoIGFzICdQM0gyNE02MFMnXCIsXHJcbiAgICBlbWFpbEFkZHJlc3M6IFwiVGhlICVkaXNwbGF5TmFtZSUgJyV2YWx1ZSUnIGlzIG5vdCBhIHZhbGlkIGVtYWlsIGFkZHJlc3NcIixcclxuICAgIGd1aWQ6IFwiJyVkaXNwbGF5TmFtZSUnIG11c3QgYmUgYSBHVUlEXCIsXHJcbiAgICBpbnRlZ2VyOiBcIiclZGlzcGxheU5hbWUlJyBtdXN0IGJlIGFuIGludGVnZXJcIixcclxuICAgIGludGVnZXJSYW5nZTogXCInJWRpc3BsYXlOYW1lJScgbXVzdCBiZSBhbiBpbnRlZ2VyIGJldHdlZW4gdGhlIHZhbHVlcyBvZiAlbWluVmFsdWUlIGFuZCAlbWF4VmFsdWUlXCIsXHJcbiAgICBtYXhMZW5ndGg6IFwiJyVkaXNwbGF5TmFtZSUnIG11c3QgYmUgYSBzdHJpbmcgd2l0aCAlbWF4TGVuZ3RoJSBjaGFyYWN0ZXJzIG9yIGxlc3NcIixcclxuICAgIG51bWJlcjogXCInJWRpc3BsYXlOYW1lJScgbXVzdCBiZSBhIG51bWJlclwiLFxyXG4gICAgcGhvbmU6IFwiVGhlICVkaXNwbGF5TmFtZSUgJyV2YWx1ZSUnIGlzIG5vdCBhIHZhbGlkIHBob25lIG51bWJlclwiLFxyXG4gICAgcmVndWxhckV4cHJlc3Npb246IFwiVGhlICVkaXNwbGF5TmFtZSUgJyV2YWx1ZSUnIGRvZXMgbm90IG1hdGNoICclZXhwcmVzc2lvbiUnXCIsXHJcbiAgICByZXF1aXJlZDogXCInJWRpc3BsYXlOYW1lJScgaXMgcmVxdWlyZWRcIixcclxuICAgIHN0cmluZzogXCInJWRpc3BsYXlOYW1lJScgbXVzdCBiZSBhIHN0cmluZ1wiLFxyXG4gICAgc3RyaW5nTGVuZ3RoOiBcIiclZGlzcGxheU5hbWUlJyBtdXN0IGJlIGEgc3RyaW5nIHdpdGggYmV0d2VlbiAlbWluTGVuZ3RoJSBhbmQgJW1heExlbmd0aCUgY2hhcmFjdGVyc1wiLFxyXG4gICAgdXJsOiBcIlRoZSAlZGlzcGxheU5hbWUlICcldmFsdWUlJyBpcyBub3QgYSB2YWxpZCB1cmxcIlxyXG4gIH07XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBzdGFuZGFyZCAncmVxdWlyZWQgdmFsdWUnIFZhbGlkYXRvclxyXG4gIEBleGFtcGxlXHJcbiAgICAgIC8vIEFzc3VtZSBlbTEgaXMgYSBwcmVleGlzdGluZyBFbnRpdHlNYW5hZ2VyLlxyXG4gICAgICB2YXIgY3VzdFR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQ3VzdG9tZXJcIik7XHJcbiAgICAgIHZhciByZWdpb25Qcm9wZXJ0eSAtIGN1c3RUeXBlLmdldFByb3BlcnR5KFwiUmVnaW9uXCIpO1xyXG4gICAgICAvLyBNYWtlcyBcIlJlZ2lvblwiIG9uIEN1c3RvbWVyIGEgcmVxdWlyZWQgcHJvcGVydHkuXHJcbiAgICAgIHJlZ2lvblByb3BlcnR5LnZhbGlkYXRvcnMucHVzaChWYWxpZGF0b3IucmVxdWlyZWQoKSk7XHJcbiAgICAgIC8vIG9yIHRvIGFsbG93IGVtcHR5IHN0cmluZ3NcclxuICAgICAgcmVnaW9uUHJvcGVydHkudmFsaWRhdG9ycy5wdXNoKFZhbGlkYXRvci5yZXF1aXJlZCh7IGFsbG93RW1wdHlTdHJpbmdzOiB0cnVlIH0pOyk7XHJcbiAgQG1ldGhvZCByZXF1aXJlZFxyXG4gIEBzdGF0aWNcclxuICBAcGFyYW0gY29udGV4dCB7T2JqZWN0fVxyXG4gIEBwYXJhbSBbY29udGV4dC5hbGxvd0VtcHR5U3RyaW5nc10ge0Jvb2xlYW59IElmIHRoaXMgcGFyYW1ldGVyIGlzIG9taXR0ZWQgb3IgZmFsc2UgdGhlbiBlbXB0eSBzdHJpbmdzIGRvIE5PVCBwYXNzIHZhbGlkYXRpb24uXHJcbiAgQHJldHVybiB7VmFsaWRhdG9yfSBBIG5ldyBWYWxpZGF0b3JcclxuICAqKi9cclxuICBwdWJsaWMgc3RhdGljIHJlcXVpcmVkID0gZnVuY3Rpb24oY29udGV4dD86IGFueSkge1xyXG4gICAgbGV0IHZhbEZuID0gZnVuY3Rpb24gKHY6IGFueSwgY3R4OiBhbnkpIHtcclxuICAgICAgaWYgKHR5cGVvZiB2ID09PSBcInN0cmluZ1wiKSB7XHJcbiAgICAgICAgaWYgKGN0eCAmJiBjdHguYWxsb3dFbXB0eVN0cmluZ3MpIHJldHVybiB0cnVlO1xyXG4gICAgICAgIHJldHVybiB2Lmxlbmd0aCA+IDA7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgcmV0dXJuIHYgIT0gbnVsbDtcclxuICAgICAgfVxyXG4gICAgfTtcclxuICAgIHJldHVybiBuZXcgVmFsaWRhdG9yKFwicmVxdWlyZWRcIiwgdmFsRm4sIGNvbnRleHQpO1xyXG4gIH07XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBzdGFuZGFyZCBtYXhpbXVtIHN0cmluZyBsZW5ndGggVmFsaWRhdG9yOyB0aGUgbWF4aW11bSBsZW5ndGggbXVzdCBiZSBzcGVjaWZpZWRcclxuICBAZXhhbXBsZVxyXG4gICAgICAvLyBBc3N1bWUgZW0xIGlzIGEgcHJlZXhpc3RpbmcgRW50aXR5TWFuYWdlci5cclxuICAgICAgdmFyIGN1c3RUeXBlID0gZW0xLm1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZShcIkN1c3RvbWVyXCIpO1xyXG4gICAgICB2YXIgcmVnaW9uUHJvcGVydHkgLSBjdXN0VHlwZS5nZXRQcm9wZXJ0eShcIlJlZ2lvblwiKTtcclxuICAgICAgLy8gVmFsaWRhdGVzIHRoYXQgdGhlIHZhbHVlIG9mIHRoZSBSZWdpb24gcHJvcGVydHkgb24gQ3VzdG9tZXIgd2lsbCBiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gNSBjaGFyYWN0ZXJzLlxyXG4gICAgICByZWdpb25Qcm9wZXJ0eS52YWxpZGF0b3JzLnB1c2goVmFsaWRhdG9yLm1heExlbmd0aCgge21heExlbmd0aDogNX0pKTtcclxuICBAbWV0aG9kIG1heExlbmd0aFxyXG4gIEBzdGF0aWNcclxuICBAcGFyYW0gY29udGV4dCB7T2JqZWN0fVxyXG4gIEBwYXJhbSBjb250ZXh0Lm1heExlbmd0aCB7SW50ZWdlcn1cclxuICBAcmV0dXJuIHtWYWxpZGF0b3J9IEEgbmV3IFZhbGlkYXRvclxyXG4gICoqL1xyXG4gIHB1YmxpYyBzdGF0aWMgbWF4TGVuZ3RoID0gZnVuY3Rpb24oY29udGV4dDogYW55KSB7XHJcbiAgICBsZXQgdmFsRm4gPSBmdW5jdGlvbiAodjogYW55LCBjdHg6IGFueSkge1xyXG4gICAgICBpZiAodiA9PSBudWxsKSByZXR1cm4gdHJ1ZTtcclxuICAgICAgaWYgKHR5cGVvZiAodikgIT09IFwic3RyaW5nXCIpIHJldHVybiBmYWxzZTtcclxuICAgICAgcmV0dXJuIHYubGVuZ3RoIDw9IGN0eC5tYXhMZW5ndGg7XHJcbiAgICB9O1xyXG4gICAgcmV0dXJuIG5ldyBWYWxpZGF0b3IoXCJtYXhMZW5ndGhcIiwgdmFsRm4sIGNvbnRleHQpO1xyXG4gIH07XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBzdGFuZGFyZCBzdHJpbmcgbGVuZ3RoIFZhbGlkYXRvcjsgYm90aCBtaW5pbXVtIGFuZCBtYXhpbXVtIGxlbmd0aHMgbXVzdCBiZSBzcGVjaWZpZWQuXHJcbiAgQGV4YW1wbGVcclxuICAgICAgLy8gQXNzdW1lIGVtMSBpcyBhIHByZWV4aXN0aW5nIEVudGl0eU1hbmFnZXIuXHJcbiAgICAgIHZhciBjdXN0VHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJDdXN0b21lclwiKTtcclxuICAgICAgdmFyIHJlZ2lvblByb3BlcnR5IC0gY3VzdFR5cGUuZ2V0UHJvcGVydHkoXCJSZWdpb25cIik7XHJcbiAgICAgIC8vIFZhbGlkYXRlcyB0aGF0IHRoZSB2YWx1ZSBvZiB0aGUgUmVnaW9uIHByb3BlcnR5IG9uIEN1c3RvbWVyIHdpbGwgYmVcclxuICAgICAgLy8gYmV0d2VlbiAyIGFuZCA1IGNoYXJhY3RlcnNcclxuICAgICAgcmVnaW9uUHJvcGVydHkudmFsaWRhdG9ycy5wdXNoKFZhbGlkYXRvci5zdHJpbmdMZW5ndGgoIHttaW5MZW5ndGg6IDIsIG1heExlbmd0aDogNX0pO1xyXG4gIEBtZXRob2Qgc3RyaW5nTGVuZ3RoXHJcbiAgQHN0YXRpY1xyXG4gIEBwYXJhbSBjb250ZXh0IHtPYmplY3R9XHJcbiAgQHBhcmFtIGNvbnRleHQubWF4TGVuZ3RoIHtJbnRlZ2VyfVxyXG4gIEBwYXJhbSBjb250ZXh0Lm1pbkxlbmd0aCB7SW50ZWdlcn1cclxuICBAcmV0dXJuIHtWYWxpZGF0b3J9IEEgbmV3IFZhbGlkYXRvclxyXG4gICoqL1xyXG4gIHB1YmxpYyBzdGF0aWMgc3RyaW5nTGVuZ3RoID0gZnVuY3Rpb24gKGNvbnRleHQ6IGFueSkge1xyXG4gICAgbGV0IHZhbEZuID0gZnVuY3Rpb24gKHY6IGFueSwgY3R4OiBhbnkpIHtcclxuICAgICAgaWYgKHYgPT0gbnVsbCkgcmV0dXJuIHRydWU7XHJcbiAgICAgIGlmICh0eXBlb2YgKHYpICE9PSBcInN0cmluZ1wiKSByZXR1cm4gZmFsc2U7XHJcbiAgICAgIGlmIChjdHgubWluTGVuZ3RoICE9IG51bGwgJiYgdi5sZW5ndGggPCBjdHgubWluTGVuZ3RoKSByZXR1cm4gZmFsc2U7XHJcbiAgICAgIGlmIChjdHgubWF4TGVuZ3RoICE9IG51bGwgJiYgdi5sZW5ndGggPiBjdHgubWF4TGVuZ3RoKSByZXR1cm4gZmFsc2U7XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfTtcclxuICAgIHJldHVybiBuZXcgVmFsaWRhdG9yKFwic3RyaW5nTGVuZ3RoXCIsIHZhbEZuLCBjb250ZXh0KTtcclxuICB9O1xyXG5cclxuICAvKipcclxuICBSZXR1cm5zIGEgc3RhbmRhcmQgc3RyaW5nIGRhdGFUeXBlIFZhbGlkYXRvci5cclxuICBAZXhhbXBsZVxyXG4gICAgICAvLyBBc3N1bWUgZW0xIGlzIGEgcHJlZXhpc3RpbmcgRW50aXR5TWFuYWdlci5cclxuICAgICAgdmFyIGN1c3RUeXBlID0gZW0xLm1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZShcIkN1c3RvbWVyXCIpO1xyXG4gICAgICB2YXIgcmVnaW9uUHJvcGVydHkgLSBjdXN0VHlwZS5nZXRQcm9wZXJ0eShcIlJlZ2lvblwiKTtcclxuICAgICAgLy8gVmFsaWRhdGVzIHRoYXQgdGhlIHZhbHVlIG9mIHRoZSBSZWdpb24gcHJvcGVydHkgb24gQ3VzdG9tZXIgaXMgYSBzdHJpbmcuXHJcbiAgICAgIHJlZ2lvblByb3BlcnR5LnZhbGlkYXRvcnMucHVzaChWYWxpZGF0b3Iuc3RyaW5nKCkpO1xyXG4gIEBtZXRob2Qgc3RyaW5nXHJcbiAgQHN0YXRpY1xyXG4gIEByZXR1cm4ge1ZhbGlkYXRvcn0gQSBuZXcgVmFsaWRhdG9yXHJcbiAgKiovXHJcbiAgcHVibGljIHN0YXRpYyBzdHJpbmcgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICBsZXQgdmFsRm4gPSBmdW5jdGlvbiAodjogYW55KSB7XHJcbiAgICAgIGlmICh2ID09IG51bGwpIHJldHVybiB0cnVlO1xyXG4gICAgICByZXR1cm4gKHR5cGVvZiB2ID09PSBcInN0cmluZ1wiKTtcclxuICAgIH07XHJcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRvcihcInN0cmluZ1wiLCB2YWxGbik7XHJcbiAgfTtcclxuXHJcbiAgLyoqXHJcbiAgUmV0dXJucyBhIEd1aWQgZGF0YSB0eXBlIFZhbGlkYXRvci5cclxuICBAZXhhbXBsZVxyXG4gICAgICAvLyBBc3N1bWUgZW0xIGlzIGEgcHJlZXhpc3RpbmcgRW50aXR5TWFuYWdlci5cclxuICAgICAgdmFyIGN1c3RUeXBlID0gZW0xLm1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZShcIkN1c3RvbWVyXCIpO1xyXG4gICAgICB2YXIgY3VzdG9tZXJJZFByb3BlcnR5IC0gY3VzdFR5cGUuZ2V0UHJvcGVydHkoXCJDdXN0b21lcklEXCIpO1xyXG4gICAgICAvLyBWYWxpZGF0ZXMgdGhhdCB0aGUgdmFsdWUgb2YgdGhlIEN1c3RvbWVySUQgcHJvcGVydHkgb24gQ3VzdG9tZXIgaXMgYSBHdWlkLlxyXG4gICAgICBjdXN0b21lcklkUHJvcGVydHkudmFsaWRhdG9ycy5wdXNoKFZhbGlkYXRvci5ndWlkKCkpO1xyXG4gIEBtZXRob2QgZ3VpZFxyXG4gIEBzdGF0aWNcclxuICBAcmV0dXJuIHtWYWxpZGF0b3J9IEEgbmV3IFZhbGlkYXRvclxyXG4gICoqL1xyXG4gIHB1YmxpYyBzdGF0aWMgZ3VpZCA9IGZ1bmN0aW9uICgpIHtcclxuICAgIGxldCB2YWxGbiA9IGZ1bmN0aW9uICh2OiBhbnkpIHtcclxuICAgICAgaWYgKHYgPT0gbnVsbCkgcmV0dXJuIHRydWU7XHJcbiAgICAgIHJldHVybiBjb3JlLmlzR3VpZCh2KTtcclxuICAgIH07XHJcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRvcihcImd1aWRcIiwgdmFsRm4pO1xyXG4gIH07XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBJU08gODYwMSBkdXJhdGlvbiBzdHJpbmcgIFZhbGlkYXRvci5cclxuICBAZXhhbXBsZVxyXG4gICAgICAvLyBBc3N1bWUgZW0xIGlzIGEgcHJlZXhpc3RpbmcgRW50aXR5TWFuYWdlci5cclxuICAgICAgdmFyIGV2ZW50VHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJFdmVudFwiKTtcclxuICAgICAgdmFyIGVsYXBzZWRUaW1lUHJvcGVydHkgLSBldmVudFR5cGUuZ2V0UHJvcGVydHkoXCJFbGFwc2VkVGltZVwiKTtcclxuICAgICAgLy8gVmFsaWRhdGVzIHRoYXQgdGhlIHZhbHVlIG9mIHRoZSBFbGFwc2VkVGltZSBwcm9wZXJ0eSBvbiBDdXN0b21lciBpcyBhIGR1cmF0aW9uLlxyXG4gICAgICBlbGFwc2VkVGltZVByb3BlcnR5LnZhbGlkYXRvcnMucHVzaChWYWxpZGF0b3IuZHVyYXRpb24oKSk7XHJcbiAgQG1ldGhvZCBkdXJhdGlvblxyXG4gIEBzdGF0aWNcclxuICBAcmV0dXJuIHtWYWxpZGF0b3J9IEEgbmV3IFZhbGlkYXRvclxyXG4gICoqL1xyXG4gIHB1YmxpYyBzdGF0aWMgZHVyYXRpb24gPSBmdW5jdGlvbiAoKSB7XHJcbiAgICBsZXQgdmFsRm4gPSBmdW5jdGlvbiAodjogYW55KSB7XHJcbiAgICAgIGlmICh2ID09IG51bGwpIHJldHVybiB0cnVlO1xyXG4gICAgICByZXR1cm4gY29yZS5pc0R1cmF0aW9uKHYpO1xyXG4gICAgfTtcclxuICAgIHJldHVybiBuZXcgVmFsaWRhdG9yKFwiZHVyYXRpb25cIiwgdmFsRm4pO1xyXG4gIH07XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBzdGFuZGFyZCBudW1lcmljIGRhdGEgdHlwZSBWYWxpZGF0b3IuXHJcbiAgQGV4YW1wbGVcclxuICAgICAgLy8gQXNzdW1lIGVtMSBpcyBhIHByZWV4aXN0aW5nIEVudGl0eU1hbmFnZXIuXHJcbiAgICAgIHZhciBvcmRlclR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiT3JkZXJcIik7XHJcbiAgICAgIHZhciBmcmVpZ2h0UHJvcGVydHkgLSBvcmRlclR5cGUuZ2V0UHJvcGVydHkoXCJGcmVpZ2h0XCIpO1xyXG4gICAgICAvLyBWYWxpZGF0ZXMgdGhhdCB0aGUgdmFsdWUgb2YgdGhlIEZyZWlnaHQgcHJvcGVydHkgb24gT3JkZXIgaXMgYSBudW1iZXIuXHJcbiAgICAgIGZyZWlnaHRQcm9wZXJ0eS52YWxpZGF0b3JzLnB1c2goVmFsaWRhdG9yLm51bWJlcigpKTtcclxuICBAbWV0aG9kIG51bWJlclxyXG4gIEBzdGF0aWNcclxuICBAcmV0dXJuIHtWYWxpZGF0b3J9IEEgbmV3IFZhbGlkYXRvclxyXG4gICoqL1xyXG5cclxuICAgIC8vIFRPRE86IG1heSBuZWVkIHRvIGhhdmUgc2VwZXJhdGUgbG9naWMgZm9yIHNpbmdsZS5cclxuICBwdWJsaWMgc3RhdGljIG51bWJlciA9IGZ1bmN0aW9uKGNvbnRleHQ/OiBhbnkpIHtcclxuICAgIGxldCB2YWxGbiA9IGZ1bmN0aW9uICh2OiBhbnksIGN0eDogYW55KSB7XHJcbiAgICAgIGlmICh2ID09IG51bGwpIHJldHVybiB0cnVlO1xyXG4gICAgICBpZiAodHlwZW9mIHYgPT09IFwic3RyaW5nXCIgJiYgY3R4ICYmIGN0eC5hbGxvd1N0cmluZykge1xyXG4gICAgICAgIHYgPSBwYXJzZUZsb2F0KHYpO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiAodHlwZW9mIHYgPT09IFwibnVtYmVyXCIgJiYgIWlzTmFOKHYpKTtcclxuICAgIH07XHJcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRvcihcIm51bWJlclwiLCB2YWxGbiwgY29udGV4dCk7XHJcbiAgfTtcclxuICBwdWJsaWMgc3RhdGljIGRvdWJsZSA9IFZhbGlkYXRvci5udW1iZXI7XHJcbiAgcHVibGljIHN0YXRpYyBzaW5nbGUgPSBWYWxpZGF0b3IubnVtYmVyO1xyXG5cclxuICAvKipcclxuICBSZXR1cm5zIGEgc3RhbmRhcmQgbGFyZ2UgaW50ZWdlciBkYXRhIHR5cGUgLSA2NCBiaXQgLSBWYWxpZGF0b3IuXHJcbiAgQGV4YW1wbGVcclxuICAgICAgLy8gQXNzdW1lIGVtMSBpcyBhIHByZWV4aXN0aW5nIEVudGl0eU1hbmFnZXIuXHJcbiAgICAgIHZhciBvcmRlclR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiT3JkZXJcIik7XHJcbiAgICAgIHZhciBmcmVpZ2h0UHJvcGVydHkgLSBvcmRlclR5cGUuZ2V0UHJvcGVydHkoXCJGcmVpZ2h0XCIpO1xyXG4gICAgICAvLyBWYWxpZGF0ZXMgdGhhdCB0aGUgdmFsdWUgb2YgdGhlIEZyZWlnaHQgcHJvcGVydHkgb24gT3JkZXIgaXMgd2l0aGluIHRoZSByYW5nZSBvZiBhIDY0IGJpdCBpbnRlZ2VyLlxyXG4gICAgICBmcmVpZ2h0UHJvcGVydHkudmFsaWRhdG9ycy5wdXNoKFZhbGlkYXRvci5pbnQ2NCgpKTtcclxuICBAbWV0aG9kIGludDY0XHJcbiAgQHN0YXRpY1xyXG4gIEByZXR1cm4ge1ZhbGlkYXRvcn0gQSBuZXcgVmFsaWRhdG9yXHJcbiAgKiovXHJcbiAgcHVibGljIHN0YXRpYyBpbnRlZ2VyID0gZnVuY3Rpb24oY29udGV4dDogYW55KSB7XHJcbiAgICBsZXQgdmFsRm4gPSBmdW5jdGlvbiAodjogYW55LCBjdHg6IGFueSkge1xyXG4gICAgICBpZiAodiA9PSBudWxsKSByZXR1cm4gdHJ1ZTtcclxuICAgICAgaWYgKHR5cGVvZiB2ID09PSBcInN0cmluZ1wiICYmIGN0eCAmJiBjdHguYWxsb3dTdHJpbmcpIHtcclxuICAgICAgICB2ID0gcGFyc2VJbnQodiwgMTApO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiAodHlwZW9mIHYgPT09IFwibnVtYmVyXCIpICYmICghaXNOYU4odikpICYmIE1hdGguZmxvb3IodikgPT09IHY7XHJcbiAgICB9O1xyXG4gICAgcmV0dXJuIG5ldyBWYWxpZGF0b3IoXCJpbnRlZ2VyXCIsIHZhbEZuLCBjb250ZXh0KTtcclxuICB9O1xyXG4gIHB1YmxpYyBzdGF0aWMgaW50NjQgPSBWYWxpZGF0b3IuaW50ZWdlcjtcclxuXHJcbiAgLyoqXHJcbiAgUmV0dXJucyBhIHN0YW5kYXJkIDMyIGJpdCBpbnRlZ2VyIGRhdGEgdHlwZSBWYWxpZGF0b3IuXHJcbiAgQGV4YW1wbGVcclxuICAgICAgLy8gQXNzdW1lIGVtMSBpcyBhIHByZWV4aXN0aW5nIEVudGl0eU1hbmFnZXIuXHJcbiAgICAgIHZhciBvcmRlclR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiT3JkZXJcIik7XHJcbiAgICAgIHZhciBmcmVpZ2h0UHJvcGVydHkgLSBvcmRlclR5cGUuZ2V0UHJvcGVydHkoXCJGcmVpZ2h0XCIpO1xyXG4gICAgICBmcmVpZ2h0UHJvcGVydHkudmFsaWRhdG9ycy5wdXNoKFZhbGlkYXRvci5pbnQzMigpKTtcclxuICBAbWV0aG9kIGludDMyXHJcbiAgQHN0YXRpY1xyXG4gIEByZXR1cm4ge1ZhbGlkYXRvcn0gQSBuZXcgVmFsaWRhdG9yXHJcbiAgKiovXHJcbiAgcHVibGljIHN0YXRpYyBpbnQzMiA9IGZ1bmN0aW9uKGNvbnRleHQ6IGFueSkge1xyXG4gICAgcmV0dXJuIGludFJhbmdlVmFsaWRhdG9yQ3RvcihcImludDMyXCIsIElOVDMyX01JTiwgSU5UMzJfTUFYLCBjb250ZXh0KSgpO1xyXG4gIH07XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBzdGFuZGFyZCAxNiBiaXQgaW50ZWdlciBkYXRhIHR5cGUgVmFsaWRhdG9yLlxyXG4gIEBleGFtcGxlXHJcbiAgICAgIC8vIEFzc3VtZSBlbTEgaXMgYSBwcmVleGlzdGluZyBFbnRpdHlNYW5hZ2VyLlxyXG4gICAgICB2YXIgb3JkZXJUeXBlID0gZW0xLm1ldGFkYXRhU3RvcmUuZ2V0RW50aXR5VHlwZShcIk9yZGVyXCIpO1xyXG4gICAgICB2YXIgZnJlaWdodFByb3BlcnR5IC0gb3JkZXJUeXBlLmdldFByb3BlcnR5KFwiRnJlaWdodFwiKTtcclxuICAgICAgLy8gVmFsaWRhdGVzIHRoYXQgdGhlIHZhbHVlIG9mIHRoZSBGcmVpZ2h0IHByb3BlcnR5IG9uIE9yZGVyIGlzIHdpdGhpbiB0aGUgcmFuZ2Ugb2YgYSAxNiBiaXQgaW50ZWdlci5cclxuICAgICAgZnJlaWdodFByb3BlcnR5LnZhbGlkYXRvcnMucHVzaChWYWxpZGF0b3IuaW50MTYoKSk7XHJcbiAgQG1ldGhvZCBpbnQxNlxyXG4gIEBzdGF0aWNcclxuICBAcmV0dXJuIHtWYWxpZGF0b3J9IEEgbmV3IFZhbGlkYXRvclxyXG4gICoqL1xyXG4gIHB1YmxpYyBzdGF0aWMgaW50MTYgPSBmdW5jdGlvbihjb250ZXh0OiBhbnkpIHtcclxuICAgIHJldHVybiBpbnRSYW5nZVZhbGlkYXRvckN0b3IoXCJpbnQxNlwiLCBJTlQxNl9NSU4sIElOVDE2X01BWCwgY29udGV4dCkoKTtcclxuICB9O1xyXG5cclxuICAvKipcclxuICBSZXR1cm5zIGEgc3RhbmRhcmQgYnl0ZSBkYXRhIHR5cGUgVmFsaWRhdG9yLiAoVGhpcyBpcyBhIGludGVnZXIgYmV0d2VlbiAwIGFuZCAyNTUgaW5jbHVzaXZlIGZvciBqcyBwdXJwb3NlcykuXHJcbiAgQGV4YW1wbGVcclxuICAgICAgLy8gQXNzdW1lIGVtMSBpcyBhIHByZWV4aXN0aW5nIEVudGl0eU1hbmFnZXIuXHJcbiAgICAgIHZhciBvcmRlclR5cGUgPSBlbTEubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiT3JkZXJcIik7XHJcbiAgICAgIHZhciBmcmVpZ2h0UHJvcGVydHkgLSBvcmRlclR5cGUuZ2V0UHJvcGVydHkoXCJGcmVpZ2h0XCIpO1xyXG4gICAgICAvLyBWYWxpZGF0ZXMgdGhhdCB0aGUgdmFsdWUgb2YgdGhlIEZyZWlnaHQgcHJvcGVydHkgb24gT3JkZXIgaXMgd2l0aGluIHRoZSByYW5nZSBvZiBhIDE2IGJpdCBpbnRlZ2VyLlxyXG4gICAgICAvLyBQcm9iYWJseSBub3QgYSB2ZXJ5IGdvb2QgdmFsaWRhdGlvbiB0byBwbGFjZSBvbiB0aGUgRnJlaWdodCBwcm9wZXJ0eS5cclxuICAgICAgcmVnaW9uUHJvcGVydHkudmFsaWRhdG9ycy5wdXNoKFZhbGlkYXRvci5ieXRlKCkpO1xyXG4gIEBtZXRob2QgYnl0ZVxyXG4gIEBzdGF0aWNcclxuICBAcmV0dXJuIHtWYWxpZGF0b3J9IEEgbmV3IFZhbGlkYXRvclxyXG4gICoqL1xyXG4gIHB1YmxpYyBzdGF0aWMgYnl0ZSA9IGZ1bmN0aW9uKGNvbnRleHQ6IGFueSkge1xyXG4gICAgcmV0dXJuIGludFJhbmdlVmFsaWRhdG9yQ3RvcihcImJ5dGVcIiwgQllURV9NSU4sIEJZVEVfTUFYLCBjb250ZXh0KSgpO1xyXG4gIH07XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBzdGFuZGFyZCBib29sZWFuIGRhdGEgdHlwZSBWYWxpZGF0b3IuXHJcbiAgQGV4YW1wbGVcclxuICAgICAgLy8gQXNzdW1lIGVtMSBpcyBhIHByZWV4aXN0aW5nIEVudGl0eU1hbmFnZXIuXHJcbiAgICAgIHZhciBwcm9kdWN0VHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJQcm9kdWN0XCIpO1xyXG4gICAgICB2YXIgZGlzY29udGludWVkUHJvcGVydHkgLSBwcm9kdWN0VHlwZS5nZXRQcm9wZXJ0eShcIkRpc2NvbnRpbnVlZFwiKTtcclxuICAgICAgLy8gVmFsaWRhdGVzIHRoYXQgdGhlIHZhbHVlIG9mIHRoZSBEaXNjb250aW51ZWQgcHJvcGVydHkgb24gUHJvZHVjdCBpcyBhIGJvb2xlYW5cclxuICAgICAgZGlzY29udGludWVkUHJvcGVydHkudmFsaWRhdG9ycy5wdXNoKFZhbGlkYXRvci5ib29sKCkpO1xyXG4gIEBtZXRob2QgYm9vbFxyXG4gIEBzdGF0aWNcclxuICBAcmV0dXJuIHtWYWxpZGF0b3J9IEEgbmV3IFZhbGlkYXRvclxyXG4gICoqL1xyXG4gIHB1YmxpYyBzdGF0aWMgYm9vbCA9IGZ1bmN0aW9uKCkge1xyXG4gICAgbGV0IHZhbEZuID0gZnVuY3Rpb24gKHY6IGFueSkge1xyXG4gICAgICBpZiAodiA9PSBudWxsKSByZXR1cm4gdHJ1ZTtcclxuICAgICAgcmV0dXJuICh2ID09PSB0cnVlKSB8fCAodiA9PT0gZmFsc2UpO1xyXG4gICAgfTtcclxuICAgIHJldHVybiBuZXcgVmFsaWRhdG9yKFwiYm9vbFwiLCB2YWxGbik7XHJcbiAgfTtcclxuXHJcbiAgcHVibGljIHN0YXRpYyBub25lID0gZnVuY3Rpb24oKSB7XHJcbiAgICBsZXQgdmFsRm4gPSBmdW5jdGlvbiAodjogYW55KSB7XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfTtcclxuICAgIHJldHVybiBuZXcgVmFsaWRhdG9yKFwibm9uZVwiLCB2YWxGbik7XHJcbiAgfTtcclxuXHJcbiAgLyoqXHJcbiAgUmV0dXJucyBhIHN0YW5kYXJkIGRhdGUgZGF0YSB0eXBlIFZhbGlkYXRvci5cclxuICBAZXhhbXBsZVxyXG4gICAgICAvLyBBc3N1bWUgZW0xIGlzIGEgcHJlZXhpc3RpbmcgRW50aXR5TWFuYWdlci5cclxuICAgICAgdmFyIG9yZGVyVHlwZSA9IGVtMS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJPcmRlclwiKTtcclxuICAgICAgdmFyIG9yZGVyRGF0ZVByb3BlcnR5IC0gb3JkZXJUeXBlLmdldFByb3BlcnR5KFwiT3JkZXJEYXRlXCIpO1xyXG4gICAgICAvLyBWYWxpZGF0ZXMgdGhhdCB0aGUgdmFsdWUgb2YgdGhlIE9yZGVyRGF0ZSBwcm9wZXJ0eSBvbiBPcmRlciBpcyBhIGRhdGVcclxuICAgICAgLy8gUHJvYmFibHkgbm90IGEgdmVyeSBnb29kIHZhbGlkYXRpb24gdG8gcGxhY2Ugb24gdGhlIEZyZWlnaHQgcHJvcGVydHkuXHJcbiAgICAgIG9yZGVyRGF0ZVByb3BlcnR5LnZhbGlkYXRvcnMucHVzaChWYWxpZGF0b3IuZGF0ZSgpKTtcclxuICBAbWV0aG9kIGRhdGVcclxuICBAc3RhdGljXHJcbiAgQHJldHVybiB7VmFsaWRhdG9yfSBBIG5ldyBWYWxpZGF0b3JcclxuICAqKi9cclxuICBwdWJsaWMgc3RhdGljIGRhdGUgPSBmdW5jdGlvbigpIHtcclxuICAgIGxldCB2YWxGbiA9IGZ1bmN0aW9uICh2OiBhbnkpIHtcclxuICAgICAgaWYgKHYgPT0gbnVsbCkgcmV0dXJuIHRydWU7XHJcbiAgICAgIGlmICh0eXBlb2YgdiA9PT0gXCJzdHJpbmdcIikge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICByZXR1cm4gIWlzTmFOKERhdGUucGFyc2UodikpO1xyXG4gICAgICAgICAgLy8gb2xkIGNvZGVcclxuICAgICAgICAgIC8vIHJldHVybiBfX2lzRGF0ZShuZXcgRGF0ZSh2KSk7XHJcbiAgICAgICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICByZXR1cm4gY29yZS5pc0RhdGUodik7XHJcbiAgICAgIH1cclxuICAgIH07XHJcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRvcihcImRhdGVcIiwgdmFsRm4pO1xyXG4gIH07XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgYSBjcmVkaXQgY2FyZCBudW1iZXIgdmFsaWRhdG9yXHJcbiAgUGVyZm9ybXMgYSBsdWhuIGFsZ29yaXRobSBjaGVja3N1bSB0ZXN0IGZvciBwbGF1c2FiaWxpdHlcclxuICBjYXRjaGVzIHNpbXBsZSBtaXN0YWtlczsgb25seSBzZXJ2aWNlIGtub3dzIGZvciBzdXJlXHJcbiAgQGV4YW1wbGVcclxuICAgICAgLy8gQXNzdW1lIGVtIGlzIGEgcHJlZXhpc3RpbmcgRW50aXR5TWFuYWdlci5cclxuICAgICAgdmFyIHBlcnNvblR5cGUgPSBlbS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJQZXJzb25cIik7XHJcbiAgICAgIHZhciBjcmVkaXRDYXJkUHJvcGVydHkgPSBwZXJzb25UeXBlLmdldFByb3BlcnR5KFwiY3JlZGl0Q2FyZFwiKTtcclxuICAgICAgLy8gVmFsaWRhdGVzIHRoYXQgdGhlIHZhbHVlIG9mIHRoZSBQZXJzb24uY3JlZGl0Q2FyZCBwcm9wZXJ0eSBpcyBjcmVkaXQgY2FyZC5cclxuICAgICAgY3JlZGl0Q2FyZFByb3BlcnR5LnZhbGlkYXRvcnMucHVzaChWYWxpZGF0b3IuY3JlZGl0Q2FyZCgpKTtcclxuICBAbWV0aG9kIGNyZWRpdENhcmRcclxuICBAc3RhdGljXHJcbiAgQHBhcmFtIFtjb250ZXh0XSB7T2JqZWN0fSBvcHRpb25hbCBwYXJhbWV0ZXJzIHRvIHBhc3MgdGhyb3VnaCB0byB2YWxpZGF0aW9uIGNvbnN0cnVjdG9yXHJcbiAgQHJldHVybiB7VmFsaWRhdG9yfSBBIG5ldyBWYWxpZGF0b3JcclxuICAqKi9cclxuICBwdWJsaWMgc3RhdGljIGNyZWRpdENhcmQgPSBmdW5jdGlvbihjb250ZXh0PzogYW55KSB7XHJcbiAgICBmdW5jdGlvbiB2YWxGbih2OiBhbnkpIHtcclxuICAgICAgaWYgKHYgPT0gbnVsbCB8fCB2ID09PSAnJykgcmV0dXJuIHRydWU7XHJcbiAgICAgIGlmICh0eXBlb2YgKHYpICE9PSAnc3RyaW5nJykgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB2ID0gdi5yZXBsYWNlKC8oXFwtfFxccykvZywgXCJcIik7IC8vIHJlbW92ZSBkYXNoZXMgYW5kIHNwYWNlc1xyXG4gICAgICBpZiAoIXYgfHwgL1xcRC8udGVzdCh2KSkgcmV0dXJuIGZhbHNlOyAvLyBhbGwgZGlnaXRzLCBub3QgZW1wdHlcclxuICAgICAgcmV0dXJuIGx1aG4odik7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRvcignY3JlZGl0Q2FyZCcsIHZhbEZuLCBjb250ZXh0KTtcclxuICB9O1xyXG5cclxuXHJcbiAgLyoqXHJcbiAgUmV0dXJucyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB2YWxpZGF0b3I7IHRoZSBleHByZXNzaW9uIG11c3QgYmUgc3BlY2lmaWVkXHJcbiAgQGV4YW1wbGVcclxuICAgICAgLy8gQWRkIHZhbGlkYXRvciB0byBhIHByb3BlcnR5LiBBc3N1bWUgZW0gaXMgYSBwcmVleGlzdGluZyBFbnRpdHlNYW5hZ2VyLlxyXG4gICAgICB2YXIgY3VzdG9tZXJUeXBlID0gZW0ubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQ3VzdG9tZXJcIik7XHJcbiAgICAgIHZhciByZWdpb25Qcm9wZXJ0eSA9IGN1c3RvbWVyVHlwZS5nZXRQcm9wZXJ0eShcIlJlZ2lvblwiKTtcclxuICAgICAgLy8gVmFsaWRhdGVzIHRoYXQgdGhlIHZhbHVlIG9mIEN1c3RvbWVyLlJlZ2lvbiBpcyAyIGNoYXIgdXBwZXJjYXNlIGFscGhhLlxyXG4gICAgICByZWdpb25Qcm9wZXJ0eS52YWxpZGF0b3JzLnB1c2goVmFsaWRhdG9yLnJlZ3VsYXJFeHByZXNzaW9uKCB7ZXhwcmVzc2lvbjogJ15bQS1aXXsyfSQnfSApO1xyXG4gIEBtZXRob2QgcmVndWxhckV4cHJlc3Npb25cclxuICBAc3RhdGljXHJcbiAgQHBhcmFtIGNvbnRleHQge09iamVjdH1cclxuICBAcGFyYW0gY29udGV4dC5leHByZXNzaW9uIHtTdHJpbmd9IFN0cmluZyBmb3JtIG9mIHRoZSByZWd1bGFyIGV4cHJlc3Npb24gdG8gYXBwbHlcclxuICBAcmV0dXJuIHtWYWxpZGF0b3J9IEEgbmV3IFZhbGlkYXRvclxyXG4gICoqL1xyXG4gIHB1YmxpYyBzdGF0aWMgcmVndWxhckV4cHJlc3Npb24gPSBmdW5jdGlvbihjb250ZXh0PzogYW55KSB7XHJcbiAgICBmdW5jdGlvbiB2YWxGbih2OiBhbnksIGN0eDogYW55KSB7XHJcbiAgICAgIC8vIGRvIG5vdCBpbnZhbGlkYXRlIGlmIGVtcHR5OyB1c2UgYSBzZXBhcmF0ZSByZXF1aXJlZCB0ZXN0XHJcbiAgICAgIGlmICh2ID09IG51bGwgfHwgdiA9PT0gJycpIHJldHVybiB0cnVlO1xyXG4gICAgICBpZiAodHlwZW9mICh2KSAhPT0gJ3N0cmluZycpIHJldHVybiBmYWxzZTtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBsZXQgcmUgPSBuZXcgUmVnRXhwKGN0eC5leHByZXNzaW9uKTtcclxuICAgICAgICByZXR1cm4gcmUudGVzdCh2KTtcclxuICAgICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBvciBpbnZhbGlkIGV4cHJlc3Npb24gcGFyYW1ldGVyIHRvIHJlZ0V4cCB2YWxpZGF0b3InKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIG5ldyBWYWxpZGF0b3IoJ3JlZ3VsYXJFeHByZXNzaW9uJywgdmFsRm4sIGNvbnRleHQpO1xyXG4gIH07XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgdGhlIGVtYWlsIGFkZHJlc3MgdmFsaWRhdG9yXHJcbiAgQGV4YW1wbGVcclxuICAgICAgLy8gQXNzdW1lIGVtIGlzIGEgcHJlZXhpc3RpbmcgRW50aXR5TWFuYWdlci5cclxuICAgICAgdmFyIHBlcnNvblR5cGUgPSBlbS5tZXRhZGF0YVN0b3JlLmdldEVudGl0eVR5cGUoXCJQZXJzb25cIik7XHJcbiAgICAgIHZhciBlbWFpbFByb3BlcnR5ID0gcGVyc29uVHlwZS5nZXRQcm9wZXJ0eShcImVtYWlsXCIpO1xyXG4gICAgICAvLyBWYWxpZGF0ZXMgdGhhdCB0aGUgdmFsdWUgb2YgdGhlIFBlcnNvbi5lbWFpbCBwcm9wZXJ0eSBpcyBhbiBlbWFpbCBhZGRyZXNzLlxyXG4gICAgICBlbWFpbFByb3BlcnR5LnZhbGlkYXRvcnMucHVzaChWYWxpZGF0b3IuZW1haWxBZGRyZXNzKCkpO1xyXG4gIEBtZXRob2QgZW1haWxBZGRyZXNzXHJcbiAgQHN0YXRpY1xyXG4gIEBwYXJhbSBbY29udGV4dF0ge09iamVjdH0gb3B0aW9uYWwgcGFyYW1ldGVycyB0byBwYXNzIHRocm91Z2ggdG8gdmFsaWRhdGlvbiBjb25zdHJ1Y3RvclxyXG4gIEByZXR1cm4ge1ZhbGlkYXRvcn0gQSBuZXcgVmFsaWRhdG9yXHJcbiAgKiovXHJcbiAgcHVibGljIHN0YXRpYyBlbWFpbEFkZHJlc3MgPSBmdW5jdGlvbihjb250ZXh0PzogYW55KSB7XHJcbiAgICAvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL3Nya2lya2xhbmQvRGF0YUFubm90YXRpb25zRXh0ZW5zaW9ucy9ibG9iL21hc3Rlci9EYXRhQW5ub3RhdGlvbnNFeHRlbnNpb25zL0VtYWlsQXR0cmlidXRlLmNzXHJcbiAgICBsZXQgcmVFbWFpbEFkZHJlc3MgPSAvXigoKFthLXpdfFxcZHxbISNcXCQlJidcXCpcXCtcXC1cXC89XFw/XFxeX2B7XFx8fX5dfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSsoXFwuKFthLXpdfFxcZHxbISNcXCQlJidcXCpcXCtcXC1cXC89XFw/XFxeX2B7XFx8fX5dfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSspKil8KChcXHgyMikoKCgoXFx4MjB8XFx4MDkpKihcXHgwZFxceDBhKSk/KFxceDIwfFxceDA5KSspPygoW1xceDAxLVxceDA4XFx4MGJcXHgwY1xceDBlLVxceDFmXFx4N2ZdfFxceDIxfFtcXHgyMy1cXHg1Yl18W1xceDVkLVxceDdlXXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSl8KFxcXFwoW1xceDAxLVxceDA5XFx4MGJcXHgwY1xceDBkLVxceDdmXXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkpKSkqKCgoXFx4MjB8XFx4MDkpKihcXHgwZFxceDBhKSk/KFxceDIwfFxceDA5KSspPyhcXHgyMikpKUAoKChbYS16XXxcXGR8W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pfCgoW2Etel18XFxkfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKShbYS16XXxcXGR8LXxcXC58X3x+fFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSooW2Etel18XFxkfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSkpXFwuKSsoKFthLXpdfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKXwoKFthLXpdfFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKShbYS16XXxcXGR8LXxcXC58X3x+fFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKSooW2Etel18W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKSlcXC4/JC9pO1xyXG4gICAgcmV0dXJuIG1ha2VSZWdFeHBWYWxpZGF0b3IoJ2VtYWlsQWRkcmVzcycsIHJlRW1haWxBZGRyZXNzLCBudWxsLCBjb250ZXh0KTtcclxuICB9O1xyXG5cclxuICAvKipcclxuICBSZXR1cm5zIHRoZSBwaG9uZSB2YWxpZGF0b3JcclxuICBQcm92aWRlcyBiYXNpYyBhc3NlcnRpb25zIG9uIHRoZSBmb3JtYXQgYW5kIHdpbGwgaGVscCB0byBlbGltaW5hdGUgbW9zdCBub25zZW5zZSBpbnB1dFxyXG4gIE1hdGNoZXM6XHJcbiAgSW50ZXJuYXRpb25hbCBkaWFsaW5nIHByZWZpeDoge3t9LCArLCAwLCAwMDAwfSAod2l0aCBvciB3aXRob3V0IGEgdHJhaWxpbmcgYnJlYWsgY2hhcmFjdGVyLCBpZiBub3QgJysnOiBbLS8uIF0pXHJcbiAgPiAoKFxcKyl8KDAoXFxkKyk/Wy0vLlxcc10pKVxyXG4gIENvdW50cnkgY29kZToge3t9LCAxLCAuLi4sIDk5OX0gKHdpdGggb3Igd2l0aG91dCBhIHRyYWlsaW5nIGJyZWFrIGNoYXJhY3RlcjogWy0vLiBdKVxyXG4gID4gWzEtOV1cXGR7LDJ9Wy0vLlxcc10/XHJcbiAgQXJlYSBjb2RlOiB7KDApLCAuLi4sICgwMDAwMDApLCAwLCAuLi4sIDAwMDAwMH0gKHdpdGggb3Igd2l0aG91dCBhIHRyYWlsaW5nIGJyZWFrIGNoYXJhY3RlcjogWy0vLiBdKVxyXG4gID4gKChcXChcXGR7MSw2fVxcKXxcXGR7MSw2fSlbLS8uXFxzXT8pP1xyXG4gIExvY2FsOiB7MCwgLi4ufSsgKHdpdGggb3Igd2l0aG91dCBhIHRyYWlsaW5nIGJyZWFrIGNoYXJhY3RlcjogWy0vLiBdKVxyXG4gID4gKFxcZCtbLS8uXFxzXT8pK1xcZCtcclxuICBAZXhhbXBsZVxyXG4gICAgICAvLyBBc3N1bWUgZW0gaXMgYSBwcmVleGlzdGluZyBFbnRpdHlNYW5hZ2VyLlxyXG4gICAgICB2YXIgY3VzdG9tZXJUeXBlID0gZW0ubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQ3VzdG9tZXJcIik7XHJcbiAgICAgIHZhciBwaG9uZVByb3BlcnR5ID0gY3VzdG9tZXJUeXBlLmdldFByb3BlcnR5KFwicGhvbmVcIik7XHJcbiAgICAgIC8vIFZhbGlkYXRlcyB0aGF0IHRoZSB2YWx1ZSBvZiB0aGUgQ3VzdG9tZXIucGhvbmUgcHJvcGVydHkgaXMgcGhvbmUuXHJcbiAgICAgIHBob25lUHJvcGVydHkudmFsaWRhdG9ycy5wdXNoKFZhbGlkYXRvci5waG9uZSgpKTtcclxuICBAbWV0aG9kIHBob25lXHJcbiAgQHN0YXRpY1xyXG4gIEBwYXJhbSBbY29udGV4dF0ge09iamVjdH0gb3B0aW9uYWwgcGFyYW1ldGVycyB0byBwYXNzIHRocm91Z2ggdG8gdmFsaWRhdGlvbiBjb25zdHJ1Y3RvclxyXG4gIEByZXR1cm4ge1ZhbGlkYXRvcn0gQSBuZXcgVmFsaWRhdG9yXHJcbiAgKiovXHJcbiAgcHVibGljIHN0YXRpYyBwaG9uZSA9IGZ1bmN0aW9uIChjb250ZXh0PzogYW55KSB7XHJcbiAgICAvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL3Nya2lya2xhbmQvRGF0YUFubm90YXRpb25zRXh0ZW5zaW9ucy9ibG9iL21hc3Rlci9EYXRhQW5ub3RhdGlvbnNFeHRlbnNpb25zL0V4cHJlc3Npb25zLmNzXHJcbiAgICBsZXQgcmVQaG9uZSA9IC9eKChcXCt8KDAoXFxkKyk/Wy0vLlxcc10/KSlbMS05XVxcZHswLDJ9Wy0vLlxcc10/KT8oKFxcKFxcZHsxLDZ9XFwpfFxcZHsxLDZ9KVstLy5cXHNdPyk/KFxcZCtbLS8uXFxzXT8pK1xcZCskLztcclxuICAgIHJldHVybiBtYWtlUmVnRXhwVmFsaWRhdG9yKCdwaG9uZScsIHJlUGhvbmUsIG51bGwsIGNvbnRleHQpO1xyXG4gIH07XHJcblxyXG4gIC8qKlxyXG4gIFJldHVybnMgdGhlIFVSTCAocHJvdG9jb2wgcmVxdWlyZWQpIHZhbGlkYXRvclxyXG4gIEBleGFtcGxlXHJcbiAgICAgIC8vIEFzc3VtZSBlbSBpcyBhIHByZWV4aXN0aW5nIEVudGl0eU1hbmFnZXIuXHJcbiAgICAgIHZhciBwZXJzb25UeXBlID0gZW0ubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiUGVyc29uXCIpO1xyXG4gICAgICB2YXIgd2Vic2l0ZVByb3BlcnR5ID0gcGVyc29uVHlwZS5nZXRQcm9wZXJ0eShcIndlYnNpdGVcIik7XHJcbiAgICAgIC8vIFZhbGlkYXRlcyB0aGF0IHRoZSB2YWx1ZSBvZiB0aGUgUGVyc29uLndlYnNpdGUgcHJvcGVydHkgaXMgYSBVUkwuXHJcbiAgICAgIHdlYnNpdGVQcm9wZXJ0eS52YWxpZGF0b3JzLnB1c2goVmFsaWRhdG9yLnVybCgpKTtcclxuICBAbWV0aG9kIHVybFxyXG4gIEBzdGF0aWNcclxuICBAcGFyYW0gW2NvbnRleHRdIHtPYmplY3R9IG9wdGlvbmFsIHBhcmFtZXRlcnMgdG8gcGFzcyB0aHJvdWdoIHRvIHZhbGlkYXRpb24gY29uc3RydWN0b3JcclxuICBAcmV0dXJuIHtWYWxpZGF0b3J9IEEgbmV3IFZhbGlkYXRvclxyXG4gICoqL1xyXG4gIHB1YmxpYyBzdGF0aWMgdXJsID0gZnVuY3Rpb24gKGNvbnRleHQ/OiBhbnkpIHtcclxuICAgIC8vU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9zcmtpcmtsYW5kL0RhdGFBbm5vdGF0aW9uc0V4dGVuc2lvbnMvYmxvYi9tYXN0ZXIvRGF0YUFubm90YXRpb25zRXh0ZW5zaW9ucy9VcmxBdHRyaWJ1dGUuY3NcclxuICAgIGxldCByZVVybFByb3RvY29sUmVxdWlyZWQgPSAvXihodHRwcz98ZnRwKTpcXC9cXC8oKCgoW2EtekEtWl18XFxkfC18XFwufF98fnxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSl8KCVbXFxkYS1mQS1GXXsyfSl8WyFcXCQmJ1xcKFxcKVxcKlxcKyw7PV18OikqQCk/KCgoXFxkfFsxLTldXFxkfDFcXGRcXGR8MlswLTRdXFxkfDI1WzAtNV0pXFwuKFxcZHxbMS05XVxcZHwxXFxkXFxkfDJbMC00XVxcZHwyNVswLTVdKVxcLihcXGR8WzEtOV1cXGR8MVxcZFxcZHwyWzAtNF1cXGR8MjVbMC01XSlcXC4oXFxkfFsxLTldXFxkfDFcXGRcXGR8MlswLTRdXFxkfDI1WzAtNV0pKXwoW2EtekEtWl1bXFwtYS16QS1aMC05XSopfCgoKFthLXpBLVpdfFxcZHxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSl8KChbYS16QS1aXXxcXGR8W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKFthLXpBLVpdfFxcZHwtfFxcLnxffH58W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKihbYS16QS1aXXxcXGR8W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKSlcXC4pKygoW2EtekEtWl18W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pfCgoW2EtekEtWl18W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKFthLXpBLVpdfFxcZHwtfFxcLnxffH58W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pKihbYS16QS1aXXxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSkpKVxcLj8pKDpcXGQqKT8pKFxcLygoKFthLXpBLVpdfFxcZHwtfFxcLnxffH58W1xcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0pfCglW1xcZGEtZkEtRl17Mn0pfFshXFwkJidcXChcXClcXCpcXCssOz1dfDp8QCkrKFxcLygoW2EtekEtWl18XFxkfC18XFwufF98fnxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSl8KCVbXFxkYS1mQS1GXXsyfSl8WyFcXCQmJ1xcKFxcKVxcKlxcKyw7PV18OnxAKSopKik/KT8oXFw/KCgoW2EtekEtWl18XFxkfC18XFwufF98fnxbXFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXSl8KCVbXFxkYS1mQS1GXXsyfSl8WyFcXCQmJ1xcKFxcKVxcKlxcKyw7PV18OnxAKXxbXFx1RTAwMC1cXHVGOEZGXXxcXC98XFw/KSopPyhcXCMoKChbYS16QS1aXXxcXGR8LXxcXC58X3x+fFtcXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZdKXwoJVtcXGRhLWZBLUZdezJ9KXxbIVxcJCYnXFwoXFwpXFwqXFwrLDs9XXw6fEApfFxcL3xcXD8pKik/JC87XHJcbiAgICByZXR1cm4gbWFrZVJlZ0V4cFZhbGlkYXRvcigndXJsJywgcmVVcmxQcm90b2NvbFJlcXVpcmVkLCBudWxsLCBjb250ZXh0KTtcclxuICB9O1xyXG5cclxuICAvKipcclxuICBDcmVhdGVzIGEgcmVndWxhciBleHByZXNzaW9uIHZhbGlkYXRvciB3aXRoIGEgZml4ZWQgZXhwcmVzc2lvbi5cclxuICBNYW55IG9mIHRoZSBzdG9jayB2YWxpZGF0b3JzIGFyZSBidWlsdCB3aXRoIHRoaXMgZmFjdG9yeSBtZXRob2QuXHJcbiAgVGhlaXIgZXhwcmVzc2lvbnMgYXJlIG9mdGVuIGRlcml2ZWQgZnJvbVxyXG4gIGh0dHBzOi8vZ2l0aHViLmNvbS9zcmtpcmtsYW5kL0RhdGFBbm5vdGF0aW9uc0V4dGVuc2lvbnMvYmxvYi9tYXN0ZXIvRGF0YUFubm90YXRpb25zRXh0ZW5zaW9uc1xyXG4gIFlvdSBjYW4gdHJ5IG1hbnkgb2YgdGhlbSBhdCBodHRwOi8vZGF0YWFubm90YXRpb25zZXh0ZW5zaW9ucy5vcmcvXHJcbiAgQGV4YW1wbGVcclxuICAgICAgLy8gTWFrZSBhIHppcGNvZGUgdmFsaWRhdG9yXHJcbiAgICAgIGZ1bmN0aW9uIHppcFZhbGlkYXRvciA9IFZhbGlkYXRvci5tYWtlUmVnRXhwVmFsaWRhdG9yKFxyXG4gICAgICBcInppcFZhbCxcclxuICAgICAgL15cXGR7NX0oW1xcLV1cXGR7NH0pPyQvLFxyXG4gICAgICBcIlRoZSAlZGlzcGxheU5hbWUlICcldmFsdWUlJyBpcyBub3QgYSB2YWxpZCBVLlMuIHppcGNvZGVcIik7XHJcbiAgICAgIC8vIFJlZ2lzdGVyIGl0LlxyXG4gICAgICBWYWxpZGF0b3IucmVnaXN0ZXIoemlwVmFsaWRhdG9yKTtcclxuICAgICAgLy8gQWRkIGl0IHRvIGEgZGF0YSBwcm9wZXJ0eS4gQXNzdW1lIGVtIGlzIGEgcHJlZXhpc3RpbmcgRW50aXR5TWFuYWdlci5cclxuICAgICAgdmFyIGN1c3RUeXBlID0gZW0ubWV0YWRhdGFTdG9yZS5nZXRFbnRpdHlUeXBlKFwiQ3VzdG9tZXJcIik7XHJcbiAgICAgIHZhciB6aXBQcm9wZXJ0eSA9IGN1c3RUeXBlLmdldFByb3BlcnR5KFwiUG9zdGFsQ29kZVwiKTtcclxuICAgICAgemlwUHJvcGVydHkudmFsaWRhdG9ycy5wdXNoKHppcFZhbGlkYXRvcik7XHJcbiAgQG1ldGhvZCBtYWtlUmVnRXhwVmFsaWRhdG9yXHJcbiAgQHN0YXRpY1xyXG4gIEBwYXJhbSB2YWxpZGF0b3JOYW1lIHtTdHJpbmd9IG5hbWUgb2YgdGhpcyB2YWxpZGF0b3JcclxuICBAcGFyYW0gZXhwcmVzc2lvbiB7U3RyaW5nIHwgUmVnRXhwfSByZWd1bGFyIGV4cHJlc3Npb24gdG8gYXBwbHlcclxuICBAcGFyYW0gW2RlZmF1bHRNZXNzYWdlXSB7U3RyaW5nfSBkZWZhdWx0IG1lc3NhZ2UgZm9yIGZhaWxlZCB2YWxpZGF0aW9uc1xyXG4gIEBwYXJhbSBbY29udGV4dF0ge09iamVjdH0gb3B0aW9uYWwgcGFyYW1ldGVycyB0byBwYXNzIHRocm91Z2ggdG8gdmFsaWRhdGlvbiBjb25zdHJ1Y3RvclxyXG4gIEByZXR1cm4ge1ZhbGlkYXRvcn0gQSBuZXcgVmFsaWRhdG9yXHJcbiAgKiovXHJcbiAgcHVibGljIHN0YXRpYyBtYWtlUmVnRXhwVmFsaWRhdG9yID0gbWFrZVJlZ0V4cFZhbGlkYXRvcjtcclxuXHJcbn1cclxuVmFsaWRhdG9yLnByb3RvdHlwZS5fJHR5cGVOYW1lID0gXCJWYWxpZGF0b3JcIjtcclxuXHJcbi8vIHJlZ2lzdGVyIGFsbCB2YWxpZGF0b3JzXHJcbkVycm9yWyd4J10gPSBjb3JlLm9iamVjdEZvckVhY2goVmFsaWRhdG9yLCBmdW5jdGlvbiAoa2V5OiBzdHJpbmcsIHZhbHVlOiBhbnkpIHtcclxuICBpZiAodHlwZW9mICh2YWx1ZSkgIT09IFwiZnVuY3Rpb25cIikge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuICBpZiAoa2V5ID09PSBcImZyb21KU09OXCIgfHwga2V5ID09PSBcInJlZ2lzdGVyXCIgfHxcclxuICAgICAga2V5ID09PSBcInJlZ2lzdGVyRmFjdG9yeVwiIHx8IGtleSA9PT0gXCJtYWtlUmVnRXhwVmFsaWRhdG9yXCIpIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIGNvbmZpZy5yZWdpc3RlckZ1bmN0aW9uKHZhbHVlLCBcIlZhbGlkYXRvci5cIiArIGtleSk7XHJcbn0pO1xyXG5cclxuZnVuY3Rpb24gZm9ybWF0VGVtcGxhdGUodGVtcGxhdGU6IHN0cmluZywgdmFyczogT2JqZWN0LCBvd25Qcm9wZXJ0aWVzT25seTogYm9vbGVhbiA9IGZhbHNlKSB7XHJcbiAgaWYgKCF2YXJzKSByZXR1cm4gdGVtcGxhdGU7XHJcbiAgcmV0dXJuIHRlbXBsYXRlLnJlcGxhY2UoLyUoW14lXSspJS9nLCBmdW5jdGlvbiAoXywga2V5KSB7XHJcbiAgICBsZXQgdmFsT3JGbjogYW55O1xyXG4gICAgaWYgKG93blByb3BlcnRpZXNPbmx5KSB7XHJcbiAgICAgIHZhbE9yRm4gPSB2YXJzLmhhc093blByb3BlcnR5KGtleSkgPyB2YXJzW2tleV0gOiAnJztcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHZhbE9yRm4gPSB2YXJzW2tleV07XHJcbiAgICB9XHJcbiAgICBpZiAodmFsT3JGbiAhPSBudWxsKSB7XHJcbiAgICAgIGlmIChjb3JlLmlzRnVuY3Rpb24odmFsT3JGbikpIHtcclxuICAgICAgICByZXR1cm4gdmFsT3JGbih2YXJzKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICByZXR1cm4gdmFsT3JGbjtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmV0dXJuIFwiXCI7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGludFJhbmdlVmFsaWRhdG9yQ3Rvcih2YWxpZGF0b3JOYW1lOiBzdHJpbmcsIG1pblZhbHVlOiBudW1iZXIsIG1heFZhbHVlOiBudW1iZXIsIGNvbnRleHQ6IGFueSkge1xyXG4gIGNvbnRleHQgPSBjb250ZXh0IHx8IHt9O1xyXG4gIGlmIChtaW5WYWx1ZSAhPT0gdW5kZWZpbmVkKSB7IGNvbnRleHQubWluID0gbWluVmFsdWU7IH1cclxuICBpZiAobWF4VmFsdWUgIT09IHVuZGVmaW5lZCkgeyBjb250ZXh0Lm1heCA9IG1heFZhbHVlOyB9XHJcbiAgbGV0IHRlbXBsYXRlRXhpc3RzID0gY29udGV4dC5tZXNzYWdlVGVtcGxhdGUgfHwgVmFsaWRhdG9yLm1lc3NhZ2VUZW1wbGF0ZXNbdmFsaWRhdG9yTmFtZV07XHJcbiAgaWYgKCF0ZW1wbGF0ZUV4aXN0cykge1xyXG4gICAgVmFsaWRhdG9yLm1lc3NhZ2VUZW1wbGF0ZXNbdmFsaWRhdG9yTmFtZV0gPSBjb3JlLmZvcm1hdFN0cmluZyhcIiclZGlzcGxheU5hbWUlJyBtdXN0IGJlIGFuIGludGVnZXIgYmV0d2VlbiB0aGUgdmFsdWVzIG9mICUxIGFuZCAlMlwiLFxyXG4gICAgICAgIG1pblZhbHVlLCBtYXhWYWx1ZSk7XHJcbiAgfVxyXG4gIHJldHVybiBmdW5jdGlvbiAoKSB7XHJcbiAgICBsZXQgdmFsRm4gPSBmdW5jdGlvbiAodjogYW55LCBjdHg6IGFueSkge1xyXG4gICAgICBpZiAodiA9PSBudWxsKSByZXR1cm4gdHJ1ZTtcclxuICAgICAgaWYgKHR5cGVvZiB2ID09PSBcInN0cmluZ1wiICYmIGN0eCAmJiBjdHguYWxsb3dTdHJpbmcpIHtcclxuICAgICAgICB2ID0gcGFyc2VJbnQodiwgMCk7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKCh0eXBlb2YgdiA9PT0gXCJudW1iZXJcIikgJiYgKCFpc05hTih2KSkgJiYgTWF0aC5mbG9vcih2KSA9PT0gdikge1xyXG4gICAgICAgIGlmIChtaW5WYWx1ZSAhPSBudWxsICYmIHYgPCBtaW5WYWx1ZSkge1xyXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAobWF4VmFsdWUgIT0gbnVsbCAmJiB2ID4gbWF4VmFsdWUpIHtcclxuICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcbiAgICB9O1xyXG4gICAgcmV0dXJuIG5ldyBWYWxpZGF0b3IodmFsaWRhdG9yTmFtZSwgdmFsRm4sIGNvbnRleHQpO1xyXG4gIH07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBtYWtlUmVnRXhwVmFsaWRhdG9yKHZhbGlkYXRvck5hbWU6IHN0cmluZywgZXhwcmVzc2lvbjogUmVnRXhwLCBkZWZhdWx0TWVzc2FnZT86IHN0cmluZyB8IG51bGwsIGNvbnRleHQ/OiBhbnkpIHtcclxuICBpZiAoZGVmYXVsdE1lc3NhZ2UpIHtcclxuICAgIFZhbGlkYXRvci5tZXNzYWdlVGVtcGxhdGVzW3ZhbGlkYXRvck5hbWVdID0gZGVmYXVsdE1lc3NhZ2U7XHJcbiAgfVxyXG4gIGxldCByZSA9ICh0eXBlb2YgKGV4cHJlc3Npb24pID09PSAnc3RyaW5nJykgPyBuZXcgUmVnRXhwKGV4cHJlc3Npb24pIDogZXhwcmVzc2lvbjtcclxuICBsZXQgdmFsRm4gPSBmdW5jdGlvbiAodjogYW55KSB7XHJcbiAgICAvLyBkbyBub3QgaW52YWxpZGF0ZSBpZiBlbXB0eTsgdXNlIGEgc2VwYXJhdGUgcmVxdWlyZWQgdGVzdFxyXG4gICAgaWYgKHYgPT0gbnVsbCB8fCB2ID09PSAnJykgcmV0dXJuIHRydWU7XHJcbiAgICBpZiAodHlwZW9mICh2KSAhPT0gJ3N0cmluZycpIHJldHVybiBmYWxzZTtcclxuICAgIHJldHVybiByZS50ZXN0KHYpO1xyXG4gIH07XHJcbiAgcmV0dXJuIG5ldyBWYWxpZGF0b3IodmFsaWRhdG9yTmFtZSwgdmFsRm4sIGNvbnRleHQpO1xyXG59XHJcblxyXG4vLyBodHRwOi8vcm9zZXR0YWNvZGUub3JnL3dpa2kvTHVobl90ZXN0X29mX2NyZWRpdF9jYXJkX251bWJlcnMjSmF2YVNjcmlwdFxyXG5cclxuLy8gZnVuY3Rpb24gbHVobihhOiBzdHJpbmcsIGI6IG51bWJlciwgYzogbnVtYmVyLCBkOiBudW1iZXIsIGU6IG51bWJlcikge1xyXG4vLyAgIGZvciAoZCA9ICthW2IgPSBhLmxlbmd0aCAtIDFdLCBlID0gMDsgYi0tOyApIHtcclxuLy8gICAgIGMgPSArYVtiXSwgZCArPSArK2UgJSAyID8gMiAqIGMgJSAxMCArIChjID4gNCkgOiBjO1xyXG4vLyAgIH1cclxuLy8gICByZXR1cm4gIShkICUgMTApO1xyXG4vLyB9O1xyXG5cclxubGV0ICBsdWhuID0gKGZ1bmN0aW9uKCkge1xyXG4gIGxldCBsdWhuQXJyID0gWzAsIDIsIDQsIDYsIDgsIDEsIDMsIDUsIDcsIDldO1xyXG4gIHJldHVybiBmdW5jdGlvbihzdHI6IHN0cmluZykgXHR7XHJcbiAgICBsZXQgY291bnRlciA9IDA7XHJcbiAgICBsZXQgaW5jTnVtOiBudW1iZXI7XHJcbiAgICBsZXQgb2RkID0gZmFsc2U7XHJcbiAgICBsZXQgdGVtcCA9IFN0cmluZyhzdHIpLnJlcGxhY2UoL1teXFxkXS9nLCBcIlwiKTtcclxuICAgIGlmICggdGVtcC5sZW5ndGggPT09IDApIHJldHVybiBmYWxzZTtcclxuICAgIGZvciAobGV0IGkgPSB0ZW1wLmxlbmd0aCAtIDE7IGkgPj0gMDsgLS1pKSAge1xyXG4gICAgICBpbmNOdW0gPSBwYXJzZUludCh0ZW1wLmNoYXJBdChpKSwgMTApO1xyXG4gICAgICBjb3VudGVyICs9IChvZGQgPSAhb2RkKSA/IGluY051bSA6IGx1aG5BcnJbaW5jTnVtXTtcclxuICAgIH1cclxuICAgIHJldHVybiAoY291bnRlciAlIDEwID09PSAwKTtcclxuICB9O1xyXG59KSgpO1xyXG5cclxuLyoqXHJcbkEgVmFsaWRhdGlvbkVycm9yIGlzIHVzZWQgdG8gZGVzY3JpYmUgYSBmYWlsZWQgdmFsaWRhdGlvbi5cclxuXHJcbkBjbGFzcyBWYWxpZGF0aW9uRXJyb3JcclxuKiovXHJcblxyXG4vKipcclxuQ29uc3RydWN0cyBhIG5ldyBWYWxpZGF0aW9uRXJyb3JcclxuQG1ldGhvZCA8Y3Rvcj4gVmFsaWRhdGlvbkVycm9yXHJcblxyXG5AcGFyYW0gdmFsaWRhdG9yIHtWYWxpZGF0b3IgfHwgbnVsbH0gVGhlIFZhbGlkYXRvciB1c2VkIHRvIGNyZWF0ZSB0aGlzIGVycm9yLCBpZiBhbnkuXHJcbkBwYXJhbSBjb250ZXh0IHsgQ29udGV4dE9iamVjdCB8fCBudWxsfSBUaGUgQ29udGV4dCBvYmplY3QgdXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBWYWxpZGF0b3IgdG8gY3JlYXRlIHRoaXMgZXJyb3IuXHJcbkBwYXJhbSBlcnJvck1lc3NhZ2UgeyBTdHJpbmd9IFRoZSBhY3R1YWwgZXJyb3IgbWVzc2FnZVxyXG5AcGFyYW0gW2tleV0ge1N0cmluZ30gQW4gb3B0aW9uYWwga2V5IHVzZWQgdG8gZGVmaW5lIGEga2V5IGZvciB0aGlzIGVycm9yLiBPbmUgd2lsbCBiZSBjcmVhdGVkIGF1dG9tYXRpY2FsbHkgaWYgbm90IHByb3ZpZGVkIGhlcmUuXHJcbioqL1xyXG5leHBvcnQgY2xhc3MgVmFsaWRhdGlvbkVycm9yIHtcclxuICB2YWxpZGF0b3I/OiBWYWxpZGF0b3I7XHJcbiAga2V5OiBzdHJpbmc7XHJcbiAgY29udGV4dDogYW55O1xyXG4gIGVycm9yTWVzc2FnZTogc3RyaW5nO1xyXG4gIHByb3BlcnR5OiBhbnk7IC8vIElQcm9wZXJ0eVxyXG4gIHByb3BlcnR5TmFtZTogc3RyaW5nO1xyXG4gIGlzU2VydmVyRXJyb3I6IGJvb2xlYW47XHJcblxyXG4gIGNvbnN0cnVjdG9yKHZhbGlkYXRvcjogVmFsaWRhdG9yIHwgbnVsbCwgY29udGV4dDogVmFsaWRhdGlvbkNvbnRleHQsIGVycm9yTWVzc2FnZTogc3RyaW5nLCBrZXk/OiBzdHJpbmcpIHtcclxuICAgIC8vIEVycm9yIGlzIHdpdGggaXNJbnN0YW5jZU9mKFZhbGlkYXRvcilcclxuICAgIGFzc2VydFBhcmFtKHZhbGlkYXRvciwgXCJ2YWxpZGF0b3JcIikuaXNPcHRpb25hbCgpLmlzSW5zdGFuY2VPZihWYWxpZGF0b3IpLmNoZWNrKCk7XHJcbiAgICBhc3NlcnRQYXJhbShlcnJvck1lc3NhZ2UsIFwiZXJyb3JNZXNzYWdlXCIpLmlzTm9uRW1wdHlTdHJpbmcoKS5jaGVjaygpO1xyXG4gICAgYXNzZXJ0UGFyYW0oa2V5LCBcImtleVwiKS5pc09wdGlvbmFsKCkuaXNOb25FbXB0eVN0cmluZygpLmNoZWNrKCk7XHJcbiAgICB0aGlzLnZhbGlkYXRvciA9IHZhbGlkYXRvciB8fCB1bmRlZmluZWQ7XHJcbiAgICBjb250ZXh0ID0gY29udGV4dCB8fCB7fTtcclxuICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgICB0aGlzLmVycm9yTWVzc2FnZSA9IGVycm9yTWVzc2FnZTtcclxuXHJcbiAgICB0aGlzLnByb3BlcnR5ID0gY29udGV4dC5wcm9wZXJ0eTtcclxuICAgIHRoaXMucHJvcGVydHlOYW1lID0gY29udGV4dC5wcm9wZXJ0eU5hbWUgfHwgKGNvbnRleHQucHJvcGVydHkgJiYgY29udGV4dC5wcm9wZXJ0eS5uYW1lKTtcclxuXHJcbiAgICBpZiAoa2V5KSB7XHJcbiAgICAgIHRoaXMua2V5ID0ga2V5O1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5rZXkgPSBWYWxpZGF0aW9uRXJyb3IuZ2V0S2V5KHZhbGlkYXRvciB8fCBlcnJvck1lc3NhZ2UsIHRoaXMucHJvcGVydHlOYW1lKTtcclxuICAgIH1cclxuICAgIHRoaXMuaXNTZXJ2ZXJFcnJvciA9IGZhbHNlO1xyXG4gIH1cclxuXHJcblxyXG4gIC8qKlxyXG4gIFRoZSBWYWxpZGF0b3IgYXNzb2NpYXRlZCB3aXRoIHRoaXMgVmFsaWRhdGlvbkVycm9yLlxyXG5cclxuICBfX3JlYWRPbmx5X19cclxuICBAcHJvcGVydHkgdmFsaWRhdG9yIHtWYWxpZGF0b3J9XHJcbiAgKiovXHJcblxyXG4gIC8qKlxyXG4gIEEgJ2NvbnRleHQnIG9iamVjdCBhc3NvY2lhdGVkIHdpdGggdGhpcyBWYWxpZGF0aW9uRXJyb3IuXHJcblxyXG4gIF9fcmVhZE9ubHlfX1xyXG4gIEBwcm9wZXJ0eSBjb250ZXh0IHtPYmplY3R9XHJcbiAgKiovXHJcblxyXG4gIC8qKlxyXG4gIFRoZSBEYXRhUHJvcGVydHkgb3IgTmF2aWdhdGlvblByb3BlcnR5IGFzc29jaWF0ZWQgd2l0aCB0aGlzIFZhbGlkYXRpb25FcnJvci5cclxuXHJcbiAgX19yZWFkT25seV9fXHJcbiAgQHByb3BlcnR5IHByb3BlcnR5IHtEYXRhUHJvcGVydHl8TmF2aWdhdGlvblByb3BlcnR5fVxyXG4gICoqL1xyXG5cclxuICAvKipcclxuICBUaGUgcHJvcGVydHkgbmFtZSBhc3NvY2lhdGVkIHdpdGggdGhpcyBWYWxpZGF0aW9uRXJyb3IuIFRoaXMgd2lsbCBiZSBhIFwicHJvcGVydHkgcGF0aFwiIGZvciBhbnkgcHJvcGVydGllcyBvZiBhIGNvbXBsZXggb2JqZWN0LlxyXG5cclxuICBfX3JlYWRPbmx5X19cclxuICBAcHJvcGVydHkgcHJvcGVydHlOYW1lIHtTdHJpbmd9XHJcbiAgKiovXHJcblxyXG4gIC8qKlxyXG4gIFRoZSBlcnJvciBtZXNzYWdlIGFzc29jaWF0ZWQgd2l0aCB0aGUgVmFsaWRhdGlvbkVycm9yLlxyXG5cclxuICBfX3JlYWRPbmx5X19cclxuICBAcHJvcGVydHkgZXJyb3JNZXNzYWdlIHtzdHJpbmd9XHJcbiAgKiovXHJcblxyXG4gIC8qKlxyXG4gIFRoZSBrZXkgYnkgd2hpY2ggdGhpcyB2YWxpZGF0aW9uIGVycm9yIG1heSBiZSByZW1vdmVkIGZyb20gYSBjb2xsZWN0aW9uIG9mIFZhbGlkYXRpb25FcnJvcnMuXHJcblxyXG4gIF9fcmVhZE9ubHlfX1xyXG4gIEBwcm9wZXJ0eSBrZXkge3N0cmluZ31cclxuICAqKi9cclxuXHJcbiAgLyoqXHJcbiAgV2hldGhlciB0aGlzIGlzIGEgc2VydmVyIGVycm9yLlxyXG5cclxuICBfX3JlYWRPbmx5X19cclxuICBAcHJvcGVydHkgaXNTZXJ2ZXJFcnJvciB7Ym9vbH1cclxuICAqKi9cclxuXHJcblxyXG4gIC8qKlxyXG4gIENvbXBvc2VzIGEgVmFsaWRhdGlvbkVycm9yICdrZXknIGdpdmVuIGEgdmFsaWRhdG9yIG9yIGFuIGVycm9yTmFtZSBhbmQgYW4gb3B0aW9uYWwgcHJvcGVydHlOYW1lXHJcbiAgQG1ldGhvZCBnZXRLZXlcclxuICBAc3RhdGljXHJcbiAgQHBhcmFtIHZhbGlkYXRvciB7VmFsaWRhdG9yT3JFcnJvcktleX0gQSBWYWxpZGF0b3Igb3IgYW4gXCJlcnJvciBuYW1lXCIgaWYgbm8gdmFsaWRhdG9yIGlzIGF2YWlsYWJsZS5cclxuICBAcGFyYW0gW3Byb3BlcnR5TmFtZV0gQSBwcm9wZXJ0eSBuYW1lXHJcbiAgQHJldHVybiB7U3RyaW5nfSBBIFZhbGlkYXRpb25FcnJvciAna2V5J1xyXG4gICoqL1xyXG4gIHB1YmxpYyBzdGF0aWMgZ2V0S2V5KHZhbGlkYXRvck9yRXJyb3JOYW1lOiBWYWxpZGF0b3IgfCBzdHJpbmcsIHByb3BlcnR5TmFtZT86IHN0cmluZykge1xyXG4gICAgbGV0IG5hbWUgPSAodHlwZW9mIHZhbGlkYXRvck9yRXJyb3JOYW1lID09PSAnc3RyaW5nJykgPyB2YWxpZGF0b3JPckVycm9yTmFtZSA6IHZhbGlkYXRvck9yRXJyb3JOYW1lLm5hbWU7XHJcbiAgICByZXR1cm4gbmFtZSArIChwcm9wZXJ0eU5hbWUgPyBcIjpcIiArIHByb3BlcnR5TmFtZSA6IFwiXCIpO1xyXG4gIH1cclxuXHJcbn1cclxuXHJcblxyXG4iXX0=